about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml14
-rw-r--r--Cargo.lock113
-rw-r--r--RELEASES.md2
-rw-r--r--compiler/rustc/Cargo.toml6
-rw-r--r--compiler/rustc_arena/src/lib.rs61
-rw-r--r--compiler/rustc_ast/src/ast.rs5
-rw-r--r--compiler/rustc_ast/src/ptr.rs8
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs20
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs22
-rw-r--r--compiler/rustc_ast_pretty/src/pp.rs71
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs8
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs24
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/item.rs6
-rw-r--r--compiler/rustc_borrowck/src/constraints/mod.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/region_infer/dump_mir.rs2
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs1
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs41
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs24
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.lock4
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.toml2
-rw-r--r--compiler/rustc_codegen_gcc/src/asm.rs3
-rw-r--r--compiler/rustc_codegen_gcc/src/builder.rs29
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs73
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs31
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs17
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs355
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs15
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/utils.rs59
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs31
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs154
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs33
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs10
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs25
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs5
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs27
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs60
-rw-r--r--compiler/rustc_data_structures/Cargo.toml2
-rw-r--r--compiler/rustc_data_structures/src/fingerprint.rs10
-rw-r--r--compiler/rustc_data_structures/src/sip128.rs18
-rw-r--r--compiler/rustc_data_structures/src/stable_hasher/tests.rs42
-rw-r--r--compiler/rustc_data_structures/src/svh.rs4
-rw-r--r--compiler/rustc_driver/src/lib.rs5
-rw-r--r--compiler/rustc_error_codes/src/error_codes.rs3
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0772.md89
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0787.md28
-rw-r--r--compiler/rustc_errors/src/json/tests.rs2
-rw-r--r--compiler/rustc_errors/src/lib.rs21
-rw-r--r--compiler/rustc_expand/src/base.rs32
-rw-r--r--compiler/rustc_expand/src/expand.rs13
-rw-r--r--compiler/rustc_expand/src/lib.rs1
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs3
-rw-r--r--compiler/rustc_hir/src/definitions.rs14
-rw-r--r--compiler/rustc_hir/src/hir.rs2
-rw-r--r--compiler/rustc_hir/src/lang_items.rs1
-rw-r--r--compiler/rustc_hir/src/stable_hash_impls.rs9
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs2
-rw-r--r--compiler/rustc_incremental/src/persist/load.rs15
-rw-r--r--compiler/rustc_index/src/vec.rs8
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs6
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs16
-rw-r--r--compiler/rustc_interface/src/interface.rs11
-rw-r--r--compiler/rustc_interface/src/lib.rs1
-rw-r--r--compiler/rustc_interface/src/passes.rs67
-rw-r--r--compiler/rustc_interface/src/util.rs92
-rw-r--r--compiler/rustc_lint/src/builtin.rs17
-rw-r--r--compiler/rustc_lint/src/context.rs60
-rw-r--r--compiler/rustc_lint/src/early.rs127
-rw-r--r--compiler/rustc_lint/src/internal.rs2
-rw-r--r--compiler/rustc_lint/src/levels.rs63
-rw-r--r--compiler/rustc_lint/src/lib.rs7
-rw-r--r--compiler/rustc_lint/src/non_ascii_idents.rs2
-rw-r--r--compiler/rustc_lint/src/non_fmt_panic.rs2
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs2
-rw-r--r--compiler/rustc_lint/src/pass_by_value.rs4
-rw-r--r--compiler/rustc_lint/src/traits.rs3
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs51
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs7
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp9
-rw-r--r--compiler/rustc_macros/src/serialize.rs18
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs107
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs10
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs6
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs7
-rw-r--r--compiler/rustc_middle/src/mir/graph_cyclic_cache.rs5
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs30
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs16
-rw-r--r--compiler/rustc_middle/src/mir/predecessors.rs7
-rw-r--r--compiler/rustc_middle/src/mir/spanview.rs6
-rw-r--r--compiler/rustc_middle/src/query/mod.rs23
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs30
-rw-r--r--compiler/rustc_middle/src/traits/select.rs4
-rw-r--r--compiler/rustc_middle/src/traits/structural_impls.rs7
-rw-r--r--compiler/rustc_middle/src/ty/assoc.rs19
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs182
-rw-r--r--compiler/rustc_middle/src/ty/consts/int.rs4
-rw-r--r--compiler/rustc_middle/src/ty/context.rs145
-rw-r--r--compiler/rustc_middle/src/ty/error.rs4
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs55
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs4
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs47
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs6
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs4
-rw-r--r--compiler/rustc_middle/src/ty/util.rs36
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs31
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs7
-rw-r--r--compiler/rustc_mir_build/src/lints.rs12
-rw-r--r--compiler/rustc_mir_transform/src/coverage/debug.rs5
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs12
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans.rs13
-rw-r--r--compiler/rustc_mir_transform/src/coverage/tests.rs5
-rw-r--r--compiler/rustc_mir_transform/src/early_otherwise_branch.rs581
-rw-r--r--compiler/rustc_mir_transform/src/function_item_references.rs65
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs8
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs10
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs30
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs22
-rw-r--r--compiler/rustc_parse/src/parser/item.rs2
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs92
-rw-r--r--compiler/rustc_query_impl/src/on_disk_cache.rs117
-rw-r--r--compiler/rustc_query_system/src/dep_graph/serialized.rs17
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs2
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs4
-rw-r--r--compiler/rustc_resolve/src/late/lifetimes.rs75
-rw-r--r--compiler/rustc_resolve/src/lib.rs19
-rw-r--r--compiler/rustc_resolve/src/macros.rs6
-rw-r--r--compiler/rustc_save_analysis/src/lib.rs2
-rw-r--r--compiler/rustc_serialize/Cargo.toml2
-rw-r--r--compiler/rustc_serialize/src/collection_impls.rs85
-rw-r--r--compiler/rustc_serialize/src/json.rs185
-rw-r--r--compiler/rustc_serialize/src/opaque.rs88
-rw-r--r--compiler/rustc_serialize/src/serialize.rs221
-rw-r--r--compiler/rustc_serialize/tests/json.rs208
-rw-r--r--compiler/rustc_serialize/tests/opaque.rs2
-rw-r--r--compiler/rustc_session/src/config.rs12
-rw-r--r--compiler/rustc_session/src/session.rs4
-rw-r--r--compiler/rustc_span/src/def_id.rs20
-rw-r--r--compiler/rustc_span/src/hygiene.rs25
-rw-r--r--compiler/rustc_span/src/lev_distance.rs68
-rw-r--r--compiler/rustc_span/src/lev_distance/tests.rs22
-rw-r--r--compiler/rustc_span/src/lib.rs77
-rw-r--r--compiler/rustc_span/src/span_encoding.rs9
-rw-r--r--compiler/rustc_span/src/symbol.rs10
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs2
-rw-r--r--compiler/rustc_target/src/asm/mod.rs27
-rw-r--r--compiler/rustc_target/src/asm/msp430.rs81
-rw-r--r--compiler/rustc_target/src/spec/l4re_base.rs17
-rw-r--r--compiler/rustc_target/src/spec/mod.rs2
-rw-r--r--compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/codegen.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs269
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs124
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs281
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs24
-rw-r--r--compiler/rustc_trait_selection/src/traits/on_unimplemented.rs21
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs194
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs138
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs77
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs5
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs4
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs2
-rw-r--r--compiler/rustc_typeck/src/astconv/errors.rs20
-rw-r--r--compiler/rustc_typeck/src/astconv/generics.rs2
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs21
-rw-r--r--compiler/rustc_typeck/src/check/callee.rs34
-rw-r--r--compiler/rustc_typeck/src/check/check.rs2
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs24
-rw-r--r--compiler/rustc_typeck/src/check/dropck.rs8
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs28
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs341
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs2
-rw-r--r--compiler/rustc_typeck/src/check/generator_interior.rs10
-rw-r--r--compiler/rustc_typeck/src/check/intrinsic.rs5
-rw-r--r--compiler/rustc_typeck/src/check/method/probe.rs19
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs10
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs10
-rw-r--r--compiler/rustc_typeck/src/check/op.rs93
-rw-r--r--compiler/rustc_typeck/src/check/wfcheck.rs21
-rw-r--r--compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs13
-rw-r--r--library/alloc/src/collections/binary_heap.rs33
-rw-r--r--library/alloc/src/collections/btree/map.rs12
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs30
-rw-r--r--library/alloc/src/lib.rs20
-rw-r--r--library/alloc/src/rc.rs94
-rw-r--r--library/alloc/src/sync.rs99
-rw-r--r--library/core/src/cell.rs12
-rw-r--r--library/core/src/cmp.rs36
-rw-r--r--library/core/src/fmt/mod.rs22
-rw-r--r--library/core/src/future/into_future.rs2
-rw-r--r--library/core/src/future/join.rs2
-rw-r--r--library/core/src/intrinsics.rs23
-rw-r--r--library/core/src/iter/traits/iterator.rs36
-rw-r--r--library/core/src/lib.rs61
-rw-r--r--library/core/src/macros/mod.rs1
-rw-r--r--library/core/src/num/saturating.rs130
-rw-r--r--library/core/src/ops/arith.rs35
-rw-r--r--library/core/src/ops/bit.rs11
-rw-r--r--library/core/src/panic/panic_info.rs16
-rw-r--r--library/core/src/panicking.rs27
-rw-r--r--library/core/src/prelude/v1.rs1
-rw-r--r--library/core/src/ptr/non_null.rs3
-rw-r--r--library/core/src/time.rs301
-rw-r--r--library/core/tests/cmp.rs1
-rw-r--r--library/core/tests/intrinsics.rs23
-rw-r--r--library/core/tests/lib.rs3
-rw-r--r--library/core/tests/ops.rs6
-rw-r--r--library/core/tests/ptr.rs16
-rw-r--r--library/panic_unwind/src/lib.rs4
-rw-r--r--library/std/Cargo.toml6
-rw-r--r--library/std/src/collections/hash/map/tests.rs21
-rw-r--r--library/std/src/error.rs2
-rw-r--r--library/std/src/ffi/c_str.rs6
-rw-r--r--library/std/src/ffi/os_str.rs6
-rw-r--r--library/std/src/fs/tests.rs16
-rw-r--r--library/std/src/io/stdio.rs25
-rw-r--r--library/std/src/lib.rs63
-rw-r--r--library/std/src/os/fd/owned.rs33
-rw-r--r--library/std/src/os/raw/mod.rs150
-rw-r--r--library/std/src/os/unix/net/addr.rs56
-rw-r--r--library/std/src/os/wasi/fs.rs15
-rw-r--r--library/std/src/os/wasi/net/mod.rs20
-rw-r--r--library/std/src/os/windows/io/handle.rs32
-rw-r--r--library/std/src/os/windows/io/socket.rs75
-rw-r--r--library/std/src/panicking.rs22
-rw-r--r--library/std/src/path.rs27
-rw-r--r--library/std/src/prelude/v1.rs1
-rw-r--r--library/std/src/sync/mutex.rs7
-rw-r--r--library/std/src/sync/rwlock.rs14
-rw-r--r--library/std/src/sys/common/alloc.rs10
-rw-r--r--library/std/src/sys/solid/abi/sockets.rs3
-rw-r--r--library/std/src/sys/solid/net.rs2
-rw-r--r--library/std/src/sys/unix/fd.rs17
-rw-r--r--library/std/src/sys/unix/fs.rs116
-rw-r--r--library/std/src/sys/unix/os.rs2
-rw-r--r--library/std/src/sys/unix/process/process_unix/tests.rs7
-rw-r--r--library/std/src/sys/wasi/fd.rs4
-rw-r--r--library/std/src/sys/wasi/mod.rs41
-rw-r--r--library/std/src/sys/wasi/net.rs66
-rw-r--r--library/std/src/sys/wasi/stdio.rs2
-rw-r--r--library/std/src/sys/wasi/thread.rs8
-rw-r--r--library/std/src/sys/wasi/time.rs2
-rw-r--r--library/std/src/sys/windows/fs.rs2
-rw-r--r--library/std/src/sys/windows/handle.rs21
-rw-r--r--library/std/src/sys/windows/mod.rs1
-rw-r--r--library/std/src/sys/windows/net.rs62
-rw-r--r--library/std/src/sys_common/io.rs8
-rw-r--r--library/std/src/thread/mod.rs93
-rw-r--r--library/std/src/thread/scoped.rs316
-rw-r--r--library/std/src/time.rs2
-rw-r--r--library/std/tests/run-time-detect.rs6
m---------library/stdarch0
-rw-r--r--src/bootstrap/builder.rs193
-rw-r--r--src/bootstrap/builder/tests.rs4
-rw-r--r--src/bootstrap/config.rs5
-rw-r--r--src/bootstrap/dist.rs4
-rw-r--r--src/bootstrap/doc.rs8
-rw-r--r--src/bootstrap/test.rs3
-rw-r--r--src/bootstrap/util.rs5
-rw-r--r--src/build_helper/lib.rs16
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile2
-rw-r--r--src/ci/github-actions/ci.yml17
m---------src/doc/rust-by-example0
-rw-r--r--src/doc/rustc/src/SUMMARY.md2
-rw-r--r--src/doc/rustc/src/linker-plugin-lto.md42
-rw-r--r--src/doc/rustc/src/platform-support.md10
-rw-r--r--src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md2
-rw-r--r--src/doc/rustc/src/platform-support/openbsd.md56
-rw-r--r--src/doc/rustdoc/src/references.md4
-rw-r--r--src/doc/unstable-book/src/language-features/asm-experimental-arch.md17
-rw-r--r--src/librustdoc/Cargo.toml2
-rw-r--r--src/librustdoc/clean/blanket_impl.rs28
-rw-r--r--src/librustdoc/clean/mod.rs10
-rw-r--r--src/librustdoc/clean/render_macro_matchers.rs240
-rw-r--r--src/librustdoc/clean/types.rs99
-rw-r--r--src/librustdoc/clean/utils.rs54
-rw-r--r--src/librustdoc/core.rs17
-rw-r--r--src/librustdoc/formats/cache.rs2
-rw-r--r--src/librustdoc/html/render/mod.rs86
-rw-r--r--src/librustdoc/html/render/search_index.rs58
-rw-r--r--src/librustdoc/html/render/span_map.rs12
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css136
-rw-r--r--src/librustdoc/html/static/css/settings.css24
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css36
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css34
-rw-r--r--src/librustdoc/html/static/css/themes/light.css36
-rw-r--r--src/librustdoc/html/static/js/main.js2
-rw-r--r--src/librustdoc/html/static/js/settings.js29
-rw-r--r--src/librustdoc/html/static/js/storage.js31
-rw-r--r--src/librustdoc/html/templates/page.html21
-rw-r--r--src/librustdoc/html/templates/print_item.html4
-rw-r--r--src/librustdoc/json/mod.rs15
-rw-r--r--src/librustdoc/lib.rs2
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs22
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links/early.rs121
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs14
-rw-r--r--src/librustdoc/passes/strip_hidden.rs4
-rw-r--r--src/librustdoc/passes/strip_private.rs2
-rw-r--r--src/librustdoc/passes/stripper.rs6
-rw-r--r--src/librustdoc/scrape_examples.rs2
m---------src/llvm-project0
-rw-r--r--src/rustdoc-json-types/lib.rs6
-rw-r--r--src/stage0.json672
-rw-r--r--src/test/assembly/asm/msp430-types.rs158
-rw-r--r--src/test/codegen/naked-functions.rs40
-rw-r--r--src/test/codegen/naked-noinline.rs1
-rw-r--r--src/test/codegen/unwind-and-panic-abort.rs2
-rw-r--r--src/test/debuginfo/function-names.rs4
-rw-r--r--src/test/debuginfo/unsized.rs50
-rw-r--r--src/test/debuginfo/vec-slices.rs48
-rw-r--r--src/test/incremental/hashes/extern_mods.rs12
-rw-r--r--src/test/incremental/hashes/inherent_impls.rs84
-rw-r--r--src/test/incremental/hashes/trait_defs.rs248
-rw-r--r--src/test/incremental/hashes/trait_impls.rs48
-rw-r--r--src/test/incremental/hashes/type_defs.rs14
-rw-r--r--src/test/incremental/issue-92987-provisional-dep-node.rs24
-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/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff10
-rw-r--r--src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff10
-rw-r--r--src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff77
-rw-r--r--src/test/mir-opt/early_otherwise_branch.rs10
-rw-r--r--src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff14
-rw-r--r--src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff10
-rw-r--r--src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff10
-rw-r--r--src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff60
-rw-r--r--src/test/mir-opt/early_otherwise_branch_noopt.rs10
-rw-r--r--src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff43
-rw-r--r--src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff30
-rw-r--r--src/test/mir-opt/early_otherwise_branch_soundness.rs32
-rw-r--r--src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir4
-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/nll/named_lifetimes_basic.use_x.nll.0.mir4
-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/pretty/ast-stmt-expr-attr.rs74
-rw-r--r--src/test/pretty/block-comment-wchar.pp8
-rw-r--r--src/test/pretty/delimited-token-groups.rs20
-rw-r--r--src/test/pretty/issue-4264.pp70
-rw-r--r--src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs8
-rw-r--r--src/test/pretty/macro_rules.rs4
-rw-r--r--src/test/pretty/match-naked-expr-medium.rs8
-rw-r--r--src/test/pretty/stmt_expr_attributes.rs66
-rw-r--r--src/test/pretty/vec-comments.pp32
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt8
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-93054.txt29
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt8
-rw-r--r--src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt8
-rw-r--r--src/test/run-make-fulldeps/coverage/issue-93054.rs28
-rw-r--r--src/test/run-make/const_fn_mir/dump.mir32
-rw-r--r--src/test/rustdoc-gui/anchors.goml2
-rw-r--r--src/test/rustdoc-gui/check_info_sign_position.goml2
-rw-r--r--src/test/rustdoc-gui/code-sidebar-toggle.goml1
-rw-r--r--src/test/rustdoc-gui/escape-key.goml2
-rw-r--r--src/test/rustdoc-gui/font-weight.goml2
-rw-r--r--src/test/rustdoc-gui/huge-collection-of-constants.goml4
-rw-r--r--src/test/rustdoc-gui/list_code_block.goml1
-rw-r--r--src/test/rustdoc-gui/mobile.goml4
-rw-r--r--src/test/rustdoc-gui/search-filter.goml1
-rw-r--r--src/test/rustdoc-gui/search-result-colors.goml1
-rw-r--r--src/test/rustdoc-gui/search-result-display.goml1
-rw-r--r--src/test/rustdoc-gui/search-result-keyword.goml1
-rw-r--r--src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml2
-rw-r--r--src/test/rustdoc-gui/sidebar-mobile.goml5
-rw-r--r--src/test/rustdoc-gui/sidebar.goml9
-rw-r--r--src/test/rustdoc-gui/source-code-page.goml1
-rw-r--r--src/test/rustdoc-gui/src/lib2/lib.rs45
-rw-r--r--src/test/rustdoc-gui/theme-change.goml17
-rw-r--r--src/test/rustdoc-gui/theme-in-history.goml25
-rw-r--r--src/test/rustdoc-gui/toggle-docs-mobile.goml2
-rw-r--r--src/test/rustdoc-gui/toggle-docs.goml1
-rw-r--r--src/test/rustdoc-gui/trait-sidebar-item-order.goml1
-rw-r--r--src/test/rustdoc-gui/type-declation-overflow.goml6
-rw-r--r--src/test/rustdoc-js/generics-multi-trait.js32
-rw-r--r--src/test/rustdoc-js/generics-multi-trait.rs12
-rw-r--r--src/test/rustdoc-json/impls/blanket_with_local.rs4
-rw-r--r--src/test/rustdoc/intra-doc/crate-relative.rs13
-rw-r--r--src/test/rustdoc/intra-doc/mod-relative.rs17
-rw-r--r--src/test/rustdoc/macro-generated-macro.macro_linebreak_pre.html6
-rw-r--r--src/test/rustdoc/macro-generated-macro.macro_morestuff_pre.html15
-rw-r--r--src/test/rustdoc/macro-generated-macro.rs39
-rw-r--r--src/test/rustdoc/source-version-separator.rs5
-rw-r--r--src/test/rustdoc/version-separator-without-source.rs23
-rw-r--r--src/test/ui-fulldeps/deriving-encodable-decodable-box.rs2
-rw-r--r--src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs2
-rw-r--r--src/test/ui-fulldeps/internal-lints/qualified_ty_ty_ctxt.stderr4
-rw-r--r--src/test/ui-fulldeps/issue-14021.rs2
-rw-r--r--src/test/ui-fulldeps/issue-4016.rs2
-rw-r--r--src/test/ui-fulldeps/issue-4036.rs2
-rw-r--r--src/test/ui/asm/naked-functions.rs71
-rw-r--r--src/test/ui/asm/naked-functions.stderr181
-rw-r--r--src/test/ui/asm/named-asm-labels.stderr36
-rw-r--r--src/test/ui/async-await/async-fn-nonsend.rs4
-rw-r--r--src/test/ui/async-await/proper-span-for-type-error.fixed11
-rw-r--r--src/test/ui/async-await/proper-span-for-type-error.rs11
-rw-r--r--src/test/ui/async-await/proper-span-for-type-error.stderr16
-rw-r--r--src/test/ui/async-await/unresolved_type_param.rs4
-rw-r--r--src/test/ui/attributes/key-value-expansion.stderr11
-rw-r--r--src/test/ui/c-variadic/variadic-ffi-4.stderr2
-rw-r--r--src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs4
-rw-r--r--src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr22
-rw-r--r--src/test/ui/closures/issue-84044-drop-non-mut.rs6
-rw-r--r--src/test/ui/closures/issue-84044-drop-non-mut.stderr11
-rw-r--r--src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr2
-rw-r--r--src/test/ui/closures/print/closure-print-generic-verbose-2.stderr2
-rw-r--r--src/test/ui/coherence/auxiliary/option_future.rs8
-rw-r--r--src/test/ui/coherence/coherence-overlap-negative-trait2.rs18
-rw-r--r--src/test/ui/conditional-compilation/cfg-arg-invalid-1.rs2
-rw-r--r--src/test/ui/conditional-compilation/cfg-arg-invalid-1.stderr2
-rw-r--r--src/test/ui/conditional-compilation/cfg-arg-invalid-9.rs4
-rw-r--r--src/test/ui/conditional-compilation/cfg-arg-invalid-9.stderr2
-rw-r--r--src/test/ui/const-generics/defaults/pretty-printing-ast.stdout2
-rw-r--r--src/test/ui/consts/const-block-const-bound.rs4
-rw-r--r--src/test/ui/consts/const-block-const-bound.stderr22
-rw-r--r--src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs3
-rw-r--r--src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr2
-rw-r--r--src/test/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs16
-rw-r--r--src/test/ui/consts/const-eval/heap/dealloc_intrinsic.rs36
-rw-r--r--src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs22
-rw-r--r--src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr15
-rw-r--r--src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs13
-rw-r--r--src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr9
-rw-r--r--src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs29
-rw-r--r--src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr27
-rw-r--r--src/test/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs17
-rw-r--r--src/test/ui/consts/miri_unleashed/tls.stderr4
-rw-r--r--src/test/ui/fmt/ifmt-unimpl.stderr5
-rw-r--r--src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr2
-rw-r--r--src/test/ui/generator/drop-control-flow.rs4
-rw-r--r--src/test/ui/generator/issue-57478.rs4
-rw-r--r--src/test/ui/generator/issue-93161.rs93
-rw-r--r--src/test/ui/generator/partial-drop.rs4
-rw-r--r--src/test/ui/generator/print/generator-print-verbose-1.stderr10
-rw-r--r--src/test/ui/generic-associated-types/elided-in-expr-position.rs38
-rw-r--r--src/test/ui/generic-associated-types/elided-in-expr-position.stderr35
-rw-r--r--src/test/ui/generic-associated-types/issue-92954.rs10
-rw-r--r--src/test/ui/generic-associated-types/issue-93141.rs25
-rw-r--r--src/test/ui/generic-associated-types/issue-93340.rs20
-rw-r--r--src/test/ui/intrinsics/const-eval-select-bad.rs4
-rw-r--r--src/test/ui/intrinsics/const-eval-select-bad.stderr13
-rw-r--r--src/test/ui/issues/issue-16683.nll.stderr13
-rw-r--r--src/test/ui/issues/issue-17758.nll.stderr13
-rw-r--r--src/test/ui/issues/issue-47377.stderr5
-rw-r--r--src/test/ui/issues/issue-47380.stderr5
-rw-r--r--src/test/ui/issues/issue-5100.stderr6
-rw-r--r--src/test/ui/issues/issue-52213.nll.stderr2
-rw-r--r--src/test/ui/issues/issue-69455.stderr10
-rw-r--r--src/test/ui/lint/lint-unconditional-recursion.rs42
-rw-r--r--src/test/ui/lint/lint-unconditional-recursion.stderr46
-rw-r--r--src/test/ui/match/issue-82392.stdout18
-rw-r--r--src/test/ui/match/match-ref-mut-invariance.nll.stderr2
-rw-r--r--src/test/ui/match/match-ref-mut-let-invariance.nll.stderr2
-rw-r--r--src/test/ui/mismatched_types/overloaded-calls-bad.rs1
-rw-r--r--src/test/ui/mismatched_types/overloaded-calls-bad.stderr8
-rw-r--r--src/test/ui/nll/issue-52113.stderr2
-rw-r--r--src/test/ui/nll/issue-55394.nll.stderr2
-rw-r--r--src/test/ui/nll/issue-67007-escaping-data.rs2
-rw-r--r--src/test/ui/nll/issue-67007-escaping-data.stderr13
-rw-r--r--src/test/ui/nll/mir_check_cast_closure.stderr2
-rw-r--r--src/test/ui/nll/outlives-suggestion-more.stderr6
-rw-r--r--src/test/ui/nll/outlives-suggestion-simple.rs2
-rw-r--r--src/test/ui/nll/outlives-suggestion-simple.stderr22
-rw-r--r--src/test/ui/nll/ty-outlives/impl-trait-captures.stderr6
-rw-r--r--src/test/ui/nll/type-alias-free-regions.nll.stderr4
-rw-r--r--src/test/ui/nll/type-check-pointer-coercions.stderr14
-rw-r--r--src/test/ui/nll/user-annotations/wf-self-type.stderr2
-rw-r--r--src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr2
-rw-r--r--src/test/ui/parser/issues/issue-93282.rs4
-rw-r--r--src/test/ui/parser/issues/issue-93282.stderr13
-rw-r--r--src/test/ui/proc-macro/cfg-eval-inner.stdout8
-rw-r--r--src/test/ui/proc-macro/issue-73933-procedural-masquerade.rs9
-rw-r--r--src/test/ui/proc-macro/issue-73933-procedural-masquerade.stderr65
-rw-r--r--src/test/ui/proc-macro/issue-73933-procedural-masquerade.stdout4
-rw-r--r--src/test/ui/proc-macro/issue-75930-derive-cfg.stderr14
-rw-r--r--src/test/ui/proc-macro/issue-75930-derive-cfg.stdout50
-rw-r--r--src/test/ui/proc-macro/macro-rules-derive-cfg.stdout8
-rw-r--r--src/test/ui/proc-macro/quote-debug.stdout44
-rw-r--r--src/test/ui/reachable/expr_unary.rs4
-rw-r--r--src/test/ui/reachable/expr_unary.stderr10
-rw-r--r--src/test/ui/recursion/issue-83150.rs2
-rw-r--r--src/test/ui/recursion/issue-83150.stderr13
-rw-r--r--src/test/ui/regions/region-object-lifetime-2.nll.stderr2
-rw-r--r--src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr2
-rw-r--r--src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr14
-rw-r--r--src/test/ui/regions/regions-bounds.nll.stderr4
-rw-r--r--src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr2
-rw-r--r--src/test/ui/regions/regions-creating-enums4.nll.stderr2
-rw-r--r--src/test/ui/regions/regions-early-bound-error-method.nll.stderr2
-rw-r--r--src/test/ui/regions/regions-free-region-ordering-incorrect.nll.stderr2
-rw-r--r--src/test/ui/regions/regions-infer-not-param.nll.stderr4
-rw-r--r--src/test/ui/regions/regions-trait-object-subtyping.nll.stderr4
-rw-r--r--src/test/ui/rfc-2294-if-let-guard/feature-gate.rs13
-rw-r--r--src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr72
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/issue-93150.rs8
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/issue-93150.stderr22
-rw-r--r--src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs4
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs4
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr13
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr9
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr78
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs4
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr78
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/const-drop.rs31
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs2
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr13
-rw-r--r--src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr26
-rw-r--r--src/test/ui/rust-2018/edition-lint-nested-empty-paths.fixed14
-rw-r--r--src/test/ui/rust-2018/edition-lint-nested-empty-paths.rs14
-rw-r--r--src/test/ui/rust-2018/edition-lint-nested-empty-paths.stderr69
-rw-r--r--src/test/ui/rust-2018/edition-lint-nested-paths.fixed10
-rw-r--r--src/test/ui/rust-2018/edition-lint-nested-paths.rs10
-rw-r--r--src/test/ui/rust-2018/edition-lint-nested-paths.stderr49
-rw-r--r--src/test/ui/rust-2018/edition-lint-paths.fixed13
-rw-r--r--src/test/ui/rust-2018/edition-lint-paths.rs13
-rw-r--r--src/test/ui/rust-2018/edition-lint-paths.stderr59
-rw-r--r--src/test/ui/rust-2018/extern-crate-rename.fixed2
-rw-r--r--src/test/ui/rust-2018/extern-crate-rename.rs2
-rw-r--r--src/test/ui/rust-2018/extern-crate-rename.stderr11
-rw-r--r--src/test/ui/rust-2018/extern-crate-submod.fixed3
-rw-r--r--src/test/ui/rust-2018/extern-crate-submod.rs3
-rw-r--r--src/test/ui/rust-2018/extern-crate-submod.stderr11
-rw-r--r--src/test/ui/save-analysis/issue-89066.rs28
-rw-r--r--src/test/ui/save-analysis/issue-89066.stderr39
-rw-r--r--src/test/ui/span/issue-39018.stderr53
-rw-r--r--src/test/ui/specialization/min_specialization/repeated_projection_type.stderr2
-rw-r--r--src/test/ui/str/str-concat-on-double-ref.stderr5
-rw-r--r--src/test/ui/suggestions/args-instead-of-tuple-errors.rs16
-rw-r--r--src/test/ui/suggestions/args-instead-of-tuple-errors.stderr33
-rw-r--r--src/test/ui/suggestions/args-instead-of-tuple.fixed27
-rw-r--r--src/test/ui/suggestions/args-instead-of-tuple.rs27
-rw-r--r--src/test/ui/suggestions/args-instead-of-tuple.stderr84
-rw-r--r--src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr3
-rw-r--r--src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr3
-rw-r--r--src/test/ui/suggestions/private-field.rs19
-rw-r--r--src/test/ui/suggestions/private-field.stderr11
-rw-r--r--src/test/ui/symbol-names/basic.legacy.stderr4
-rw-r--r--src/test/ui/symbol-names/basic.v0.stderr2
-rw-r--r--src/test/ui/symbol-names/foreign-types.stderr2
-rw-r--r--src/test/ui/symbol-names/impl1.legacy.stderr12
-rw-r--r--src/test/ui/symbol-names/impl1.v0.stderr6
-rw-r--r--src/test/ui/symbol-names/issue-60925.legacy.stderr4
-rw-r--r--src/test/ui/symbol-names/issue-60925.v0.stderr2
-rw-r--r--src/test/ui/symbol-names/issue-75326.legacy.stderr4
-rw-r--r--src/test/ui/symbol-names/issue-75326.v0.stderr2
-rw-r--r--src/test/ui/symbol-names/trait-objects.v0.stderr6
-rw-r--r--src/test/ui/terminal-width/non-1-width-unicode-multiline-label.stderr5
-rw-r--r--src/test/ui/thir-tree.stdout4
-rw-r--r--src/test/ui/traits/issue-91594.rs17
-rw-r--r--src/test/ui/traits/issue-91594.stderr17
-rw-r--r--src/test/ui/tuple/array-diagnostics.rs7
-rw-r--r--src/test/ui/tuple/array-diagnostics.stderr9
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-60662.stdout4
-rw-r--r--src/test/ui/variance/variance-contravariant-arg-object.nll.stderr4
-rw-r--r--src/test/ui/variance/variance-covariant-arg-object.nll.stderr4
-rw-r--r--src/test/ui/variance/variance-invariant-arg-object.nll.stderr4
-rw-r--r--src/test/ui/variance/variance-use-contravariant-struct-1.nll.stderr2
-rw-r--r--src/test/ui/variance/variance-use-covariant-struct-1.nll.stderr2
-rw-r--r--src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr4
-rw-r--r--src/test/ui/wf/wf-static-method.nll.stderr10
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/CHANGELOG.md3
-rw-r--r--src/tools/clippy/clippy_dev/src/bless.rs7
-rw-r--r--src/tools/clippy/clippy_dev/src/lint.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/approx_const.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/as_conversions.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs199
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/else_if_without_else.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_variants.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/eq_op.rs69
-rw-r--r--src/tools/clippy/clippy_lints/src/formatting.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/from_over_into.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_hasher.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/index_refutable_slice.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/items_after_statements.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_all.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_complexity.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_bits.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/map_clone.rs64
-rw-r--r--src/tools/clippy/clippy_lints/src/matches.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/mem_replace.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/module_style.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_question_mark.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/non_expressive_names.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/octal_escapes.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs613
-rw-r--r--src/tools/clippy/clippy_lints/src/ranges.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_closure_call.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_else.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_field_names.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/reference.rs57
-rw-r--r--src/tools/clippy/clippy_lints/src/same_name_method.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/single_component_path_imports.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/trait_bounds.rs58
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs10
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs52
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs22
-rw-r--r--src/tools/clippy/clippy_utils/src/numeric_literal.rs9
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs113
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/src/driver.rs3
-rw-r--r--src/tools/clippy/tests/compile-test.rs8
-rw-r--r--src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs24
-rw-r--r--src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.stderr10
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs6
-rw-r--r--src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr28
-rw-r--r--src/tools/clippy/tests/ui/bytecount.rs2
-rw-r--r--src/tools/clippy/tests/ui/bytecount.stderr8
-rw-r--r--src/tools/clippy/tests/ui/clone_on_copy.fixed3
-rw-r--r--src/tools/clippy/tests/ui/clone_on_copy.rs3
-rw-r--r--src/tools/clippy/tests/ui/clone_on_copy.stderr16
-rw-r--r--src/tools/clippy/tests/ui/duration_subsec.fixed2
-rw-r--r--src/tools/clippy/tests/ui/duration_subsec.rs2
-rw-r--r--src/tools/clippy/tests/ui/enum_variants.rs7
-rw-r--r--src/tools/clippy/tests/ui/eta.fixed9
-rw-r--r--src/tools/clippy/tests/ui/eta.rs7
-rw-r--r--src/tools/clippy/tests/ui/eta.stderr50
-rw-r--r--src/tools/clippy/tests/ui/explicit_deref_methods.fixed2
-rw-r--r--src/tools/clippy/tests/ui/explicit_deref_methods.rs2
-rw-r--r--src/tools/clippy/tests/ui/for_loop_fixable.fixed7
-rw-r--r--src/tools/clippy/tests/ui/for_loop_fixable.rs7
-rw-r--r--src/tools/clippy/tests/ui/for_loop_fixable.stderr30
-rw-r--r--src/tools/clippy/tests/ui/format.fixed7
-rw-r--r--src/tools/clippy/tests/ui/format.rs7
-rw-r--r--src/tools/clippy/tests/ui/format.stderr34
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.fixed27
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.rs27
-rw-r--r--src/tools/clippy/tests/ui/needless_borrow.stderr76
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.rs51
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.stderr94
-rw-r--r--src/tools/clippy/tests/ui/needless_question_mark.fixed13
-rw-r--r--src/tools/clippy/tests/ui/needless_question_mark.rs13
-rw-r--r--src/tools/clippy/tests/ui/needless_question_mark.stderr14
-rw-r--r--src/tools/clippy/tests/ui/op_ref.rs39
-rw-r--r--src/tools/clippy/tests/ui/op_ref.stderr18
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.rs29
-rw-r--r--src/tools/clippy/tests/ui/ptr_arg.stderr158
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed2
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs2
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed1
-rw-r--r--src/tools/clippy/tests/ui/rename.rs1
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr26
-rw-r--r--src/tools/clippy/tests/ui/search_is_some_fixable_none.rs2
-rw-r--r--src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr10
-rw-r--r--src/tools/clippy/tests/ui/search_is_some_fixable_some.rs2
-rw-r--r--src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr10
-rw-r--r--src/tools/clippy/tests/ui/slow_vector_initialization.rs2
-rw-r--r--src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs22
-rw-r--r--src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr24
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.rs7
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_cast.stderr38
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_ref.fixed23
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_ref.rs23
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_ref.stderr22
-rw-r--r--src/tools/clippy/tests/ui/useless_asref.fixed2
-rw-r--r--src/tools/clippy/tests/ui/useless_asref.rs2
-rw-r--r--src/tools/clippy/tests/ui/write_literal.rs48
-rw-r--r--src/tools/clippy/tests/ui/write_literal.stderr110
-rw-r--r--src/tools/clippy/tests/ui/write_literal_2.rs16
-rw-r--r--src/tools/clippy/tests/ui/write_literal_2.stderr50
-rw-r--r--src/tools/clippy/tests/ui/write_with_newline.rs56
-rw-r--r--src/tools/clippy/tests/ui/write_with_newline.stderr72
-rw-r--r--src/tools/clippy/tests/ui/writeln_empty_string.fixed10
-rw-r--r--src/tools/clippy/tests/ui/writeln_empty_string.rs10
-rw-r--r--src/tools/clippy/tests/ui/writeln_empty_string.stderr12
-rw-r--r--src/tools/clippy/util/gh-pages/index.html5
-rw-r--r--src/tools/compiletest/src/runtest.rs97
715 files changed, 12472 insertions, 6890 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index cf85591ac01..e97cd29bba5 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -290,8 +290,8 @@ jobs:
             os: ubuntu-20.04-xl
           - name: dist-x86_64-apple
             env:
-              SCRIPT: "./x.py dist --exclude rust-docs --exclude extended && ./x.py dist --target=x86_64-apple-darwin rust-docs && ./x.py dist extended"
-              RUST_CONFIGURE_ARGS: "--host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+              SCRIPT: "./x.py dist --host=x86_64-apple-darwin --target=x86_64-apple-darwin"
+              RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.7
               NO_LLVM_ASSERTIONS: 1
@@ -299,6 +299,16 @@ jobs:
               NO_OVERFLOW_CHECKS: 1
               DIST_REQUIRE_ALL_TOOLS: 1
             os: macos-latest
+          - name: dist-apple-various
+            env:
+              SCRIPT: "./x.py dist --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim"
+              RUST_CONFIGURE_ARGS: "--enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false"
+              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+              MACOSX_DEPLOYMENT_TARGET: 10.7
+              NO_LLVM_ASSERTIONS: 1
+              NO_DEBUG_ASSERTIONS: 1
+              NO_OVERFLOW_CHECKS: 1
+            os: macos-latest
           - name: dist-x86_64-apple-alt
             env:
               SCRIPT: "./x.py dist"
diff --git a/Cargo.lock b/Cargo.lock
index 1e7c9ee029b..b05351a1e96 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -379,7 +379,7 @@ dependencies = [
  "tar",
  "tempfile",
  "termcolor",
- "toml",
+ "toml_edit",
  "unicode-width",
  "unicode-xid",
  "url 2.2.2",
@@ -465,7 +465,7 @@ dependencies = [
  "serde_json",
  "tar",
  "termcolor",
- "toml",
+ "toml_edit",
  "url 2.2.2",
 ]
 
@@ -689,7 +689,7 @@ dependencies = [
  "clippy_utils",
  "if_chain",
  "itertools 0.10.1",
- "pulldown-cmark 0.9.0",
+ "pulldown-cmark",
  "quine-mc_cluskey",
  "regex-syntax",
  "rustc-semver",
@@ -732,6 +732,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "combine"
+version = "4.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "50b727aacc797f9fc28e355d21f34709ac4fc9adecfe470ad07b8f4464f53062"
+dependencies = [
+ "bytes",
+ "memchr",
+]
+
+[[package]]
 name = "commoncrypto"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1463,7 +1473,7 @@ checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
 dependencies = [
  "cfg-if 0.1.10",
  "libc",
- "wasi",
+ "wasi 0.9.0+wasi-snapshot-preview1",
 ]
 
 [[package]]
@@ -1474,7 +1484,7 @@ checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4"
 dependencies = [
  "cfg-if 0.1.10",
  "libc",
- "wasi",
+ "wasi 0.9.0+wasi-snapshot-preview1",
 ]
 
 [[package]]
@@ -1587,6 +1597,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
 dependencies = [
  "ahash",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c21d40587b92fa6a6c6e3c1bdbf87d75511db5672f9c93175574b3a00df1758"
+dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
@@ -1731,12 +1749,13 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "1.7.0"
+version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
+checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
 dependencies = [
  "autocfg",
- "hashbrown",
+ "hashbrown 0.11.2",
+ "rustc-rayon",
  "serde",
 ]
 
@@ -1945,6 +1964,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "kstring"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b310ccceade8121d7d77fee406160e457c2f4e7c7982d589da3499bc7ea4526"
+dependencies = [
+ "serde",
+]
+
+[[package]]
 name = "lazy_static"
 version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1958,9 +1986,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
 
 [[package]]
 name = "libc"
-version = "0.2.108"
+version = "0.2.116"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8521a1b57e76b1ec69af7599e75e38e7b7fad6610f037db8c79b127201b5d119"
+checksum = "565dbd88872dbe4cc8a46e527f26483c1d1f7afa6b884a3bd6cd893d4f98da74"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -2186,9 +2214,9 @@ dependencies = [
 
 [[package]]
 name = "mdbook"
-version = "0.4.14"
+version = "0.4.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6e77253c46a90eb7e96b2807201dab941a4db5ea05eca5aaaf7027395f352b3"
+checksum = "241f10687eb3b4e0634b3b4e423f97c5f1efbd69dc9522e24a8b94583eeec3c6"
 dependencies = [
  "ammonia",
  "anyhow",
@@ -2201,7 +2229,7 @@ dependencies = [
  "log",
  "memchr",
  "opener",
- "pulldown-cmark 0.8.0",
+ "pulldown-cmark",
  "regex",
  "serde",
  "serde_derive",
@@ -2270,9 +2298,9 @@ dependencies = [
 
 [[package]]
 name = "minifier"
-version = "0.0.41"
+version = "0.0.42"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5594542d20834f2b974f5e5fb8e0cf1c67a2119dcadc29ef5d93a081fb30cc08"
+checksum = "55a1388517eda8a68875243b650c26997e055a33d82571b5a0349129faef7d99"
 dependencies = [
  "macro-utils",
 ]
@@ -2411,7 +2439,7 @@ checksum = "7ce8b38d41f9f3618fc23f908faae61510f8d8ce2d99cbe910641e8f1971f084"
 dependencies = [
  "crc32fast",
  "flate2",
- "hashbrown",
+ "hashbrown 0.11.2",
  "indexmap",
  "memchr",
 ]
@@ -2865,9 +2893,9 @@ dependencies = [
 
 [[package]]
 name = "pulldown-cmark"
-version = "0.8.0"
+version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8"
+checksum = "34f197a544b0c9ab3ae46c359a7ec9cbbb5c7bf97054266fecb7ead794a181d6"
 dependencies = [
  "bitflags",
  "getopts",
@@ -2876,17 +2904,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "pulldown-cmark"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acd16514d1af5f7a71f909a44ef253cdb712a376d7ebc8ae4a471a9be9743548"
-dependencies = [
- "bitflags",
- "memchr",
- "unicase",
-]
-
-[[package]]
 name = "punycode"
 version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3302,7 +3319,6 @@ dependencies = [
  "rustc_codegen_ssa",
  "rustc_driver",
  "tikv-jemalloc-sys",
- "tikv-jemallocator",
 ]
 
 [[package]]
@@ -4440,7 +4456,7 @@ dependencies = [
  "expect-test",
  "itertools 0.9.0",
  "minifier",
- "pulldown-cmark 0.9.0",
+ "pulldown-cmark",
  "rayon",
  "regex",
  "rustdoc-json-types",
@@ -4825,7 +4841,7 @@ dependencies = [
  "core",
  "dlmalloc",
  "fortanix-sgx-abi",
- "hashbrown",
+ "hashbrown 0.12.0",
  "hermit-abi",
  "libc",
  "miniz_oxide",
@@ -4837,7 +4853,7 @@ dependencies = [
  "rustc-demangle",
  "std_detect",
  "unwind",
- "wasi",
+ "wasi 0.11.0+wasi-snapshot-preview1",
 ]
 
 [[package]]
@@ -5107,7 +5123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dd95b4559c196987c8451b4e14d08a4c796c2844f9adf4d2a2dbc9b3142843be"
 dependencies = [
  "gimli 0.26.1",
- "hashbrown",
+ "hashbrown 0.11.2",
  "object 0.28.1",
  "tracing",
 ]
@@ -5148,16 +5164,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "tikv-jemallocator"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c14a5a604eb8715bc5785018a37d00739b180bcf609916ddf4393d33d49ccdf"
-dependencies = [
- "libc",
- "tikv-jemalloc-sys",
-]
-
-[[package]]
 name = "time"
 version = "0.1.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5226,6 +5232,19 @@ dependencies = [
 ]
 
 [[package]]
+name = "toml_edit"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b80ac5e1b91e3378c63dab121962472b5ca20cf9ab1975e3d588548717807a8"
+dependencies = [
+ "combine",
+ "indexmap",
+ "itertools 0.10.1",
+ "kstring",
+ "serde",
+]
+
+[[package]]
 name = "topological-sort"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5582,6 +5601,12 @@ name = "wasi"
 version = "0.9.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-alloc",
diff --git a/RELEASES.md b/RELEASES.md
index f44291c1fa3..aae2a669650 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -7,7 +7,7 @@ Version 1.58.1 (2022-01-19)
 * [Fix wrong error message displayed when some imports are missing][91254]
 * [Fix rustfmt not formatting generated files from stdin][92912]
 
-[CVE-2022-21658]: https://www.cve.org/CVERecord?id=CVE-2022-21658]
+[CVE-2022-21658]: https://www.cve.org/CVERecord?id=CVE-2022-21658
 [91254]: https://github.com/rust-lang/rust/pull/91254
 [92912]: https://github.com/rust-lang/rust/pull/92912
 [clippy/8075]: https://github.com/rust-lang/rust-clippy/pull/8075
diff --git a/compiler/rustc/Cargo.toml b/compiler/rustc/Cargo.toml
index 277cf0f51d3..696c003a587 100644
--- a/compiler/rustc/Cargo.toml
+++ b/compiler/rustc/Cargo.toml
@@ -15,11 +15,7 @@ version = '0.4.0'
 optional = true
 features = ['unprefixed_malloc_on_supported_platforms']
 
-[dependencies.tikv-jemallocator]
-version = '0.4.0'
-optional = true
-
 [features]
-jemalloc = ['tikv-jemalloc-sys', 'tikv-jemallocator']
+jemalloc = ['tikv-jemalloc-sys']
 llvm = ['rustc_driver/llvm']
 max_level_info = ['rustc_driver/max_level_info']
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index 6f9ecb9cd21..3928d70c0ed 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -45,24 +45,24 @@ pub struct TypedArena<T> {
     end: Cell<*mut T>,
 
     /// A vector of arena chunks.
-    chunks: RefCell<Vec<TypedArenaChunk<T>>>,
+    chunks: RefCell<Vec<ArenaChunk<T>>>,
 
     /// Marker indicating that dropping the arena causes its owned
     /// instances of `T` to be dropped.
     _own: PhantomData<T>,
 }
 
-struct TypedArenaChunk<T> {
+struct ArenaChunk<T = u8> {
     /// The raw storage for the arena chunk.
     storage: Box<[MaybeUninit<T>]>,
     /// The number of valid entries in the chunk.
     entries: usize,
 }
 
-impl<T> TypedArenaChunk<T> {
+impl<T> ArenaChunk<T> {
     #[inline]
-    unsafe fn new(capacity: usize) -> TypedArenaChunk<T> {
-        TypedArenaChunk { storage: Box::new_uninit_slice(capacity), entries: 0 }
+    unsafe fn new(capacity: usize) -> ArenaChunk<T> {
+        ArenaChunk { storage: Box::new_uninit_slice(capacity), entries: 0 }
     }
 
     /// Destroys this arena chunk.
@@ -125,6 +125,11 @@ impl<I, T> IterExt<T> for I
 where
     I: IntoIterator<Item = T>,
 {
+    // This default collects into a `SmallVec` and then allocates by copying
+    // from it. The specializations below for types like `Vec` are more
+    // efficient, copying directly without the intermediate collecting step.
+    // This default could be made more efficient, like
+    // `DroplessArena::alloc_from_iter`, but it's not hot enough to bother.
     #[inline]
     default fn alloc_from_iter(self, arena: &TypedArena<T>) -> &mut [T] {
         let vec: SmallVec<[_; 8]> = self.into_iter().collect();
@@ -139,7 +144,7 @@ impl<T, const N: usize> IterExt<T> for std::array::IntoIter<T, N> {
         if len == 0 {
             return &mut [];
         }
-        // Move the content to the arena by copying and then forgetting it
+        // Move the content to the arena by copying and then forgetting it.
         unsafe {
             let start_ptr = arena.alloc_raw_slice(len);
             self.as_slice().as_ptr().copy_to_nonoverlapping(start_ptr, len);
@@ -156,7 +161,7 @@ impl<T> IterExt<T> for Vec<T> {
         if len == 0 {
             return &mut [];
         }
-        // Move the content to the arena by copying and then forgetting it
+        // Move the content to the arena by copying and then forgetting it.
         unsafe {
             let start_ptr = arena.alloc_raw_slice(len);
             self.as_ptr().copy_to_nonoverlapping(start_ptr, len);
@@ -173,7 +178,7 @@ impl<A: smallvec::Array> IterExt<A::Item> for SmallVec<A> {
         if len == 0 {
             return &mut [];
         }
-        // Move the content to the arena by copying and then forgetting it
+        // Move the content to the arena by copying and then forgetting it.
         unsafe {
             let start_ptr = arena.alloc_raw_slice(len);
             self.as_ptr().copy_to_nonoverlapping(start_ptr, len);
@@ -272,7 +277,7 @@ impl<T> TypedArena<T> {
             // Also ensure that this chunk can fit `additional`.
             new_cap = cmp::max(additional, new_cap);
 
-            let mut chunk = TypedArenaChunk::<T>::new(new_cap);
+            let mut chunk = ArenaChunk::<T>::new(new_cap);
             self.ptr.set(chunk.start());
             self.end.set(chunk.end());
             chunks.push(chunk);
@@ -281,7 +286,7 @@ impl<T> TypedArena<T> {
 
     // Drops the contents of the last chunk. The last chunk is partially empty, unlike all other
     // chunks.
-    fn clear_last_chunk(&self, last_chunk: &mut TypedArenaChunk<T>) {
+    fn clear_last_chunk(&self, last_chunk: &mut ArenaChunk<T>) {
         // Determine how much was filled.
         let start = last_chunk.start() as usize;
         // We obtain the value of the pointer to the first uninitialized element.
@@ -340,7 +345,7 @@ pub struct DroplessArena {
     end: Cell<*mut u8>,
 
     /// A vector of arena chunks.
-    chunks: RefCell<Vec<TypedArenaChunk<u8>>>,
+    chunks: RefCell<Vec<ArenaChunk>>,
 }
 
 unsafe impl Send for DroplessArena {}
@@ -378,7 +383,7 @@ impl DroplessArena {
             // Also ensure that this chunk can fit `additional`.
             new_cap = cmp::max(additional, new_cap);
 
-            let mut chunk = TypedArenaChunk::<u8>::new(new_cap);
+            let mut chunk = ArenaChunk::new(new_cap);
             self.start.set(chunk.start());
             self.end.set(chunk.end());
             chunks.push(chunk);
@@ -520,10 +525,19 @@ impl DroplessArena {
     }
 }
 
-// Declare an `Arena` containing one dropless arena and many typed arenas (the
-// types of the typed arenas are specified by the arguments). The dropless
-// arena will be used for any types that impl `Copy`, and also for any of the
-// specified types that satisfy `!mem::needs_drop`.
+/// Declare an `Arena` containing one dropless arena and many typed arenas (the
+/// types of the typed arenas are specified by the arguments).
+///
+/// There are three cases of interest.
+/// - Types that are `Copy`: these need not be specified in the arguments. They
+///   will use the `DroplessArena`.
+/// - Types that are `!Copy` and `!Drop`: these must be specified in the
+///   arguments. An empty `TypedArena` will be created for each one, but the
+///   `DroplessArena` will always be used and the `TypedArena` will stay empty.
+///   This is odd but harmless, because an empty arena allocates no memory.
+/// - Types that are `!Copy` and `Drop`: these must be specified in the
+///   arguments. The `TypedArena` will be used for them.
+///
 #[rustc_macro_transparency = "semitransparent"]
 pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
     #[derive(Default)]
@@ -532,7 +546,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
         $($name: $crate::TypedArena<$ty>,)*
     }
 
-    pub trait ArenaAllocatable<'tcx, T = Self>: Sized {
+    pub trait ArenaAllocatable<'tcx, C = rustc_arena::IsNotCopy>: Sized {
         fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self;
         fn allocate_from_iter<'a>(
             arena: &'a Arena<'tcx>,
@@ -541,7 +555,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
     }
 
     // Any type that impls `Copy` can be arena-allocated in the `DroplessArena`.
-    impl<'tcx, T: Copy> ArenaAllocatable<'tcx, ()> for T {
+    impl<'tcx, T: Copy> ArenaAllocatable<'tcx, rustc_arena::IsCopy> for T {
         #[inline]
         fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
             arena.dropless.alloc(self)
@@ -555,7 +569,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
         }
     }
     $(
-        impl<'tcx> ArenaAllocatable<'tcx, $ty> for $ty {
+        impl<'tcx> ArenaAllocatable<'tcx, rustc_arena::IsNotCopy> for $ty {
             #[inline]
             fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self {
                 if !::std::mem::needs_drop::<Self>() {
@@ -581,7 +595,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
 
     impl<'tcx> Arena<'tcx> {
         #[inline]
-        pub fn alloc<T: ArenaAllocatable<'tcx, U>, U>(&self, value: T) -> &mut T {
+        pub fn alloc<T: ArenaAllocatable<'tcx, C>, C>(&self, value: T) -> &mut T {
             value.allocate_on(self)
         }
 
@@ -594,7 +608,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
             self.dropless.alloc_slice(value)
         }
 
-        pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx, U>, U>(
+        pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx, C>, C>(
             &'a self,
             iter: impl ::std::iter::IntoIterator<Item = T>,
         ) -> &'a mut [T] {
@@ -603,5 +617,10 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
     }
 }
 
+// Marker types that let us give different behaviour for arenas allocating
+// `Copy` types vs `!Copy` types.
+pub struct IsCopy;
+pub struct IsNotCopy;
+
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 438168f4fcc..7c19559ed91 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2418,8 +2418,9 @@ impl<S: Encoder> rustc_serialize::Encodable<S> for AttrId {
 }
 
 impl<D: Decoder> rustc_serialize::Decodable<D> for AttrId {
-    fn decode(d: &mut D) -> Result<AttrId, D::Error> {
-        d.read_nil().map(|_| crate::attr::mk_attr_id())
+    fn decode(d: &mut D) -> AttrId {
+        d.read_unit();
+        crate::attr::mk_attr_id()
     }
 }
 
diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs
index 9fe87a0a637..70dbda82224 100644
--- a/compiler/rustc_ast/src/ptr.rs
+++ b/compiler/rustc_ast/src/ptr.rs
@@ -115,8 +115,8 @@ impl<T> fmt::Pointer for P<T> {
 }
 
 impl<D: Decoder, T: 'static + Decodable<D>> Decodable<D> for P<T> {
-    fn decode(d: &mut D) -> Result<P<T>, D::Error> {
-        Decodable::decode(d).map(P)
+    fn decode(d: &mut D) -> P<T> {
+        P(Decodable::decode(d))
     }
 }
 
@@ -204,8 +204,8 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for P<[T]> {
 }
 
 impl<D: Decoder, T: Decodable<D>> Decodable<D> for P<[T]> {
-    fn decode(d: &mut D) -> Result<P<[T]>, D::Error> {
-        Ok(P::from_vec(Decodable::decode(d)?))
+    fn decode(d: &mut D) -> P<[T]> {
+        P::from_vec(Decodable::decode(d))
     }
 }
 
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 51cabb50cd3..2174378a560 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -163,7 +163,7 @@ impl<S: Encoder> Encodable<S> for LazyTokenStream {
 }
 
 impl<D: Decoder> Decodable<D> for LazyTokenStream {
-    fn decode(_d: &mut D) -> Result<Self, D::Error> {
+    fn decode(_d: &mut D) -> Self {
         panic!("Attempted to decode LazyTokenStream");
     }
 }
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index f04dc85b28a..17bc8d7591b 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -625,18 +625,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
     ///     }
     /// }
     /// ```
-    fn lower_expr_await(&mut self, await_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
-        let dot_await_span = expr.span.shrink_to_hi().to(await_span);
+    fn lower_expr_await(&mut self, dot_await_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
+        let full_span = expr.span.to(dot_await_span);
         match self.generator_kind {
             Some(hir::GeneratorKind::Async(_)) => {}
             Some(hir::GeneratorKind::Gen) | None => {
                 let mut err = struct_span_err!(
                     self.sess,
-                    await_span,
+                    dot_await_span,
                     E0728,
                     "`await` is only allowed inside `async` functions and blocks"
                 );
-                err.span_label(await_span, "only allowed inside `async` functions and blocks");
+                err.span_label(dot_await_span, "only allowed inside `async` functions and blocks");
                 if let Some(item_sp) = self.current_item {
                     err.span_label(item_sp, "this is not `async`");
                 }
@@ -646,7 +646,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let span = self.mark_span_with_reason(DesugaringKind::Await, dot_await_span, None);
         let gen_future_span = self.mark_span_with_reason(
             DesugaringKind::Await,
-            await_span,
+            full_span,
             self.allow_gen_future.clone(),
         );
         let expr = self.lower_expr_mut(expr);
@@ -699,9 +699,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let loop_hir_id = self.lower_node_id(loop_node_id);
         let ready_arm = {
             let x_ident = Ident::with_dummy_span(sym::result);
-            let (x_pat, x_pat_hid) = self.pat_ident(span, x_ident);
-            let x_expr = self.expr_ident(span, x_ident, x_pat_hid);
-            let ready_field = self.single_pat_field(span, x_pat);
+            let (x_pat, x_pat_hid) = self.pat_ident(gen_future_span, x_ident);
+            let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid);
+            let ready_field = self.single_pat_field(gen_future_span, x_pat);
             let ready_pat = self.pat_lang_item_variant(
                 span,
                 hir::LangItem::PollReady,
@@ -711,7 +711,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             let break_x = self.with_loop_scope(loop_node_id, move |this| {
                 let expr_break =
                     hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr));
-                this.arena.alloc(this.expr(span, expr_break, ThinVec::new()))
+                this.arena.alloc(this.expr(gen_future_span, expr_break, ThinVec::new()))
             });
             self.arm(ready_pat, break_x)
         };
@@ -783,7 +783,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         // `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
         let into_future_span = self.mark_span_with_reason(
             DesugaringKind::Await,
-            await_span,
+            dot_await_span,
             self.allow_into_future.clone(),
         );
         let into_future_expr = self.expr_call_lang_item_fn(
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 47b61067055..32cec3a295a 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -479,6 +479,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let attrs = std::mem::take(&mut self.attrs);
         let mut bodies = std::mem::take(&mut self.bodies);
         let local_node_ids = std::mem::take(&mut self.local_node_ids);
+
+        let local_id_to_def_id = local_node_ids
+            .iter()
+            .filter_map(|&node_id| {
+                let hir_id = self.node_id_to_hir_id[node_id]?;
+                if hir_id.local_id == hir::ItemLocalId::new(0) {
+                    None
+                } else {
+                    let def_id = self.resolver.opt_local_def_id(node_id)?;
+                    Some((hir_id.local_id, def_id))
+                }
+            })
+            .collect();
+
         let trait_map = local_node_ids
             .into_iter()
             .filter_map(|node_id| {
@@ -501,7 +515,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let (hash_including_bodies, hash_without_bodies) = self.hash_owner(node, &bodies);
         let (nodes, parenting) =
             index::index_hir(self.sess, self.resolver.definitions(), node, &bodies);
-        let nodes = hir::OwnerNodes { hash_including_bodies, hash_without_bodies, nodes, bodies };
+        let nodes = hir::OwnerNodes {
+            hash_including_bodies,
+            hash_without_bodies,
+            nodes,
+            bodies,
+            local_id_to_def_id,
+        };
         let attrs = {
             let mut hcx = self.resolver.create_stable_hashing_context();
             let mut stable_hasher = StableHasher::new();
diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs
index 82c40868d18..e1f43cb20dc 100644
--- a/compiler/rustc_ast_pretty/src/pp.rs
+++ b/compiler/rustc_ast_pretty/src/pp.rs
@@ -147,6 +147,22 @@ pub enum Breaks {
 }
 
 #[derive(Clone, Copy)]
+enum IndentStyle {
+    /// Vertically aligned under whatever column this block begins at.
+    ///
+    ///     fn demo(arg1: usize,
+    ///             arg2: usize);
+    Visual,
+    /// Indented relative to the indentation level of the previous line.
+    ///
+    ///     fn demo(
+    ///         arg1: usize,
+    ///         arg2: usize,
+    ///     );
+    Block { offset: isize },
+}
+
+#[derive(Clone, Copy)]
 pub struct BreakToken {
     offset: isize,
     blank_space: isize,
@@ -154,7 +170,7 @@ pub struct BreakToken {
 
 #[derive(Clone, Copy)]
 pub struct BeginToken {
-    offset: isize,
+    indent: IndentStyle,
     breaks: Breaks,
 }
 
@@ -178,7 +194,7 @@ impl Token {
 #[derive(Copy, Clone)]
 enum PrintFrame {
     Fits,
-    Broken { offset: isize, breaks: Breaks },
+    Broken { indent: usize, breaks: Breaks },
 }
 
 const SIZE_INFINITY: isize = 0xffff;
@@ -204,6 +220,8 @@ pub struct Printer {
     scan_stack: VecDeque<usize>,
     /// Stack of blocks-in-progress being flushed by print
     print_stack: Vec<PrintFrame>,
+    /// Level of indentation of current line
+    indent: usize,
     /// Buffered indentation to avoid writing trailing whitespace
     pending_indentation: isize,
     /// The token most recently popped from the left boundary of the
@@ -229,6 +247,7 @@ impl Printer {
             right_total: 0,
             scan_stack: VecDeque::new(),
             print_stack: Vec::new(),
+            indent: 0,
             pending_indentation: 0,
             last_printed: None,
         }
@@ -368,38 +387,41 @@ impl Printer {
         *self
             .print_stack
             .last()
-            .unwrap_or(&PrintFrame::Broken { offset: 0, breaks: Breaks::Inconsistent })
+            .unwrap_or(&PrintFrame::Broken { indent: 0, breaks: Breaks::Inconsistent })
     }
 
     fn print_begin(&mut self, token: BeginToken, size: isize) {
         if size > self.space {
-            let col = self.margin - self.space + token.offset;
-            self.print_stack.push(PrintFrame::Broken { offset: col, breaks: token.breaks });
+            self.print_stack.push(PrintFrame::Broken { indent: self.indent, breaks: token.breaks });
+            self.indent = match token.indent {
+                IndentStyle::Block { offset } => (self.indent as isize + offset) as usize,
+                IndentStyle::Visual => (self.margin - self.space) as usize,
+            };
         } else {
             self.print_stack.push(PrintFrame::Fits);
         }
     }
 
     fn print_end(&mut self) {
-        self.print_stack.pop().unwrap();
+        if let PrintFrame::Broken { indent, .. } = self.print_stack.pop().unwrap() {
+            self.indent = indent;
+        }
     }
 
     fn print_break(&mut self, token: BreakToken, size: isize) {
-        let break_offset =
-            match self.get_top() {
-                PrintFrame::Fits => None,
-                PrintFrame::Broken { offset, breaks: Breaks::Consistent } => Some(offset),
-                PrintFrame::Broken { offset, breaks: Breaks::Inconsistent } => {
-                    if size > self.space { Some(offset) } else { None }
-                }
-            };
-        if let Some(offset) = break_offset {
-            self.out.push('\n');
-            self.pending_indentation = offset + token.offset;
-            self.space = self.margin - (offset + token.offset);
-        } else {
+        let fits = match self.get_top() {
+            PrintFrame::Fits => true,
+            PrintFrame::Broken { breaks: Breaks::Consistent, .. } => false,
+            PrintFrame::Broken { breaks: Breaks::Inconsistent, .. } => size <= self.space,
+        };
+        if fits {
             self.pending_indentation += token.blank_space;
             self.space -= token.blank_space;
+        } else {
+            self.out.push('\n');
+            let indent = self.indent as isize + token.offset;
+            self.pending_indentation = indent;
+            self.space = self.margin - indent;
         }
     }
 
@@ -422,7 +444,10 @@ impl Printer {
 
     /// "raw box"
     pub fn rbox(&mut self, indent: usize, breaks: Breaks) {
-        self.scan_begin(BeginToken { offset: indent as isize, breaks })
+        self.scan_begin(BeginToken {
+            indent: IndentStyle::Block { offset: indent as isize },
+            breaks,
+        })
     }
 
     /// Inconsistent breaking box
@@ -435,6 +460,10 @@ impl Printer {
         self.rbox(indent, Breaks::Consistent)
     }
 
+    pub fn visual_align(&mut self) {
+        self.scan_begin(BeginToken { indent: IndentStyle::Visual, breaks: Breaks::Consistent });
+    }
+
     pub fn break_offset(&mut self, n: usize, off: isize) {
         self.scan_break(BreakToken { offset: off, blank_space: n as isize })
     }
@@ -457,7 +486,7 @@ impl Printer {
         self.break_offset(n, 0)
     }
 
-    crate fn zerobreak(&mut self) {
+    pub fn zerobreak(&mut self) {
         self.spaces(0)
     }
 
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 1cbc3162d43..b575dc21961 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -315,7 +315,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
                     self.word(cmnt.lines[0].clone());
                     self.hardbreak()
                 } else {
-                    self.ibox(0);
+                    self.visual_align();
                     for line in &cmnt.lines {
                         if !line.is_empty() {
                             self.word(line.clone());
@@ -607,7 +607,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
         &mut self,
         macro_def: &ast::MacroDef,
         ident: &Ident,
-        sp: &Span,
+        sp: Span,
         print_visibility: impl FnOnce(&mut Self),
     ) {
         let (kw, has_bang) = if macro_def.macro_rules {
@@ -623,7 +623,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
             macro_def.body.delim(),
             &macro_def.body.inner_tokens(),
             true,
-            *sp,
+            sp,
         );
         if macro_def.body.need_semicolon() {
             self.word(";");
@@ -655,7 +655,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
         // Outer-box is consistent.
         self.cbox(INDENT_UNIT);
         // Head-box is inconsistent.
-        self.ibox(w.len() + 1);
+        self.ibox(0);
         // Keyword that starts the head.
         if !w.is_empty() {
             self.word_nbsp(w);
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 956200d60f5..6a5bba30b8b 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -320,7 +320,9 @@ impl<'a> State<'a> {
                     self.print_ident(label.ident);
                     self.word_space(":");
                 }
-                self.head("while");
+                self.cbox(0);
+                self.ibox(0);
+                self.word_nbsp("while");
                 self.print_expr_as_cond(test);
                 self.space();
                 self.print_block_with_attrs(blk, attrs);
@@ -330,7 +332,9 @@ impl<'a> State<'a> {
                     self.print_ident(label.ident);
                     self.word_space(":");
                 }
-                self.head("for");
+                self.cbox(0);
+                self.ibox(0);
+                self.word_nbsp("for");
                 self.print_pat(pat);
                 self.space();
                 self.word_space("in");
@@ -343,12 +347,14 @@ impl<'a> State<'a> {
                     self.print_ident(label.ident);
                     self.word_space(":");
                 }
-                self.head("loop");
+                self.cbox(0);
+                self.ibox(0);
+                self.word_nbsp("loop");
                 self.print_block_with_attrs(blk, attrs);
             }
             ast::ExprKind::Match(ref expr, ref arms) => {
-                self.cbox(INDENT_UNIT);
-                self.ibox(INDENT_UNIT);
+                self.cbox(0);
+                self.ibox(0);
                 self.word_nbsp("match");
                 self.print_expr_as_cond(expr);
                 self.space();
@@ -388,7 +394,7 @@ impl<'a> State<'a> {
                     self.word_space(":");
                 }
                 // containing cbox, will be closed by print-block at }
-                self.cbox(INDENT_UNIT);
+                self.cbox(0);
                 // head-box, will be closed by print-block after {
                 self.ibox(0);
                 self.print_block_with_attrs(blk, attrs);
@@ -397,7 +403,7 @@ impl<'a> State<'a> {
                 self.word_nbsp("async");
                 self.print_capture_clause(capture_clause);
                 // cbox/ibox in analogy to the `ExprKind::Block` arm above
-                self.cbox(INDENT_UNIT);
+                self.cbox(0);
                 self.ibox(0);
                 self.print_block_with_attrs(blk, attrs);
             }
@@ -500,7 +506,9 @@ impl<'a> State<'a> {
                 self.word("?")
             }
             ast::ExprKind::TryBlock(ref blk) => {
-                self.head("try");
+                self.cbox(0);
+                self.ibox(0);
+                self.word_nbsp("try");
                 self.print_block_with_attrs(blk, attrs)
             }
             ast::ExprKind::Err => {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index c756b946b1e..dac84ae9d5f 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -1,5 +1,5 @@
 use crate::pp::Breaks::Inconsistent;
-use crate::pprust::state::{AnnNode, PrintState, State, INDENT_UNIT};
+use crate::pprust::state::{AnnNode, PrintState, State};
 
 use rustc_ast as ast;
 use rustc_ast::GenericBound;
@@ -347,7 +347,7 @@ impl<'a> State<'a> {
                 }
             }
             ast::ItemKind::MacroDef(ref macro_def) => {
-                self.print_mac_def(macro_def, &item.ident, &item.span, |state| {
+                self.print_mac_def(macro_def, &item.ident, item.span, |state| {
                     state.print_visibility(&item.vis)
                 });
             }
@@ -377,7 +377,7 @@ impl<'a> State<'a> {
             self.space_if_not_bol();
             self.maybe_print_comment(v.span.lo());
             self.print_outer_attributes(&v.attrs);
-            self.ibox(INDENT_UNIT);
+            self.ibox(0);
             self.print_variant(v);
             self.word(",");
             self.end();
diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs
index 98378a98684..d41143ee763 100644
--- a/compiler/rustc_borrowck/src/constraints/mod.rs
+++ b/compiler/rustc_borrowck/src/constraints/mod.rs
@@ -72,7 +72,7 @@ impl<'tcx> Index<OutlivesConstraintIndex> for OutlivesConstraintSet<'tcx> {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Clone, PartialEq, Eq)]
 pub struct OutlivesConstraint<'tcx> {
     // NB. The ordering here is not significant for correctness, but
     // it is for convenience. Before we dump the constraints in the
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 8f4e574fbd6..8ed50075ecb 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -798,7 +798,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                     .map(|assoc_items| {
                         assoc_items
                             .in_definition_order()
-                            .map(|assoc_item_def| assoc_item_def.ident)
+                            .map(|assoc_item_def| assoc_item_def.ident(self.infcx.tcx))
                             .filter(|&ident| {
                                 let original_method_ident = path_segment.ident;
                                 original_method_ident != ident
diff --git a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs
index cfd3acb6bde..97233b930c3 100644
--- a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs
+++ b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs
@@ -72,7 +72,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         }
 
         let mut constraints: Vec<_> = self.constraints.outlives().iter().collect();
-        constraints.sort();
+        constraints.sort_by_key(|c| (c.sup, c.sub));
         for constraint in &constraints {
             let OutlivesConstraint { sup, sub, locations, category, variance_info: _ } = constraint;
             let (name, arg) = match locations {
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index b39a28f79aa..d9120ff2457 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -612,7 +612,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     fn propagate_constraints(&mut self, _body: &Body<'tcx>) {
         debug!("constraints={:#?}", {
             let mut constraints: Vec<_> = self.constraints.outlives().iter().collect();
-            constraints.sort();
+            constraints.sort_by_key(|c| (c.sup, c.sub));
             constraints
                 .into_iter()
                 .map(|c| (c, self.constraint_sccs.scc(c.sup), self.constraint_sccs.scc(c.sub)))
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index b6f5f4998a6..73103643e3e 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -758,6 +758,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
             },
             ProjectionElem::Field(field, fty) => {
                 let fty = self.sanitize_type(place, fty);
+                let fty = self.cx.normalize(fty, location);
                 match self.field_ty(place, base, field, location) {
                     Ok(ty) => {
                         let ty = self.cx.normalize(ty, location);
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index b986df403f9..16a903d5e59 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -180,8 +180,9 @@ pub enum RegionClassification {
     /// anywhere. There is only one, `'static`.
     Global,
 
-    /// An **external** region is only relevant for closures. In that
-    /// case, it refers to regions that are free in the closure type
+    /// An **external** region is only relevant for
+    /// closures, generators, and inline consts. In that
+    /// case, it refers to regions that are free in the type
     /// -- basically, something bound in the surrounding context.
     ///
     /// Consider this example:
@@ -198,8 +199,8 @@ pub enum RegionClassification {
     /// Here, the lifetimes `'a` and `'b` would be **external** to the
     /// closure.
     ///
-    /// If we are not analyzing a closure, there are no external
-    /// lifetimes.
+    /// If we are not analyzing a closure/generator/inline-const,
+    /// there are no external lifetimes.
     External,
 
     /// A **local** lifetime is one about which we know the full set
@@ -424,22 +425,30 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
 
         let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
 
-        // If this is a closure or generator, then the late-bound regions from the enclosing
-        // function are actually external regions to us. For example, here, 'a is not local
-        // to the closure c (although it is local to the fn foo):
-        // fn foo<'a>() {
-        //     let c = || { let x: &'a u32 = ...; }
-        // }
-        if self.mir_def.did.to_def_id() != typeck_root_def_id {
+        // If this is is a 'root' body (not a closure/generator/inline const), then
+        // there are no extern regions, so the local regions start at the same
+        // position as the (empty) sub-list of extern regions
+        let first_local_index = if self.mir_def.did.to_def_id() == typeck_root_def_id {
+            first_extern_index
+        } else {
+            // If this is a closure, generator, or inline-const, then the late-bound regions from the enclosing
+            // function are actually external regions to us. For example, here, 'a is not local
+            // to the closure c (although it is local to the fn foo):
+            // fn foo<'a>() {
+            //     let c = || { let x: &'a u32 = ...; }
+            // }
             self.infcx
-                .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices)
-        }
-
-        let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty);
+                .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
+            // Any regions created during the execution of `defining_ty` or during the above
+            // late-bound region replacement are all considered 'extern' regions
+            self.infcx.num_region_vars()
+        };
 
         // "Liberate" the late-bound regions. These correspond to
         // "local" free regions.
-        let first_local_index = self.infcx.num_region_vars();
+
+        let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty);
+
         let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars(
             FR,
             self.mir_def.did,
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index d1393528d1c..41b56cca1dc 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -791,7 +791,7 @@ impl<'a, 'b> Context<'a, 'b> {
         // Thus in the not nicely ordered case we emit the following instead:
         //
         //     match (&$arg0, &$arg1, …) {
-        //         _args => [ArgumentV1::new(_args.$i, …), ArgumentV1::new(_args.$j, …), …]
+        //         args => [ArgumentV1::new(args.$i, …), ArgumentV1::new(args.$j, …), …]
         //     }
         //
         // for the sequence of indices $i, $j, … governed by fmt_arg_index_and_ty.
@@ -804,7 +804,7 @@ impl<'a, 'b> Context<'a, 'b> {
                 self.ecx.expr_addr_of(expansion_span, P(e.take()))
             } else {
                 let def_site = self.ecx.with_def_site_ctxt(span);
-                let args_tuple = self.ecx.expr_ident(def_site, Ident::new(sym::_args, def_site));
+                let args_tuple = self.ecx.expr_ident(def_site, Ident::new(sym::args, def_site));
                 let member = Ident::new(sym::integer(arg_index), def_site);
                 self.ecx.expr(def_site, ast::ExprKind::Field(args_tuple, member))
             };
@@ -828,7 +828,7 @@ impl<'a, 'b> Context<'a, 'b> {
                     .map(|e| self.ecx.expr_addr_of(e.span.with_ctxt(self.macsp.ctxt()), e))
                     .collect();
 
-                let pat = self.ecx.pat_ident(self.macsp, Ident::new(sym::_args, self.macsp));
+                let pat = self.ecx.pat_ident(self.macsp, Ident::new(sym::args, self.macsp));
                 let arm = self.ecx.arm(self.macsp, pat, args_array);
                 let head = self.ecx.expr(self.macsp, ast::ExprKind::Tup(heads));
                 self.ecx.expr_match(self.macsp, head, vec![arm])
@@ -877,11 +877,21 @@ impl<'a, 'b> Context<'a, 'b> {
                 return ecx.expr_call_global(macsp, path, vec![arg]);
             }
         };
+        let new_fn_name = match trait_ {
+            "Display" => "new_display",
+            "Debug" => "new_debug",
+            "LowerExp" => "new_lower_exp",
+            "UpperExp" => "new_upper_exp",
+            "Octal" => "new_octal",
+            "Pointer" => "new_pointer",
+            "Binary" => "new_binary",
+            "LowerHex" => "new_lower_hex",
+            "UpperHex" => "new_upper_hex",
+            _ => unreachable!(),
+        };
 
-        let path = ecx.std_path(&[sym::fmt, Symbol::intern(trait_), sym::fmt]);
-        let format_fn = ecx.path_global(sp, path);
-        let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, sym::new]);
-        ecx.expr_call_global(macsp, path, vec![arg, ecx.expr_path(format_fn)])
+        let path = ecx.std_path(&[sym::fmt, sym::ArgumentV1, Symbol::intern(new_fn_name)]);
+        ecx.expr_call_global(sp, path, vec![arg])
     }
 }
 
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index 65e142a00f8..faed52727c8 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -172,9 +172,9 @@ checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
 
 [[package]]
 name = "indexmap"
-version = "1.7.0"
+version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
+checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
 dependencies = [
  "autocfg",
  "hashbrown",
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index 3be4250296e..2d19040b509 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -19,7 +19,7 @@ gimli = { version = "0.25.0", default-features = false, features = ["write"]}
 object = { version = "0.27.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"
+indexmap = "1.8.0"
 libloading = { version = "0.6.0", optional = true }
 smallvec = "1.6.1"
 
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index b4213da6e05..8a74c4c07e0 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -560,6 +560,7 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
             InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => unimplemented!(),
             InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => unimplemented!(),
             InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => unimplemented!(),
+            InlineAsmRegClass::Msp430(_) => unimplemented!(),
             InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => unimplemented!(),
             InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => unimplemented!(),
             InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => unimplemented!(),
@@ -622,6 +623,7 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
         InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
         InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(),
         InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(),
+        InlineAsmRegClass::Msp430(_) => unimplemented!(),
         InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(),
         InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(),
         InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(),
@@ -729,6 +731,7 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option
         InlineAsmRegClass::Bpf(_) => unimplemented!(),
         InlineAsmRegClass::Hexagon(_) => unimplemented!(),
         InlineAsmRegClass::Mips(_) => unimplemented!(),
+        InlineAsmRegClass::Msp430(_) => unimplemented!(),
         InlineAsmRegClass::Nvptx(_) => unimplemented!(),
         InlineAsmRegClass::PowerPC(_) => unimplemented!(),
         InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg)
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index 379c88bbd40..ffb77e16a14 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -1256,7 +1256,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         aggregate_value
     }
 
-    fn landing_pad(&mut self, _ty: Type<'gcc>, _pers_fn: RValue<'gcc>, _num_clauses: usize) -> RValue<'gcc> {
+    fn set_personality_fn(&mut self, _personality: RValue<'gcc>) {
+        // TODO(antoyo)
+    }
+
+    fn cleanup_landing_pad(&mut self, _ty: Type<'gcc>, _pers_fn: RValue<'gcc>) -> RValue<'gcc> {
         let field1 = self.context.new_field(None, self.u8_type, "landing_pad_field_1");
         let field2 = self.context.new_field(None, self.i32_type, "landing_pad_field_1");
         let struct_type = self.context.new_struct_type(None, "landing_pad", &[field1, field2]);
@@ -1267,11 +1271,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         // rustc_codegen_ssa now calls the unwinding builder methods even on panic=abort.
     }
 
-    fn set_cleanup(&mut self, _landing_pad: RValue<'gcc>) {
-        // TODO(antoyo)
-    }
-
-    fn resume(&mut self, _exn: RValue<'gcc>) -> RValue<'gcc> {
+    fn resume(&mut self, _exn: RValue<'gcc>) {
         unimplemented!();
     }
 
@@ -1279,7 +1279,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         unimplemented!();
     }
 
-    fn cleanup_ret(&mut self, _funclet: &Funclet, _unwind: Option<Block<'gcc>>) -> RValue<'gcc> {
+    fn cleanup_ret(&mut self, _funclet: &Funclet, _unwind: Option<Block<'gcc>>) {
         unimplemented!();
     }
 
@@ -1287,18 +1287,15 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
         unimplemented!();
     }
 
-    fn catch_switch(&mut self, _parent: Option<RValue<'gcc>>, _unwind: Option<Block<'gcc>>, _num_handlers: usize) -> RValue<'gcc> {
+    fn catch_switch(
+        &mut self,
+        _parent: Option<RValue<'gcc>>,
+        _unwind: Option<Block<'gcc>>,
+        _handlers: &[Block<'gcc>],
+    ) -> RValue<'gcc> {
         unimplemented!();
     }
 
-    fn add_handler(&mut self, _catch_switch: RValue<'gcc>, _handler: Block<'gcc>) {
-        unimplemented!();
-    }
-
-    fn set_personality_fn(&mut self, _personality: RValue<'gcc>) {
-        // TODO(antoyo)
-    }
-
     // Atomic Operations
     fn atomic_cmpxchg(&mut self, dst: RValue<'gcc>, cmp: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> {
         let expected = self.current_func().new_local(None, cmp.get_type(), "expected");
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 8b696dc6fba..e22bec24951 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -232,6 +232,9 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                 InlineAsmArch::SpirV => {}
                 InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {}
                 InlineAsmArch::Bpf => {}
+                InlineAsmArch::Msp430 => {
+                    constraints.push("~{sr}".to_string());
+                }
             }
         }
         if !options.contains(InlineAsmOptions::NOMEM) {
@@ -580,6 +583,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
             InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e",
             InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
             InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
+            InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r",
             InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
                 bug!("LLVM backend does not support SPIR-V")
             }
@@ -666,6 +670,7 @@ fn modifier_to_llvm(
         },
         InlineAsmRegClass::Avr(_) => None,
         InlineAsmRegClass::S390x(_) => None,
+        InlineAsmRegClass::Msp430(_) => None,
         InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
             bug!("LLVM backend does not support SPIR-V")
         }
@@ -734,6 +739,7 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
         InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => cx.type_i16(),
         InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(),
         InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
+        InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => cx.type_i16(),
         InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
             bug!("LLVM backend does not support SPIR-V")
         }
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 8a9450c20dd..c9a04e6280f 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -956,29 +956,24 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         unsafe { llvm::LLVMBuildInsertValue(self.llbuilder, agg_val, elt, idx as c_uint, UNNAMED) }
     }
 
-    fn landing_pad(
-        &mut self,
-        ty: &'ll Type,
-        pers_fn: &'ll Value,
-        num_clauses: usize,
-    ) -> &'ll Value {
-        // Use LLVMSetPersonalityFn to set the personality. It supports arbitrary Consts while,
-        // LLVMBuildLandingPad requires the argument to be a Function (as of LLVM 12). The
-        // personality lives on the parent function anyway.
-        self.set_personality_fn(pers_fn);
+    fn set_personality_fn(&mut self, personality: &'ll Value) {
         unsafe {
-            llvm::LLVMBuildLandingPad(self.llbuilder, ty, None, num_clauses as c_uint, UNNAMED)
+            llvm::LLVMSetPersonalityFn(self.llfn(), personality);
         }
     }
 
-    fn set_cleanup(&mut self, landing_pad: &'ll Value) {
+    fn cleanup_landing_pad(&mut self, ty: &'ll Type, pers_fn: &'ll Value) -> &'ll Value {
+        let landing_pad = self.landing_pad(ty, pers_fn, 1 /* FIXME should this be 0? */);
         unsafe {
             llvm::LLVMSetCleanup(landing_pad, llvm::True);
         }
+        landing_pad
     }
 
-    fn resume(&mut self, exn: &'ll Value) -> &'ll Value {
-        unsafe { llvm::LLVMBuildResume(self.llbuilder, exn) }
+    fn resume(&mut self, exn: &'ll Value) {
+        unsafe {
+            llvm::LLVMBuildResume(self.llbuilder, exn);
+        }
     }
 
     fn cleanup_pad(&mut self, parent: Option<&'ll Value>, args: &[&'ll Value]) -> Funclet<'ll> {
@@ -995,14 +990,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         Funclet::new(ret.expect("LLVM does not have support for cleanuppad"))
     }
 
-    fn cleanup_ret(
-        &mut self,
-        funclet: &Funclet<'ll>,
-        unwind: Option<&'ll BasicBlock>,
-    ) -> &'ll Value {
-        let ret =
-            unsafe { llvm::LLVMRustBuildCleanupRet(self.llbuilder, funclet.cleanuppad(), unwind) };
-        ret.expect("LLVM does not have support for cleanupret")
+    fn cleanup_ret(&mut self, funclet: &Funclet<'ll>, unwind: Option<&'ll BasicBlock>) {
+        unsafe {
+            llvm::LLVMRustBuildCleanupRet(self.llbuilder, funclet.cleanuppad(), unwind)
+                .expect("LLVM does not have support for cleanupret");
+        }
     }
 
     fn catch_pad(&mut self, parent: &'ll Value, args: &[&'ll Value]) -> Funclet<'ll> {
@@ -1023,7 +1015,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         &mut self,
         parent: Option<&'ll Value>,
         unwind: Option<&'ll BasicBlock>,
-        num_handlers: usize,
+        handlers: &[&'ll BasicBlock],
     ) -> &'ll Value {
         let name = cstr!("catchswitch");
         let ret = unsafe {
@@ -1031,23 +1023,17 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
                 self.llbuilder,
                 parent,
                 unwind,
-                num_handlers as c_uint,
+                handlers.len() as c_uint,
                 name.as_ptr(),
             )
         };
-        ret.expect("LLVM does not have support for catchswitch")
-    }
-
-    fn add_handler(&mut self, catch_switch: &'ll Value, handler: &'ll BasicBlock) {
-        unsafe {
-            llvm::LLVMRustAddHandler(catch_switch, handler);
-        }
-    }
-
-    fn set_personality_fn(&mut self, personality: &'ll Value) {
-        unsafe {
-            llvm::LLVMSetPersonalityFn(self.llfn(), personality);
+        let ret = ret.expect("LLVM does not have support for catchswitch");
+        for handler in handlers {
+            unsafe {
+                llvm::LLVMRustAddHandler(ret, handler);
+            }
         }
+        ret
     }
 
     // Atomic Operations
@@ -1478,4 +1464,19 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
             None
         }
     }
+
+    pub(crate) fn landing_pad(
+        &mut self,
+        ty: &'ll Type,
+        pers_fn: &'ll Value,
+        num_clauses: usize,
+    ) -> &'ll Value {
+        // Use LLVMSetPersonalityFn to set the personality. It supports arbitrary Consts while,
+        // LLVMBuildLandingPad requires the argument to be a Function (as of LLVM 12). The
+        // personality lives on the parent function anyway.
+        self.set_personality_fn(pers_fn);
+        unsafe {
+            llvm::LLVMBuildLandingPad(self.llbuilder, ty, None, num_clauses as c_uint, UNNAMED)
+        }
+    }
 }
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index bb16bc5dccd..8672459b5da 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -215,16 +215,19 @@ pub unsafe fn create_module<'ll>(
     // to ensure intrinsic calls don't use it.
     if !sess.needs_plt() {
         let avoid_plt = "RtLibUseGOT\0".as_ptr().cast();
-        llvm::LLVMRustAddModuleFlag(llmod, avoid_plt, 1);
+        llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
     }
 
     if sess.is_sanitizer_cfi_enabled() {
         // FIXME(rcvalle): Add support for non canonical jump tables.
         let canonical_jump_tables = "CFI Canonical Jump Tables\0".as_ptr().cast();
-        // FIXME(rcvalle): Add it with Override behavior flag--LLVMRustAddModuleFlag adds it with
-        // Warning behavior flag. Add support for specifying the behavior flag to
-        // LLVMRustAddModuleFlag.
-        llvm::LLVMRustAddModuleFlag(llmod, canonical_jump_tables, 1);
+        // FIXME(rcvalle): Add it with Override behavior flag.
+        llvm::LLVMRustAddModuleFlag(
+            llmod,
+            llvm::LLVMModFlagBehavior::Warning,
+            canonical_jump_tables,
+            1,
+        );
     }
 
     // Control Flow Guard is currently only supported by the MSVC linker on Windows.
@@ -233,11 +236,21 @@ pub unsafe fn create_module<'ll>(
             CFGuard::Disabled => {}
             CFGuard::NoChecks => {
                 // Set `cfguard=1` module flag to emit metadata only.
-                llvm::LLVMRustAddModuleFlag(llmod, "cfguard\0".as_ptr() as *const _, 1)
+                llvm::LLVMRustAddModuleFlag(
+                    llmod,
+                    llvm::LLVMModFlagBehavior::Warning,
+                    "cfguard\0".as_ptr() as *const _,
+                    1,
+                )
             }
             CFGuard::Checks => {
                 // Set `cfguard=2` module flag to emit metadata and checks.
-                llvm::LLVMRustAddModuleFlag(llmod, "cfguard\0".as_ptr() as *const _, 2)
+                llvm::LLVMRustAddModuleFlag(
+                    llmod,
+                    llvm::LLVMModFlagBehavior::Warning,
+                    "cfguard\0".as_ptr() as *const _,
+                    2,
+                )
             }
         }
     }
@@ -247,24 +260,28 @@ pub unsafe fn create_module<'ll>(
 
         llvm::LLVMRustAddModuleFlag(
             llmod,
+            llvm::LLVMModFlagBehavior::Error,
             "branch-target-enforcement\0".as_ptr().cast(),
             bti.into(),
         );
 
         llvm::LLVMRustAddModuleFlag(
             llmod,
+            llvm::LLVMModFlagBehavior::Error,
             "sign-return-address\0".as_ptr().cast(),
             pac.is_some().into(),
         );
         let pac_opts = pac.unwrap_or(PacRet { leaf: false, key: PAuthKey::A });
         llvm::LLVMRustAddModuleFlag(
             llmod,
+            llvm::LLVMModFlagBehavior::Error,
             "sign-return-address-all\0".as_ptr().cast(),
             pac_opts.leaf.into(),
         );
         let is_bkey = if pac_opts.key == PAuthKey::A { false } else { true };
         llvm::LLVMRustAddModuleFlag(
             llmod,
+            llvm::LLVMModFlagBehavior::Error,
             "sign-return-address-with-bkey\0".as_ptr().cast(),
             is_bkey.into(),
         );
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 32f18419753..3014d2f1930 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -9,6 +9,7 @@ use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefIdSet;
 use rustc_llvm::RustString;
+use rustc_middle::bug;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::coverage::CodeRegion;
 use rustc_middle::ty::TyCtxt;
@@ -76,10 +77,18 @@ pub fn finalize<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) {
         let coverage_mapping_buffer = llvm::build_byte_buffer(|coverage_mapping_buffer| {
             mapgen.write_coverage_mapping(expressions, counter_regions, coverage_mapping_buffer);
         });
-        debug_assert!(
-            !coverage_mapping_buffer.is_empty(),
-            "Every `FunctionCoverage` should have at least one counter"
-        );
+
+        if coverage_mapping_buffer.is_empty() {
+            if function_coverage.is_used() {
+                bug!(
+                    "A used function should have had coverage mapping data but did not: {}",
+                    mangled_function_name
+                );
+            } else {
+                debug!("unused function had no coverage mapping data: {}", mangled_function_name);
+                continue;
+            }
+        }
 
         function_data.push((mangled_function_name, source_hash, is_used, coverage_mapping_buffer));
     }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 3d5fd2f354e..1266b540aae 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -10,6 +10,8 @@ use super::CrateDebugContext;
 
 use crate::abi;
 use crate::common::CodegenCx;
+use crate::debuginfo::utils::fat_pointer_kind;
+use crate::debuginfo::utils::FatPtrKind;
 use crate::llvm;
 use crate::llvm::debuginfo::{
     DIArray, DICompositeType, DIDescriptor, DIFile, DIFlags, DILexicalBlock, DIScope, DIType,
@@ -376,22 +378,24 @@ macro_rules! return_if_metadata_created_in_meantime {
     };
 }
 
-fn fixed_vec_metadata<'ll, 'tcx>(
+/// Creates debuginfo for a fixed size array (e.g. `[u64; 123]`).
+/// For slices (that is, "arrays" of unknown size) use [slice_type_metadata].
+fn fixed_size_array_metadata<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
     unique_type_id: UniqueTypeId,
-    array_or_slice_type: Ty<'tcx>,
-    element_type: Ty<'tcx>,
+    array_type: Ty<'tcx>,
 ) -> MetadataCreationResult<'ll> {
+    let ty::Array(element_type, len) = array_type.kind() else {
+        bug!("fixed_size_array_metadata() called with non-ty::Array type `{:?}`", array_type)
+    };
+
     let element_type_metadata = type_metadata(cx, element_type);
 
     return_if_metadata_created_in_meantime!(cx, unique_type_id);
 
-    let (size, align) = cx.size_and_align_of(array_or_slice_type);
+    let (size, align) = cx.size_and_align_of(array_type);
 
-    let upper_bound = match array_or_slice_type.kind() {
-        ty::Array(_, len) => len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong,
-        _ => -1,
-    };
+    let upper_bound = len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong;
 
     let subrange =
         unsafe { Some(llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound)) };
@@ -410,55 +414,111 @@ fn fixed_vec_metadata<'ll, 'tcx>(
     MetadataCreationResult::new(metadata, false)
 }
 
-fn vec_slice_metadata<'ll, 'tcx>(
+/// Creates debuginfo for built-in pointer-like things:
+///
+///  - ty::Ref
+///  - ty::RawPtr
+///  - ty::Adt in the case it's Box
+///
+/// At some point we might want to remove the special handling of Box
+/// and treat it the same as other smart pointers (like Rc, Arc, ...).
+fn pointer_or_reference_metadata<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
-    slice_ptr_type: Ty<'tcx>,
-    element_type: Ty<'tcx>,
+    ptr_type: Ty<'tcx>,
+    pointee_type: Ty<'tcx>,
     unique_type_id: UniqueTypeId,
 ) -> MetadataCreationResult<'ll> {
-    let data_ptr_type = cx.tcx.mk_imm_ptr(element_type);
-
-    let data_ptr_metadata = type_metadata(cx, data_ptr_type);
+    let pointee_type_metadata = type_metadata(cx, pointee_type);
 
     return_if_metadata_created_in_meantime!(cx, unique_type_id);
 
-    let slice_type_name = compute_debuginfo_type_name(cx.tcx, slice_ptr_type, true);
-
-    let (pointer_size, pointer_align) = cx.size_and_align_of(data_ptr_type);
-    let (usize_size, usize_align) = cx.size_and_align_of(cx.tcx.types.usize);
-
-    let member_descriptions = vec![
-        MemberDescription {
-            name: "data_ptr".to_owned(),
-            type_metadata: data_ptr_metadata,
-            offset: Size::ZERO,
-            size: pointer_size,
-            align: pointer_align,
-            flags: DIFlags::FlagZero,
-            discriminant: None,
-            source_info: None,
-        },
-        MemberDescription {
-            name: "length".to_owned(),
-            type_metadata: type_metadata(cx, cx.tcx.types.usize),
-            offset: pointer_size,
-            size: usize_size,
-            align: usize_align,
-            flags: DIFlags::FlagZero,
-            discriminant: None,
-            source_info: None,
-        },
-    ];
+    let (thin_pointer_size, thin_pointer_align) =
+        cx.size_and_align_of(cx.tcx.mk_imm_ptr(cx.tcx.types.unit));
+    let ptr_type_debuginfo_name = compute_debuginfo_type_name(cx.tcx, ptr_type, true);
 
-    let metadata = composite_type_metadata(
-        cx,
-        slice_ptr_type,
-        &slice_type_name,
-        unique_type_id,
-        member_descriptions,
-        NO_SCOPE_METADATA,
-    );
-    MetadataCreationResult::new(metadata, false)
+    let pointer_type_metadata = match fat_pointer_kind(cx, pointee_type) {
+        None => {
+            // This is a thin pointer. Create a regular pointer type and give it the correct name.
+            debug_assert_eq!(
+                (thin_pointer_size, thin_pointer_align),
+                cx.size_and_align_of(ptr_type)
+            );
+
+            unsafe {
+                llvm::LLVMRustDIBuilderCreatePointerType(
+                    DIB(cx),
+                    pointee_type_metadata,
+                    thin_pointer_size.bits(),
+                    thin_pointer_align.bits() as u32,
+                    0, // Ignore DWARF address space.
+                    ptr_type_debuginfo_name.as_ptr().cast(),
+                    ptr_type_debuginfo_name.len(),
+                )
+            }
+        }
+        Some(fat_pointer_kind) => {
+            let layout = cx.layout_of(ptr_type);
+
+            let addr_field = layout.field(cx, abi::FAT_PTR_ADDR);
+            let extra_field = layout.field(cx, abi::FAT_PTR_EXTRA);
+
+            let (addr_field_name, extra_field_name) = match fat_pointer_kind {
+                FatPtrKind::Dyn => ("pointer", "vtable"),
+                FatPtrKind::Slice => ("data_ptr", "length"),
+            };
+
+            debug_assert_eq!(abi::FAT_PTR_ADDR, 0);
+            debug_assert_eq!(abi::FAT_PTR_EXTRA, 1);
+
+            // The data pointer type is a regular, thin pointer, regardless of whether this is a slice
+            // or a trait object.
+            let data_ptr_type_metadata = unsafe {
+                llvm::LLVMRustDIBuilderCreatePointerType(
+                    DIB(cx),
+                    pointee_type_metadata,
+                    addr_field.size.bits(),
+                    addr_field.align.abi.bits() as u32,
+                    0, // Ignore DWARF address space.
+                    std::ptr::null(),
+                    0,
+                )
+            };
+
+            let member_descriptions = vec![
+                MemberDescription {
+                    name: addr_field_name.into(),
+                    type_metadata: data_ptr_type_metadata,
+                    offset: layout.fields.offset(abi::FAT_PTR_ADDR),
+                    size: addr_field.size,
+                    align: addr_field.align.abi,
+                    flags: DIFlags::FlagZero,
+                    discriminant: None,
+                    source_info: None,
+                },
+                MemberDescription {
+                    name: extra_field_name.into(),
+                    type_metadata: type_metadata(cx, extra_field.ty),
+                    offset: layout.fields.offset(abi::FAT_PTR_EXTRA),
+                    size: extra_field.size,
+                    align: extra_field.align.abi,
+                    flags: DIFlags::FlagZero,
+                    discriminant: None,
+                    source_info: None,
+                },
+            ];
+
+            composite_type_metadata(
+                cx,
+                ptr_type,
+                &ptr_type_debuginfo_name,
+                unique_type_id,
+                member_descriptions,
+                NO_SCOPE_METADATA,
+            )
+        }
+    };
+
+    MetadataCreationResult { metadata: pointer_type_metadata, already_stored_in_typemap: false }
 }
 
 fn subroutine_type_metadata<'ll, 'tcx>(
@@ -495,83 +555,57 @@ fn subroutine_type_metadata<'ll, 'tcx>(
     )
 }
 
-// FIXME(1563): This is all a bit of a hack because 'trait pointer' is an ill-
-// defined concept. For the case of an actual trait pointer (i.e., `Box<Trait>`,
-// `&Trait`), `trait_object_type` should be the whole thing (e.g, `Box<Trait>`) and
-// `trait_type` should be the actual trait (e.g., `Trait`). Where the trait is part
-// of a DST struct, there is no `trait_object_type` and the results of this
-// function will be a little bit weird.
-fn trait_pointer_metadata<'ll, 'tcx>(
+/// Create debuginfo for `dyn SomeTrait` types. Currently these are empty structs
+/// we with the correct type name (e.g. "dyn SomeTrait<Foo, Item=u32> + Sync").
+fn dyn_type_metadata<'ll, 'tcx>(
     cx: &CodegenCx<'ll, 'tcx>,
-    trait_type: Ty<'tcx>,
-    trait_object_type: Option<Ty<'tcx>>,
+    dyn_type: Ty<'tcx>,
     unique_type_id: UniqueTypeId,
 ) -> &'ll DIType {
-    // The implementation provided here is a stub. It makes sure that the trait
-    // type is assigned the correct name, size, namespace, and source location.
-    // However, it does not describe the trait's methods.
-
-    let (containing_scope, trait_type_name) = match trait_object_type {
-        Some(trait_object_type) => match trait_object_type.kind() {
-            ty::Adt(def, _) => (
-                Some(get_namespace_for_item(cx, def.did)),
-                compute_debuginfo_type_name(cx.tcx, trait_object_type, false),
-            ),
-            ty::RawPtr(_) | ty::Ref(..) => {
-                (NO_SCOPE_METADATA, compute_debuginfo_type_name(cx.tcx, trait_object_type, true))
-            }
-            _ => {
-                bug!(
-                    "debuginfo: unexpected trait-object type in \
-                      trait_pointer_metadata(): {:?}",
-                    trait_object_type
-                );
-            }
-        },
+    if let ty::Dynamic(..) = dyn_type.kind() {
+        let type_name = compute_debuginfo_type_name(cx.tcx, dyn_type, true);
+        composite_type_metadata(cx, dyn_type, &type_name, unique_type_id, vec![], NO_SCOPE_METADATA)
+    } else {
+        bug!("Only ty::Dynamic is valid for dyn_type_metadata(). Found {:?} instead.", dyn_type)
+    }
+}
 
-        // No object type, use the trait type directly (no scope here since the type
-        // will be wrapped in the dyn$ synthetic type).
-        None => (NO_SCOPE_METADATA, compute_debuginfo_type_name(cx.tcx, trait_type, true)),
+/// Create debuginfo for `[T]` and `str`. These are unsized.
+///
+/// NOTE: We currently emit just emit the debuginfo for the element type here
+/// (i.e. `T` for slices and `u8` for `str`), so that we end up with
+/// `*const T` for the `data_ptr` field of the corresponding fat-pointer
+/// debuginfo of `&[T]`.
+///
+/// It would be preferable and more accurate if we emitted a DIArray of T
+/// without an upper bound instead. That is, LLVM already supports emitting
+/// debuginfo of arrays of unknown size. But GDB currently seems to end up
+/// in an infinite loop when confronted with such a type.
+///
+/// As a side effect of the current encoding every instance of a type like
+/// `struct Foo { unsized_field: [u8] }` will look like
+/// `struct Foo { unsized_field: u8 }` in debuginfo. If the length of the
+/// slice is zero, then accessing `unsized_field` in the debugger would
+/// result in an out-of-bounds access.
+fn slice_type_metadata<'ll, 'tcx>(
+    cx: &CodegenCx<'ll, 'tcx>,
+    slice_type: Ty<'tcx>,
+    unique_type_id: UniqueTypeId,
+) -> MetadataCreationResult<'ll> {
+    let element_type = match slice_type.kind() {
+        ty::Slice(element_type) => element_type,
+        ty::Str => cx.tcx.types.u8,
+        _ => {
+            bug!(
+                "Only ty::Slice is valid for slice_type_metadata(). Found {:?} instead.",
+                slice_type
+            )
+        }
     };
 
-    let layout = cx.layout_of(cx.tcx.mk_mut_ptr(trait_type));
-
-    assert_eq!(abi::FAT_PTR_ADDR, 0);
-    assert_eq!(abi::FAT_PTR_EXTRA, 1);
-
-    let data_ptr_field = layout.field(cx, 0);
-    let vtable_field = layout.field(cx, 1);
-    let member_descriptions = vec![
-        MemberDescription {
-            name: "pointer".to_owned(),
-            type_metadata: type_metadata(cx, cx.tcx.mk_mut_ptr(cx.tcx.types.u8)),
-            offset: layout.fields.offset(0),
-            size: data_ptr_field.size,
-            align: data_ptr_field.align.abi,
-            flags: DIFlags::FlagArtificial,
-            discriminant: None,
-            source_info: None,
-        },
-        MemberDescription {
-            name: "vtable".to_owned(),
-            type_metadata: type_metadata(cx, vtable_field.ty),
-            offset: layout.fields.offset(1),
-            size: vtable_field.size,
-            align: vtable_field.align.abi,
-            flags: DIFlags::FlagArtificial,
-            discriminant: None,
-            source_info: None,
-        },
-    ];
-
-    composite_type_metadata(
-        cx,
-        trait_object_type.unwrap_or(trait_type),
-        &trait_type_name,
-        unique_type_id,
-        member_descriptions,
-        containing_scope,
-    )
+    let element_type_metadata = type_metadata(cx, element_type);
+    return_if_metadata_created_in_meantime!(cx, unique_type_id);
+    MetadataCreationResult { metadata: element_type_metadata, already_stored_in_typemap: false }
 }
 
 pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
@@ -610,26 +644,6 @@ pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll
 
     debug!("type_metadata: {:?}", t);
 
-    let ptr_metadata = |ty: Ty<'tcx>| match *ty.kind() {
-        ty::Slice(typ) => Ok(vec_slice_metadata(cx, t, typ, unique_type_id)),
-        ty::Str => Ok(vec_slice_metadata(cx, t, cx.tcx.types.u8, unique_type_id)),
-        ty::Dynamic(..) => Ok(MetadataCreationResult::new(
-            trait_pointer_metadata(cx, ty, Some(t), unique_type_id),
-            false,
-        )),
-        _ => {
-            let pointee_metadata = type_metadata(cx, ty);
-
-            if let Some(metadata) =
-                debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id)
-            {
-                return Err(metadata);
-            }
-
-            Ok(MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata), false))
-        }
-    };
-
     let MetadataCreationResult { metadata, already_stored_in_typemap } = match *t.kind() {
         ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => {
             MetadataCreationResult::new(basic_type_metadata(cx, t), false)
@@ -637,22 +651,20 @@ pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll
         ty::Tuple(elements) if elements.is_empty() => {
             MetadataCreationResult::new(basic_type_metadata(cx, t), false)
         }
-        ty::Array(typ, _) | ty::Slice(typ) => fixed_vec_metadata(cx, unique_type_id, t, typ),
-        ty::Str => fixed_vec_metadata(cx, unique_type_id, t, cx.tcx.types.i8),
+        ty::Array(..) => fixed_size_array_metadata(cx, unique_type_id, t),
+        ty::Slice(_) | ty::Str => slice_type_metadata(cx, t, unique_type_id),
         ty::Dynamic(..) => {
-            MetadataCreationResult::new(trait_pointer_metadata(cx, t, None, unique_type_id), false)
+            MetadataCreationResult::new(dyn_type_metadata(cx, t, unique_type_id), false)
         }
         ty::Foreign(..) => {
             MetadataCreationResult::new(foreign_type_metadata(cx, t, unique_type_id), false)
         }
-        ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => match ptr_metadata(ty) {
-            Ok(res) => res,
-            Err(metadata) => return metadata,
-        },
-        ty::Adt(def, _) if def.is_box() => match ptr_metadata(t.boxed_ty()) {
-            Ok(res) => res,
-            Err(metadata) => return metadata,
-        },
+        ty::RawPtr(ty::TypeAndMut { ty: pointee_type, .. }) | ty::Ref(_, pointee_type, _) => {
+            pointer_or_reference_metadata(cx, t, pointee_type, unique_type_id)
+        }
+        ty::Adt(def, _) if def.is_box() => {
+            pointer_or_reference_metadata(cx, t, t.boxed_ty(), unique_type_id)
+        }
         ty::FnDef(..) | ty::FnPtr(_) => {
             if let Some(metadata) =
                 debug_context(cx).type_map.borrow().find_metadata_for_unique_id(unique_type_id)
@@ -694,7 +706,22 @@ pub fn type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll
             type_map.borrow_mut().remove_type(t);
 
             // This is actually a function pointer, so wrap it in pointer DI.
-            MetadataCreationResult::new(pointer_type_metadata(cx, t, fn_metadata), false)
+            let (pointer_size, pointer_align) =
+                cx.size_and_align_of(cx.tcx.mk_imm_ptr(cx.tcx.mk_unit()));
+            let name = compute_debuginfo_type_name(cx.tcx, t, false);
+            let md = unsafe {
+                llvm::LLVMRustDIBuilderCreatePointerType(
+                    DIB(cx),
+                    fn_metadata,
+                    pointer_size.bits(),
+                    pointer_align.bits() as u32,
+                    0, // Ignore DWARF address space.
+                    name.as_ptr().cast(),
+                    name.len(),
+                )
+            };
+
+            MetadataCreationResult::new(md, false)
         }
         ty::Closure(def_id, substs) => {
             let upvar_tys: Vec<_> = substs.as_closure().upvar_tys().collect();
@@ -959,26 +986,6 @@ fn foreign_type_metadata<'ll, 'tcx>(
     create_struct_stub(cx, t, &name, unique_type_id, NO_SCOPE_METADATA, DIFlags::FlagZero)
 }
 
-fn pointer_type_metadata<'ll, 'tcx>(
-    cx: &CodegenCx<'ll, 'tcx>,
-    pointer_type: Ty<'tcx>,
-    pointee_type_metadata: &'ll DIType,
-) -> &'ll DIType {
-    let (pointer_size, pointer_align) = cx.size_and_align_of(pointer_type);
-    let name = compute_debuginfo_type_name(cx.tcx, pointer_type, false);
-    unsafe {
-        llvm::LLVMRustDIBuilderCreatePointerType(
-            DIB(cx),
-            pointee_type_metadata,
-            pointer_size.bits(),
-            pointer_align.bits() as u32,
-            0, // Ignore DWARF address space.
-            name.as_ptr().cast(),
-            name.len(),
-        )
-    }
-}
-
 fn param_type_metadata<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
     debug!("param_type_metadata: {:?}", t);
     let name = format!("{:?}", t);
@@ -1493,7 +1500,7 @@ fn generator_layout_and_saved_local_names<'tcx>(
 
     let state_arg = mir::Local::new(1);
     for var in &body.var_debug_info {
-        let place = if let mir::VarDebugInfoContents::Place(p) = var.value { p } else { continue };
+        let mir::VarDebugInfoContents::Place(place) = &var.value else { continue };
         if place.local != state_arg {
             continue;
         }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 61e49fab6ff..28eb8e2a0a4 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -108,18 +108,29 @@ impl<'a, 'tcx> CrateDebugContext<'a, 'tcx> {
             // This can be overridden using --llvm-opts -dwarf-version,N.
             // Android has the same issue (#22398)
             if let Some(version) = sess.target.dwarf_version {
-                llvm::LLVMRustAddModuleFlag(self.llmod, "Dwarf Version\0".as_ptr().cast(), version)
+                llvm::LLVMRustAddModuleFlag(
+                    self.llmod,
+                    llvm::LLVMModFlagBehavior::Warning,
+                    "Dwarf Version\0".as_ptr().cast(),
+                    version,
+                )
             }
 
             // Indicate that we want CodeView debug information on MSVC
             if sess.target.is_like_msvc {
-                llvm::LLVMRustAddModuleFlag(self.llmod, "CodeView\0".as_ptr().cast(), 1)
+                llvm::LLVMRustAddModuleFlag(
+                    self.llmod,
+                    llvm::LLVMModFlagBehavior::Warning,
+                    "CodeView\0".as_ptr().cast(),
+                    1,
+                )
             }
 
             // Prevent bitcode readers from deleting the debug info.
             let ptr = "Debug Info Version\0".as_ptr();
             llvm::LLVMRustAddModuleFlag(
                 self.llmod,
+                llvm::LLVMModFlagBehavior::Warning,
                 ptr.cast(),
                 llvm::LLVMRustDebugMetadataVersion(),
             );
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
index 953b6765a48..6dd0d58efe3 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs
@@ -4,7 +4,9 @@ use super::namespace::item_namespace;
 use super::CrateDebugContext;
 
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::DefIdTree;
+use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::ty::{self, DefIdTree, Ty};
+use rustc_target::abi::VariantIdx;
 
 use crate::common::CodegenCx;
 use crate::llvm;
@@ -46,3 +48,58 @@ pub fn DIB<'a, 'll>(cx: &'a CodegenCx<'ll, '_>) -> &'a DIBuilder<'ll> {
 pub fn get_namespace_for_item<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope {
     item_namespace(cx, cx.tcx.parent(def_id).expect("get_namespace_for_item: missing parent?"))
 }
+
+#[derive(Debug, PartialEq, Eq)]
+pub(crate) enum FatPtrKind {
+    Slice,
+    Dyn,
+}
+
+/// Determines if `pointee_ty` is slice-like or trait-object-like, i.e.
+/// if the second field of the fat pointer is a length or a vtable-pointer.
+/// If `pointee_ty` does not require a fat pointer (because it is Sized) then
+/// the function returns `None`.
+pub(crate) fn fat_pointer_kind<'ll, 'tcx>(
+    cx: &CodegenCx<'ll, 'tcx>,
+    pointee_ty: Ty<'tcx>,
+) -> Option<FatPtrKind> {
+    let layout = cx.layout_of(pointee_ty);
+
+    if !layout.is_unsized() {
+        return None;
+    }
+
+    match *pointee_ty.kind() {
+        ty::Str | ty::Slice(_) => Some(FatPtrKind::Slice),
+        ty::Dynamic(..) => Some(FatPtrKind::Dyn),
+        ty::Adt(adt_def, _) => {
+            assert!(adt_def.is_struct());
+            assert!(adt_def.variants.len() == 1);
+            let variant = &adt_def.variants[VariantIdx::from_usize(0)];
+            assert!(!variant.fields.is_empty());
+            let last_field_index = variant.fields.len() - 1;
+
+            debug_assert!(
+                (0..last_field_index)
+                    .all(|field_index| { !layout.field(cx, field_index).is_unsized() })
+            );
+
+            let unsized_field = layout.field(cx, last_field_index);
+            assert!(unsized_field.is_unsized());
+            fat_pointer_kind(cx, unsized_field.ty)
+        }
+        ty::Foreign(_) => {
+            // Assert that pointers to foreign types really are thin:
+            debug_assert_eq!(
+                cx.size_of(cx.tcx.mk_imm_ptr(pointee_ty)),
+                cx.size_of(cx.tcx.mk_imm_ptr(cx.tcx.types.u8))
+            );
+            None
+        }
+        _ => {
+            // For all other pointee types we should already have returned None
+            // at the beginning of the function.
+            panic!("fat_pointer_kind() - Encountered unexpected `pointee_ty`: {:?}", pointee_ty)
+        }
+    }
+}
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 5adfa18035a..f51d014bfb3 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -525,9 +525,8 @@ fn codegen_msvc_try<'ll>(
 
         normal.ret(bx.const_i32(0));
 
-        let cs = catchswitch.catch_switch(None, None, 2);
-        catchswitch.add_handler(cs, catchpad_rust.llbb());
-        catchswitch.add_handler(cs, catchpad_foreign.llbb());
+        let cs =
+            catchswitch.catch_switch(None, None, &[catchpad_rust.llbb(), catchpad_foreign.llbb()]);
 
         // We can't use the TypeDescriptor defined in libpanic_unwind because it
         // might be in another DLL and the SEH encoding only supports specifying
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index cea4595fbbf..f0612eaba80 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -7,6 +7,7 @@
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(bool_to_option)]
 #![feature(crate_visibility_modifier)]
+#![feature(let_else)]
 #![feature(extern_types)]
 #![feature(nll)]
 #![recursion_limit = "256"]
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index a1c7d2b4f61..2b102188790 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -61,6 +61,26 @@ pub enum LLVMMachineType {
     ARM = 0x01c0,
 }
 
+/// LLVM's Module::ModFlagBehavior, defined in llvm/include/llvm/IR/Module.h.
+///
+/// When merging modules (e.g. during LTO), their metadata flags are combined. Conflicts are
+/// resolved according to the merge behaviors specified here. Flags differing only in merge
+/// behavior are still considered to be in conflict.
+///
+/// In order for Rust-C LTO to work, we must specify behaviors compatible with Clang. Notably,
+/// 'Error' and 'Warning' cannot be mixed for a given flag.
+#[derive(Copy, Clone, PartialEq)]
+#[repr(C)]
+pub enum LLVMModFlagBehavior {
+    Error = 1,
+    Warning = 2,
+    Require = 3,
+    Override = 4,
+    Append = 5,
+    AppendUnique = 6,
+    Max = 7,
+}
+
 // Consts for the LLVM CallConv type, pre-cast to usize.
 
 /// LLVM CallingConv::ID. Should we wrap this?
@@ -1895,7 +1915,16 @@ extern "C" {
 
     pub fn LLVMRustIsRustLLVM() -> bool;
 
-    pub fn LLVMRustAddModuleFlag(M: &Module, name: *const c_char, value: u32);
+    /// Add LLVM module flags.
+    ///
+    /// In order for Rust-C LTO to work, module flags must be compatible with Clang. What
+    /// "compatible" means depends on the merge behaviors involved.
+    pub fn LLVMRustAddModuleFlag(
+        M: &Module,
+        merge_behavior: LLVMModFlagBehavior,
+        name: *const c_char,
+        value: u32,
+    );
 
     pub fn LLVMRustMetadataAsValue<'a>(C: &'a Context, MD: &'a Metadata) -> &'a Value;
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index acf65259f61..7a13e424f9a 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -932,7 +932,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
                      but `link.exe` was not found",
                 );
                 sess.note_without_error(
-                    "please ensure that VS 2013, VS 2015, VS 2017 or VS 2019 \
+                    "please ensure that VS 2013, VS 2015, VS 2017, VS 2019 or VS 2022 \
                      was installed with the Visual C++ option",
                 );
             }
@@ -1159,6 +1159,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
                     LinkerFlavor::Lld(_) => "lld",
                     LinkerFlavor::PtxLinker => "rust-ptx-linker",
                     LinkerFlavor::BpfLinker => "bpf-linker",
+                    LinkerFlavor::L4Bender => "l4-bender",
                 }),
                 flavor,
             )),
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 15d16e7d3d6..3fb56f42b8c 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -126,7 +126,6 @@ pub fn get_linker<'a>(
     // FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction
     // to the linker args construction.
     assert!(cmd.get_args().is_empty() || sess.target.vendor == "uwp");
-
     match flavor {
         LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => {
             Box::new(MsvcLinker { cmd, sess }) as Box<dyn Linker>
@@ -149,6 +148,8 @@ pub fn get_linker<'a>(
         LinkerFlavor::PtxLinker => Box::new(PtxLinker { cmd, sess }) as Box<dyn Linker>,
 
         LinkerFlavor::BpfLinker => Box::new(BpfLinker { cmd, sess }) as Box<dyn Linker>,
+
+        LinkerFlavor::L4Bender => Box::new(L4Bender::new(cmd, sess)) as Box<dyn Linker>,
     }
 }
 
@@ -1355,6 +1356,157 @@ impl<'a> Linker for WasmLd<'a> {
     }
 }
 
+/// Linker shepherd script for L4Re (Fiasco)
+pub struct L4Bender<'a> {
+    cmd: Command,
+    sess: &'a Session,
+    hinted_static: bool,
+}
+
+impl<'a> Linker for L4Bender<'a> {
+    fn link_dylib(&mut self, _lib: Symbol, _verbatim: bool, _as_needed: bool) {
+        bug!("dylibs are not supported on L4Re");
+    }
+    fn link_staticlib(&mut self, lib: Symbol, _verbatim: bool) {
+        self.hint_static();
+        self.cmd.arg(format!("-PC{}", lib));
+    }
+    fn link_rlib(&mut self, lib: &Path) {
+        self.hint_static();
+        self.cmd.arg(lib);
+    }
+    fn include_path(&mut self, path: &Path) {
+        self.cmd.arg("-L").arg(path);
+    }
+    fn framework_path(&mut self, _: &Path) {
+        bug!("frameworks are not supported on L4Re");
+    }
+    fn output_filename(&mut self, path: &Path) {
+        self.cmd.arg("-o").arg(path);
+    }
+
+    fn add_object(&mut self, path: &Path) {
+        self.cmd.arg(path);
+    }
+
+    fn full_relro(&mut self) {
+        self.cmd.arg("-zrelro");
+        self.cmd.arg("-znow");
+    }
+
+    fn partial_relro(&mut self) {
+        self.cmd.arg("-zrelro");
+    }
+
+    fn no_relro(&mut self) {
+        self.cmd.arg("-znorelro");
+    }
+
+    fn cmd(&mut self) -> &mut Command {
+        &mut self.cmd
+    }
+
+    fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
+
+    fn link_rust_dylib(&mut self, _: Symbol, _: &Path) {
+        panic!("Rust dylibs not supported");
+    }
+
+    fn link_framework(&mut self, _framework: Symbol, _as_needed: bool) {
+        bug!("frameworks not supported on L4Re");
+    }
+
+    fn link_whole_staticlib(&mut self, lib: Symbol, _verbatim: bool, _search_path: &[PathBuf]) {
+        self.hint_static();
+        self.cmd.arg("--whole-archive").arg(format!("-l{}", lib));
+        self.cmd.arg("--no-whole-archive");
+    }
+
+    fn link_whole_rlib(&mut self, lib: &Path) {
+        self.hint_static();
+        self.cmd.arg("--whole-archive").arg(lib).arg("--no-whole-archive");
+    }
+
+    fn gc_sections(&mut self, keep_metadata: bool) {
+        if !keep_metadata {
+            self.cmd.arg("--gc-sections");
+        }
+    }
+
+    fn no_gc_sections(&mut self) {
+        self.cmd.arg("--no-gc-sections");
+    }
+
+    fn optimize(&mut self) {
+        // GNU-style linkers support optimization with -O. GNU ld doesn't
+        // need a numeric argument, but other linkers do.
+        if self.sess.opts.optimize == config::OptLevel::Default
+            || self.sess.opts.optimize == config::OptLevel::Aggressive
+        {
+            self.cmd.arg("-O1");
+        }
+    }
+
+    fn pgo_gen(&mut self) {}
+
+    fn debuginfo(&mut self, strip: Strip) {
+        match strip {
+            Strip::None => {}
+            Strip::Debuginfo => {
+                self.cmd().arg("--strip-debug");
+            }
+            Strip::Symbols => {
+                self.cmd().arg("--strip-all");
+            }
+        }
+    }
+
+    fn no_default_libraries(&mut self) {
+        self.cmd.arg("-nostdlib");
+    }
+
+    fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
+        // ToDo, not implemented, copy from GCC
+        self.sess.warn("exporting symbols not implemented yet for L4Bender");
+        return;
+    }
+
+    fn subsystem(&mut self, subsystem: &str) {
+        self.cmd.arg(&format!("--subsystem {}", subsystem));
+    }
+
+    fn reset_per_library_state(&mut self) {
+        self.hint_static(); // Reset to default before returning the composed command line.
+    }
+
+    fn group_start(&mut self) {
+        self.cmd.arg("--start-group");
+    }
+
+    fn group_end(&mut self) {
+        self.cmd.arg("--end-group");
+    }
+
+    fn linker_plugin_lto(&mut self) {}
+
+    fn control_flow_guard(&mut self) {}
+
+    fn no_crt_objects(&mut self) {}
+}
+
+impl<'a> L4Bender<'a> {
+    pub fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> {
+        L4Bender { cmd: cmd, sess: sess, hinted_static: false }
+    }
+
+    fn hint_static(&mut self) {
+        if !self.hinted_static {
+            self.cmd.arg("-static");
+            self.hinted_static = true;
+        }
+    }
+}
+
 pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
     if let Some(ref exports) = tcx.sess.target.override_export_symbols {
         return exports.clone();
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 5ce4e606fd2..4c7a09ca1e9 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -477,6 +477,28 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         helper.do_call(self, &mut bx, fn_abi, llfn, &args, None, cleanup);
     }
 
+    fn codegen_abort_terminator(
+        &mut self,
+        helper: TerminatorCodegenHelper<'tcx>,
+        mut bx: Bx,
+        terminator: &mir::Terminator<'tcx>,
+    ) {
+        let span = terminator.source_info.span;
+        self.set_debug_loc(&mut bx, terminator.source_info);
+
+        // Get the location information.
+        let location = self.get_caller_location(&mut bx, terminator.source_info).immediate();
+
+        // Obtain the panic entry point.
+        let def_id = common::langcall(bx.tcx(), Some(span), "", LangItem::PanicNoUnwind);
+        let instance = ty::Instance::mono(bx.tcx(), def_id);
+        let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
+        let llfn = bx.get_fn_addr(instance);
+
+        // Codegen the actual panic invoke/call.
+        helper.do_call(self, &mut bx, fn_abi, llfn, &[location], None, None);
+    }
+
     /// Returns `true` if this is indeed a panic intrinsic and codegen is done.
     fn codegen_panic_intrinsic(
         &mut self,
@@ -1014,10 +1036,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             mir::TerminatorKind::Resume => self.codegen_resume_terminator(helper, bx),
 
             mir::TerminatorKind::Abort => {
-                bx.abort();
-                // `abort` does not terminate the block, so we still need to generate
-                // an `unreachable` terminator after it.
-                bx.unreachable();
+                self.codegen_abort_terminator(helper, bx, terminator);
             }
 
             mir::TerminatorKind::Goto { target } => {
@@ -1327,8 +1346,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     let mut cp_bx = self.new_block(&format!("cp_funclet{:?}", bb));
                     ret_llbb = cs_bx.llbb();
 
-                    let cs = cs_bx.catch_switch(None, None, 1);
-                    cs_bx.add_handler(cs, cp_bx.llbb());
+                    let cs = cs_bx.catch_switch(None, None, &[cp_bx.llbb()]);
 
                     // The "null" here is actually a RTTI type descriptor for the
                     // C++ personality function, but `catch (...)` has no type so
@@ -1355,8 +1373,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
             let llpersonality = self.cx.eh_personality();
             let llretty = self.landing_pad_type();
-            let lp = bx.landing_pad(llretty, llpersonality, 1);
-            bx.set_cleanup(lp);
+            let lp = bx.cleanup_landing_pad(llretty, llpersonality);
 
             let slot = self.get_personality_slot(&mut bx);
             slot.storage_live(&mut bx);
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 3657f80c2de..c654232c10a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -369,6 +369,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 }
             }
 
+            sym::const_allocate => {
+                // returns a null pointer at runtime.
+                bx.const_null(bx.type_i8p())
+            }
+
+            sym::const_deallocate => {
+                // nop at runtime.
+                return;
+            }
+
             // This requires that atomic intrinsics follow a specific naming pattern:
             // "atomic_<operation>[_<ordering>]", and no ordering means SeqCst
             name if name_str.starts_with("atomic_") => {
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 5a06fb46105..53fb21b269a 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -421,29 +421,22 @@ pub trait BuilderMethods<'a, 'tcx>:
     fn extract_value(&mut self, agg_val: Self::Value, idx: u64) -> Self::Value;
     fn insert_value(&mut self, agg_val: Self::Value, elt: Self::Value, idx: u64) -> Self::Value;
 
-    fn landing_pad(
-        &mut self,
-        ty: Self::Type,
-        pers_fn: Self::Value,
-        num_clauses: usize,
-    ) -> Self::Value;
-    fn set_cleanup(&mut self, landing_pad: Self::Value);
-    fn resume(&mut self, exn: Self::Value) -> Self::Value;
+    fn set_personality_fn(&mut self, personality: Self::Value);
+
+    // These are used by everyone except msvc
+    fn cleanup_landing_pad(&mut self, ty: Self::Type, pers_fn: Self::Value) -> Self::Value;
+    fn resume(&mut self, exn: Self::Value);
+
+    // These are used only by msvc
     fn cleanup_pad(&mut self, parent: Option<Self::Value>, args: &[Self::Value]) -> Self::Funclet;
-    fn cleanup_ret(
-        &mut self,
-        funclet: &Self::Funclet,
-        unwind: Option<Self::BasicBlock>,
-    ) -> Self::Value;
+    fn cleanup_ret(&mut self, funclet: &Self::Funclet, unwind: Option<Self::BasicBlock>);
     fn catch_pad(&mut self, parent: Self::Value, args: &[Self::Value]) -> Self::Funclet;
     fn catch_switch(
         &mut self,
         parent: Option<Self::Value>,
         unwind: Option<Self::BasicBlock>,
-        num_handlers: usize,
+        handlers: &[Self::BasicBlock],
     ) -> Self::Value;
-    fn add_handler(&mut self, catch_switch: Self::Value, handler: Self::BasicBlock);
-    fn set_personality_fn(&mut self, personality: Self::Value);
 
     fn atomic_cmpxchg(
         &mut self,
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 3ec9f3ca3b8..9dc34260de7 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -7,7 +7,6 @@ use crate::interpret::{
 };
 
 use rustc_errors::ErrorReported;
-use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::ErrorHandled;
@@ -216,7 +215,7 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
 ) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
-    assert!(key.param_env.constness() == hir::Constness::Const);
+    assert!(key.param_env.is_const());
     // see comment in eval_to_allocation_raw_provider for what we're doing here
     if key.param_env.reveal() == Reveal::All {
         let mut key = key;
@@ -251,7 +250,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
     tcx: TyCtxt<'tcx>,
     key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
 ) -> ::rustc_middle::mir::interpret::EvalToAllocationRawResult<'tcx> {
-    assert!(key.param_env.constness() == hir::Constness::Const);
+    assert!(key.param_env.is_const());
     // Because the constant is computed twice (once per value of `Reveal`), we are at risk of
     // reporting the same error twice here. To resolve this, we check whether we can evaluate the
     // constant in the more restrictive `Reveal::UserFacing`, which most likely already was
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 30e9cbe4403..89717b75f12 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -347,6 +347,33 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
                 )?;
                 ecx.write_pointer(ptr, dest)?;
             }
+            sym::const_deallocate => {
+                let ptr = ecx.read_pointer(&args[0])?;
+                let size = ecx.read_scalar(&args[1])?.to_machine_usize(ecx)?;
+                let align = ecx.read_scalar(&args[2])?.to_machine_usize(ecx)?;
+
+                let size = Size::from_bytes(size);
+                let align = match Align::from_bytes(align) {
+                    Ok(a) => a,
+                    Err(err) => throw_ub_format!("align has to be a power of 2, {}", err),
+                };
+
+                // If an allocation is created in an another const,
+                // we don't deallocate it.
+                let (alloc_id, _, _) = ecx.memory.ptr_get_alloc(ptr)?;
+                let is_allocated_in_another_const = matches!(
+                    ecx.tcx.get_global_alloc(alloc_id),
+                    Some(interpret::GlobalAlloc::Memory(_))
+                );
+
+                if !is_allocated_in_another_const {
+                    ecx.memory.deallocate(
+                        ptr,
+                        Some((size, align)),
+                        interpret::MemoryKind::Machine(MemoryKind::Heap),
+                    )?;
+                }
+            }
             _ => {
                 return Err(ConstEvalErrKind::NeedsRfc(format!(
                     "calling intrinsic `{}`",
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index cf939aaa73f..91610b15eb9 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -4,11 +4,12 @@
 
 use rustc_errors::ErrorReported;
 use rustc_infer::infer::TyCtxtInferExt;
+use rustc_infer::traits::TraitEngine;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
 use rustc_span::DUMMY_SP;
 use rustc_trait_selection::traits::{
-    self, ImplSource, Obligation, ObligationCause, SelectionContext,
+    self, FulfillmentContext, ImplSource, Obligation, ObligationCause, SelectionContext,
 };
 
 use super::ConstCx;
@@ -145,15 +146,10 @@ impl Qualif for NeedsNonConstDrop {
         qualifs.needs_non_const_drop
     }
 
-    fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, mut ty: Ty<'tcx>) -> bool {
-        // Avoid selecting for simple cases.
-        match ty::util::needs_drop_components(ty, &cx.tcx.data_layout).as_deref() {
-            Ok([]) => return false,
-            Err(ty::util::AlwaysRequiresDrop) => return true,
-            // If we've got a single component, select with that
-            // to increase the chance that we hit the selection cache.
-            Ok([t]) => ty = t,
-            Ok([..]) => {}
+    fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
+        // Avoid selecting for simple cases, such as builtin types.
+        if ty::util::is_trivially_const_drop(ty) {
+            return false;
         }
 
         let Some(drop_trait) = cx.tcx.lang_items().drop_trait() else {
@@ -161,28 +157,50 @@ impl Qualif for NeedsNonConstDrop {
             // without having the lang item present.
             return false;
         };
-        let trait_ref =
-            ty::TraitRef { def_id: drop_trait, substs: cx.tcx.mk_substs_trait(ty, &[]) };
+
         let obligation = Obligation::new(
             ObligationCause::dummy(),
             cx.param_env,
             ty::Binder::dummy(ty::TraitPredicate {
-                trait_ref,
+                trait_ref: ty::TraitRef {
+                    def_id: drop_trait,
+                    substs: cx.tcx.mk_substs_trait(ty, &[]),
+                },
                 constness: ty::BoundConstness::ConstIfConst,
                 polarity: ty::ImplPolarity::Positive,
             }),
         );
 
-        let implsrc = cx.tcx.infer_ctxt().enter(|infcx| {
+        cx.tcx.infer_ctxt().enter(|infcx| {
             let mut selcx = SelectionContext::new(&infcx);
-            selcx.select(&obligation)
-        });
-        !matches!(
-            implsrc,
-            Ok(Some(
+            let Some(impl_src) = selcx.select(&obligation).ok().flatten() else {
+                // If we couldn't select a const drop candidate, then it's bad
+                return true;
+            };
+
+            if !matches!(
+                impl_src,
                 ImplSource::ConstDrop(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
-            ))
-        )
+            ) {
+                // If our const drop candidate is not ConstDrop or implied by the param env,
+                // then it's bad
+                return true;
+            }
+
+            if impl_src.borrow_nested_obligations().is_empty() {
+                return false;
+            }
+
+            // If we successfully found one, then select all of the predicates
+            // implied by our const drop impl.
+            let mut fcx = FulfillmentContext::new();
+            for nested in impl_src.nested_obligations() {
+                fcx.register_predicate_obligation(&infcx, nested);
+            }
+
+            // If we had any errors, then it's bad
+            !fcx.select_all_or_error(&infcx).is_empty()
+        })
     }
 
     fn in_adt_inherently<'tcx>(
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 2bb9d6c1893..ad296c97659 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -9,7 +9,7 @@ doctest = false
 [dependencies]
 arrayvec = { version = "0.7", default-features = false }
 ena = "0.14"
-indexmap = "1.5.1"
+indexmap = { version = "1.8.0", features = ["rustc-rayon"] }
 tracing = "0.1"
 jobserver_crate = { version = "0.1.13", package = "jobserver" }
 rustc_serialize = { path = "../rustc_serialize" }
diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs
index c9af35da4bc..525cd650dd2 100644
--- a/compiler/rustc_data_structures/src/fingerprint.rs
+++ b/compiler/rustc_data_structures/src/fingerprint.rs
@@ -149,10 +149,10 @@ impl<E: rustc_serialize::Encoder> Encodable<E> for Fingerprint {
 
 impl<D: rustc_serialize::Decoder> Decodable<D> for Fingerprint {
     #[inline]
-    fn decode(d: &mut D) -> Result<Self, D::Error> {
+    fn decode(d: &mut D) -> Self {
         let mut bytes = [0u8; 16];
-        d.read_raw_bytes_into(&mut bytes)?;
-        Ok(Fingerprint::from_le_bytes(bytes))
+        d.read_raw_bytes_into(&mut bytes);
+        Fingerprint::from_le_bytes(bytes)
     }
 }
 
@@ -195,8 +195,8 @@ impl<E: rustc_serialize::Encoder> Encodable<E> for PackedFingerprint {
 
 impl<D: rustc_serialize::Decoder> Decodable<D> for PackedFingerprint {
     #[inline]
-    fn decode(d: &mut D) -> Result<Self, D::Error> {
-        Fingerprint::decode(d).map(PackedFingerprint)
+    fn decode(d: &mut D) -> Self {
+        Self(Fingerprint::decode(d))
     }
 }
 
diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs
index 872b0eb7854..53062b9c20d 100644
--- a/compiler/rustc_data_structures/src/sip128.rs
+++ b/compiler/rustc_data_structures/src/sip128.rs
@@ -409,20 +409,6 @@ impl SipHasher128 {
     }
 }
 
-macro_rules! dispatch_value {
-    ($target: expr, $value:expr) => {
-        let value = $value;
-        #[allow(unreachable_patterns)]
-        #[allow(overflowing_literals)]
-        match value {
-            0..=0xFF => $target.short_write(value as u8),
-            0x100..=0xFFFF => $target.short_write(value as u16),
-            0x10000..=0xFFFFFFFF => $target.short_write(value as u32),
-            _ => $target.short_write(value as u64),
-        }
-    };
-}
-
 impl Hasher for SipHasher128 {
     #[inline]
     fn write_u8(&mut self, i: u8) {
@@ -436,7 +422,7 @@ impl Hasher for SipHasher128 {
 
     #[inline]
     fn write_u32(&mut self, i: u32) {
-        dispatch_value!(self, i);
+        self.short_write(i);
     }
 
     #[inline]
@@ -466,7 +452,7 @@ impl Hasher for SipHasher128 {
 
     #[inline]
     fn write_i64(&mut self, i: i64) {
-        dispatch_value!(self, i as u64);
+        self.short_write(i as u64);
     }
 
     #[inline]
diff --git a/compiler/rustc_data_structures/src/stable_hasher/tests.rs b/compiler/rustc_data_structures/src/stable_hasher/tests.rs
index 391db67d29d..31190363eb6 100644
--- a/compiler/rustc_data_structures/src/stable_hasher/tests.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher/tests.rs
@@ -98,3 +98,45 @@ fn test_hash_bit_matrix() {
     assert_ne!(a, b);
     assert_ne!(hash(&a), hash(&b));
 }
+
+// Check that exchanging the value of two adjacent fields changes the hash.
+#[test]
+fn test_attribute_permutation() {
+    macro_rules! test_type {
+        ($ty: ty) => {{
+            struct Foo {
+                a: $ty,
+                b: $ty,
+            }
+
+            impl<CTX> HashStable<CTX> for Foo {
+                fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
+                    self.a.hash_stable(hcx, hasher);
+                    self.b.hash_stable(hcx, hasher);
+                }
+            }
+
+            #[allow(overflowing_literals)]
+            let mut item = Foo { a: 0xFF, b: 0xFF_FF };
+            let hash_a = hash(&item);
+            std::mem::swap(&mut item.a, &mut item.b);
+            let hash_b = hash(&item);
+            assert_ne!(
+                hash_a,
+                hash_b,
+                "The hash stayed the same after values were swapped for type `{}`!",
+                stringify!($ty)
+            );
+        }};
+    }
+
+    test_type!(u16);
+    test_type!(u32);
+    test_type!(u64);
+    test_type!(u128);
+
+    test_type!(i16);
+    test_type!(i32);
+    test_type!(i64);
+    test_type!(i128);
+}
diff --git a/compiler/rustc_data_structures/src/svh.rs b/compiler/rustc_data_structures/src/svh.rs
index ce90fbacaa4..12ef286091c 100644
--- a/compiler/rustc_data_structures/src/svh.rs
+++ b/compiler/rustc_data_structures/src/svh.rs
@@ -55,8 +55,8 @@ impl<S: Encoder> Encodable<S> for Svh {
 }
 
 impl<D: Decoder> Decodable<D> for Svh {
-    fn decode(d: &mut D) -> Result<Svh, D::Error> {
-        d.read_u64().map(u64::from_le).map(Svh::new)
+    fn decode(d: &mut D) -> Svh {
+        Svh::new(u64::from_le(d.read_u64()))
     }
 }
 
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 19fa6812b45..2b64312dbef 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -597,10 +597,7 @@ impl RustcDefaultCalls {
                 let rlink_data = fs::read_to_string(file).unwrap_or_else(|err| {
                     sess.fatal(&format!("failed to read rlink file: {}", err));
                 });
-                let codegen_results: CodegenResults =
-                    json::decode(&rlink_data).unwrap_or_else(|err| {
-                        sess.fatal(&format!("failed to decode rlink: {}", err));
-                    });
+                let codegen_results: CodegenResults = json::decode(&rlink_data);
                 let result = compiler.codegen_backend().link(sess, codegen_results, &outputs);
                 abort_on_err(result, sess);
             } else {
diff --git a/compiler/rustc_error_codes/src/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs
index 79d9c55b547..c401f65edda 100644
--- a/compiler/rustc_error_codes/src/error_codes.rs
+++ b/compiler/rustc_error_codes/src/error_codes.rs
@@ -472,6 +472,7 @@ E0768: include_str!("./error_codes/E0768.md"),
 E0769: include_str!("./error_codes/E0769.md"),
 E0770: include_str!("./error_codes/E0770.md"),
 E0771: include_str!("./error_codes/E0771.md"),
+E0772: include_str!("./error_codes/E0772.md"),
 E0773: include_str!("./error_codes/E0773.md"),
 E0774: include_str!("./error_codes/E0774.md"),
 E0775: include_str!("./error_codes/E0775.md"),
@@ -486,6 +487,7 @@ E0783: include_str!("./error_codes/E0783.md"),
 E0784: include_str!("./error_codes/E0784.md"),
 E0785: include_str!("./error_codes/E0785.md"),
 E0786: include_str!("./error_codes/E0786.md"),
+E0787: include_str!("./error_codes/E0787.md"),
 ;
 //  E0006, // merged with E0005
 //  E0008, // cannot bind by-move into a pattern guard
@@ -641,5 +643,4 @@ E0786: include_str!("./error_codes/E0786.md"),
 //  E0723, // unstable feature in `const` context
     E0726, // non-explicit (not `'_`) elided lifetime in unsupported position
 //  E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`.
-    E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`.
 }
diff --git a/compiler/rustc_error_codes/src/error_codes/E0772.md b/compiler/rustc_error_codes/src/error_codes/E0772.md
new file mode 100644
index 00000000000..262e52351ef
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0772.md
@@ -0,0 +1,89 @@
+A trait object has some specific lifetime `'1`, but it was used in a way that
+requires it to have a `'static` lifetime.
+
+Example of erroneous code:
+
+```compile_fail,E0772
+trait BooleanLike {}
+trait Person {}
+
+impl BooleanLike for bool {}
+
+impl dyn Person {
+    fn is_cool(&self) -> bool {
+        // hey you, you're pretty cool
+        true
+    }
+}
+
+fn get_is_cool<'p>(person: &'p dyn Person) -> impl BooleanLike {
+    // error: `person` has an anonymous lifetime `'p` but calling
+    //        `print_cool_fn` introduces an implicit `'static` lifetime
+    //        requirement
+    person.is_cool()
+}
+```
+
+The trait object `person` in the function `get_is_cool`, while already being
+behind a reference with lifetime `'p`, also has it's own implicit lifetime,
+`'2`.
+
+Lifetime `'2` represents the data the trait object might hold inside, for
+example:
+
+```
+trait MyTrait {}
+
+struct MyStruct<'a>(&'a i32);
+
+impl<'a> MyTrait for MyStruct<'a> {}
+```
+
+With this scenario, if a trait object of `dyn MyTrait + '2` was made from
+`MyStruct<'a>`, `'a` must live as long, if not longer than `'2`. This allows the
+trait object's internal data to be accessed safely from any trait methods. This
+rule also goes for any lifetime any struct made into a trait object may have.
+
+In the implementation for `dyn Person`, the `'2` lifetime representing the
+internal data was ommitted, meaning that the compiler inferred the lifetime
+`'static`. As a result, the implementation's `is_cool` is inferred by the
+compiler to look like this:
+
+```
+# trait Person {}
+#
+# impl dyn Person {
+fn is_cool<'a>(self: &'a (dyn Person + 'static)) -> bool {unimplemented!()}
+# }
+```
+
+While the `get_is_cool` function is inferred to look like this:
+
+```
+# trait Person {}
+# trait BooleanLike {}
+#
+fn get_is_cool<'p, R: BooleanLike>(person: &'p (dyn Person + 'p)) -> R {
+    unimplemented!()
+}
+```
+
+Which brings us to the core of the problem; the assignment of type
+`&'_ (dyn Person + '_)` to type `&'_ (dyn Person + 'static)` is impossible.
+
+Fixing it is as simple as being generic over lifetime `'2`, as to prevent the
+compiler from inferring it as `'static`:
+
+```
+# trait Person {}
+#
+impl<'d> dyn Person + 'd {/* ... */}
+
+// This works too, and is more elegant:
+//impl dyn Person + '_ {/* ... */}
+```
+
+See the [Rust Reference on Trait Object Lifetime Bounds][trait-objects] for
+more information on trait object lifetimes.
+
+[trait-object-lifetime-bounds]: https://doc.rust-lang.org/reference/types/trait-object.html#trait-object-lifetime-bounds
diff --git a/compiler/rustc_error_codes/src/error_codes/E0787.md b/compiler/rustc_error_codes/src/error_codes/E0787.md
new file mode 100644
index 00000000000..cee50829270
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0787.md
@@ -0,0 +1,28 @@
+An unsupported naked function definition.
+
+Erroneous code example:
+
+```compile_fail,E0787
+#![feature(naked_functions)]
+
+#[naked]
+pub extern "C" fn f() -> u32 {
+    42
+}
+```
+
+The naked functions must be defined using a single inline assembly
+block.
+
+The execution must never fall through past the end of the assembly
+code so the block must use `noreturn` option. The asm block can also
+use `att_syntax` and `raw` options, but others options are not allowed.
+
+The asm block must not contain any operands other than `const` and
+`sym`.
+
+### Additional information
+
+For more information, please see [RFC 2972].
+
+[RFC 2972]: https://github.com/rust-lang/rfcs/blob/master/text/2972-constrained-naked.md
diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs
index d055937ac36..c5b3d204407 100644
--- a/compiler/rustc_errors/src/json/tests.rs
+++ b/compiler/rustc_errors/src/json/tests.rs
@@ -64,7 +64,7 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
 
         let bytes = output.lock().unwrap();
         let actual_output = str::from_utf8(&bytes).unwrap();
-        let actual_output: TestData = decode(actual_output).unwrap();
+        let actual_output: TestData = decode(actual_output);
 
         assert_eq!(expected_output, actual_output)
     })
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index a681298301a..16e9b265d69 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -99,8 +99,8 @@ impl Hash for ToolMetadata {
 
 // Doesn't really need to round-trip
 impl<D: Decoder> Decodable<D> for ToolMetadata {
-    fn decode(_d: &mut D) -> Result<Self, D::Error> {
-        Ok(ToolMetadata(None))
+    fn decode(_d: &mut D) -> Self {
+        ToolMetadata(None)
     }
 }
 
@@ -445,9 +445,6 @@ struct HandlerInner {
     deduplicated_warn_count: usize,
 
     future_breakage_diagnostics: Vec<Diagnostic>,
-
-    /// If set to `true`, no warning or error will be emitted.
-    quiet: bool,
 }
 
 /// A key denoting where from a diagnostic was stashed.
@@ -563,19 +560,10 @@ impl Handler {
                 emitted_diagnostics: Default::default(),
                 stashed_diagnostics: Default::default(),
                 future_breakage_diagnostics: Vec::new(),
-                quiet: false,
             }),
         }
     }
 
-    pub fn with_disabled_diagnostic<T, F: FnOnce() -> T>(&self, f: F) -> T {
-        let prev = self.inner.borrow_mut().quiet;
-        self.inner.borrow_mut().quiet = true;
-        let ret = f();
-        self.inner.borrow_mut().quiet = prev;
-        ret
-    }
-
     // This is here to not allow mutation of flags;
     // as of this writing it's only used in tests in librustc_middle.
     pub fn can_emit_warnings(&self) -> bool {
@@ -946,7 +934,7 @@ impl HandlerInner {
     }
 
     fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) {
-        if diagnostic.cancelled() || self.quiet {
+        if diagnostic.cancelled() {
             return;
         }
 
@@ -1170,9 +1158,6 @@ impl HandlerInner {
     }
 
     fn delay_as_bug(&mut self, diagnostic: Diagnostic) {
-        if self.quiet {
-            return;
-        }
         if self.flags.report_delayed_bugs {
             self.emit_diagnostic(&diagnostic);
         }
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 07b5e20b2dd..258320aeb63 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -8,7 +8,7 @@ use rustc_ast::tokenstream::{CanSynthesizeMissingTokens, TokenStream};
 use rustc_ast::visit::{AssocCtxt, Visitor};
 use rustc_ast::{self as ast, AstLike, Attribute, Item, NodeId, PatKind};
 use rustc_attr::{self as attr, Deprecation, Stability};
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::{self, Lrc};
 use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported};
 use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
@@ -920,8 +920,25 @@ pub trait ResolverExpand {
     /// we generated proc macros harnesses, so that we can map
     /// HIR proc macros items back to their harness items.
     fn declare_proc_macro(&mut self, id: NodeId);
+
+    /// Tools registered with `#![register_tool]` and used by tool attributes and lints.
+    fn registered_tools(&self) -> &FxHashSet<Ident>;
 }
 
+pub trait LintStoreExpand {
+    fn pre_expansion_lint(
+        &self,
+        sess: &Session,
+        registered_tools: &FxHashSet<Ident>,
+        node_id: NodeId,
+        attrs: &[Attribute],
+        items: &[P<Item>],
+        name: &str,
+    );
+}
+
+type LintStoreExpandDyn<'a> = Option<&'a (dyn LintStoreExpand + 'a)>;
+
 #[derive(Clone, Default)]
 pub struct ModuleData {
     /// Path to the module starting from the crate name, like `my_crate::foo::bar`.
@@ -956,9 +973,6 @@ pub struct ExpansionData {
     pub is_trailing_mac: bool,
 }
 
-type OnExternModLoaded<'a> =
-    Option<&'a dyn Fn(Ident, Vec<Attribute>, Vec<P<Item>>, Span) -> (Vec<Attribute>, Vec<P<Item>>)>;
-
 /// One of these is made during expansion and incrementally updated as we go;
 /// when a macro expansion occurs, the resulting nodes have the `backtrace()
 /// -> expn_data` of their expansion context stored into their span.
@@ -973,10 +987,8 @@ pub struct ExtCtxt<'a> {
     /// (or during eager expansion, but that's a hack).
     pub force_mode: bool,
     pub expansions: FxHashMap<Span, Vec<String>>,
-    /// Called directly after having parsed an external `mod foo;` in expansion.
-    ///
-    /// `Ident` is the module name.
-    pub(super) extern_mod_loaded: OnExternModLoaded<'a>,
+    /// Used for running pre-expansion lints on freshly loaded modules.
+    pub(super) lint_store: LintStoreExpandDyn<'a>,
     /// When we 'expand' an inert attribute, we leave it
     /// in the AST, but insert it here so that we know
     /// not to expand it again.
@@ -988,14 +1000,14 @@ impl<'a> ExtCtxt<'a> {
         sess: &'a Session,
         ecfg: expand::ExpansionConfig<'a>,
         resolver: &'a mut dyn ResolverExpand,
-        extern_mod_loaded: OnExternModLoaded<'a>,
+        lint_store: LintStoreExpandDyn<'a>,
     ) -> ExtCtxt<'a> {
         ExtCtxt {
             sess,
             ecfg,
             reduced_recursion_limit: None,
             resolver,
-            extern_mod_loaded,
+            lint_store,
             root_path: PathBuf::new(),
             current_expansion: ExpansionData {
                 id: LocalExpnId::ROOT,
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 7604a464be2..9a4daa6d750 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1097,7 +1097,7 @@ impl InvocationCollectorNode for P<ast::Item> {
             ModKind::Unloaded => {
                 // We have an outline `mod foo;` so we need to parse the file.
                 let old_attrs_len = attrs.len();
-                let ParsedExternalMod { mut items, inner_span, file_path, dir_path, dir_ownership } =
+                let ParsedExternalMod { items, inner_span, file_path, dir_path, dir_ownership } =
                     parse_external_mod(
                         &ecx.sess,
                         ident,
@@ -1107,8 +1107,15 @@ impl InvocationCollectorNode for P<ast::Item> {
                         &mut attrs,
                     );
 
-                if let Some(extern_mod_loaded) = ecx.extern_mod_loaded {
-                    (attrs, items) = extern_mod_loaded(ident, attrs, items, inner_span);
+                if let Some(lint_store) = ecx.lint_store {
+                    lint_store.pre_expansion_lint(
+                        ecx.sess,
+                        ecx.resolver.registered_tools(),
+                        ecx.current_expansion.lint_node_id,
+                        &attrs,
+                        &items,
+                        ident.name.as_str(),
+                    );
                 }
 
                 *mod_kind = ModKind::Loaded(items, Inline::No, inner_span);
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index 5599c1df6d9..dfc07da9169 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -2,7 +2,6 @@
 #![feature(associated_type_defaults)]
 #![feature(crate_visibility_modifier)]
 #![feature(decl_macro)]
-#![cfg_attr(bootstrap, feature(destructuring_assignment))]
 #![feature(if_let_guard)]
 #![feature(let_else)]
 #![feature(proc_macro_diagnostic)]
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 723cc06864a..fc7f01f041d 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -625,7 +625,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
     rustc_attr!(
         rustc_pass_by_value, Normal,
-        template!(Word), WarnFollowing,
+        template!(Word), ErrorFollowing,
         "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
     ),
     BuiltinAttribute {
@@ -697,6 +697,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(TEST, rustc_capture_analysis, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_insignificant_dtor, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_strict_coherence, Normal, template!(Word), WarnFollowing),
+    rustc_attr!(TEST, rustc_with_negative_coherence, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_variance, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."), WarnFollowing),
     rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing),
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index e839f7fc777..74d6b05ca5f 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -107,8 +107,6 @@ pub struct Definitions {
     /// Their `HirId`s are defined by their position while lowering the enclosing owner.
     // FIXME(cjgillot) Some `LocalDefId`s from `use` items are dropped during lowering and lack a `HirId`.
     pub(super) def_id_to_hir_id: IndexVec<LocalDefId, Option<hir::HirId>>,
-    /// The reverse mapping of `def_id_to_hir_id`.
-    pub(super) hir_id_to_def_id: FxHashMap<hir::HirId, LocalDefId>,
 
     /// Item with a given `LocalDefId` was defined during macro expansion with ID `ExpnId`.
     expansions_that_defined: FxHashMap<LocalDefId, ExpnId>,
@@ -330,11 +328,6 @@ impl Definitions {
         self.def_id_to_hir_id[id].unwrap()
     }
 
-    #[inline]
-    pub fn opt_hir_id_to_local_def_id(&self, hir_id: hir::HirId) -> Option<LocalDefId> {
-        self.hir_id_to_def_id.get(&hir_id).copied()
-    }
-
     /// Adds a root definition (no parent) and a few other reserved definitions.
     pub fn new(stable_crate_id: StableCrateId, crate_span: Span) -> Definitions {
         let key = DefKey {
@@ -362,7 +355,6 @@ impl Definitions {
         Definitions {
             table,
             def_id_to_hir_id: Default::default(),
-            hir_id_to_def_id: Default::default(),
             expansions_that_defined: Default::default(),
             def_id_to_span,
             stable_crate_id,
@@ -425,12 +417,6 @@ impl Definitions {
             "trying to initialize `LocalDefId` <-> `HirId` mappings twice"
         );
 
-        // Build the reverse mapping of `def_id_to_hir_id`.
-        self.hir_id_to_def_id = mapping
-            .iter_enumerated()
-            .filter_map(|(def_id, hir_id)| hir_id.map(|hir_id| (hir_id, def_id)))
-            .collect();
-
         self.def_id_to_hir_id = mapping;
     }
 
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 4e6fac5eb28..a0ed72c9e9e 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -707,6 +707,8 @@ pub struct OwnerNodes<'tcx> {
     pub nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>,
     /// Content of local bodies.
     pub bodies: SortedMap<ItemLocalId, &'tcx Body<'tcx>>,
+    /// Non-owning definitions contained in this owner.
+    pub local_id_to_def_id: SortedMap<ItemLocalId, LocalDefId>,
 }
 
 /// Full information resulting from lowering an AST node.
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index def0c1d0687..be4849d0b84 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -283,6 +283,7 @@ language_item_table! {
     PanicInfo,               sym::panic_info,          panic_info,                 Target::Struct,         GenericRequirement::None;
     PanicLocation,           sym::panic_location,      panic_location,             Target::Struct,         GenericRequirement::None;
     PanicImpl,               sym::panic_impl,          panic_impl,                 Target::Fn,             GenericRequirement::None;
+    PanicNoUnwind,           sym::panic_no_unwind,     panic_no_unwind,            Target::Fn,             GenericRequirement::Exact(0);
     /// libstd panic entry point. Necessary for const eval to be able to catch it
     BeginPanic,              sym::begin_panic,         begin_panic_fn,             Target::Fn,             GenericRequirement::None;
 
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index a43c1f9d9ae..b15054ae6d6 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -208,8 +208,13 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<'
     fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
         // We ignore the `nodes` and `bodies` fields since these refer to information included in
         // `hash` which is hashed in the collector and used for the crate hash.
-        let OwnerNodes { hash_including_bodies, hash_without_bodies: _, nodes: _, bodies: _ } =
-            *self;
+        let OwnerNodes {
+            hash_including_bodies,
+            hash_without_bodies: _,
+            nodes: _,
+            bodies: _,
+            local_id_to_def_id: _,
+        } = *self;
         hash_including_bodies.hash_stable(hcx, hasher);
     }
 }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 9e54122f8dd..a47ebaf1237 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -571,7 +571,7 @@ impl<'a> State<'a> {
                 self.ann.nested(self, Nested::Body(body));
             }
             hir::ItemKind::Macro(ref macro_def) => {
-                self.print_mac_def(macro_def, &item.ident, &item.span, |state| {
+                self.print_mac_def(macro_def, &item.ident, item.span, |state| {
                     state.print_visibility(&item.vis)
                 });
             }
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index d563a6ca478..870c3f80682 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -158,14 +158,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
             // Decode the list of work_products
             let mut work_product_decoder = Decoder::new(&work_products_data[..], start_pos);
             let work_products: Vec<SerializedWorkProduct> =
-                Decodable::decode(&mut work_product_decoder).unwrap_or_else(|e| {
-                    let msg = format!(
-                        "Error decoding `work-products` from incremental \
-                                    compilation session directory: {}",
-                        e
-                    );
-                    sess.fatal(&msg)
-                });
+                Decodable::decode(&mut work_product_decoder);
 
             for swp in work_products {
                 let mut all_files_exist = true;
@@ -203,8 +196,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
             LoadResult::Error { message } => LoadResult::Error { message },
             LoadResult::Ok { data: (bytes, start_pos) } => {
                 let mut decoder = Decoder::new(&bytes, start_pos);
-                let prev_commandline_args_hash = u64::decode(&mut decoder)
-                    .expect("Error reading commandline arg hash from cached dep-graph");
+                let prev_commandline_args_hash = u64::decode(&mut decoder);
 
                 if prev_commandline_args_hash != expected_hash {
                     if report_incremental_info {
@@ -220,8 +212,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
                     return LoadResult::DataOutOfDate;
                 }
 
-                let dep_graph = SerializedDepGraph::decode(&mut decoder)
-                    .expect("Error reading cached dep-graph");
+                let dep_graph = SerializedDepGraph::decode(&mut decoder);
 
                 LoadResult::Ok { data: (dep_graph, prev_work_products) }
             }
diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs
index e3c6528b218..8b61530577d 100644
--- a/compiler/rustc_index/src/vec.rs
+++ b/compiler/rustc_index/src/vec.rs
@@ -395,8 +395,8 @@ macro_rules! newtype_index {
 
     (@serializable $type:ident) => (
         impl<D: ::rustc_serialize::Decoder> ::rustc_serialize::Decodable<D> for $type {
-            fn decode(d: &mut D) -> Result<Self, D::Error> {
-                d.read_u32().map(Self::from_u32)
+            fn decode(d: &mut D) -> Self {
+                Self::from_u32(d.read_u32())
             }
         }
         impl<E: ::rustc_serialize::Encoder> ::rustc_serialize::Encodable<E> for $type {
@@ -527,8 +527,8 @@ impl<S: Encoder, I: Idx, T: Encodable<S>> Encodable<S> for &IndexVec<I, T> {
 }
 
 impl<D: Decoder, I: Idx, T: Decodable<D>> Decodable<D> for IndexVec<I, T> {
-    fn decode(d: &mut D) -> Result<Self, D::Error> {
-        Decodable::decode(d).map(|v| IndexVec { raw: v, _marker: PhantomData })
+    fn decode(d: &mut D) -> Self {
+        IndexVec { raw: Decodable::decode(d), _marker: PhantomData }
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 14ab635a2ae..1eb8190bd7d 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -2650,7 +2650,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
             infer::LateBoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!(
                 " for lifetime parameter {}in trait containing associated type `{}`",
                 br_string(br),
-                self.tcx.associated_item(def_id).ident
+                self.tcx.associated_item(def_id).name
             ),
             infer::EarlyBoundRegion(_, name) => format!(" for lifetime parameter `{}`", name),
             infer::UpvarRegion(ref upvar_id, _) => {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 412a077959d..0a9f59fbc97 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -70,7 +70,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                             .map(|s| format!("`{}`", s))
                             .unwrap_or_else(|| "`fn` parameter".to_string()),
                         lifetime,
-                        ctxt.assoc_item.ident,
+                        ctxt.assoc_item.name,
                     );
                     err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
                     err.span_label(
@@ -231,7 +231,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                 // Handle case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a
                 // `'static` lifetime when called as a method on a binding: `bar.qux()`.
                 if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {
-                    override_error_code = Some(ctxt.assoc_item.ident);
+                    override_error_code = Some(ctxt.assoc_item.name);
                 }
             }
         }
@@ -252,7 +252,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                     self.get_impl_ident_and_self_ty_from_trait(*item_def_id, &v.0)
                 {
                     if self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0, ident, self_ty) {
-                        override_error_code = Some(ident);
+                        override_error_code = Some(ident.name);
                     }
                 }
             }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 266eec08ceb..d1b24b332bd 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -195,7 +195,7 @@ pub struct InferCtxtInner<'tcx> {
     // Opaque types found in explicit return types and their
     // associated fresh inference variable. Writeback resolves these
     // variables to get the concrete type, which can be used to
-    // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions.
+    // 'de-opaque' OpaqueTypeDecl outside of type inference.
     pub opaque_types: OpaqueTypeMap<'tcx>,
 
     /// A map from inference variables created from opaque
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 4851e637d3a..e7dca94806c 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -569,13 +569,15 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
             let predicate = predicate.fold_with(&mut BottomUpFolder {
                 tcx,
                 ty_op: |ty| match ty.kind() {
-                    ty::Projection(projection_ty) => infcx.infer_projection(
-                        self.param_env,
-                        *projection_ty,
-                        traits::ObligationCause::misc(self.value_span, self.body_id),
-                        0,
-                        &mut self.obligations,
-                    ),
+                    ty::Projection(projection_ty) if !projection_ty.has_escaping_bound_vars() => {
+                        infcx.infer_projection(
+                            self.param_env,
+                            *projection_ty,
+                            traits::ObligationCause::misc(self.value_span, self.body_id),
+                            0,
+                            &mut self.obligations,
+                        )
+                    }
                     _ => ty,
                 },
                 lt_op: |lt| lt,
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 3804e100307..26343561959 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -124,7 +124,16 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String
                     Err(errs) => errs.into_iter().for_each(|mut err| err.cancel()),
                 }
 
-                error!(r#"expected `key` or `key="value"`"#);
+                // If the user tried to use a key="value" flag, but is missing the quotes, provide
+                // a hint about how to resolve this.
+                if s.contains("=") && !s.contains("=\"") && !s.ends_with("\"") {
+                    error!(concat!(
+                        r#"expected `key` or `key="value"`, ensure escaping is appropriate"#,
+                        r#" for your shell, try 'key="value"' or key=\"value\""#
+                    ));
+                } else {
+                    error!(r#"expected `key` or `key="value"`"#);
+                }
             })
             .collect::<CrateConfig>();
         cfg.into_iter().map(|(a, b)| (a.to_string(), b.map(|b| b.to_string()))).collect()
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index 2fc3759968f..b911b108a73 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -1,5 +1,6 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
+#![feature(let_else)]
 #![feature(internal_output_capture)]
 #![feature(thread_spawn_unchecked)]
 #![feature(nll)]
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 33bf670f570..be31eb89f1b 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -3,7 +3,7 @@ use crate::proc_macro_decls;
 use crate::util;
 
 use rustc_ast::mut_visit::MutVisitor;
-use rustc_ast::{self as ast, visit, DUMMY_NODE_ID};
+use rustc_ast::{self as ast, visit};
 use rustc_borrowck as mir_borrowck;
 use rustc_codegen_ssa::back::link::emit_metadata;
 use rustc_codegen_ssa::traits::CodegenBackend;
@@ -11,16 +11,16 @@ use rustc_data_structures::parallel;
 use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
 use rustc_data_structures::temp_dir::MaybeTempDir;
 use rustc_errors::{Applicability, ErrorReported, PResult};
-use rustc_expand::base::ExtCtxt;
+use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand};
 use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
 use rustc_hir::Crate;
-use rustc_lint::LintStore;
+use rustc_lint::{EarlyCheckNode, LintStore};
 use rustc_metadata::creader::CStore;
 use rustc_metadata::{encode_metadata, EncodedMetadata};
 use rustc_middle::arena::Arena;
 use rustc_middle::dep_graph::DepGraph;
 use rustc_middle::ty::query::{ExternProviders, Providers};
-use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt};
+use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, ResolverOutputs, TyCtxt};
 use rustc_mir_build as mir_build;
 use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr};
 use rustc_passes::{self, hir_stats, layout_test};
@@ -34,7 +34,7 @@ use rustc_session::lint;
 use rustc_session::output::{filename_for_input, filename_for_metadata};
 use rustc_session::search_paths::PathKind;
 use rustc_session::{Limit, Session};
-use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{FileName, MultiSpan};
 use rustc_trait_selection::traits;
 use rustc_typeck as typeck;
@@ -233,26 +233,43 @@ pub fn register_plugins<'a>(
     Ok((krate, lint_store))
 }
 
-fn pre_expansion_lint(
+fn pre_expansion_lint<'a>(
     sess: &Session,
     lint_store: &LintStore,
-    krate: &ast::Crate,
-    crate_attrs: &[ast::Attribute],
-    crate_name: &str,
+    registered_tools: &RegisteredTools,
+    check_node: impl EarlyCheckNode<'a>,
+    node_name: &str,
 ) {
-    sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", crate_name).run(|| {
-        rustc_lint::check_ast_crate(
+    sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", node_name).run(|| {
+        rustc_lint::check_ast_node(
             sess,
-            lint_store,
-            krate,
-            crate_attrs,
             true,
+            lint_store,
+            registered_tools,
             None,
             rustc_lint::BuiltinCombinedPreExpansionLintPass::new(),
+            check_node,
         );
     });
 }
 
+// Cannot implement directly for `LintStore` due to trait coherence.
+struct LintStoreExpandImpl<'a>(&'a LintStore);
+
+impl LintStoreExpand for LintStoreExpandImpl<'_> {
+    fn pre_expansion_lint(
+        &self,
+        sess: &Session,
+        registered_tools: &RegisteredTools,
+        node_id: ast::NodeId,
+        attrs: &[ast::Attribute],
+        items: &[rustc_ast::ptr::P<ast::Item>],
+        name: &str,
+    ) {
+        pre_expansion_lint(sess, self.0, registered_tools, (node_id, attrs, items), name);
+    }
+}
+
 /// Runs the "early phases" of the compiler: initial `cfg` processing, loading compiler plugins,
 /// syntax expansion, secondary `cfg` expansion, synthesis of a test
 /// harness if one is to be provided, injection of a dependency on the
@@ -265,7 +282,7 @@ pub fn configure_and_expand(
     resolver: &mut Resolver<'_>,
 ) -> Result<ast::Crate> {
     tracing::trace!("configure_and_expand");
-    pre_expansion_lint(sess, lint_store, &krate, &krate.attrs, crate_name);
+    pre_expansion_lint(sess, lint_store, resolver.registered_tools(), &krate, crate_name);
     rustc_builtin_macros::register_builtin_macros(resolver);
 
     krate = sess.time("crate_injection", || {
@@ -321,13 +338,8 @@ pub fn configure_and_expand(
             ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string())
         };
 
-        let crate_attrs = krate.attrs.clone();
-        let extern_mod_loaded = |ident: Ident, attrs, items, span| {
-            let krate = ast::Crate { attrs, items, span, id: DUMMY_NODE_ID, is_placeholder: false };
-            pre_expansion_lint(sess, lint_store, &krate, &crate_attrs, ident.name.as_str());
-            (krate.attrs, krate.items)
-        };
-        let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&extern_mod_loaded));
+        let lint_store = LintStoreExpandImpl(lint_store);
+        let mut ecx = ExtCtxt::new(sess, cfg, resolver, Some(&lint_store));
 
         // Expand macros now!
         let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate));
@@ -499,14 +511,15 @@ pub fn lower_to_hir<'res, 'tcx>(
     );
 
     sess.time("early_lint_checks", || {
-        rustc_lint::check_ast_crate(
+        let lint_buffer = Some(std::mem::take(resolver.lint_buffer()));
+        rustc_lint::check_ast_node(
             sess,
-            lint_store,
-            &krate,
-            &krate.attrs,
             false,
-            Some(std::mem::take(resolver.lint_buffer())),
+            lint_store,
+            resolver.registered_tools(),
+            lint_buffer,
             rustc_lint::BuiltinCombinedEarlyLintPass::new(),
+            &*krate,
         )
     });
 
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 3921187baa5..6d9183eda9d 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -717,57 +717,57 @@ impl<'a, 'b> ReplaceBodyWithLoop<'a, 'b> {
     }
 
     fn should_ignore_fn(ret_ty: &ast::FnRetTy) -> bool {
-        if let ast::FnRetTy::Ty(ref ty) = ret_ty {
-            fn involves_impl_trait(ty: &ast::Ty) -> bool {
-                match ty.kind {
-                    ast::TyKind::ImplTrait(..) => true,
-                    ast::TyKind::Slice(ref subty)
-                    | ast::TyKind::Array(ref subty, _)
-                    | ast::TyKind::Ptr(ast::MutTy { ty: ref subty, .. })
-                    | ast::TyKind::Rptr(_, ast::MutTy { ty: ref subty, .. })
-                    | ast::TyKind::Paren(ref subty) => involves_impl_trait(subty),
-                    ast::TyKind::Tup(ref tys) => any_involves_impl_trait(tys.iter()),
-                    ast::TyKind::Path(_, ref path) => {
-                        path.segments.iter().any(|seg| match seg.args.as_deref() {
-                            None => false,
-                            Some(&ast::GenericArgs::AngleBracketed(ref data)) => {
-                                data.args.iter().any(|arg| match arg {
-                                    ast::AngleBracketedArg::Arg(arg) => match arg {
-                                        ast::GenericArg::Type(ty) => involves_impl_trait(ty),
-                                        ast::GenericArg::Lifetime(_)
-                                        | ast::GenericArg::Const(_) => false,
-                                    },
-                                    ast::AngleBracketedArg::Constraint(c) => match c.kind {
-                                        ast::AssocConstraintKind::Bound { .. } => true,
-                                        ast::AssocConstraintKind::Equality { ref term } => {
-                                            match term {
-                                                Term::Ty(ty) => involves_impl_trait(ty),
-                                                // FIXME(...): This should check if the constant
-                                                // involves a trait impl, but for now ignore.
-                                                Term::Const(_) => false,
-                                            }
+        let ast::FnRetTy::Ty(ref ty) = ret_ty else {
+            return false;
+        };
+        fn involves_impl_trait(ty: &ast::Ty) -> bool {
+            match ty.kind {
+                ast::TyKind::ImplTrait(..) => true,
+                ast::TyKind::Slice(ref subty)
+                | ast::TyKind::Array(ref subty, _)
+                | ast::TyKind::Ptr(ast::MutTy { ty: ref subty, .. })
+                | ast::TyKind::Rptr(_, ast::MutTy { ty: ref subty, .. })
+                | ast::TyKind::Paren(ref subty) => involves_impl_trait(subty),
+                ast::TyKind::Tup(ref tys) => any_involves_impl_trait(tys.iter()),
+                ast::TyKind::Path(_, ref path) => {
+                    path.segments.iter().any(|seg| match seg.args.as_deref() {
+                        None => false,
+                        Some(&ast::GenericArgs::AngleBracketed(ref data)) => {
+                            data.args.iter().any(|arg| match arg {
+                                ast::AngleBracketedArg::Arg(arg) => match arg {
+                                    ast::GenericArg::Type(ty) => involves_impl_trait(ty),
+                                    ast::GenericArg::Lifetime(_) | ast::GenericArg::Const(_) => {
+                                        false
+                                    }
+                                },
+                                ast::AngleBracketedArg::Constraint(c) => match c.kind {
+                                    ast::AssocConstraintKind::Bound { .. } => true,
+                                    ast::AssocConstraintKind::Equality { ref term } => {
+                                        match term {
+                                            Term::Ty(ty) => involves_impl_trait(ty),
+                                            // FIXME(...): This should check if the constant
+                                            // involves a trait impl, but for now ignore.
+                                            Term::Const(_) => false,
                                         }
-                                    },
-                                })
-                            }
-                            Some(&ast::GenericArgs::Parenthesized(ref data)) => {
-                                any_involves_impl_trait(data.inputs.iter())
-                                    || ReplaceBodyWithLoop::should_ignore_fn(&data.output)
-                            }
-                        })
-                    }
-                    _ => false,
+                                    }
+                                },
+                            })
+                        }
+                        Some(&ast::GenericArgs::Parenthesized(ref data)) => {
+                            any_involves_impl_trait(data.inputs.iter())
+                                || ReplaceBodyWithLoop::should_ignore_fn(&data.output)
+                        }
+                    })
                 }
+                _ => false,
             }
+        }
 
-            fn any_involves_impl_trait<'a, I: Iterator<Item = &'a P<ast::Ty>>>(mut it: I) -> bool {
-                it.any(|subty| involves_impl_trait(subty))
-            }
-
-            involves_impl_trait(ty)
-        } else {
-            false
+        fn any_involves_impl_trait<'a, I: Iterator<Item = &'a P<ast::Ty>>>(mut it: I) -> bool {
+            it.any(|subty| involves_impl_trait(subty))
         }
+
+        involves_impl_trait(ty)
     }
 
     fn is_sig_const(sig: &ast::FnSig) -> bool {
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 65385d4c7a1..9b24f43f7fd 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -912,7 +912,7 @@ declare_lint_pass!(
 
 impl EarlyLintPass for AnonymousParameters {
     fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
-        if cx.sess.edition() != Edition::Edition2015 {
+        if cx.sess().edition() != Edition::Edition2015 {
             // This is a hard error in future editions; avoid linting and erroring
             return;
         }
@@ -921,7 +921,7 @@ impl EarlyLintPass for AnonymousParameters {
                 if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
                     if ident.name == kw::Empty {
                         cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| {
-                            let ty_snip = cx.sess.source_map().span_to_snippet(arg.ty.span);
+                            let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);
 
                             let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
                                 (snip.as_str(), Applicability::MachineApplicable)
@@ -1775,7 +1775,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
                 };
                 if join.edition() >= Edition::Edition2021 {
                     let mut err =
-                        rustc_errors::struct_span_err!(cx.sess, pat.span, E0783, "{}", msg,);
+                        rustc_errors::struct_span_err!(cx.sess(), pat.span, E0783, "{}", msg,);
                     err.span_suggestion(
                         pat.span,
                         suggestion,
@@ -1799,7 +1799,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
                 let replace = "..=".to_owned();
                 if join.edition() >= Edition::Edition2021 {
                     let mut err =
-                        rustc_errors::struct_span_err!(cx.sess, pat.span, E0783, "{}", msg,);
+                        rustc_errors::struct_span_err!(cx.sess(), pat.span, E0783, "{}", msg,);
                     err.span_suggestion_short(
                         join,
                         suggestion,
@@ -1983,7 +1983,7 @@ impl KeywordIdents {
         UnderMacro(under_macro): UnderMacro,
         ident: Ident,
     ) {
-        let next_edition = match cx.sess.edition() {
+        let next_edition = match cx.sess().edition() {
             Edition::Edition2015 => {
                 match ident.name {
                     kw::Async | kw::Await | kw::Try => Edition::Edition2018,
@@ -2011,7 +2011,7 @@ impl KeywordIdents {
         };
 
         // Don't lint `r#foo`.
-        if cx.sess.parse_sess.raw_identifier_spans.borrow().contains(&ident.span) {
+        if cx.sess().parse_sess.raw_identifier_spans.borrow().contains(&ident.span) {
             return;
         }
 
@@ -2379,7 +2379,7 @@ declare_lint_pass!(
 
 impl EarlyLintPass for IncompleteFeatures {
     fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
-        let features = cx.sess.features_untracked();
+        let features = cx.sess().features_untracked();
         features
             .declared_lang_features
             .iter()
@@ -3158,7 +3158,10 @@ declare_lint! {
     /// of this, GNU assembler [local labels] *must* be used instead of labels
     /// with a name. Using named labels might cause assembler or linker errors.
     ///
+    /// See the explanation in [Rust By Example] for more details.
+    ///
     /// [local labels]: https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels
+    /// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels
     pub NAMED_ASM_LABELS,
     Deny,
     "named labels in inline assembly",
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 69c376c6169..cb08e952586 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -16,10 +16,9 @@
 
 use self::TargetLint::*;
 
-use crate::levels::{is_known_lint_tool, LintLevelsBuilder};
+use crate::levels::LintLevelsBuilder;
 use crate::passes::{EarlyLintPassObject, LateLintPassObject};
-use ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
-use rustc_ast as ast;
+use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync;
 use rustc_errors::{struct_span_err, Applicability, SuggestionStyle};
@@ -32,13 +31,14 @@ use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::middle::stability;
 use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
 use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt};
+use rustc_middle::ty::{self, print::Printer, subst::GenericArg, RegisteredTools, Ty, TyCtxt};
 use rustc_serialize::json::Json;
 use rustc_session::lint::{BuiltinLintDiagnostics, ExternDepSpec};
 use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
 use rustc_session::Session;
 use rustc_span::lev_distance::find_best_match_for_name;
-use rustc_span::{symbol::Symbol, BytePos, MultiSpan, Span, DUMMY_SP};
+use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
 use rustc_target::abi;
 use tracing::debug;
 
@@ -313,7 +313,7 @@ impl LintStore {
         sess: &Session,
         lint_name: &str,
         level: Level,
-        crate_attrs: &[ast::Attribute],
+        registered_tools: &RegisteredTools,
     ) {
         let (tool_name, lint_name_only) = parse_lint_and_tool_name(lint_name);
         if lint_name_only == crate::WARNINGS.name_lower() && level == Level::ForceWarn {
@@ -326,7 +326,7 @@ impl LintStore {
             )
             .emit();
         }
-        let db = match self.check_lint_name(sess, lint_name_only, tool_name, crate_attrs) {
+        let db = match self.check_lint_name(lint_name_only, tool_name, registered_tools) {
             CheckLintNameResult::Ok(_) => None,
             CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)),
             CheckLintNameResult::NoLint(suggestion) => {
@@ -397,13 +397,16 @@ impl LintStore {
     /// printing duplicate warnings.
     pub fn check_lint_name(
         &self,
-        sess: &Session,
         lint_name: &str,
         tool_name: Option<Symbol>,
-        crate_attrs: &[ast::Attribute],
+        registered_tools: &RegisteredTools,
     ) -> CheckLintNameResult<'_> {
         if let Some(tool_name) = tool_name {
-            if !is_known_lint_tool(tool_name, sess, crate_attrs) {
+            // FIXME: rustc and rustdoc are considered tools for lints, but not for attributes.
+            if tool_name != sym::rustc
+                && tool_name != sym::rustdoc
+                && !registered_tools.contains(&Ident::with_dummy_span(tool_name))
+            {
                 return CheckLintNameResult::NoTool;
             }
         }
@@ -521,7 +524,7 @@ impl LintStore {
     }
 }
 
-/// Context for lint checking after type checking.
+/// Context for lint checking outside of type inference.
 pub struct LateContext<'tcx> {
     /// Type context we're checking in.
     pub tcx: TyCtxt<'tcx>,
@@ -553,20 +556,9 @@ pub struct LateContext<'tcx> {
     pub only_module: bool,
 }
 
-/// Context for lint checking of the AST, after expansion, before lowering to
-/// HIR.
+/// Context for lint checking of the AST, after expansion, before lowering to HIR.
 pub struct EarlyContext<'a> {
-    /// Type context we're checking in.
-    pub sess: &'a Session,
-
-    /// The crate being checked.
-    pub krate: &'a ast::Crate,
-
     pub builder: LintLevelsBuilder<'a>,
-
-    /// The store of registered lints and the lint levels.
-    pub lint_store: &'a LintStore,
-
     pub buffered: LintBuffer,
 }
 
@@ -770,6 +762,7 @@ pub trait LintContext: Sized {
                 }
                 BuiltinLintDiagnostics::NamedAsmLabel(help) => {
                     db.help(&help);
+                    db.note("see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information");
                 }
             }
             // Rewrap `db`, and pass control to the user.
@@ -801,19 +794,20 @@ pub trait LintContext: Sized {
 }
 
 impl<'a> EarlyContext<'a> {
-    pub fn new(
+    pub(crate) fn new(
         sess: &'a Session,
+        warn_about_weird_lints: bool,
         lint_store: &'a LintStore,
-        krate: &'a ast::Crate,
-        crate_attrs: &'a [ast::Attribute],
+        registered_tools: &'a RegisteredTools,
         buffered: LintBuffer,
-        warn_about_weird_lints: bool,
     ) -> EarlyContext<'a> {
         EarlyContext {
-            sess,
-            krate,
-            lint_store,
-            builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store, crate_attrs),
+            builder: LintLevelsBuilder::new(
+                sess,
+                warn_about_weird_lints,
+                lint_store,
+                registered_tools,
+            ),
             buffered,
         }
     }
@@ -851,11 +845,11 @@ impl LintContext for EarlyContext<'_> {
 
     /// Gets the overall compiler `Session` object.
     fn sess(&self) -> &Session {
-        &self.sess
+        &self.builder.sess()
     }
 
     fn lints(&self) -> &LintStore {
-        &*self.lint_store
+        self.builder.lint_store()
     }
 
     fn lookup<S: Into<MultiSpan>>(
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 0bba66d3838..1b2c88867d4 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -16,9 +16,11 @@
 
 use crate::context::{EarlyContext, LintContext, LintStore};
 use crate::passes::{EarlyLintPass, EarlyLintPassObject};
-use rustc_ast as ast;
-use rustc_ast::visit as ast_visit;
+use rustc_ast::ptr::P;
+use rustc_ast::visit::{self as ast_visit, Visitor};
 use rustc_ast::AstLike;
+use rustc_ast::{self as ast, walk_list};
+use rustc_middle::ty::RegisteredTools;
 use rustc_session::lint::{BufferedEarlyLint, LintBuffer, LintPass};
 use rustc_session::Session;
 use rustc_span::symbol::Ident;
@@ -31,7 +33,7 @@ macro_rules! run_early_pass { ($cx:expr, $f:ident, $($args:expr),*) => ({
     $cx.pass.$f(&$cx.context, $($args),*);
 }) }
 
-struct EarlyContextAndPass<'a, T: EarlyLintPass> {
+pub struct EarlyContextAndPass<'a, T: EarlyLintPass> {
     context: EarlyContext<'a>,
     pass: T,
 }
@@ -57,7 +59,7 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> {
         F: FnOnce(&mut Self),
     {
         let is_crate_node = id == ast::CRATE_NODE_ID;
-        let push = self.context.builder.push(attrs, &self.context.lint_store, is_crate_node);
+        let push = self.context.builder.push(attrs, is_crate_node);
         self.check_id(id);
         self.enter_attrs(attrs);
         f(self);
@@ -325,48 +327,89 @@ macro_rules! early_lint_pass_impl {
 
 crate::early_lint_methods!(early_lint_pass_impl, []);
 
-fn early_lint_crate<T: EarlyLintPass>(
+/// Early lints work on different nodes - either on the crate root, or on freshly loaded modules.
+/// This trait generalizes over those nodes.
+pub trait EarlyCheckNode<'a>: Copy {
+    fn id(self) -> ast::NodeId;
+    fn attrs<'b>(self) -> &'b [ast::Attribute]
+    where
+        'a: 'b;
+    fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>)
+    where
+        'a: 'b;
+}
+
+impl<'a> EarlyCheckNode<'a> for &'a ast::Crate {
+    fn id(self) -> ast::NodeId {
+        ast::CRATE_NODE_ID
+    }
+    fn attrs<'b>(self) -> &'b [ast::Attribute]
+    where
+        'a: 'b,
+    {
+        &self.attrs
+    }
+    fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>)
+    where
+        'a: 'b,
+    {
+        run_early_pass!(cx, check_crate, self);
+        ast_visit::walk_crate(cx, self);
+        run_early_pass!(cx, check_crate_post, self);
+    }
+}
+
+impl<'a> EarlyCheckNode<'a> for (ast::NodeId, &'a [ast::Attribute], &'a [P<ast::Item>]) {
+    fn id(self) -> ast::NodeId {
+        self.0
+    }
+    fn attrs<'b>(self) -> &'b [ast::Attribute]
+    where
+        'a: 'b,
+    {
+        self.1
+    }
+    fn check<'b>(self, cx: &mut EarlyContextAndPass<'b, impl EarlyLintPass>)
+    where
+        'a: 'b,
+    {
+        walk_list!(cx, visit_attribute, self.1);
+        walk_list!(cx, visit_item, self.2);
+    }
+}
+
+fn early_lint_node<'a>(
     sess: &Session,
+    warn_about_weird_lints: bool,
     lint_store: &LintStore,
-    krate: &ast::Crate,
-    crate_attrs: &[ast::Attribute],
-    pass: T,
+    registered_tools: &RegisteredTools,
     buffered: LintBuffer,
-    warn_about_weird_lints: bool,
+    pass: impl EarlyLintPass,
+    check_node: impl EarlyCheckNode<'a>,
 ) -> LintBuffer {
     let mut cx = EarlyContextAndPass {
         context: EarlyContext::new(
             sess,
+            warn_about_weird_lints,
             lint_store,
-            krate,
-            crate_attrs,
+            registered_tools,
             buffered,
-            warn_about_weird_lints,
         ),
         pass,
     };
 
-    // Visit the whole crate.
-    cx.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |cx| {
-        // since the root module isn't visited as an item (because it isn't an
-        // item), warn for it here.
-        run_early_pass!(cx, check_crate, krate);
-
-        ast_visit::walk_crate(cx, krate);
-
-        run_early_pass!(cx, check_crate_post, krate);
-    });
+    cx.with_lint_attrs(check_node.id(), check_node.attrs(), |cx| check_node.check(cx));
     cx.context.buffered
 }
 
-pub fn check_ast_crate<T: EarlyLintPass>(
+pub fn check_ast_node<'a>(
     sess: &Session,
-    lint_store: &LintStore,
-    krate: &ast::Crate,
-    crate_attrs: &[ast::Attribute],
     pre_expansion: bool,
+    lint_store: &LintStore,
+    registered_tools: &RegisteredTools,
     lint_buffer: Option<LintBuffer>,
-    builtin_lints: T,
+    builtin_lints: impl EarlyLintPass,
+    check_node: impl EarlyCheckNode<'a>,
 ) {
     let passes =
         if pre_expansion { &lint_store.pre_expansion_passes } else { &lint_store.early_passes };
@@ -374,39 +417,39 @@ pub fn check_ast_crate<T: EarlyLintPass>(
     let mut buffered = lint_buffer.unwrap_or_default();
 
     if !sess.opts.debugging_opts.no_interleave_lints {
-        buffered = early_lint_crate(
+        buffered = early_lint_node(
             sess,
+            pre_expansion,
             lint_store,
-            krate,
-            crate_attrs,
-            builtin_lints,
+            registered_tools,
             buffered,
-            pre_expansion,
+            builtin_lints,
+            check_node,
         );
 
         if !passes.is_empty() {
-            buffered = early_lint_crate(
+            buffered = early_lint_node(
                 sess,
+                false,
                 lint_store,
-                krate,
-                crate_attrs,
-                EarlyLintPassObjects { lints: &mut passes[..] },
+                registered_tools,
                 buffered,
-                false,
+                EarlyLintPassObjects { lints: &mut passes[..] },
+                check_node,
             );
         }
     } else {
         for (i, pass) in passes.iter_mut().enumerate() {
             buffered =
                 sess.prof.extra_verbose_generic_activity("run_lint", pass.name()).run(|| {
-                    early_lint_crate(
+                    early_lint_node(
                         sess,
+                        pre_expansion && i == 0,
                         lint_store,
-                        krate,
-                        crate_attrs,
-                        EarlyLintPassObjects { lints: slice::from_mut(pass) },
+                        registered_tools,
                         buffered,
-                        pre_expansion && i == 0,
+                        EarlyLintPassObjects { lints: slice::from_mut(pass) },
+                        check_node,
                     )
                 });
         }
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 7353cd6b876..d8e1162890c 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
                                     lint.build(&format!("usage of qualified `ty::{}`", t))
                                         .span_suggestion(
                                             path.span,
-                                            "try using it unqualified",
+                                            "try importing it and using it unqualified",
                                             t,
                                             // The import probably needs to be changed
                                             Applicability::MaybeIncorrect,
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 6e95708b17f..8afbd462c14 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -5,7 +5,7 @@ use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
 use rustc_hir as hir;
-use rustc_hir::{intravisit, HirId, CRATE_HIR_ID};
+use rustc_hir::{intravisit, HirId};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::LevelAndSource;
 use rustc_middle::lint::LintDiagnosticBuilder;
@@ -14,7 +14,7 @@ use rustc_middle::lint::{
     COMMAND_LINE,
 };
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{RegisteredTools, TyCtxt};
 use rustc_session::lint::{
     builtin::{self, FORBIDDEN_LINT_GROUPS},
     Level, Lint, LintId,
@@ -27,14 +27,14 @@ use tracing::debug;
 
 fn lint_levels(tcx: TyCtxt<'_>, (): ()) -> LintLevelMap {
     let store = unerased_lint_store(tcx);
-    let crate_attrs = tcx.hir().attrs(CRATE_HIR_ID);
-    let levels = LintLevelsBuilder::new(tcx.sess, false, &store, crate_attrs);
-    let mut builder = LintLevelMapBuilder { levels, tcx, store };
+    let levels =
+        LintLevelsBuilder::new(tcx.sess, false, &store, &tcx.resolutions(()).registered_tools);
+    let mut builder = LintLevelMapBuilder { levels, tcx };
     let krate = tcx.hir().krate();
 
     builder.levels.id_to_set.reserve(krate.owners.len() + 1);
 
-    let push = builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), &store, true);
+    let push = builder.levels.push(tcx.hir().attrs(hir::CRATE_HIR_ID), true);
     builder.levels.register_id(hir::CRATE_HIR_ID);
     tcx.hir().walk_toplevel_module(&mut builder);
     builder.levels.pop(push);
@@ -49,7 +49,7 @@ pub struct LintLevelsBuilder<'s> {
     cur: LintStackIndex,
     warn_about_weird_lints: bool,
     store: &'s LintStore,
-    crate_attrs: &'s [ast::Attribute],
+    registered_tools: &'s RegisteredTools,
 }
 
 pub struct BuilderPush {
@@ -62,7 +62,7 @@ impl<'s> LintLevelsBuilder<'s> {
         sess: &'s Session,
         warn_about_weird_lints: bool,
         store: &'s LintStore,
-        crate_attrs: &'s [ast::Attribute],
+        registered_tools: &'s RegisteredTools,
     ) -> Self {
         let mut builder = LintLevelsBuilder {
             sess,
@@ -71,19 +71,27 @@ impl<'s> LintLevelsBuilder<'s> {
             id_to_set: Default::default(),
             warn_about_weird_lints,
             store,
-            crate_attrs,
+            registered_tools,
         };
         builder.process_command_line(sess, store);
         assert_eq!(builder.sets.list.len(), 1);
         builder
     }
 
+    pub(crate) fn sess(&self) -> &Session {
+        self.sess
+    }
+
+    pub(crate) fn lint_store(&self) -> &LintStore {
+        self.store
+    }
+
     fn process_command_line(&mut self, sess: &Session, store: &LintStore) {
         let mut specs = FxHashMap::default();
         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, self.crate_attrs);
+            store.check_lint_name_cmdline(sess, &lint_name, level, self.registered_tools);
             let orig_level = level;
             let lint_flag_val = Symbol::intern(lint_name);
 
@@ -217,12 +225,7 @@ impl<'s> LintLevelsBuilder<'s> {
     ///   `#[allow]`
     ///
     /// Don't forget to call `pop`!
-    pub(crate) fn push(
-        &mut self,
-        attrs: &[ast::Attribute],
-        store: &LintStore,
-        is_crate_node: bool,
-    ) -> BuilderPush {
+    pub(crate) fn push(&mut self, attrs: &[ast::Attribute], is_crate_node: bool) -> BuilderPush {
         let mut specs = FxHashMap::default();
         let sess = self.sess;
         let bad_attr = |span| struct_span_err!(sess, span, E0452, "malformed lint attribute input");
@@ -310,7 +313,8 @@ impl<'s> LintLevelsBuilder<'s> {
                 };
                 let tool_name = tool_ident.map(|ident| ident.name);
                 let name = pprust::path_to_string(&meta_item.path);
-                let lint_result = store.check_lint_name(sess, &name, tool_name, self.crate_attrs);
+                let lint_result =
+                    self.store.check_lint_name(&name, tool_name, self.registered_tools);
                 match &lint_result {
                     CheckLintNameResult::Ok(ids) => {
                         let src = LintLevelSource::Node(
@@ -459,7 +463,7 @@ impl<'s> LintLevelsBuilder<'s> {
                     // Ignore any errors or warnings that happen because the new name is inaccurate
                     // NOTE: `new_name` already includes the tool name, so we don't have to add it again.
                     if let CheckLintNameResult::Ok(ids) =
-                        store.check_lint_name(sess, &new_name, None, self.crate_attrs)
+                        self.store.check_lint_name(&new_name, None, self.registered_tools)
                     {
                         let src = LintLevelSource::Node(Symbol::intern(&new_name), sp, reason);
                         for &id in ids {
@@ -562,34 +566,19 @@ impl<'s> LintLevelsBuilder<'s> {
     }
 }
 
-pub fn is_known_lint_tool(m_item: Symbol, sess: &Session, attrs: &[ast::Attribute]) -> bool {
-    if [sym::clippy, sym::rustc, sym::rustdoc].contains(&m_item) {
-        return true;
-    }
-    // Look for registered tools
-    // NOTE: does no error handling; error handling is done by rustc_resolve.
-    sess.filter_by_name(attrs, sym::register_tool)
-        .filter_map(|attr| attr.meta_item_list())
-        .flatten()
-        .filter_map(|nested_meta| nested_meta.ident())
-        .map(|ident| ident.name)
-        .any(|name| name == m_item)
-}
-
-struct LintLevelMapBuilder<'a, 'tcx> {
+struct LintLevelMapBuilder<'tcx> {
     levels: LintLevelsBuilder<'tcx>,
     tcx: TyCtxt<'tcx>,
-    store: &'a LintStore,
 }
 
-impl LintLevelMapBuilder<'_, '_> {
+impl LintLevelMapBuilder<'_> {
     fn with_lint_attrs<F>(&mut self, id: hir::HirId, f: F)
     where
         F: FnOnce(&mut Self),
     {
         let is_crate_hir = id == hir::CRATE_HIR_ID;
         let attrs = self.tcx.hir().attrs(id);
-        let push = self.levels.push(attrs, self.store, is_crate_hir);
+        let push = self.levels.push(attrs, is_crate_hir);
         if push.changed {
             self.levels.register_id(id);
         }
@@ -598,7 +587,7 @@ impl LintLevelMapBuilder<'_, '_> {
     }
 }
 
-impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'_, 'tcx> {
+impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> {
     type NestedFilter = nested_filter::All;
 
     fn nested_visit_map(&mut self) -> Self::Map {
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 4aa8505c940..a87f2b2768d 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -96,7 +96,7 @@ use unused::*;
 pub use builtin::SoftLints;
 pub use context::{CheckLintNameResult, FindLintError, LintStore};
 pub use context::{EarlyContext, LateContext, LintContext};
-pub use early::check_ast_crate;
+pub use early::{check_ast_node, EarlyCheckNode};
 pub use late::check_crate;
 pub use passes::{EarlyLintPass, LateLintPass};
 pub use rustc_session::lint::Level::{self, *};
@@ -481,6 +481,11 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) {
          <https://github.com/rust-lang/rust/issues/59014> for more information",
     );
     store.register_removed("plugin_as_library", "plugins have been deprecated and retired");
+    store.register_removed(
+        "unsupported_naked_functions",
+        "converted into hard error, see RFC 2972 \
+         <https://github.com/rust-lang/rfcs/blob/master/text/2972-constrained-naked.md> for more information",
+    );
 }
 
 fn register_internals(store: &mut LintStore) {
diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs
index a570206f1ee..2dd6dbd67a8 100644
--- a/compiler/rustc_lint/src/non_ascii_idents.rs
+++ b/compiler/rustc_lint/src/non_ascii_idents.rs
@@ -166,7 +166,7 @@ impl EarlyLintPass for NonAsciiIdents {
         }
 
         let mut has_non_ascii_idents = false;
-        let symbols = cx.sess.parse_sess.symbol_gallery.symbols.lock();
+        let symbols = cx.sess().parse_sess.symbol_gallery.symbols.lock();
 
         // Sort by `Span` so that error messages make sense with respect to the
         // order of identifier locations in the code.
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index a919b3c82aa..6bf25732f60 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -336,5 +336,5 @@ fn is_arg_inside_call(arg: Span, call: Span) -> bool {
     // panic call in the source file, to avoid invalid suggestions when macros are involved.
     // We specifically check for the spans to not be identical, as that happens sometimes when
     // proc_macros lie about spans and apply the same span to all the tokens they produce.
-    call.contains(arg) && !call.source_equal(&arg)
+    call.contains(arg) && !call.source_equal(arg)
 }
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index be7756b0f28..f73388c675e 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -164,7 +164,7 @@ impl EarlyLintPass for NonCamelCaseTypes {
         let has_repr_c = it
             .attrs
             .iter()
-            .any(|attr| attr::find_repr_attrs(&cx.sess, attr).contains(&attr::ReprC));
+            .any(|attr| attr::find_repr_attrs(cx.sess(), attr).contains(&attr::ReprC));
 
         if has_repr_c {
             return;
diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs
index 26d0560bf89..2caf929788f 100644
--- a/compiler/rustc_lint/src/pass_by_value.rs
+++ b/compiler/rustc_lint/src/pass_by_value.rs
@@ -76,10 +76,10 @@ fn gen_args(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> String {
             .map(|arg| match arg {
                 GenericArg::Lifetime(lt) => lt.name.ident().to_string(),
                 GenericArg::Type(ty) => {
-                    cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_default()
+                    cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_else(|_| "_".into())
                 }
                 GenericArg::Const(c) => {
-                    cx.tcx.sess.source_map().span_to_snippet(c.span).unwrap_or_default()
+                    cx.tcx.sess.source_map().span_to_snippet(c.span).unwrap_or_else(|_| "_".into())
                 }
                 GenericArg::Infer(_) => String::from("_"),
             })
diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs
index dafff640b36..4c7f3482776 100644
--- a/compiler/rustc_lint/src/traits.rs
+++ b/compiler/rustc_lint/src/traits.rs
@@ -86,7 +86,6 @@ declare_lint_pass!(
 
 impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
-        use rustc_middle::ty;
         use rustc_middle::ty::PredicateKind::*;
 
         let predicates = cx.tcx.explicit_predicates_of(item.def_id);
@@ -94,7 +93,7 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints {
             let Trait(trait_predicate) = predicate.kind().skip_binder() else {
                 continue
             };
-            if trait_predicate.constness == ty::BoundConstness::ConstIfConst {
+            if trait_predicate.is_const_if_const() {
                 // `~const Drop` definitely have meanings so avoid linting here.
                 continue;
             }
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index c2f6118227a..4af68233f0d 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -2456,6 +2456,10 @@ declare_lint! {
     /// register size, to alert you of possibly using the incorrect width. To
     /// fix this, add the suggested modifier to the template, or cast the
     /// value to the correct size.
+    ///
+    /// See [register template modifiers] in the reference for more details.
+    ///
+    /// [register template modifiers]: https://doc.rust-lang.org/nightly/reference/inline-assembly.html#template-modifiers
     pub ASM_SUB_REGISTER,
     Warn,
     "using only a subset of a register for inline asm inputs",
@@ -2760,52 +2764,6 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `unsupported_naked_functions` lint detects naked function
-    /// definitions that are unsupported but were previously accepted.
-    ///
-    /// ### Example
-    ///
-    /// ```rust
-    /// #![feature(naked_functions)]
-    ///
-    /// #[naked]
-    /// pub extern "C" fn f() -> u32 {
-    ///     42
-    /// }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// The naked functions must be defined using a single inline assembly
-    /// block.
-    ///
-    /// The execution must never fall through past the end of the assembly
-    /// code so the block must use `noreturn` option. The asm block can also
-    /// use `att_syntax` option, but other options are not allowed.
-    ///
-    /// The asm block must not contain any operands other than `const` and
-    /// `sym`. Additionally, naked function should specify a non-Rust ABI.
-    ///
-    /// Naked functions cannot be inlined. All forms of the `inline` attribute
-    /// are prohibited.
-    ///
-    /// While other definitions of naked functions were previously accepted,
-    /// they are unsupported and might not work reliably. This is a
-    /// [future-incompatible] lint that will transition into hard error in
-    /// the future.
-    ///
-    /// [future-incompatible]: ../index.md#future-incompatible-lints
-    pub UNSUPPORTED_NAKED_FUNCTIONS,
-    Warn,
-    "unsupported naked function definitions",
-    @future_incompatible = FutureIncompatibleInfo {
-        reference: "issue #32408 <https://github.com/rust-lang/rust/issues/32408>",
-    };
-}
-
-declare_lint! {
     /// The `ineffective_unstable_trait_impl` lint detects `#[unstable]` attributes which are not used.
     ///
     /// ### Example
@@ -3070,7 +3028,6 @@ declare_lint_pass! {
         UNINHABITED_STATIC,
         FUNCTION_ITEM_REFERENCES,
         USELESS_DEPRECATED,
-        UNSUPPORTED_NAKED_FUNCTIONS,
         MISSING_ABI,
         INVALID_DOC_ATTRIBUTES,
         SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 97f6df51f88..3b5d636124d 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -282,7 +282,7 @@ pub enum ExternDepSpec {
 
 // This could be a closure, but then implementing derive trait
 // becomes hacky (and it gets allocated).
-#[derive(PartialEq, Debug)]
+#[derive(Debug)]
 pub enum BuiltinLintDiagnostics {
     Normal,
     AbsPathWithModule(Span),
@@ -309,7 +309,6 @@ pub enum BuiltinLintDiagnostics {
 
 /// Lints that are buffered up early on in the `Session` before the
 /// `LintLevels` is calculated.
-#[derive(PartialEq)]
 pub struct BufferedEarlyLint {
     /// The span of code that we are linting on.
     pub span: MultiSpan,
@@ -336,9 +335,7 @@ pub struct LintBuffer {
 impl LintBuffer {
     pub fn add_early_lint(&mut self, early_lint: BufferedEarlyLint) {
         let arr = self.map.entry(early_lint.node_id).or_default();
-        if !arr.contains(&early_lint) {
-            arr.push(early_lint);
-        }
+        arr.push(early_lint);
     }
 
     pub fn add_lint(
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index c21e4acbefe..dcd6327c92f 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -722,9 +722,12 @@ extern "C" bool LLVMRustIsRustLLVM() {
 #endif
 }
 
-extern "C" void LLVMRustAddModuleFlag(LLVMModuleRef M, const char *Name,
-                                      uint32_t Value) {
-  unwrap(M)->addModuleFlag(Module::Warning, Name, Value);
+extern "C" void LLVMRustAddModuleFlag(
+    LLVMModuleRef M,
+    Module::ModFlagBehavior MergeBehavior,
+    const char *Name,
+    uint32_t Value) {
+  unwrap(M)->addModuleFlag(MergeBehavior, Name, Value);
 }
 
 extern "C" LLVMValueRef LLVMRustMetadataAsValue(LLVMContextRef C, LLVMMetadataRef MD) {
diff --git a/compiler/rustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs
index 3351564299c..6c5461505fa 100644
--- a/compiler/rustc_macros/src/serialize.rs
+++ b/compiler/rustc_macros/src/serialize.rs
@@ -47,7 +47,7 @@ fn decodable_body(
             quote! {
                 ::rustc_serialize::Decoder::read_struct(
                     __decoder,
-                    |__decoder| { ::std::result::Result::Ok(#construct) },
+                    |__decoder| { #construct },
                 )
             }
         }
@@ -57,7 +57,7 @@ fn decodable_body(
                 .enumerate()
                 .map(|(idx, vi)| {
                     let construct = vi.construct(|field, index| decode_field(field, index, false));
-                    quote! { #idx => { ::std::result::Result::Ok(#construct) } }
+                    quote! { #idx => { #construct } }
                 })
                 .collect();
             let names: TokenStream = variants
@@ -82,8 +82,7 @@ fn decodable_body(
                             |__decoder, __variant_idx| {
                                 match __variant_idx {
                                     #match_inner
-                                    _ => return ::std::result::Result::Err(
-                                        ::rustc_serialize::Decoder::error(__decoder, #message)),
+                                    _ => panic!(#message),
                                 }
                             })
                     }
@@ -95,9 +94,7 @@ fn decodable_body(
     s.bound_impl(
         quote!(::rustc_serialize::Decodable<#decoder_ty>),
         quote! {
-            fn decode(
-                __decoder: &mut #decoder_ty,
-            ) -> ::std::result::Result<Self, <#decoder_ty as ::rustc_serialize::Decoder>::Error> {
+            fn decode(__decoder: &mut #decoder_ty) -> Self {
                 #decode_body
             }
         },
@@ -127,12 +124,7 @@ fn decode_field(field: &syn::Field, index: usize, is_struct: bool) -> proc_macro
                 #__decoder, #opt_field_name #decode_inner_method)
     };
 
-    quote! {
-        match #decode_call  {
-            ::std::result::Result::Ok(__res) => __res,
-            ::std::result::Result::Err(__err) => return ::std::result::Result::Err(__err),
-        }
-    }
+    quote! { #decode_call }
 }
 
 pub fn type_encodable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 220bc9c5f75..fb1c71fb8cd 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -263,7 +263,7 @@ impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Lazy<T> {
     fn decode<M: Metadata<'a, 'tcx>>(self, metadata: M) -> T {
         let mut dcx = metadata.decoder(self.position.get());
         dcx.lazy_state = LazyState::NodeStart(self.position);
-        T::decode(&mut dcx).unwrap()
+        T::decode(&mut dcx)
     }
 }
 
@@ -274,7 +274,7 @@ impl<'a: 'x, 'tcx: 'x, 'x, T: Decodable<DecodeContext<'a, 'tcx>>> Lazy<[T]> {
     ) -> impl ExactSizeIterator<Item = T> + Captures<'a> + Captures<'tcx> + 'x {
         let mut dcx = metadata.decoder(self.position.get());
         dcx.lazy_state = LazyState::NodeStart(self.position);
-        (0..self.meta).map(move |_| T::decode(&mut dcx).unwrap())
+        (0..self.meta).map(move |_| T::decode(&mut dcx))
     }
 }
 
@@ -300,11 +300,8 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
         if cnum == LOCAL_CRATE { self.cdata().cnum } else { self.cdata().cnum_map[cnum] }
     }
 
-    fn read_lazy_with_meta<T: ?Sized + LazyMeta>(
-        &mut self,
-        meta: T::Meta,
-    ) -> Result<Lazy<T>, <Self as Decoder>::Error> {
-        let distance = self.read_usize()?;
+    fn read_lazy_with_meta<T: ?Sized + LazyMeta>(&mut self, meta: T::Meta) -> Lazy<T> {
+        let distance = self.read_usize();
         let position = match self.lazy_state {
             LazyState::NoNode => bug!("read_lazy_with_meta: outside of a metadata node"),
             LazyState::NodeStart(start) => {
@@ -315,7 +312,7 @@ impl<'a, 'tcx> DecodeContext<'a, 'tcx> {
             LazyState::Previous(last_pos) => last_pos.get() + distance,
         };
         self.lazy_state = LazyState::Previous(NonZeroUsize::new(position).unwrap());
-        Ok(Lazy::from_position_and_meta(NonZeroUsize::new(position).unwrap(), meta))
+        Lazy::from_position_and_meta(NonZeroUsize::new(position).unwrap(), meta)
     }
 
     #[inline]
@@ -342,25 +339,21 @@ impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> {
         self.opaque.position()
     }
 
-    fn cached_ty_for_shorthand<F>(
-        &mut self,
-        shorthand: usize,
-        or_insert_with: F,
-    ) -> Result<Ty<'tcx>, Self::Error>
+    fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx>
     where
-        F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>,
+        F: FnOnce(&mut Self) -> Ty<'tcx>,
     {
         let tcx = self.tcx();
 
         let key = ty::CReaderCacheKey { cnum: Some(self.cdata().cnum), pos: shorthand };
 
         if let Some(&ty) = tcx.ty_rcache.borrow().get(&key) {
-            return Ok(ty);
+            return ty;
         }
 
-        let ty = or_insert_with(self)?;
+        let ty = or_insert_with(self);
         tcx.ty_rcache.borrow_mut().insert(key, ty);
-        Ok(ty)
+        ty
     }
 
     fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
@@ -376,7 +369,7 @@ impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> {
         r
     }
 
-    fn decode_alloc_id(&mut self) -> Result<rustc_middle::mir::interpret::AllocId, Self::Error> {
+    fn decode_alloc_id(&mut self) -> rustc_middle::mir::interpret::AllocId {
         if let Some(alloc_decoding_session) = self.alloc_decoding_session {
             alloc_decoding_session.decode_alloc_id(self)
         } else {
@@ -386,48 +379,48 @@ impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> {
 }
 
 impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for CrateNum {
-    fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<CrateNum, String> {
-        let cnum = CrateNum::from_u32(d.read_u32()?);
-        Ok(d.map_encoded_cnum_to_current(cnum))
+    fn decode(d: &mut DecodeContext<'a, 'tcx>) -> CrateNum {
+        let cnum = CrateNum::from_u32(d.read_u32());
+        d.map_encoded_cnum_to_current(cnum)
     }
 }
 
 impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefIndex {
-    fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<DefIndex, String> {
-        Ok(DefIndex::from_u32(d.read_u32()?))
+    fn decode(d: &mut DecodeContext<'a, 'tcx>) -> DefIndex {
+        DefIndex::from_u32(d.read_u32())
     }
 }
 
 impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnIndex {
-    fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<ExpnIndex, String> {
-        Ok(ExpnIndex::from_u32(d.read_u32()?))
+    fn decode(d: &mut DecodeContext<'a, 'tcx>) -> ExpnIndex {
+        ExpnIndex::from_u32(d.read_u32())
     }
 }
 
 impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for SyntaxContext {
-    fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<SyntaxContext, String> {
+    fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> SyntaxContext {
         let cdata = decoder.cdata();
         let sess = decoder.sess.unwrap();
         let cname = cdata.root.name;
         rustc_span::hygiene::decode_syntax_context(decoder, &cdata.hygiene_context, |_, id| {
             debug!("SpecializedDecoder<SyntaxContext>: decoding {}", id);
-            Ok(cdata
+            cdata
                 .root
                 .syntax_contexts
                 .get(cdata, id)
                 .unwrap_or_else(|| panic!("Missing SyntaxContext {:?} for crate {:?}", id, cname))
-                .decode((cdata, sess)))
+                .decode((cdata, sess))
         })
     }
 }
 
 impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnId {
-    fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<ExpnId, String> {
+    fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> ExpnId {
         let local_cdata = decoder.cdata();
         let sess = decoder.sess.unwrap();
 
-        let cnum = CrateNum::decode(decoder)?;
-        let index = u32::decode(decoder)?;
+        let cnum = CrateNum::decode(decoder);
+        let index = u32::decode(decoder);
 
         let expn_id = rustc_span::hygiene::decode_expn_id(cnum, index, |expn_id| {
             let ExpnId { krate: cnum, local_id: index } = expn_id;
@@ -453,23 +446,23 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for ExpnId {
                 .decode((crate_data, sess));
             (expn_data, expn_hash)
         });
-        Ok(expn_id)
+        expn_id
     }
 }
 
 impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
-    fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<Span, String> {
-        let ctxt = SyntaxContext::decode(decoder)?;
-        let tag = u8::decode(decoder)?;
+    fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Span {
+        let ctxt = SyntaxContext::decode(decoder);
+        let tag = u8::decode(decoder);
 
         if tag == TAG_PARTIAL_SPAN {
-            return Ok(DUMMY_SP.with_ctxt(ctxt));
+            return DUMMY_SP.with_ctxt(ctxt);
         }
 
         debug_assert!(tag == TAG_VALID_SPAN_LOCAL || tag == TAG_VALID_SPAN_FOREIGN);
 
-        let lo = BytePos::decode(decoder)?;
-        let len = BytePos::decode(decoder)?;
+        let lo = BytePos::decode(decoder);
+        let len = BytePos::decode(decoder);
         let hi = lo + len;
 
         let Some(sess) = decoder.sess else {
@@ -512,7 +505,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
             if decoder.cdata().root.is_proc_macro_crate() {
                 // Decode `CrateNum` as u32 - using `CrateNum::decode` will ICE
                 // since we don't have `cnum_map` populated.
-                let cnum = u32::decode(decoder)?;
+                let cnum = u32::decode(decoder);
                 panic!(
                     "Decoding of crate {:?} tried to access proc-macro dep {:?}",
                     decoder.cdata().root.name,
@@ -520,7 +513,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
                 );
             }
             // tag is TAG_VALID_SPAN_FOREIGN, checked by `debug_assert` above
-            let cnum = CrateNum::decode(decoder)?;
+            let cnum = CrateNum::decode(decoder);
             debug!(
                 "SpecializedDecoder<Span>::specialized_decode: loading source files from cnum {:?}",
                 cnum
@@ -582,18 +575,18 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Span {
             (hi + source_file.translated_source_file.start_pos) - source_file.original_start_pos;
 
         // Do not try to decode parent for foreign spans.
-        Ok(Span::new(lo, hi, ctxt, None))
+        Span::new(lo, hi, ctxt, None)
     }
 }
 
 impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] {
-    fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
+    fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self {
         ty::codec::RefDecodable::decode(d)
     }
 }
 
 impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
-    fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
+    fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Self {
         ty::codec::RefDecodable::decode(d)
     }
 }
@@ -601,7 +594,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx
 impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Decodable<DecodeContext<'a, 'tcx>>
     for Lazy<T>
 {
-    fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
+    fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
         decoder.read_lazy_with_meta(())
     }
 }
@@ -609,9 +602,9 @@ impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Decodable<DecodeContext<'a
 impl<'a, 'tcx, T: Decodable<DecodeContext<'a, 'tcx>>> Decodable<DecodeContext<'a, 'tcx>>
     for Lazy<[T]>
 {
-    fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
-        let len = decoder.read_usize()?;
-        if len == 0 { Ok(Lazy::empty()) } else { decoder.read_lazy_with_meta(len) }
+    fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
+        let len = decoder.read_usize();
+        if len == 0 { Lazy::empty() } else { decoder.read_lazy_with_meta(len) }
     }
 }
 
@@ -620,8 +613,8 @@ impl<'a, 'tcx, I: Idx, T: Decodable<DecodeContext<'a, 'tcx>>> Decodable<DecodeCo
 where
     Option<T>: FixedSizeEncoding,
 {
-    fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Result<Self, String> {
-        let len = decoder.read_usize()?;
+    fn decode(decoder: &mut DecodeContext<'a, 'tcx>) -> Self {
+        let len = decoder.read_usize();
         decoder.read_lazy_with_meta(len)
     }
 }
@@ -1286,7 +1279,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         };
 
         ty::AssocItem {
-            ident,
+            name: ident.name,
             kind,
             vis: self.get_visibility(id),
             defaultness: container.defaultness(),
@@ -1380,11 +1373,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
         self.root.traits.decode(self).map(move |index| self.local_def_id(index))
     }
 
-    fn get_trait_impls(self) -> impl Iterator<Item = (DefId, Option<SimplifiedType>)> + 'a {
-        self.cdata.trait_impls.values().flat_map(move |impls| {
-            impls
-                .decode(self)
-                .map(move |(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty))
+    fn get_trait_impls(self) -> impl Iterator<Item = (DefId, DefId, Option<SimplifiedType>)> + 'a {
+        self.cdata.trait_impls.iter().flat_map(move |((trait_cnum_raw, trait_index), impls)| {
+            let trait_def_id = DefId {
+                krate: self.cnum_map[CrateNum::from_u32(*trait_cnum_raw)],
+                index: *trait_index,
+            };
+            impls.decode(self).map(move |(impl_index, simplified_self_ty)| {
+                (trait_def_id, self.local_def_id(impl_index), simplified_self_ty)
+            })
         })
     }
 
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 9b59c14c2fe..2f8e35648ec 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -493,7 +493,7 @@ impl CStore {
     pub fn trait_impls_in_crate_untracked(
         &self,
         cnum: CrateNum,
-    ) -> impl Iterator<Item = (DefId, Option<SimplifiedType>)> + '_ {
+    ) -> impl Iterator<Item = (DefId, DefId, Option<SimplifiedType>)> + '_ {
         self.get_crate_data(cnum).get_trait_impls()
     }
 }
diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
index 054431169a2..d66f2b031a8 100644
--- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
+++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
@@ -39,11 +39,11 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for DefPathHashMapRef<'tcx> {
 }
 
 impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefPathHashMapRef<'static> {
-    fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result<DefPathHashMapRef<'static>, String> {
+    fn decode(d: &mut DecodeContext<'a, 'tcx>) -> DefPathHashMapRef<'static> {
         // Import TyDecoder so we can access the DecodeContext::position() method
         use crate::rustc_middle::ty::codec::TyDecoder;
 
-        let len = d.read_usize()?;
+        let len = d.read_usize();
         let pos = d.position();
         let o = OwningRef::new(d.blob().clone()).map(|x| &x[pos..pos + len]);
 
@@ -52,7 +52,9 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefPathHashMapRef<'static>
         // the method. We use read_raw_bytes() for that.
         let _ = d.read_raw_bytes(len);
 
-        let inner = odht::HashTable::from_raw_bytes(o).map_err(|e| format!("{}", e))?;
-        Ok(DefPathHashMapRef::OwnedFromMetadata(inner))
+        let inner = odht::HashTable::from_raw_bytes(o).unwrap_or_else(|e| {
+            panic!("decode error: {}", e);
+        });
+        DefPathHashMapRef::OwnedFromMetadata(inner)
     }
 }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index ebb78adf343..3fae652ee2e 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1291,7 +1291,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 record!(self.tables.kind[def_id] <- EntryKind::AssocType(container));
             }
         }
-        self.encode_ident_span(def_id, impl_item.ident);
+        self.encode_ident_span(def_id, impl_item.ident(self.tcx));
         self.encode_item_type(def_id);
         if let Some(trait_item_def_id) = impl_item.trait_item_def_id {
             record!(self.tables.trait_item_def_id[def_id] <- trait_item_def_id);
@@ -1314,7 +1314,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             return;
         }
 
-        let mut keys_and_jobs = self
+        let keys_and_jobs = self
             .tcx
             .mir_keys(())
             .iter()
@@ -1327,8 +1327,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 }
             })
             .collect::<Vec<_>>();
-        // Sort everything to ensure a stable order for diagnotics.
-        keys_and_jobs.sort_by_key(|&(def_id, _, _)| def_id.index());
         for (def_id, encode_const, encode_opt) in keys_and_jobs.into_iter() {
             debug_assert!(encode_const || encode_opt);
 
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index 82ea7ff6aab..1885df6ac5d 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -204,8 +204,11 @@ impl<'hir> Map<'hir> {
         if hir_id.local_id == ItemLocalId::new(0) {
             Some(hir_id.owner)
         } else {
-            // FIXME(#85914) is this access safe for incr. comp.?
-            self.tcx.untracked_resolutions.definitions.opt_hir_id_to_local_def_id(hir_id)
+            self.tcx
+                .hir_owner_nodes(hir_id.owner)?
+                .local_id_to_def_id
+                .get(&hir_id.local_id)
+                .copied()
         }
     }
 
diff --git a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs
index 5f028975bd0..e2f3d6e078f 100644
--- a/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs
+++ b/compiler/rustc_middle/src/mir/graph_cyclic_cache.rs
@@ -45,8 +45,9 @@ impl<S: serialize::Encoder> serialize::Encodable<S> for GraphIsCyclicCache {
 
 impl<D: serialize::Decoder> serialize::Decodable<D> for GraphIsCyclicCache {
     #[inline]
-    fn decode(d: &mut D) -> Result<Self, D::Error> {
-        serialize::Decodable::decode(d).map(|_v: ()| Self::new())
+    fn decode(d: &mut D) -> Self {
+        let () = serialize::Decodable::decode(d);
+        Self::new()
     }
 }
 
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index b762a10da84..66f2c6e78a2 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -273,20 +273,20 @@ pub struct AllocDecodingSession<'s> {
 
 impl<'s> AllocDecodingSession<'s> {
     /// Decodes an `AllocId` in a thread-safe way.
-    pub fn decode_alloc_id<'tcx, D>(&self, decoder: &mut D) -> Result<AllocId, D::Error>
+    pub fn decode_alloc_id<'tcx, D>(&self, decoder: &mut D) -> AllocId
     where
         D: TyDecoder<'tcx>,
     {
         // Read the index of the allocation.
-        let idx = usize::try_from(decoder.read_u32()?).unwrap();
+        let idx = usize::try_from(decoder.read_u32()).unwrap();
         let pos = usize::try_from(self.state.data_offsets[idx]).unwrap();
 
         // Decode the `AllocDiscriminant` now so that we know if we have to reserve an
         // `AllocId`.
         let (alloc_kind, pos) = decoder.with_position(pos, |decoder| {
-            let alloc_kind = AllocDiscriminant::decode(decoder)?;
-            Ok((alloc_kind, decoder.position()))
-        })?;
+            let alloc_kind = AllocDiscriminant::decode(decoder);
+            (alloc_kind, decoder.position())
+        });
 
         // Check the decoding state to see if it's already decoded or if we should
         // decode it here.
@@ -295,7 +295,7 @@ impl<'s> AllocDecodingSession<'s> {
 
             match *entry {
                 State::Done(alloc_id) => {
-                    return Ok(alloc_id);
+                    return alloc_id;
                 }
                 ref mut entry @ State::Empty => {
                     // We are allowed to decode.
@@ -329,7 +329,7 @@ impl<'s> AllocDecodingSession<'s> {
                 State::InProgress(ref mut sessions, alloc_id) => {
                     if sessions.contains(&self.session_id) {
                         // Don't recurse.
-                        return Ok(alloc_id);
+                        return alloc_id;
                     } else {
                         // Start decoding concurrently.
                         sessions.insert(self.session_id);
@@ -343,37 +343,37 @@ impl<'s> AllocDecodingSession<'s> {
         let alloc_id = decoder.with_position(pos, |decoder| {
             match alloc_kind {
                 AllocDiscriminant::Alloc => {
-                    let alloc = <&'tcx Allocation as Decodable<_>>::decode(decoder)?;
+                    let alloc = <&'tcx Allocation as Decodable<_>>::decode(decoder);
                     // We already have a reserved `AllocId`.
                     let alloc_id = alloc_id.unwrap();
                     trace!("decoded alloc {:?}: {:#?}", alloc_id, alloc);
                     decoder.tcx().set_alloc_id_same_memory(alloc_id, alloc);
-                    Ok(alloc_id)
+                    alloc_id
                 }
                 AllocDiscriminant::Fn => {
                     assert!(alloc_id.is_none());
                     trace!("creating fn alloc ID");
-                    let instance = ty::Instance::decode(decoder)?;
+                    let instance = ty::Instance::decode(decoder);
                     trace!("decoded fn alloc instance: {:?}", instance);
                     let alloc_id = decoder.tcx().create_fn_alloc(instance);
-                    Ok(alloc_id)
+                    alloc_id
                 }
                 AllocDiscriminant::Static => {
                     assert!(alloc_id.is_none());
                     trace!("creating extern static alloc ID");
-                    let did = <DefId as Decodable<D>>::decode(decoder)?;
+                    let did = <DefId as Decodable<D>>::decode(decoder);
                     trace!("decoded static def-ID: {:?}", did);
                     let alloc_id = decoder.tcx().create_static_alloc(did);
-                    Ok(alloc_id)
+                    alloc_id
                 }
             }
-        })?;
+        });
 
         self.state.decoding_state[idx].with_lock(|entry| {
             *entry = State::Done(alloc_id);
         });
 
-        Ok(alloc_id)
+        alloc_id
     }
 }
 
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 48f39b26152..b1ab0f5b533 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -619,20 +619,20 @@ impl<'tcx, E: TyEncoder<'tcx>, T: Encodable<E>> Encodable<E> for ClearCrossCrate
 }
 impl<'tcx, D: TyDecoder<'tcx>, T: Decodable<D>> Decodable<D> for ClearCrossCrate<T> {
     #[inline]
-    fn decode(d: &mut D) -> Result<ClearCrossCrate<T>, D::Error> {
+    fn decode(d: &mut D) -> ClearCrossCrate<T> {
         if D::CLEAR_CROSS_CRATE {
-            return Ok(ClearCrossCrate::Clear);
+            return ClearCrossCrate::Clear;
         }
 
-        let discr = u8::decode(d)?;
+        let discr = u8::decode(d);
 
         match discr {
-            TAG_CLEAR_CROSS_CRATE_CLEAR => Ok(ClearCrossCrate::Clear),
+            TAG_CLEAR_CROSS_CRATE_CLEAR => ClearCrossCrate::Clear,
             TAG_CLEAR_CROSS_CRATE_SET => {
-                let val = T::decode(d)?;
-                Ok(ClearCrossCrate::Set(val))
+                let val = T::decode(d);
+                ClearCrossCrate::Set(val)
             }
-            tag => Err(d.error(&format!("Invalid tag for ClearCrossCrate: {:?}", tag))),
+            tag => panic!("Invalid tag for ClearCrossCrate: {:?}", tag),
         }
     }
 }
@@ -894,7 +894,7 @@ pub struct LocalDecl<'tcx> {
     /// across a suspension point against the type components of the generator
     /// which type checking knows are live across a suspension point. We need to
     /// flag drop flags to avoid triggering this check as they are introduced
-    /// after typeck.
+    /// outside of type inference.
     ///
     /// This should be sound because the drop flags are fully algebraic, and
     /// therefore don't affect the auto-trait or outlives properties of the
diff --git a/compiler/rustc_middle/src/mir/predecessors.rs b/compiler/rustc_middle/src/mir/predecessors.rs
index fd6bb76dc43..2562baac911 100644
--- a/compiler/rustc_middle/src/mir/predecessors.rs
+++ b/compiler/rustc_middle/src/mir/predecessors.rs
@@ -57,14 +57,15 @@ impl PredecessorCache {
 impl<S: serialize::Encoder> serialize::Encodable<S> for PredecessorCache {
     #[inline]
     fn encode(&self, s: &mut S) -> Result<(), S::Error> {
-        serialize::Encodable::encode(&(), s)
+        s.emit_unit()
     }
 }
 
 impl<D: serialize::Decoder> serialize::Decodable<D> for PredecessorCache {
     #[inline]
-    fn decode(d: &mut D) -> Result<Self, D::Error> {
-        serialize::Decodable::decode(d).map(|_v: ()| Self::new())
+    fn decode(d: &mut D) -> Self {
+        let () = d.read_unit();
+        Self::new()
     }
 }
 
diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs
index 06cbc3383ef..965d30a7b92 100644
--- a/compiler/rustc_middle/src/mir/spanview.rs
+++ b/compiler/rustc_middle/src/mir/spanview.rs
@@ -230,7 +230,7 @@ where
 }
 
 /// Format a string showing the start line and column, and end line and column within a file.
-pub fn source_range_no_file<'tcx>(tcx: TyCtxt<'tcx>, span: &Span) -> String {
+pub fn source_range_no_file<'tcx>(tcx: TyCtxt<'tcx>, span: Span) -> String {
     let source_map = tcx.sess.source_map();
     let start = source_map.lookup_char_pos(span.lo());
     let end = source_map.lookup_char_pos(span.hi());
@@ -629,7 +629,7 @@ fn tooltip<'tcx>(
     let mut text = Vec::new();
     text.push(format!("{}: {}:", spanview_id, &source_map.span_to_embeddable_string(span)));
     for statement in statements {
-        let source_range = source_range_no_file(tcx, &statement.source_info.span);
+        let source_range = source_range_no_file(tcx, statement.source_info.span);
         text.push(format!(
             "\n{}{}: {}: {:?}",
             TOOLTIP_INDENT,
@@ -639,7 +639,7 @@ fn tooltip<'tcx>(
         ));
     }
     if let Some(term) = terminator {
-        let source_range = source_range_no_file(tcx, &term.source_info.span);
+        let source_range = source_range_no_file(tcx, term.source_info.span);
         text.push(format!(
             "\n{}{}: {}: {:?}",
             TOOLTIP_INDENT,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 5dc7b219642..54391bd649e 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -252,7 +252,7 @@ rustc_queries! {
     /// 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.
-    query mir_keys(_: ()) -> FxHashSet<LocalDefId> {
+    query mir_keys(_: ()) -> rustc_data_structures::fx::FxIndexSet<LocalDefId> {
         storage(ArenaCacheSelector<'tcx>)
         desc { "getting a list of all mir_keys" }
     }
@@ -784,24 +784,11 @@ rustc_queries! {
         desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) }
         cache_on_disk_if { true }
         load_cached(tcx, id) {
-            #[cfg(bootstrap)]
-            {
-                match match tcx.on_disk_cache().as_ref() {
-                    Some(c) => c.try_load_query_result(*tcx, id),
-                    None => None,
-                } {
-                    Some(x) => Some(&*tcx.arena.alloc(x)),
-                    None => None,
-                }
-            }
-            #[cfg(not(bootstrap))]
-            {
-                let typeck_results: Option<ty::TypeckResults<'tcx>> = tcx
-                    .on_disk_cache().as_ref()
-                    .and_then(|c| c.try_load_query_result(*tcx, id));
+            let typeck_results: Option<ty::TypeckResults<'tcx>> = tcx
+                .on_disk_cache().as_ref()
+                .and_then(|c| c.try_load_query_result(*tcx, id));
 
-                typeck_results.map(|x| &*tcx.arena.alloc(x))
-            }
+            typeck_results.map(|x| &*tcx.arena.alloc(x))
         }
     }
 
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index de5beffb5c5..1123cab8076 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -402,7 +402,7 @@ impl ObligationCauseCode<'_> {
 
 // `ObligationCauseCode` is used a lot. Make sure it doesn't unintentionally get bigger.
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(ObligationCauseCode<'_>, 40);
+static_assert_size!(ObligationCauseCode<'_>, 48);
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
 pub enum StatementAsExpression {
@@ -440,11 +440,11 @@ pub struct IfExpressionCause {
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)]
 pub struct DerivedObligationCause<'tcx> {
-    /// The trait reference of the parent obligation that led to the
+    /// The trait predicate of the parent obligation that led to the
     /// current obligation. Note that only trait obligations lead to
-    /// derived obligations, so we just store the trait reference here
+    /// derived obligations, so we just store the trait predicate here
     /// directly.
-    pub parent_trait_ref: ty::PolyTraitRef<'tcx>,
+    pub parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
 
     /// The parent trait had this cause.
     pub parent_code: Lrc<ObligationCauseCode<'tcx>>,
@@ -566,7 +566,7 @@ pub enum ImplSource<'tcx, N> {
     TraitAlias(ImplSourceTraitAliasData<'tcx, N>),
 
     /// ImplSource for a `const Drop` implementation.
-    ConstDrop(ImplSourceConstDropData),
+    ConstDrop(ImplSourceConstDropData<N>),
 }
 
 impl<'tcx, N> ImplSource<'tcx, N> {
@@ -581,10 +581,10 @@ impl<'tcx, N> ImplSource<'tcx, N> {
             ImplSource::Object(d) => d.nested,
             ImplSource::FnPointer(d) => d.nested,
             ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
-            | ImplSource::Pointee(ImplSourcePointeeData)
-            | ImplSource::ConstDrop(ImplSourceConstDropData) => Vec::new(),
+            | ImplSource::Pointee(ImplSourcePointeeData) => Vec::new(),
             ImplSource::TraitAlias(d) => d.nested,
             ImplSource::TraitUpcasting(d) => d.nested,
+            ImplSource::ConstDrop(i) => i.nested,
         }
     }
 
@@ -599,10 +599,10 @@ impl<'tcx, N> ImplSource<'tcx, N> {
             ImplSource::Object(d) => &d.nested,
             ImplSource::FnPointer(d) => &d.nested,
             ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)
-            | ImplSource::Pointee(ImplSourcePointeeData)
-            | ImplSource::ConstDrop(ImplSourceConstDropData) => &[],
+            | ImplSource::Pointee(ImplSourcePointeeData) => &[],
             ImplSource::TraitAlias(d) => &d.nested,
             ImplSource::TraitUpcasting(d) => &d.nested,
+            ImplSource::ConstDrop(i) => &i.nested,
         }
     }
 
@@ -661,9 +661,9 @@ impl<'tcx, N> ImplSource<'tcx, N> {
                     nested: d.nested.into_iter().map(f).collect(),
                 })
             }
-            ImplSource::ConstDrop(ImplSourceConstDropData) => {
-                ImplSource::ConstDrop(ImplSourceConstDropData)
-            }
+            ImplSource::ConstDrop(i) => ImplSource::ConstDrop(ImplSourceConstDropData {
+                nested: i.nested.into_iter().map(f).collect(),
+            }),
         }
     }
 }
@@ -755,8 +755,10 @@ pub struct ImplSourceDiscriminantKindData;
 #[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
 pub struct ImplSourcePointeeData;
 
-#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
-pub struct ImplSourceConstDropData;
+#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
+pub struct ImplSourceConstDropData<N> {
+    pub nested: Vec<N>,
+}
 
 #[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)]
 pub struct ImplSourceTraitAliasData<'tcx, N> {
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index 71ee00c602a..e18f04d92ee 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -146,8 +146,8 @@ pub enum SelectionCandidate<'tcx> {
 
     BuiltinUnsizeCandidate,
 
-    /// Implementation of `const Drop`.
-    ConstDropCandidate,
+    /// Implementation of `const Drop`, optionally from a custom `impl const Drop`.
+    ConstDropCandidate(Option<DefId>),
 }
 
 /// The result of trait evaluation. The order is important
diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs
index aa2f37bd81a..6ce9f5eea34 100644
--- a/compiler/rustc_middle/src/traits/structural_impls.rs
+++ b/compiler/rustc_middle/src/traits/structural_impls.rs
@@ -120,6 +120,12 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx,
     }
 }
 
+impl<N: fmt::Debug> fmt::Debug for traits::ImplSourceConstDropData<N> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "ImplSourceConstDropData(nested={:?})", self.nested)
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // Lift implementations
 
@@ -127,5 +133,4 @@ TrivialTypeFoldableAndLiftImpls! {
     super::IfExpressionCause,
     super::ImplSourceDiscriminantKindData,
     super::ImplSourcePointeeData,
-    super::ImplSourceConstDropData,
 }
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
index 2776370ba6f..c23d4eae1a4 100644
--- a/compiler/rustc_middle/src/ty/assoc.rs
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -44,8 +44,7 @@ impl AssocItemContainer {
 #[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash)]
 pub struct AssocItem {
     pub def_id: DefId,
-    #[stable_hasher(project(name))]
-    pub ident: Ident,
+    pub name: Symbol,
     pub kind: AssocKind,
     pub vis: Visibility,
     pub defaultness: hir::Defaultness,
@@ -61,6 +60,10 @@ pub struct AssocItem {
 }
 
 impl AssocItem {
+    pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
+        Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
+    }
+
     pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
         match self.kind {
             ty::AssocKind::Fn => {
@@ -70,9 +73,9 @@ impl AssocItem {
                 // regions just fine, showing `fn(&MyType)`.
                 tcx.fn_sig(self.def_id).skip_binder().to_string()
             }
-            ty::AssocKind::Type => format!("type {};", self.ident),
+            ty::AssocKind::Type => format!("type {};", self.name),
             ty::AssocKind::Const => {
-                format!("const {}: {:?};", self.ident, tcx.type_of(self.def_id))
+                format!("const {}: {:?};", self.name, tcx.type_of(self.def_id))
             }
         }
     }
@@ -115,7 +118,7 @@ pub struct AssocItems<'tcx> {
 impl<'tcx> AssocItems<'tcx> {
     /// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order.
     pub fn new(items_in_def_order: impl IntoIterator<Item = &'tcx ty::AssocItem>) -> Self {
-        let items = items_in_def_order.into_iter().map(|item| (item.ident.name, item)).collect();
+        let items = items_in_def_order.into_iter().map(|item| (item.name, item)).collect();
         AssocItems { items }
     }
 
@@ -149,7 +152,7 @@ impl<'tcx> AssocItems<'tcx> {
     ) -> Option<&ty::AssocItem> {
         self.filter_by_name_unhygienic(ident.name)
             .filter(|item| item.kind == kind)
-            .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
+            .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
     }
 
     /// Returns the associated item with the given name and any of `AssocKind`, if one exists.
@@ -162,7 +165,7 @@ impl<'tcx> AssocItems<'tcx> {
     ) -> Option<&ty::AssocItem> {
         self.filter_by_name_unhygienic(ident.name)
             .filter(|item| kinds.contains(&item.kind))
-            .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
+            .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
     }
 
     /// Returns the associated item with the given name in the given `Namespace`, if one exists.
@@ -175,6 +178,6 @@ impl<'tcx> AssocItems<'tcx> {
     ) -> Option<&ty::AssocItem> {
         self.filter_by_name_unhygienic(ident.name)
             .filter(|item| item.kind.namespace() == ns)
-            .find(|item| tcx.hygienic_eq(ident, item.ident, parent_def_id))
+            .find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
     }
 }
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index db37d98614e..65b91eedf8a 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -14,7 +14,7 @@ use crate::mir::{
 };
 use crate::thir;
 use crate::ty::subst::SubstsRef;
-use crate::ty::{self, List, Ty, TyCtxt};
+use crate::ty::{self, Ty, TyCtxt};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use rustc_span::Span;
@@ -71,7 +71,7 @@ pub trait TyEncoder<'tcx>: Encoder {
 /// `Decodable` can still be implemented in cases where `Decodable` is required
 /// by a trait bound.
 pub trait RefDecodable<'tcx, D: TyDecoder<'tcx>> {
-    fn decode(d: &mut D) -> Result<&'tcx Self, D::Error>;
+    fn decode(d: &mut D) -> &'tcx Self;
 }
 
 /// Encode the given value or a previously cached shorthand.
@@ -172,13 +172,9 @@ pub trait TyDecoder<'tcx>: Decoder {
 
     fn position(&self) -> usize;
 
-    fn cached_ty_for_shorthand<F>(
-        &mut self,
-        shorthand: usize,
-        or_insert_with: F,
-    ) -> Result<Ty<'tcx>, Self::Error>
+    fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx>
     where
-        F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>;
+        F: FnOnce(&mut Self) -> Ty<'tcx>;
 
     fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
     where
@@ -188,35 +184,35 @@ pub trait TyDecoder<'tcx>: Decoder {
         (self.peek_byte() & (SHORTHAND_OFFSET as u8)) != 0
     }
 
-    fn decode_alloc_id(&mut self) -> Result<AllocId, Self::Error>;
+    fn decode_alloc_id(&mut self) -> AllocId;
 }
 
 #[inline]
 fn decode_arena_allocable<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable<D>>(
     decoder: &mut D,
-) -> Result<&'tcx T, D::Error>
+) -> &'tcx T
 where
     D: TyDecoder<'tcx>,
 {
-    Ok(decoder.tcx().arena.alloc(Decodable::decode(decoder)?))
+    decoder.tcx().arena.alloc(Decodable::decode(decoder))
 }
 
 #[inline]
 fn decode_arena_allocable_slice<'tcx, D, T: ArenaAllocatable<'tcx> + Decodable<D>>(
     decoder: &mut D,
-) -> Result<&'tcx [T], D::Error>
+) -> &'tcx [T]
 where
     D: TyDecoder<'tcx>,
 {
-    Ok(decoder.tcx().arena.alloc_from_iter(<Vec<T> as Decodable<D>>::decode(decoder)?))
+    decoder.tcx().arena.alloc_from_iter(<Vec<T> as Decodable<D>>::decode(decoder))
 }
 
 impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for Ty<'tcx> {
     #[allow(rustc::usage_of_ty_tykind)]
-    fn decode(decoder: &mut D) -> Result<Ty<'tcx>, D::Error> {
+    fn decode(decoder: &mut D) -> Ty<'tcx> {
         // Handle shorthands first, if we have a usize > 0x80.
         if decoder.positioned_at_shorthand() {
-            let pos = decoder.read_usize()?;
+            let pos = decoder.read_usize();
             assert!(pos >= SHORTHAND_OFFSET);
             let shorthand = pos - SHORTHAND_OFFSET;
 
@@ -225,87 +221,89 @@ impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for Ty<'tcx> {
             })
         } else {
             let tcx = decoder.tcx();
-            Ok(tcx.mk_ty(ty::TyKind::decode(decoder)?))
+            tcx.mk_ty(ty::TyKind::decode(decoder))
         }
     }
 }
 
 impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Binder<'tcx, ty::PredicateKind<'tcx>> {
-    fn decode(decoder: &mut D) -> Result<ty::Binder<'tcx, ty::PredicateKind<'tcx>>, D::Error> {
-        let bound_vars = Decodable::decode(decoder)?;
+    fn decode(decoder: &mut D) -> ty::Binder<'tcx, ty::PredicateKind<'tcx>> {
+        let bound_vars = Decodable::decode(decoder);
         // Handle shorthands first, if we have a usize > 0x80.
-        Ok(ty::Binder::bind_with_vars(
+        ty::Binder::bind_with_vars(
             if decoder.positioned_at_shorthand() {
-                let pos = decoder.read_usize()?;
+                let pos = decoder.read_usize();
                 assert!(pos >= SHORTHAND_OFFSET);
                 let shorthand = pos - SHORTHAND_OFFSET;
 
-                decoder.with_position(shorthand, ty::PredicateKind::decode)?
+                decoder.with_position(shorthand, ty::PredicateKind::decode)
             } else {
-                ty::PredicateKind::decode(decoder)?
+                ty::PredicateKind::decode(decoder)
             },
             bound_vars,
-        ))
+        )
     }
 }
 
 impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Predicate<'tcx> {
-    fn decode(decoder: &mut D) -> Result<ty::Predicate<'tcx>, D::Error> {
-        let predicate_kind = Decodable::decode(decoder)?;
-        let predicate = decoder.tcx().mk_predicate(predicate_kind);
-        Ok(predicate)
+    fn decode(decoder: &mut D) -> ty::Predicate<'tcx> {
+        let predicate_kind = Decodable::decode(decoder);
+        decoder.tcx().mk_predicate(predicate_kind)
     }
 }
 
 impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for SubstsRef<'tcx> {
-    fn decode(decoder: &mut D) -> Result<Self, D::Error> {
-        let len = decoder.read_usize()?;
+    fn decode(decoder: &mut D) -> Self {
+        let len = decoder.read_usize();
         let tcx = decoder.tcx();
-        tcx.mk_substs((0..len).map(|_| Decodable::decode(decoder)))
+        tcx.mk_substs(
+            (0..len).map::<ty::subst::GenericArg<'tcx>, _>(|_| Decodable::decode(decoder)),
+        )
     }
 }
 
 impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for mir::Place<'tcx> {
-    fn decode(decoder: &mut D) -> Result<Self, D::Error> {
-        let local: mir::Local = Decodable::decode(decoder)?;
-        let len = decoder.read_usize()?;
-        let projection: &'tcx List<mir::PlaceElem<'tcx>> =
-            decoder.tcx().mk_place_elems((0..len).map(|_| Decodable::decode(decoder)))?;
-        Ok(mir::Place { local, projection })
+    fn decode(decoder: &mut D) -> Self {
+        let local: mir::Local = Decodable::decode(decoder);
+        let len = decoder.read_usize();
+        let projection = decoder.tcx().mk_place_elems(
+            (0..len).map::<mir::PlaceElem<'tcx>, _>(|_| Decodable::decode(decoder)),
+        );
+        mir::Place { local, projection }
     }
 }
 
 impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Region<'tcx> {
-    fn decode(decoder: &mut D) -> Result<Self, D::Error> {
-        Ok(decoder.tcx().mk_region(Decodable::decode(decoder)?))
+    fn decode(decoder: &mut D) -> Self {
+        decoder.tcx().mk_region(Decodable::decode(decoder))
     }
 }
 
 impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for CanonicalVarInfos<'tcx> {
-    fn decode(decoder: &mut D) -> Result<Self, D::Error> {
-        let len = decoder.read_usize()?;
-        let interned: Result<Vec<CanonicalVarInfo<'tcx>>, _> =
+    fn decode(decoder: &mut D) -> Self {
+        let len = decoder.read_usize();
+        let interned: Vec<CanonicalVarInfo<'tcx>> =
             (0..len).map(|_| Decodable::decode(decoder)).collect();
-        Ok(decoder.tcx().intern_canonical_var_infos(interned?.as_slice()))
+        decoder.tcx().intern_canonical_var_infos(interned.as_slice())
     }
 }
 
 impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for AllocId {
-    fn decode(decoder: &mut D) -> Result<Self, D::Error> {
+    fn decode(decoder: &mut D) -> Self {
         decoder.decode_alloc_id()
     }
 }
 
 impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::SymbolName<'tcx> {
-    fn decode(decoder: &mut D) -> Result<Self, D::Error> {
-        Ok(ty::SymbolName::new(decoder.tcx(), &decoder.read_str()?))
+    fn decode(decoder: &mut D) -> Self {
+        ty::SymbolName::new(decoder.tcx(), &decoder.read_str())
     }
 }
 
 macro_rules! impl_decodable_via_ref {
     ($($t:ty),+) => {
         $(impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for $t {
-            fn decode(decoder: &mut D) -> Result<Self, D::Error> {
+            fn decode(decoder: &mut D) -> Self {
                 RefDecodable::decode(decoder)
             }
         })*
@@ -313,77 +311,73 @@ macro_rules! impl_decodable_via_ref {
 }
 
 impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<Ty<'tcx>> {
-    fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
-        let len = decoder.read_usize()?;
-        decoder.tcx().mk_type_list((0..len).map(|_| Decodable::decode(decoder)))
+    fn decode(decoder: &mut D) -> &'tcx Self {
+        let len = decoder.read_usize();
+        decoder.tcx().mk_type_list((0..len).map::<Ty<'tcx>, _>(|_| Decodable::decode(decoder)))
     }
 }
 
 impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D>
     for ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>
 {
-    fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
-        let len = decoder.read_usize()?;
-        decoder.tcx().mk_poly_existential_predicates((0..len).map(|_| Decodable::decode(decoder)))
+    fn decode(decoder: &mut D) -> &'tcx Self {
+        let len = decoder.read_usize();
+        decoder.tcx().mk_poly_existential_predicates(
+            (0..len).map::<ty::Binder<'tcx, _>, _>(|_| Decodable::decode(decoder)),
+        )
     }
 }
 
 impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::Const<'tcx> {
-    fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
-        Ok(decoder.tcx().mk_const(Decodable::decode(decoder)?))
+    fn decode(decoder: &mut D) -> &'tcx Self {
+        decoder.tcx().mk_const(Decodable::decode(decoder))
     }
 }
 
 impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [ty::ValTree<'tcx>] {
-    fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
-        Ok(decoder.tcx().arena.alloc_from_iter(
-            (0..decoder.read_usize()?)
-                .map(|_| Decodable::decode(decoder))
-                .collect::<Result<Vec<_>, _>>()?,
-        ))
+    fn decode(decoder: &mut D) -> &'tcx Self {
+        decoder.tcx().arena.alloc_from_iter(
+            (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
+        )
     }
 }
 
 impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for Allocation {
-    fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
-        Ok(decoder.tcx().intern_const_alloc(Decodable::decode(decoder)?))
+    fn decode(decoder: &mut D) -> &'tcx Self {
+        decoder.tcx().intern_const_alloc(Decodable::decode(decoder))
     }
 }
 
 impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Predicate<'tcx>, Span)] {
-    fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
-        Ok(decoder.tcx().arena.alloc_from_iter(
-            (0..decoder.read_usize()?)
-                .map(|_| Decodable::decode(decoder))
-                .collect::<Result<Vec<_>, _>>()?,
-        ))
+    fn decode(decoder: &mut D) -> &'tcx Self {
+        decoder.tcx().arena.alloc_from_iter(
+            (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
+        )
     }
 }
 
 impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::Node<'tcx>] {
-    fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
-        Ok(decoder.tcx().arena.alloc_from_iter(
-            (0..decoder.read_usize()?)
-                .map(|_| Decodable::decode(decoder))
-                .collect::<Result<Vec<_>, _>>()?,
-        ))
+    fn decode(decoder: &mut D) -> &'tcx Self {
+        decoder.tcx().arena.alloc_from_iter(
+            (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
+        )
     }
 }
 
 impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [thir::abstract_const::NodeId] {
-    fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
-        Ok(decoder.tcx().arena.alloc_from_iter(
-            (0..decoder.read_usize()?)
-                .map(|_| Decodable::decode(decoder))
-                .collect::<Result<Vec<_>, _>>()?,
-        ))
+    fn decode(decoder: &mut D) -> &'tcx Self {
+        decoder.tcx().arena.alloc_from_iter(
+            (0..decoder.read_usize()).map(|_| Decodable::decode(decoder)).collect::<Vec<_>>(),
+        )
     }
 }
 
 impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for ty::List<ty::BoundVariableKind> {
-    fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
-        let len = decoder.read_usize()?;
-        decoder.tcx().mk_bound_variable_kinds((0..len).map(|_| Decodable::decode(decoder)))
+    fn decode(decoder: &mut D) -> &'tcx Self {
+        let len = decoder.read_usize();
+        decoder.tcx().mk_bound_variable_kinds(
+            (0..len).map::<ty::BoundVariableKind, _>(|_| Decodable::decode(decoder)),
+        )
     }
 }
 
@@ -405,7 +399,7 @@ macro_rules! __impl_decoder_methods {
     ($($name:ident -> $ty:ty;)*) => {
         $(
             #[inline]
-            fn $name(&mut self) -> Result<$ty, Self::Error> {
+            fn $name(&mut self) -> $ty {
                 self.opaque.$name()
             }
         )*
@@ -418,14 +412,14 @@ macro_rules! impl_arena_allocatable_decoder {
      [$name:ident: $ty:ty]) => {
         impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for $ty {
             #[inline]
-            fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
+            fn decode(decoder: &mut D) -> &'tcx Self {
                 decode_arena_allocable(decoder)
             }
         }
 
         impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [$ty] {
             #[inline]
-            fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> {
+            fn decode(decoder: &mut D) -> &'tcx Self {
                 decode_arena_allocable_slice(decoder)
             }
         }
@@ -456,10 +450,8 @@ macro_rules! implement_ty_decoder {
             use super::$DecoderName;
 
             impl<$($typaram ),*> Decoder for $DecoderName<$($typaram),*> {
-                type Error = String;
-
                 $crate::__impl_decoder_methods! {
-                    read_nil -> ();
+                    read_unit -> ();
 
                     read_u128 -> u128;
                     read_u64 -> u64;
@@ -483,13 +475,9 @@ macro_rules! implement_ty_decoder {
                 }
 
                 #[inline]
-                fn read_raw_bytes_into(&mut self, bytes: &mut [u8]) -> Result<(), Self::Error> {
+                fn read_raw_bytes_into(&mut self, bytes: &mut [u8]) {
                     self.opaque.read_raw_bytes_into(bytes)
                 }
-
-                fn error(&mut self, err: &str) -> Self::Error {
-                    self.opaque.error(err)
-                }
             }
         }
     }
@@ -505,9 +493,9 @@ macro_rules! impl_binder_encode_decode {
                 }
             }
             impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ty::Binder<'tcx, $t> {
-                fn decode(decoder: &mut D) -> Result<Self, D::Error> {
-                    let bound_vars = Decodable::decode(decoder)?;
-                    Ok(ty::Binder::bind_with_vars(Decodable::decode(decoder)?, bound_vars))
+                fn decode(decoder: &mut D) -> Self {
+                    let bound_vars = Decodable::decode(decoder);
+                    ty::Binder::bind_with_vars(Decodable::decode(decoder), bound_vars)
                 }
             }
         )*
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index 1f4ebd03676..de45e1bb851 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -147,8 +147,8 @@ impl<S: Encoder> Encodable<S> for ScalarInt {
 }
 
 impl<D: Decoder> Decodable<D> for ScalarInt {
-    fn decode(d: &mut D) -> Result<ScalarInt, D::Error> {
-        Ok(ScalarInt { data: d.read_u128()?, size: d.read_u8()? })
+    fn decode(d: &mut D) -> ScalarInt {
+        ScalarInt { data: d.read_u128(), size: d.read_u8() }
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index a7d7ee5efc8..d063494f2bc 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -113,6 +113,12 @@ pub struct CtxtInterners<'tcx> {
     bound_variable_kinds: InternedSet<'tcx, List<ty::BoundVariableKind>>,
     layout: InternedSet<'tcx, Layout>,
     adt_def: InternedSet<'tcx, AdtDef>,
+
+    /// `#[stable]` and `#[unstable]` attributes
+    stability: InternedSet<'tcx, attr::Stability>,
+
+    /// `#[rustc_const_stable]` and `#[rustc_const_unstable]` attributes
+    const_stability: InternedSet<'tcx, attr::ConstStability>,
 }
 
 impl<'tcx> CtxtInterners<'tcx> {
@@ -134,6 +140,8 @@ impl<'tcx> CtxtInterners<'tcx> {
             bound_variable_kinds: Default::default(),
             layout: Default::default(),
             adt_def: Default::default(),
+            stability: Default::default(),
+            const_stability: Default::default(),
         }
     }
 
@@ -212,7 +220,7 @@ pub struct CommonLifetimes<'tcx> {
     /// `ReStatic`
     pub re_static: Region<'tcx>,
 
-    /// Erased region, used after type-checking
+    /// Erased region, used outside of type inference.
     pub re_erased: Region<'tcx>,
 }
 
@@ -352,7 +360,7 @@ pub struct TypeckResults<'tcx> {
     field_indices: ItemLocalMap<usize>,
 
     /// Stores the types for various nodes in the AST. Note that this table
-    /// is not guaranteed to be populated until after typeck. See
+    /// is not guaranteed to be populated outside inference. See
     /// typeck::check::fn_ctxt for details.
     node_types: ItemLocalMap<Ty<'tcx>>,
 
@@ -1035,12 +1043,6 @@ pub struct GlobalCtxt<'tcx> {
     /// Data layout specification for the current target.
     pub data_layout: TargetDataLayout,
 
-    /// `#[stable]` and `#[unstable]` attributes
-    stability_interner: ShardedHashMap<&'tcx attr::Stability, ()>,
-
-    /// `#[rustc_const_stable]` and `#[rustc_const_unstable]` attributes
-    const_stability_interner: ShardedHashMap<&'tcx attr::ConstStability, ()>,
-
     /// Stores memory for globals (statics/consts).
     pub(crate) alloc_map: Lock<interpret::AllocMap<'tcx>>,
 
@@ -1092,16 +1094,6 @@ impl<'tcx> TyCtxt<'tcx> {
         self.create_memory_alloc(alloc)
     }
 
-    // FIXME(eddyb) move to `direct_interners!`.
-    pub fn intern_stability(self, stab: attr::Stability) -> &'tcx attr::Stability {
-        self.stability_interner.intern(stab, |stab| self.arena.alloc(stab))
-    }
-
-    // FIXME(eddyb) move to `direct_interners!`.
-    pub fn intern_const_stability(self, stab: attr::ConstStability) -> &'tcx attr::ConstStability {
-        self.const_stability_interner.intern(stab, |stab| self.arena.alloc(stab))
-    }
-
     /// Returns a range of the start/end indices specified with the
     /// `rustc_layout_scalar_valid_range` attribute.
     // FIXME(eddyb) this is an awkward spot for this method, maybe move it?
@@ -1185,8 +1177,6 @@ impl<'tcx> TyCtxt<'tcx> {
             evaluation_cache: Default::default(),
             crate_name: Symbol::intern(crate_name),
             data_layout,
-            stability_interner: Default::default(),
-            const_stability_interner: Default::default(),
             alloc_map: Lock::new(interpret::AllocMap::new()),
             output_filenames: Arc::new(output_filenames),
         }
@@ -1952,11 +1942,11 @@ impl<'tcx> TyCtxt<'tcx> {
 
                 writeln!(fmt, "InternalSubsts interner: #{}", self.0.interners.substs.len())?;
                 writeln!(fmt, "Region interner: #{}", self.0.interners.region.len())?;
-                writeln!(fmt, "Stability interner: #{}", self.0.stability_interner.len())?;
+                writeln!(fmt, "Stability interner: #{}", self.0.interners.stability.len())?;
                 writeln!(
                     fmt,
                     "Const Stability interner: #{}",
-                    self.0.const_stability_interner.len()
+                    self.0.interners.const_stability.len()
                 )?;
                 writeln!(
                     fmt,
@@ -1973,7 +1963,10 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 }
 
-/// An entry in an interner.
+// This type holds a `T` in the interner. The `T` is stored in the arena and
+// this type just holds a pointer to it, but it still effectively owns it. It
+// impls `Borrow` so that it can be looked up using the original
+// (non-arena-memory-owning) types.
 struct Interned<'tcx, T: ?Sized>(&'tcx T);
 
 impl<'tcx, T: 'tcx + ?Sized> Clone for Interned<'tcx, T> {
@@ -1981,6 +1974,7 @@ impl<'tcx, T: 'tcx + ?Sized> Clone for Interned<'tcx, T> {
         Interned(self.0)
     }
 }
+
 impl<'tcx, T: 'tcx + ?Sized> Copy for Interned<'tcx, T> {}
 
 impl<'tcx, T: 'tcx + ?Sized> IntoPointer for Interned<'tcx, T> {
@@ -1988,9 +1982,18 @@ impl<'tcx, T: 'tcx + ?Sized> IntoPointer for Interned<'tcx, T> {
         self.0 as *const _ as *const ()
     }
 }
-// N.B., an `Interned<Ty>` compares and hashes as a `TyKind`.
+
+#[allow(rustc::usage_of_ty_tykind)]
+impl<'tcx> Borrow<TyKind<'tcx>> for Interned<'tcx, TyS<'tcx>> {
+    fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> {
+        &self.0.kind()
+    }
+}
+
 impl<'tcx> PartialEq for Interned<'tcx, TyS<'tcx>> {
     fn eq(&self, other: &Interned<'tcx, TyS<'tcx>>) -> bool {
+        // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
+        // `x == y`.
         self.0.kind() == other.0.kind()
     }
 }
@@ -1999,19 +2002,21 @@ impl<'tcx> Eq for Interned<'tcx, TyS<'tcx>> {}
 
 impl<'tcx> Hash for Interned<'tcx, TyS<'tcx>> {
     fn hash<H: Hasher>(&self, s: &mut H) {
+        // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
         self.0.kind().hash(s)
     }
 }
 
-#[allow(rustc::usage_of_ty_tykind)]
-impl<'tcx> Borrow<TyKind<'tcx>> for Interned<'tcx, TyS<'tcx>> {
-    fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> {
-        &self.0.kind()
+impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>> for Interned<'tcx, PredicateInner<'tcx>> {
+    fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> {
+        &self.0.kind
     }
 }
-// N.B., an `Interned<PredicateInner>` compares and hashes as a `PredicateKind`.
+
 impl<'tcx> PartialEq for Interned<'tcx, PredicateInner<'tcx>> {
     fn eq(&self, other: &Interned<'tcx, PredicateInner<'tcx>>) -> bool {
+        // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
+        // `x == y`.
         self.0.kind == other.0.kind
     }
 }
@@ -2020,19 +2025,21 @@ impl<'tcx> Eq for Interned<'tcx, PredicateInner<'tcx>> {}
 
 impl<'tcx> Hash for Interned<'tcx, PredicateInner<'tcx>> {
     fn hash<H: Hasher>(&self, s: &mut H) {
+        // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
         self.0.kind.hash(s)
     }
 }
 
-impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>> for Interned<'tcx, PredicateInner<'tcx>> {
-    fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> {
-        &self.0.kind
+impl<'tcx, T> Borrow<[T]> for Interned<'tcx, List<T>> {
+    fn borrow<'a>(&'a self) -> &'a [T] {
+        &self.0[..]
     }
 }
 
-// N.B., an `Interned<List<T>>` compares and hashes as its elements.
 impl<'tcx, T: PartialEq> PartialEq for Interned<'tcx, List<T>> {
     fn eq(&self, other: &Interned<'tcx, List<T>>) -> bool {
+        // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
+        // `x == y`.
         self.0[..] == other.0[..]
     }
 }
@@ -2041,20 +2048,23 @@ impl<'tcx, T: Eq> Eq for Interned<'tcx, List<T>> {}
 
 impl<'tcx, T: Hash> Hash for Interned<'tcx, List<T>> {
     fn hash<H: Hasher>(&self, s: &mut H) {
+        // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
         self.0[..].hash(s)
     }
 }
 
-impl<'tcx, T> Borrow<[T]> for Interned<'tcx, List<T>> {
-    fn borrow<'a>(&'a self) -> &'a [T] {
-        &self.0[..]
-    }
-}
-
 macro_rules! direct_interners {
     ($($name:ident: $method:ident($ty:ty),)+) => {
-        $(impl<'tcx> PartialEq for Interned<'tcx, $ty> {
+        $(impl<'tcx> Borrow<$ty> for Interned<'tcx, $ty> {
+            fn borrow<'a>(&'a self) -> &'a $ty {
+                &self.0
+            }
+        }
+
+        impl<'tcx> PartialEq for Interned<'tcx, $ty> {
             fn eq(&self, other: &Self) -> bool {
+                // The `Borrow` trait requires that `x.borrow() == y.borrow()`
+                // equals `x == y`.
                 self.0 == other.0
             }
         }
@@ -2063,16 +2073,12 @@ macro_rules! direct_interners {
 
         impl<'tcx> Hash for Interned<'tcx, $ty> {
             fn hash<H: Hasher>(&self, s: &mut H) {
+                // The `Borrow` trait requires that `x.borrow().hash(s) ==
+                // x.hash(s)`.
                 self.0.hash(s)
             }
         }
 
-        impl<'tcx> Borrow<$ty> for Interned<'tcx, $ty> {
-            fn borrow<'a>(&'a self) -> &'a $ty {
-                &self.0
-            }
-        }
-
         impl<'tcx> TyCtxt<'tcx> {
             pub fn $method(self, v: $ty) -> &'tcx $ty {
                 self.interners.$name.intern(v, |v| {
@@ -2089,6 +2095,8 @@ direct_interners! {
     const_allocation: intern_const_alloc(Allocation),
     layout: intern_layout(Layout),
     adt_def: intern_adt_def(AdtDef),
+    stability: intern_stability(attr::Stability),
+    const_stability: intern_const_stability(attr::ConstStability),
 }
 
 macro_rules! slice_interners {
@@ -2786,8 +2794,33 @@ pub trait InternIteratorElement<T, R>: Sized {
 
 impl<T, R> InternIteratorElement<T, R> for T {
     type Output = R;
-    fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output {
-        f(&iter.collect::<SmallVec<[_; 8]>>())
+    fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(
+        mut iter: I,
+        f: F,
+    ) -> Self::Output {
+        // This code is hot enough that it's worth specializing for the most
+        // common length lists, to avoid the overhead of `SmallVec` creation.
+        // Lengths 0, 1, and 2 typically account for ~95% of cases. If
+        // `size_hint` is incorrect a panic will occur via an `unwrap` or an
+        // `assert`.
+        match iter.size_hint() {
+            (0, Some(0)) => {
+                assert!(iter.next().is_none());
+                f(&[])
+            }
+            (1, Some(1)) => {
+                let t0 = iter.next().unwrap();
+                assert!(iter.next().is_none());
+                f(&[t0])
+            }
+            (2, Some(2)) => {
+                let t0 = iter.next().unwrap();
+                let t1 = iter.next().unwrap();
+                assert!(iter.next().is_none());
+                f(&[t0, t1])
+            }
+            _ => f(&iter.collect::<SmallVec<[_; 8]>>()),
+        }
     }
 }
 
@@ -2797,6 +2830,7 @@ where
 {
     type Output = R;
     fn intern_with<I: Iterator<Item = Self>, F: FnOnce(&[T]) -> R>(iter: I, f: F) -> Self::Output {
+        // This code isn't hot.
         f(&iter.cloned().collect::<SmallVec<[_; 8]>>())
     }
 }
@@ -2809,10 +2843,15 @@ impl<T, R, E> InternIteratorElement<T, R> for Result<T, E> {
     ) -> Self::Output {
         // This code is hot enough that it's worth specializing for the most
         // common length lists, to avoid the overhead of `SmallVec` creation.
-        // The match arms are in order of frequency. The 1, 2, and 0 cases are
-        // typically hit in ~95% of cases. We assume that if the upper and
-        // lower bounds from `size_hint` agree they are correct.
+        // Lengths 0, 1, and 2 typically account for ~95% of cases. If
+        // `size_hint` is incorrect a panic will occur via an `unwrap` or an
+        // `assert`, unless a failure happens first, in which case the result
+        // will be an error anyway.
         Ok(match iter.size_hint() {
+            (0, Some(0)) => {
+                assert!(iter.next().is_none());
+                f(&[])
+            }
             (1, Some(1)) => {
                 let t0 = iter.next().unwrap()?;
                 assert!(iter.next().is_none());
@@ -2824,10 +2863,6 @@ impl<T, R, E> InternIteratorElement<T, R> for Result<T, E> {
                 assert!(iter.next().is_none());
                 f(&[t0, t1])
             }
-            (0, Some(0)) => {
-                assert!(iter.next().is_none());
-                f(&[])
-            }
             _ => f(&iter.collect::<Result<SmallVec<[_; 8]>, _>>()?),
         })
     }
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 5bb687512f3..5c4a4cdde25 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -972,10 +972,10 @@ fn foo(&self) -> Self::T { String::new() }
             let (span, sugg) = if has_params {
                 let pos = span.hi() - BytePos(1);
                 let span = Span::new(pos, pos, span.ctxt(), span.parent());
-                (span, format!(", {} = {}", assoc.ident, ty))
+                (span, format!(", {} = {}", assoc.ident(self), ty))
             } else {
                 let item_args = self.format_generic_args(assoc_substs);
-                (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident, item_args, ty))
+                (span.shrink_to_hi(), format!("<{}{} = {}>", assoc.ident(self), item_args, ty))
             };
             db.span_suggestion_verbose(span, msg, sugg, MaybeIncorrect);
             return true;
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 4bc3e23f4a5..e7a8e71ce71 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -119,6 +119,8 @@ mod sty;
 
 // Data types
 
+pub type RegisteredTools = FxHashSet<Ident>;
+
 #[derive(Debug)]
 pub struct ResolverOutputs {
     pub definitions: rustc_hir::definitions::Definitions,
@@ -141,6 +143,7 @@ pub struct ResolverOutputs {
     /// Mapping from ident span to path span for paths that don't exist as written, but that
     /// exist under `std`. For example, wrote `str::from_utf8` instead of `std::str::from_utf8`.
     pub confused_type_with_std_module: FxHashMap<Span, Span>,
+    pub registered_tools: RegisteredTools,
 }
 
 #[derive(Clone, Copy, Debug)]
@@ -376,15 +379,28 @@ pub struct CReaderCacheKey {
     pub pos: usize,
 }
 
+/// Represents a type.
+///
+/// IMPORTANT: Every `TyS` is *required* to have unique contents. The type's
+/// correctness relies on this, *but it does not enforce it*. Therefore, any
+/// code that creates a `TyS` must ensure uniqueness itself. In practice this
+/// is achieved by interning.
 #[allow(rustc::usage_of_ty_tykind)]
 pub struct TyS<'tcx> {
     /// This field shouldn't be used directly and may be removed in the future.
     /// Use `TyS::kind()` instead.
     kind: TyKind<'tcx>,
+
+    /// This field provides fast access to information that is also contained
+    /// in `kind`.
+    ///
     /// This field shouldn't be used directly and may be removed in the future.
     /// Use `TyS::flags()` instead.
     flags: TypeFlags,
 
+    /// This field provides fast access to information that is also contained
+    /// in `kind`.
+    ///
     /// This is a kind of confusing thing: it stores the smallest
     /// binder such that
     ///
@@ -436,6 +452,8 @@ impl<'tcx> PartialOrd for TyS<'tcx> {
 impl<'tcx> PartialEq for TyS<'tcx> {
     #[inline]
     fn eq(&self, other: &TyS<'tcx>) -> bool {
+        // Pointer equality implies equality (due to the unique contents
+        // assumption).
         ptr::eq(self, other)
     }
 }
@@ -443,6 +461,8 @@ impl<'tcx> Eq for TyS<'tcx> {}
 
 impl<'tcx> Hash for TyS<'tcx> {
     fn hash<H: Hasher>(&self, s: &mut H) {
+        // Pointer hashing is sufficient (due to the unique contents
+        // assumption).
         (self as *const TyS<'_>).hash(s)
     }
 }
@@ -746,6 +766,17 @@ impl<'tcx> TraitPredicate<'tcx> {
             *param_env = param_env.with_constness(self.constness.and(param_env.constness()))
         }
     }
+
+    /// Remap the constness of this predicate before emitting it for diagnostics.
+    pub fn remap_constness_diag(&mut self, param_env: ParamEnv<'tcx>) {
+        // this is different to `remap_constness` that callees want to print this predicate
+        // in case of selection errors. `T: ~const Drop` bounds cannot end up here when the
+        // param_env is not const because we it is always satisfied in non-const contexts.
+        if let hir::Constness::NotConst = param_env.constness() {
+            self.constness = ty::BoundConstness::NotConst;
+        }
+    }
+
     pub fn def_id(self) -> DefId {
         self.trait_ref.def_id
     }
@@ -753,6 +784,11 @@ impl<'tcx> TraitPredicate<'tcx> {
     pub fn self_ty(self) -> Ty<'tcx> {
         self.trait_ref.self_ty()
     }
+
+    #[inline]
+    pub fn is_const_if_const(self) -> bool {
+        self.constness == BoundConstness::ConstIfConst
+    }
 }
 
 impl<'tcx> PolyTraitPredicate<'tcx> {
@@ -764,6 +800,19 @@ impl<'tcx> PolyTraitPredicate<'tcx> {
     pub fn self_ty(self) -> ty::Binder<'tcx, Ty<'tcx>> {
         self.map_bound(|trait_ref| trait_ref.self_ty())
     }
+
+    /// Remap the constness of this predicate before emitting it for diagnostics.
+    pub fn remap_constness_diag(&mut self, param_env: ParamEnv<'tcx>) {
+        *self = self.map_bound(|mut p| {
+            p.remap_constness_diag(param_env);
+            p
+        });
+    }
+
+    #[inline]
+    pub fn is_const_if_const(self) -> bool {
+        self.skip_binder().is_const_if_const()
+    }
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
@@ -1349,6 +1398,11 @@ impl<'tcx> ParamEnv<'tcx> {
         self.packed.tag().constness
     }
 
+    #[inline]
+    pub fn is_const(self) -> bool {
+        self.packed.tag().constness == hir::Constness::Const
+    }
+
     /// Construct a trait environment with no where-clauses in scope
     /// where the values of all `impl Trait` and other hidden types
     /// are revealed. This is suitable for monomorphized, post-typeck
@@ -1464,6 +1518,7 @@ impl<'tcx> PolyTraitRef<'tcx> {
             polarity: ty::ImplPolarity::Positive,
         })
     }
+
     #[inline]
     pub fn without_const(self) -> PolyTraitPredicate<'tcx> {
         self.with_constness(BoundConstness::NotConst)
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index 84ab42a760b..b3b2bb4459f 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -34,8 +34,8 @@ impl<'tcx> TyCtxt<'tcx> {
     /// Erase the regions in `value` and then fully normalize all the
     /// types found within. The result will also have regions erased.
     ///
-    /// This is appropriate to use only after type-check: it assumes
-    /// that normalization will succeed, for example.
+    /// This should only be used outside of type inference. For example,
+    /// it assumes that normalization will succeed.
     pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T
     where
         T: TypeFoldable<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index bbdaf248a9e..ddcc8680d83 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -908,7 +908,7 @@ pub trait PrettyPrinter<'tcx>:
                     if !first {
                         p!(", ");
                     }
-                    p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).ident));
+                    p!(write("{} = ", self.tcx().associated_item(assoc_item_def_id).name));
 
                     match term.skip_binder() {
                         Term::Ty(ty) => {
@@ -2413,6 +2413,29 @@ impl<'tcx> ty::Binder<'tcx, ty::TraitRef<'tcx>> {
     }
 }
 
+#[derive(Copy, Clone, TypeFoldable, Lift)]
+pub struct TraitPredPrintModifiersAndPath<'tcx>(ty::TraitPredicate<'tcx>);
+
+impl<'tcx> fmt::Debug for TraitPredPrintModifiersAndPath<'tcx> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt::Display::fmt(self, f)
+    }
+}
+
+impl<'tcx> ty::TraitPredicate<'tcx> {
+    pub fn print_modifiers_and_trait_path(self) -> TraitPredPrintModifiersAndPath<'tcx> {
+        TraitPredPrintModifiersAndPath(self)
+    }
+}
+
+impl<'tcx> ty::PolyTraitPredicate<'tcx> {
+    pub fn print_modifiers_and_trait_path(
+        self,
+    ) -> ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>> {
+        self.map_bound(TraitPredPrintModifiersAndPath)
+    }
+}
+
 forward_display_to_print! {
     Ty<'tcx>,
     &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
@@ -2427,6 +2450,7 @@ forward_display_to_print! {
     ty::Binder<'tcx, TraitRefPrintOnlyTraitName<'tcx>>,
     ty::Binder<'tcx, ty::FnSig<'tcx>>,
     ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
+    ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>>,
     ty::Binder<'tcx, ty::SubtypePredicate<'tcx>>,
     ty::Binder<'tcx, ty::ProjectionPredicate<'tcx>>,
     ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>,
@@ -2455,7 +2479,7 @@ define_print_and_forward_display! {
     }
 
     ty::ExistentialProjection<'tcx> {
-        let name = cx.tcx().associated_item(self.item_def_id).ident;
+        let name = cx.tcx().associated_item(self.item_def_id).name;
         p!(write("{} = ", name), print(self.term))
     }
 
@@ -2491,6 +2515,18 @@ define_print_and_forward_display! {
         p!(print_def_path(self.0.def_id, &[]));
     }
 
+    TraitPredPrintModifiersAndPath<'tcx> {
+        if let ty::BoundConstness::ConstIfConst = self.0.constness {
+            p!("~const ")
+        }
+
+        if let ty::ImplPolarity::Negative = self.0.polarity {
+            p!("!")
+        }
+
+        p!(print(self.0.trait_ref.print_only_trait_path()));
+    }
+
     ty::ParamTy {
         p!(write("{}", self.name))
     }
@@ -2508,8 +2544,11 @@ define_print_and_forward_display! {
     }
 
     ty::TraitPredicate<'tcx> {
-        p!(print(self.trait_ref.self_ty()), ": ",
-           print(self.trait_ref.print_only_trait_path()))
+        p!(print(self.trait_ref.self_ty()), ": ");
+        if let ty::BoundConstness::ConstIfConst = self.constness {
+            p!("~const ");
+        }
+        p!(print(self.trait_ref.print_only_trait_path()))
     }
 
     ty::ProjectionPredicate<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 20db25f7899..7d4af6cfa40 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1464,11 +1464,11 @@ pub enum RegionKind {
     /// Static data that has an "infinite" lifetime. Top in the region lattice.
     ReStatic,
 
-    /// A region variable. Should not exist after typeck.
+    /// A region variable. Should not exist outside of type inference.
     ReVar(RegionVid),
 
     /// A placeholder region -- basically, the higher-ranked version of `ReFree`.
-    /// Should not exist after typeck.
+    /// Should not exist outside of type inference.
     RePlaceholder(ty::PlaceholderRegion),
 
     /// Empty lifetime is for data that is never accessed.  We tag the
@@ -1810,7 +1810,7 @@ impl<'tcx> TyS<'tcx> {
     pub fn sequence_element_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         match self.kind() {
             Array(ty, _) | Slice(ty) => ty,
-            Str => tcx.mk_mach_uint(ty::UintTy::U8),
+            Str => tcx.types.u8,
             _ => bug!("`sequence_element_type` called on non-sequence value: {}", self),
         }
     }
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index 63e9b58584c..cf97344f18e 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -180,8 +180,8 @@ impl<'tcx, E: TyEncoder<'tcx>> Encodable<E> for GenericArg<'tcx> {
 }
 
 impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for GenericArg<'tcx> {
-    fn decode(d: &mut D) -> Result<GenericArg<'tcx>, D::Error> {
-        Ok(GenericArgKind::decode(d)?.pack())
+    fn decode(d: &mut D) -> GenericArg<'tcx> {
+        GenericArgKind::decode(d).pack()
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 8793264a47f..96c27d649e4 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1041,6 +1041,42 @@ pub fn needs_drop_components<'tcx>(
     }
 }
 
+pub fn is_trivially_const_drop<'tcx>(ty: Ty<'tcx>) -> bool {
+    match *ty.kind() {
+        ty::Bool
+        | ty::Char
+        | ty::Int(_)
+        | ty::Uint(_)
+        | ty::Float(_)
+        | ty::Infer(ty::IntVar(_))
+        | ty::Infer(ty::FloatVar(_))
+        | ty::Str
+        | ty::RawPtr(_)
+        | ty::Ref(..)
+        | ty::FnDef(..)
+        | ty::FnPtr(_)
+        | ty::Never
+        | ty::Foreign(_) => true,
+
+        ty::Opaque(..)
+        | ty::Dynamic(..)
+        | ty::Error(_)
+        | ty::Bound(..)
+        | ty::Param(_)
+        | ty::Placeholder(_)
+        | ty::Projection(_)
+        | ty::Infer(_) => false,
+
+        // Not trivial because they have components, and instead of looking inside,
+        // we'll just perform trait selection.
+        ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(_) | ty::Adt(..) => false,
+
+        ty::Array(ty, _) | ty::Slice(ty) => is_trivially_const_drop(ty),
+
+        ty::Tuple(tys) => tys.iter().all(|ty| is_trivially_const_drop(ty.expect_ty())),
+    }
+}
+
 // Does the equivalent of
 // ```
 // let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 85950d82419..3294f2cf641 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -1347,23 +1347,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         let mut otherwise = None;
         for match_pair in match_pairs {
-            if let PatKind::Or { ref pats } = *match_pair.pattern.kind {
-                let or_span = match_pair.pattern.span;
-                let place = match_pair.place;
-
-                first_candidate.visit_leaves(|leaf_candidate| {
-                    self.test_or_pattern(
-                        leaf_candidate,
-                        &mut otherwise,
-                        pats,
-                        or_span,
-                        place.clone(),
-                        fake_borrows,
-                    );
-                });
-            } else {
+            let PatKind::Or { ref pats } = &*match_pair.pattern.kind else {
                 bug!("Or-patterns should have been sorted to the end");
-            }
+            };
+            let or_span = match_pair.pattern.span;
+            let place = match_pair.place;
+
+            first_candidate.visit_leaves(|leaf_candidate| {
+                self.test_or_pattern(
+                    leaf_candidate,
+                    &mut otherwise,
+                    pats,
+                    or_span,
+                    place.clone(),
+                    fake_borrows,
+                );
+            });
         }
 
         let remainder_start = otherwise.unwrap_or_else(|| self.cfg.start_new_block());
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 7ed5d1d67ab..f4bf28bfa5c 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -88,11 +88,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         switch_ty: Ty<'tcx>,
         options: &mut FxIndexMap<&'tcx ty::Const<'tcx>, u128>,
     ) -> bool {
-        let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) {
-            Some(match_pair) => match_pair,
-            _ => {
-                return false;
-            }
+        let Some(match_pair) = candidate.match_pairs.iter().find(|mp| mp.place == *test_place) else {
+            return false;
         };
 
         match *match_pair.pattern.kind {
diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs
index d348aaa899e..b21ca6028a2 100644
--- a/compiler/rustc_mir_build/src/lints.rs
+++ b/compiler/rustc_mir_build/src/lints.rs
@@ -33,6 +33,9 @@ crate fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
         if let Some(NonRecursive) = TriColorDepthFirstSearch::new(&body).run_from_start(&mut vis) {
             return;
         }
+        if vis.reachable_recursive_calls.is_empty() {
+            return;
+        }
 
         vis.reachable_recursive_calls.sort();
 
@@ -148,13 +151,14 @@ impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> {
     }
 
     fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool {
+        let terminator = self.body[bb].terminator();
+        if terminator.unwind() == Some(&Some(target)) && terminator.successors().count() > 1 {
+            return true;
+        }
         // Don't traverse successors of recursive calls or false CFG edges.
         match self.body[bb].terminator().kind {
             TerminatorKind::Call { ref func, .. } => self.is_recursive_call(func),
-
-            TerminatorKind::FalseUnwind { unwind: Some(imaginary_target), .. }
-            | TerminatorKind::FalseEdge { imaginary_target, .. } => imaginary_target == target,
-
+            TerminatorKind::FalseEdge { imaginary_target, .. } => imaginary_target == target,
             _ => false,
         }
     }
diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs
index c61ee6f7e6c..ce8b187a744 100644
--- a/compiler/rustc_mir_transform/src/coverage/debug.rs
+++ b/compiler/rustc_mir_transform/src/coverage/debug.rs
@@ -111,6 +111,7 @@
 use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
 use super::spans::CoverageSpan;
 
+use itertools::Itertools;
 use rustc_middle::mir::create_dump_file;
 use rustc_middle::mir::generic_graphviz::GraphvizWriter;
 use rustc_middle::mir::spanview::{self, SpanViewable};
@@ -739,7 +740,6 @@ pub(super) fn dump_coverage_graphviz<'tcx>(
                         )
                     }
                 })
-                .collect::<Vec<_>>()
                 .join("\n  ")
         ));
     }
@@ -768,7 +768,6 @@ fn bcb_to_string_sections<'tcx>(
                 .map(|expression| {
                     format!("Intermediate {}", debug_counters.format_counter(expression))
                 })
-                .collect::<Vec<_>>()
                 .join("\n"),
         );
     }
@@ -783,7 +782,6 @@ fn bcb_to_string_sections<'tcx>(
                         covspan.format(tcx, mir_body)
                     )
                 })
-                .collect::<Vec<_>>()
                 .join("\n"),
         );
     }
@@ -793,7 +791,6 @@ fn bcb_to_string_sections<'tcx>(
             dependency_counters
                 .iter()
                 .map(|counter| debug_counters.format_counter(counter))
-                .collect::<Vec<_>>()
                 .join("  \n"),
         ));
     }
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index a25402a1ff9..57862b6628d 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -1,5 +1,6 @@
 use super::Error;
 
+use itertools::Itertools;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::graph::dominators::{self, Dominators};
 use rustc_data_structures::graph::{self, GraphSuccessors, WithNumNodes, WithStartNode};
@@ -418,18 +419,11 @@ impl BasicCoverageBlockData {
     pub fn take_edge_counters(
         &mut self,
     ) -> Option<impl Iterator<Item = (BasicCoverageBlock, CoverageKind)>> {
-        self.edge_from_bcbs.take().map_or(None, |m| Some(m.into_iter()))
+        self.edge_from_bcbs.take().map(|m| m.into_iter())
     }
 
     pub fn id(&self) -> String {
-        format!(
-            "@{}",
-            self.basic_blocks
-                .iter()
-                .map(|bb| bb.index().to_string())
-                .collect::<Vec<_>>()
-                .join(ID_SEPARATOR)
-        )
+        format!("@{}", self.basic_blocks.iter().map(|bb| bb.index().to_string()).join(ID_SEPARATOR))
     }
 }
 
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index a9161580bc6..d1cb2826ded 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -1,6 +1,7 @@
 use super::debug::term_type;
 use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB};
 
+use itertools::Itertools;
 use rustc_data_structures::graph::WithNumNodes;
 use rustc_middle::mir::spanview::source_range_no_file;
 use rustc_middle::mir::{
@@ -27,7 +28,7 @@ impl CoverageStatement {
                 let stmt = &mir_body[bb].statements[stmt_index];
                 format!(
                     "{}: @{}[{}]: {:?}",
-                    source_range_no_file(tcx, &span),
+                    source_range_no_file(tcx, span),
                     bb.index(),
                     stmt_index,
                     stmt
@@ -37,7 +38,7 @@ impl CoverageStatement {
                 let term = mir_body[bb].terminator();
                 format!(
                     "{}: @{}.{}: {:?}",
-                    source_range_no_file(tcx, &span),
+                    source_range_no_file(tcx, span),
                     bb.index(),
                     term_type(&term.kind),
                     term.kind
@@ -154,7 +155,7 @@ impl CoverageSpan {
     pub fn format<'tcx>(&self, tcx: TyCtxt<'tcx>, mir_body: &mir::Body<'tcx>) -> String {
         format!(
             "{}\n    {}",
-            source_range_no_file(tcx, &self.span),
+            source_range_no_file(tcx, self.span),
             self.format_coverage_statements(tcx, mir_body).replace('\n', "\n    "),
         )
     }
@@ -169,11 +170,7 @@ impl CoverageSpan {
             CoverageStatement::Statement(bb, _, index) => (bb, index),
             CoverageStatement::Terminator(bb, _) => (bb, usize::MAX),
         });
-        sorted_coverage_statements
-            .iter()
-            .map(|covstmt| covstmt.format(tcx, mir_body))
-            .collect::<Vec<_>>()
-            .join("\n")
+        sorted_coverage_statements.iter().map(|covstmt| covstmt.format(tcx, mir_body)).join("\n")
     }
 
     /// If the span is part of a macro, returns the macro name symbol.
diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs
index b9c79d4cf2d..62ea2538ff0 100644
--- a/compiler/rustc_mir_transform/src/coverage/tests.rs
+++ b/compiler/rustc_mir_transform/src/coverage/tests.rs
@@ -31,6 +31,7 @@ use super::spans;
 
 use coverage_test_macros::let_bcb;
 
+use itertools::Itertools;
 use rustc_data_structures::graph::WithNumNodes;
 use rustc_data_structures::graph::WithSuccessors;
 use rustc_index::vec::{Idx, IndexVec};
@@ -232,11 +233,9 @@ fn print_mir_graphviz(name: &str, mir_body: &Body<'_>) {
                         mir_body
                             .successors(bb)
                             .map(|successor| { format!("    {:?} -> {:?};", bb, successor) })
-                            .collect::<Vec<_>>()
                             .join("\n")
                     )
                 })
-                .collect::<Vec<_>>()
                 .join("\n")
         );
     }
@@ -262,11 +261,9 @@ fn print_coverage_graphviz(
                         basic_coverage_blocks
                             .successors(bcb)
                             .map(|successor| { format!("    {:?} -> {:?};", bcb, successor) })
-                            .collect::<Vec<_>>()
                             .join("\n")
                     )
                 })
-                .collect::<Vec<_>>()
                 .join("\n")
         );
     }
diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
index ac88060f0d3..9a6b6532ce8 100644
--- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
+++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
@@ -1,12 +1,12 @@
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
-use rustc_middle::ty::{Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use std::fmt::Debug;
 
 use super::simplify::simplify_cfg;
 
 /// This pass optimizes something like
-/// ```text
+/// ```ignore (syntax-highlighting-only)
 /// let x: Option<()>;
 /// let y: Option<()>;
 /// match (x,y) {
@@ -15,144 +15,201 @@ use super::simplify::simplify_cfg;
 /// }
 /// ```
 /// into something like
-/// ```text
+/// ```ignore (syntax-highlighting-only)
 /// let x: Option<()>;
 /// let y: Option<()>;
-/// let discriminant_x = // get discriminant of x
-/// let discriminant_y = // get discriminant of y
-/// if discriminant_x != discriminant_y || discriminant_x == None {1} else {0}
+/// let discriminant_x = std::mem::discriminant(x);
+/// let discriminant_y = std::mem::discriminant(y);
+/// if discriminant_x == discriminant_y {
+///     match x {
+///         Some(_) => 0,
+///         _ => 1, // <----
+///     } //               | Actually the same bb
+/// } else { //            |
+///     1 // <--------------
+/// }
+/// ```
+///
+/// Specifically, it looks for instances of control flow like this:
+/// ```text
+///
+///     =================
+///     |      BB1      |
+///     |---------------|                  ============================
+///     |     ...       |         /------> |            BBC           |
+///     |---------------|         |        |--------------------------|
+///     |  switchInt(Q) |         |        |   _cl = discriminant(P)  |
+///     |       c       | --------/        |--------------------------|
+///     |       d       | -------\         |       switchInt(_cl)     |
+///     |      ...      |        |         |            c             | ---> BBC.2
+///     |    otherwise  | --\    |    /--- |         otherwise        |
+///     =================   |    |    |    ============================
+///                         |    |    |
+///     =================   |    |    |
+///     |      BBU      | <-|    |    |    ============================
+///     |---------------|   |    \-------> |            BBD           |
+///     |---------------|   |         |    |--------------------------|
+///     |  unreachable  |   |         |    |   _dl = discriminant(P)  |
+///     =================   |         |    |--------------------------|
+///                         |         |    |       switchInt(_dl)     |
+///     =================   |         |    |            d             | ---> BBD.2
+///     |      BB9      | <--------------- |         otherwise        |
+///     |---------------|                  ============================
+///     |      ...      |
+///     =================
 /// ```
+/// Where the `otherwise` branch on `BB1` is permitted to either go to `BBU` or to `BB9`. In the
+/// code:
+///  - `BB1` is `parent` and `BBC, BBD` are children
+///  - `P` is `child_place`
+///  - `child_ty` is the type of `_cl`.
+///  - `Q` is `parent_op`.
+///  - `parent_ty` is the type of `Q`.
+///  - `BB9` is `destination`
+/// All this is then transformed into:
+/// ```text
+///
+///     =======================
+///     |          BB1        |
+///     |---------------------|                  ============================
+///     |          ...        |         /------> |           BBEq           |
+///     | _s = discriminant(P)|         |        |--------------------------|
+///     | _t = Ne(Q, _s)      |         |        |--------------------------|
+///     |---------------------|         |        |       switchInt(Q)       |
+///     |     switchInt(_t)   |         |        |            c             | ---> BBC.2
+///     |        false        | --------/        |            d             | ---> BBD.2
+///     |       otherwise     | ---------------- |         otherwise        |
+///     =======================       |          ============================
+///                                   |
+///     =================             |
+///     |      BB9      | <-----------/
+///     |---------------|
+///     |      ...      |
+///     =================
+/// ```
+///
+/// This is only correct for some `P`, since `P` is now computed outside the original `switchInt`.
+/// The filter on which `P` are allowed (together with discussion of its correctness) is found in
+/// `may_hoist`.
 pub struct EarlyOtherwiseBranch;
 
 impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
-        //  FIXME(#78496)
-        sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() >= 3
+        sess.mir_opt_level() >= 2
     }
 
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         trace!("running EarlyOtherwiseBranch on {:?}", body.source);
 
-        // we are only interested in this bb if the terminator is a switchInt
-        let bbs_with_switch =
-            body.basic_blocks().iter_enumerated().filter(|(_, bb)| is_switch(bb.terminator()));
+        let mut should_cleanup = false;
 
-        let opts_to_apply: Vec<OptimizationToApply<'tcx>> = bbs_with_switch
-            .flat_map(|(bb_idx, bb)| {
-                let switch = bb.terminator();
-                let helper = Helper { body, tcx };
-                let infos = helper.go(bb, switch)?;
-                Some(OptimizationToApply { infos, basic_block_first_switch: bb_idx })
-            })
-            .collect();
-
-        let should_cleanup = !opts_to_apply.is_empty();
+        // Also consider newly generated bbs in the same pass
+        for i in 0..body.basic_blocks().len() {
+            let bbs = body.basic_blocks();
+            let parent = BasicBlock::from_usize(i);
+            let Some(opt_data) = evaluate_candidate(tcx, body, parent) else {
+                continue
+            };
 
-        for opt_to_apply in opts_to_apply {
-            if !tcx.consider_optimizing(|| format!("EarlyOtherwiseBranch {:?}", &opt_to_apply)) {
+            if !tcx.consider_optimizing(|| format!("EarlyOtherwiseBranch {:?}", &opt_data)) {
                 break;
             }
 
-            trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_to_apply);
+            trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_data);
 
-            let statements_before =
-                body.basic_blocks()[opt_to_apply.basic_block_first_switch].statements.len();
-            let end_of_block_location = Location {
-                block: opt_to_apply.basic_block_first_switch,
-                statement_index: statements_before,
+            should_cleanup = true;
+
+            let TerminatorKind::SwitchInt {
+                discr: parent_op,
+                switch_ty: parent_ty,
+                targets: parent_targets
+            } = &bbs[parent].terminator().kind else {
+                unreachable!()
+            };
+            // Always correct since we can only switch on `Copy` types
+            let parent_op = match parent_op {
+                Operand::Move(x) => Operand::Copy(*x),
+                Operand::Copy(x) => Operand::Copy(*x),
+                Operand::Constant(x) => Operand::Constant(x.clone()),
             };
+            let statements_before = bbs[parent].statements.len();
+            let parent_end = Location { block: parent, statement_index: statements_before };
 
             let mut patch = MirPatch::new(body);
 
-            // create temp to store second discriminant in
-            let discr_type = opt_to_apply.infos[0].second_switch_info.discr_ty;
-            let discr_span = opt_to_apply.infos[0].second_switch_info.discr_source_info.span;
-            let second_discriminant_temp = patch.new_temp(discr_type, discr_span);
+            // create temp to store second discriminant in, `_s` in example above
+            let second_discriminant_temp =
+                patch.new_temp(opt_data.child_ty, opt_data.child_source.span);
 
-            patch.add_statement(
-                end_of_block_location,
-                StatementKind::StorageLive(second_discriminant_temp),
-            );
+            patch.add_statement(parent_end, StatementKind::StorageLive(second_discriminant_temp));
 
             // create assignment of discriminant
-            let place_of_adt_to_get_discriminant_of =
-                opt_to_apply.infos[0].second_switch_info.place_of_adt_discr_read;
             patch.add_assign(
-                end_of_block_location,
+                parent_end,
                 Place::from(second_discriminant_temp),
-                Rvalue::Discriminant(place_of_adt_to_get_discriminant_of),
+                Rvalue::Discriminant(opt_data.child_place),
             );
 
-            // create temp to store NotEqual comparison between the two discriminants
-            let not_equal = BinOp::Ne;
-            let not_equal_res_type = not_equal.ty(tcx, discr_type, discr_type);
-            let not_equal_temp = patch.new_temp(not_equal_res_type, discr_span);
-            patch.add_statement(end_of_block_location, StatementKind::StorageLive(not_equal_temp));
-
-            // create NotEqual comparison between the two discriminants
-            let first_descriminant_place =
-                opt_to_apply.infos[0].first_switch_info.discr_used_in_switch;
-            let not_equal_rvalue = Rvalue::BinaryOp(
-                not_equal,
-                Box::new((
-                    Operand::Copy(Place::from(second_discriminant_temp)),
-                    Operand::Copy(first_descriminant_place),
-                )),
+            // create temp to store inequality comparison between the two discriminants, `_t` in
+            // example above
+            let nequal = BinOp::Ne;
+            let comp_res_type = nequal.ty(tcx, parent_ty, opt_data.child_ty);
+            let comp_temp = patch.new_temp(comp_res_type, opt_data.child_source.span);
+            patch.add_statement(parent_end, StatementKind::StorageLive(comp_temp));
+
+            // create inequality comparison between the two discriminants
+            let comp_rvalue = Rvalue::BinaryOp(
+                nequal,
+                Box::new((parent_op.clone(), Operand::Move(Place::from(second_discriminant_temp)))),
             );
             patch.add_statement(
-                end_of_block_location,
-                StatementKind::Assign(Box::new((Place::from(not_equal_temp), not_equal_rvalue))),
+                parent_end,
+                StatementKind::Assign(Box::new((Place::from(comp_temp), comp_rvalue))),
             );
 
-            let new_targets = opt_to_apply
-                .infos
-                .iter()
-                .flat_map(|x| x.second_switch_info.targets_with_values.iter())
-                .cloned();
-
-            let targets = SwitchTargets::new(
-                new_targets,
-                opt_to_apply.infos[0].first_switch_info.otherwise_bb,
-            );
-
-            // new block that jumps to the correct discriminant case. This block is switched to if the discriminants are equal
-            let new_switch_data = BasicBlockData::new(Some(Terminator {
-                source_info: opt_to_apply.infos[0].second_switch_info.discr_source_info,
+            let eq_new_targets = parent_targets.iter().map(|(value, child)| {
+                let TerminatorKind::SwitchInt{ targets, .. } = &bbs[child].terminator().kind else {
+                    unreachable!()
+                };
+                (value, targets.target_for_value(value))
+            });
+            let eq_targets = SwitchTargets::new(eq_new_targets, opt_data.destination);
+
+            // Create `bbEq` in example above
+            let eq_switch = BasicBlockData::new(Some(Terminator {
+                source_info: bbs[parent].terminator().source_info,
                 kind: TerminatorKind::SwitchInt {
-                    // the first and second discriminants are equal, so just pick one
-                    discr: Operand::Copy(first_descriminant_place),
-                    switch_ty: discr_type,
-                    targets,
+                    // switch on the first discriminant, so we can mark the second one as dead
+                    discr: parent_op,
+                    switch_ty: opt_data.child_ty,
+                    targets: eq_targets,
                 },
             }));
 
-            let new_switch_bb = patch.new_block(new_switch_data);
+            let eq_bb = patch.new_block(eq_switch);
 
-            // switch on the NotEqual. If true, then jump to the `otherwise` case.
-            // If false, then jump to a basic block that then jumps to the correct disciminant case
-            let true_case = opt_to_apply.infos[0].first_switch_info.otherwise_bb;
-            let false_case = new_switch_bb;
+            // Jump to it on the basis of the inequality comparison
+            let true_case = opt_data.destination;
+            let false_case = eq_bb;
             patch.patch_terminator(
-                opt_to_apply.basic_block_first_switch,
+                parent,
                 TerminatorKind::if_(
                     tcx,
-                    Operand::Move(Place::from(not_equal_temp)),
+                    Operand::Move(Place::from(comp_temp)),
                     true_case,
                     false_case,
                 ),
             );
 
             // generate StorageDead for the second_discriminant_temp not in use anymore
-            patch.add_statement(
-                end_of_block_location,
-                StatementKind::StorageDead(second_discriminant_temp),
-            );
+            patch.add_statement(parent_end, StatementKind::StorageDead(second_discriminant_temp));
 
-            // Generate a StorageDead for not_equal_temp in each of the targets, since we moved it into the switch
+            // Generate a StorageDead for comp_temp in each of the targets, since we moved it into
+            // the switch
             for bb in [false_case, true_case].iter() {
                 patch.add_statement(
                     Location { block: *bb, statement_index: 0 },
-                    StatementKind::StorageDead(not_equal_temp),
+                    StatementKind::StorageDead(comp_temp),
                 );
             }
 
@@ -167,201 +224,177 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
     }
 }
 
-fn is_switch(terminator: &Terminator<'_>) -> bool {
-    matches!(terminator.kind, TerminatorKind::SwitchInt { .. })
-}
-
-struct Helper<'a, 'tcx> {
-    body: &'a Body<'tcx>,
-    tcx: TyCtxt<'tcx>,
-}
-
-#[derive(Debug, Clone)]
-struct SwitchDiscriminantInfo<'tcx> {
-    /// Type of the discriminant being switched on
-    discr_ty: Ty<'tcx>,
-    /// The basic block that the otherwise branch points to
-    otherwise_bb: BasicBlock,
-    /// Target along with the value being branched from. Otherwise is not included
-    targets_with_values: Vec<(u128, BasicBlock)>,
-    discr_source_info: SourceInfo,
-    /// The place of the discriminant used in the switch
-    discr_used_in_switch: Place<'tcx>,
-    /// The place of the adt that has its discriminant read
-    place_of_adt_discr_read: Place<'tcx>,
-    /// The type of the adt that has its discriminant read
-    type_adt_matched_on: Ty<'tcx>,
-}
-
-#[derive(Debug)]
-struct OptimizationToApply<'tcx> {
-    infos: Vec<OptimizationInfo<'tcx>>,
-    /// Basic block of the original first switch
-    basic_block_first_switch: BasicBlock,
+/// Returns true if computing the discriminant of `place` may be hoisted out of the branch
+fn may_hoist<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, place: Place<'tcx>) -> bool {
+    for (place, proj) in place.iter_projections() {
+        match proj {
+            // Dereferencing in the computation of `place` might cause issues from one of two
+            // cateogires. First, the referrent might be invalid. We protect against this by
+            // dereferencing references only (not pointers). Second, the use of a reference may
+            // invalidate other references that are used later (for aliasing reasons). Consider
+            // where such an invalidated reference may appear:
+            //  - In `Q`: Not possible since `Q` is used as the operand of a `SwitchInt` and so
+            //    cannot contain referenced data.
+            //  - In `BBU`: Not possible since that block contains only the `unreachable` terminator
+            //  - In `BBC.2, BBD.2`: Not possible, since `discriminant(P)` was computed prior to
+            //    reaching that block in the input to our transformation, and so any data
+            //    invalidated by that computation could not have been used there.
+            //  - In `BB9`: Not possible since control flow might have reached `BB9` via the
+            //    `otherwise` branch in `BBC, BBD` in the input to our transformation, which would
+            //    have invalidated the data when computing `discriminant(P)`
+            // So dereferencing here is correct.
+            ProjectionElem::Deref => match place.ty(body.local_decls(), tcx).ty.kind() {
+                ty::Ref(..) => {}
+                _ => return false,
+            },
+            // Field projections are always valid
+            ProjectionElem::Field(..) => {}
+            // We cannot allow
+            // downcasts either, since the correctness of the downcast may depend on the parent
+            // branch being taken. An easy example of this is
+            // ```
+            // Q = discriminant(_3)
+            // P = (_3 as Variant)
+            // ```
+            // However, checking if the child and parent place are the same and only erroring then
+            // is not sufficient either, since the `discriminant(_3) == 1` (or whatever) check may
+            // be replaced by another optimization pass with any other condition that can be proven
+            // equivalent.
+            ProjectionElem::Downcast(..) => {
+                return false;
+            }
+            // We cannot allow indexing since the index may be out of bounds.
+            _ => {
+                return false;
+            }
+        }
+    }
+    true
 }
 
 #[derive(Debug)]
-struct OptimizationInfo<'tcx> {
-    /// Info about the first switch and discriminant
-    first_switch_info: SwitchDiscriminantInfo<'tcx>,
-    /// Info about the second switch and discriminant
-    second_switch_info: SwitchDiscriminantInfo<'tcx>,
+struct OptimizationData<'tcx> {
+    destination: BasicBlock,
+    child_place: Place<'tcx>,
+    child_ty: Ty<'tcx>,
+    child_source: SourceInfo,
 }
 
-impl<'tcx> Helper<'_, 'tcx> {
-    pub fn go(
-        &self,
-        bb: &BasicBlockData<'tcx>,
-        switch: &Terminator<'tcx>,
-    ) -> Option<Vec<OptimizationInfo<'tcx>>> {
-        // try to find the statement that defines the discriminant that is used for the switch
-        let discr = self.find_switch_discriminant_info(bb, switch)?;
-
-        // go through each target, finding a discriminant read, and a switch
-        let results = discr
-            .targets_with_values
-            .iter()
-            .map(|(value, target)| self.find_discriminant_switch_pairing(&discr, *target, *value));
-
-        // if the optimization did not apply for one of the targets, then abort
-        if results.clone().any(|x| x.is_none()) || results.len() == 0 {
-            trace!("NO: not all of the targets matched the pattern for optimization");
-            return None;
+fn evaluate_candidate<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    body: &Body<'tcx>,
+    parent: BasicBlock,
+) -> Option<OptimizationData<'tcx>> {
+    let bbs = body.basic_blocks();
+    let TerminatorKind::SwitchInt {
+        targets,
+        switch_ty: parent_ty,
+        ..
+    } = &bbs[parent].terminator().kind else {
+        return None
+    };
+    let parent_dest = {
+        let poss = targets.otherwise();
+        // If the fallthrough on the parent is trivially unreachable, we can let the
+        // children choose the destination
+        if bbs[poss].statements.len() == 0
+            && bbs[poss].terminator().kind == TerminatorKind::Unreachable
+        {
+            None
+        } else {
+            Some(poss)
         }
-
-        Some(results.flatten().collect())
+    };
+    let Some((_, child)) = targets.iter().next() else {
+        return None
+    };
+    let child_terminator = &bbs[child].terminator();
+    let TerminatorKind::SwitchInt {
+        switch_ty: child_ty,
+        targets: child_targets,
+        ..
+    } = &child_terminator.kind else {
+        return None
+    };
+    if child_ty != parent_ty {
+        return None;
+    }
+    let Some(StatementKind::Assign(boxed))
+        = &bbs[child].statements.first().map(|x| &x.kind) else {
+        return None;
+    };
+    let (_, Rvalue::Discriminant(child_place)) = &**boxed else {
+        return None;
+    };
+    let destination = parent_dest.unwrap_or(child_targets.otherwise());
+
+    // Verify that the optimization is legal in general
+    // We can hoist evaluating the child discriminant out of the branch
+    if !may_hoist(tcx, body, *child_place) {
+        return None;
     }
 
-    fn find_discriminant_switch_pairing(
-        &self,
-        discr_info: &SwitchDiscriminantInfo<'tcx>,
-        target: BasicBlock,
-        value: u128,
-    ) -> Option<OptimizationInfo<'tcx>> {
-        let bb = &self.body.basic_blocks()[target];
-        // find switch
-        let terminator = bb.terminator();
-        if is_switch(terminator) {
-            let this_bb_discr_info = self.find_switch_discriminant_info(bb, terminator)?;
-
-            // the types of the two adts matched on have to be equalfor this optimization to apply
-            if discr_info.type_adt_matched_on != this_bb_discr_info.type_adt_matched_on {
-                trace!(
-                    "NO: types do not match. LHS: {:?}, RHS: {:?}",
-                    discr_info.type_adt_matched_on,
-                    this_bb_discr_info.type_adt_matched_on
-                );
-                return None;
-            }
-
-            // the otherwise branch of the two switches have to point to the same bb
-            if discr_info.otherwise_bb != this_bb_discr_info.otherwise_bb {
-                trace!("NO: otherwise target is not the same");
-                return None;
-            }
-
-            // check that the value being matched on is the same. The
-            if !this_bb_discr_info.targets_with_values.iter().any(|x| x.0 == value) {
-                trace!("NO: values being matched on are not the same");
-                return None;
-            }
-
-            // only allow optimization if the left and right of the tuple being matched are the same variants.
-            // so the following should not optimize
-            //  ```rust
-            // let x: Option<()>;
-            // let y: Option<()>;
-            // match (x,y) {
-            //     (Some(_), None) => {},
-            //     _ => {}
-            // }
-            //  ```
-            // We check this by seeing that the value of the first discriminant is the only other discriminant value being used as a target in the second switch
-            if !(this_bb_discr_info.targets_with_values.len() == 1
-                && this_bb_discr_info.targets_with_values[0].0 == value)
-            {
-                trace!(
-                    "NO: The second switch did not have only 1 target (besides otherwise) that had the same value as the value from the first switch that got us here"
-                );
-                return None;
-            }
-
-            // when the second place is a projection of the first one, it's not safe to calculate their discriminant values sequentially.
-            // for example, this should not be optimized:
-            //
-            // ```rust
-            // enum E<'a> { Empty, Some(&'a E<'a>), }
-            // let Some(Some(_)) = e;
-            // ```
-            //
-            // ```mir
-            // bb0: {
-            //   _2 = discriminant(*_1)
-            //   switchInt(_2) -> [...]
-            // }
-            // bb1: {
-            //   _3 = discriminant(*(((*_1) as Some).0: &E))
-            //   switchInt(_3) -> [...]
-            // }
-            // ```
-            let discr_place = discr_info.place_of_adt_discr_read;
-            let this_discr_place = this_bb_discr_info.place_of_adt_discr_read;
-            if discr_place.local == this_discr_place.local
-                && this_discr_place.projection.starts_with(discr_place.projection)
-            {
-                trace!("NO: one target is the projection of another");
-                return None;
-            }
-
-            // if we reach this point, the optimization applies, and we should be able to optimize this case
-            // store the info that is needed to apply the optimization
-
-            Some(OptimizationInfo {
-                first_switch_info: discr_info.clone(),
-                second_switch_info: this_bb_discr_info,
-            })
-        } else {
-            None
+    // Verify that the optimization is legal for each branch
+    for (value, child) in targets.iter() {
+        if !verify_candidate_branch(&bbs[child], value, *child_place, destination) {
+            return None;
         }
     }
+    Some(OptimizationData {
+        destination,
+        child_place: *child_place,
+        child_ty,
+        child_source: child_terminator.source_info,
+    })
+}
 
-    fn find_switch_discriminant_info(
-        &self,
-        bb: &BasicBlockData<'tcx>,
-        switch: &Terminator<'tcx>,
-    ) -> Option<SwitchDiscriminantInfo<'tcx>> {
-        match &switch.kind {
-            TerminatorKind::SwitchInt { discr, targets, .. } => {
-                let discr_local = discr.place()?.as_local()?;
-                // the declaration of the discriminant read. Place of this read is being used in the switch
-                let discr_decl = &self.body.local_decls()[discr_local];
-                let discr_ty = discr_decl.ty;
-                // the otherwise target lies as the last element
-                let otherwise_bb = targets.otherwise();
-                let targets_with_values = targets.iter().collect();
-
-                // find the place of the adt where the discriminant is being read from
-                // assume this is the last statement of the block
-                let place_of_adt_discr_read = match bb.statements.last()?.kind {
-                    StatementKind::Assign(box (_, Rvalue::Discriminant(adt_place))) => {
-                        Some(adt_place)
-                    }
-                    _ => None,
-                }?;
-
-                let type_adt_matched_on = place_of_adt_discr_read.ty(self.body, self.tcx).ty;
-
-                Some(SwitchDiscriminantInfo {
-                    discr_used_in_switch: discr.place()?,
-                    discr_ty,
-                    otherwise_bb,
-                    targets_with_values,
-                    discr_source_info: discr_decl.source_info,
-                    place_of_adt_discr_read,
-                    type_adt_matched_on,
-                })
-            }
-            _ => unreachable!("must only be passed terminator that is a switch"),
-        }
+fn verify_candidate_branch<'tcx>(
+    branch: &BasicBlockData<'tcx>,
+    value: u128,
+    place: Place<'tcx>,
+    destination: BasicBlock,
+) -> bool {
+    // In order for the optimization to be correct, the branch must...
+    // ...have exactly one statement
+    if branch.statements.len() != 1 {
+        return false;
+    }
+    // ...assign the descriminant of `place` in that statement
+    let StatementKind::Assign(boxed) = &branch.statements[0].kind else {
+        return false
+    };
+    let (discr_place, Rvalue::Discriminant(from_place)) = &**boxed else {
+        return false
+    };
+    if *from_place != place {
+        return false;
+    }
+    // ...make that assignment to a local
+    if discr_place.projection.len() != 0 {
+        return false;
+    }
+    // ...terminate on a `SwitchInt` that invalidates that local
+    let TerminatorKind::SwitchInt{ discr: switch_op, targets, .. } = &branch.terminator().kind else {
+        return false
+    };
+    if *switch_op != Operand::Move(*discr_place) {
+        return false;
+    }
+    // ...fall through to `destination` if the switch misses
+    if destination != targets.otherwise() {
+        return false;
+    }
+    // ...have a branch for value `value`
+    let mut iter = targets.iter();
+    let Some((target_value, _)) = iter.next() else {
+        return false;
+    };
+    if target_value != value {
+        return false;
+    }
+    // ...and have no more branches
+    if let Some(_) = iter.next() {
+        return false;
     }
+    return true;
 }
diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs
index f364a332a78..1b9fddec2be 100644
--- a/compiler/rustc_mir_transform/src/function_item_references.rs
+++ b/compiler/rustc_mir_transform/src/function_item_references.rs
@@ -1,3 +1,4 @@
+use itertools::Itertools;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::visit::Visitor;
@@ -42,54 +43,28 @@ impl<'tcx> Visitor<'tcx> for FunctionItemRefChecker<'_, 'tcx> {
         } = &terminator.kind
         {
             let source_info = *self.body.source_info(location);
-            // Only handle function calls outside macros
-            if !source_info.span.from_expansion() {
-                let func_ty = func.ty(self.body, self.tcx);
-                if let ty::FnDef(def_id, substs_ref) = *func_ty.kind() {
-                    // Handle calls to `transmute`
-                    if self.tcx.is_diagnostic_item(sym::transmute, def_id) {
-                        let arg_ty = args[0].ty(self.body, self.tcx);
-                        for generic_inner_ty in arg_ty.walk() {
-                            if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() {
-                                if let Some((fn_id, fn_substs)) =
-                                    FunctionItemRefChecker::is_fn_ref(inner_ty)
-                                {
-                                    let span = self.nth_arg_span(&args, 0);
-                                    self.emit_lint(fn_id, fn_substs, source_info, span);
-                                }
+            let func_ty = func.ty(self.body, self.tcx);
+            if let ty::FnDef(def_id, substs_ref) = *func_ty.kind() {
+                // Handle calls to `transmute`
+                if self.tcx.is_diagnostic_item(sym::transmute, def_id) {
+                    let arg_ty = args[0].ty(self.body, self.tcx);
+                    for generic_inner_ty in arg_ty.walk() {
+                        if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() {
+                            if let Some((fn_id, fn_substs)) =
+                                FunctionItemRefChecker::is_fn_ref(inner_ty)
+                            {
+                                let span = self.nth_arg_span(&args, 0);
+                                self.emit_lint(fn_id, fn_substs, source_info, span);
                             }
                         }
-                    } else {
-                        self.check_bound_args(def_id, substs_ref, &args, source_info);
                     }
+                } else {
+                    self.check_bound_args(def_id, substs_ref, &args, source_info);
                 }
             }
         }
         self.super_terminator(terminator, location);
     }
-
-    /// Emits a lint for function references formatted with `fmt::Pointer::fmt` by macros. These
-    /// cases are handled as operands instead of call terminators to avoid any dependence on
-    /// unstable, internal formatting details like whether `fmt` is called directly or not.
-    fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
-        let source_info = *self.body.source_info(location);
-        if source_info.span.from_expansion() {
-            let op_ty = operand.ty(self.body, self.tcx);
-            if let ty::FnDef(def_id, substs_ref) = *op_ty.kind() {
-                if self.tcx.is_diagnostic_item(sym::pointer_trait_fmt, def_id) {
-                    let param_ty = substs_ref.type_at(0);
-                    if let Some((fn_id, fn_substs)) = FunctionItemRefChecker::is_fn_ref(param_ty) {
-                        // The operand's ctxt wouldn't display the lint since it's inside a macro so
-                        // we have to use the callsite's ctxt.
-                        let callsite_ctxt = source_info.span.source_callsite().ctxt();
-                        let span = source_info.span.with_ctxt(callsite_ctxt);
-                        self.emit_lint(fn_id, fn_substs, source_info, span);
-                    }
-                }
-            }
-        }
-        self.super_operand(operand, location);
-    }
 }
 
 impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
@@ -119,7 +94,13 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
                                 if let Some((fn_id, fn_substs)) =
                                     FunctionItemRefChecker::is_fn_ref(subst_ty)
                                 {
-                                    let span = self.nth_arg_span(args, arg_num);
+                                    let mut span = self.nth_arg_span(args, arg_num);
+                                    if span.from_expansion() {
+                                        // The operand's ctxt wouldn't display the lint since it's inside a macro so
+                                        // we have to use the callsite's ctxt.
+                                        let callsite_ctxt = span.source_callsite().ctxt();
+                                        span = span.with_ctxt(callsite_ctxt);
+                                    }
                                     self.emit_lint(fn_id, fn_substs, source_info, span);
                                 }
                             }
@@ -197,7 +178,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
         let ident = self.tcx.item_name(fn_id).to_ident_string();
         let ty_params = fn_substs.types().map(|ty| format!("{}", ty));
         let const_params = fn_substs.consts().map(|c| format!("{}", c));
-        let params = ty_params.chain(const_params).collect::<Vec<String>>().join(", ");
+        let params = ty_params.chain(const_params).join(", ");
         let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder();
         let variadic = if fn_sig.c_variadic() { ", ..." } else { "" };
         let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" };
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index bf6f13fa67b..8e1601fb719 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -18,7 +18,7 @@ extern crate rustc_middle;
 
 use required_consts::RequiredConstsVisitor;
 use rustc_const_eval::util;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::steal::Steal;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -136,8 +136,8 @@ fn is_mir_available(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
 
 /// Finds the full set of `DefId`s within the current crate that have
 /// MIR associated with them.
-fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxHashSet<LocalDefId> {
-    let mut set = FxHashSet::default();
+fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> {
+    let mut set = FxIndexSet::default();
 
     // All body-owners have MIR associated with them.
     set.extend(tcx.hir().body_owners());
@@ -146,7 +146,7 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxHashSet<LocalDefId> {
     // they don't have a BodyId, so we need to build them separately.
     struct GatherCtors<'a, 'tcx> {
         tcx: TyCtxt<'tcx>,
-        set: &'a mut FxHashSet<LocalDefId>,
+        set: &'a mut FxIndexSet<LocalDefId>,
     }
     impl<'tcx> Visitor<'tcx> for GatherCtors<'_, 'tcx> {
         fn visit_variant_data(
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 7e7f6938706..7f13da5d38f 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -807,10 +807,18 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                     self.output.push(create_fn_mono_item(tcx, instance, source));
                 }
             }
+            mir::TerminatorKind::Abort { .. } => {
+                let instance = Instance::mono(
+                    tcx,
+                    tcx.require_lang_item(LangItem::PanicNoUnwind, Some(source)),
+                );
+                if should_codegen_locally(tcx, &instance) {
+                    self.output.push(create_fn_mono_item(tcx, instance, source));
+                }
+            }
             mir::TerminatorKind::Goto { .. }
             | mir::TerminatorKind::SwitchInt { .. }
             | mir::TerminatorKind::Resume
-            | mir::TerminatorKind::Abort
             | mir::TerminatorKind::Return
             | mir::TerminatorKind::Unreachable => {}
             mir::TerminatorKind::GeneratorDrop
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index c41f2d3299b..17bac362ec8 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -731,28 +731,22 @@ impl<'a> Parser<'a> {
                     match x {
                         Ok((_, _, false)) => {
                             if self.eat(&token::Gt) {
-                                let turbo_err = e.span_suggestion_verbose(
+                                e.span_suggestion_verbose(
                                     binop.span.shrink_to_lo(),
                                     TURBOFISH_SUGGESTION_STR,
                                     "::".to_string(),
                                     Applicability::MaybeIncorrect,
-                                );
-                                if self.check(&TokenKind::Semi) {
-                                    turbo_err.emit();
-                                    *expr = self.mk_expr_err(expr.span);
-                                    return Ok(());
-                                } else {
-                                    match self.parse_expr() {
-                                        Ok(_) => {
-                                            turbo_err.emit();
-                                            *expr = self
-                                                .mk_expr_err(expr.span.to(self.prev_token.span));
-                                            return Ok(());
-                                        }
-                                        Err(mut err) => {
-                                            turbo_err.cancel();
-                                            err.cancel();
-                                        }
+                                )
+                                .emit();
+                                match self.parse_expr() {
+                                    Ok(_) => {
+                                        *expr =
+                                            self.mk_expr_err(expr.span.to(self.prev_token.span));
+                                        return Ok(());
+                                    }
+                                    Err(mut err) => {
+                                        *expr = self.mk_expr_err(expr.span);
+                                        err.cancel();
                                     }
                                 }
                             }
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 192e87b4c01..693dd0051da 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1458,7 +1458,7 @@ impl<'a> Parser<'a> {
             self.parse_block_expr(label, lo, BlockCheckMode::Default, attrs)
         } else if !ate_colon && (self.check(&TokenKind::Comma) || self.check(&TokenKind::Gt)) {
             // We're probably inside of a `Path<'a>` that needs a turbofish, so suppress the
-            // "must be followed by a colon" error.
+            // "must be followed by a colon" error, and the "expected one of" error.
             self.diagnostic().delay_span_bug(lo, "this label wasn't parsed correctly");
             consume_colon = false;
             Ok(self.mk_expr_err(lo))
@@ -2383,6 +2383,17 @@ impl<'a> Parser<'a> {
     }
 
     pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
+        fn check_let_expr(expr: &Expr) -> (bool, bool) {
+            match expr.kind {
+                ExprKind::Binary(_, ref lhs, ref rhs) => {
+                    let lhs_rslt = check_let_expr(lhs);
+                    let rhs_rslt = check_let_expr(rhs);
+                    (lhs_rslt.0 || rhs_rslt.0, false)
+                }
+                ExprKind::Let(..) => (true, true),
+                _ => (false, true),
+            }
+        }
         let attrs = self.parse_outer_attributes()?;
         self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
             let lo = this.token.span;
@@ -2390,9 +2401,12 @@ impl<'a> Parser<'a> {
             let guard = if this.eat_keyword(kw::If) {
                 let if_span = this.prev_token.span;
                 let cond = this.parse_expr()?;
-                if let ExprKind::Let(..) = cond.kind {
-                    // Remove the last feature gating of a `let` expression since it's stable.
-                    this.sess.gated_spans.ungate_last(sym::let_chains, cond.span);
+                let (has_let_expr, does_not_have_bin_op) = check_let_expr(&cond);
+                if has_let_expr {
+                    if does_not_have_bin_op {
+                        // Remove the last feature gating of a `let` expression since it's stable.
+                        this.sess.gated_spans.ungate_last(sym::let_chains, cond.span);
+                    }
                     let span = if_span.to(cond.span);
                     this.sess.gated_spans.gate(sym::if_let_guard, span);
                 }
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index ade441b0e7d..06849b31256 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -423,7 +423,7 @@ impl<'a> Parser<'a> {
                 // Maybe the user misspelled `macro_rules` (issue #91227)
                 if self.token.is_ident()
                     && path.segments.len() == 1
-                    && lev_distance("macro_rules", &path.segments[0].ident.to_string()) <= 3
+                    && lev_distance("macro_rules", &path.segments[0].ident.to_string(), 3).is_some()
                 {
                     err.span_suggestion(
                         path.span,
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index 0228196d1a1..00a93ccc9aa 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -1,6 +1,7 @@
 //! Checks validity of naked functions.
 
 use rustc_ast::{Attribute, InlineAsmOptions};
+use rustc_errors::struct_span_err;
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{FnKind, Visitor};
@@ -8,7 +9,6 @@ use rustc_hir::{ExprKind, HirId, InlineAsmOperand, StmtKind};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
-use rustc_session::lint::builtin::UNSUPPORTED_NAKED_FUNCTIONS;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
@@ -64,18 +64,16 @@ impl<'tcx> Visitor<'tcx> for CheckNakedFunctions<'tcx> {
             check_abi(self.tcx, hir_id, fn_header.abi, ident_span);
             check_no_patterns(self.tcx, body.params);
             check_no_parameters_use(self.tcx, body);
-            check_asm(self.tcx, hir_id, body, span);
-            check_inline(self.tcx, hir_id, attrs);
+            check_asm(self.tcx, body, span);
+            check_inline(self.tcx, attrs);
         }
     }
 }
 
 /// Check that the function isn't inlined.
-fn check_inline(tcx: TyCtxt<'_>, hir_id: HirId, attrs: &[Attribute]) {
+fn check_inline(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
     for attr in attrs.iter().filter(|attr| attr.has_name(sym::inline)) {
-        tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, attr.span, |lint| {
-            lint.build("naked functions cannot be inlined").emit();
-        });
+        tcx.sess.struct_span_err(attr.span, "naked functions cannot be inlined").emit();
     }
 }
 
@@ -146,31 +144,31 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
 }
 
 /// Checks that function body contains a single inline assembly block.
-fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, hir_id: HirId, body: &'tcx hir::Body<'tcx>, fn_span: Span) {
+fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, body: &'tcx hir::Body<'tcx>, fn_span: Span) {
     let mut this = CheckInlineAssembly { tcx, items: Vec::new() };
     this.visit_body(body);
     if let [(ItemKind::Asm, _)] = this.items[..] {
         // Ok.
     } else {
-        tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, fn_span, |lint| {
-            let mut diag = lint.build("naked functions must contain a single asm block");
-            let mut has_asm = false;
-            for &(kind, span) in &this.items {
-                match kind {
-                    ItemKind::Asm if has_asm => {
-                        diag.span_label(
-                            span,
-                            "multiple asm blocks are unsupported in naked functions",
-                        );
-                    }
-                    ItemKind::Asm => has_asm = true,
-                    ItemKind::NonAsm => {
-                        diag.span_label(span, "non-asm is unsupported in naked functions");
-                    }
+        let mut diag = struct_span_err!(
+            tcx.sess,
+            fn_span,
+            E0787,
+            "naked functions must contain a single asm block"
+        );
+        let mut has_asm = false;
+        for &(kind, span) in &this.items {
+            match kind {
+                ItemKind::Asm if has_asm => {
+                    diag.span_label(span, "multiple asm blocks are unsupported in naked functions");
+                }
+                ItemKind::Asm => has_asm = true,
+                ItemKind::NonAsm => {
+                    diag.span_label(span, "non-asm is unsupported in naked functions");
                 }
             }
-            diag.emit();
-        });
+        }
+        diag.emit();
     }
 }
 
@@ -221,7 +219,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
 
             ExprKind::InlineAsm(ref asm) => {
                 self.items.push((ItemKind::Asm, span));
-                self.check_inline_asm(expr.hir_id, asm, span);
+                self.check_inline_asm(asm, span);
             }
 
             ExprKind::DropTemps(..) | ExprKind::Block(..) | ExprKind::Err => {
@@ -230,7 +228,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
         }
     }
 
-    fn check_inline_asm(&self, hir_id: HirId, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) {
+    fn check_inline_asm(&self, asm: &'tcx hir::InlineAsm<'tcx>, span: Span) {
         let unsupported_operands: Vec<Span> = asm
             .operands
             .iter()
@@ -243,18 +241,17 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
             })
             .collect();
         if !unsupported_operands.is_empty() {
-            self.tcx.struct_span_lint_hir(
-                UNSUPPORTED_NAKED_FUNCTIONS,
-                hir_id,
+            struct_span_err!(
+                self.tcx.sess,
                 unsupported_operands,
-                |lint| {
-                    lint.build("only `const` and `sym` operands are supported in naked functions")
-                        .emit();
-                },
-            );
+                E0787,
+                "only `const` and `sym` operands are supported in naked functions",
+            )
+            .emit();
         }
 
         let unsupported_options: Vec<&'static str> = [
+            (InlineAsmOptions::MAY_UNWIND, "`may_unwind`"),
             (InlineAsmOptions::NOMEM, "`nomem`"),
             (InlineAsmOptions::NOSTACK, "`nostack`"),
             (InlineAsmOptions::PRESERVES_FLAGS, "`preserves_flags`"),
@@ -266,19 +263,24 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
         .collect();
 
         if !unsupported_options.is_empty() {
-            self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| {
-                lint.build(&format!(
-                    "asm options unsupported in naked functions: {}",
-                    unsupported_options.join(", ")
-                ))
-                .emit();
-            });
+            struct_span_err!(
+                self.tcx.sess,
+                span,
+                E0787,
+                "asm options unsupported in naked functions: {}",
+                unsupported_options.join(", ")
+            )
+            .emit();
         }
 
         if !asm.options.contains(InlineAsmOptions::NORETURN) {
-            self.tcx.struct_span_lint_hir(UNSUPPORTED_NAKED_FUNCTIONS, hir_id, span, |lint| {
-                lint.build("asm in naked functions must use `noreturn` option").emit();
-            });
+            struct_span_err!(
+                self.tcx.sess,
+                span,
+                E0787,
+                "asm in naked functions must use `noreturn` option"
+            )
+            .emit();
         }
     }
 }
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_query_impl/src/on_disk_cache.rs
index 5f6d9b050b2..06e276ab42b 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_query_impl/src/on_disk_cache.rs
@@ -163,15 +163,12 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
             // Decode the *position* of the footer, which can be found in the
             // last 8 bytes of the file.
             decoder.set_position(data.len() - IntEncodedWithFixedSize::ENCODED_SIZE);
-            let footer_pos = IntEncodedWithFixedSize::decode(&mut decoder)
-                .expect("error while trying to decode footer position")
-                .0 as usize;
+            let footer_pos = IntEncodedWithFixedSize::decode(&mut decoder).0 as usize;
 
             // Decode the file footer, which contains all the lookup tables, etc.
             decoder.set_position(footer_pos);
 
             decode_tagged(&mut decoder, TAG_FILE_FOOTER)
-                .expect("error while trying to decode footer position")
         };
 
         Self {
@@ -372,7 +369,7 @@ impl<'sess> OnDiskCache<'sess> {
         dep_node_index: SerializedDepNodeIndex,
     ) -> QuerySideEffects {
         let side_effects: Option<QuerySideEffects> =
-            self.load_indexed(tcx, dep_node_index, &self.prev_side_effects_index, "side_effects");
+            self.load_indexed(tcx, dep_node_index, &self.prev_side_effects_index);
 
         side_effects.unwrap_or_default()
     }
@@ -398,7 +395,7 @@ impl<'sess> OnDiskCache<'sess> {
     where
         T: for<'a> Decodable<CacheDecoder<'a, 'tcx>>,
     {
-        self.load_indexed(tcx, dep_node_index, &self.query_result_index, "query result")
+        self.load_indexed(tcx, dep_node_index, &self.query_result_index)
     }
 
     /// Stores side effect emitted during computation of an anonymous query.
@@ -423,17 +420,13 @@ impl<'sess> OnDiskCache<'sess> {
         tcx: TyCtxt<'tcx>,
         dep_node_index: SerializedDepNodeIndex,
         index: &FxHashMap<SerializedDepNodeIndex, AbsoluteBytePos>,
-        debug_tag: &'static str,
     ) -> Option<T>
     where
         T: for<'a> Decodable<CacheDecoder<'a, 'tcx>>,
     {
         let pos = index.get(&dep_node_index).cloned()?;
 
-        self.with_decoder(tcx, pos, |decoder| match decode_tagged(decoder, dep_node_index) {
-            Ok(v) => Some(v),
-            Err(e) => bug!("could not decode cached {}: {}", debug_tag, e),
-        })
+        self.with_decoder(tcx, pos, |decoder| Some(decode_tagged(decoder, dep_node_index)))
     }
 
     fn with_decoder<'a, 'tcx, T, F: for<'s> FnOnce(&mut CacheDecoder<'s, 'tcx>) -> T>(
@@ -535,7 +528,7 @@ impl<'a, 'tcx> DecoderWithPosition for CacheDecoder<'a, 'tcx> {
 
 // Decodes something that was encoded with `encode_tagged()` and verify that the
 // tag matches and the correct amount of bytes was read.
-fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> Result<V, D::Error>
+fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> V
 where
     T: Decodable<D> + Eq + std::fmt::Debug,
     V: Decodable<D>,
@@ -543,15 +536,15 @@ where
 {
     let start_pos = decoder.position();
 
-    let actual_tag = T::decode(decoder)?;
+    let actual_tag = T::decode(decoder);
     assert_eq!(actual_tag, expected_tag);
-    let value = V::decode(decoder)?;
+    let value = V::decode(decoder);
     let end_pos = decoder.position();
 
-    let expected_len: u64 = Decodable::decode(decoder)?;
+    let expected_len: u64 = Decodable::decode(decoder);
     assert_eq!((end_pos - start_pos) as u64, expected_len);
 
-    Ok(value)
+    value
 }
 
 impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> {
@@ -572,26 +565,22 @@ impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> {
         self.opaque.data[self.opaque.position()]
     }
 
-    fn cached_ty_for_shorthand<F>(
-        &mut self,
-        shorthand: usize,
-        or_insert_with: F,
-    ) -> Result<Ty<'tcx>, Self::Error>
+    fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx>
     where
-        F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>,
+        F: FnOnce(&mut Self) -> Ty<'tcx>,
     {
         let tcx = self.tcx();
 
         let cache_key = ty::CReaderCacheKey { cnum: None, pos: shorthand };
 
         if let Some(&ty) = tcx.ty_rcache.borrow().get(&cache_key) {
-            return Ok(ty);
+            return ty;
         }
 
-        let ty = or_insert_with(self)?;
+        let ty = or_insert_with(self);
         // This may overwrite the entry, but it should overwrite with the same value.
         tcx.ty_rcache.borrow_mut().insert_same(cache_key, ty);
-        Ok(ty)
+        ty
     }
 
     fn with_position<F, R>(&mut self, pos: usize, f: F) -> R
@@ -607,7 +596,7 @@ impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> {
         r
     }
 
-    fn decode_alloc_id(&mut self) -> Result<interpret::AllocId, Self::Error> {
+    fn decode_alloc_id(&mut self) -> interpret::AllocId {
         let alloc_decoding_session = self.alloc_decoding_session;
         alloc_decoding_session.decode_alloc_id(self)
     }
@@ -619,35 +608,35 @@ rustc_middle::implement_ty_decoder!(CacheDecoder<'a, 'tcx>);
 // when a `CacheDecoder` is passed to `Decodable::decode`. Unfortunately, we have to manually opt
 // into specializations this way, given how `CacheDecoder` and the decoding traits currently work.
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Vec<u8> {
-    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
         Decodable::decode(&mut d.opaque)
     }
 }
 
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for SyntaxContext {
-    fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+    fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self {
         let syntax_contexts = decoder.syntax_contexts;
         rustc_span::hygiene::decode_syntax_context(decoder, decoder.hygiene_context, |this, id| {
             // This closure is invoked if we haven't already decoded the data for the `SyntaxContext` we are deserializing.
             // We look up the position of the associated `SyntaxData` and decode it.
             let pos = syntax_contexts.get(&id).unwrap();
             this.with_position(pos.to_usize(), |decoder| {
-                let data: SyntaxContextData = decode_tagged(decoder, TAG_SYNTAX_CONTEXT)?;
-                Ok(data)
+                let data: SyntaxContextData = decode_tagged(decoder, TAG_SYNTAX_CONTEXT);
+                data
             })
         })
     }
 }
 
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId {
-    fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
-        let hash = ExpnHash::decode(decoder)?;
+    fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self {
+        let hash = ExpnHash::decode(decoder);
         if hash.is_root() {
-            return Ok(ExpnId::root());
+            return ExpnId::root();
         }
 
         if let Some(expn_id) = ExpnId::from_hash(hash) {
-            return Ok(expn_id);
+            return expn_id;
         }
 
         let krate = decoder.tcx.stable_crate_id_to_crate_num(hash.stable_crate_id());
@@ -660,7 +649,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId {
                 .unwrap_or_else(|| panic!("Bad hash {:?} (map {:?})", hash, decoder.expn_data));
 
             let data: ExpnData = decoder
-                .with_position(pos.to_usize(), |decoder| decode_tagged(decoder, TAG_EXPN_DATA))?;
+                .with_position(pos.to_usize(), |decoder| decode_tagged(decoder, TAG_EXPN_DATA));
             let expn_id = rustc_span::hygiene::register_local_expn_id(data, hash);
 
             #[cfg(debug_assertions)]
@@ -687,21 +676,21 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId {
         };
 
         debug_assert_eq!(expn_id.krate, krate);
-        Ok(expn_id)
+        expn_id
     }
 }
 
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span {
-    fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
-        let ctxt = SyntaxContext::decode(decoder)?;
-        let parent = Option::<LocalDefId>::decode(decoder)?;
-        let tag: u8 = Decodable::decode(decoder)?;
+    fn decode(decoder: &mut CacheDecoder<'a, 'tcx>) -> Self {
+        let ctxt = SyntaxContext::decode(decoder);
+        let parent = Option::<LocalDefId>::decode(decoder);
+        let tag: u8 = Decodable::decode(decoder);
 
         if tag == TAG_PARTIAL_SPAN {
-            return Ok(Span::new(BytePos(0), BytePos(0), ctxt, parent));
+            return Span::new(BytePos(0), BytePos(0), ctxt, parent);
         } else if tag == TAG_RELATIVE_SPAN {
-            let dlo = u32::decode(decoder)?;
-            let dto = u32::decode(decoder)?;
+            let dlo = u32::decode(decoder);
+            let dto = u32::decode(decoder);
 
             let enclosing =
                 decoder.tcx.definitions_untracked().def_span(parent.unwrap()).data_untracked();
@@ -712,29 +701,29 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span {
                 parent,
             );
 
-            return Ok(span);
+            return span;
         } else {
             debug_assert_eq!(tag, TAG_FULL_SPAN);
         }
 
-        let file_lo_index = SourceFileIndex::decode(decoder)?;
-        let line_lo = usize::decode(decoder)?;
-        let col_lo = BytePos::decode(decoder)?;
-        let len = BytePos::decode(decoder)?;
+        let file_lo_index = SourceFileIndex::decode(decoder);
+        let line_lo = usize::decode(decoder);
+        let col_lo = BytePos::decode(decoder);
+        let len = BytePos::decode(decoder);
 
         let file_lo = decoder.file_index_to_file(file_lo_index);
         let lo = file_lo.lines[line_lo - 1] + col_lo;
         let hi = lo + len;
 
-        Ok(Span::new(lo, hi, ctxt, parent))
+        Span::new(lo, hi, ctxt, parent)
     }
 }
 
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for CrateNum {
-    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
-        let stable_id = StableCrateId::decode(d)?;
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
+        let stable_id = StableCrateId::decode(d);
         let cnum = d.tcx.stable_crate_id_to_crate_num(stable_id);
-        Ok(cnum)
+        cnum
     }
 }
 
@@ -743,8 +732,8 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for CrateNum {
 // because we would not know how to transform the `DefIndex` to the current
 // context.
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefIndex {
-    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<DefIndex, String> {
-        Err(d.error("trying to decode `DefIndex` outside the context of a `DefId`"))
+    fn decode(_d: &mut CacheDecoder<'a, 'tcx>) -> DefIndex {
+        panic!("trying to decode `DefIndex` outside the context of a `DefId`")
     }
 }
 
@@ -752,23 +741,23 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefIndex {
 // compilation sessions. We use the `DefPathHash`, which is stable across
 // sessions, to map the old `DefId` to the new one.
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId {
-    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
         // Load the `DefPathHash` which is was we encoded the `DefId` as.
-        let def_path_hash = DefPathHash::decode(d)?;
+        let def_path_hash = DefPathHash::decode(d);
 
         // Using the `DefPathHash`, we can lookup the new `DefId`.
         // Subtle: We only encode a `DefId` as part of a query result.
         // If we get to this point, then all of the query inputs were green,
         // which means that the definition with this hash is guaranteed to
         // still exist in the current compilation session.
-        Ok(d.tcx().def_path_hash_to_def_id(def_path_hash, &mut || {
+        d.tcx().def_path_hash_to_def_id(def_path_hash, &mut || {
             panic!("Failed to convert DefPathHash {:?}", def_path_hash)
-        }))
+        })
     }
 }
 
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx FxHashSet<LocalDefId> {
-    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
         RefDecodable::decode(d)
     }
 }
@@ -776,31 +765,31 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx FxHashSet<LocalDefId>
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
     for &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>>
 {
-    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
         RefDecodable::decode(d)
     }
 }
 
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [thir::abstract_const::Node<'tcx>] {
-    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
         RefDecodable::decode(d)
     }
 }
 
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
-    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
         RefDecodable::decode(d)
     }
 }
 
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [rustc_ast::InlineAsmTemplatePiece] {
-    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
         RefDecodable::decode(d)
     }
 }
 
 impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [Span] {
-    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result<Self, String> {
+    fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
         RefDecodable::decode(d)
     }
 }
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index 47197a1e492..283eda7c85e 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -100,7 +100,7 @@ impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder<
     for SerializedDepGraph<K>
 {
     #[instrument(level = "debug", skip(d))]
-    fn decode(d: &mut opaque::Decoder<'a>) -> Result<SerializedDepGraph<K>, String> {
+    fn decode(d: &mut opaque::Decoder<'a>) -> SerializedDepGraph<K> {
         let start_position = d.position();
 
         // The last 16 bytes are the node count and edge count.
@@ -108,8 +108,8 @@ impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder<
         d.set_position(d.data.len() - 2 * IntEncodedWithFixedSize::ENCODED_SIZE);
         debug!("position: {:?}", d.position());
 
-        let node_count = IntEncodedWithFixedSize::decode(d)?.0 as usize;
-        let edge_count = IntEncodedWithFixedSize::decode(d)?.0 as usize;
+        let node_count = IntEncodedWithFixedSize::decode(d).0 as usize;
+        let edge_count = IntEncodedWithFixedSize::decode(d).0 as usize;
         debug!(?node_count, ?edge_count);
 
         debug!("position: {:?}", d.position());
@@ -123,12 +123,12 @@ impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder<
 
         for _index in 0..node_count {
             d.read_struct(|d| {
-                let dep_node: DepNode<K> = d.read_struct_field("node", Decodable::decode)?;
+                let dep_node: DepNode<K> = d.read_struct_field("node", Decodable::decode);
                 let _i: SerializedDepNodeIndex = nodes.push(dep_node);
                 debug_assert_eq!(_i.index(), _index);
 
                 let fingerprint: Fingerprint =
-                    d.read_struct_field("fingerprint", Decodable::decode)?;
+                    d.read_struct_field("fingerprint", Decodable::decode);
                 let _i: SerializedDepNodeIndex = fingerprints.push(fingerprint);
                 debug_assert_eq!(_i.index(), _index);
 
@@ -136,22 +136,21 @@ impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder<
                     d.read_seq(|d, len| {
                         let start = edge_list_data.len().try_into().unwrap();
                         for _ in 0..len {
-                            let edge = d.read_seq_elt(Decodable::decode)?;
+                            let edge = d.read_seq_elt(Decodable::decode);
                             edge_list_data.push(edge);
                         }
                         let end = edge_list_data.len().try_into().unwrap();
                         let _i: SerializedDepNodeIndex = edge_list_indices.push((start, end));
                         debug_assert_eq!(_i.index(), _index);
-                        Ok(())
                     })
                 })
-            })?;
+            });
         }
 
         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 })
+        SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data, index }
     }
 }
 
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 631b8fef668..e4d8b7d5283 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -108,7 +108,7 @@ impl<'a> Resolver<'a> {
     /// Reachable macros with block module parents exist due to `#[macro_export] macro_rules!`,
     /// but they cannot use def-site hygiene, so the assumption holds
     /// (<https://github.com/rust-lang/rust/pull/77984#issuecomment-712445508>).
-    crate fn get_nearest_non_block_module(&mut self, mut def_id: DefId) -> Module<'a> {
+    pub fn get_nearest_non_block_module(&mut self, mut def_id: DefId) -> Module<'a> {
         loop {
             match self.get_module(def_id) {
                 Some(module) => return module,
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 7b4fe6f0e07..7e1e5c78805 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1171,9 +1171,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
         ident: Symbol,
         kind: &AssocItemKind,
     ) -> Option<Symbol> {
-        let module = if let Some((module, _)) = self.current_trait_ref {
-            module
-        } else {
+        let Some((module, _)) = &self.current_trait_ref else {
             return None;
         };
         if ident == kw::Underscore {
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index b077a5c9144..4c7bdb33fb8 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -1000,46 +1000,45 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 // `fn foo<'a>() -> MyAnonTy<'a> { ... }`
                 //          ^                 ^this gets resolved in the current scope
                 for lifetime in lifetimes {
-                    if let hir::GenericArg::Lifetime(lifetime) = lifetime {
-                        self.visit_lifetime(lifetime);
+                    let hir::GenericArg::Lifetime(lifetime) = lifetime else {
+                        continue
+                    };
+                    self.visit_lifetime(lifetime);
+
+                    // Check for predicates like `impl for<'a> Trait<impl OtherTrait<'a>>`
+                    // and ban them. Type variables instantiated inside binders aren't
+                    // well-supported at the moment, so this doesn't work.
+                    // In the future, this should be fixed and this error should be removed.
+                    let def = self.map.defs.get(&lifetime.hir_id).cloned();
+                    let Some(Region::LateBound(_, _, def_id, _)) = def else {
+                        continue
+                    };
+                    let Some(def_id) = def_id.as_local() else {
+                        continue
+                    };
+                    let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
+                    // Ensure that the parent of the def is an item, not HRTB
+                    let parent_id = self.tcx.hir().get_parent_node(hir_id);
+                    // FIXME(cjgillot) Can this check be replaced by
+                    // `let parent_is_item = parent_id.is_owner();`?
+                    let parent_is_item = if let Some(parent_def_id) = parent_id.as_owner() {
+                        matches!(self.tcx.hir().krate().owners.get(parent_def_id), Some(Some(_)),)
+                    } else {
+                        false
+                    };
 
-                        // Check for predicates like `impl for<'a> Trait<impl OtherTrait<'a>>`
-                        // and ban them. Type variables instantiated inside binders aren't
-                        // well-supported at the moment, so this doesn't work.
-                        // In the future, this should be fixed and this error should be removed.
-                        let def = self.map.defs.get(&lifetime.hir_id).cloned();
-                        if let Some(Region::LateBound(_, _, def_id, _)) = def {
-                            if let Some(def_id) = def_id.as_local() {
-                                let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
-                                // Ensure that the parent of the def is an item, not HRTB
-                                let parent_id = self.tcx.hir().get_parent_node(hir_id);
-                                // FIXME(cjgillot) Can this check be replaced by
-                                // `let parent_is_item = parent_id.is_owner();`?
-                                let parent_is_item =
-                                    if let Some(parent_def_id) = parent_id.as_owner() {
-                                        matches!(
-                                            self.tcx.hir().krate().owners.get(parent_def_id),
-                                            Some(Some(_)),
-                                        )
-                                    } else {
-                                        false
-                                    };
-
-                                if !parent_is_item {
-                                    if !self.trait_definition_only {
-                                        struct_span_err!(
-                                            self.tcx.sess,
-                                            lifetime.span,
-                                            E0657,
-                                            "`impl Trait` can only capture lifetimes \
-                                                bound at the fn or impl level"
-                                        )
-                                        .emit();
-                                    }
-                                    self.uninsert_lifetime_on_error(lifetime, def.unwrap());
-                                }
-                            }
+                    if !parent_is_item {
+                        if !self.trait_definition_only {
+                            struct_span_err!(
+                                self.tcx.sess,
+                                lifetime.span,
+                                E0657,
+                                "`impl Trait` can only capture lifetimes \
+                                    bound at the fn or impl level"
+                            )
+                            .emit();
                         }
+                        self.uninsert_lifetime_on_error(lifetime, def.unwrap());
                     }
                 }
 
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index f5b2ba8fd72..45cc64ea194 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -53,7 +53,7 @@ use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::span_bug;
 use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, DefIdTree, MainDefinition, ResolverOutputs};
+use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools, ResolverOutputs};
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::cstore::{CrateStore, MetadataLoaderDyn};
 use rustc_session::lint;
@@ -614,7 +614,8 @@ impl<'a> ModuleData<'a> {
         }
     }
 
-    fn def_id(&self) -> DefId {
+    // Public for rustdoc.
+    pub fn def_id(&self) -> DefId {
         self.opt_def_id().expect("`ModuleData::def_id` is called on a block module")
     }
 
@@ -989,7 +990,7 @@ pub struct Resolver<'a> {
     macro_names: FxHashSet<Ident>,
     builtin_macros: FxHashMap<Symbol, BuiltinMacroState>,
     registered_attrs: FxHashSet<Ident>,
-    registered_tools: FxHashSet<Ident>,
+    registered_tools: RegisteredTools,
     macro_use_prelude: FxHashMap<Symbol, &'a NameBinding<'a>>,
     all_macros: FxHashMap<Symbol, Res>,
     macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
@@ -1487,6 +1488,7 @@ impl<'a> Resolver<'a> {
             trait_impls: self.trait_impls,
             proc_macros,
             confused_type_with_std_module,
+            registered_tools: self.registered_tools,
         }
     }
 
@@ -1511,6 +1513,7 @@ impl<'a> Resolver<'a> {
             trait_impls: self.trait_impls.clone(),
             proc_macros,
             confused_type_with_std_module: self.confused_type_with_std_module.clone(),
+            registered_tools: self.registered_tools.clone(),
         }
     }
 
@@ -3405,6 +3408,16 @@ impl<'a> Resolver<'a> {
         &self.all_macros
     }
 
+    /// For rustdoc.
+    /// For local modules returns only reexports, for external modules returns all children.
+    pub fn module_children_or_reexports(&self, def_id: DefId) -> Vec<ModChild> {
+        if let Some(def_id) = def_id.as_local() {
+            self.reexport_map.get(&def_id).cloned().unwrap_or_default()
+        } else {
+            self.cstore().module_children_untracked(def_id, self.session)
+        }
+    }
+
     /// Retrieves the span of the given `DefId` if `DefId` is in the local crate.
     #[inline]
     pub fn opt_span(&self, def_id: DefId) -> Option<Span> {
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 52685ec697c..82807e2d0a2 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -23,7 +23,7 @@ use rustc_hir::def::{self, DefKind, NonMacroAttrKind};
 use rustc_hir::def_id::{CrateNum, LocalDefId};
 use rustc_hir::PrimTy;
 use rustc_middle::middle::stability;
-use rustc_middle::ty;
+use rustc_middle::ty::{self, RegisteredTools};
 use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK};
 use rustc_session::lint::builtin::{SOFT_UNSTABLE, UNUSED_MACROS};
 use rustc_session::lint::BuiltinLintDiagnostics;
@@ -447,6 +447,10 @@ impl<'a> ResolverExpand for Resolver<'a> {
     fn declare_proc_macro(&mut self, id: NodeId) {
         self.proc_macros.push(id)
     }
+
+    fn registered_tools(&self) -> &RegisteredTools {
+        &self.registered_tools
+    }
 }
 
 impl<'a> Resolver<'a> {
diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs
index b95fe1b0549..570fa873a23 100644
--- a/compiler/rustc_save_analysis/src/lib.rs
+++ b/compiler/rustc_save_analysis/src/lib.rs
@@ -984,7 +984,7 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>(
         tcx.dep_graph.with_ignore(|| {
             info!("Dumping crate {}", cratename);
 
-            // Privacy checking requires and is done after type checking; use a
+            // Privacy checking must be done outside of type inference; use a
             // fallback in case the access levels couldn't have been correctly computed.
             let access_levels = match tcx.sess.compile_status() {
                 Ok(..) => tcx.privacy_access_levels(()),
diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml
index 49778f82253..f6b9e17e58e 100644
--- a/compiler/rustc_serialize/Cargo.toml
+++ b/compiler/rustc_serialize/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 edition = "2021"
 
 [dependencies]
-indexmap = "1"
+indexmap = "1.8.0"
 smallvec = { version = "1.6.1", features = ["union", "may_dangle"] }
 
 [dev-dependencies]
diff --git a/compiler/rustc_serialize/src/collection_impls.rs b/compiler/rustc_serialize/src/collection_impls.rs
index 80a7f650188..02b28f7c626 100644
--- a/compiler/rustc_serialize/src/collection_impls.rs
+++ b/compiler/rustc_serialize/src/collection_impls.rs
@@ -17,15 +17,8 @@ impl<S: Encoder, A: Array<Item: Encodable<S>>> Encodable<S> for SmallVec<A> {
 }
 
 impl<D: Decoder, A: Array<Item: Decodable<D>>> Decodable<D> for SmallVec<A> {
-    fn decode(d: &mut D) -> Result<SmallVec<A>, D::Error> {
-        d.read_seq(|d, len| {
-            let mut vec = SmallVec::with_capacity(len);
-            // FIXME(#48994) - could just be collected into a Result<SmallVec, D::Error>
-            for _ in 0..len {
-                vec.push(d.read_seq_elt(|d| Decodable::decode(d))?);
-            }
-            Ok(vec)
-        })
+    fn decode(d: &mut D) -> SmallVec<A> {
+        d.read_seq(|d, len| (0..len).map(|_| d.read_seq_elt(|d| Decodable::decode(d))).collect())
     }
 }
 
@@ -41,14 +34,8 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for LinkedList<T> {
 }
 
 impl<D: Decoder, T: Decodable<D>> Decodable<D> for LinkedList<T> {
-    fn decode(d: &mut D) -> Result<LinkedList<T>, D::Error> {
-        d.read_seq(|d, len| {
-            let mut list = LinkedList::new();
-            for _ in 0..len {
-                list.push_back(d.read_seq_elt(|d| Decodable::decode(d))?);
-            }
-            Ok(list)
-        })
+    fn decode(d: &mut D) -> LinkedList<T> {
+        d.read_seq(|d, len| (0..len).map(|_| d.read_seq_elt(|d| Decodable::decode(d))).collect())
     }
 }
 
@@ -64,14 +51,8 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for VecDeque<T> {
 }
 
 impl<D: Decoder, T: Decodable<D>> Decodable<D> for VecDeque<T> {
-    fn decode(d: &mut D) -> Result<VecDeque<T>, D::Error> {
-        d.read_seq(|d, len| {
-            let mut deque: VecDeque<T> = VecDeque::with_capacity(len);
-            for _ in 0..len {
-                deque.push_back(d.read_seq_elt(|d| Decodable::decode(d))?);
-            }
-            Ok(deque)
-        })
+    fn decode(d: &mut D) -> VecDeque<T> {
+        d.read_seq(|d, len| (0..len).map(|_| d.read_seq_elt(|d| Decodable::decode(d))).collect())
     }
 }
 
@@ -96,15 +77,15 @@ where
     K: Decodable<D> + PartialEq + Ord,
     V: Decodable<D>,
 {
-    fn decode(d: &mut D) -> Result<BTreeMap<K, V>, D::Error> {
+    fn decode(d: &mut D) -> BTreeMap<K, V> {
         d.read_map(|d, len| {
             let mut map = BTreeMap::new();
             for _ in 0..len {
-                let key = d.read_map_elt_key(|d| Decodable::decode(d))?;
-                let val = d.read_map_elt_val(|d| Decodable::decode(d))?;
+                let key = d.read_map_elt_key(|d| Decodable::decode(d));
+                let val = d.read_map_elt_val(|d| Decodable::decode(d));
                 map.insert(key, val);
             }
-            Ok(map)
+            map
         })
     }
 }
@@ -127,13 +108,13 @@ impl<D: Decoder, T> Decodable<D> for BTreeSet<T>
 where
     T: Decodable<D> + PartialEq + Ord,
 {
-    fn decode(d: &mut D) -> Result<BTreeSet<T>, D::Error> {
+    fn decode(d: &mut D) -> BTreeSet<T> {
         d.read_seq(|d, len| {
             let mut set = BTreeSet::new();
             for _ in 0..len {
-                set.insert(d.read_seq_elt(|d| Decodable::decode(d))?);
+                set.insert(d.read_seq_elt(|d| Decodable::decode(d)));
             }
-            Ok(set)
+            set
         })
     }
 }
@@ -161,16 +142,16 @@ where
     V: Decodable<D>,
     S: BuildHasher + Default,
 {
-    fn decode(d: &mut D) -> Result<HashMap<K, V, S>, D::Error> {
+    fn decode(d: &mut D) -> HashMap<K, V, S> {
         d.read_map(|d, len| {
             let state = Default::default();
             let mut map = HashMap::with_capacity_and_hasher(len, state);
             for _ in 0..len {
-                let key = d.read_map_elt_key(|d| Decodable::decode(d))?;
-                let val = d.read_map_elt_val(|d| Decodable::decode(d))?;
+                let key = d.read_map_elt_key(|d| Decodable::decode(d));
+                let val = d.read_map_elt_val(|d| Decodable::decode(d));
                 map.insert(key, val);
             }
-            Ok(map)
+            map
         })
     }
 }
@@ -205,14 +186,14 @@ where
     T: Decodable<D> + Hash + Eq,
     S: BuildHasher + Default,
 {
-    fn decode(d: &mut D) -> Result<HashSet<T, S>, D::Error> {
+    fn decode(d: &mut D) -> HashSet<T, S> {
         d.read_seq(|d, len| {
             let state = Default::default();
             let mut set = HashSet::with_capacity_and_hasher(len, state);
             for _ in 0..len {
-                set.insert(d.read_seq_elt(|d| Decodable::decode(d))?);
+                set.insert(d.read_seq_elt(|d| Decodable::decode(d)));
             }
-            Ok(set)
+            set
         })
     }
 }
@@ -240,16 +221,16 @@ where
     V: Decodable<D>,
     S: BuildHasher + Default,
 {
-    fn decode(d: &mut D) -> Result<indexmap::IndexMap<K, V, S>, D::Error> {
+    fn decode(d: &mut D) -> indexmap::IndexMap<K, V, S> {
         d.read_map(|d, len| {
             let state = Default::default();
             let mut map = indexmap::IndexMap::with_capacity_and_hasher(len, state);
             for _ in 0..len {
-                let key = d.read_map_elt_key(|d| Decodable::decode(d))?;
-                let val = d.read_map_elt_val(|d| Decodable::decode(d))?;
+                let key = d.read_map_elt_key(|d| Decodable::decode(d));
+                let val = d.read_map_elt_val(|d| Decodable::decode(d));
                 map.insert(key, val);
             }
-            Ok(map)
+            map
         })
     }
 }
@@ -274,14 +255,14 @@ where
     T: Decodable<D> + Hash + Eq,
     S: BuildHasher + Default,
 {
-    fn decode(d: &mut D) -> Result<indexmap::IndexSet<T, S>, D::Error> {
+    fn decode(d: &mut D) -> indexmap::IndexSet<T, S> {
         d.read_seq(|d, len| {
             let state = Default::default();
             let mut set = indexmap::IndexSet::with_capacity_and_hasher(len, state);
             for _ in 0..len {
-                set.insert(d.read_seq_elt(|d| Decodable::decode(d))?);
+                set.insert(d.read_seq_elt(|d| Decodable::decode(d)));
             }
-            Ok(set)
+            set
         })
     }
 }
@@ -294,9 +275,9 @@ impl<E: Encoder, T: Encodable<E>> Encodable<E> for Rc<[T]> {
 }
 
 impl<D: Decoder, T: Decodable<D>> Decodable<D> for Rc<[T]> {
-    fn decode(d: &mut D) -> Result<Rc<[T]>, D::Error> {
-        let vec: Vec<T> = Decodable::decode(d)?;
-        Ok(vec.into())
+    fn decode(d: &mut D) -> Rc<[T]> {
+        let vec: Vec<T> = Decodable::decode(d);
+        vec.into()
     }
 }
 
@@ -308,8 +289,8 @@ impl<E: Encoder, T: Encodable<E>> Encodable<E> for Arc<[T]> {
 }
 
 impl<D: Decoder, T: Decodable<D>> Decodable<D> for Arc<[T]> {
-    fn decode(d: &mut D) -> Result<Arc<[T]>, D::Error> {
-        let vec: Vec<T> = Decodable::decode(d)?;
-        Ok(vec.into())
+    fn decode(d: &mut D) -> Arc<[T]> {
+        let vec: Vec<T> = Decodable::decode(d);
+        vec.into()
     }
 }
diff --git a/compiler/rustc_serialize/src/json.rs b/compiler/rustc_serialize/src/json.rs
index cb9df3c3389..044de8e4e24 100644
--- a/compiler/rustc_serialize/src/json.rs
+++ b/compiler/rustc_serialize/src/json.rs
@@ -89,7 +89,7 @@
 //! let encoded = json::encode(&object).unwrap();
 //!
 //! // Deserialize using `json::decode`
-//! let decoded: TestStruct = json::decode(&encoded[..]).unwrap();
+//! let decoded: TestStruct = json::decode(&encoded[..]);
 //! ```
 //!
 //! ## Using the `ToJson` trait
@@ -173,7 +173,7 @@
 //! let json_str: String = json_obj.to_string();
 //!
 //! // Deserialize like before
-//! let decoded: TestStruct = json::decode(&json_str).unwrap();
+//! let decoded: TestStruct = json::decode(&json_str);
 //! ```
 
 use self::DecoderError::*;
@@ -265,6 +265,12 @@ pub enum DecoderError {
     ApplicationError(string::String),
 }
 
+macro_rules! bad {
+    ($e:expr) => {{
+        panic!("json decode error: {:?}", $e);
+    }};
+}
+
 #[derive(Copy, Clone, Debug)]
 pub enum EncoderError {
     FmtError(fmt::Error),
@@ -295,10 +301,10 @@ pub fn error_str(error: ErrorCode) -> &'static str {
 }
 
 /// Shortcut function to decode a JSON `&str` into an object
-pub fn decode<T: crate::Decodable<Decoder>>(s: &str) -> DecodeResult<T> {
+pub fn decode<T: crate::Decodable<Decoder>>(s: &str) -> T {
     let json = match from_str(s) {
         Ok(x) => x,
-        Err(e) => return Err(ParseError(e)),
+        Err(e) => bad!(ParseError(e)),
     };
 
     let mut decoder = Decoder::new(json);
@@ -334,15 +340,6 @@ impl fmt::Display for ParserError {
     }
 }
 
-impl fmt::Display for DecoderError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // FIXME this should be a nicer error
-        fmt::Debug::fmt(self, f)
-    }
-}
-
-impl std::error::Error for DecoderError {}
-
 impl fmt::Display for EncoderError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         // FIXME this should be a nicer error
@@ -2206,41 +2203,39 @@ impl Decoder {
 macro_rules! expect {
     ($e:expr, Null) => {{
         match $e {
-            Json::Null => Ok(()),
-            other => Err(ExpectedError("Null".to_owned(), other.to_string())),
+            Json::Null => (),
+            other => bad!(ExpectedError("Null".to_owned(), other.to_string())),
         }
     }};
     ($e:expr, $t:ident) => {{
         match $e {
-            Json::$t(v) => Ok(v),
-            other => Err(ExpectedError(stringify!($t).to_owned(), other.to_string())),
+            Json::$t(v) => v,
+            other => bad!(ExpectedError(stringify!($t).to_owned(), other.to_string())),
         }
     }};
 }
 
 macro_rules! read_primitive {
     ($name:ident, $ty:ty) => {
-        fn $name(&mut self) -> DecodeResult<$ty> {
+        fn $name(&mut self) -> $ty {
             match self.pop() {
-                Json::I64(f) => Ok(f as $ty),
-                Json::U64(f) => Ok(f as $ty),
-                Json::F64(f) => Err(ExpectedError("Integer".to_owned(), f.to_string())),
+                Json::I64(f) => f as $ty,
+                Json::U64(f) => f as $ty,
+                Json::F64(f) => bad!(ExpectedError("Integer".to_owned(), f.to_string())),
                 // re: #12967.. a type w/ numeric keys (ie HashMap<usize, V> etc)
                 // is going to have a string here, as per JSON spec.
                 Json::String(s) => match s.parse().ok() {
-                    Some(f) => Ok(f),
-                    None => Err(ExpectedError("Number".to_owned(), s)),
+                    Some(f) => f,
+                    None => bad!(ExpectedError("Number".to_owned(), s)),
                 },
-                value => Err(ExpectedError("Number".to_owned(), value.to_string())),
+                value => bad!(ExpectedError("Number".to_owned(), value.to_string())),
             }
         }
     };
 }
 
 impl crate::Decoder for Decoder {
-    type Error = DecoderError;
-
-    fn read_nil(&mut self) -> DecodeResult<()> {
+    fn read_unit(&mut self) -> () {
         expect!(self.pop(), Null)
     }
 
@@ -2257,156 +2252,150 @@ impl crate::Decoder for Decoder {
     read_primitive! { read_i64, i64 }
     read_primitive! { read_i128, i128 }
 
-    fn read_f32(&mut self) -> DecodeResult<f32> {
-        self.read_f64().map(|x| x as f32)
+    fn read_f32(&mut self) -> f32 {
+        self.read_f64() as f32
     }
 
-    fn read_f64(&mut self) -> DecodeResult<f64> {
+    fn read_f64(&mut self) -> f64 {
         match self.pop() {
-            Json::I64(f) => Ok(f as f64),
-            Json::U64(f) => Ok(f as f64),
-            Json::F64(f) => Ok(f),
+            Json::I64(f) => f as f64,
+            Json::U64(f) => f as f64,
+            Json::F64(f) => f,
             Json::String(s) => {
                 // re: #12967.. a type w/ numeric keys (ie HashMap<usize, V> etc)
                 // is going to have a string here, as per JSON spec.
                 match s.parse().ok() {
-                    Some(f) => Ok(f),
-                    None => Err(ExpectedError("Number".to_owned(), s)),
+                    Some(f) => f,
+                    None => bad!(ExpectedError("Number".to_owned(), s)),
                 }
             }
-            Json::Null => Ok(f64::NAN),
-            value => Err(ExpectedError("Number".to_owned(), value.to_string())),
+            Json::Null => f64::NAN,
+            value => bad!(ExpectedError("Number".to_owned(), value.to_string())),
         }
     }
 
-    fn read_bool(&mut self) -> DecodeResult<bool> {
+    fn read_bool(&mut self) -> bool {
         expect!(self.pop(), Boolean)
     }
 
-    fn read_char(&mut self) -> DecodeResult<char> {
-        let s = self.read_str()?;
-        {
-            let mut it = s.chars();
-            if let (Some(c), None) = (it.next(), it.next()) {
-                // exactly one character
-                return Ok(c);
-            }
+    fn read_char(&mut self) -> char {
+        let s = self.read_str();
+        let mut it = s.chars();
+        if let (Some(c), None) = (it.next(), it.next()) {
+            // exactly one character
+            return c;
         }
-        Err(ExpectedError("single character string".to_owned(), s.to_string()))
+        bad!(ExpectedError("single character string".to_owned(), s.to_string()));
     }
 
-    fn read_str(&mut self) -> DecodeResult<Cow<'_, str>> {
-        expect!(self.pop(), String).map(Cow::Owned)
+    fn read_str(&mut self) -> Cow<'_, str> {
+        Cow::Owned(expect!(self.pop(), String))
     }
 
-    fn read_raw_bytes_into(&mut self, s: &mut [u8]) -> Result<(), Self::Error> {
+    fn read_raw_bytes_into(&mut self, s: &mut [u8]) {
         for c in s.iter_mut() {
-            *c = self.read_u8()?;
+            *c = self.read_u8();
         }
-        Ok(())
     }
 
-    fn read_enum<T, F>(&mut self, f: F) -> DecodeResult<T>
+    fn read_enum<T, F>(&mut self, f: F) -> T
     where
-        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+        F: FnOnce(&mut Decoder) -> T,
     {
         f(self)
     }
 
-    fn read_enum_variant<T, F>(&mut self, names: &[&str], mut f: F) -> DecodeResult<T>
+    fn read_enum_variant<T, F>(&mut self, names: &[&str], mut f: F) -> T
     where
-        F: FnMut(&mut Decoder, usize) -> DecodeResult<T>,
+        F: FnMut(&mut Decoder, usize) -> T,
     {
         let name = match self.pop() {
             Json::String(s) => s,
             Json::Object(mut o) => {
                 let n = match o.remove("variant") {
                     Some(Json::String(s)) => s,
-                    Some(val) => return Err(ExpectedError("String".to_owned(), val.to_string())),
-                    None => return Err(MissingFieldError("variant".to_owned())),
+                    Some(val) => bad!(ExpectedError("String".to_owned(), val.to_string())),
+                    None => bad!(MissingFieldError("variant".to_owned())),
                 };
                 match o.remove("fields") {
                     Some(Json::Array(l)) => {
                         self.stack.extend(l.into_iter().rev());
                     }
-                    Some(val) => return Err(ExpectedError("Array".to_owned(), val.to_string())),
-                    None => return Err(MissingFieldError("fields".to_owned())),
+                    Some(val) => bad!(ExpectedError("Array".to_owned(), val.to_string())),
+                    None => bad!(MissingFieldError("fields".to_owned())),
                 }
                 n
             }
-            json => return Err(ExpectedError("String or Object".to_owned(), json.to_string())),
+            json => bad!(ExpectedError("String or Object".to_owned(), json.to_string())),
         };
         let idx = match names.iter().position(|n| *n == &name[..]) {
             Some(idx) => idx,
-            None => return Err(UnknownVariantError(name)),
+            None => bad!(UnknownVariantError(name)),
         };
         f(self, idx)
     }
 
-    fn read_enum_variant_arg<T, F>(&mut self, f: F) -> DecodeResult<T>
+    fn read_enum_variant_arg<T, F>(&mut self, f: F) -> T
     where
-        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+        F: FnOnce(&mut Decoder) -> T,
     {
         f(self)
     }
 
-    fn read_struct<T, F>(&mut self, f: F) -> DecodeResult<T>
+    fn read_struct<T, F>(&mut self, f: F) -> T
     where
-        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+        F: FnOnce(&mut Decoder) -> T,
     {
-        let value = f(self)?;
+        let value = f(self);
         self.pop();
-        Ok(value)
+        value
     }
 
-    fn read_struct_field<T, F>(&mut self, name: &str, f: F) -> DecodeResult<T>
+    fn read_struct_field<T, F>(&mut self, name: &str, f: F) -> T
     where
-        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+        F: FnOnce(&mut Decoder) -> T,
     {
-        let mut obj = expect!(self.pop(), Object)?;
+        let mut obj = expect!(self.pop(), Object);
 
         let value = match obj.remove(name) {
             None => {
                 // Add a Null and try to parse it as an Option<_>
                 // to get None as a default value.
                 self.stack.push(Json::Null);
-                match f(self) {
-                    Ok(x) => x,
-                    Err(_) => return Err(MissingFieldError(name.to_string())),
-                }
+                f(self)
             }
             Some(json) => {
                 self.stack.push(json);
-                f(self)?
+                f(self)
             }
         };
         self.stack.push(Json::Object(obj));
-        Ok(value)
+        value
     }
 
-    fn read_tuple<T, F>(&mut self, tuple_len: usize, f: F) -> DecodeResult<T>
+    fn read_tuple<T, F>(&mut self, tuple_len: usize, f: F) -> T
     where
-        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+        F: FnOnce(&mut Decoder) -> T,
     {
         self.read_seq(move |d, len| {
             if len == tuple_len {
                 f(d)
             } else {
-                Err(ExpectedError(format!("Tuple{}", tuple_len), format!("Tuple{}", len)))
+                bad!(ExpectedError(format!("Tuple{}", tuple_len), format!("Tuple{}", len)));
             }
         })
     }
 
-    fn read_tuple_arg<T, F>(&mut self, f: F) -> DecodeResult<T>
+    fn read_tuple_arg<T, F>(&mut self, f: F) -> T
     where
-        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+        F: FnOnce(&mut Decoder) -> T,
     {
         self.read_seq_elt(f)
     }
 
-    fn read_option<T, F>(&mut self, mut f: F) -> DecodeResult<T>
+    fn read_option<T, F>(&mut self, mut f: F) -> T
     where
-        F: FnMut(&mut Decoder, bool) -> DecodeResult<T>,
+        F: FnMut(&mut Decoder, bool) -> T,
     {
         match self.pop() {
             Json::Null => f(self, false),
@@ -2417,28 +2406,28 @@ impl crate::Decoder for Decoder {
         }
     }
 
-    fn read_seq<T, F>(&mut self, f: F) -> DecodeResult<T>
+    fn read_seq<T, F>(&mut self, f: F) -> T
     where
-        F: FnOnce(&mut Decoder, usize) -> DecodeResult<T>,
+        F: FnOnce(&mut Decoder, usize) -> T,
     {
-        let array = expect!(self.pop(), Array)?;
+        let array = expect!(self.pop(), Array);
         let len = array.len();
         self.stack.extend(array.into_iter().rev());
         f(self, len)
     }
 
-    fn read_seq_elt<T, F>(&mut self, f: F) -> DecodeResult<T>
+    fn read_seq_elt<T, F>(&mut self, f: F) -> T
     where
-        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+        F: FnOnce(&mut Decoder) -> T,
     {
         f(self)
     }
 
-    fn read_map<T, F>(&mut self, f: F) -> DecodeResult<T>
+    fn read_map<T, F>(&mut self, f: F) -> T
     where
-        F: FnOnce(&mut Decoder, usize) -> DecodeResult<T>,
+        F: FnOnce(&mut Decoder, usize) -> T,
     {
-        let obj = expect!(self.pop(), Object)?;
+        let obj = expect!(self.pop(), Object);
         let len = obj.len();
         for (key, value) in obj {
             self.stack.push(value);
@@ -2447,23 +2436,19 @@ impl crate::Decoder for Decoder {
         f(self, len)
     }
 
-    fn read_map_elt_key<T, F>(&mut self, f: F) -> DecodeResult<T>
+    fn read_map_elt_key<T, F>(&mut self, f: F) -> T
     where
-        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+        F: FnOnce(&mut Decoder) -> T,
     {
         f(self)
     }
 
-    fn read_map_elt_val<T, F>(&mut self, f: F) -> DecodeResult<T>
+    fn read_map_elt_val<T, F>(&mut self, f: F) -> T
     where
-        F: FnOnce(&mut Decoder) -> DecodeResult<T>,
+        F: FnOnce(&mut Decoder) -> T,
     {
         f(self)
     }
-
-    fn error(&mut self, err: &str) -> DecoderError {
-        ApplicationError(err.to_string())
-    }
 }
 
 /// A trait for converting values to JSON
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index 078237801be..c272c687a7e 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -560,134 +560,126 @@ impl<'a> Decoder<'a> {
 }
 
 macro_rules! read_leb128 {
-    ($dec:expr, $fun:ident) => {{ Ok(leb128::$fun($dec.data, &mut $dec.position)) }};
+    ($dec:expr, $fun:ident) => {{ leb128::$fun($dec.data, &mut $dec.position) }};
 }
 
 impl<'a> serialize::Decoder for Decoder<'a> {
-    type Error = String;
-
     #[inline]
-    fn read_nil(&mut self) -> Result<(), Self::Error> {
-        Ok(())
+    fn read_unit(&mut self) -> () {
+        ()
     }
 
     #[inline]
-    fn read_u128(&mut self) -> Result<u128, Self::Error> {
+    fn read_u128(&mut self) -> u128 {
         read_leb128!(self, read_u128_leb128)
     }
 
     #[inline]
-    fn read_u64(&mut self) -> Result<u64, Self::Error> {
+    fn read_u64(&mut self) -> u64 {
         read_leb128!(self, read_u64_leb128)
     }
 
     #[inline]
-    fn read_u32(&mut self) -> Result<u32, Self::Error> {
+    fn read_u32(&mut self) -> u32 {
         read_leb128!(self, read_u32_leb128)
     }
 
     #[inline]
-    fn read_u16(&mut self) -> Result<u16, Self::Error> {
+    fn read_u16(&mut self) -> u16 {
         let bytes = [self.data[self.position], self.data[self.position + 1]];
         let value = u16::from_le_bytes(bytes);
         self.position += 2;
-        Ok(value)
+        value
     }
 
     #[inline]
-    fn read_u8(&mut self) -> Result<u8, Self::Error> {
+    fn read_u8(&mut self) -> u8 {
         let value = self.data[self.position];
         self.position += 1;
-        Ok(value)
+        value
     }
 
     #[inline]
-    fn read_usize(&mut self) -> Result<usize, Self::Error> {
+    fn read_usize(&mut self) -> usize {
         read_leb128!(self, read_usize_leb128)
     }
 
     #[inline]
-    fn read_i128(&mut self) -> Result<i128, Self::Error> {
+    fn read_i128(&mut self) -> i128 {
         read_leb128!(self, read_i128_leb128)
     }
 
     #[inline]
-    fn read_i64(&mut self) -> Result<i64, Self::Error> {
+    fn read_i64(&mut self) -> i64 {
         read_leb128!(self, read_i64_leb128)
     }
 
     #[inline]
-    fn read_i32(&mut self) -> Result<i32, Self::Error> {
+    fn read_i32(&mut self) -> i32 {
         read_leb128!(self, read_i32_leb128)
     }
 
     #[inline]
-    fn read_i16(&mut self) -> Result<i16, Self::Error> {
+    fn read_i16(&mut self) -> i16 {
         let bytes = [self.data[self.position], self.data[self.position + 1]];
         let value = i16::from_le_bytes(bytes);
         self.position += 2;
-        Ok(value)
+        value
     }
 
     #[inline]
-    fn read_i8(&mut self) -> Result<i8, Self::Error> {
+    fn read_i8(&mut self) -> i8 {
         let as_u8 = self.data[self.position];
         self.position += 1;
-        unsafe { Ok(::std::mem::transmute(as_u8)) }
+        unsafe { ::std::mem::transmute(as_u8) }
     }
 
     #[inline]
-    fn read_isize(&mut self) -> Result<isize, Self::Error> {
+    fn read_isize(&mut self) -> isize {
         read_leb128!(self, read_isize_leb128)
     }
 
     #[inline]
-    fn read_bool(&mut self) -> Result<bool, Self::Error> {
-        let value = self.read_u8()?;
-        Ok(value != 0)
+    fn read_bool(&mut self) -> bool {
+        let value = self.read_u8();
+        value != 0
     }
 
     #[inline]
-    fn read_f64(&mut self) -> Result<f64, Self::Error> {
-        let bits = self.read_u64()?;
-        Ok(f64::from_bits(bits))
+    fn read_f64(&mut self) -> f64 {
+        let bits = self.read_u64();
+        f64::from_bits(bits)
     }
 
     #[inline]
-    fn read_f32(&mut self) -> Result<f32, Self::Error> {
-        let bits = self.read_u32()?;
-        Ok(f32::from_bits(bits))
+    fn read_f32(&mut self) -> f32 {
+        let bits = self.read_u32();
+        f32::from_bits(bits)
     }
 
     #[inline]
-    fn read_char(&mut self) -> Result<char, Self::Error> {
-        let bits = self.read_u32()?;
-        Ok(std::char::from_u32(bits).unwrap())
+    fn read_char(&mut self) -> char {
+        let bits = self.read_u32();
+        std::char::from_u32(bits).unwrap()
     }
 
     #[inline]
-    fn read_str(&mut self) -> Result<Cow<'_, str>, Self::Error> {
-        let len = self.read_usize()?;
+    fn read_str(&mut self) -> Cow<'_, str> {
+        let len = self.read_usize();
         let sentinel = self.data[self.position + len];
         assert!(sentinel == STR_SENTINEL);
         let s = unsafe {
             std::str::from_utf8_unchecked(&self.data[self.position..self.position + len])
         };
         self.position += len + 1;
-        Ok(Cow::Borrowed(s))
-    }
-
-    #[inline]
-    fn error(&mut self, err: &str) -> Self::Error {
-        err.to_string()
+        Cow::Borrowed(s)
     }
 
     #[inline]
-    fn read_raw_bytes_into(&mut self, s: &mut [u8]) -> Result<(), String> {
+    fn read_raw_bytes_into(&mut self, s: &mut [u8]) {
         let start = self.position;
         self.position += s.len();
         s.copy_from_slice(&self.data[start..self.position]);
-        Ok(())
     }
 }
 
@@ -715,9 +707,9 @@ impl serialize::Encodable<FileEncoder> for [u8] {
 // Specialize decoding `Vec<u8>`. This specialization also applies to decoding `Box<[u8]>`s, etc.,
 // since the default implementations call `decode` to produce a `Vec<u8>` internally.
 impl<'a> serialize::Decodable<Decoder<'a>> for Vec<u8> {
-    fn decode(d: &mut Decoder<'a>) -> Result<Self, String> {
-        let len = serialize::Decoder::read_usize(d)?;
-        Ok(d.read_raw_bytes(len).to_owned())
+    fn decode(d: &mut Decoder<'a>) -> Self {
+        let len = serialize::Decoder::read_usize(d);
+        d.read_raw_bytes(len).to_owned()
     }
 }
 
@@ -752,13 +744,13 @@ impl serialize::Encodable<FileEncoder> for IntEncodedWithFixedSize {
 
 impl<'a> serialize::Decodable<Decoder<'a>> for IntEncodedWithFixedSize {
     #[inline]
-    fn decode(decoder: &mut Decoder<'a>) -> Result<IntEncodedWithFixedSize, String> {
+    fn decode(decoder: &mut Decoder<'a>) -> IntEncodedWithFixedSize {
         let _start_pos = decoder.position();
         let bytes = decoder.read_raw_bytes(IntEncodedWithFixedSize::ENCODED_SIZE);
         let _end_pos = decoder.position();
         debug_assert_eq!((_end_pos - _start_pos), IntEncodedWithFixedSize::ENCODED_SIZE);
 
         let value = u64::from_le_bytes(bytes.try_into().unwrap());
-        Ok(IntEncodedWithFixedSize(value))
+        IntEncodedWithFixedSize(value)
     }
 }
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index 96a2231b590..a6172403fd6 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -173,144 +173,145 @@ pub trait Encoder {
     }
 }
 
+// Note: all the methods in this trait are infallible, which may be surprising.
+// They used to be fallible (i.e. return a `Result`) but many of the impls just
+// panicked when something went wrong, and for the cases that didn't the
+// top-level invocation would also just panic on failure. Switching to
+// infallibility made things faster and lots of code a little simpler and more
+// concise.
 pub trait Decoder {
-    type Error;
-
     // Primitive types:
-    fn read_nil(&mut self) -> Result<(), Self::Error>;
-    fn read_usize(&mut self) -> Result<usize, Self::Error>;
-    fn read_u128(&mut self) -> Result<u128, Self::Error>;
-    fn read_u64(&mut self) -> Result<u64, Self::Error>;
-    fn read_u32(&mut self) -> Result<u32, Self::Error>;
-    fn read_u16(&mut self) -> Result<u16, Self::Error>;
-    fn read_u8(&mut self) -> Result<u8, Self::Error>;
-    fn read_isize(&mut self) -> Result<isize, Self::Error>;
-    fn read_i128(&mut self) -> Result<i128, Self::Error>;
-    fn read_i64(&mut self) -> Result<i64, Self::Error>;
-    fn read_i32(&mut self) -> Result<i32, Self::Error>;
-    fn read_i16(&mut self) -> Result<i16, Self::Error>;
-    fn read_i8(&mut self) -> Result<i8, Self::Error>;
-    fn read_bool(&mut self) -> Result<bool, Self::Error>;
-    fn read_f64(&mut self) -> Result<f64, Self::Error>;
-    fn read_f32(&mut self) -> Result<f32, Self::Error>;
-    fn read_char(&mut self) -> Result<char, Self::Error>;
-    fn read_str(&mut self) -> Result<Cow<'_, str>, Self::Error>;
-    fn read_raw_bytes_into(&mut self, s: &mut [u8]) -> Result<(), Self::Error>;
+    fn read_unit(&mut self) -> ();
+    fn read_usize(&mut self) -> usize;
+    fn read_u128(&mut self) -> u128;
+    fn read_u64(&mut self) -> u64;
+    fn read_u32(&mut self) -> u32;
+    fn read_u16(&mut self) -> u16;
+    fn read_u8(&mut self) -> u8;
+    fn read_isize(&mut self) -> isize;
+    fn read_i128(&mut self) -> i128;
+    fn read_i64(&mut self) -> i64;
+    fn read_i32(&mut self) -> i32;
+    fn read_i16(&mut self) -> i16;
+    fn read_i8(&mut self) -> i8;
+    fn read_bool(&mut self) -> bool;
+    fn read_f64(&mut self) -> f64;
+    fn read_f32(&mut self) -> f32;
+    fn read_char(&mut self) -> char;
+    fn read_str(&mut self) -> Cow<'_, str>;
+    fn read_raw_bytes_into(&mut self, s: &mut [u8]);
 
     // Compound types:
     #[inline]
-    fn read_enum<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+    fn read_enum<T, F>(&mut self, f: F) -> T
     where
-        F: FnOnce(&mut Self) -> Result<T, Self::Error>,
+        F: FnOnce(&mut Self) -> T,
     {
         f(self)
     }
 
     #[inline]
-    fn read_enum_variant<T, F>(&mut self, _names: &[&str], mut f: F) -> Result<T, Self::Error>
+    fn read_enum_variant<T, F>(&mut self, _names: &[&str], mut f: F) -> T
     where
-        F: FnMut(&mut Self, usize) -> Result<T, Self::Error>,
+        F: FnMut(&mut Self, usize) -> T,
     {
-        let disr = self.read_usize()?;
+        let disr = self.read_usize();
         f(self, disr)
     }
 
     #[inline]
-    fn read_enum_variant_arg<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+    fn read_enum_variant_arg<T, F>(&mut self, f: F) -> T
     where
-        F: FnOnce(&mut Self) -> Result<T, Self::Error>,
+        F: FnOnce(&mut Self) -> T,
     {
         f(self)
     }
 
     #[inline]
-    fn read_struct<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+    fn read_struct<T, F>(&mut self, f: F) -> T
     where
-        F: FnOnce(&mut Self) -> Result<T, Self::Error>,
+        F: FnOnce(&mut Self) -> T,
     {
         f(self)
     }
 
     #[inline]
-    fn read_struct_field<T, F>(&mut self, _f_name: &str, f: F) -> Result<T, Self::Error>
+    fn read_struct_field<T, F>(&mut self, _f_name: &str, f: F) -> T
     where
-        F: FnOnce(&mut Self) -> Result<T, Self::Error>,
+        F: FnOnce(&mut Self) -> T,
     {
         f(self)
     }
 
     #[inline]
-    fn read_tuple<T, F>(&mut self, _len: usize, f: F) -> Result<T, Self::Error>
+    fn read_tuple<T, F>(&mut self, _len: usize, f: F) -> T
     where
-        F: FnOnce(&mut Self) -> Result<T, Self::Error>,
+        F: FnOnce(&mut Self) -> T,
     {
         f(self)
     }
 
     #[inline]
-    fn read_tuple_arg<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+    fn read_tuple_arg<T, F>(&mut self, f: F) -> T
     where
-        F: FnOnce(&mut Self) -> Result<T, Self::Error>,
+        F: FnOnce(&mut Self) -> T,
     {
         f(self)
     }
 
     // Specialized types:
-    fn read_option<T, F>(&mut self, mut f: F) -> Result<T, Self::Error>
+    fn read_option<T, F>(&mut self, mut f: F) -> T
     where
-        F: FnMut(&mut Self, bool) -> Result<T, Self::Error>,
+        F: FnMut(&mut Self, bool) -> T,
     {
         self.read_enum(move |this| {
             this.read_enum_variant(&["None", "Some"], move |this, idx| match idx {
                 0 => f(this, false),
                 1 => f(this, true),
-                _ => Err(this.error("read_option: expected 0 for None or 1 for Some")),
+                _ => panic!("read_option: expected 0 for None or 1 for Some"),
             })
         })
     }
 
-    fn read_seq<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+    fn read_seq<T, F>(&mut self, f: F) -> T
     where
-        F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>,
+        F: FnOnce(&mut Self, usize) -> T,
     {
-        let len = self.read_usize()?;
+        let len = self.read_usize();
         f(self, len)
     }
 
     #[inline]
-    fn read_seq_elt<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+    fn read_seq_elt<T, F>(&mut self, f: F) -> T
     where
-        F: FnOnce(&mut Self) -> Result<T, Self::Error>,
+        F: FnOnce(&mut Self) -> T,
     {
         f(self)
     }
 
-    fn read_map<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+    fn read_map<T, F>(&mut self, f: F) -> T
     where
-        F: FnOnce(&mut Self, usize) -> Result<T, Self::Error>,
+        F: FnOnce(&mut Self, usize) -> T,
     {
-        let len = self.read_usize()?;
+        let len = self.read_usize();
         f(self, len)
     }
 
     #[inline]
-    fn read_map_elt_key<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+    fn read_map_elt_key<T, F>(&mut self, f: F) -> T
     where
-        F: FnOnce(&mut Self) -> Result<T, Self::Error>,
+        F: FnOnce(&mut Self) -> T,
     {
         f(self)
     }
 
     #[inline]
-    fn read_map_elt_val<T, F>(&mut self, f: F) -> Result<T, Self::Error>
+    fn read_map_elt_val<T, F>(&mut self, f: F) -> T
     where
-        F: FnOnce(&mut Self) -> Result<T, Self::Error>,
+        F: FnOnce(&mut Self) -> T,
     {
         f(self)
     }
-
-    // Failure
-    fn error(&mut self, err: &str) -> Self::Error;
 }
 
 /// Trait for types that can be serialized
@@ -340,7 +341,7 @@ pub trait Encodable<S: Encoder> {
 /// * `TyDecodable` should be used for types that are only serialized in crate
 ///   metadata or the incremental cache. This is most types in `rustc_middle`.
 pub trait Decodable<D: Decoder>: Sized {
-    fn decode(d: &mut D) -> Result<Self, D::Error>;
+    fn decode(d: &mut D) -> Self;
 }
 
 macro_rules! direct_serialize_impls {
@@ -353,7 +354,7 @@ macro_rules! direct_serialize_impls {
             }
 
             impl<D: Decoder> Decodable<D> for $ty {
-                fn decode(d: &mut D) -> Result<$ty, D::Error> {
+                fn decode(d: &mut D) -> $ty {
                     d.$read_method()
                 }
             }
@@ -387,7 +388,7 @@ impl<S: Encoder> Encodable<S> for ! {
 }
 
 impl<D: Decoder> Decodable<D> for ! {
-    fn decode(_d: &mut D) -> Result<!, D::Error> {
+    fn decode(_d: &mut D) -> ! {
         unreachable!()
     }
 }
@@ -399,8 +400,8 @@ impl<S: Encoder> Encodable<S> for ::std::num::NonZeroU32 {
 }
 
 impl<D: Decoder> Decodable<D> for ::std::num::NonZeroU32 {
-    fn decode(d: &mut D) -> Result<Self, D::Error> {
-        d.read_u32().map(|d| ::std::num::NonZeroU32::new(d).unwrap())
+    fn decode(d: &mut D) -> Self {
+        ::std::num::NonZeroU32::new(d.read_u32()).unwrap()
     }
 }
 
@@ -423,8 +424,8 @@ impl<S: Encoder> Encodable<S> for String {
 }
 
 impl<D: Decoder> Decodable<D> for String {
-    fn decode(d: &mut D) -> Result<String, D::Error> {
-        Ok(d.read_str()?.into_owned())
+    fn decode(d: &mut D) -> String {
+        d.read_str().into_owned()
     }
 }
 
@@ -435,8 +436,8 @@ impl<S: Encoder> Encodable<S> for () {
 }
 
 impl<D: Decoder> Decodable<D> for () {
-    fn decode(d: &mut D) -> Result<(), D::Error> {
-        d.read_nil()
+    fn decode(d: &mut D) -> () {
+        d.read_unit()
     }
 }
 
@@ -447,16 +448,16 @@ impl<S: Encoder, T> Encodable<S> for PhantomData<T> {
 }
 
 impl<D: Decoder, T> Decodable<D> for PhantomData<T> {
-    fn decode(d: &mut D) -> Result<PhantomData<T>, D::Error> {
-        d.read_nil()?;
-        Ok(PhantomData)
+    fn decode(d: &mut D) -> PhantomData<T> {
+        d.read_unit();
+        PhantomData
     }
 }
 
 impl<D: Decoder, T: Decodable<D>> Decodable<D> for Box<[T]> {
-    fn decode(d: &mut D) -> Result<Box<[T]>, D::Error> {
-        let v: Vec<T> = Decodable::decode(d)?;
-        Ok(v.into_boxed_slice())
+    fn decode(d: &mut D) -> Box<[T]> {
+        let v: Vec<T> = Decodable::decode(d);
+        v.into_boxed_slice()
     }
 }
 
@@ -467,8 +468,8 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for Rc<T> {
 }
 
 impl<D: Decoder, T: Decodable<D>> Decodable<D> for Rc<T> {
-    fn decode(d: &mut D) -> Result<Rc<T>, D::Error> {
-        Ok(Rc::new(Decodable::decode(d)?))
+    fn decode(d: &mut D) -> Rc<T> {
+        Rc::new(Decodable::decode(d))
     }
 }
 
@@ -491,13 +492,22 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for Vec<T> {
 }
 
 impl<D: Decoder, T: Decodable<D>> Decodable<D> for Vec<T> {
-    default fn decode(d: &mut D) -> Result<Vec<T>, D::Error> {
+    default fn decode(d: &mut D) -> Vec<T> {
         d.read_seq(|d, len| {
-            let mut v = Vec::with_capacity(len);
-            for _ in 0..len {
-                v.push(d.read_seq_elt(|d| Decodable::decode(d))?);
+            // SAFETY: we set the capacity in advance, only write elements, and
+            // only set the length at the end once the writing has succeeded.
+            let mut vec = Vec::with_capacity(len);
+            unsafe {
+                let ptr: *mut T = vec.as_mut_ptr();
+                for i in 0..len {
+                    std::ptr::write(
+                        ptr.offset(i as isize),
+                        d.read_seq_elt(|d| Decodable::decode(d)),
+                    );
+                }
+                vec.set_len(len);
             }
-            Ok(v)
+            vec
         })
     }
 }
@@ -510,14 +520,14 @@ impl<S: Encoder, T: Encodable<S>, const N: usize> Encodable<S> for [T; N] {
 }
 
 impl<D: Decoder, const N: usize> Decodable<D> for [u8; N] {
-    fn decode(d: &mut D) -> Result<[u8; N], D::Error> {
+    fn decode(d: &mut D) -> [u8; N] {
         d.read_seq(|d, len| {
             assert!(len == N);
             let mut v = [0u8; N];
             for i in 0..len {
-                v[i] = d.read_seq_elt(|d| Decodable::decode(d))?;
+                v[i] = d.read_seq_elt(|d| Decodable::decode(d));
             }
-            Ok(v)
+            v
         })
     }
 }
@@ -536,9 +546,9 @@ impl<D: Decoder, T: Decodable<D> + ToOwned> Decodable<D> for Cow<'static, [T]>
 where
     [T]: ToOwned<Owned = Vec<T>>,
 {
-    fn decode(d: &mut D) -> Result<Cow<'static, [T]>, D::Error> {
-        let v: Vec<T> = Decodable::decode(d)?;
-        Ok(Cow::Owned(v))
+    fn decode(d: &mut D) -> Cow<'static, [T]> {
+        let v: Vec<T> = Decodable::decode(d);
+        Cow::Owned(v)
     }
 }
 
@@ -552,8 +562,8 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for Option<T> {
 }
 
 impl<D: Decoder, T: Decodable<D>> Decodable<D> for Option<T> {
-    fn decode(d: &mut D) -> Result<Option<T>, D::Error> {
-        d.read_option(|d, b| if b { Ok(Some(Decodable::decode(d)?)) } else { Ok(None) })
+    fn decode(d: &mut D) -> Option<T> {
+        d.read_option(|d, b| if b { Some(Decodable::decode(d)) } else { None })
     }
 }
 
@@ -571,17 +581,12 @@ impl<S: Encoder, T1: Encodable<S>, T2: Encodable<S>> Encodable<S> for Result<T1,
 }
 
 impl<D: Decoder, T1: Decodable<D>, T2: Decodable<D>> Decodable<D> for Result<T1, T2> {
-    fn decode(d: &mut D) -> Result<Result<T1, T2>, D::Error> {
+    fn decode(d: &mut D) -> Result<T1, T2> {
         d.read_enum(|d| {
             d.read_enum_variant(&["Ok", "Err"], |d, disr| match disr {
-                0 => Ok(Ok(d.read_enum_variant_arg(|d| T1::decode(d))?)),
-                1 => Ok(Err(d.read_enum_variant_arg(|d| T2::decode(d))?)),
-                _ => {
-                    panic!(
-                        "Encountered invalid discriminant while \
-                                decoding `Result`."
-                    );
-                }
+                0 => Ok(d.read_enum_variant_arg(|d| T1::decode(d))),
+                1 => Err(d.read_enum_variant_arg(|d| T2::decode(d))),
+                _ => panic!("Encountered invalid discriminant while decoding `Result`."),
             })
         })
     }
@@ -609,13 +614,13 @@ macro_rules! tuple {
     ( $($name:ident,)+ ) => (
         impl<D: Decoder, $($name: Decodable<D>),+> Decodable<D> for ($($name,)+) {
             #[allow(non_snake_case)]
-            fn decode(d: &mut D) -> Result<($($name,)+), D::Error> {
+            fn decode(d: &mut D) -> ($($name,)+) {
                 let len: usize = count!($($name)+);
                 d.read_tuple(len, |d| {
-                    let ret = ($(d.read_tuple_arg(|d| -> Result<$name, D::Error> {
+                    let ret = ($(d.read_tuple_arg(|d| -> $name {
                         Decodable::decode(d)
-                    })?,)+);
-                    Ok(ret)
+                    }),)+);
+                    ret
                 })
             }
         }
@@ -651,9 +656,9 @@ impl<S: Encoder> Encodable<S> for path::PathBuf {
 }
 
 impl<D: Decoder> Decodable<D> for path::PathBuf {
-    fn decode(d: &mut D) -> Result<path::PathBuf, D::Error> {
-        let bytes: String = Decodable::decode(d)?;
-        Ok(path::PathBuf::from(bytes))
+    fn decode(d: &mut D) -> path::PathBuf {
+        let bytes: String = Decodable::decode(d);
+        path::PathBuf::from(bytes)
     }
 }
 
@@ -664,8 +669,8 @@ impl<S: Encoder, T: Encodable<S> + Copy> Encodable<S> for Cell<T> {
 }
 
 impl<D: Decoder, T: Decodable<D> + Copy> Decodable<D> for Cell<T> {
-    fn decode(d: &mut D) -> Result<Cell<T>, D::Error> {
-        Ok(Cell::new(Decodable::decode(d)?))
+    fn decode(d: &mut D) -> Cell<T> {
+        Cell::new(Decodable::decode(d))
     }
 }
 
@@ -681,8 +686,8 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for RefCell<T> {
 }
 
 impl<D: Decoder, T: Decodable<D>> Decodable<D> for RefCell<T> {
-    fn decode(d: &mut D) -> Result<RefCell<T>, D::Error> {
-        Ok(RefCell::new(Decodable::decode(d)?))
+    fn decode(d: &mut D) -> RefCell<T> {
+        RefCell::new(Decodable::decode(d))
     }
 }
 
@@ -693,8 +698,8 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for Arc<T> {
 }
 
 impl<D: Decoder, T: Decodable<D>> Decodable<D> for Arc<T> {
-    fn decode(d: &mut D) -> Result<Arc<T>, D::Error> {
-        Ok(Arc::new(Decodable::decode(d)?))
+    fn decode(d: &mut D) -> Arc<T> {
+        Arc::new(Decodable::decode(d))
     }
 }
 
@@ -704,7 +709,7 @@ impl<S: Encoder, T: ?Sized + Encodable<S>> Encodable<S> for Box<T> {
     }
 }
 impl<D: Decoder, T: Decodable<D>> Decodable<D> for Box<T> {
-    fn decode(d: &mut D) -> Result<Box<T>, D::Error> {
-        Ok(Box::new(Decodable::decode(d)?))
+    fn decode(d: &mut D) -> Box<T> {
+        Box::new(Decodable::decode(d))
     }
 }
diff --git a/compiler/rustc_serialize/tests/json.rs b/compiler/rustc_serialize/tests/json.rs
index a759fa1bf1a..ede912bdfb6 100644
--- a/compiler/rustc_serialize/tests/json.rs
+++ b/compiler/rustc_serialize/tests/json.rs
@@ -1,14 +1,10 @@
 #![allow(rustc::internal)]
 
-use json::DecoderError::*;
 use json::ErrorCode::*;
 use json::Json::*;
 use json::JsonEvent::*;
 use json::ParserError::*;
-use json::{
-    from_str, DecodeResult, Decoder, DecoderError, Encoder, EncoderError, Json, JsonEvent, Parser,
-    StackElement,
-};
+use json::{from_str, Decoder, Encoder, EncoderError, Json, JsonEvent, Parser, StackElement};
 use rustc_macros::{Decodable, Encodable};
 use rustc_serialize::json;
 use rustc_serialize::{Decodable, Encodable};
@@ -26,27 +22,27 @@ struct OptionData {
 #[test]
 fn test_decode_option_none() {
     let s = "{}";
-    let obj: OptionData = json::decode(s).unwrap();
+    let obj: OptionData = json::decode(s);
     assert_eq!(obj, OptionData { opt: None });
 }
 
 #[test]
 fn test_decode_option_some() {
     let s = "{ \"opt\": 10 }";
-    let obj: OptionData = json::decode(s).unwrap();
+    let obj: OptionData = json::decode(s);
     assert_eq!(obj, OptionData { opt: Some(10) });
 }
 
 #[test]
-fn test_decode_option_malformed() {
-    check_err::<OptionData>(
-        "{ \"opt\": [] }",
-        ExpectedError("Number".to_string(), "[]".to_string()),
-    );
-    check_err::<OptionData>(
-        "{ \"opt\": false }",
-        ExpectedError("Number".to_string(), "false".to_string()),
-    );
+#[should_panic(expected = r#"ExpectedError("Number", "[]")"#)]
+fn test_decode_option_malformed1() {
+    check_err::<OptionData>(r#"{ "opt": [] }"#);
+}
+
+#[test]
+#[should_panic(expected = r#"ExpectedError("Number", "false")"#)]
+fn test_decode_option_malformed2() {
+    check_err::<OptionData>(r#"{ "opt": false }"#);
 }
 
 #[derive(PartialEq, Encodable, Decodable, Debug)]
@@ -329,13 +325,13 @@ fn test_read_identifiers() {
 
 #[test]
 fn test_decode_identifiers() {
-    let v: () = json::decode("null").unwrap();
+    let v: () = json::decode("null");
     assert_eq!(v, ());
 
-    let v: bool = json::decode("true").unwrap();
+    let v: bool = json::decode("true");
     assert_eq!(v, true);
 
-    let v: bool = json::decode("false").unwrap();
+    let v: bool = json::decode("false");
     assert_eq!(v, false);
 }
 
@@ -368,42 +364,42 @@ fn test_read_number() {
 }
 
 #[test]
+#[should_panic(expected = r#"ExpectedError("Integer", "765.25")"#)]
 fn test_decode_numbers() {
-    let v: f64 = json::decode("3").unwrap();
+    let v: f64 = json::decode("3");
     assert_eq!(v, 3.0);
 
-    let v: f64 = json::decode("3.1").unwrap();
+    let v: f64 = json::decode("3.1");
     assert_eq!(v, 3.1);
 
-    let v: f64 = json::decode("-1.2").unwrap();
+    let v: f64 = json::decode("-1.2");
     assert_eq!(v, -1.2);
 
-    let v: f64 = json::decode("0.4").unwrap();
+    let v: f64 = json::decode("0.4");
     assert_eq!(v, 0.4);
 
-    let v: f64 = json::decode("0.4e5").unwrap();
+    let v: f64 = json::decode("0.4e5");
     assert_eq!(v, 0.4e5);
 
-    let v: f64 = json::decode("0.4e15").unwrap();
+    let v: f64 = json::decode("0.4e15");
     assert_eq!(v, 0.4e15);
 
-    let v: f64 = json::decode("0.4e-01").unwrap();
+    let v: f64 = json::decode("0.4e-01");
     assert_eq!(v, 0.4e-01);
 
-    let v: u64 = json::decode("0").unwrap();
+    let v: u64 = json::decode("0");
     assert_eq!(v, 0);
 
-    let v: u64 = json::decode("18446744073709551615").unwrap();
+    let v: u64 = json::decode("18446744073709551615");
     assert_eq!(v, u64::MAX);
 
-    let v: i64 = json::decode("-9223372036854775808").unwrap();
+    let v: i64 = json::decode("-9223372036854775808");
     assert_eq!(v, i64::MIN);
 
-    let v: i64 = json::decode("9223372036854775807").unwrap();
+    let v: i64 = json::decode("9223372036854775807");
     assert_eq!(v, i64::MAX);
 
-    let res: DecodeResult<i64> = json::decode("765.25");
-    assert_eq!(res, Err(ExpectedError("Integer".to_string(), "765.25".to_string())));
+    json::decode::<i64>("765.25");
 }
 
 #[test]
@@ -438,7 +434,7 @@ fn test_decode_str() {
     ];
 
     for (i, o) in s {
-        let v: string::String = json::decode(i).unwrap();
+        let v: string::String = json::decode(i);
         assert_eq!(v, o);
     }
 }
@@ -463,39 +459,41 @@ fn test_read_array() {
 
 #[test]
 fn test_decode_array() {
-    let v: Vec<()> = json::decode("[]").unwrap();
+    let v: Vec<()> = json::decode("[]");
     assert_eq!(v, []);
 
-    let v: Vec<()> = json::decode("[null]").unwrap();
+    let v: Vec<()> = json::decode("[null]");
     assert_eq!(v, [()]);
 
-    let v: Vec<bool> = json::decode("[true]").unwrap();
+    let v: Vec<bool> = json::decode("[true]");
     assert_eq!(v, [true]);
 
-    let v: Vec<isize> = json::decode("[3, 1]").unwrap();
+    let v: Vec<isize> = json::decode("[3, 1]");
     assert_eq!(v, [3, 1]);
 
-    let v: Vec<Vec<usize>> = json::decode("[[3], [1, 2]]").unwrap();
+    let v: Vec<Vec<usize>> = json::decode("[[3], [1, 2]]");
     assert_eq!(v, [vec![3], vec![1, 2]]);
 }
 
 #[test]
 fn test_decode_tuple() {
-    let t: (usize, usize, usize) = json::decode("[1, 2, 3]").unwrap();
+    let t: (usize, usize, usize) = json::decode("[1, 2, 3]");
     assert_eq!(t, (1, 2, 3));
 
-    let t: (usize, string::String) = json::decode("[1, \"two\"]").unwrap();
+    let t: (usize, string::String) = json::decode("[1, \"two\"]");
     assert_eq!(t, (1, "two".to_string()));
 }
 
 #[test]
+#[should_panic]
 fn test_decode_tuple_malformed_types() {
-    assert!(json::decode::<(usize, string::String)>("[1, 2]").is_err());
+    json::decode::<(usize, string::String)>("[1, 2]");
 }
 
 #[test]
+#[should_panic]
 fn test_decode_tuple_malformed_length() {
-    assert!(json::decode::<(usize, usize)>("[1, 2, 3]").is_err());
+    json::decode::<(usize, usize)>("[1, 2, 3]");
 }
 
 #[test]
@@ -562,7 +560,7 @@ fn test_decode_struct() {
         ]
     }";
 
-    let v: Outer = json::decode(s).unwrap();
+    let v: Outer = json::decode(s);
     assert_eq!(
         v,
         Outer { inner: vec![Inner { a: (), b: 2, c: vec!["abc".to_string(), "xyz".to_string()] }] }
@@ -577,7 +575,7 @@ struct FloatStruct {
 #[test]
 fn test_decode_struct_with_nan() {
     let s = "{\"f\":null,\"a\":[null,123]}";
-    let obj: FloatStruct = json::decode(s).unwrap();
+    let obj: FloatStruct = json::decode(s);
     assert!(obj.f.is_nan());
     assert!(obj.a[0].is_nan());
     assert_eq!(obj.a[1], 123f64);
@@ -585,20 +583,20 @@ fn test_decode_struct_with_nan() {
 
 #[test]
 fn test_decode_option() {
-    let value: Option<string::String> = json::decode("null").unwrap();
+    let value: Option<string::String> = json::decode("null");
     assert_eq!(value, None);
 
-    let value: Option<string::String> = json::decode("\"jodhpurs\"").unwrap();
+    let value: Option<string::String> = json::decode("\"jodhpurs\"");
     assert_eq!(value, Some("jodhpurs".to_string()));
 }
 
 #[test]
 fn test_decode_enum() {
-    let value: Animal = json::decode("\"Dog\"").unwrap();
+    let value: Animal = json::decode("\"Dog\"");
     assert_eq!(value, Dog);
 
     let s = "{\"variant\":\"Frog\",\"fields\":[\"Henry\",349]}";
-    let value: Animal = json::decode(s).unwrap();
+    let value: Animal = json::decode(s);
     assert_eq!(value, Frog("Henry".to_string(), 349));
 }
 
@@ -606,7 +604,7 @@ fn test_decode_enum() {
 fn test_decode_map() {
     let s = "{\"a\": \"Dog\", \"b\": {\"variant\":\"Frog\",\
               \"fields\":[\"Henry\", 349]}}";
-    let mut map: BTreeMap<string::String, Animal> = json::decode(s).unwrap();
+    let mut map: BTreeMap<string::String, Animal> = json::decode(s);
 
     assert_eq!(map.remove(&"a".to_string()), Some(Dog));
     assert_eq!(map.remove(&"b".to_string()), Some(Frog("Henry".to_string(), 349)));
@@ -630,59 +628,65 @@ enum DecodeEnum {
     A(f64),
     B(string::String),
 }
-fn check_err<T: Decodable<Decoder>>(to_parse: &'static str, expected: DecoderError) {
-    let res: DecodeResult<T> = match from_str(to_parse) {
-        Err(e) => Err(ParseError(e)),
-        Ok(json) => Decodable::decode(&mut Decoder::new(json)),
-    };
-    match res {
-        Ok(_) => panic!("`{:?}` parsed & decoded ok, expecting error `{:?}`", to_parse, expected),
-        Err(ParseError(e)) => panic!("`{:?}` is not valid json: {:?}", to_parse, e),
-        Err(e) => {
-            assert_eq!(e, expected);
-        }
-    }
+fn check_err<T: Decodable<Decoder>>(to_parse: &str) {
+    let json = from_str(to_parse).unwrap();
+    let _: T = Decodable::decode(&mut Decoder::new(json));
 }
 #[test]
-fn test_decode_errors_struct() {
-    check_err::<DecodeStruct>("[]", ExpectedError("Object".to_string(), "[]".to_string()));
-    check_err::<DecodeStruct>(
-        "{\"x\": true, \"y\": true, \"z\": \"\", \"w\": []}",
-        ExpectedError("Number".to_string(), "true".to_string()),
-    );
-    check_err::<DecodeStruct>(
-        "{\"x\": 1, \"y\": [], \"z\": \"\", \"w\": []}",
-        ExpectedError("Boolean".to_string(), "[]".to_string()),
-    );
-    check_err::<DecodeStruct>(
-        "{\"x\": 1, \"y\": true, \"z\": {}, \"w\": []}",
-        ExpectedError("String".to_string(), "{}".to_string()),
-    );
-    check_err::<DecodeStruct>(
-        "{\"x\": 1, \"y\": true, \"z\": \"\", \"w\": null}",
-        ExpectedError("Array".to_string(), "null".to_string()),
-    );
-    check_err::<DecodeStruct>(
-        "{\"x\": 1, \"y\": true, \"z\": \"\"}",
-        MissingFieldError("w".to_string()),
-    );
+#[should_panic(expected = r#"ExpectedError("Object", "[]")"#)]
+fn test_decode_errors_struct1() {
+    check_err::<DecodeStruct>("[]");
 }
 #[test]
-fn test_decode_errors_enum() {
-    check_err::<DecodeEnum>("{}", MissingFieldError("variant".to_string()));
-    check_err::<DecodeEnum>(
-        "{\"variant\": 1}",
-        ExpectedError("String".to_string(), "1".to_string()),
-    );
-    check_err::<DecodeEnum>("{\"variant\": \"A\"}", MissingFieldError("fields".to_string()));
-    check_err::<DecodeEnum>(
-        "{\"variant\": \"A\", \"fields\": null}",
-        ExpectedError("Array".to_string(), "null".to_string()),
-    );
-    check_err::<DecodeEnum>(
-        "{\"variant\": \"C\", \"fields\": []}",
-        UnknownVariantError("C".to_string()),
-    );
+#[should_panic(expected = r#"ExpectedError("Number", "true")"#)]
+fn test_decode_errors_struct2() {
+    check_err::<DecodeStruct>(r#"{"x": true, "y": true, "z": "", "w": []}"#);
+}
+#[test]
+#[should_panic(expected = r#"ExpectedError("Boolean", "[]")"#)]
+fn test_decode_errors_struct3() {
+    check_err::<DecodeStruct>(r#"{"x": 1, "y": [], "z": "", "w": []}"#);
+}
+#[test]
+#[should_panic(expected = r#"ExpectedError("String", "{}")"#)]
+fn test_decode_errors_struct4() {
+    check_err::<DecodeStruct>(r#"{"x": 1, "y": true, "z": {}, "w": []}"#);
+}
+#[test]
+#[should_panic(expected = r#"ExpectedError("Array", "null")"#)]
+fn test_decode_errors_struct5() {
+    check_err::<DecodeStruct>(r#"{"x": 1, "y": true, "z": "", "w": null}"#);
+}
+#[test]
+#[should_panic(expected = r#"ExpectedError("Array", "null")"#)]
+fn test_decode_errors_struct6() {
+    check_err::<DecodeStruct>(r#"{"x": 1, "y": true, "z": ""}"#);
+}
+
+#[test]
+#[should_panic(expected = r#"MissingFieldError("variant")"#)]
+fn test_decode_errors_enum1() {
+    check_err::<DecodeEnum>(r#"{}"#);
+}
+#[test]
+#[should_panic(expected = r#"ExpectedError("String", "1")"#)]
+fn test_decode_errors_enum2() {
+    check_err::<DecodeEnum>(r#"{"variant": 1}"#);
+}
+#[test]
+#[should_panic(expected = r#"MissingFieldError("fields")"#)]
+fn test_decode_errors_enum3() {
+    check_err::<DecodeEnum>(r#"{"variant": "A"}"#);
+}
+#[test]
+#[should_panic(expected = r#"ExpectedError("Array", "null")"#)]
+fn test_decode_errors_enum4() {
+    check_err::<DecodeEnum>(r#"{"variant": "A", "fields": null}"#);
+}
+#[test]
+#[should_panic(expected = r#"UnknownVariantError("C")"#)]
+fn test_decode_errors_enum5() {
+    check_err::<DecodeEnum>(r#"{"variant": "C", "fields": []}"#);
 }
 
 #[test]
@@ -944,7 +948,7 @@ fn test_hashmap_with_enum_key() {
     map.insert(Enum::Foo, 0);
     let result = json::encode(&map).unwrap();
     assert_eq!(&result[..], r#"{"Foo":0}"#);
-    let decoded: HashMap<Enum, _> = json::decode(&result).unwrap();
+    let decoded: HashMap<Enum, _> = json::decode(&result);
     assert_eq!(map, decoded);
 }
 
@@ -957,10 +961,11 @@ fn test_hashmap_with_numeric_key_can_handle_double_quote_delimited_key() {
         Ok(o) => o,
     };
     let mut decoder = Decoder::new(json_obj);
-    let _hm: HashMap<usize, bool> = Decodable::decode(&mut decoder).unwrap();
+    let _hm: HashMap<usize, bool> = Decodable::decode(&mut decoder);
 }
 
 #[test]
+#[should_panic(expected = r#"ExpectedError("Number", "a")"#)]
 fn test_hashmap_with_numeric_key_will_error_with_string_keys() {
     use std::collections::HashMap;
     let json_str = "{\"a\":true}";
@@ -969,8 +974,7 @@ fn test_hashmap_with_numeric_key_will_error_with_string_keys() {
         Ok(o) => o,
     };
     let mut decoder = Decoder::new(json_obj);
-    let result: Result<HashMap<usize, bool>, DecoderError> = Decodable::decode(&mut decoder);
-    assert_eq!(result, Err(ExpectedError("Number".to_string(), "a".to_string())));
+    let _: HashMap<usize, bool> = Decodable::decode(&mut decoder);
 }
 
 fn assert_stream_equal(src: &str, expected: Vec<(JsonEvent, Vec<StackElement<'_>>)>) {
diff --git a/compiler/rustc_serialize/tests/opaque.rs b/compiler/rustc_serialize/tests/opaque.rs
index 13b3676a56c..298eb115111 100644
--- a/compiler/rustc_serialize/tests/opaque.rs
+++ b/compiler/rustc_serialize/tests/opaque.rs
@@ -41,7 +41,7 @@ fn check_round_trip<T: Encodable<Encoder> + for<'a> Decodable<Decoder<'a>> + Par
     let mut decoder = Decoder::new(&data[..], 0);
 
     for value in values {
-        let decoded = Decodable::decode(&mut decoder).unwrap();
+        let decoded = Decodable::decode(&mut decoder);
         assert_eq!(value, decoded);
     }
 }
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 92ad0723f48..a756de4c0fc 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -12,7 +12,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::impl_stable_hash_via_hash;
 
 use rustc_target::abi::{Align, TargetDataLayout};
-use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple, TargetWarnings};
+use rustc_target::spec::{LinkerFlavor, SplitDebuginfo, Target, TargetTriple, TargetWarnings};
 
 use rustc_serialize::json;
 
@@ -2237,6 +2237,16 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
         }
     }
 
+    if cg.linker_flavor == Some(LinkerFlavor::L4Bender)
+        && !nightly_options::is_unstable_enabled(matches)
+    {
+        early_error(
+            error_format,
+            "`l4-bender` linker flavor is unstable, `-Z unstable-options` \
+             flag must also be passed to explicitly use it",
+        );
+    }
+
     let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
 
     let cg = cg;
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 730e79a5647..9bcdd7f3da6 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -476,10 +476,6 @@ impl Session {
         &self.parse_sess.span_diagnostic
     }
 
-    pub fn with_disabled_diagnostic<T, F: FnOnce() -> T>(&self, f: F) -> T {
-        self.parse_sess.span_diagnostic.with_disabled_diagnostic(f)
-    }
-
     /// Analogous to calling methods on the given `DiagnosticBuilder`, but
     /// deduplicates on lint ID, span (if any), and message for this `Session`
     fn diag_once<'a, 'b>(
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index 5390eed89fa..147c1f9e043 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -47,8 +47,8 @@ impl<E: Encoder> Encodable<E> for CrateNum {
 }
 
 impl<D: Decoder> Decodable<D> for CrateNum {
-    default fn decode(d: &mut D) -> Result<CrateNum, D::Error> {
-        Ok(CrateNum::from_u32(d.read_u32()?))
+    default fn decode(d: &mut D) -> CrateNum {
+        CrateNum::from_u32(d.read_u32())
     }
 }
 
@@ -209,7 +209,7 @@ impl<E: Encoder> Encodable<E> for DefIndex {
 }
 
 impl<D: Decoder> Decodable<D> for DefIndex {
-    default fn decode(_: &mut D) -> Result<DefIndex, D::Error> {
+    default fn decode(_: &mut D) -> DefIndex {
         panic!("cannot decode `DefIndex` with `{}`", std::any::type_name::<D>());
     }
 }
@@ -298,12 +298,10 @@ impl<E: Encoder> Encodable<E> for DefId {
 }
 
 impl<D: Decoder> Decodable<D> for DefId {
-    default fn decode(d: &mut D) -> Result<DefId, D::Error> {
-        d.read_struct(|d| {
-            Ok(DefId {
-                krate: d.read_struct_field("krate", Decodable::decode)?,
-                index: d.read_struct_field("index", Decodable::decode)?,
-            })
+    default fn decode(d: &mut D) -> DefId {
+        d.read_struct(|d| DefId {
+            krate: d.read_struct_field("krate", Decodable::decode),
+            index: d.read_struct_field("index", Decodable::decode),
         })
     }
 }
@@ -378,8 +376,8 @@ impl<E: Encoder> Encodable<E> for LocalDefId {
 }
 
 impl<D: Decoder> Decodable<D> for LocalDefId {
-    fn decode(d: &mut D) -> Result<LocalDefId, D::Error> {
-        DefId::decode(d).map(|d| d.expect_local())
+    fn decode(d: &mut D) -> LocalDefId {
+        DefId::decode(d).expect_local()
     }
 }
 
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 7b70c20d307..e0d6bd8cb7b 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -1314,19 +1314,16 @@ pub fn decode_expn_id(
 // to track which `SyntaxContext`s we have already decoded.
 // The provided closure will be invoked to deserialize a `SyntaxContextData`
 // if we haven't already seen the id of the `SyntaxContext` we are deserializing.
-pub fn decode_syntax_context<
-    D: Decoder,
-    F: FnOnce(&mut D, u32) -> Result<SyntaxContextData, D::Error>,
->(
+pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContextData>(
     d: &mut D,
     context: &HygieneDecodeContext,
     decode_data: F,
-) -> Result<SyntaxContext, D::Error> {
-    let raw_id: u32 = Decodable::decode(d)?;
+) -> SyntaxContext {
+    let raw_id: u32 = Decodable::decode(d);
     if raw_id == 0 {
         debug!("decode_syntax_context: deserialized root");
         // The root is special
-        return Ok(SyntaxContext::root());
+        return SyntaxContext::root();
     }
 
     let outer_ctxts = &context.remapped_ctxts;
@@ -1334,7 +1331,7 @@ pub fn decode_syntax_context<
     // Ensure that the lock() temporary is dropped early
     {
         if let Some(ctxt) = outer_ctxts.lock().get(raw_id as usize).copied().flatten() {
-            return Ok(ctxt);
+            return ctxt;
         }
     }
 
@@ -1364,7 +1361,7 @@ pub fn decode_syntax_context<
 
     // Don't try to decode data while holding the lock, since we need to
     // be able to recursively decode a SyntaxContext
-    let mut ctxt_data = decode_data(d, raw_id)?;
+    let mut ctxt_data = decode_data(d, raw_id);
     // Reset `dollar_crate_name` so that it will be updated by `update_dollar_crate_names`
     // We don't care what the encoding crate set this to - we want to resolve it
     // from the perspective of the current compilation session
@@ -1380,7 +1377,7 @@ pub fn decode_syntax_context<
         assert_eq!(dummy.dollar_crate_name, kw::Empty);
     });
 
-    Ok(new_ctxt)
+    new_ctxt
 }
 
 fn for_all_ctxts_in<E, F: FnMut(u32, SyntaxContext, &SyntaxContextData) -> Result<(), E>>(
@@ -1422,13 +1419,13 @@ impl<E: Encoder> Encodable<E> for ExpnId {
 }
 
 impl<D: Decoder> Decodable<D> for LocalExpnId {
-    fn decode(d: &mut D) -> Result<Self, D::Error> {
-        ExpnId::decode(d).map(ExpnId::expect_local)
+    fn decode(d: &mut D) -> Self {
+        ExpnId::expect_local(ExpnId::decode(d))
     }
 }
 
 impl<D: Decoder> Decodable<D> for ExpnId {
-    default fn decode(_: &mut D) -> Result<Self, D::Error> {
+    default fn decode(_: &mut D) -> Self {
         panic!("cannot decode `ExpnId` with `{}`", std::any::type_name::<D>());
     }
 }
@@ -1451,7 +1448,7 @@ impl<E: Encoder> Encodable<E> for SyntaxContext {
 }
 
 impl<D: Decoder> Decodable<D> for SyntaxContext {
-    default fn decode(_: &mut D) -> Result<Self, D::Error> {
+    default fn decode(_: &mut D) -> Self {
         panic!("cannot decode `SyntaxContext` with `{}`", std::any::type_name::<D>());
     }
 }
diff --git a/compiler/rustc_span/src/lev_distance.rs b/compiler/rustc_span/src/lev_distance.rs
index aed699e4839..93cf965f105 100644
--- a/compiler/rustc_span/src/lev_distance.rs
+++ b/compiler/rustc_span/src/lev_distance.rs
@@ -11,16 +11,21 @@ use std::cmp;
 mod tests;
 
 /// Finds the Levenshtein distance between two strings.
-pub fn lev_distance(a: &str, b: &str) -> usize {
-    // cases which don't require further computation
-    if a.is_empty() {
-        return b.chars().count();
-    } else if b.is_empty() {
-        return a.chars().count();
+///
+/// Returns None if the distance exceeds the limit.
+pub fn lev_distance(a: &str, b: &str, limit: usize) -> Option<usize> {
+    let n = a.chars().count();
+    let m = b.chars().count();
+    let min_dist = if n < m { m - n } else { n - m };
+
+    if min_dist > limit {
+        return None;
+    }
+    if n == 0 || m == 0 {
+        return (min_dist <= limit).then_some(min_dist);
     }
 
-    let mut dcol: Vec<_> = (0..=b.len()).collect();
-    let mut t_last = 0;
+    let mut dcol: Vec<_> = (0..=m).collect();
 
     for (i, sc) in a.chars().enumerate() {
         let mut current = i;
@@ -35,10 +40,10 @@ pub fn lev_distance(a: &str, b: &str) -> usize {
                 dcol[j + 1] = cmp::min(dcol[j + 1], dcol[j]) + 1;
             }
             current = next;
-            t_last = j;
         }
     }
-    dcol[t_last + 1]
+
+    (dcol[m] <= limit).then_some(dcol[m])
 }
 
 /// Finds the best match for a given word in the given iterator.
@@ -51,39 +56,38 @@ pub fn lev_distance(a: &str, b: &str) -> usize {
 /// on an edge case with a lower(upper)case letters mismatch.
 #[cold]
 pub fn find_best_match_for_name(
-    name_vec: &[Symbol],
+    candidates: &[Symbol],
     lookup: Symbol,
     dist: Option<usize>,
 ) -> Option<Symbol> {
     let lookup = lookup.as_str();
-    let max_dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3);
+    let lookup_uppercase = lookup.to_uppercase();
 
     // Priority of matches:
     // 1. Exact case insensitive match
     // 2. Levenshtein distance match
     // 3. Sorted word match
-    if let Some(case_insensitive_match) =
-        name_vec.iter().find(|candidate| candidate.as_str().to_uppercase() == lookup.to_uppercase())
-    {
-        return Some(*case_insensitive_match);
+    if let Some(c) = candidates.iter().find(|c| c.as_str().to_uppercase() == lookup_uppercase) {
+        return Some(*c);
     }
-    let levenshtein_match = name_vec
-        .iter()
-        .filter_map(|&name| {
-            let dist = lev_distance(lookup, name.as_str());
-            if dist <= max_dist { Some((name, dist)) } else { None }
-        })
-        // Here we are collecting the next structure:
-        // (levenshtein_match, levenshtein_distance)
-        .fold(None, |result, (candidate, dist)| match result {
-            None => Some((candidate, dist)),
-            Some((c, d)) => Some(if dist < d { (candidate, dist) } else { (c, d) }),
-        });
-    if levenshtein_match.is_some() {
-        levenshtein_match.map(|(candidate, _)| candidate)
-    } else {
-        find_match_by_sorted_words(name_vec, lookup)
+
+    let mut dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3);
+    let mut best = None;
+    for c in candidates {
+        match lev_distance(lookup, c.as_str(), dist) {
+            Some(0) => return Some(*c),
+            Some(d) => {
+                dist = d - 1;
+                best = Some(*c);
+            }
+            None => {}
+        }
     }
+    if best.is_some() {
+        return best;
+    }
+
+    find_match_by_sorted_words(candidates, lookup)
 }
 
 fn find_match_by_sorted_words(iter_names: &[Symbol], lookup: &str) -> Option<Symbol> {
diff --git a/compiler/rustc_span/src/lev_distance/tests.rs b/compiler/rustc_span/src/lev_distance/tests.rs
index b32f8d32c13..4e34219248d 100644
--- a/compiler/rustc_span/src/lev_distance/tests.rs
+++ b/compiler/rustc_span/src/lev_distance/tests.rs
@@ -5,18 +5,26 @@ fn test_lev_distance() {
     use std::char::{from_u32, MAX};
     // Test bytelength agnosticity
     for c in (0..MAX as u32).filter_map(from_u32).map(|i| i.to_string()) {
-        assert_eq!(lev_distance(&c[..], &c[..]), 0);
+        assert_eq!(lev_distance(&c[..], &c[..], usize::MAX), Some(0));
     }
 
     let a = "\nMäry häd ä little lämb\n\nLittle lämb\n";
     let b = "\nMary häd ä little lämb\n\nLittle lämb\n";
     let c = "Mary häd ä little lämb\n\nLittle lämb\n";
-    assert_eq!(lev_distance(a, b), 1);
-    assert_eq!(lev_distance(b, a), 1);
-    assert_eq!(lev_distance(a, c), 2);
-    assert_eq!(lev_distance(c, a), 2);
-    assert_eq!(lev_distance(b, c), 1);
-    assert_eq!(lev_distance(c, b), 1);
+    assert_eq!(lev_distance(a, b, usize::MAX), Some(1));
+    assert_eq!(lev_distance(b, a, usize::MAX), Some(1));
+    assert_eq!(lev_distance(a, c, usize::MAX), Some(2));
+    assert_eq!(lev_distance(c, a, usize::MAX), Some(2));
+    assert_eq!(lev_distance(b, c, usize::MAX), Some(1));
+    assert_eq!(lev_distance(c, b, usize::MAX), Some(1));
+}
+
+#[test]
+fn test_lev_distance_limit() {
+    assert_eq!(lev_distance("abc", "abcd", 1), Some(1));
+    assert_eq!(lev_distance("abc", "abcd", 0), None);
+    assert_eq!(lev_distance("abc", "xyz", 3), Some(3));
+    assert_eq!(lev_distance("abc", "xyz", 2), None);
 }
 
 #[test]
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 9602bc5d0b7..2c3db35bb66 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -15,6 +15,7 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(array_windows)]
+#![feature(bool_to_option)]
 #![feature(crate_visibility_modifier)]
 #![feature(if_let_guard)]
 #![feature(negative_impls)]
@@ -611,7 +612,7 @@ impl Span {
 
     #[inline]
     /// Returns `true` if `hi == lo`.
-    pub fn is_empty(&self) -> bool {
+    pub fn is_empty(self) -> bool {
         let span = self.data_untracked();
         span.hi == span.lo
     }
@@ -639,7 +640,7 @@ impl Span {
     ///
     /// Use this instead of `==` when either span could be generated code,
     /// and you only care that they point to the same bytes of source text.
-    pub fn source_equal(&self, other: &Span) -> bool {
+    pub fn source_equal(self, other: Span) -> bool {
         let span = self.data();
         let other = other.data();
         span.lo == other.lo && span.hi == other.hi
@@ -680,17 +681,17 @@ impl Span {
     }
 
     #[inline]
-    pub fn rust_2015(&self) -> bool {
+    pub fn rust_2015(self) -> bool {
         self.edition() == edition::Edition::Edition2015
     }
 
     #[inline]
-    pub fn rust_2018(&self) -> bool {
+    pub fn rust_2018(self) -> bool {
         self.edition() >= edition::Edition::Edition2018
     }
 
     #[inline]
-    pub fn rust_2021(&self) -> bool {
+    pub fn rust_2021(self) -> bool {
         self.edition() >= edition::Edition::Edition2021
     }
 
@@ -711,7 +712,7 @@ impl Span {
     /// Checks if a span is "internal" to a macro in which `#[unstable]`
     /// items can be used (that is, a macro marked with
     /// `#[allow_internal_unstable]`).
-    pub fn allows_unstable(&self, feature: Symbol) -> bool {
+    pub fn allows_unstable(self, feature: Symbol) -> bool {
         self.ctxt()
             .outer_expn_data()
             .allow_internal_unstable
@@ -719,7 +720,7 @@ impl Span {
     }
 
     /// Checks if this span arises from a compiler desugaring of kind `kind`.
-    pub fn is_desugaring(&self, kind: DesugaringKind) -> bool {
+    pub fn is_desugaring(self, kind: DesugaringKind) -> bool {
         match self.ctxt().outer_expn_data().kind {
             ExpnKind::Desugaring(k) => k == kind,
             _ => false,
@@ -728,7 +729,7 @@ impl Span {
 
     /// Returns the compiler desugaring that created this span, or `None`
     /// if this span is not from a desugaring.
-    pub fn desugaring_kind(&self) -> Option<DesugaringKind> {
+    pub fn desugaring_kind(self) -> Option<DesugaringKind> {
         match self.ctxt().outer_expn_data().kind {
             ExpnKind::Desugaring(k) => Some(k),
             _ => None,
@@ -738,7 +739,7 @@ impl Span {
     /// Checks if a span is "internal" to a macro in which `unsafe`
     /// can be used without triggering the `unsafe_code` lint.
     //  (that is, a macro marked with `#[allow_internal_unsafe]`).
-    pub fn allows_unsafe(&self) -> bool {
+    pub fn allows_unsafe(self) -> bool {
         self.ctxt().outer_expn_data().allow_internal_unsafe
     }
 
@@ -751,7 +752,7 @@ impl Span {
                     return None;
                 }
 
-                let is_recursive = expn_data.call_site.source_equal(&prev_span);
+                let is_recursive = expn_data.call_site.source_equal(prev_span);
 
                 prev_span = self;
                 self = expn_data.call_site;
@@ -865,13 +866,13 @@ impl Span {
 
     /// Equivalent of `Span::call_site` from the proc macro API,
     /// except that the location is taken from the `self` span.
-    pub fn with_call_site_ctxt(&self, expn_id: ExpnId) -> Span {
+    pub fn with_call_site_ctxt(self, expn_id: ExpnId) -> Span {
         self.with_ctxt_from_mark(expn_id, Transparency::Transparent)
     }
 
     /// Equivalent of `Span::mixed_site` from the proc macro API,
     /// except that the location is taken from the `self` span.
-    pub fn with_mixed_site_ctxt(&self, expn_id: ExpnId) -> Span {
+    pub fn with_mixed_site_ctxt(self, expn_id: ExpnId) -> Span {
         self.with_ctxt_from_mark(expn_id, Transparency::SemiTransparent)
     }
 
@@ -975,12 +976,12 @@ impl<E: Encoder> Encodable<E> for Span {
     }
 }
 impl<D: Decoder> Decodable<D> for Span {
-    default fn decode(s: &mut D) -> Result<Span, D::Error> {
+    default fn decode(s: &mut D) -> Span {
         s.read_struct(|d| {
-            let lo = d.read_struct_field("lo", Decodable::decode)?;
-            let hi = d.read_struct_field("hi", Decodable::decode)?;
+            let lo = d.read_struct_field("lo", Decodable::decode);
+            let hi = d.read_struct_field("hi", Decodable::decode);
 
-            Ok(Span::new(lo, hi, SyntaxContext::root(), None))
+            Span::new(lo, hi, SyntaxContext::root(), None)
         })
     }
 }
@@ -1448,30 +1449,30 @@ impl<S: Encoder> Encodable<S> for SourceFile {
 }
 
 impl<D: Decoder> Decodable<D> for SourceFile {
-    fn decode(d: &mut D) -> Result<SourceFile, D::Error> {
+    fn decode(d: &mut D) -> SourceFile {
         d.read_struct(|d| {
-            let name: FileName = d.read_struct_field("name", |d| Decodable::decode(d))?;
+            let name: FileName = d.read_struct_field("name", |d| Decodable::decode(d));
             let src_hash: SourceFileHash =
-                d.read_struct_field("src_hash", |d| Decodable::decode(d))?;
-            let start_pos: BytePos = d.read_struct_field("start_pos", |d| Decodable::decode(d))?;
-            let end_pos: BytePos = d.read_struct_field("end_pos", |d| Decodable::decode(d))?;
+                d.read_struct_field("src_hash", |d| Decodable::decode(d));
+            let start_pos: BytePos = d.read_struct_field("start_pos", |d| Decodable::decode(d));
+            let end_pos: BytePos = d.read_struct_field("end_pos", |d| Decodable::decode(d));
             let lines: Vec<BytePos> = d.read_struct_field("lines", |d| {
-                let num_lines: u32 = Decodable::decode(d)?;
+                let num_lines: u32 = Decodable::decode(d);
                 let mut lines = Vec::with_capacity(num_lines as usize);
 
                 if num_lines > 0 {
                     // Read the number of bytes used per diff.
-                    let bytes_per_diff: u8 = Decodable::decode(d)?;
+                    let bytes_per_diff: u8 = Decodable::decode(d);
 
                     // Read the first element.
-                    let mut line_start: BytePos = Decodable::decode(d)?;
+                    let mut line_start: BytePos = Decodable::decode(d);
                     lines.push(line_start);
 
                     for _ in 1..num_lines {
                         let diff = match bytes_per_diff {
-                            1 => d.read_u8()? as u32,
-                            2 => d.read_u16()? as u32,
-                            4 => d.read_u32()?,
+                            1 => d.read_u8() as u32,
+                            2 => d.read_u16() as u32,
+                            4 => d.read_u32(),
                             _ => unreachable!(),
                         };
 
@@ -1481,17 +1482,17 @@ impl<D: Decoder> Decodable<D> for SourceFile {
                     }
                 }
 
-                Ok(lines)
-            })?;
+                lines
+            });
             let multibyte_chars: Vec<MultiByteChar> =
-                d.read_struct_field("multibyte_chars", |d| Decodable::decode(d))?;
+                d.read_struct_field("multibyte_chars", |d| Decodable::decode(d));
             let non_narrow_chars: Vec<NonNarrowChar> =
-                d.read_struct_field("non_narrow_chars", |d| Decodable::decode(d))?;
-            let name_hash: u128 = d.read_struct_field("name_hash", |d| Decodable::decode(d))?;
+                d.read_struct_field("non_narrow_chars", |d| Decodable::decode(d));
+            let name_hash: u128 = d.read_struct_field("name_hash", |d| Decodable::decode(d));
             let normalized_pos: Vec<NormalizedPos> =
-                d.read_struct_field("normalized_pos", |d| Decodable::decode(d))?;
-            let cnum: CrateNum = d.read_struct_field("cnum", |d| Decodable::decode(d))?;
-            Ok(SourceFile {
+                d.read_struct_field("normalized_pos", |d| Decodable::decode(d));
+            let cnum: CrateNum = d.read_struct_field("cnum", |d| Decodable::decode(d));
+            SourceFile {
                 name,
                 start_pos,
                 end_pos,
@@ -1506,7 +1507,7 @@ impl<D: Decoder> Decodable<D> for SourceFile {
                 normalized_pos,
                 name_hash,
                 cnum,
-            })
+            }
         })
     }
 }
@@ -1949,8 +1950,8 @@ impl<S: rustc_serialize::Encoder> Encodable<S> for BytePos {
 }
 
 impl<D: rustc_serialize::Decoder> Decodable<D> for BytePos {
-    fn decode(d: &mut D) -> Result<BytePos, D::Error> {
-        Ok(BytePos(d.read_u32()?))
+    fn decode(d: &mut D) -> BytePos {
+        BytePos(d.read_u32())
     }
 }
 
diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs
index e9120b98aab..61e4074a7c8 100644
--- a/compiler/rustc_span/src/span_encoding.rs
+++ b/compiler/rustc_span/src/span_encoding.rs
@@ -61,6 +61,15 @@ use rustc_data_structures::fx::FxIndexSet;
 /// using the callback `SPAN_TRACK` to access the query engine.
 ///
 #[derive(Clone, Copy, Eq, PartialEq, Hash)]
+// FIXME(@lcnr): Enable this attribute once the bootstrap
+// compiler knows of `rustc_pass_by_value`.
+//
+// Right now, this lint would only trigger when compiling the
+// stage 2 compiler, which is fairly annoying as there are
+// a lot of places using `&Span` right now. After the next bootstrap bump,
+// the lint will already trigger when using stage 1, which is a lot less annoying.
+//
+// #[cfg_attr(not(bootstrap), rustc_pass_by_value)]
 pub struct Span {
     base_or_index: u32,
     len_or_tag: u16,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 702e3594660..757c430e799 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -272,7 +272,6 @@ symbols! {
         __H,
         __S,
         __try_var,
-        _args,
         _d,
         _e,
         _task_context,
@@ -321,8 +320,10 @@ symbols! {
         and,
         and_then,
         any,
+        append_const_msg,
         arbitrary_enum_discriminant,
         arbitrary_self_types,
+        args,
         arith_offset,
         arm,
         arm_target_feature,
@@ -460,6 +461,7 @@ symbols! {
         const_async_blocks,
         const_compare_raw_pointers,
         const_constructor,
+        const_deallocate,
         const_eval_limit,
         const_eval_select,
         const_eval_select_ct,
@@ -990,6 +992,7 @@ symbols! {
         panic_implementation,
         panic_info,
         panic_location,
+        panic_no_unwind,
         panic_runtime,
         panic_str,
         panic_unwind,
@@ -1203,6 +1206,7 @@ symbols! {
         rustc_trivial_field_reads,
         rustc_unsafe_specialization_marker,
         rustc_variance,
+        rustc_with_negative_coherence,
         rustdoc,
         rustdoc_internals,
         rustfmt,
@@ -1755,8 +1759,8 @@ impl<S: Encoder> Encodable<S> for Symbol {
 
 impl<D: Decoder> Decodable<D> for Symbol {
     #[inline]
-    fn decode(d: &mut D) -> Result<Symbol, D::Error> {
-        Ok(Symbol::intern(&d.read_str()?))
+    fn decode(d: &mut D) -> Symbol {
+        Symbol::intern(&d.read_str())
     }
 }
 
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 0d51f7779e1..f8e8e15e78c 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -556,7 +556,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
                         cx = cx.print_def_path(trait_ref.def_id, trait_ref.substs)?;
                     }
                     ty::ExistentialPredicate::Projection(projection) => {
-                        let name = cx.tcx.associated_item(projection.item_def_id).ident;
+                        let name = cx.tcx.associated_item(projection.item_def_id).name;
                         cx.push("p");
                         cx.push_ident(name.as_str());
                         cx = match projection.term {
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index 6b82bb337e6..a84410d0f3c 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -152,6 +152,7 @@ mod avr;
 mod bpf;
 mod hexagon;
 mod mips;
+mod msp430;
 mod nvptx;
 mod powerpc;
 mod riscv;
@@ -166,6 +167,7 @@ pub use avr::{AvrInlineAsmReg, AvrInlineAsmRegClass};
 pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass};
 pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
 pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
+pub use msp430::{Msp430InlineAsmReg, Msp430InlineAsmRegClass};
 pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass};
 pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass};
 pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass};
@@ -194,6 +196,7 @@ pub enum InlineAsmArch {
     Wasm64,
     Bpf,
     Avr,
+    Msp430,
 }
 
 impl FromStr for InlineAsmArch {
@@ -219,6 +222,7 @@ impl FromStr for InlineAsmArch {
             "wasm64" => Ok(Self::Wasm64),
             "bpf" => Ok(Self::Bpf),
             "avr" => Ok(Self::Avr),
+            "msp430" => Ok(Self::Msp430),
             _ => Err(()),
         }
     }
@@ -250,6 +254,7 @@ pub enum InlineAsmReg {
     Wasm(WasmInlineAsmReg),
     Bpf(BpfInlineAsmReg),
     Avr(AvrInlineAsmReg),
+    Msp430(Msp430InlineAsmReg),
     // Placeholder for invalid register constraints for the current target
     Err,
 }
@@ -267,6 +272,7 @@ impl InlineAsmReg {
             Self::S390x(r) => r.name(),
             Self::Bpf(r) => r.name(),
             Self::Avr(r) => r.name(),
+            Self::Msp430(r) => r.name(),
             Self::Err => "<reg>",
         }
     }
@@ -283,6 +289,7 @@ impl InlineAsmReg {
             Self::S390x(r) => InlineAsmRegClass::S390x(r.reg_class()),
             Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()),
             Self::Avr(r) => InlineAsmRegClass::Avr(r.reg_class()),
+            Self::Msp430(r) => InlineAsmRegClass::Msp430(r.reg_class()),
             Self::Err => InlineAsmRegClass::Err,
         }
     }
@@ -336,6 +343,9 @@ impl InlineAsmReg {
             InlineAsmArch::Avr => {
                 Self::Avr(AvrInlineAsmReg::parse(arch, target_features, target, name)?)
             }
+            InlineAsmArch::Msp430 => {
+                Self::Msp430(Msp430InlineAsmReg::parse(arch, target_features, target, name)?)
+            }
         })
     }
 
@@ -358,6 +368,7 @@ impl InlineAsmReg {
             Self::S390x(r) => r.emit(out, arch, modifier),
             Self::Bpf(r) => r.emit(out, arch, modifier),
             Self::Avr(r) => r.emit(out, arch, modifier),
+            Self::Msp430(r) => r.emit(out, arch, modifier),
             Self::Err => unreachable!("Use of InlineAsmReg::Err"),
         }
     }
@@ -374,6 +385,7 @@ impl InlineAsmReg {
             Self::S390x(_) => cb(self),
             Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
             Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))),
+            Self::Msp430(_) => cb(self),
             Self::Err => unreachable!("Use of InlineAsmReg::Err"),
         }
     }
@@ -405,6 +417,7 @@ pub enum InlineAsmRegClass {
     Wasm(WasmInlineAsmRegClass),
     Bpf(BpfInlineAsmRegClass),
     Avr(AvrInlineAsmRegClass),
+    Msp430(Msp430InlineAsmRegClass),
     // Placeholder for invalid register constraints for the current target
     Err,
 }
@@ -425,12 +438,13 @@ impl InlineAsmRegClass {
             Self::Wasm(r) => r.name(),
             Self::Bpf(r) => r.name(),
             Self::Avr(r) => r.name(),
+            Self::Msp430(r) => r.name(),
             Self::Err => rustc_span::symbol::sym::reg,
         }
     }
 
     /// Returns a suggested register class to use for this type. This is called
-    /// after type checking via `supported_types` fails to give a better error
+    /// when `supported_types` fails to give a better error
     /// message to the user.
     pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option<Self> {
         match self {
@@ -447,6 +461,7 @@ impl InlineAsmRegClass {
             Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm),
             Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf),
             Self::Avr(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Avr),
+            Self::Msp430(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Msp430),
             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
         }
     }
@@ -476,6 +491,7 @@ impl InlineAsmRegClass {
             Self::Wasm(r) => r.suggest_modifier(arch, ty),
             Self::Bpf(r) => r.suggest_modifier(arch, ty),
             Self::Avr(r) => r.suggest_modifier(arch, ty),
+            Self::Msp430(r) => r.suggest_modifier(arch, ty),
             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
         }
     }
@@ -501,6 +517,7 @@ impl InlineAsmRegClass {
             Self::Wasm(r) => r.default_modifier(arch),
             Self::Bpf(r) => r.default_modifier(arch),
             Self::Avr(r) => r.default_modifier(arch),
+            Self::Msp430(r) => r.default_modifier(arch),
             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
         }
     }
@@ -525,6 +542,7 @@ impl InlineAsmRegClass {
             Self::Wasm(r) => r.supported_types(arch),
             Self::Bpf(r) => r.supported_types(arch),
             Self::Avr(r) => r.supported_types(arch),
+            Self::Msp430(r) => r.supported_types(arch),
             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
         }
     }
@@ -554,6 +572,7 @@ impl InlineAsmRegClass {
             }
             InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(arch, name)?),
             InlineAsmArch::Avr => Self::Avr(AvrInlineAsmRegClass::parse(arch, name)?),
+            InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmRegClass::parse(arch, name)?),
         })
     }
 
@@ -574,6 +593,7 @@ impl InlineAsmRegClass {
             Self::Wasm(r) => r.valid_modifiers(arch),
             Self::Bpf(r) => r.valid_modifiers(arch),
             Self::Avr(r) => r.valid_modifiers(arch),
+            Self::Msp430(r) => r.valid_modifiers(arch),
             Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
         }
     }
@@ -764,6 +784,11 @@ pub fn allocatable_registers(
             avr::fill_reg_map(arch, target_features, target, &mut map);
             map
         }
+        InlineAsmArch::Msp430 => {
+            let mut map = msp430::regclass_map();
+            msp430::fill_reg_map(arch, target_features, target, &mut map);
+            map
+        }
     }
 }
 
diff --git a/compiler/rustc_target/src/asm/msp430.rs b/compiler/rustc_target/src/asm/msp430.rs
new file mode 100644
index 00000000000..a27d6390a72
--- /dev/null
+++ b/compiler/rustc_target/src/asm/msp430.rs
@@ -0,0 +1,81 @@
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
+use std::fmt;
+
+def_reg_class! {
+    Msp430 Msp430InlineAsmRegClass {
+        reg,
+    }
+}
+
+impl Msp430InlineAsmRegClass {
+    pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
+        &[]
+    }
+
+    pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+        None
+    }
+
+    pub fn suggest_modifier(
+        self,
+        _arch: InlineAsmArch,
+        _ty: InlineAsmType,
+    ) -> Option<(char, &'static str)> {
+        None
+    }
+
+    pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+        None
+    }
+
+    pub fn supported_types(
+        self,
+        arch: InlineAsmArch,
+    ) -> &'static [(InlineAsmType, Option<Symbol>)] {
+        match (self, arch) {
+            (Self::reg, _) => types! { _: I8, I16; },
+        }
+    }
+}
+
+// The reserved registers are taken from:
+// https://github.com/llvm/llvm-project/blob/36cb29cbbe1b22dcd298ad65e1fabe899b7d7249/llvm/lib/Target/MSP430/MSP430RegisterInfo.cpp#L73.
+def_regs! {
+    Msp430 Msp430InlineAsmReg Msp430InlineAsmRegClass {
+        r5: reg = ["r5"],
+        r6: reg = ["r6"],
+        r7: reg = ["r7"],
+        r8: reg = ["r8"],
+        r9: reg = ["r9"],
+        r10: reg = ["r10"],
+        r11: reg = ["r11"],
+        r12: reg = ["r12"],
+        r13: reg = ["r13"],
+        r14: reg = ["r14"],
+        r15: reg = ["r15"],
+
+        #error = ["r0", "pc"] =>
+            "the program counter cannot be used as an operand for inline asm",
+        #error = ["r1", "sp"] =>
+            "the stack pointer cannot be used as an operand for inline asm",
+        #error = ["r2", "sr"] =>
+            "the status register cannot be used as an operand for inline asm",
+        #error = ["r3", "cg"] =>
+            "the constant generator cannot be used as an operand for inline asm",
+        #error = ["r4", "fp"] =>
+            "the frame pointer cannot be used as an operand for inline asm",
+    }
+}
+
+impl Msp430InlineAsmReg {
+    pub fn emit(
+        self,
+        out: &mut dyn fmt::Write,
+        _arch: InlineAsmArch,
+        _modifier: Option<char>,
+    ) -> fmt::Result {
+        out.write_str(self.name())
+    }
+}
diff --git a/compiler/rustc_target/src/spec/l4re_base.rs b/compiler/rustc_target/src/spec/l4re_base.rs
index f6e3102f617..9e7973f63a9 100644
--- a/compiler/rustc_target/src/spec/l4re_base.rs
+++ b/compiler/rustc_target/src/spec/l4re_base.rs
@@ -1,25 +1,14 @@
 use crate::spec::{LinkerFlavor, PanicStrategy, TargetOptions};
-//use std::process::Command;
-
-// Use GCC to locate code for crt* libraries from the host, not from L4Re. Note
-// that a few files also come from L4Re, for these, the function shouldn't be
-// used. This uses GCC for the location of the file, but GCC is required for L4Re anyway.
-//fn get_path_or(filename: &str) -> String {
-//    let child = Command::new("gcc")
-//        .arg(format!("-print-file-name={}", filename)).output()
-//        .expect("Failed to execute GCC");
-//    String::from_utf8(child.stdout)
-//        .expect("Couldn't read path from GCC").trim().into()
-//}
+use std::default::Default;
 
 pub fn opts() -> TargetOptions {
     TargetOptions {
         os: "l4re".to_string(),
         env: "uclibc".to_string(),
-        linker_flavor: LinkerFlavor::Ld,
+        linker_flavor: LinkerFlavor::L4Bender,
         executables: true,
         panic_strategy: PanicStrategy::Abort,
-        linker: Some("ld".to_string()),
+        linker: Some("l4-bender".to_string()),
         linker_is_gnu: false,
         families: vec!["unix".to_string()],
         ..Default::default()
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 2c149318730..4effb8bacf6 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -90,6 +90,7 @@ mod windows_uwp_msvc_base;
 pub enum LinkerFlavor {
     Em,
     Gcc,
+    L4Bender,
     Ld,
     Msvc,
     Lld(LldFlavor),
@@ -160,6 +161,7 @@ macro_rules! flavor_mappings {
 flavor_mappings! {
     ((LinkerFlavor::Em), "em"),
     ((LinkerFlavor::Gcc), "gcc"),
+    ((LinkerFlavor::L4Bender), "l4-bender"),
     ((LinkerFlavor::Ld), "ld"),
     ((LinkerFlavor::Msvc), "msvc"),
     ((LinkerFlavor::PtxLinker), "ptx-linker"),
diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs
index 1fbd0bb4cec..64c7c1c5f6f 100644
--- a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs
+++ b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs
@@ -1,9 +1,12 @@
-use crate::spec::Target;
+use crate::spec::{PanicStrategy, Target};
 
 pub fn target() -> Target {
     let mut base = super::l4re_base::opts();
     base.cpu = "x86-64".to_string();
     base.max_atomic_width = Some(64);
+    base.crt_static_allows_dylibs = false;
+    base.dynamic_linking = false;
+    base.panic_strategy = PanicStrategy::Abort;
 
     Target {
         llvm_target: "x86_64-unknown-l4re-uclibc".to_string(),
diff --git a/compiler/rustc_trait_selection/src/traits/codegen.rs b/compiler/rustc_trait_selection/src/traits/codegen.rs
index 848aba7c912..759bc696981 100644
--- a/compiler/rustc_trait_selection/src/traits/codegen.rs
+++ b/compiler/rustc_trait_selection/src/traits/codegen.rs
@@ -18,7 +18,6 @@ use rustc_middle::ty::{self, TyCtxt};
 /// that type check should guarantee to us that all nested
 /// obligations *could be* resolved if we wanted to.
 ///
-/// Assumes that this is run after the entire crate has been successfully type-checked.
 /// This also expects that `trait_ref` is fully normalized.
 pub fn codegen_fulfill_obligation<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -101,7 +100,7 @@ pub fn codegen_fulfill_obligation<'tcx>(
 /// Finishes processes any obligations that remain in the
 /// fulfillment context, and then returns the result with all type
 /// variables removed and regions erased. Because this is intended
-/// for use after type-check has completed, if any errors occur,
+/// for use outside of type inference, if any errors occur,
 /// it will panic. It is used during normalization and other cases
 /// where processing the obligations in `fulfill_cx` may cause
 /// type inference variables that appear in `result` to be
@@ -124,7 +123,10 @@ where
     if !errors.is_empty() {
         infcx.tcx.sess.delay_span_bug(
             rustc_span::DUMMY_SP,
-            &format!("Encountered errors `{:?}` resolving bounds after type-checking", errors),
+            &format!(
+                "Encountered errors `{:?}` resolving bounds outside of type inference",
+                errors
+            ),
         );
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index af3540386f9..ab1dc8fcbfe 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -7,10 +7,13 @@
 use crate::infer::{CombinedSnapshot, InferOk, TyCtxtInferExt};
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::select::IntercrateAmbiguityCause;
+use crate::traits::util::impl_trait_ref_and_oblig;
 use crate::traits::SkipLeakCheck;
 use crate::traits::{
-    self, Normalized, Obligation, ObligationCause, PredicateObligation, SelectionContext,
+    self, FulfillmentContext, Normalized, Obligation, ObligationCause, PredicateObligation,
+    PredicateObligations, SelectionContext,
 };
+use rustc_ast::Attribute;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_middle::ty::fast_reject::{self, SimplifyParams, StripReferences};
 use rustc_middle::ty::fold::TypeFoldable;
@@ -135,45 +138,89 @@ fn with_fresh_ty_vars<'cx, 'tcx>(
     header
 }
 
+/// What kind of overlap check are we doing -- this exists just for testing and feature-gating
+/// purposes.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+enum OverlapMode {
+    /// The 1.0 rules (either types fail to unify, or where clauses are not implemented for crate-local types)
+    Stable,
+    /// Feature-gated test: Stable, *or* there is an explicit negative impl that rules out one of the where-clauses.
+    WithNegative,
+    /// Just check for negative impls, not for "where clause not implemented": used for testing.
+    Strict,
+}
+
+impl OverlapMode {
+    fn use_negative_impl(&self) -> bool {
+        *self == OverlapMode::Strict || *self == OverlapMode::WithNegative
+    }
+
+    fn use_implicit_negative(&self) -> bool {
+        *self == OverlapMode::Stable || *self == OverlapMode::WithNegative
+    }
+}
+
+fn overlap_mode<'tcx>(tcx: TyCtxt<'tcx>, impl1_def_id: DefId, impl2_def_id: DefId) -> OverlapMode {
+    // Find the possible coherence mode override opt-in attributes for each `DefId`
+    let find_coherence_attr = |attr: &Attribute| {
+        let name = attr.name_or_empty();
+        match name {
+            sym::rustc_with_negative_coherence | sym::rustc_strict_coherence => Some(name),
+            _ => None,
+        }
+    };
+    let impl1_coherence_mode = tcx.get_attrs(impl1_def_id).iter().find_map(find_coherence_attr);
+    let impl2_coherence_mode = tcx.get_attrs(impl2_def_id).iter().find_map(find_coherence_attr);
+
+    // If there are any (that currently happens in tests), they need to match. Otherwise, the
+    // default 1.0 rules are used.
+    match (impl1_coherence_mode, impl2_coherence_mode) {
+        (None, None) => OverlapMode::Stable,
+        (Some(sym::rustc_with_negative_coherence), Some(sym::rustc_with_negative_coherence)) => {
+            OverlapMode::WithNegative
+        }
+        (Some(sym::rustc_strict_coherence), Some(sym::rustc_strict_coherence)) => {
+            OverlapMode::Strict
+        }
+        (Some(mode), _) | (_, Some(mode)) => {
+            bug!("Use the same coherence mode on both impls: {}", mode)
+        }
+    }
+}
+
 /// Can both impl `a` and impl `b` be satisfied by a common type (including
 /// where-clauses)? If so, returns an `ImplHeader` that unifies the two impls.
 fn overlap<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     skip_leak_check: SkipLeakCheck,
-    a_def_id: DefId,
-    b_def_id: DefId,
+    impl1_def_id: DefId,
+    impl2_def_id: DefId,
 ) -> Option<OverlapResult<'tcx>> {
-    debug!("overlap(a_def_id={:?}, b_def_id={:?})", a_def_id, b_def_id);
+    debug!("overlap(impl1_def_id={:?}, impl2_def_id={:?})", impl1_def_id, impl2_def_id);
 
     selcx.infcx().probe_maybe_skip_leak_check(skip_leak_check.is_yes(), |snapshot| {
-        overlap_within_probe(selcx, skip_leak_check, a_def_id, b_def_id, snapshot)
+        overlap_within_probe(selcx, skip_leak_check, impl1_def_id, impl2_def_id, snapshot)
     })
 }
 
 fn overlap_within_probe<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     skip_leak_check: SkipLeakCheck,
-    a_def_id: DefId,
-    b_def_id: DefId,
+    impl1_def_id: DefId,
+    impl2_def_id: DefId,
     snapshot: &CombinedSnapshot<'_, 'tcx>,
 ) -> Option<OverlapResult<'tcx>> {
-    fn loose_check<'cx, 'tcx>(
-        selcx: &mut SelectionContext<'cx, 'tcx>,
-        o: &PredicateObligation<'tcx>,
-    ) -> bool {
-        !selcx.predicate_may_hold_fatal(o)
-    }
+    let infcx = selcx.infcx();
+    let tcx = infcx.tcx;
+
+    let overlap_mode = overlap_mode(tcx, impl1_def_id, impl2_def_id);
 
-    fn strict_check<'cx, 'tcx>(
-        selcx: &SelectionContext<'cx, 'tcx>,
-        o: &PredicateObligation<'tcx>,
-    ) -> bool {
-        let infcx = selcx.infcx();
-        let tcx = infcx.tcx;
-        o.flip_polarity(tcx)
-            .as_ref()
-            .map(|o| selcx.infcx().predicate_must_hold_modulo_regions(o))
-            .unwrap_or(false)
+    if overlap_mode.use_negative_impl() {
+        if negative_impl(selcx, impl1_def_id, impl2_def_id)
+            || negative_impl(selcx, impl2_def_id, impl1_def_id)
+        {
+            return None;
+        }
     }
 
     // For the purposes of this check, we don't bring any placeholder
@@ -182,26 +229,61 @@ fn overlap_within_probe<'cx, 'tcx>(
     // empty environment.
     let param_env = ty::ParamEnv::empty();
 
-    let a_impl_header = with_fresh_ty_vars(selcx, param_env, a_def_id);
-    let b_impl_header = with_fresh_ty_vars(selcx, param_env, b_def_id);
+    let impl1_header = with_fresh_ty_vars(selcx, param_env, impl1_def_id);
+    let impl2_header = with_fresh_ty_vars(selcx, param_env, impl2_def_id);
 
-    debug!("overlap: a_impl_header={:?}", a_impl_header);
-    debug!("overlap: b_impl_header={:?}", b_impl_header);
+    debug!("overlap: impl1_header={:?}", impl1_header);
+    debug!("overlap: impl2_header={:?}", impl2_header);
 
-    // Do `a` and `b` unify? If not, no overlap.
-    let obligations = match selcx
-        .infcx()
-        .at(&ObligationCause::dummy(), param_env)
-        .eq_impl_headers(&a_impl_header, &b_impl_header)
-    {
-        Ok(InferOk { obligations, value: () }) => obligations,
-        Err(_) => {
+    let obligations = equate_impl_headers(selcx, &impl1_header, &impl2_header)?;
+    debug!("overlap: unification check succeeded");
+
+    if overlap_mode.use_implicit_negative() {
+        if implicit_negative(selcx, param_env, &impl1_header, impl2_header, obligations) {
             return None;
         }
-    };
+    }
 
-    debug!("overlap: unification check succeeded");
+    if !skip_leak_check.is_yes() {
+        if infcx.leak_check(true, snapshot).is_err() {
+            debug!("overlap: leak check failed");
+            return None;
+        }
+    }
+
+    let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
+    debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
+
+    let involves_placeholder =
+        matches!(selcx.infcx().region_constraints_added_in_snapshot(snapshot), Some(true));
+
+    let impl_header = selcx.infcx().resolve_vars_if_possible(impl1_header);
+    Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
+}
+
+fn equate_impl_headers<'cx, 'tcx>(
+    selcx: &mut SelectionContext<'cx, 'tcx>,
+    impl1_header: &ty::ImplHeader<'tcx>,
+    impl2_header: &ty::ImplHeader<'tcx>,
+) -> Option<PredicateObligations<'tcx>> {
+    // Do `a` and `b` unify? If not, no overlap.
+    selcx
+        .infcx()
+        .at(&ObligationCause::dummy(), ty::ParamEnv::empty())
+        .eq_impl_headers(impl1_header, impl2_header)
+        .map(|infer_ok| infer_ok.obligations)
+        .ok()
+}
 
+/// Given impl1 and impl2 check if both impls can be satisfied by a common type (including
+/// where-clauses) If so, return false, otherwise return true, they are disjoint.
+fn implicit_negative<'cx, 'tcx>(
+    selcx: &mut SelectionContext<'cx, 'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+    impl1_header: &ty::ImplHeader<'tcx>,
+    impl2_header: ty::ImplHeader<'tcx>,
+    obligations: PredicateObligations<'tcx>,
+) -> bool {
     // There's no overlap if obligations are unsatisfiable or if the obligation negated is
     // satisfied.
     //
@@ -225,11 +307,11 @@ fn overlap_within_probe<'cx, 'tcx>(
     // at some point an impl for `&'?a str: Error` could be added.
     let infcx = selcx.infcx();
     let tcx = infcx.tcx;
-    let opt_failing_obligation = a_impl_header
+    let opt_failing_obligation = impl1_header
         .predicates
         .iter()
         .copied()
-        .chain(b_impl_header.predicates)
+        .chain(impl2_header.predicates)
         .map(|p| infcx.resolve_vars_if_possible(p))
         .map(|p| Obligation {
             cause: ObligationCause::dummy(),
@@ -239,15 +321,7 @@ fn overlap_within_probe<'cx, 'tcx>(
         })
         .chain(obligations)
         .find(|o| {
-            // if both impl headers are set to strict coherence it means that this will be accepted
-            // only if it's stated that T: !Trait. So only prove that the negated obligation holds.
-            if tcx.has_attr(a_def_id, sym::rustc_strict_coherence)
-                && tcx.has_attr(b_def_id, sym::rustc_strict_coherence)
-            {
-                strict_check(selcx, o)
-            } else {
-                loose_check(selcx, o) || tcx.features().negative_impls && strict_check(selcx, o)
-            }
+            loose_check(selcx, o) || tcx.features().negative_impls && negative_impl_exists(selcx, o)
         });
     // FIXME: the call to `selcx.predicate_may_hold_fatal` above should be ported
     // to the canonical trait query form, `infcx.predicate_may_hold`, once
@@ -255,24 +329,97 @@ fn overlap_within_probe<'cx, 'tcx>(
 
     if let Some(failing_obligation) = opt_failing_obligation {
         debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
-        return None;
+        true
+    } else {
+        false
     }
+}
 
-    if !skip_leak_check.is_yes() {
-        if infcx.leak_check(true, snapshot).is_err() {
-            debug!("overlap: leak check failed");
-            return None;
-        }
-    }
+/// Given impl1 and impl2 check if both impls are never satisfied by a common type (including
+/// where-clauses) If so, return true, they are disjoint and false otherwise.
+fn negative_impl<'cx, 'tcx>(
+    selcx: &mut SelectionContext<'cx, 'tcx>,
+    impl1_def_id: DefId,
+    impl2_def_id: DefId,
+) -> bool {
+    let tcx = selcx.infcx().tcx;
 
-    let impl_header = selcx.infcx().resolve_vars_if_possible(a_impl_header);
-    let intercrate_ambiguity_causes = selcx.take_intercrate_ambiguity_causes();
-    debug!("overlap: intercrate_ambiguity_causes={:#?}", intercrate_ambiguity_causes);
+    // create a parameter environment corresponding to a (placeholder) instantiation of impl1
+    let impl1_env = tcx.param_env(impl1_def_id);
+    let impl1_trait_ref = tcx.impl_trait_ref(impl1_def_id).unwrap();
 
-    let involves_placeholder =
-        matches!(selcx.infcx().region_constraints_added_in_snapshot(snapshot), Some(true));
+    // Create an infcx, taking the predicates of impl1 as assumptions:
+    tcx.infer_ctxt().enter(|infcx| {
+        // Normalize the trait reference. The WF rules ought to ensure
+        // that this always succeeds.
+        let impl1_trait_ref = match traits::fully_normalize(
+            &infcx,
+            FulfillmentContext::new(),
+            ObligationCause::dummy(),
+            impl1_env,
+            impl1_trait_ref,
+        ) {
+            Ok(impl1_trait_ref) => impl1_trait_ref,
+            Err(err) => {
+                bug!("failed to fully normalize {:?}: {:?}", impl1_trait_ref, err);
+            }
+        };
+
+        // Attempt to prove that impl2 applies, given all of the above.
+        let selcx = &mut SelectionContext::new(&infcx);
+        let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
+        let (impl2_trait_ref, obligations) =
+            impl_trait_ref_and_oblig(selcx, impl1_env, impl2_def_id, impl2_substs);
+
+        // do the impls unify? If not, not disjoint.
+        let more_obligations = match infcx
+            .at(&ObligationCause::dummy(), impl1_env)
+            .eq(impl1_trait_ref, impl2_trait_ref)
+        {
+            Ok(InferOk { obligations, .. }) => obligations,
+            Err(_) => {
+                debug!(
+                    "explicit_disjoint: {:?} does not unify with {:?}",
+                    impl1_trait_ref, impl2_trait_ref
+                );
+                return false;
+            }
+        };
 
-    Some(OverlapResult { impl_header, intercrate_ambiguity_causes, involves_placeholder })
+        let opt_failing_obligation = obligations
+            .into_iter()
+            .chain(more_obligations)
+            .find(|o| negative_impl_exists(selcx, o));
+
+        if let Some(failing_obligation) = opt_failing_obligation {
+            debug!("overlap: obligation unsatisfiable {:?}", failing_obligation);
+            true
+        } else {
+            false
+        }
+    })
+}
+
+fn loose_check<'cx, 'tcx>(
+    selcx: &mut SelectionContext<'cx, 'tcx>,
+    o: &PredicateObligation<'tcx>,
+) -> bool {
+    !selcx.predicate_may_hold_fatal(o)
+}
+
+fn negative_impl_exists<'cx, 'tcx>(
+    selcx: &SelectionContext<'cx, 'tcx>,
+    o: &PredicateObligation<'tcx>,
+) -> bool {
+    let infcx = selcx.infcx();
+    let tcx = infcx.tcx;
+    o.flip_polarity(tcx)
+        .as_ref()
+        .map(|o| {
+            // FIXME This isn't quite correct, regions should be included
+            selcx.infcx().predicate_must_hold_modulo_regions(o)
+        })
+        .unwrap_or(false)
 }
 
 pub fn trait_ref_is_knowable<'tcx>(
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 0760f626851..687bd16ba30 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -205,6 +205,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         self.note_obligation_cause_code(
             &mut err,
             &obligation.predicate,
+            obligation.param_env,
             obligation.cause.code(),
             &mut vec![],
             &mut Default::default(),
@@ -288,7 +289,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 match bound_predicate.skip_binder() {
                     ty::PredicateKind::Trait(trait_predicate) => {
                         let trait_predicate = bound_predicate.rebind(trait_predicate);
-                        let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
+                        let mut trait_predicate = self.resolve_vars_if_possible(trait_predicate);
+
+                        trait_predicate.remap_constness_diag(obligation.param_env);
+                        let predicate_is_const = ty::BoundConstness::ConstIfConst
+                            == trait_predicate.skip_binder().constness;
 
                         if self.tcx.sess.has_errors() && trait_predicate.references_error() {
                             return;
@@ -305,13 +310,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             })
                             .unwrap_or_default();
 
-                        let OnUnimplementedNote { message, label, note, enclosing_scope } =
-                            self.on_unimplemented_note(trait_ref, &obligation);
+                        let OnUnimplementedNote {
+                            message,
+                            label,
+                            note,
+                            enclosing_scope,
+                            append_const_msg,
+                        } = self.on_unimplemented_note(trait_ref, &obligation);
                         let have_alt_message = message.is_some() || label.is_some();
                         let is_try_conversion = self.is_try_conversion(span, trait_ref.def_id());
                         let is_unsize =
                             { Some(trait_ref.def_id()) == self.tcx.lang_items().unsize_trait() };
-                        let (message, note) = if is_try_conversion {
+                        let (message, note, append_const_msg) = if is_try_conversion {
                             (
                                 Some(format!(
                                     "`?` couldn't convert the error to `{}`",
@@ -322,9 +332,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                                         conversion on the error value using the `From` trait"
                                         .to_owned(),
                                 ),
+                                Some(None),
                             )
                         } else {
-                            (message, note)
+                            (message, note, append_const_msg)
                         };
 
                         let mut err = struct_span_err!(
@@ -332,11 +343,27 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             span,
                             E0277,
                             "{}",
-                            message.unwrap_or_else(|| format!(
-                                "the trait bound `{}` is not satisfied{}",
-                                trait_ref.without_const().to_predicate(tcx),
-                                post_message,
-                            ))
+                            message
+                                .and_then(|cannot_do_this| {
+                                    match (predicate_is_const, append_const_msg) {
+                                        // do nothing if predicate is not const
+                                        (false, _) => Some(cannot_do_this),
+                                        // suggested using default post message
+                                        (true, Some(None)) => {
+                                            Some(format!("{cannot_do_this} in const contexts"))
+                                        }
+                                        // overriden post message
+                                        (true, Some(Some(post_message))) => {
+                                            Some(format!("{cannot_do_this}{post_message}"))
+                                        }
+                                        // fallback to generic message
+                                        (true, None) => None,
+                                    }
+                                })
+                                .unwrap_or_else(|| format!(
+                                    "the trait bound `{}` is not satisfied{}",
+                                    trait_predicate, post_message,
+                                ))
                         );
 
                         if is_try_conversion {
@@ -384,7 +411,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             format!(
                                 "{}the trait `{}` is not implemented for `{}`",
                                 pre_message,
-                                trait_ref.print_only_trait_path(),
+                                trait_predicate.print_modifiers_and_trait_path(),
                                 trait_ref.skip_binder().self_ty(),
                             )
                         };
@@ -392,7 +419,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         if self.suggest_add_reference_to_arg(
                             &obligation,
                             &mut err,
-                            &trait_ref,
+                            trait_predicate,
                             have_alt_message,
                         ) {
                             self.note_obligation_cause(&mut err, &obligation);
@@ -412,6 +439,28 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         } else {
                             err.span_label(span, explanation);
                         }
+
+                        if trait_predicate.is_const_if_const() && obligation.param_env.is_const() {
+                            let non_const_predicate = trait_ref.without_const();
+                            let non_const_obligation = Obligation {
+                                cause: obligation.cause.clone(),
+                                param_env: obligation.param_env.without_const(),
+                                predicate: non_const_predicate.to_predicate(tcx),
+                                recursion_depth: obligation.recursion_depth,
+                            };
+                            if self.predicate_may_hold(&non_const_obligation) {
+                                err.span_note(
+                                    span,
+                                    &format!(
+                                        "the trait `{}` is implemented for `{}`, \
+                                        but that implementation is not `const`",
+                                        non_const_predicate.print_modifiers_and_trait_path(),
+                                        trait_ref.skip_binder().self_ty(),
+                                    ),
+                                );
+                            }
+                        }
+
                         if let Some((msg, span)) = type_def {
                             err.span_label(span, &msg);
                         }
@@ -435,18 +484,28 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             err.span_label(enclosing_scope_span, s.as_str());
                         }
 
-                        self.suggest_dereferences(&obligation, &mut err, trait_ref);
-                        self.suggest_fn_call(&obligation, &mut err, trait_ref);
-                        self.suggest_remove_reference(&obligation, &mut err, trait_ref);
-                        self.suggest_semicolon_removal(&obligation, &mut err, span, trait_ref);
+                        self.suggest_dereferences(&obligation, &mut err, trait_predicate);
+                        self.suggest_fn_call(&obligation, &mut err, trait_predicate);
+                        self.suggest_remove_reference(&obligation, &mut err, trait_predicate);
+                        self.suggest_semicolon_removal(
+                            &obligation,
+                            &mut err,
+                            span,
+                            trait_predicate,
+                        );
                         self.note_version_mismatch(&mut err, &trait_ref);
                         self.suggest_remove_await(&obligation, &mut err);
 
                         if Some(trait_ref.def_id()) == tcx.lang_items().try_trait() {
-                            self.suggest_await_before_try(&mut err, &obligation, trait_ref, span);
+                            self.suggest_await_before_try(
+                                &mut err,
+                                &obligation,
+                                trait_predicate,
+                                span,
+                            );
                         }
 
-                        if self.suggest_impl_trait(&mut err, span, &obligation, trait_ref) {
+                        if self.suggest_impl_trait(&mut err, span, &obligation, trait_predicate) {
                             err.emit();
                             return;
                         }
@@ -494,7 +553,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             // which is somewhat confusing.
                             self.suggest_restricting_param_bound(
                                 &mut err,
-                                trait_ref,
+                                trait_predicate,
                                 obligation.cause.body_id,
                             );
                         } else if !have_alt_message {
@@ -506,7 +565,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         // Changing mutability doesn't make a difference to whether we have
                         // an `Unsize` impl (Fixes ICE in #71036)
                         if !is_unsize {
-                            self.suggest_change_mut(&obligation, &mut err, trait_ref);
+                            self.suggest_change_mut(&obligation, &mut err, trait_predicate);
                         }
 
                         // If this error is due to `!: Trait` not implemented but `(): Trait` is
@@ -1121,7 +1180,7 @@ trait InferCtxtPrivExt<'hir, 'tcx> {
     fn mk_trait_obligation_with_new_self_ty(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_ref: ty::PolyTraitPredicate<'tcx>,
         new_self_ty: Ty<'tcx>,
     ) -> PredicateObligation<'tcx>;
 
@@ -1353,6 +1412,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                                 .map(|id| (trait_assoc_item, id))
                         })
                         .and_then(|(trait_assoc_item, id)| {
+                            let trait_assoc_ident = trait_assoc_item.ident(self.tcx);
                             self.tcx.find_map_relevant_impl(
                                 id,
                                 proj.projection_ty.self_ty(),
@@ -1360,7 +1420,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
                                     self.tcx
                                         .associated_items(did)
                                         .in_definition_order()
-                                        .filter(|assoc| assoc.ident == trait_assoc_item.ident)
+                                        .filter(|assoc| assoc.ident(self.tcx) == trait_assoc_ident)
                                         .next()
                                 },
                             )
@@ -1540,7 +1600,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
     ) -> Option<(String, Option<Span>)> {
         match code {
             ObligationCauseCode::BuiltinDerivedObligation(data) => {
-                let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
+                let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
                 match self.get_parent_trait_ref(&data.parent_code) {
                     Some(t) => Some(t),
                     None => {
@@ -1593,21 +1653,20 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
     fn mk_trait_obligation_with_new_self_ty(
         &self,
         param_env: ty::ParamEnv<'tcx>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_ref: ty::PolyTraitPredicate<'tcx>,
         new_self_ty: Ty<'tcx>,
     ) -> PredicateObligation<'tcx> {
         assert!(!new_self_ty.has_escaping_bound_vars());
 
-        let trait_ref = trait_ref.map_bound_ref(|tr| ty::TraitRef {
-            substs: self.tcx.mk_substs_trait(new_self_ty, &tr.substs[1..]),
+        let trait_pred = trait_ref.map_bound_ref(|tr| ty::TraitPredicate {
+            trait_ref: ty::TraitRef {
+                substs: self.tcx.mk_substs_trait(new_self_ty, &tr.trait_ref.substs[1..]),
+                ..tr.trait_ref
+            },
             ..*tr
         });
 
-        Obligation::new(
-            ObligationCause::dummy(),
-            param_env,
-            trait_ref.without_const().to_predicate(self.tcx),
-        )
+        Obligation::new(ObligationCause::dummy(), param_env, trait_pred.to_predicate(self.tcx))
     }
 
     #[instrument(skip(self), level = "debug")]
@@ -2008,6 +2067,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
             self.note_obligation_cause_code(
                 err,
                 &obligation.predicate,
+                obligation.param_env,
                 obligation.cause.code(),
                 &mut vec![],
                 &mut Default::default(),
@@ -2155,7 +2215,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'a, 'tcx> for InferCtxt<'a, 'tcx> {
         cause_code: &ObligationCauseCode<'tcx>,
     ) -> bool {
         if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code {
-            let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
+            let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
             let self_ty = parent_trait_ref.skip_binder().self_ty();
             if obligated_types.iter().any(|ot| ot == &self_ty) {
                 return true;
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 e94c600bb49..8c0dbe9b064 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -48,7 +48,7 @@ pub trait InferCtxtExt<'tcx> {
     fn suggest_restricting_param_bound(
         &self,
         err: &mut DiagnosticBuilder<'_>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
         body_id: hir::HirId,
     );
 
@@ -56,7 +56,7 @@ pub trait InferCtxtExt<'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'tcx>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
     );
 
     fn get_closure_name(
@@ -70,14 +70,14 @@ pub trait InferCtxtExt<'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
-        trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
     );
 
     fn suggest_add_reference_to_arg(
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
-        trait_ref: &ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
         has_custom_message: bool,
     ) -> bool;
 
@@ -85,7 +85,7 @@ pub trait InferCtxtExt<'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
-        trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
     );
 
     fn suggest_remove_await(
@@ -98,7 +98,7 @@ pub trait InferCtxtExt<'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
-        trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
     );
 
     fn suggest_semicolon_removal(
@@ -106,7 +106,7 @@ pub trait InferCtxtExt<'tcx> {
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
         span: Span,
-        trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
     );
 
     fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span>;
@@ -116,7 +116,7 @@ pub trait InferCtxtExt<'tcx> {
         err: &mut DiagnosticBuilder<'_>,
         span: Span,
         obligation: &PredicateObligation<'tcx>,
-        trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool;
 
     fn point_at_returns_when_relevant(
@@ -154,7 +154,7 @@ pub trait InferCtxtExt<'tcx> {
         interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>,
         inner_generator_body: Option<&hir::Body<'tcx>>,
         outer_generator: Option<DefId>,
-        trait_ref: ty::TraitRef<'tcx>,
+        trait_pred: ty::TraitPredicate<'tcx>,
         target_ty: Ty<'tcx>,
         typeck_results: Option<&ty::TypeckResults<'tcx>>,
         obligation: &PredicateObligation<'tcx>,
@@ -165,6 +165,7 @@ pub trait InferCtxtExt<'tcx> {
         &self,
         err: &mut DiagnosticBuilder<'_>,
         predicate: &T,
+        param_env: ty::ParamEnv<'tcx>,
         cause_code: &ObligationCauseCode<'tcx>,
         obligated_types: &mut Vec<&ty::TyS<'tcx>>,
         seen_requirements: &mut FxHashSet<DefId>,
@@ -178,7 +179,7 @@ pub trait InferCtxtExt<'tcx> {
         &self,
         err: &mut DiagnosticBuilder<'_>,
         obligation: &PredicateObligation<'tcx>,
-        trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
         span: Span,
     );
 }
@@ -204,7 +205,7 @@ fn suggest_restriction<'tcx>(
     err: &mut DiagnosticBuilder<'_>,
     fn_sig: Option<&hir::FnSig<'_>>,
     projection: Option<&ty::ProjectionTy<'_>>,
-    trait_ref: ty::PolyTraitRef<'tcx>,
+    trait_pred: ty::PolyTraitPredicate<'tcx>,
     super_traits: Option<(&Ident, &hir::GenericBounds<'_>)>,
 ) {
     // When we are dealing with a trait, `super_traits` will be `Some`:
@@ -257,9 +258,9 @@ fn suggest_restriction<'tcx>(
         // The type param `T: Trait` we will suggest to introduce.
         let type_param = format!("{}: {}", type_param_name, bound_str);
 
-        // FIXME: modify the `trait_ref` instead of string shenanigans.
+        // FIXME: modify the `trait_pred` instead of string shenanigans.
         // Turn `<impl Trait as Foo>::Bar: Qux` into `<T as Foo>::Bar: Qux`.
-        let pred = trait_ref.without_const().to_predicate(tcx).to_string();
+        let pred = trait_pred.to_predicate(tcx).to_string();
         let pred = pred.replace(&impl_trait_str, &type_param_name);
         let mut sugg = vec![
             // Find the last of the generic parameters contained within the span of
@@ -301,19 +302,19 @@ fn suggest_restriction<'tcx>(
                 .find(|p| !matches!(p.kind, hir::GenericParamKind::Type { synthetic: true, .. })),
             super_traits,
         ) {
-            (_, None) => predicate_constraint(
-                generics,
-                trait_ref.without_const().to_predicate(tcx).to_string(),
+            (_, None) => predicate_constraint(generics, trait_pred.to_predicate(tcx).to_string()),
+            (None, Some((ident, []))) => (
+                ident.span.shrink_to_hi(),
+                format!(": {}", trait_pred.print_modifiers_and_trait_path()),
+            ),
+            (_, Some((_, [.., bounds]))) => (
+                bounds.span().shrink_to_hi(),
+                format!(" + {}", trait_pred.print_modifiers_and_trait_path()),
+            ),
+            (Some(_), Some((_, []))) => (
+                generics.span.shrink_to_hi(),
+                format!(": {}", trait_pred.print_modifiers_and_trait_path()),
             ),
-            (None, Some((ident, []))) => {
-                (ident.span.shrink_to_hi(), format!(": {}", trait_ref.print_only_trait_path()))
-            }
-            (_, Some((_, [.., bounds]))) => {
-                (bounds.span().shrink_to_hi(), format!(" + {}", trait_ref.print_only_trait_path()))
-            }
-            (Some(_), Some((_, []))) => {
-                (generics.span.shrink_to_hi(), format!(": {}", trait_ref.print_only_trait_path()))
-            }
         };
 
         err.span_suggestion_verbose(
@@ -329,10 +330,10 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
     fn suggest_restricting_param_bound(
         &self,
         mut err: &mut DiagnosticBuilder<'_>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
         body_id: hir::HirId,
     ) {
-        let self_ty = trait_ref.skip_binder().self_ty();
+        let self_ty = trait_pred.skip_binder().self_ty();
         let (param_ty, projection) = match self_ty.kind() {
             ty::Param(_) => (true, None),
             ty::Projection(projection) => (false, Some(projection)),
@@ -358,7 +359,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         err,
                         None,
                         projection,
-                        trait_ref,
+                        trait_pred,
                         Some((ident, bounds)),
                     );
                     return;
@@ -372,7 +373,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     assert!(param_ty);
                     // Restricting `Self` for a single method.
                     suggest_restriction(
-                        self.tcx, &generics, "`Self`", err, None, projection, trait_ref, None,
+                        self.tcx, &generics, "`Self`", err, None, projection, trait_pred, None,
                     );
                     return;
                 }
@@ -398,7 +399,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         err,
                         Some(fn_sig),
                         projection,
-                        trait_ref,
+                        trait_pred,
                         None,
                     );
                     return;
@@ -417,7 +418,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         err,
                         None,
                         projection,
-                        trait_ref,
+                        trait_pred,
                         None,
                     );
                     return;
@@ -442,15 +443,16 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 {
                     // Missing generic type parameter bound.
                     let param_name = self_ty.to_string();
-                    let constraint =
-                        with_no_trimmed_paths(|| trait_ref.print_only_trait_path().to_string());
+                    let constraint = with_no_trimmed_paths(|| {
+                        trait_pred.print_modifiers_and_trait_path().to_string()
+                    });
                     if suggest_constraining_type_param(
                         self.tcx,
                         generics,
                         &mut err,
                         &param_name,
                         &constraint,
-                        Some(trait_ref.def_id()),
+                        Some(trait_pred.def_id()),
                     ) {
                         return;
                     }
@@ -471,7 +473,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 }) if !param_ty => {
                     // Missing generic type parameter bound.
                     let param_name = self_ty.to_string();
-                    let constraint = trait_ref.print_only_trait_path().to_string();
+                    let constraint = trait_pred.print_modifiers_and_trait_path().to_string();
                     if suggest_arbitrary_trait_bound(generics, &mut err, &param_name, &constraint) {
                         return;
                     }
@@ -492,7 +494,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'tcx>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) {
         // It only make sense when suggesting dereferences for arguments
         let code = if let ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } =
@@ -505,13 +507,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         let param_env = obligation.param_env;
         let body_id = obligation.cause.body_id;
         let span = obligation.cause.span;
-        let real_trait_ref = match &*code {
+        let real_trait_pred = match &*code {
             ObligationCauseCode::ImplDerivedObligation(cause)
             | ObligationCauseCode::DerivedObligation(cause)
-            | ObligationCauseCode::BuiltinDerivedObligation(cause) => cause.parent_trait_ref,
-            _ => trait_ref,
+            | ObligationCauseCode::BuiltinDerivedObligation(cause) => cause.parent_trait_pred,
+            _ => trait_pred,
         };
-        let real_ty = match real_trait_ref.self_ty().no_bound_vars() {
+        let real_ty = match real_trait_pred.self_ty().no_bound_vars() {
             Some(ty) => ty,
             None => return,
         };
@@ -522,7 +524,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 // Re-add the `&`
                 let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
                 let obligation =
-                    self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_ref, ty);
+                    self.mk_trait_obligation_with_new_self_ty(param_env, real_trait_pred, ty);
                 Some(steps).filter(|_| self.predicate_may_hold(&obligation))
             }) {
                 if steps > 0 {
@@ -589,9 +591,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
-        trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) {
-        let self_ty = match trait_ref.self_ty().no_bound_vars() {
+        let self_ty = match trait_pred.self_ty().no_bound_vars() {
             None => return,
             Some(ty) => ty,
         };
@@ -611,7 +613,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         };
 
         let new_obligation =
-            self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_ref, output_ty);
+            self.mk_trait_obligation_with_new_self_ty(obligation.param_env, trait_pred, output_ty);
 
         match self.evaluate_obligation(&new_obligation) {
             Ok(
@@ -682,7 +684,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
-        poly_trait_ref: &ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        poly_trait_pred: ty::PolyTraitPredicate<'tcx>,
         has_custom_message: bool,
     ) -> bool {
         let span = obligation.cause.span;
@@ -715,24 +717,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         let param_env = obligation.param_env;
 
         // Try to apply the original trait binding obligation by borrowing.
-        let mut try_borrowing = |old_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        let mut try_borrowing = |old_pred: ty::PolyTraitPredicate<'tcx>,
                                  blacklist: &[DefId]|
          -> bool {
-            if blacklist.contains(&old_ref.def_id()) {
+            if blacklist.contains(&old_pred.def_id()) {
                 return false;
             }
 
-            let orig_ty = old_ref.self_ty().skip_binder();
+            let orig_ty = old_pred.self_ty().skip_binder();
             let mk_result = |new_ty| {
-                let new_ref = old_ref.rebind(ty::TraitRef::new(
-                    old_ref.def_id(),
-                    self.tcx.mk_substs_trait(new_ty, &old_ref.skip_binder().substs[1..]),
-                ));
-                self.predicate_must_hold_modulo_regions(&Obligation::new(
-                    ObligationCause::dummy(),
-                    param_env,
-                    new_ref.without_const().to_predicate(self.tcx),
-                ))
+                let obligation =
+                    self.mk_trait_obligation_with_new_self_ty(param_env, old_pred, new_ty);
+                self.predicate_must_hold_modulo_regions(&obligation)
             };
             let imm_result = mk_result(self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, orig_ty));
             let mut_result = mk_result(self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, orig_ty));
@@ -748,7 +744,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     let msg = format!(
                         "the trait bound `{}: {}` is not satisfied",
                         orig_ty,
-                        old_ref.print_only_trait_path(),
+                        old_pred.print_modifiers_and_trait_path(),
                     );
                     if has_custom_message {
                         err.note(&msg);
@@ -764,7 +760,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         span,
                         &format!(
                             "expected an implementor of trait `{}`",
-                            old_ref.print_only_trait_path(),
+                            old_pred.print_modifiers_and_trait_path(),
                         ),
                     );
 
@@ -806,11 +802,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         };
 
         if let ObligationCauseCode::ImplDerivedObligation(obligation) = code {
-            try_borrowing(obligation.parent_trait_ref, &[])
+            try_borrowing(obligation.parent_trait_pred, &[])
         } else if let ObligationCauseCode::BindingObligation(_, _)
         | ObligationCauseCode::ItemObligation(_) = code
         {
-            try_borrowing(*poly_trait_ref, &never_suggest_borrow)
+            try_borrowing(poly_trait_pred, &never_suggest_borrow)
         } else {
             false
         }
@@ -822,7 +818,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
-        trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) {
         let span = obligation.cause.span;
 
@@ -834,45 +830,44 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 return;
             }
 
-            let mut suggested_ty = match trait_ref.self_ty().no_bound_vars() {
+            let mut suggested_ty = match trait_pred.self_ty().no_bound_vars() {
                 Some(ty) => ty,
                 None => return,
             };
 
             for refs_remaining in 0..refs_number {
-                if let ty::Ref(_, inner_ty, _) = suggested_ty.kind() {
-                    suggested_ty = inner_ty;
+                let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
+                    break;
+                };
+                suggested_ty = inner_ty;
 
-                    let new_obligation = self.mk_trait_obligation_with_new_self_ty(
-                        obligation.param_env,
-                        trait_ref,
-                        suggested_ty,
-                    );
+                let new_obligation = self.mk_trait_obligation_with_new_self_ty(
+                    obligation.param_env,
+                    trait_pred,
+                    suggested_ty,
+                );
 
-                    if self.predicate_may_hold(&new_obligation) {
-                        let sp = self
-                            .tcx
-                            .sess
-                            .source_map()
-                            .span_take_while(span, |c| c.is_whitespace() || *c == '&');
+                if self.predicate_may_hold(&new_obligation) {
+                    let sp = self
+                        .tcx
+                        .sess
+                        .source_map()
+                        .span_take_while(span, |c| c.is_whitespace() || *c == '&');
 
-                        let remove_refs = refs_remaining + 1;
+                    let remove_refs = refs_remaining + 1;
 
-                        let msg = if remove_refs == 1 {
-                            "consider removing the leading `&`-reference".to_string()
-                        } else {
-                            format!("consider removing {} leading `&`-references", remove_refs)
-                        };
+                    let msg = if remove_refs == 1 {
+                        "consider removing the leading `&`-reference".to_string()
+                    } else {
+                        format!("consider removing {} leading `&`-references", remove_refs)
+                    };
 
-                        err.span_suggestion_short(
-                            sp,
-                            &msg,
-                            String::new(),
-                            Applicability::MachineApplicable,
-                        );
-                        break;
-                    }
-                } else {
+                    err.span_suggestion_short(
+                        sp,
+                        &msg,
+                        String::new(),
+                        Applicability::MachineApplicable,
+                    );
                     break;
                 }
             }
@@ -942,7 +937,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         &self,
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
-        trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) {
         let points_at_arg = matches!(
             obligation.cause.code(),
@@ -957,14 +952,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 // Do not suggest removal of borrow from type arguments.
                 return;
             }
-            let trait_ref = self.resolve_vars_if_possible(trait_ref);
-            if trait_ref.has_infer_types_or_consts() {
+            let trait_pred = self.resolve_vars_if_possible(trait_pred);
+            if trait_pred.has_infer_types_or_consts() {
                 // Do not ICE while trying to find if a reborrow would succeed on a trait with
                 // unresolved bindings.
                 return;
             }
 
-            if let ty::Ref(region, t_type, mutability) = *trait_ref.skip_binder().self_ty().kind() {
+            if let ty::Ref(region, t_type, mutability) = *trait_pred.skip_binder().self_ty().kind()
+            {
                 if region.is_late_bound() || t_type.has_escaping_bound_vars() {
                     // Avoid debug assertion in `mk_obligation_for_def_id`.
                     //
@@ -981,7 +977,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
 
                 let new_obligation = self.mk_trait_obligation_with_new_self_ty(
                     obligation.param_env,
-                    trait_ref,
+                    trait_pred,
                     suggested_ty,
                 );
                 let suggested_ty_would_satisfy_obligation = self
@@ -1003,9 +999,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     } else {
                         err.note(&format!(
                             "`{}` is implemented for `{:?}`, but not for `{:?}`",
-                            trait_ref.print_only_trait_path(),
+                            trait_pred.print_modifiers_and_trait_path(),
                             suggested_ty,
-                            trait_ref.skip_binder().self_ty(),
+                            trait_pred.skip_binder().self_ty(),
                         ));
                     }
                 }
@@ -1018,7 +1014,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         obligation: &PredicateObligation<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
         span: Span,
-        trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) {
         let is_empty_tuple =
             |ty: ty::Binder<'tcx, Ty<'_>>| *ty.skip_binder().kind() == ty::Tuple(ty::List::empty());
@@ -1034,7 +1030,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             if let hir::ExprKind::Block(blk, _) = &body.value.kind {
                 if sig.decl.output.span().overlaps(span)
                     && blk.expr.is_none()
-                    && is_empty_tuple(trait_ref.self_ty())
+                    && is_empty_tuple(trait_pred.self_ty())
                 {
                     // FIXME(estebank): When encountering a method with a trait
                     // bound not satisfied in the return type with a body that has
@@ -1070,7 +1066,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         err: &mut DiagnosticBuilder<'_>,
         span: Span,
         obligation: &PredicateObligation<'tcx>,
-        trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool {
         match obligation.cause.code().peel_derives() {
             // Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`.
@@ -1089,8 +1085,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             return false;
         };
         let body = hir.body(*body_id);
-        let trait_ref = self.resolve_vars_if_possible(trait_ref);
-        let ty = trait_ref.skip_binder().self_ty();
+        let trait_pred = self.resolve_vars_if_possible(trait_pred);
+        let ty = trait_pred.skip_binder().self_ty();
         let is_object_safe = match ty.kind() {
             ty::Dynamic(predicates, _) => {
                 // If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
@@ -1327,9 +1323,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             trait_ref.rebind(sig).to_string()
         }
 
-        let argument_kind = match expected_ref.skip_binder().substs.type_at(0) {
-            t if t.is_closure() => "closure",
-            t if t.is_generator() => "generator",
+        let argument_kind = match expected_ref.skip_binder().self_ty().kind() {
+            ty::Closure(..) => "closure",
+            ty::Generator(..) => "generator",
             _ => "function",
         };
         let mut err = struct_span_err!(
@@ -1368,7 +1364,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 err.span_suggestion(
                     span,
                     "use the fully qualified path to an implementation",
-                    format!("<Type as {}>::{}", self.tcx.def_path_str(trait_ref), assoc_item.ident),
+                    format!("<Type as {}>::{}", self.tcx.def_path_str(trait_ref), assoc_item.name),
                     Applicability::HasPlaceholders,
                 );
             }
@@ -1456,7 +1452,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         // bound was introduced. At least one generator should be present for this diagnostic to be
         // modified.
         let (mut trait_ref, mut target_ty) = match obligation.predicate.kind().skip_binder() {
-            ty::PredicateKind::Trait(p) => (Some(p.trait_ref), Some(p.self_ty())),
+            ty::PredicateKind::Trait(p) => (Some(p), Some(p.self_ty())),
             _ => (None, None),
         };
         let mut generator = None;
@@ -1474,11 +1470,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 ObligationCauseCode::DerivedObligation(derived_obligation)
                 | ObligationCauseCode::BuiltinDerivedObligation(derived_obligation)
                 | ObligationCauseCode::ImplDerivedObligation(derived_obligation) => {
-                    let ty = derived_obligation.parent_trait_ref.skip_binder().self_ty();
+                    let ty = derived_obligation.parent_trait_pred.skip_binder().self_ty();
                     debug!(
                         "maybe_note_obligation_cause_for_async_await: \
                             parent_trait_ref={:?} self_ty.kind={:?}",
-                        derived_obligation.parent_trait_ref,
+                        derived_obligation.parent_trait_pred,
                         ty.kind()
                     );
 
@@ -1496,7 +1492,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                             seen_upvar_tys_infer_tuple = true;
                         }
                         _ if generator.is_none() => {
-                            trait_ref = Some(derived_obligation.parent_trait_ref.skip_binder());
+                            trait_ref = Some(derived_obligation.parent_trait_pred.skip_binder());
                             target_ty = Some(ty);
                         }
                         _ => {}
@@ -1652,7 +1648,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         interior_extra_info: Option<(Option<Span>, Span, Option<hir::HirId>, Option<Span>)>,
         inner_generator_body: Option<&hir::Body<'tcx>>,
         outer_generator: Option<DefId>,
-        trait_ref: ty::TraitRef<'tcx>,
+        trait_pred: ty::TraitPredicate<'tcx>,
         target_ty: Ty<'tcx>,
         typeck_results: Option<&ty::TypeckResults<'tcx>>,
         obligation: &PredicateObligation<'tcx>,
@@ -1672,7 +1668,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         // not implemented.
         let hir = self.tcx.hir();
         let trait_explanation = if let Some(name @ (sym::Send | sym::Sync)) =
-            self.tcx.get_diagnostic_name(trait_ref.def_id)
+            self.tcx.get_diagnostic_name(trait_pred.def_id())
         {
             let (trait_name, trait_verb) =
                 if name == sym::Send { ("`Send`", "sent") } else { ("`Sync`", "shared") };
@@ -1714,7 +1710,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
 
             format!("is not {}", trait_name)
         } else {
-            format!("does not implement `{}`", trait_ref.print_only_trait_path())
+            format!("does not implement `{}`", trait_pred.print_modifiers_and_trait_path())
         };
 
         let mut explain_yield = |interior_span: Span,
@@ -1895,6 +1891,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         self.note_obligation_cause_code(
             err,
             &obligation.predicate,
+            obligation.param_env,
             next_code.unwrap(),
             &mut Vec::new(),
             &mut Default::default(),
@@ -1905,6 +1902,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         &self,
         err: &mut DiagnosticBuilder<'_>,
         predicate: &T,
+        param_env: ty::ParamEnv<'tcx>,
         cause_code: &ObligationCauseCode<'tcx>,
         obligated_types: &mut Vec<&ty::TyS<'tcx>>,
         seen_requirements: &mut FxHashSet<DefId>,
@@ -2135,7 +2133,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 err.note("shared static variables must have a type that implements `Sync`");
             }
             ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
-                let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
+                let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
                 let ty = parent_trait_ref.skip_binder().self_ty();
                 if parent_trait_ref.references_error() {
                     err.cancel();
@@ -2150,7 +2148,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     if let ObligationCauseCode::BuiltinDerivedObligation(ref data) =
                         *data.parent_code
                     {
-                        let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
+                        let parent_trait_ref =
+                            self.resolve_vars_if_possible(data.parent_trait_pred);
                         let ty = parent_trait_ref.skip_binder().self_ty();
                         matches!(ty.kind(), ty::Generator(..))
                             || matches!(ty.kind(), ty::Closure(..))
@@ -2173,13 +2172,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
 
                 obligated_types.push(ty);
 
-                let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx);
+                let parent_predicate = parent_trait_ref.to_predicate(tcx);
                 if !self.is_recursive_obligation(obligated_types, &data.parent_code) {
                     // #74711: avoid a stack overflow
                     ensure_sufficient_stack(|| {
                         self.note_obligation_cause_code(
                             err,
                             &parent_predicate,
+                            param_env,
                             &data.parent_code,
                             obligated_types,
                             seen_requirements,
@@ -2190,6 +2190,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                         self.note_obligation_cause_code(
                             err,
                             &parent_predicate,
+                            param_env,
                             &cause_code.peel_derives(),
                             obligated_types,
                             seen_requirements,
@@ -2198,17 +2199,18 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 }
             }
             ObligationCauseCode::ImplDerivedObligation(ref data) => {
-                let mut parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
-                let parent_def_id = parent_trait_ref.def_id();
+                let mut parent_trait_pred = self.resolve_vars_if_possible(data.parent_trait_pred);
+                parent_trait_pred.remap_constness_diag(param_env);
+                let parent_def_id = parent_trait_pred.def_id();
                 let msg = format!(
                     "required because of the requirements on the impl of `{}` for `{}`",
-                    parent_trait_ref.print_only_trait_path(),
-                    parent_trait_ref.skip_binder().self_ty()
+                    parent_trait_pred.print_modifiers_and_trait_path(),
+                    parent_trait_pred.skip_binder().self_ty()
                 );
                 let mut candidates = vec![];
                 self.tcx.for_each_relevant_impl(
                     parent_def_id,
-                    parent_trait_ref.self_ty().skip_binder(),
+                    parent_trait_pred.self_ty().skip_binder(),
                     |impl_def_id| match self.tcx.hir().get_if_local(impl_def_id) {
                         Some(Node::Item(hir::Item {
                             kind: hir::ItemKind::Impl(hir::Impl { .. }),
@@ -2237,21 +2239,21 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     _ => err.note(&msg),
                 };
 
-                let mut parent_predicate = parent_trait_ref.without_const().to_predicate(tcx);
+                let mut parent_predicate = parent_trait_pred.to_predicate(tcx);
                 let mut data = data;
                 let mut count = 0;
                 seen_requirements.insert(parent_def_id);
                 while let ObligationCauseCode::ImplDerivedObligation(child) = &*data.parent_code {
                     // Skip redundant recursive obligation notes. See `ui/issue-20413.rs`.
-                    let child_trait_ref = self.resolve_vars_if_possible(child.parent_trait_ref);
-                    let child_def_id = child_trait_ref.def_id();
+                    let child_trait_pred = self.resolve_vars_if_possible(child.parent_trait_pred);
+                    let child_def_id = child_trait_pred.def_id();
                     if seen_requirements.insert(child_def_id) {
                         break;
                     }
                     count += 1;
                     data = child;
-                    parent_predicate = child_trait_ref.without_const().to_predicate(tcx);
-                    parent_trait_ref = child_trait_ref;
+                    parent_predicate = child_trait_pred.to_predicate(tcx);
+                    parent_trait_pred = child_trait_pred;
                 }
                 if count > 0 {
                     err.note(&format!(
@@ -2261,8 +2263,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     ));
                     err.note(&format!(
                         "required because of the requirements on the impl of `{}` for `{}`",
-                        parent_trait_ref.print_only_trait_path(),
-                        parent_trait_ref.skip_binder().self_ty()
+                        parent_trait_pred.print_modifiers_and_trait_path(),
+                        parent_trait_pred.skip_binder().self_ty()
                     ));
                 }
                 // #74711: avoid a stack overflow
@@ -2270,6 +2272,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     self.note_obligation_cause_code(
                         err,
                         &parent_predicate,
+                        param_env,
                         &data.parent_code,
                         obligated_types,
                         seen_requirements,
@@ -2277,13 +2280,14 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 });
             }
             ObligationCauseCode::DerivedObligation(ref data) => {
-                let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_ref);
-                let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx);
+                let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
+                let parent_predicate = parent_trait_ref.to_predicate(tcx);
                 // #74711: avoid a stack overflow
                 ensure_sufficient_stack(|| {
                     self.note_obligation_cause_code(
                         err,
                         &parent_predicate,
+                        param_env,
                         &data.parent_code,
                         obligated_types,
                         seen_requirements,
@@ -2337,6 +2341,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                     self.note_obligation_cause_code(
                         err,
                         predicate,
+                        param_env,
                         &parent_code,
                         obligated_types,
                         seen_requirements,
@@ -2427,15 +2432,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         &self,
         err: &mut DiagnosticBuilder<'_>,
         obligation: &PredicateObligation<'tcx>,
-        trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
         span: Span,
     ) {
         debug!(
-            "suggest_await_before_try: obligation={:?}, span={:?}, trait_ref={:?}, trait_ref_self_ty={:?}",
+            "suggest_await_before_try: obligation={:?}, span={:?}, trait_pred={:?}, trait_pred_self_ty={:?}",
             obligation,
             span,
-            trait_ref,
-            trait_ref.self_ty()
+            trait_pred,
+            trait_pred.self_ty()
         );
         let body_hir_id = obligation.cause.body_id;
         let item_id = self.tcx.hir().get_parent_node(body_hir_id);
@@ -2445,7 +2450,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind {
                 let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
 
-                let self_ty = self.resolve_vars_if_possible(trait_ref.self_ty());
+                let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
 
                 // Do not check on infer_types to avoid panic in evaluate_obligation.
                 if self_ty.has_infer_types() {
@@ -2465,7 +2470,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 let projection_ty = ty::ProjectionTy {
                     // `T`
                     substs: self.tcx.mk_substs_trait(
-                        trait_ref.self_ty().skip_binder(),
+                        trait_pred.self_ty().skip_binder(),
                         self.fresh_substs_for_item(span, item_def_id),
                     ),
                     // `Future::Output`
@@ -2490,7 +2495,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 );
                 let try_obligation = self.mk_trait_obligation_with_new_self_ty(
                     obligation.param_env,
-                    trait_ref,
+                    trait_pred,
                     normalized_ty,
                 );
                 debug!("suggest_await_before_try: try_trait_obligation {:?}", try_obligation);
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 23f534858b8..2927e64f705 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -291,7 +291,7 @@ pub fn normalize_param_env_or_error<'tcx>(
     //
     // In any case, in practice, typeck constructs all the
     // parameter environments once for every fn as it goes,
-    // and errors will get reported then; so after typeck we
+    // and errors will get reported then; so outside of type inference we
     // can be sure that no errors should occur.
 
     debug!(
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 7bfedecbdc7..7818053218d 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -89,7 +89,7 @@ fn object_safety_violations_for_trait(
         .filter(|item| item.kind == ty::AssocKind::Fn)
         .filter_map(|item| {
             object_safety_violation_for_method(tcx, trait_def_id, &item)
-                .map(|(code, span)| ObjectSafetyViolation::Method(item.ident.name, code, span))
+                .map(|(code, span)| ObjectSafetyViolation::Method(item.name, code, span))
         })
         .filter(|violation| {
             if let ObjectSafetyViolation::Method(
@@ -125,7 +125,10 @@ fn object_safety_violations_for_trait(
         tcx.associated_items(trait_def_id)
             .in_definition_order()
             .filter(|item| item.kind == ty::AssocKind::Const)
-            .map(|item| ObjectSafetyViolation::AssocConst(item.ident.name, item.ident.span)),
+            .map(|item| {
+                let ident = item.ident(tcx);
+                ObjectSafetyViolation::AssocConst(ident.name, ident.span)
+            }),
     );
 
     violations.extend(
@@ -133,7 +136,10 @@ fn object_safety_violations_for_trait(
             .in_definition_order()
             .filter(|item| item.kind == ty::AssocKind::Type)
             .filter(|item| !tcx.generics_of(item.def_id).params.is_empty())
-            .map(|item| ObjectSafetyViolation::GAT(item.ident.name, item.ident.span)),
+            .map(|item| {
+                let ident = item.ident(tcx);
+                ObjectSafetyViolation::GAT(ident.name, ident.span)
+            }),
     );
 
     debug!(
@@ -367,15 +373,15 @@ fn object_safety_violation_for_method(
             (MethodViolationCode::ReferencesSelfInput(arg), Some(node)) => node
                 .fn_decl()
                 .and_then(|decl| decl.inputs.get(arg + 1))
-                .map_or(method.ident.span, |arg| arg.span),
+                .map_or(method.ident(tcx).span, |arg| arg.span),
             (MethodViolationCode::UndispatchableReceiver, Some(node)) => node
                 .fn_decl()
                 .and_then(|decl| decl.inputs.get(0))
-                .map_or(method.ident.span, |arg| arg.span),
+                .map_or(method.ident(tcx).span, |arg| arg.span),
             (MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
-                node.fn_decl().map_or(method.ident.span, |decl| decl.output.span())
+                node.fn_decl().map_or(method.ident(tcx).span, |decl| decl.output.span())
             }
-            _ => method.ident.span,
+            _ => method.ident(tcx).span,
         };
         (v, span)
     })
@@ -404,10 +410,10 @@ fn virtual_call_violation_for_method<'tcx>(
             );
         // Get the span pointing at where the `self` receiver should be.
         let sm = tcx.sess.source_map();
-        let self_span = method.ident.span.to(tcx
+        let self_span = method.ident(tcx).span.to(tcx
             .hir()
             .span_if_local(method.def_id)
-            .unwrap_or_else(|| sm.next_point(method.ident.span))
+            .unwrap_or_else(|| sm.next_point(method.ident(tcx).span))
             .shrink_to_hi());
         let self_span = sm.span_through_char(self_span, '(').shrink_to_hi();
         return Some(MethodViolationCode::StaticMethod(
diff --git a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
index 4840995275a..6b20476b955 100644
--- a/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs
@@ -19,6 +19,7 @@ pub struct OnUnimplementedDirective {
     pub label: Option<OnUnimplementedFormatString>,
     pub note: Option<OnUnimplementedFormatString>,
     pub enclosing_scope: Option<OnUnimplementedFormatString>,
+    pub append_const_msg: Option<Option<Symbol>>,
 }
 
 #[derive(Default)]
@@ -27,6 +28,11 @@ pub struct OnUnimplementedNote {
     pub label: Option<String>,
     pub note: Option<String>,
     pub enclosing_scope: Option<String>,
+    /// Append a message for `~const Trait` errors. `None` means not requested and
+    /// should fallback to a generic message, `Some(None)` suggests using the default
+    /// appended message, `Some(Some(s))` suggests use the `s` message instead of the
+    /// default one..
+    pub append_const_msg: Option<Option<Symbol>>,
 }
 
 fn parse_error(
@@ -89,6 +95,7 @@ impl<'tcx> OnUnimplementedDirective {
         let mut note = None;
         let mut enclosing_scope = None;
         let mut subcommands = vec![];
+        let mut append_const_msg = None;
 
         let parse_value = |value_str| {
             OnUnimplementedFormatString::try_parse(tcx, trait_def_id, value_str, span).map(Some)
@@ -131,6 +138,14 @@ impl<'tcx> OnUnimplementedDirective {
                     }
                     continue;
                 }
+            } else if item.has_name(sym::append_const_msg) && append_const_msg.is_none() {
+                if let Some(msg) = item.value_str() {
+                    append_const_msg = Some(Some(msg));
+                    continue;
+                } else if item.is_word() {
+                    append_const_msg = Some(None);
+                    continue;
+                }
             }
 
             // nothing found
@@ -153,6 +168,7 @@ impl<'tcx> OnUnimplementedDirective {
                 label,
                 note,
                 enclosing_scope,
+                append_const_msg,
             })
         }
     }
@@ -183,6 +199,7 @@ impl<'tcx> OnUnimplementedDirective {
                 )?),
                 note: None,
                 enclosing_scope: None,
+                append_const_msg: None,
             }))
         } else {
             return Err(ErrorReported);
@@ -201,6 +218,7 @@ impl<'tcx> OnUnimplementedDirective {
         let mut label = None;
         let mut note = None;
         let mut enclosing_scope = None;
+        let mut append_const_msg = None;
         info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
 
         for command in self.subcommands.iter().chain(Some(self)).rev() {
@@ -235,6 +253,8 @@ impl<'tcx> OnUnimplementedDirective {
             if let Some(ref enclosing_scope_) = command.enclosing_scope {
                 enclosing_scope = Some(enclosing_scope_.clone());
             }
+
+            append_const_msg = command.append_const_msg.clone();
         }
 
         let options: FxHashMap<Symbol, String> =
@@ -244,6 +264,7 @@ impl<'tcx> OnUnimplementedDirective {
             message: message.map(|m| m.format(tcx, trait_ref, &options)),
             note: note.map(|n| n.format(tcx, trait_ref, &options)),
             enclosing_scope: enclosing_scope.map(|e_s| e_s.format(tcx, trait_ref, &options)),
+            append_const_msg,
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index f49f53351aa..087fc6034d9 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -391,7 +391,7 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
             // severe performance implications for large opaque types with
             // late-bound regions. See `issue-88862` benchmark.
             ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
-                // Only normalize `impl Trait` after type-checking, usually in codegen.
+                // Only normalize `impl Trait` outside of type inference, usually in codegen.
                 match self.param_env.reveal() {
                     Reveal::UserFacing => ty.super_fold_with(self),
 
@@ -1600,7 +1600,7 @@ fn confirm_generator_candidate<'cx, 'tcx>(
         gen_sig,
     )
     .map_bound(|(trait_ref, yield_ty, return_ty)| {
-        let name = tcx.associated_item(obligation.predicate.item_def_id).ident.name;
+        let name = tcx.associated_item(obligation.predicate.item_def_id).name;
         let ty = if name == sym::Return {
             return_ty
         } else if name == sym::Yield {
@@ -1842,7 +1842,7 @@ fn confirm_impl_candidate<'cx, 'tcx>(
         // just return Error.
         debug!(
             "confirm_impl_candidate: no associated type {:?} for {:?}",
-            assoc_ty.item.ident, obligation.predicate
+            assoc_ty.item.name, obligation.predicate
         );
         return Progress { ty: tcx.ty_error(), obligations: nested };
     }
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 81ee22c1de4..3c9e1bbcef2 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -200,7 +200,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
             // severe performance implications for large opaque types with
             // late-bound regions. See `issue-88862` benchmark.
             ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
-                // Only normalize `impl Trait` after type-checking, usually in codegen.
+                // Only normalize `impl Trait` outside of type inference, usually in codegen.
                 match self.param_env.reveal() {
                     Reveal::UserFacing => ty.try_super_fold_with(self),
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index b573c4b4390..db86041f618 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -305,15 +305,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             } else if lang_items.unsize_trait() == Some(def_id) {
                 self.assemble_candidates_for_unsizing(obligation, &mut candidates);
             } else if lang_items.drop_trait() == Some(def_id)
-                && obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst
+                && obligation.predicate.is_const_if_const()
             {
-                if obligation.param_env.constness() == hir::Constness::Const {
-                    self.assemble_const_drop_candidates(obligation, stack, &mut candidates)?;
-                } else {
-                    debug!("passing ~const Drop bound; in non-const context");
-                    // `~const Drop` when we are not in a const context has no effect.
-                    candidates.vec.push(ConstDropCandidate)
-                }
+                self.assemble_const_drop_candidates(obligation, &mut candidates);
             } else {
                 if lang_items.clone_trait() == Some(def_id) {
                     // Same builtin conditions as `Copy`, i.e., every type which has builtin support
@@ -918,139 +912,77 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
     }
 
-    fn assemble_const_drop_candidates<'a>(
+    fn assemble_const_drop_candidates(
         &mut self,
         obligation: &TraitObligation<'tcx>,
-        obligation_stack: &TraitObligationStack<'a, 'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
-    ) -> Result<(), SelectionError<'tcx>> {
-        let mut stack: Vec<(Ty<'tcx>, usize)> = vec![(obligation.self_ty().skip_binder(), 0)];
-
-        while let Some((ty, depth)) = stack.pop() {
-            let mut noreturn = false;
-
-            self.check_recursion_depth(depth, obligation)?;
-            let mut new_candidates = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
-            let mut copy_obligation =
-                obligation.with(obligation.predicate.rebind(ty::TraitPredicate {
-                    trait_ref: ty::TraitRef {
-                        def_id: self.tcx().require_lang_item(hir::LangItem::Copy, None),
-                        substs: self.tcx().mk_substs_trait(ty, &[]),
-                    },
-                    constness: ty::BoundConstness::NotConst,
-                    polarity: ty::ImplPolarity::Positive,
-                }));
-            copy_obligation.recursion_depth = depth + 1;
-            self.assemble_candidates_from_impls(&copy_obligation, &mut new_candidates);
-            let copy_conditions = self.copy_clone_conditions(&copy_obligation);
-            self.assemble_builtin_bound_candidates(copy_conditions, &mut new_candidates);
-            let copy_stack = self.push_stack(obligation_stack.list(), &copy_obligation);
-            self.assemble_candidates_from_caller_bounds(&copy_stack, &mut new_candidates)?;
-
-            let const_drop_obligation =
-                obligation.with(obligation.predicate.rebind(ty::TraitPredicate {
-                    trait_ref: ty::TraitRef {
-                        def_id: self.tcx().require_lang_item(hir::LangItem::Drop, None),
-                        substs: self.tcx().mk_substs_trait(ty, &[]),
-                    },
-                    constness: ty::BoundConstness::ConstIfConst,
-                    polarity: ty::ImplPolarity::Positive,
-                }));
-
-            let const_drop_stack = self.push_stack(obligation_stack.list(), &const_drop_obligation);
-            self.assemble_candidates_from_caller_bounds(&const_drop_stack, &mut new_candidates)?;
-
-            if !new_candidates.vec.is_empty() {
-                noreturn = true;
-            }
-            debug!(?new_candidates.vec, "assemble_const_drop_candidates");
-
-            match ty.kind() {
-                ty::Int(_)
-                | ty::Uint(_)
-                | ty::Float(_)
-                | ty::Infer(ty::IntVar(_))
-                | ty::Infer(ty::FloatVar(_))
-                | ty::FnPtr(_)
-                | ty::Never
-                | ty::Ref(..)
-                | ty::FnDef(..)
-                | ty::RawPtr(_)
-                | ty::Bool
-                | ty::Char
-                | ty::Str
-                | ty::Foreign(_) => {} // Do nothing. These types satisfy `const Drop`.
-
-                ty::Adt(def, subst) => {
-                    let mut set = SelectionCandidateSet { vec: Vec::new(), ambiguous: false };
-                    self.assemble_candidates_from_impls(
-                        &obligation.with(obligation.predicate.map_bound(|mut pred| {
-                            pred.trait_ref.substs = self.tcx().mk_substs_trait(ty, &[]);
-                            pred
-                        })),
-                        &mut set,
-                    );
-                    stack.extend(def.all_fields().map(|f| (f.ty(self.tcx(), subst), depth + 1)));
-
-                    debug!(?set.vec, "assemble_const_drop_candidates - ty::Adt");
-                    if set.vec.into_iter().any(|candidate| {
-                        if let SelectionCandidate::ImplCandidate(did) = candidate {
-                            matches!(self.tcx().impl_constness(did), hir::Constness::NotConst)
-                        } else {
-                            false
-                        }
-                    }) {
-                        if !noreturn {
-                            // has non-const Drop
-                            return Ok(());
-                        }
-                        debug!("not returning");
-                    }
-                }
-
-                ty::Array(ty, _) => stack.push((ty, depth + 1)),
-
-                ty::Tuple(_) => stack.extend(ty.tuple_fields().map(|t| (t, depth + 1))),
+    ) {
+        // If the predicate is `~const Drop` in a non-const environment, we don't actually need
+        // to check anything. We'll short-circuit checking any obligations in confirmation, too.
+        if obligation.param_env.constness() == hir::Constness::NotConst {
+            candidates.vec.push(ConstDropCandidate(None));
+            return;
+        }
 
-                ty::Closure(_, substs) => {
-                    let substs = substs.as_closure();
-                    let ty = self.infcx.shallow_resolve(substs.tupled_upvars_ty());
-                    stack.push((ty, depth + 1));
-                }
+        let self_ty = self.infcx().shallow_resolve(obligation.self_ty());
+        match self_ty.skip_binder().kind() {
+            ty::Opaque(..)
+            | ty::Dynamic(..)
+            | ty::Error(_)
+            | ty::Bound(..)
+            | ty::Param(_)
+            | ty::Placeholder(_)
+            | ty::Projection(_) => {
+                // We don't know if these are `~const Drop`, at least
+                // not structurally... so don't push a candidate.
+            }
 
-                ty::Generator(_, substs, _) => {
-                    let substs = substs.as_generator();
-                    let ty = self.infcx.shallow_resolve(substs.tupled_upvars_ty());
+            ty::Bool
+            | ty::Char
+            | ty::Int(_)
+            | ty::Uint(_)
+            | ty::Float(_)
+            | ty::Infer(ty::IntVar(_))
+            | ty::Infer(ty::FloatVar(_))
+            | ty::Str
+            | ty::RawPtr(_)
+            | ty::Ref(..)
+            | ty::FnDef(..)
+            | ty::FnPtr(_)
+            | ty::Never
+            | ty::Foreign(_)
+            | ty::Array(..)
+            | ty::Slice(_)
+            | ty::Closure(..)
+            | ty::Generator(..)
+            | ty::Tuple(_)
+            | ty::GeneratorWitness(_) => {
+                // These are built-in, and cannot have a custom `impl const Drop`.
+                candidates.vec.push(ConstDropCandidate(None));
+            }
 
-                    stack.push((ty, depth + 1));
-                    stack.push((substs.witness(), depth + 1));
-                }
+            ty::Adt(..) => {
+                // Find a custom `impl Drop` impl, if it exists
+                let relevant_impl = self.tcx().find_map_relevant_impl(
+                    obligation.predicate.def_id(),
+                    obligation.predicate.skip_binder().trait_ref.self_ty(),
+                    Some,
+                );
 
-                ty::GeneratorWitness(tys) => stack.extend(
-                    self.tcx().erase_late_bound_regions(*tys).iter().map(|t| (t, depth + 1)),
-                ),
-
-                ty::Slice(ty) => stack.push((ty, depth + 1)),
-
-                ty::Opaque(..)
-                | ty::Dynamic(..)
-                | ty::Error(_)
-                | ty::Bound(..)
-                | ty::Infer(_)
-                | ty::Placeholder(_)
-                | ty::Projection(..)
-                | ty::Param(..) => {
-                    if !noreturn {
-                        return Ok(());
+                if let Some(impl_def_id) = relevant_impl {
+                    // Check that `impl Drop` is actually const, if there is a custom impl
+                    if self.tcx().impl_constness(impl_def_id) == hir::Constness::Const {
+                        candidates.vec.push(ConstDropCandidate(Some(impl_def_id)));
                     }
-                    debug!("not returning");
+                } else {
+                    // Otherwise check the ADT like a built-in type (structurally)
+                    candidates.vec.push(ConstDropCandidate(None));
                 }
             }
-            debug!(?stack, "assemble_const_drop_candidates - in loop");
-        }
-        // all types have passed.
-        candidates.vec.push(ConstDropCandidate);
 
-        Ok(())
+            ty::Infer(_) => {
+                candidates.ambiguous = true;
+            }
+        }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 669b6023397..639884844b2 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -72,15 +72,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // CheckPredicate(&A: Super)
         // CheckPredicate(A: ~const Super) // <- still const env, failure
         // ```
-        if obligation.param_env.constness() == Constness::Const
-            && obligation.predicate.skip_binder().constness == ty::BoundConstness::NotConst
-        {
+        if obligation.param_env.is_const() && !obligation.predicate.is_const_if_const() {
             new_obligation = TraitObligation {
                 cause: obligation.cause.clone(),
                 param_env: obligation.param_env.without_const(),
                 ..*obligation
             };
-
             obligation = &new_obligation;
         }
 
@@ -159,7 +156,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 Ok(ImplSource::TraitUpcasting(data))
             }
 
-            ConstDropCandidate => Ok(ImplSource::ConstDrop(ImplSourceConstDropData)),
+            ConstDropCandidate(def_id) => {
+                let data = self.confirm_const_drop_candidate(obligation, def_id)?;
+                Ok(ImplSource::ConstDrop(data))
+            }
         }
     }
 
@@ -657,7 +657,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             _ => bug!("closure candidate for non-closure {:?}", obligation),
         };
 
-        let obligation_predicate = obligation.predicate.to_poly_trait_ref();
+        let obligation_predicate = obligation.predicate;
         let Normalized { value: obligation_predicate, mut obligations } =
             ensure_sufficient_stack(|| {
                 normalize_with_depth(
@@ -687,7 +687,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         obligations.extend(self.confirm_poly_trait_refs(
             obligation.cause.clone(),
             obligation.param_env,
-            obligation_predicate,
+            obligation_predicate.to_poly_trait_ref(),
             trait_ref,
         )?);
 
@@ -1087,4 +1087,128 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         Ok(ImplSourceBuiltinData { nested })
     }
+
+    fn confirm_const_drop_candidate(
+        &mut self,
+        obligation: &TraitObligation<'tcx>,
+        impl_def_id: Option<DefId>,
+    ) -> Result<ImplSourceConstDropData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
+        // `~const Drop` in a non-const environment is always trivially true, since our type is `Drop`
+        if obligation.param_env.constness() == Constness::NotConst {
+            return Ok(ImplSourceConstDropData { nested: vec![] });
+        }
+
+        let tcx = self.tcx();
+        let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
+
+        let mut nested = vec![];
+        let cause = obligation.derived_cause(BuiltinDerivedObligation);
+
+        // If we have a custom `impl const Drop`, then
+        // first check it like a regular impl candidate
+        if let Some(impl_def_id) = impl_def_id {
+            nested.extend(self.confirm_impl_candidate(obligation, impl_def_id).nested);
+        }
+
+        // We want to confirm the ADT's fields if we have an ADT
+        let mut stack = match *self_ty.skip_binder().kind() {
+            ty::Adt(def, substs) => def.all_fields().map(|f| f.ty(tcx, substs)).collect(),
+            _ => vec![self_ty.skip_binder()],
+        };
+
+        while let Some(nested_ty) = stack.pop() {
+            match *nested_ty.kind() {
+                // We know these types are trivially drop
+                ty::Bool
+                | ty::Char
+                | ty::Int(_)
+                | ty::Uint(_)
+                | ty::Float(_)
+                | ty::Infer(ty::IntVar(_))
+                | ty::Infer(ty::FloatVar(_))
+                | ty::Str
+                | ty::RawPtr(_)
+                | ty::Ref(..)
+                | ty::FnDef(..)
+                | ty::FnPtr(_)
+                | ty::Never
+                | ty::Foreign(_) => {}
+
+                // These types are built-in, so we can fast-track by registering
+                // nested predicates for their constituient type(s)
+                ty::Array(ty, _) | ty::Slice(ty) => {
+                    stack.push(ty);
+                }
+                ty::Tuple(tys) => {
+                    stack.extend(tys.iter().map(|ty| ty.expect_ty()));
+                }
+                ty::Closure(_, substs) => {
+                    stack.push(substs.as_closure().tupled_upvars_ty());
+                }
+                ty::Generator(_, substs, _) => {
+                    let generator = substs.as_generator();
+                    stack.extend([generator.tupled_upvars_ty(), generator.witness()]);
+                }
+                ty::GeneratorWitness(tys) => {
+                    stack.extend(tcx.erase_late_bound_regions(tys).to_vec());
+                }
+
+                // If we have a projection type, make sure to normalize it so we replace it
+                // with a fresh infer variable
+                ty::Projection(..) => {
+                    self.infcx.commit_unconditionally(|_| {
+                        let predicate = normalize_with_depth_to(
+                            self,
+                            obligation.param_env,
+                            cause.clone(),
+                            obligation.recursion_depth + 1,
+                            self_ty
+                                .rebind(ty::TraitPredicate {
+                                    trait_ref: ty::TraitRef {
+                                        def_id: self.tcx().require_lang_item(LangItem::Drop, None),
+                                        substs: self.tcx().mk_substs_trait(nested_ty, &[]),
+                                    },
+                                    constness: ty::BoundConstness::ConstIfConst,
+                                    polarity: ty::ImplPolarity::Positive,
+                                })
+                                .to_predicate(tcx),
+                            &mut nested,
+                        );
+
+                        nested.push(Obligation::with_depth(
+                            cause.clone(),
+                            obligation.recursion_depth + 1,
+                            obligation.param_env,
+                            predicate,
+                        ));
+                    });
+                }
+
+                // If we have any other type (e.g. an ADT), just register a nested obligation
+                // since it's either not `const Drop` (and we raise an error during selection),
+                // or it's an ADT (and we need to check for a custom impl during selection)
+                _ => {
+                    let predicate = self_ty
+                        .rebind(ty::TraitPredicate {
+                            trait_ref: ty::TraitRef {
+                                def_id: self.tcx().require_lang_item(LangItem::Drop, None),
+                                substs: self.tcx().mk_substs_trait(nested_ty, &[]),
+                            },
+                            constness: ty::BoundConstness::ConstIfConst,
+                            polarity: ty::ImplPolarity::Positive,
+                        })
+                        .to_predicate(tcx);
+
+                    nested.push(Obligation::with_depth(
+                        cause.clone(),
+                        obligation.recursion_depth + 1,
+                        obligation.param_env,
+                        predicate,
+                    ));
+                }
+            }
+        }
+
+        Ok(ImplSourceConstDropData { nested })
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 1414c742635..47427395b93 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -765,14 +765,38 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             debug!(?result, "CACHE MISS");
             self.insert_evaluation_cache(param_env, fresh_trait_pred, dep_node, result);
 
-            stack.cache().on_completion(stack.dfn, |fresh_trait_pred, provisional_result| {
-                self.insert_evaluation_cache(
-                    param_env,
-                    fresh_trait_pred,
-                    dep_node,
-                    provisional_result.max(result),
-                );
-            });
+            stack.cache().on_completion(
+                stack.dfn,
+                |fresh_trait_pred, provisional_result, provisional_dep_node| {
+                    // Create a new `DepNode` that has dependencies on:
+                    // * The `DepNode` for the original evaluation that resulted in a provisional cache
+                    // entry being crated
+                    // * The `DepNode` for the *current* evaluation, which resulted in us completing
+                    // provisional caches entries and inserting them into the evaluation cache
+                    //
+                    // This ensures that when a query reads this entry from the evaluation cache,
+                    // it will end up (transitively) dependening on all of the incr-comp dependencies
+                    // created during the evaluation of this trait. For example, evaluating a trait
+                    // will usually require us to invoke `type_of(field_def_id)` to determine the
+                    // constituent types, and we want any queries reading from this evaluation
+                    // cache entry to end up with a transitive `type_of(field_def_id`)` dependency.
+                    //
+                    // By using `in_task`, we're also creating an edge from the *current* query
+                    // to the newly-created `combined_dep_node`. This is probably redundant,
+                    // but it's better to add too many dep graph edges than to add too few
+                    // dep graph edges.
+                    let ((), combined_dep_node) = self.in_task(|this| {
+                        this.tcx().dep_graph.read_index(provisional_dep_node);
+                        this.tcx().dep_graph.read_index(dep_node);
+                    });
+                    self.insert_evaluation_cache(
+                        param_env,
+                        fresh_trait_pred,
+                        combined_dep_node,
+                        provisional_result.max(result),
+                    );
+                },
+            );
         } else {
             debug!(?result, "PROVISIONAL");
             debug!(
@@ -781,7 +805,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 fresh_trait_pred, stack.depth, reached_depth,
             );
 
-            stack.cache().insert_provisional(stack.dfn, reached_depth, fresh_trait_pred, result);
+            stack.cache().insert_provisional(
+                stack.dfn,
+                reached_depth,
+                fresh_trait_pred,
+                result,
+                dep_node,
+            );
         }
 
         Ok(result)
@@ -1143,9 +1173,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     ImplCandidate(def_id)
                         if tcx.impl_constness(def_id) == hir::Constness::Const => {}
                     // const param
-                    ParamCandidate(trait_pred)
-                        if trait_pred.skip_binder().constness
-                            == ty::BoundConstness::ConstIfConst => {}
+                    ParamCandidate(trait_pred) if trait_pred.is_const_if_const() => {}
                     // auto trait impl
                     AutoImplCandidate(..) => {}
                     // generator, this will raise error in other places
@@ -1153,7 +1181,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     GeneratorCandidate => {}
                     // FnDef where the function is const
                     FnPointerCandidate { is_const: true } => {}
-                    ConstDropCandidate => {}
+                    ConstDropCandidate(_) => {}
                     _ => {
                         // reject all other types of candidates
                         continue;
@@ -1537,7 +1565,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         };
 
         // (*) Prefer `BuiltinCandidate { has_nested: false }`, `PointeeCandidate`,
-        // and `DiscriminantKindCandidate` to anything else.
+        // `DiscriminantKindCandidate`, and `ConstDropCandidate` to anything else.
         //
         // This is a fix for #53123 and prevents winnowing from accidentally extending the
         // lifetime of a variable.
@@ -1554,7 +1582,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 BuiltinCandidate { has_nested: false }
                 | DiscriminantKindCandidate
                 | PointeeCandidate
-                | ConstDropCandidate,
+                | ConstDropCandidate(_),
                 _,
             ) => true,
             (
@@ -1562,7 +1590,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 BuiltinCandidate { has_nested: false }
                 | DiscriminantKindCandidate
                 | PointeeCandidate
-                | ConstDropCandidate,
+                | ConstDropCandidate(_),
             ) => false,
 
             (ParamCandidate(other), ParamCandidate(victim)) => {
@@ -2383,7 +2411,7 @@ impl<'tcx> TraitObligationExt<'tcx> for TraitObligation<'tcx> {
         // chain. Ideally, we should have a way to configure this either
         // by using -Z verbose or just a CLI argument.
         let derived_cause = DerivedObligationCause {
-            parent_trait_ref: obligation.predicate.to_poly_trait_ref(),
+            parent_trait_pred: obligation.predicate,
             parent_code: obligation.cause.clone_code(),
         };
         let derived_code = variant(derived_cause);
@@ -2506,6 +2534,11 @@ struct ProvisionalEvaluation {
     from_dfn: usize,
     reached_depth: usize,
     result: EvaluationResult,
+    /// The `DepNodeIndex` created for the `evaluate_stack` call for this provisional
+    /// evaluation. When we create an entry in the evaluation cache using this provisional
+    /// cache entry (see `on_completion`), we use this `dep_node` to ensure that future reads from
+    /// the cache will have all of the necessary incr comp dependencies tracked.
+    dep_node: DepNodeIndex,
 }
 
 impl<'tcx> Default for ProvisionalEvaluationCache<'tcx> {
@@ -2548,6 +2581,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
         reached_depth: usize,
         fresh_trait_pred: ty::PolyTraitPredicate<'tcx>,
         result: EvaluationResult,
+        dep_node: DepNodeIndex,
     ) {
         debug!(?from_dfn, ?fresh_trait_pred, ?result, "insert_provisional");
 
@@ -2573,7 +2607,10 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
             }
         }
 
-        map.insert(fresh_trait_pred, ProvisionalEvaluation { from_dfn, reached_depth, result });
+        map.insert(
+            fresh_trait_pred,
+            ProvisionalEvaluation { from_dfn, reached_depth, result, dep_node },
+        );
     }
 
     /// Invoked when the node with dfn `dfn` does not get a successful
@@ -2624,7 +2661,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
     fn on_completion(
         &self,
         dfn: usize,
-        mut op: impl FnMut(ty::PolyTraitPredicate<'tcx>, EvaluationResult),
+        mut op: impl FnMut(ty::PolyTraitPredicate<'tcx>, EvaluationResult, DepNodeIndex),
     ) {
         debug!(?dfn, "on_completion");
 
@@ -2633,7 +2670,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> {
         {
             debug!(?fresh_trait_pred, ?eval, "on_completion");
 
-            op(fresh_trait_pred, eval.result);
+            op(fresh_trait_pred, eval.result, eval.dep_node);
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 195a4a4a653..2c5e7e40cc8 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -506,12 +506,21 @@ crate fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Option<St
     let mut pretty_predicates =
         Vec::with_capacity(predicates.len() + types_without_default_bounds.len());
 
-    for (p, _) in predicates {
+    for (mut p, _) in predicates {
         if let Some(poly_trait_ref) = p.to_opt_poly_trait_pred() {
             if Some(poly_trait_ref.def_id()) == sized_trait {
                 types_without_default_bounds.remove(poly_trait_ref.self_ty().skip_binder());
                 continue;
             }
+
+            if ty::BoundConstness::ConstIfConst == poly_trait_ref.skip_binder().constness {
+                let new_trait_pred = poly_trait_ref.map_bound(|mut trait_pred| {
+                    trait_pred.constness = ty::BoundConstness::NotConst;
+                    trait_pred
+                });
+
+                p = tcx.mk_predicate(new_trait_pred.map_bound(ty::PredicateKind::Trait))
+            }
         }
         pretty_predicates.push(p.to_string());
     }
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 6a355b567e0..493cb199f11 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -306,10 +306,9 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
 
         let extend = |obligation: traits::PredicateObligation<'tcx>| {
             let mut cause = cause.clone();
-            if let Some(parent_trait_ref) = obligation.predicate.to_opt_poly_trait_pred() {
+            if let Some(parent_trait_pred) = obligation.predicate.to_opt_poly_trait_pred() {
                 let derived_cause = traits::DerivedObligationCause {
-                    // FIXME(fee1-dead): when improving error messages, change this to PolyTraitPredicate
-                    parent_trait_ref: parent_trait_ref.map_bound(|t| t.trait_ref),
+                    parent_trait_pred,
                     parent_code: obligation.cause.clone_code(),
                 };
                 *cause.make_mut_code() =
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index 781a639b09e..4142c999ca7 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -100,7 +100,7 @@ fn associated_item_from_trait_item_ref(
     };
 
     ty::AssocItem {
-        ident: trait_item_ref.ident,
+        name: trait_item_ref.ident.name,
         kind,
         vis: tcx.visibility(def_id),
         defaultness: trait_item_ref.defaultness,
@@ -124,7 +124,7 @@ fn associated_item_from_impl_item_ref(
     };
 
     ty::AssocItem {
-        ident: impl_item_ref.ident,
+        name: impl_item_ref.ident.name,
         kind,
         vis: tcx.visibility(def_id),
         defaultness: impl_item_ref.defaultness,
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index fef83190468..b882a940d40 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -149,7 +149,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
     // kind of an "idempotent" action, but I'm not sure where would be
     // a better place. In practice, we construct environments for
     // every fn once during type checking, and we'll abort if there
-    // are any errors at that point, so after type checking you can be
+    // are any errors at that point, so outside of type inference you can be
     // sure that this will succeed without errors anyway.
 
     if tcx.sess.opts.debugging_opts.chalk {
diff --git a/compiler/rustc_typeck/src/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs
index b532c41642c..a49d6e24f26 100644
--- a/compiler/rustc_typeck/src/astconv/errors.rs
+++ b/compiler/rustc_typeck/src/astconv/errors.rs
@@ -214,7 +214,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             .map(|r| self.tcx().associated_items(r.def_id()).in_definition_order())
             .flatten()
             .filter_map(
-                |item| if item.kind == ty::AssocKind::Type { Some(item.ident.name) } else { None },
+                |item| if item.kind == ty::AssocKind::Type { Some(item.name) } else { None },
             )
             .collect();
 
@@ -270,7 +270,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 let trait_def_id = assoc_item.container.id();
                 names.push(format!(
                     "`{}` (from trait `{}`)",
-                    assoc_item.ident,
+                    assoc_item.name,
                     tcx.def_path_str(trait_def_id),
                 ));
             }
@@ -327,11 +327,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             let mut names: FxHashMap<_, usize> = FxHashMap::default();
             for item in assoc_items {
                 types_count += 1;
-                *names.entry(item.ident.name).or_insert(0) += 1;
+                *names.entry(item.name).or_insert(0) += 1;
             }
             let mut dupes = false;
             for item in assoc_items {
-                let prefix = if names[&item.ident.name] > 1 {
+                let prefix = if names[&item.name] > 1 {
                     let trait_def_id = item.container.id();
                     dupes = true;
                     format!("{}::", tcx.def_path_str(trait_def_id))
@@ -339,7 +339,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     String::new()
                 };
                 if let Some(sp) = tcx.hir().span_if_local(item.def_id) {
-                    err.span_label(sp, format!("`{}{}` defined here", prefix, item.ident));
+                    err.span_label(sp, format!("`{}{}` defined here", prefix, item.name));
                 }
             }
             if potential_assoc_types.len() == assoc_items.len() {
@@ -350,14 +350,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 // `Iterator<Item = isize>`.
                 for (potential, item) in iter::zip(&potential_assoc_types, assoc_items) {
                     if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(*potential) {
-                        suggestions.push((*potential, format!("{} = {}", item.ident, snippet)));
+                        suggestions.push((*potential, format!("{} = {}", item.name, snippet)));
                     }
                 }
             } else if let (Ok(snippet), false) =
                 (tcx.sess.source_map().span_to_snippet(*span), dupes)
             {
                 let types: Vec<_> =
-                    assoc_items.iter().map(|item| format!("{} = Type", item.ident)).collect();
+                    assoc_items.iter().map(|item| format!("{} = Type", item.name)).collect();
                 let code = if snippet.ends_with('>') {
                     // The user wrote `Trait<'a>` or similar and we don't have a type we can
                     // suggest, but at least we can clue them to the correct syntax
@@ -388,17 +388,17 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 let mut names: FxHashMap<_, usize> = FxHashMap::default();
                 for item in assoc_items {
                     types_count += 1;
-                    *names.entry(item.ident.name).or_insert(0) += 1;
+                    *names.entry(item.name).or_insert(0) += 1;
                 }
                 let mut label = vec![];
                 for item in assoc_items {
-                    let postfix = if names[&item.ident.name] > 1 {
+                    let postfix = if names[&item.name] > 1 {
                         let trait_def_id = item.container.id();
                         format!(" (from trait `{}`)", tcx.def_path_str(trait_def_id))
                     } else {
                         String::new()
                     };
-                    label.push(format!("`{}`{}", item.ident, postfix));
+                    label.push(format!("`{}`{}", item.name, postfix));
                 }
                 if !label.is_empty() {
                     err.span_label(
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index 956696546da..05ff7f818c7 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -445,7 +445,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         let named_type_param_count =
             param_counts.types - has_self as usize - synth_type_param_count;
         let infer_lifetimes =
-            gen_pos != GenericArgPosition::Type && !gen_args.has_lifetime_params();
+            (gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params();
 
         if gen_pos != GenericArgPosition::Type && !gen_args.bindings.is_empty() {
             Self::prohibit_assoc_ty_binding(tcx, gen_args.bindings[0].span);
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index d9b3f51b5bd..16fc9a01a27 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -482,7 +482,20 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             ) -> subst::GenericArg<'tcx> {
                 let tcx = self.astconv.tcx();
                 match param.kind {
-                    GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(),
+                    GenericParamDefKind::Lifetime => self
+                        .astconv
+                        .re_infer(Some(param), self.span)
+                        .unwrap_or_else(|| {
+                            debug!(?param, "unelided lifetime in signature");
+
+                            // This indicates an illegal lifetime in a non-assoc-trait position
+                            tcx.sess.delay_span_bug(self.span, "unelided lifetime in signature");
+
+                            // Supply some dummy value. We don't have an
+                            // `re_error`, annoyingly, so use `'static`.
+                            tcx.lifetimes.re_static
+                        })
+                        .into(),
                     GenericParamDefKind::Type { has_default, .. } => {
                         if !infer_args && has_default {
                             // No type parameter provided, but a default exists.
@@ -1137,7 +1150,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             .filter_by_name_unhygienic(assoc_ident.name)
             .find(|i| {
                 (i.kind == ty::AssocKind::Type || i.kind == ty::AssocKind::Const)
-                    && i.ident.normalize_to_macros_2_0() == assoc_ident
+                    && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
             })
             .expect("missing associated type");
         // FIXME(associated_const_equality): need to handle assoc_consts here as well.
@@ -1176,7 +1189,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         // Include substitutions for generic parameters of associated types
         let projection_ty = candidate.map_bound(|trait_ref| {
-            let ident = Ident::new(assoc_ty.ident.name, binding.item_name.span);
+            let ident = Ident::new(assoc_ty.name, binding.item_name.span);
             let item_segment = hir::PathSegment {
                 ident,
                 hir_id: Some(binding.hir_id),
@@ -1868,7 +1881,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             .in_definition_order()
             .find(|i| {
                 i.kind.namespace() == Namespace::TypeNS
-                    && i.ident.normalize_to_macros_2_0() == assoc_ident
+                    && i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
             })
             .expect("missing associated type");
 
diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs
index eea8f40635d..0fea0afb572 100644
--- a/compiler/rustc_typeck/src/check/callee.rs
+++ b/compiler/rustc_typeck/src/check/callee.rs
@@ -307,6 +307,36 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    /// Give appropriate suggestion when encountering `[("a", 0) ("b", 1)]`, where the
+    /// likely intention is to create an array containing tuples.
+    fn maybe_suggest_bad_array_definition(
+        &self,
+        err: &mut DiagnosticBuilder<'a>,
+        call_expr: &'tcx hir::Expr<'tcx>,
+        callee_expr: &'tcx hir::Expr<'tcx>,
+    ) -> bool {
+        let hir_id = self.tcx.hir().get_parent_node(call_expr.hir_id);
+        let parent_node = self.tcx.hir().get(hir_id);
+        if let (
+            hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Array(_), .. }),
+            hir::ExprKind::Tup(exp),
+            hir::ExprKind::Call(_, args),
+        ) = (parent_node, &callee_expr.kind, &call_expr.kind)
+        {
+            if args.len() == exp.len() {
+                let start = callee_expr.span.shrink_to_hi();
+                err.span_suggestion(
+                    start,
+                    "consider separating array elements with a comma",
+                    ",".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+                return true;
+            }
+        }
+        false
+    }
+
     fn confirm_builtin_call(
         &self,
         call_expr: &'tcx hir::Expr<'tcx>,
@@ -422,7 +452,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     _ => Res::Err,
                 };
 
-                err.span_label(call_expr.span, "call expression requires function");
+                if !self.maybe_suggest_bad_array_definition(&mut err, call_expr, callee_expr) {
+                    err.span_label(call_expr.span, "call expression requires function");
+                }
 
                 if let Some(span) = self.tcx.hir().res_span(def) {
                     let callee_ty = callee_ty.to_string();
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index eb49cc0233d..18a0a8767d4 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -999,7 +999,7 @@ fn check_impl_items_against_trait<'tcx>(
 
                 if is_implemented_here {
                     let trait_item = tcx.associated_item(trait_item_id);
-                    if required_items.contains(&trait_item.ident) {
+                    if required_items.contains(&trait_item.ident(tcx)) {
                         must_implement_one_of = None;
                     }
                 }
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index 94648d5702c..74910234b7e 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -300,7 +300,7 @@ fn compare_predicate_entailment<'tcx>(
                 cause.span(tcx),
                 E0053,
                 "method `{}` has an incompatible type for trait",
-                trait_m.ident
+                trait_m.name
             );
             match &terr {
                 TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
@@ -452,7 +452,7 @@ fn check_region_bounds_on_impl_item<'tcx>(
         tcx.sess.emit_err(LifetimesOrBoundsMismatchOnTrait {
             span,
             item_kind,
-            ident: impl_m.ident,
+            ident: impl_m.ident(tcx),
             generics_span,
         });
         return Err(ErrorReported);
@@ -540,14 +540,14 @@ fn compare_self_type<'tcx>(
                 impl_m_span,
                 E0185,
                 "method `{}` has a `{}` declaration in the impl, but not in the trait",
-                trait_m.ident,
+                trait_m.name,
                 self_descr
             );
             err.span_label(impl_m_span, format!("`{}` used in impl", self_descr));
             if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) {
                 err.span_label(span, format!("trait method declared without `{}`", self_descr));
             } else {
-                err.note_trait_signature(trait_m.ident.to_string(), trait_m.signature(tcx));
+                err.note_trait_signature(trait_m.name.to_string(), trait_m.signature(tcx));
             }
             err.emit();
             return Err(ErrorReported);
@@ -560,14 +560,14 @@ fn compare_self_type<'tcx>(
                 impl_m_span,
                 E0186,
                 "method `{}` has a `{}` declaration in the trait, but not in the impl",
-                trait_m.ident,
+                trait_m.name,
                 self_descr
             );
             err.span_label(impl_m_span, format!("expected `{}` in impl", self_descr));
             if let Some(span) = tcx.hir().span_if_local(trait_m.def_id) {
                 err.span_label(span, format!("`{}` used in trait", self_descr));
             } else {
-                err.note_trait_signature(trait_m.ident.to_string(), trait_m.signature(tcx));
+                err.note_trait_signature(trait_m.name.to_string(), trait_m.signature(tcx));
             }
             err.emit();
             return Err(ErrorReported);
@@ -640,7 +640,7 @@ fn compare_number_of_generics<'tcx>(
                     "{} `{}` has {} {kind} parameter{} but its trait \
                      declaration has {} {kind} parameter{}",
                     item_kind,
-                    trait_.ident,
+                    trait_.name,
                     impl_count,
                     pluralize!(impl_count),
                     trait_count,
@@ -747,7 +747,7 @@ fn compare_number_of_method_arguments<'tcx>(
             impl_span,
             E0050,
             "method `{}` has {} but the declaration in trait `{}` has {}",
-            trait_m.ident,
+            trait_m.name,
             potentially_plural_count(impl_number_args, "parameter"),
             tcx.def_path_str(trait_m.def_id),
             trait_number_args
@@ -761,7 +761,7 @@ fn compare_number_of_method_arguments<'tcx>(
                 ),
             );
         } else {
-            err.note_trait_signature(trait_m.ident.to_string(), trait_m.signature(tcx));
+            err.note_trait_signature(trait_m.name.to_string(), trait_m.signature(tcx));
         }
         err.span_label(
             impl_span,
@@ -811,7 +811,7 @@ fn compare_synthetic_generics<'tcx>(
                 impl_span,
                 E0643,
                 "method `{}` has incompatible signature for trait",
-                trait_m.ident
+                trait_m.name
             );
             err.span_label(trait_span, "declaration in trait here");
             match (impl_synthetic, trait_synthetic) {
@@ -965,7 +965,7 @@ fn compare_const_param_types<'tcx>(
                 *impl_span,
                 E0053,
                 "method `{}` has an incompatible const parameter type for trait",
-                trait_m.ident
+                trait_m.name
             );
             err.span_note(
                 trait_span.map_or_else(|| trait_item_span.unwrap_or(*impl_span), |span| *span),
@@ -1053,7 +1053,7 @@ crate fn compare_const_impl<'tcx>(
                 cause.span,
                 E0326,
                 "implemented const `{}` has an incompatible type for trait",
-                trait_c.ident
+                trait_c.name
             );
 
             let trait_c_span = trait_c.def_id.as_local().map(|trait_c_def_id| {
diff --git a/compiler/rustc_typeck/src/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs
index c8986aa7f53..89866c20b61 100644
--- a/compiler/rustc_typeck/src/check/dropck.rs
+++ b/compiler/rustc_typeck/src/check/dropck.rs
@@ -229,7 +229,13 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
             let p = p.kind();
             match (predicate.skip_binder(), p.skip_binder()) {
                 (ty::PredicateKind::Trait(a), ty::PredicateKind::Trait(b)) => {
-                    relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
+                    // Since struct predicates cannot have ~const, project the impl predicate
+                    // onto one that ignores the constness. This is equivalent to saying that
+                    // we match a `Trait` bound on the struct with a `Trait` or `~const Trait`
+                    // in the impl.
+                    let non_const_a =
+                        ty::TraitPredicate { constness: ty::BoundConstness::NotConst, ..a };
+                    relator.relate(predicate.rebind(non_const_a), p.rebind(b)).is_ok()
                 }
                 (ty::PredicateKind::Projection(a), ty::PredicateKind::Projection(b)) => {
                     relator.relate(predicate.rebind(a), p.rebind(b)).is_ok()
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 2cad8aab29e..0e1dbc53806 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -31,7 +31,7 @@ use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::{ExprKind, QPath};
+use rustc_hir::{ExprKind, HirId, QPath};
 use rustc_infer::infer;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::InferOk;
@@ -1970,7 +1970,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             "ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, expr_ty={:?}",
             field, base, expr, expr_t
         );
-        let mut err = self.no_such_field_err(field, expr_t);
+        let mut err = self.no_such_field_err(field, expr_t, base.hir_id);
 
         match *expr_t.peel_refs().kind() {
             ty::Array(_, len) => {
@@ -2209,6 +2209,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         field: Ident,
         expr_t: &'tcx ty::TyS<'tcx>,
+        id: HirId,
     ) -> DiagnosticBuilder<'_> {
         let span = field.span;
         debug!("no_such_field_err(span: {:?}, field: {:?}, expr_t: {:?})", span, field, expr_t);
@@ -2226,9 +2227,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // try to add a suggestion in case the field is a nested field of a field of the Adt
         if let Some((fields, substs)) = self.get_field_candidates(span, &expr_t) {
             for candidate_field in fields.iter() {
-                if let Some(field_path) =
-                    self.check_for_nested_field(span, field, candidate_field, substs, vec![])
-                {
+                if let Some(field_path) = self.check_for_nested_field(
+                    span,
+                    field,
+                    candidate_field,
+                    substs,
+                    vec![],
+                    self.tcx.parent_module(id).to_def_id(),
+                ) {
                     let field_path_str = field_path
                         .iter()
                         .map(|id| id.name.to_ident_string())
@@ -2280,6 +2286,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         candidate_field: &ty::FieldDef,
         subst: SubstsRef<'tcx>,
         mut field_path: Vec<Ident>,
+        id: DefId,
     ) -> Option<Vec<Ident>> {
         debug!(
             "check_for_nested_field(span: {:?}, candidate_field: {:?}, field_path: {:?}",
@@ -2299,10 +2306,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let field_ty = candidate_field.ty(self.tcx, subst);
             if let Some((nested_fields, subst)) = self.get_field_candidates(span, &field_ty) {
                 for field in nested_fields.iter() {
-                    let ident = field.ident(self.tcx).normalize_to_macros_2_0();
-                    if ident == target_field {
-                        return Some(field_path);
-                    } else {
+                    let accessible = field.vis.is_accessible_from(id, self.tcx);
+                    if accessible {
+                        let ident = field.ident(self.tcx).normalize_to_macros_2_0();
+                        if ident == target_field {
+                            return Some(field_path);
+                        }
                         let field_path = field_path.clone();
                         if let Some(path) = self.check_for_nested_field(
                             span,
@@ -2310,6 +2319,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             field,
                             subst,
                             field_path,
+                            id,
                         ) {
                             return Some(path);
                         }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index e42d94a6f40..1b93017c5aa 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -28,6 +28,11 @@ use crate::structured_errors::StructuredDiagnostic;
 use std::iter;
 use std::slice;
 
+struct FnArgsAsTuple<'hir> {
+    first: &'hir hir::Expr<'hir>,
+    last: &'hir hir::Expr<'hir>,
+}
+
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(in super::super) fn check_casts(&self) {
         let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
@@ -127,136 +132,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let expected_arg_count = formal_input_tys.len();
 
-        let param_count_error = |expected_count: usize,
-                                 arg_count: usize,
-                                 error_code: &str,
-                                 c_variadic: bool,
-                                 sugg_unit: bool| {
-            let (span, start_span, args, ctor_of) = match &call_expr.kind {
-                hir::ExprKind::Call(
-                    hir::Expr {
-                        span,
-                        kind:
-                            hir::ExprKind::Path(hir::QPath::Resolved(
-                                _,
-                                hir::Path { res: Res::Def(DefKind::Ctor(of, _), _), .. },
-                            )),
-                        ..
-                    },
-                    args,
-                ) => (*span, *span, &args[..], Some(of)),
-                hir::ExprKind::Call(hir::Expr { span, .. }, args) => {
-                    (*span, *span, &args[..], None)
-                }
-                hir::ExprKind::MethodCall(path_segment, args, _) => (
-                    path_segment.ident.span,
-                    // `sp` doesn't point at the whole `foo.bar()`, only at `bar`.
-                    path_segment
-                        .args
-                        .and_then(|args| args.args.iter().last())
-                        // Account for `foo.bar::<T>()`.
-                        .map(|arg| {
-                            // Skip the closing `>`.
-                            tcx.sess
-                                .source_map()
-                                .next_point(tcx.sess.source_map().next_point(arg.span()))
-                        })
-                        .unwrap_or(path_segment.ident.span),
-                    &args[1..], // Skip the receiver.
-                    None,       // methods are never ctors
-                ),
-                k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k),
-            };
-            let arg_spans = if provided_args.is_empty() {
-                // foo()
-                // ^^^-- supplied 0 arguments
-                // |
-                // expected 2 arguments
-                vec![tcx.sess.source_map().next_point(start_span).with_hi(call_span.hi())]
-            } else {
-                // foo(1, 2, 3)
-                // ^^^ -  -  - supplied 3 arguments
-                // |
-                // expected 2 arguments
-                args.iter().map(|arg| arg.span).collect::<Vec<Span>>()
-            };
-
-            let mut err = tcx.sess.struct_span_err_with_code(
-                span,
-                &format!(
-                    "this {} takes {}{} but {} {} supplied",
-                    match ctor_of {
-                        Some(CtorOf::Struct) => "struct",
-                        Some(CtorOf::Variant) => "enum variant",
-                        None => "function",
-                    },
-                    if c_variadic { "at least " } else { "" },
-                    potentially_plural_count(expected_count, "argument"),
-                    potentially_plural_count(arg_count, "argument"),
-                    if arg_count == 1 { "was" } else { "were" }
-                ),
-                DiagnosticId::Error(error_code.to_owned()),
-            );
-            let label = format!("supplied {}", potentially_plural_count(arg_count, "argument"));
-            for (i, span) in arg_spans.into_iter().enumerate() {
-                err.span_label(
-                    span,
-                    if arg_count == 0 || i + 1 == arg_count { &label } else { "" },
-                );
-            }
-
-            if let Some(def_id) = fn_def_id {
-                if let Some(def_span) = tcx.def_ident_span(def_id) {
-                    let mut spans: MultiSpan = def_span.into();
-
-                    let params = tcx
-                        .hir()
-                        .get_if_local(def_id)
-                        .and_then(|node| node.body_id())
-                        .into_iter()
-                        .map(|id| tcx.hir().body(id).params)
-                        .flatten();
-
-                    for param in params {
-                        spans.push_span_label(param.span, String::new());
-                    }
-
-                    let def_kind = tcx.def_kind(def_id);
-                    err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
-                }
-            }
-
-            if sugg_unit {
-                let sugg_span = tcx.sess.source_map().end_point(call_expr.span);
-                // remove closing `)` from the span
-                let sugg_span = sugg_span.shrink_to_lo();
-                err.span_suggestion(
-                    sugg_span,
-                    "expected the unit value `()`; create it with empty parentheses",
-                    String::from("()"),
-                    Applicability::MachineApplicable,
-                );
-            } else {
-                err.span_label(
-                    span,
-                    format!(
-                        "expected {}{}",
-                        if c_variadic { "at least " } else { "" },
-                        potentially_plural_count(expected_count, "argument")
-                    ),
-                );
-            }
-            err.emit();
-        };
+        // expected_count, arg_count, error_code, sugg_unit, sugg_tuple_wrap_args
+        let mut error: Option<(usize, usize, &str, bool, Option<FnArgsAsTuple<'_>>)> = None;
 
+        // If the arguments should be wrapped in a tuple (ex: closures), unwrap them here
         let (formal_input_tys, expected_input_tys) = if tuple_arguments == TupleArguments {
             let tuple_type = self.structurally_resolved_type(call_span, formal_input_tys[0]);
             match tuple_type.kind() {
-                ty::Tuple(arg_types) if arg_types.len() != provided_args.len() => {
-                    param_count_error(arg_types.len(), provided_args.len(), "E0057", false, false);
-                    (self.err_args(provided_args.len()), vec![])
-                }
+                // We expected a tuple and got a tuple
                 ty::Tuple(arg_types) => {
+                    // Argument length differs
+                    if arg_types.len() != provided_args.len() {
+                        error = Some((arg_types.len(), provided_args.len(), "E0057", false, None));
+                    }
                     let expected_input_tys = match expected_input_tys.get(0) {
                         Some(&ty) => match ty.kind() {
                             ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(),
@@ -267,6 +155,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     (arg_types.iter().map(|k| k.expect_ty()).collect(), expected_input_tys)
                 }
                 _ => {
+                    // Otherwise, there's a mismatch, so clear out what we're expecting, and set
+                    // our input typs to err_args so we don't blow up the error messages
                     struct_span_err!(
                         tcx.sess,
                         call_span,
@@ -284,7 +174,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if supplied_arg_count >= expected_arg_count {
                 (formal_input_tys.to_vec(), expected_input_tys)
             } else {
-                param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false);
+                error = Some((expected_arg_count, supplied_arg_count, "E0060", false, None));
                 (self.err_args(supplied_arg_count), vec![])
             }
         } else {
@@ -296,8 +186,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             } else {
                 false
             };
-            param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit);
 
+            // are we passing elements of a tuple without the tuple parentheses?
+            let expected_input_tys = if expected_input_tys.is_empty() {
+                // In most cases we can use expected_input_tys, but some callers won't have the type
+                // information, in which case we fall back to the types from the input expressions.
+                formal_input_tys
+            } else {
+                &*expected_input_tys
+            };
+
+            let sugg_tuple_wrap_args = self.suggested_tuple_wrap(expected_input_tys, provided_args);
+
+            error = Some((
+                expected_arg_count,
+                supplied_arg_count,
+                "E0061",
+                sugg_unit,
+                sugg_tuple_wrap_args,
+            ));
             (self.err_args(supplied_arg_count), vec![])
         };
 
@@ -315,13 +222,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         assert_eq!(expected_input_tys.len(), formal_input_tys.len());
 
+        let provided_arg_count: usize = provided_args.len();
+
         // Keep track of the fully coerced argument types
-        let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![];
+        let mut final_arg_types: Vec<Option<(Ty<'_>, Ty<'_>)>> = vec![None; provided_arg_count];
 
         // We introduce a helper function to demand that a given argument satisfy a given input
         // This is more complicated than just checking type equality, as arguments could be coerced
         // This version writes those types back so further type checking uses the narrowed types
-        let demand_compatible = |idx, final_arg_types: &mut Vec<(usize, Ty<'tcx>, Ty<'tcx>)>| {
+        let demand_compatible = |idx, final_arg_types: &mut Vec<Option<(Ty<'tcx>, Ty<'tcx>)>>| {
             let formal_input_ty: Ty<'tcx> = formal_input_tys[idx];
             let expected_input_ty: Ty<'tcx> = expected_input_tys[idx];
             let provided_arg = &provided_args[idx];
@@ -340,13 +249,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty);
 
             // Keep track of these for below
-            final_arg_types.push((idx, checked_ty, coerced_ty));
+            final_arg_types[idx] = Some((checked_ty, coerced_ty));
 
             // Cause selection errors caused by resolving a single argument to point at the
             // argument and not the call. This is otherwise redundant with the `demand_coerce`
             // call immediately after, but it lets us customize the span pointed to in the
             // fulfillment error to be more accurate.
-            let _ =
+            let coerced_ty =
                 self.resolve_vars_with_obligations_and_mutate_fulfillment(coerced_ty, |errors| {
                     self.point_at_type_arg_instead_of_call_if_possible(errors, call_expr);
                     self.point_at_arg_instead_of_call_if_possible(
@@ -358,6 +267,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     );
                 });
 
+            final_arg_types[idx] = Some((checked_ty, coerced_ty));
+
             // We're processing function arguments so we definitely want to use
             // two-phase borrows.
             self.demand_coerce(&provided_arg, checked_ty, coerced_ty, None, AllowTwoPhase::Yes);
@@ -416,6 +327,133 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         }
 
+        // If there was an error in parameter count, emit that here
+        if let Some((expected_count, arg_count, err_code, sugg_unit, sugg_tuple_wrap_args)) = error
+        {
+            let (span, start_span, args, ctor_of) = match &call_expr.kind {
+                hir::ExprKind::Call(
+                    hir::Expr {
+                        span,
+                        kind:
+                            hir::ExprKind::Path(hir::QPath::Resolved(
+                                _,
+                                hir::Path { res: Res::Def(DefKind::Ctor(of, _), _), .. },
+                            )),
+                        ..
+                    },
+                    args,
+                ) => (*span, *span, &args[..], Some(of)),
+                hir::ExprKind::Call(hir::Expr { span, .. }, args) => {
+                    (*span, *span, &args[..], None)
+                }
+                hir::ExprKind::MethodCall(path_segment, args, _) => (
+                    path_segment.ident.span,
+                    // `sp` doesn't point at the whole `foo.bar()`, only at `bar`.
+                    path_segment
+                        .args
+                        .and_then(|args| args.args.iter().last())
+                        // Account for `foo.bar::<T>()`.
+                        .map(|arg| {
+                            // Skip the closing `>`.
+                            tcx.sess
+                                .source_map()
+                                .next_point(tcx.sess.source_map().next_point(arg.span()))
+                        })
+                        .unwrap_or(path_segment.ident.span),
+                    &args[1..], // Skip the receiver.
+                    None,       // methods are never ctors
+                ),
+                k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k),
+            };
+            let arg_spans = if provided_args.is_empty() {
+                // foo()
+                // ^^^-- supplied 0 arguments
+                // |
+                // expected 2 arguments
+                vec![tcx.sess.source_map().next_point(start_span).with_hi(call_span.hi())]
+            } else {
+                // foo(1, 2, 3)
+                // ^^^ -  -  - supplied 3 arguments
+                // |
+                // expected 2 arguments
+                args.iter().map(|arg| arg.span).collect::<Vec<Span>>()
+            };
+            let call_name = match ctor_of {
+                Some(CtorOf::Struct) => "struct",
+                Some(CtorOf::Variant) => "enum variant",
+                None => "function",
+            };
+            let mut err = tcx.sess.struct_span_err_with_code(
+                span,
+                &format!(
+                    "this {} takes {}{} but {} {} supplied",
+                    call_name,
+                    if c_variadic { "at least " } else { "" },
+                    potentially_plural_count(expected_count, "argument"),
+                    potentially_plural_count(arg_count, "argument"),
+                    if arg_count == 1 { "was" } else { "were" }
+                ),
+                DiagnosticId::Error(err_code.to_owned()),
+            );
+            let label = format!("supplied {}", potentially_plural_count(arg_count, "argument"));
+            for (i, span) in arg_spans.into_iter().enumerate() {
+                err.span_label(
+                    span,
+                    if arg_count == 0 || i + 1 == arg_count { &label } else { "" },
+                );
+            }
+            if let Some(def_id) = fn_def_id {
+                if let Some(def_span) = tcx.def_ident_span(def_id) {
+                    let mut spans: MultiSpan = def_span.into();
+
+                    let params = tcx
+                        .hir()
+                        .get_if_local(def_id)
+                        .and_then(|node| node.body_id())
+                        .into_iter()
+                        .map(|id| tcx.hir().body(id).params)
+                        .flatten();
+
+                    for param in params {
+                        spans.push_span_label(param.span, String::new());
+                    }
+
+                    let def_kind = tcx.def_kind(def_id);
+                    err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id)));
+                }
+            }
+            if sugg_unit {
+                let sugg_span = tcx.sess.source_map().end_point(call_expr.span);
+                // remove closing `)` from the span
+                let sugg_span = sugg_span.shrink_to_lo();
+                err.span_suggestion(
+                    sugg_span,
+                    "expected the unit value `()`; create it with empty parentheses",
+                    String::from("()"),
+                    Applicability::MachineApplicable,
+                );
+            } else if let Some(FnArgsAsTuple { first, last }) = sugg_tuple_wrap_args {
+                err.multipart_suggestion(
+                    "use parentheses to construct a tuple",
+                    vec![
+                        (first.span.shrink_to_lo(), '('.to_string()),
+                        (last.span.shrink_to_hi(), ')'.to_string()),
+                    ],
+                    Applicability::MachineApplicable,
+                );
+            } else {
+                err.span_label(
+                    span,
+                    format!(
+                        "expected {}{}",
+                        if c_variadic { "at least " } else { "" },
+                        potentially_plural_count(expected_count, "argument")
+                    ),
+                );
+            }
+            err.emit();
+        }
+
         // We also need to make sure we at least write the ty of the other
         // arguments which we skipped above.
         if c_variadic {
@@ -452,6 +490,35 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    fn suggested_tuple_wrap(
+        &self,
+        expected_input_tys: &[Ty<'tcx>],
+        provided_args: &'tcx [hir::Expr<'tcx>],
+    ) -> Option<FnArgsAsTuple<'_>> {
+        let [expected_arg_type] = &expected_input_tys[..] else { return None };
+
+        let ty::Tuple(expected_elems) = self.resolve_vars_if_possible(*expected_arg_type).kind()
+            else { return None };
+
+        let expected_types: Vec<_> = expected_elems.iter().map(|k| k.expect_ty()).collect();
+        let supplied_types: Vec<_> = provided_args.iter().map(|arg| self.check_expr(arg)).collect();
+
+        let all_match = iter::zip(expected_types, supplied_types)
+            .all(|(expected, supplied)| self.can_eq(self.param_env, expected, supplied).is_ok());
+
+        if all_match {
+            match provided_args {
+                [] => None,
+                [_] => unreachable!(
+                    "shouldn't reach here - need count mismatch between 1-tuple and 1-argument"
+                ),
+                [first, .., last] => Some(FnArgsAsTuple { first, last }),
+            }
+        } else {
+            None
+        }
+    }
+
     // AST fragment checking
     pub(in super::super) fn check_lit(
         &self,
@@ -975,7 +1042,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn point_at_arg_instead_of_call_if_possible(
         &self,
         errors: &mut Vec<traits::FulfillmentError<'tcx>>,
-        final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)],
+        final_arg_types: &[Option<(Ty<'tcx>, Ty<'tcx>)>],
         expr: &'tcx hir::Expr<'tcx>,
         call_sp: Span,
         args: &'tcx [hir::Expr<'tcx>],
@@ -1016,7 +1083,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 ObligationCauseCode::BuiltinDerivedObligation(code) |
                 ObligationCauseCode::ImplDerivedObligation(code) |
                 ObligationCauseCode::DerivedObligation(code) => {
-                    code.parent_trait_ref.self_ty().skip_binder().into()
+                    code.parent_trait_pred.self_ty().skip_binder().into()
                 }
                 _ if let ty::PredicateKind::Trait(predicate) =
                     error.obligation.predicate.kind().skip_binder() => {
@@ -1030,8 +1097,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // `FulfillmentError`.
             let mut referenced_in = final_arg_types
                 .iter()
-                .map(|&(i, checked_ty, _)| (i, checked_ty))
-                .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty)))
+                .enumerate()
+                .filter_map(|(i, arg)| match arg {
+                    Some((checked_ty, coerce_ty)) => Some([(i, *checked_ty), (i, *coerce_ty)]),
+                    _ => None,
+                })
+                .flatten()
                 .flat_map(|(i, ty)| {
                     let ty = self.resolve_vars_if_possible(ty);
                     // We walk the argument type because the argument's type could have
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
index be4c9ec99b9..86cf850d723 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs
@@ -237,7 +237,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) {
                     let mut suggestions = iter::zip(iter::repeat(&expr_text), &methods)
                         .filter_map(|(receiver, method)| {
-                            let method_call = format!(".{}()", method.ident);
+                            let method_call = format!(".{}()", method.name);
                             if receiver.ends_with(&method_call) {
                                 None // do not suggest code that is already there (#53348)
                             } else {
diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs
index 56b6dd9a284..c6b92db88ae 100644
--- a/compiler/rustc_typeck/src/check/generator_interior.rs
+++ b/compiler/rustc_typeck/src/check/generator_interior.rs
@@ -22,6 +22,11 @@ use tracing::debug;
 
 mod drop_ranges;
 
+// FIXME(eholk): This flag is here to give a quick way to disable drop tracking in case we find
+// unexpected breakages while it's still new. It should be removed before too long. For example,
+// see #93161.
+const ENABLE_DROP_TRACKING: bool = false;
+
 struct InteriorVisitor<'a, 'tcx> {
     fcx: &'a FnCtxt<'a, 'tcx>,
     types: FxIndexSet<ty::GeneratorInteriorTypeCause<'tcx>>,
@@ -77,7 +82,10 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
                                 yield_data.expr_and_pat_count, self.expr_count, source_span
                             );
 
-                            if self.drop_ranges.is_dropped_at(hir_id, yield_data.expr_and_pat_count)
+                            if ENABLE_DROP_TRACKING
+                                && self
+                                    .drop_ranges
+                                    .is_dropped_at(hir_id, yield_data.expr_and_pat_count)
                             {
                                 debug!("value is dropped at yield point; not recording");
                                 return false;
diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs
index 4c612ed5be5..74f6f50d412 100644
--- a/compiler/rustc_typeck/src/check/intrinsic.rs
+++ b/compiler/rustc_typeck/src/check/intrinsic.rs
@@ -297,6 +297,11 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             sym::const_allocate => {
                 (0, vec![tcx.types.usize, tcx.types.usize], tcx.mk_mut_ptr(tcx.types.u8))
             }
+            sym::const_deallocate => (
+                0,
+                vec![tcx.mk_mut_ptr(tcx.types.u8), tcx.types.usize, tcx.types.usize],
+                tcx.mk_unit(),
+            ),
 
             sym::ptr_offset_from => {
                 (1, vec![tcx.mk_imm_ptr(param(0)), tcx.mk_imm_ptr(param(0))], tcx.types.isize)
diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs
index 86f3568d2e3..3815fd1992b 100644
--- a/compiler/rustc_typeck/src/check/method/probe.rs
+++ b/compiler/rustc_typeck/src/check/method/probe.rs
@@ -1033,7 +1033,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     true
                 }
             })
-            .map(|candidate| candidate.item.ident)
+            .map(|candidate| candidate.item.ident(self.tcx))
             .filter(|&name| set.insert(name))
             .collect();
 
@@ -1438,7 +1438,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                                 "<{} as {}>::{}",
                                 stable_pick.self_ty,
                                 self.tcx.def_path_str(def_id),
-                                stable_pick.item.ident
+                                stable_pick.item.name
                             ),
                             Applicability::MachineApplicable,
                         );
@@ -1748,14 +1748,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 let best_name = {
                     let names = applicable_close_candidates
                         .iter()
-                        .map(|cand| cand.ident.name)
+                        .map(|cand| cand.name)
                         .collect::<Vec<Symbol>>();
                     find_best_match_for_name(&names, self.method_name.unwrap().name, None)
                 }
                 .unwrap();
-                Ok(applicable_close_candidates
-                    .into_iter()
-                    .find(|method| method.ident.name == best_name))
+                Ok(applicable_close_candidates.into_iter().find(|method| method.name == best_name))
             }
         })
     }
@@ -1906,8 +1904,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     .associated_items(def_id)
                     .in_definition_order()
                     .filter(|x| {
-                        let dist = lev_distance(name.as_str(), x.ident.as_str());
-                        x.kind.namespace() == Namespace::ValueNS && dist > 0 && dist <= max_dist
+                        if x.kind.namespace() != Namespace::ValueNS {
+                            return false;
+                        }
+                        match lev_distance(name.as_str(), x.name.as_str(), max_dist) {
+                            Some(d) => d > 0,
+                            None => false,
+                        }
                     })
                     .copied()
                     .collect()
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index 96ab800afaf..58ea197d3e9 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -823,9 +823,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             _ => None,
                         })
                     {
-                        let parent_trait_ref = data.parent_trait_ref;
+                        let parent_trait_ref = data.parent_trait_pred;
                         let parent_def_id = parent_trait_ref.def_id();
-                        let path = parent_trait_ref.print_only_trait_path();
+                        let path = parent_trait_ref.print_modifiers_and_trait_path();
                         let tr_self_ty = parent_trait_ref.skip_binder().self_ty();
                         let mut candidates = vec![];
                         self.tcx.for_each_relevant_impl(
@@ -1025,7 +1025,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 def_kind.article(),
                                 def_kind.descr(lev_candidate.def_id),
                             ),
-                            lev_candidate.ident.to_string(),
+                            lev_candidate.name.to_string(),
                             Applicability::MaybeIncorrect,
                         );
                     }
@@ -1480,7 +1480,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     let skip = skippable.contains(&did);
                     if pick.autoderefs == 0 && !skip {
                         err.span_label(
-                            pick.item.ident.span,
+                            pick.item.ident(self.tcx).span,
                             &format!("the method is available for `{}` here", rcvr_ty),
                         );
                     }
@@ -1514,7 +1514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             // an autoderef to `&self`
                             if pick.autoderefs == 0 && !skip {
                                 err.span_label(
-                                    pick.item.ident.span,
+                                    pick.item.ident(self.tcx).span,
                                     &format!("the method is available for `{}` here", new_rcvr_t),
                                 );
                                 err.multipart_suggestion(
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index 34caabe44d6..6e0b902a00b 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -599,7 +599,7 @@ fn missing_items_err(
 ) {
     let missing_items_msg = missing_items
         .iter()
-        .map(|trait_item| trait_item.ident.to_string())
+        .map(|trait_item| trait_item.name.to_string())
         .collect::<Vec<_>>()
         .join("`, `");
 
@@ -628,7 +628,7 @@ fn missing_items_err(
         let msg = format!("implement the missing item: `{}`", snippet);
         let appl = Applicability::HasPlaceholders;
         if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) {
-            err.span_label(span, format!("`{}` from trait", trait_item.ident));
+            err.span_label(span, format!("`{}` from trait", trait_item.name));
             err.tool_only_span_suggestion(sugg_sp, &msg, code, appl);
         } else {
             err.span_suggestion_hidden(sugg_sp, &msg, code, appl);
@@ -805,16 +805,16 @@ fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String {
             fn_sig_suggestion(
                 tcx,
                 tcx.fn_sig(assoc.def_id).skip_binder(),
-                assoc.ident,
+                assoc.ident(tcx),
                 tcx.predicates_of(assoc.def_id),
                 assoc,
             )
         }
-        ty::AssocKind::Type => format!("type {} = Type;", assoc.ident),
+        ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
         ty::AssocKind::Const => {
             let ty = tcx.type_of(assoc.def_id);
             let val = expr::ty_kind_suggestion(ty).unwrap_or("value");
-            format!("const {}: {} = {};", assoc.ident, ty, val)
+            format!("const {}: {} = {};", assoc.name, ty, val)
         }
     }
 }
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index c20c457de85..74516acbfcf 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -549,16 +549,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         is_assign: IsAssign,
         op: hir::BinOp,
     ) -> bool {
-        let source_map = self.tcx.sess.source_map();
-        let remove_borrow_msg = "String concatenation appends the string on the right to the \
-                                 string on the left and may require reallocation. This \
-                                 requires ownership of the string on the left";
-
-        let msg = "`to_owned()` can be used to create an owned `String` \
-                   from a string reference. String concatenation \
-                   appends the string on the right to the string \
-                   on the left and may require reallocation. This \
-                   requires ownership of the string on the left";
+        let str_concat_note = "string concatenation requires an owned `String` on the left";
+        let rm_borrow_msg = "remove the borrow to obtain an owned `String`";
+        let to_owned_msg = "create an owned `String` from a string reference";
 
         let string_type = self.tcx.get_diagnostic_item(sym::String);
         let is_std_string = |ty: Ty<'tcx>| match ty.ty_adt_def() {
@@ -574,31 +567,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     ) =>
             {
                 if let IsAssign::No = is_assign { // Do not supply this message if `&str += &str`
-                    err.span_label(
-                        op.span,
-                        "`+` cannot be used to concatenate two `&str` strings",
-                    );
-                    match source_map.span_to_snippet(lhs_expr.span) {
-                        Ok(lstring) => {
-                            err.span_suggestion(
-                                lhs_expr.span,
-                                if lstring.starts_with('&') {
-                                    remove_borrow_msg
-                                } else {
-                                    msg
-                                },
-                                if let Some(stripped) = lstring.strip_prefix('&') {
-                                    // let a = String::new();
-                                    // let _ = &a + "bar";
-                                    stripped.to_string()
-                                } else {
-                                    format!("{}.to_owned()", lstring)
-                                },
-                                Applicability::MachineApplicable,
-                            )
-                        }
-                        _ => err.help(msg),
-                    };
+                    err.span_label(op.span, "`+` cannot be used to concatenate two `&str` strings");
+                    err.note(str_concat_note);
+                    if let hir::ExprKind::AddrOf(_, _, lhs_inner_expr) = lhs_expr.kind {
+                        err.span_suggestion_verbose(
+                            lhs_expr.span.until(lhs_inner_expr.span),
+                            rm_borrow_msg,
+                            "".to_owned(),
+                            Applicability::MachineApplicable
+                        );
+                    } else {
+                        err.span_suggestion_verbose(
+                            lhs_expr.span.shrink_to_hi(),
+                            to_owned_msg,
+                            ".to_owned()".to_owned(),
+                            Applicability::MachineApplicable
+                        );
+                    }
                 }
                 true
             }
@@ -609,32 +594,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     op.span,
                     "`+` cannot be used to concatenate a `&str` with a `String`",
                 );
-                match (
-                    source_map.span_to_snippet(lhs_expr.span),
-                    source_map.span_to_snippet(rhs_expr.span),
-                    is_assign,
-                ) {
-                    (Ok(l), Ok(r), IsAssign::No) => {
-                        let to_string = if let Some(stripped) = l.strip_prefix('&') {
-                            // let a = String::new(); let b = String::new();
-                            // let _ = &a + b;
-                            stripped.to_string()
+                match is_assign {
+                    IsAssign::No => {
+                        let sugg_msg;
+                        let lhs_sugg = if let hir::ExprKind::AddrOf(_, _, lhs_inner_expr) = lhs_expr.kind {
+                            sugg_msg = "remove the borrow on the left and add one on the right";
+                            (lhs_expr.span.until(lhs_inner_expr.span), "".to_owned())
                         } else {
-                            format!("{}.to_owned()", l)
+                            sugg_msg = "create an owned `String` on the left and add a borrow on the right";
+                            (lhs_expr.span.shrink_to_hi(), ".to_owned()".to_owned())
                         };
-                        err.multipart_suggestion(
-                            msg,
-                            vec![
-                                (lhs_expr.span, to_string),
-                                (rhs_expr.span, format!("&{}", r)),
-                            ],
+                        let suggestions = vec![
+                            lhs_sugg,
+                            (rhs_expr.span.shrink_to_lo(), "&".to_owned()),
+                        ];
+                        err.multipart_suggestion_verbose(
+                            sugg_msg,
+                            suggestions,
                             Applicability::MachineApplicable,
                         );
                     }
-                    _ => {
-                        err.help(msg);
+                    IsAssign::Yes => {
+                        err.note(str_concat_note);
                     }
-                };
+                }
                 true
             }
             _ => false,
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 606a2d6a24e..71f45320e49 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -312,7 +312,7 @@ fn check_gat_where_clauses(
         // of  the function signature. In our example, the GAT in the return
         // type is `<Self as LendingIterator>::Item<'a>`, so 'a and Self are arguments.
         let (regions, types) =
-            GATSubstCollector::visit(trait_item.def_id.to_def_id(), sig.output());
+            GATSubstCollector::visit(tcx, trait_item.def_id.to_def_id(), sig.output());
 
         // If both regions and types are empty, then this GAT isn't in the
         // return type, and we shouldn't try to do clause analysis
@@ -602,6 +602,7 @@ fn resolve_regions_with_wf_tys<'tcx>(
 /// the two vectors, `regions` and `types` (depending on their kind). For each
 /// parameter `Pi` also track the index `i`.
 struct GATSubstCollector<'tcx> {
+    tcx: TyCtxt<'tcx>,
     gat: DefId,
     // Which region appears and which parameter index its subsituted for
     regions: FxHashSet<(ty::Region<'tcx>, usize)>,
@@ -611,11 +612,16 @@ struct GATSubstCollector<'tcx> {
 
 impl<'tcx> GATSubstCollector<'tcx> {
     fn visit<T: TypeFoldable<'tcx>>(
+        tcx: TyCtxt<'tcx>,
         gat: DefId,
         t: T,
     ) -> (FxHashSet<(ty::Region<'tcx>, usize)>, FxHashSet<(Ty<'tcx>, usize)>) {
-        let mut visitor =
-            GATSubstCollector { gat, regions: FxHashSet::default(), types: FxHashSet::default() };
+        let mut visitor = GATSubstCollector {
+            tcx,
+            gat,
+            regions: FxHashSet::default(),
+            types: FxHashSet::default(),
+        };
         t.visit_with(&mut visitor);
         (visitor.regions, visitor.types)
     }
@@ -624,6 +630,13 @@ impl<'tcx> GATSubstCollector<'tcx> {
 impl<'tcx> TypeVisitor<'tcx> for GATSubstCollector<'tcx> {
     type BreakTy = !;
 
+    fn visit_binder<T: TypeFoldable<'tcx>>(
+        &mut self,
+        t: &ty::Binder<'tcx, T>,
+    ) -> ControlFlow<Self::BreakTy> {
+        self.tcx.liberate_late_bound_regions(self.gat, t.clone()).visit_with(self)
+    }
+
     fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
         match t.kind() {
             ty::Projection(p) if p.item_def_id == self.gat => {
@@ -851,7 +864,7 @@ fn check_associated_item(
                 let hir_sig = sig_if_method.expect("bad signature for method");
                 check_fn_or_method(
                     fcx,
-                    item.ident.span,
+                    item.ident(fcx.tcx).span,
                     sig,
                     hir_sig.decl,
                     item.def_id,
diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
index 59f211bd2c3..a409201372b 100644
--- a/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs
@@ -36,7 +36,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
 
         for item1 in impl_items1.in_definition_order() {
             let collision = impl_items2
-                .filter_by_name_unhygienic(item1.ident.name)
+                .filter_by_name_unhygienic(item1.name)
                 .any(|item2| self.compare_hygienically(item1, item2));
 
             if collision {
@@ -50,7 +50,8 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
     fn compare_hygienically(&self, item1: &ty::AssocItem, item2: &ty::AssocItem) -> bool {
         // Symbols and namespace match, compare hygienically.
         item1.kind.namespace() == item2.kind.namespace()
-            && item1.ident.normalize_to_macros_2_0() == item2.ident.normalize_to_macros_2_0()
+            && item1.ident(self.tcx).normalize_to_macros_2_0()
+                == item2.ident(self.tcx).normalize_to_macros_2_0()
     }
 
     fn check_for_common_items_in_impls(
@@ -64,11 +65,11 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
 
         for item1 in impl_items1.in_definition_order() {
             let collision = impl_items2
-                .filter_by_name_unhygienic(item1.ident.name)
+                .filter_by_name_unhygienic(item1.name)
                 .find(|item2| self.compare_hygienically(item1, item2));
 
             if let Some(item2) = collision {
-                let name = item1.ident.normalize_to_macros_2_0();
+                let name = item1.ident(self.tcx).normalize_to_macros_2_0();
                 let mut err = struct_span_err!(
                     self.tcx.sess,
                     self.tcx.span_of_impl(item1.def_id).unwrap(),
@@ -181,11 +182,11 @@ impl<'tcx> ItemLikeVisitor<'_> for InherentOverlapChecker<'tcx> {
                         let mut ids = impl_items
                             .in_definition_order()
                             .filter_map(|item| {
-                                let entry = connected_region_ids.entry(item.ident.name);
+                                let entry = connected_region_ids.entry(item.name);
                                 if let Entry::Occupied(e) = &entry {
                                     Some(*e.get())
                                 } else {
-                                    idents_to_add.push(item.ident.name);
+                                    idents_to_add.push(item.name);
                                     None
                                 }
                             })
diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs
index 6fc6002d551..56a47001811 100644
--- a/library/alloc/src/collections/binary_heap.rs
+++ b/library/alloc/src/collections/binary_heap.rs
@@ -433,7 +433,7 @@ impl<T: Ord> BinaryHeap<T> {
     ///
     /// ```
     /// use std::collections::BinaryHeap;
-    /// let mut heap = BinaryHeap::from(vec![1, 3]);
+    /// let mut heap = BinaryHeap::from([1, 3]);
     ///
     /// assert_eq!(heap.pop(), Some(3));
     /// assert_eq!(heap.pop(), Some(1));
@@ -506,7 +506,7 @@ impl<T: Ord> BinaryHeap<T> {
     /// ```
     /// use std::collections::BinaryHeap;
     ///
-    /// let mut heap = BinaryHeap::from(vec![1, 2, 4, 5, 7]);
+    /// let mut heap = BinaryHeap::from([1, 2, 4, 5, 7]);
     /// heap.push(6);
     /// heap.push(3);
     ///
@@ -725,11 +725,8 @@ impl<T: Ord> BinaryHeap<T> {
     /// ```
     /// use std::collections::BinaryHeap;
     ///
-    /// let v = vec![-10, 1, 2, 3, 3];
-    /// let mut a = BinaryHeap::from(v);
-    ///
-    /// let v = vec![-20, 5, 43];
-    /// let mut b = BinaryHeap::from(v);
+    /// let mut a = BinaryHeap::from([-10, 1, 2, 3, 3]);
+    /// let mut b = BinaryHeap::from([-20, 5, 43]);
     ///
     /// a.append(&mut b);
     ///
@@ -765,7 +762,7 @@ impl<T: Ord> BinaryHeap<T> {
     /// #![feature(binary_heap_drain_sorted)]
     /// use std::collections::BinaryHeap;
     ///
-    /// let mut heap = BinaryHeap::from(vec![1, 2, 3, 4, 5]);
+    /// let mut heap = BinaryHeap::from([1, 2, 3, 4, 5]);
     /// assert_eq!(heap.len(), 5);
     ///
     /// drop(heap.drain_sorted()); // removes all elements in heap order
@@ -790,7 +787,7 @@ impl<T: Ord> BinaryHeap<T> {
     /// #![feature(binary_heap_retain)]
     /// use std::collections::BinaryHeap;
     ///
-    /// let mut heap = BinaryHeap::from(vec![-10, -5, 1, 2, 4, 13]);
+    /// let mut heap = BinaryHeap::from([-10, -5, 1, 2, 4, 13]);
     ///
     /// heap.retain(|x| x % 2 == 0); // only keep even numbers
     ///
@@ -826,7 +823,7 @@ impl<T> BinaryHeap<T> {
     ///
     /// ```
     /// use std::collections::BinaryHeap;
-    /// let heap = BinaryHeap::from(vec![1, 2, 3, 4]);
+    /// let heap = BinaryHeap::from([1, 2, 3, 4]);
     ///
     /// // Print 1, 2, 3, 4 in arbitrary order
     /// for x in heap.iter() {
@@ -848,9 +845,9 @@ impl<T> BinaryHeap<T> {
     /// ```
     /// #![feature(binary_heap_into_iter_sorted)]
     /// use std::collections::BinaryHeap;
-    /// let heap = BinaryHeap::from(vec![1, 2, 3, 4, 5]);
+    /// let heap = BinaryHeap::from([1, 2, 3, 4, 5]);
     ///
-    /// assert_eq!(heap.into_iter_sorted().take(2).collect::<Vec<_>>(), vec![5, 4]);
+    /// assert_eq!(heap.into_iter_sorted().take(2).collect::<Vec<_>>(), [5, 4]);
     /// ```
     #[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")]
     pub fn into_iter_sorted(self) -> IntoIterSorted<T> {
@@ -1086,7 +1083,7 @@ impl<T> BinaryHeap<T> {
     /// use std::collections::BinaryHeap;
     /// use std::io::{self, Write};
     ///
-    /// let heap = BinaryHeap::from(vec![1, 2, 3, 4, 5, 6, 7]);
+    /// let heap = BinaryHeap::from([1, 2, 3, 4, 5, 6, 7]);
     ///
     /// io::sink().write(heap.as_slice()).unwrap();
     /// ```
@@ -1105,7 +1102,7 @@ impl<T> BinaryHeap<T> {
     ///
     /// ```
     /// use std::collections::BinaryHeap;
-    /// let heap = BinaryHeap::from(vec![1, 2, 3, 4, 5, 6, 7]);
+    /// let heap = BinaryHeap::from([1, 2, 3, 4, 5, 6, 7]);
     /// let vec = heap.into_vec();
     ///
     /// // Will print in some order
@@ -1127,7 +1124,7 @@ impl<T> BinaryHeap<T> {
     ///
     /// ```
     /// use std::collections::BinaryHeap;
-    /// let heap = BinaryHeap::from(vec![1, 3]);
+    /// let heap = BinaryHeap::from([1, 3]);
     ///
     /// assert_eq!(heap.len(), 2);
     /// ```
@@ -1171,7 +1168,7 @@ impl<T> BinaryHeap<T> {
     ///
     /// ```
     /// use std::collections::BinaryHeap;
-    /// let mut heap = BinaryHeap::from(vec![1, 3]);
+    /// let mut heap = BinaryHeap::from([1, 3]);
     ///
     /// assert!(!heap.is_empty());
     ///
@@ -1195,7 +1192,7 @@ impl<T> BinaryHeap<T> {
     ///
     /// ```
     /// use std::collections::BinaryHeap;
-    /// let mut heap = BinaryHeap::from(vec![1, 3]);
+    /// let mut heap = BinaryHeap::from([1, 3]);
     ///
     /// assert!(!heap.is_empty());
     ///
@@ -1616,7 +1613,7 @@ impl<T> IntoIterator for BinaryHeap<T> {
     ///
     /// ```
     /// use std::collections::BinaryHeap;
-    /// let heap = BinaryHeap::from(vec![1, 2, 3, 4]);
+    /// let heap = BinaryHeap::from([1, 2, 3, 4]);
     ///
     /// // Print 1, 2, 3, 4 in arbitrary order
     /// for x in heap.into_iter() {
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 794b9356e7c..cdb961d4cfb 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -1098,10 +1098,8 @@ impl<K, V> BTreeMap<K, V> {
     /// ```
     /// use std::collections::BTreeMap;
     ///
-    /// let mut map: BTreeMap<&str, i32> = ["Alice", "Bob", "Carol", "Cheryl"]
-    ///     .iter()
-    ///     .map(|&s| (s, 0))
-    ///     .collect();
+    /// let mut map: BTreeMap<&str, i32> =
+    ///     [("Alice", 0), ("Bob", 0), ("Carol", 0), ("Cheryl", 0)].into();
     /// for (_, balance) in map.range_mut("B".."Cheryl") {
     ///     *balance += 100;
     /// }
@@ -1135,7 +1133,7 @@ impl<K, V> BTreeMap<K, V> {
     /// let mut count: BTreeMap<&str, usize> = BTreeMap::new();
     ///
     /// // count the number of occurrences of letters in the vec
-    /// for x in vec!["a", "b", "a", "c", "a", "b"] {
+    /// for x in ["a", "b", "a", "c", "a", "b"] {
     ///     *count.entry(x).or_insert(0) += 1;
     /// }
     ///
@@ -1235,8 +1233,8 @@ impl<K, V> BTreeMap<K, V> {
     /// let mut map: BTreeMap<i32, i32> = (0..8).map(|x| (x, x)).collect();
     /// let evens: BTreeMap<_, _> = map.drain_filter(|k, _v| k % 2 == 0).collect();
     /// let odds = map;
-    /// assert_eq!(evens.keys().copied().collect::<Vec<_>>(), vec![0, 2, 4, 6]);
-    /// assert_eq!(odds.keys().copied().collect::<Vec<_>>(), vec![1, 3, 5, 7]);
+    /// assert_eq!(evens.keys().copied().collect::<Vec<_>>(), [0, 2, 4, 6]);
+    /// assert_eq!(odds.keys().copied().collect::<Vec<_>>(), [1, 3, 5, 7]);
     /// ```
     #[unstable(feature = "btree_drain_filter", issue = "70530")]
     pub fn drain_filter<F>(&mut self, pred: F) -> DrainFilter<'_, K, V, F>
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index 1259c53bfab..a8a18d65585 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -669,7 +669,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut buf: VecDeque<i32> = [1].into_iter().collect();
+    /// let mut buf: VecDeque<i32> = [1].into();
     /// buf.reserve_exact(10);
     /// assert!(buf.capacity() >= 11);
     /// ```
@@ -692,7 +692,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut buf: VecDeque<i32> = [1].into_iter().collect();
+    /// let mut buf: VecDeque<i32> = [1].into();
     /// buf.reserve(10);
     /// assert!(buf.capacity() >= 11);
     /// ```
@@ -1153,7 +1153,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let v: VecDeque<_> = [1, 2, 3].into_iter().collect();
+    /// let v: VecDeque<_> = [1, 2, 3].into();
     /// let range = v.range(2..).copied().collect::<VecDeque<_>>();
     /// assert_eq!(range, [3]);
     ///
@@ -1188,17 +1188,17 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut v: VecDeque<_> = [1, 2, 3].into_iter().collect();
+    /// let mut v: VecDeque<_> = [1, 2, 3].into();
     /// for v in v.range_mut(2..) {
     ///   *v *= 2;
     /// }
-    /// assert_eq!(v, vec![1, 2, 6]);
+    /// assert_eq!(v, [1, 2, 6]);
     ///
     /// // A full range covers all contents
     /// for v in v.range_mut(..) {
     ///   *v *= 2;
     /// }
-    /// assert_eq!(v, vec![2, 4, 12]);
+    /// assert_eq!(v, [2, 4, 12]);
     /// ```
     #[inline]
     #[stable(feature = "deque_range", since = "1.51.0")]
@@ -1235,7 +1235,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut v: VecDeque<_> = [1, 2, 3].into_iter().collect();
+    /// let mut v: VecDeque<_> = [1, 2, 3].into();
     /// let drained = v.drain(2..).collect::<VecDeque<_>>();
     /// assert_eq!(drained, [3]);
     /// assert_eq!(v, [1, 2]);
@@ -2025,7 +2025,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut buf: VecDeque<_> = [1, 2, 3].into_iter().collect();
+    /// let mut buf: VecDeque<_> = [1, 2, 3].into();
     /// let buf2 = buf.split_off(1);
     /// assert_eq!(buf, [1]);
     /// assert_eq!(buf2, [2, 3]);
@@ -2091,8 +2091,8 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut buf: VecDeque<_> = [1, 2].into_iter().collect();
-    /// let mut buf2: VecDeque<_> = [3, 4].into_iter().collect();
+    /// let mut buf: VecDeque<_> = [1, 2].into();
+    /// let mut buf2: VecDeque<_> = [3, 4].into();
     /// buf.append(&mut buf2);
     /// assert_eq!(buf, [1, 2, 3, 4]);
     /// assert_eq!(buf2, []);
@@ -2547,7 +2547,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
+    /// let deque: VecDeque<_> = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
     ///
     /// assert_eq!(deque.binary_search(&13),  Ok(9));
     /// assert_eq!(deque.binary_search(&4),   Err(7));
@@ -2562,7 +2562,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let mut deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
+    /// let mut deque: VecDeque<_> = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
     /// let num = 42;
     /// let idx = deque.binary_search(&num).unwrap_or_else(|x| x);
     /// deque.insert(idx, num);
@@ -2605,7 +2605,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
+    /// let deque: VecDeque<_> = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into();
     ///
     /// assert_eq!(deque.binary_search_by(|x| x.cmp(&13)),  Ok(9));
     /// assert_eq!(deque.binary_search_by(|x| x.cmp(&4)),   Err(7));
@@ -2658,7 +2658,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let deque: VecDeque<_> = vec![(0, 0), (2, 1), (4, 1), (5, 1),
+    /// let deque: VecDeque<_> = [(0, 0), (2, 1), (4, 1), (5, 1),
     ///          (3, 1), (1, 2), (2, 3), (4, 5), (5, 8), (3, 13),
     ///          (1, 21), (2, 34), (4, 55)].into();
     ///
@@ -2701,7 +2701,7 @@ impl<T, A: Allocator> VecDeque<T, A> {
     /// ```
     /// use std::collections::VecDeque;
     ///
-    /// let deque: VecDeque<_> = vec![1, 2, 3, 3, 5, 6, 7].into();
+    /// let deque: VecDeque<_> = [1, 2, 3, 3, 5, 6, 7].into();
     /// let i = deque.partition_point(|&x| x < 5);
     ///
     /// assert_eq!(i, 4);
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 1cbc2b65f4d..dfd3771c1d0 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -67,17 +67,14 @@
     issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/",
     test(no_crate_inject, attr(allow(unused_variables), deny(warnings)))
 )]
-#![cfg_attr(
-    not(bootstrap),
-    doc(cfg_hide(
-        not(test),
-        not(any(test, bootstrap)),
-        any(not(feature = "miri-test-libstd"), test, doctest),
-        no_global_oom_handling,
-        not(no_global_oom_handling),
-        target_has_atomic = "ptr"
-    ))
-)]
+#![doc(cfg_hide(
+    not(test),
+    not(any(test, bootstrap)),
+    any(not(feature = "miri-test-libstd"), test, doctest),
+    no_global_oom_handling,
+    not(no_global_oom_handling),
+    target_has_atomic = "ptr"
+))]
 #![no_std]
 #![needs_allocator]
 //
@@ -151,7 +148,6 @@
 #![feature(const_precise_live_drops)]
 #![feature(const_trait_impl)]
 #![feature(const_try)]
-#![cfg_attr(bootstrap, feature(destructuring_assignment))]
 #![feature(dropck_eyepatch)]
 #![feature(exclusive_range_pattern)]
 #![feature(fundamental)]
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 33bee4324fd..78bf28c843c 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -374,33 +374,51 @@ impl<T> Rc<T> {
         }
     }
 
-    /// Constructs a new `Rc<T>` using a weak reference to itself. Attempting
-    /// to upgrade the weak reference before this function returns will result
-    /// in a `None` value. However, the weak reference may be cloned freely and
-    /// stored for use at a later time.
+    /// Constructs a new `Rc<T>` using a closure `data_fn` that has access to a
+    /// weak reference to the constructing `Rc<T>`.
+    ///
+    /// Generally, a structure circularly referencing itself, either directly or
+    /// indirectly, should not hold a strong reference to prevent a memory leak.
+    /// In `data_fn`, initialization of `T` can make use of the weak reference
+    /// by cloning and storing it inside `T` for use at a later time.
+    ///
+    /// Since the new `Rc<T>` is not fully-constructed until `Rc<T>::new_cyclic`
+    /// returns, calling [`upgrade`] on the weak reference inside `data_fn` will
+    /// fail and result in a `None` value.
+    ///
+    /// # Panics
+    /// If `data_fn` panics, the panic is propagated to the caller, and the
+    /// temporary [`Weak<T>`] is dropped normally.
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(arc_new_cyclic)]
     /// #![allow(dead_code)]
     /// use std::rc::{Rc, Weak};
     ///
     /// struct Gadget {
-    ///     self_weak: Weak<Self>,
-    ///     // ... more fields
+    ///     me: Weak<Gadget>,
     /// }
+    ///
     /// impl Gadget {
-    ///     pub fn new() -> Rc<Self> {
-    ///         Rc::new_cyclic(|self_weak| {
-    ///             Gadget { self_weak: self_weak.clone(), /* ... */ }
-    ///         })
+    ///     /// Construct a reference counted Gadget.
+    ///     fn new() -> Rc<Self> {
+    ///         Rc::new_cyclic(|me| Gadget { me: me.clone() })
+    ///     }
+    ///
+    ///     /// Return a reference counted pointer to Self.
+    ///     fn me(&self) -> Rc<Self> {
+    ///         self.me.upgrade().unwrap()
     ///     }
     /// }
     /// ```
+    /// [`upgrade`]: Weak::upgrade
     #[cfg(not(no_global_oom_handling))]
-    #[unstable(feature = "arc_new_cyclic", issue = "75861")]
-    pub fn new_cyclic(data_fn: impl FnOnce(&Weak<T>) -> T) -> Rc<T> {
+    #[stable(feature = "arc_new_cyclic", since = "1.60.0")]
+    pub fn new_cyclic<F>(data_fn: F) -> Rc<T>
+    where
+        F: FnOnce(&Weak<T>) -> T,
+    {
         // Construct the inner in the "uninitialized" state with a single
         // weak reference.
         let uninit_ptr: NonNull<_> = Box::leak(box RcBox {
@@ -451,12 +469,10 @@ impl<T> Rc<T> {
     ///
     /// let mut five = Rc::<u32>::new_uninit();
     ///
-    /// let five = unsafe {
-    ///     // Deferred initialization:
-    ///     Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
+    /// // Deferred initialization:
+    /// Rc::get_mut(&mut five).unwrap().write(5);
     ///
-    ///     five.assume_init()
-    /// };
+    /// let five = unsafe { five.assume_init() };
     ///
     /// assert_eq!(*five, 5)
     /// ```
@@ -543,12 +559,10 @@ impl<T> Rc<T> {
     ///
     /// let mut five = Rc::<u32>::try_new_uninit()?;
     ///
-    /// let five = unsafe {
-    ///     // Deferred initialization:
-    ///     Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
+    /// // Deferred initialization:
+    /// Rc::get_mut(&mut five).unwrap().write(5);
     ///
-    ///     five.assume_init()
-    /// };
+    /// let five = unsafe { five.assume_init() };
     ///
     /// assert_eq!(*five, 5);
     /// # Ok::<(), std::alloc::AllocError>(())
@@ -660,14 +674,13 @@ impl<T> Rc<[T]> {
     ///
     /// let mut values = Rc::<[u32]>::new_uninit_slice(3);
     ///
-    /// let values = unsafe {
-    ///     // Deferred initialization:
-    ///     Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
-    ///     Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
-    ///     Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
+    /// // Deferred initialization:
+    /// let data = Rc::get_mut(&mut values).unwrap();
+    /// data[0].write(1);
+    /// data[1].write(2);
+    /// data[2].write(3);
     ///
-    ///     values.assume_init()
-    /// };
+    /// let values = unsafe { values.assume_init() };
     ///
     /// assert_eq!(*values, [1, 2, 3])
     /// ```
@@ -738,12 +751,10 @@ impl<T> Rc<mem::MaybeUninit<T>> {
     ///
     /// let mut five = Rc::<u32>::new_uninit();
     ///
-    /// let five = unsafe {
-    ///     // Deferred initialization:
-    ///     Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
+    /// // Deferred initialization:
+    /// Rc::get_mut(&mut five).unwrap().write(5);
     ///
-    ///     five.assume_init()
-    /// };
+    /// let five = unsafe { five.assume_init() };
     ///
     /// assert_eq!(*five, 5)
     /// ```
@@ -777,14 +788,13 @@ impl<T> Rc<[mem::MaybeUninit<T>]> {
     ///
     /// let mut values = Rc::<[u32]>::new_uninit_slice(3);
     ///
-    /// let values = unsafe {
-    ///     // Deferred initialization:
-    ///     Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
-    ///     Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
-    ///     Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
+    /// // Deferred initialization:
+    /// let data = Rc::get_mut(&mut values).unwrap();
+    /// data[0].write(1);
+    /// data[1].write(2);
+    /// data[2].write(3);
     ///
-    ///     values.assume_init()
-    /// };
+    /// let values = unsafe { values.assume_init() };
     ///
     /// assert_eq!(*values, [1, 2, 3])
     /// ```
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 7c065f37d1f..64f21d087da 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -351,30 +351,51 @@ impl<T> Arc<T> {
         unsafe { Self::from_inner(Box::leak(x).into()) }
     }
 
-    /// Constructs a new `Arc<T>` using a weak reference to itself. Attempting
-    /// to upgrade the weak reference before this function returns will result
-    /// in a `None` value. However, the weak reference may be cloned freely and
-    /// stored for use at a later time.
+    /// Constructs a new `Arc<T>` using a closure `data_fn` that has access to
+    /// a weak reference to the constructing `Arc<T>`.
     ///
-    /// # Examples
+    /// Generally, a structure circularly referencing itself, either directly or
+    /// indirectly, should not hold a strong reference to prevent a memory leak.
+    /// In `data_fn`, initialization of `T` can make use of the weak reference
+    /// by cloning and storing it inside `T` for use at a later time.
+    ///
+    /// Since the new `Arc<T>` is not fully-constructed until
+    /// `Arc<T>::new_cyclic` returns, calling [`upgrade`] on the weak
+    /// reference inside `data_fn` will fail and result in a `None` value.
+    ///
+    /// # Panics
+    /// If `data_fn` panics, the panic is propagated to the caller, and the
+    /// temporary [`Weak<T>`] is dropped normally.
+    ///
+    /// # Example
     /// ```
-    /// #![feature(arc_new_cyclic)]
     /// #![allow(dead_code)]
-    ///
     /// use std::sync::{Arc, Weak};
     ///
-    /// struct Foo {
-    ///     me: Weak<Foo>,
+    /// struct Gadget {
+    ///     me: Weak<Gadget>,
     /// }
     ///
-    /// let foo = Arc::new_cyclic(|me| Foo {
-    ///     me: me.clone(),
-    /// });
+    /// impl Gadget {
+    ///     /// Construct a reference counted Gadget.
+    ///     fn new() -> Arc<Self> {
+    ///         Arc::new_cyclic(|me| Gadget { me: me.clone() })
+    ///     }
+    ///
+    ///     /// Return a reference counted pointer to Self.
+    ///     fn me(&self) -> Arc<Self> {
+    ///         self.me.upgrade().unwrap()
+    ///     }
+    /// }
     /// ```
+    /// [`upgrade`]: Weak::upgrade
     #[cfg(not(no_global_oom_handling))]
     #[inline]
-    #[unstable(feature = "arc_new_cyclic", issue = "75861")]
-    pub fn new_cyclic(data_fn: impl FnOnce(&Weak<T>) -> T) -> Arc<T> {
+    #[stable(feature = "arc_new_cyclic", since = "1.60.0")]
+    pub fn new_cyclic<F>(data_fn: F) -> Arc<T>
+    where
+        F: FnOnce(&Weak<T>) -> T,
+    {
         // Construct the inner in the "uninitialized" state with a single
         // weak reference.
         let uninit_ptr: NonNull<_> = Box::leak(box ArcInner {
@@ -437,12 +458,10 @@ impl<T> Arc<T> {
     ///
     /// let mut five = Arc::<u32>::new_uninit();
     ///
-    /// let five = unsafe {
-    ///     // Deferred initialization:
-    ///     Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
+    /// // Deferred initialization:
+    /// Arc::get_mut(&mut five).unwrap().write(5);
     ///
-    ///     five.assume_init()
-    /// };
+    /// let five = unsafe { five.assume_init() };
     ///
     /// assert_eq!(*five, 5)
     /// ```
@@ -545,12 +564,10 @@ impl<T> Arc<T> {
     ///
     /// let mut five = Arc::<u32>::try_new_uninit()?;
     ///
-    /// let five = unsafe {
-    ///     // Deferred initialization:
-    ///     Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
+    /// // Deferred initialization:
+    /// Arc::get_mut(&mut five).unwrap().write(5);
     ///
-    ///     five.assume_init()
-    /// };
+    /// let five = unsafe { five.assume_init() };
     ///
     /// assert_eq!(*five, 5);
     /// # Ok::<(), std::alloc::AllocError>(())
@@ -652,14 +669,13 @@ impl<T> Arc<[T]> {
     ///
     /// let mut values = Arc::<[u32]>::new_uninit_slice(3);
     ///
-    /// let values = unsafe {
-    ///     // Deferred initialization:
-    ///     Arc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
-    ///     Arc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
-    ///     Arc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
+    /// // Deferred initialization:
+    /// let data = Arc::get_mut(&mut values).unwrap();
+    /// data[0].write(1);
+    /// data[1].write(2);
+    /// data[2].write(3);
     ///
-    ///     values.assume_init()
-    /// };
+    /// let values = unsafe { values.assume_init() };
     ///
     /// assert_eq!(*values, [1, 2, 3])
     /// ```
@@ -730,12 +746,10 @@ impl<T> Arc<mem::MaybeUninit<T>> {
     ///
     /// let mut five = Arc::<u32>::new_uninit();
     ///
-    /// let five = unsafe {
-    ///     // Deferred initialization:
-    ///     Arc::get_mut_unchecked(&mut five).as_mut_ptr().write(5);
+    /// // Deferred initialization:
+    /// Arc::get_mut(&mut five).unwrap().write(5);
     ///
-    ///     five.assume_init()
-    /// };
+    /// let five = unsafe { five.assume_init() };
     ///
     /// assert_eq!(*five, 5)
     /// ```
@@ -770,14 +784,13 @@ impl<T> Arc<[mem::MaybeUninit<T>]> {
     ///
     /// let mut values = Arc::<[u32]>::new_uninit_slice(3);
     ///
-    /// let values = unsafe {
-    ///     // Deferred initialization:
-    ///     Arc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(1);
-    ///     Arc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(2);
-    ///     Arc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(3);
+    /// // Deferred initialization:
+    /// let data = Arc::get_mut(&mut values).unwrap();
+    /// data[0].write(1);
+    /// data[1].write(2);
+    /// data[2].write(3);
     ///
-    ///     values.assume_init()
-    /// };
+    /// let values = unsafe { values.assume_init() };
     ///
     /// assert_eq!(*values, [1, 2, 3])
     /// ```
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index bc3f7167fac..5fd60b75928 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -1310,11 +1310,7 @@ impl Clone for BorrowRef<'_> {
 ///
 /// See the [module-level documentation](self) for more.
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(
-    not(bootstrap),
-    must_not_suspend = "holding a Ref across suspend \
-                      points can cause BorrowErrors"
-)]
+#[must_not_suspend = "holding a Ref across suspend points can cause BorrowErrors"]
 pub struct Ref<'b, T: ?Sized + 'b> {
     value: &'b T,
     borrow: BorrowRef<'b>,
@@ -1692,11 +1688,7 @@ impl<'b> BorrowRefMut<'b> {
 ///
 /// See the [module-level documentation](self) for more.
 #[stable(feature = "rust1", since = "1.0.0")]
-#[cfg_attr(
-    not(bootstrap),
-    must_not_suspend = "holding a RefMut across suspend \
-                      points can cause BorrowErrors"
-)]
+#[must_not_suspend = "holding a RefMut across suspend points can cause BorrowErrors"]
 pub struct RefMut<'b, T: ?Sized + 'b> {
     value: &'b mut T,
     borrow: BorrowRefMut<'b>,
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index f89cf812e97..a3e77479911 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -199,9 +199,20 @@ use self::Ordering::*;
 #[stable(feature = "rust1", since = "1.0.0")]
 #[doc(alias = "==")]
 #[doc(alias = "!=")]
-#[rustc_on_unimplemented(
-    message = "can't compare `{Self}` with `{Rhs}`",
-    label = "no implementation for `{Self} == {Rhs}`"
+#[cfg_attr(
+    bootstrap,
+    rustc_on_unimplemented(
+        message = "can't compare `{Self}` with `{Rhs}`",
+        label = "no implementation for `{Self} == {Rhs}`"
+    )
+)]
+#[cfg_attr(
+    not(bootstrap),
+    rustc_on_unimplemented(
+        message = "can't compare `{Self}` with `{Rhs}`",
+        label = "no implementation for `{Self} == {Rhs}`",
+        append_const_msg,
+    )
 )]
 #[rustc_diagnostic_item = "PartialEq"]
 pub trait PartialEq<Rhs: ?Sized = Self> {
@@ -869,7 +880,7 @@ impl PartialOrd for Ordering {
     }
 }
 
-/// Trait for values that can be compared for a sort-order.
+/// Trait for types that form a [partial order](https://en.wikipedia.org/wiki/Partial_order).
 ///
 /// The `lt`, `le`, `gt`, and `ge` methods of this trait can be called using
 /// the `<`, `<=`, `>`, and `>=` operators, respectively.
@@ -1031,9 +1042,20 @@ impl PartialOrd for Ordering {
 #[doc(alias = "<")]
 #[doc(alias = "<=")]
 #[doc(alias = ">=")]
-#[rustc_on_unimplemented(
-    message = "can't compare `{Self}` with `{Rhs}`",
-    label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`"
+#[cfg_attr(
+    bootstrap,
+    rustc_on_unimplemented(
+        message = "can't compare `{Self}` with `{Rhs}`",
+        label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`",
+    )
+)]
+#[cfg_attr(
+    not(bootstrap),
+    rustc_on_unimplemented(
+        message = "can't compare `{Self}` with `{Rhs}`",
+        label = "no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`",
+        append_const_msg,
+    )
 )]
 #[rustc_diagnostic_item = "PartialOrd"]
 pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 8a2a64f8dc9..e1ea9881303 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -308,9 +308,21 @@ static USIZE_MARKER: fn(&usize, &mut Formatter<'_>) -> Result = |ptr, _| {
     loop {}
 };
 
+macro_rules! arg_new {
+    ($f: ident, $t: ident) => {
+        #[doc(hidden)]
+        #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
+        #[inline]
+        pub fn $f<'b, T: $t>(x: &'b T) -> ArgumentV1<'_> {
+            Self::new(x, $t::fmt)
+        }
+    };
+}
+
 impl<'a> ArgumentV1<'a> {
     #[doc(hidden)]
     #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
+    #[inline]
     pub fn new<'b, T>(x: &'b T, f: fn(&T, &mut Formatter<'_>) -> Result) -> ArgumentV1<'b> {
         // SAFETY: `mem::transmute(x)` is safe because
         //     1. `&'b T` keeps the lifetime it originated with `'b`
@@ -323,6 +335,16 @@ impl<'a> ArgumentV1<'a> {
         unsafe { ArgumentV1 { formatter: mem::transmute(f), value: mem::transmute(x) } }
     }
 
+    arg_new!(new_display, Display);
+    arg_new!(new_debug, Debug);
+    arg_new!(new_octal, Octal);
+    arg_new!(new_lower_hex, LowerHex);
+    arg_new!(new_upper_hex, UpperHex);
+    arg_new!(new_pointer, Pointer);
+    arg_new!(new_binary, Binary);
+    arg_new!(new_lower_exp, LowerExp);
+    arg_new!(new_upper_exp, UpperExp);
+
     #[doc(hidden)]
     #[unstable(feature = "fmt_internals", reason = "internal to format_args!", issue = "none")]
     pub fn from_usize(x: &usize) -> ArgumentV1<'_> {
diff --git a/library/core/src/future/into_future.rs b/library/core/src/future/into_future.rs
index cac1866188e..0912f8675fa 100644
--- a/library/core/src/future/into_future.rs
+++ b/library/core/src/future/into_future.rs
@@ -13,7 +13,7 @@ pub trait IntoFuture {
 
     /// Creates a future from a value.
     #[unstable(feature = "into_future", issue = "67644")]
-    #[cfg_attr(not(bootstrap), lang = "into_future")]
+    #[lang = "into_future"]
     fn into_future(self) -> Self::Future;
 }
 
diff --git a/library/core/src/future/join.rs b/library/core/src/future/join.rs
index a6ffbe07d91..fa4eb0d2f33 100644
--- a/library/core/src/future/join.rs
+++ b/library/core/src/future/join.rs
@@ -9,7 +9,7 @@ use crate::task::{Context, Poll};
 /// Polls multiple futures simultaneously, returning a tuple
 /// of all results once complete.
 ///
-/// While `join!(a, b)` is similar to `(a.await, b.await)`,
+/// While `join!(a, b).await` is similar to `(a.await, b.await)`,
 /// `join!` polls both futures concurrently and is therefore more efficient.
 ///
 /// # Examples
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 9781dc320ed..b5228397f0a 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1914,10 +1914,31 @@ extern "rust-intrinsic" {
     #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")]
     pub fn ptr_guaranteed_ne<T>(ptr: *const T, other: *const T) -> bool;
 
-    /// Allocate at compile time. Should not be called at runtime.
+    /// Allocates a block of memory at compile time.
+    /// At runtime, just returns a null pointer.
+    ///
+    /// # Safety
+    ///
+    /// - The `align` argument must be a power of two.
+    ///    - At compile time, a compile error occurs if this constraint is violated.
+    ///    - At runtime, it is not checked.
     #[rustc_const_unstable(feature = "const_heap", issue = "79597")]
     pub fn const_allocate(size: usize, align: usize) -> *mut u8;
 
+    /// Deallocates a memory which allocated by `intrinsics::const_allocate` at compile time.
+    /// At runtime, does nothing.
+    ///
+    /// # Safety
+    ///
+    /// - The `align` argument must be a power of two.
+    ///    - At compile time, a compile error occurs if this constraint is violated.
+    ///    - At runtime, it is not checked.
+    /// - If the `ptr` is created in an another const, this intrinsic doesn't deallocate it.
+    /// - If the `ptr` is pointing to a local variable, this intrinsic doesn't deallocate it.
+    #[rustc_const_unstable(feature = "const_heap", issue = "79597")]
+    #[cfg(not(bootstrap))]
+    pub fn const_deallocate(ptr: *mut u8, size: usize, align: usize);
+
     /// Determines whether the raw bytes of the two values are equal.
     ///
     /// This is particularly handy for arrays, since it allows things like just
diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs
index 1d947297463..a8fe5f59bae 100644
--- a/library/core/src/iter/traits/iterator.rs
+++ b/library/core/src/iter/traits/iterator.rs
@@ -515,8 +515,44 @@ pub trait Iterator {
     /// assert_eq!((2, 'o'), zipper[2]);
     /// ```
     ///
+    /// If both iterators have roughly equivalent syntax, it may be more readable to use [`zip`]:
+    ///
+    /// ```
+    /// use std::iter::zip;
+    ///
+    /// let a = [1, 2, 3];
+    /// let b = [2, 3, 4];
+    ///
+    /// let mut zipped = zip(
+    ///     a.into_iter().map(|x| x * 2).skip(1),
+    ///     b.into_iter().map(|x| x * 2).skip(1),
+    /// );
+    ///
+    /// assert_eq!(zipped.next(), Some((4, 6)));
+    /// assert_eq!(zipped.next(), Some((6, 8)));
+    /// assert_eq!(zipped.next(), None);
+    /// ```
+    ///
+    /// compared to:
+    ///
+    /// ```
+    /// # let a = [1, 2, 3];
+    /// # let b = [2, 3, 4];
+    /// #
+    /// let mut zipped = a
+    ///     .into_iter()
+    ///     .map(|x| x * 2)
+    ///     .skip(1)
+    ///     .zip(b.into_iter().map(|x| x * 2).skip(1));
+    /// #
+    /// # assert_eq!(zipped.next(), Some((4, 6)));
+    /// # assert_eq!(zipped.next(), Some((6, 8)));
+    /// # assert_eq!(zipped.next(), None);
+    /// ```
+    ///
     /// [`enumerate`]: Iterator::enumerate
     /// [`next`]: Iterator::next
+    /// [`zip`]: crate::iter::zip
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn zip<U>(self, other: U) -> Zip<Self, U::IntoIter>
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index d8ac816fb15..e52d52e954c 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -60,32 +60,29 @@
     test(no_crate_inject, attr(deny(warnings))),
     test(attr(allow(dead_code, deprecated, unused_variables, unused_mut)))
 )]
-#![cfg_attr(
-    not(bootstrap),
-    doc(cfg_hide(
-        not(test),
-        any(not(feature = "miri-test-libstd"), test, doctest),
-        no_fp_fmt_parse,
-        target_pointer_width = "16",
-        target_pointer_width = "32",
-        target_pointer_width = "64",
-        target_has_atomic = "8",
-        target_has_atomic = "16",
-        target_has_atomic = "32",
-        target_has_atomic = "64",
-        target_has_atomic = "ptr",
-        target_has_atomic_equal_alignment = "8",
-        target_has_atomic_equal_alignment = "16",
-        target_has_atomic_equal_alignment = "32",
-        target_has_atomic_equal_alignment = "64",
-        target_has_atomic_equal_alignment = "ptr",
-        target_has_atomic_load_store = "8",
-        target_has_atomic_load_store = "16",
-        target_has_atomic_load_store = "32",
-        target_has_atomic_load_store = "64",
-        target_has_atomic_load_store = "ptr",
-    ))
-)]
+#![doc(cfg_hide(
+    not(test),
+    any(not(feature = "miri-test-libstd"), test, doctest),
+    no_fp_fmt_parse,
+    target_pointer_width = "16",
+    target_pointer_width = "32",
+    target_pointer_width = "64",
+    target_has_atomic = "8",
+    target_has_atomic = "16",
+    target_has_atomic = "32",
+    target_has_atomic = "64",
+    target_has_atomic = "ptr",
+    target_has_atomic_equal_alignment = "8",
+    target_has_atomic_equal_alignment = "16",
+    target_has_atomic_equal_alignment = "32",
+    target_has_atomic_equal_alignment = "64",
+    target_has_atomic_equal_alignment = "ptr",
+    target_has_atomic_load_store = "8",
+    target_has_atomic_load_store = "16",
+    target_has_atomic_load_store = "32",
+    target_has_atomic_load_store = "64",
+    target_has_atomic_load_store = "ptr",
+))]
 #![no_core]
 //
 // Lints:
@@ -374,6 +371,12 @@ pub mod arch {
     pub use crate::core_arch::arch::*;
 
     /// Inline assembly.
+    ///
+    /// Refer to [rust by example] for a usage guide and the [reference] for
+    /// detailed information about the syntax and available options.
+    ///
+    /// [rust by example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html
+    /// [reference]: https://doc.rust-lang.org/nightly/reference/inline-assembly.html
     #[stable(feature = "asm", since = "1.59.0")]
     #[rustc_builtin_macro]
     pub macro asm("assembly template", $(operands,)* $(options($(option),*))?) {
@@ -381,6 +384,12 @@ pub mod arch {
     }
 
     /// Module-level inline assembly.
+    ///
+    /// Refer to [rust by example] for a usage guide and the [reference] for
+    /// detailed information about the syntax and available options.
+    ///
+    /// [rust by example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html
+    /// [reference]: https://doc.rust-lang.org/nightly/reference/inline-assembly.html
     #[stable(feature = "global_asm", since = "1.59.0")]
     #[rustc_builtin_macro]
     pub macro global_asm("assembly template", $(operands,)* $(options($(option),*))?) {
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 488bb875c35..0cc428d6962 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1003,7 +1003,6 @@ pub(crate) mod builtin {
     /// assert_eq!(s, b"ABCDEF");
     /// # }
     /// ```
-    #[cfg(not(bootstrap))]
     #[unstable(feature = "concat_bytes", issue = "87555")]
     #[rustc_builtin_macro]
     #[macro_export]
diff --git a/library/core/src/num/saturating.rs b/library/core/src/num/saturating.rs
index 31755503475..8982473b2dc 100644
--- a/library/core/src/num/saturating.rs
+++ b/library/core/src/num/saturating.rs
@@ -217,18 +217,6 @@ macro_rules! saturating_impl {
         forward_ref_binop! { impl Add, add for Saturating<$t>, Saturating<$t>,
                 #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 
-        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
-        impl Add<$t> for Saturating<$t> {
-            type Output = Saturating<$t>;
-
-            #[inline]
-            fn add(self, other: $t) -> Saturating<$t> {
-                Saturating(self.0.saturating_add(other))
-            }
-        }
-        forward_ref_binop! { impl Add, add for Saturating<$t>, $t,
-                #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] }
-
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl AddAssign for Saturating<$t> {
             #[inline]
@@ -242,7 +230,7 @@ macro_rules! saturating_impl {
         impl AddAssign<$t> for Saturating<$t> {
             #[inline]
             fn add_assign(&mut self, other: $t) {
-                *self = *self + other;
+                *self = *self + Saturating(other);
             }
         }
         forward_ref_op_assign! { impl AddAssign, add_assign for Saturating<$t>, $t }
@@ -259,18 +247,6 @@ macro_rules! saturating_impl {
         forward_ref_binop! { impl Sub, sub for Saturating<$t>, Saturating<$t>,
                 #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 
-        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
-        impl Sub<$t> for Saturating<$t> {
-            type Output = Saturating<$t>;
-
-            #[inline]
-            fn sub(self, other: $t) -> Saturating<$t> {
-                Saturating(self.0.saturating_sub(other))
-            }
-        }
-        forward_ref_binop! { impl Sub, sub for Saturating<$t>, $t,
-                #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] }
-
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl SubAssign for Saturating<$t> {
             #[inline]
@@ -284,7 +260,7 @@ macro_rules! saturating_impl {
         impl SubAssign<$t> for Saturating<$t> {
             #[inline]
             fn sub_assign(&mut self, other: $t) {
-                *self = *self - other;
+                *self = *self - Saturating(other);
             }
         }
         forward_ref_op_assign! { impl SubAssign, sub_assign for Saturating<$t>, $t }
@@ -301,18 +277,6 @@ macro_rules! saturating_impl {
         forward_ref_binop! { impl Mul, mul for Saturating<$t>, Saturating<$t>,
                 #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 
-        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
-        impl Mul<$t> for Saturating<$t> {
-            type Output = Saturating<$t>;
-
-            #[inline]
-            fn mul(self, other: $t) -> Saturating<$t> {
-                Saturating(self.0.saturating_mul(other))
-            }
-        }
-        forward_ref_binop! { impl Mul, mul for Saturating<$t>, $t,
-                #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] }
-
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl MulAssign for Saturating<$t> {
             #[inline]
@@ -326,7 +290,7 @@ macro_rules! saturating_impl {
         impl MulAssign<$t> for Saturating<$t> {
             #[inline]
             fn mul_assign(&mut self, other: $t) {
-                *self = *self * other;
+                *self = *self * Saturating(other);
             }
         }
         forward_ref_op_assign! { impl MulAssign, mul_assign for Saturating<$t>, $t }
@@ -362,36 +326,6 @@ macro_rules! saturating_impl {
         forward_ref_binop! { impl Div, div for Saturating<$t>, Saturating<$t>,
                 #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 
-        /// # Examples
-        ///
-        /// Basic usage:
-        ///
-        /// ```
-        /// #![feature(saturating_int_impl, saturating_int_assign_impl)]
-        /// use std::num::Saturating;
-        ///
-        #[doc = concat!("assert_eq!(Saturating(2", stringify!($t), "), Saturating(5", stringify!($t), ") / 2);")]
-        #[doc = concat!("assert_eq!(Saturating(", stringify!($t), "::MAX), Saturating(", stringify!($t), "::MAX) / 1);")]
-        #[doc = concat!("assert_eq!(Saturating(", stringify!($t), "::MIN), Saturating(", stringify!($t), "::MIN) / 1);")]
-        /// ```
-        ///
-        /// ```should_panic
-        /// #![feature(saturating_int_impl, saturating_int_assign_impl)]
-        /// use std::num::Saturating;
-        ///
-        #[doc = concat!("let _ = Saturating(0", stringify!($t), ") / 0;")]
-        /// ```
-        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
-        impl Div<$t> for Saturating<$t> {
-            type Output = Saturating<$t>;
-
-            #[inline]
-            fn div(self, other: $t) -> Saturating<$t> {
-                Saturating(self.0.saturating_div(other))
-            }
-        }
-        forward_ref_binop! { impl Div, div for Saturating<$t>, $t,
-                #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] }
 
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl DivAssign for Saturating<$t> {
@@ -406,7 +340,7 @@ macro_rules! saturating_impl {
         impl DivAssign<$t> for Saturating<$t> {
             #[inline]
             fn div_assign(&mut self, other: $t) {
-                *self = *self / other;
+                *self = *self / Saturating(other);
             }
         }
         forward_ref_op_assign! { impl DivAssign, div_assign for Saturating<$t>, $t }
@@ -423,18 +357,6 @@ macro_rules! saturating_impl {
         forward_ref_binop! { impl Rem, rem for Saturating<$t>, Saturating<$t>,
                 #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 
-        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
-        impl Rem<$t> for Saturating<$t> {
-            type Output = Saturating<$t>;
-
-            #[inline]
-            fn rem(self, other: $t) -> Saturating<$t> {
-                Saturating(self.0.rem(other))
-            }
-        }
-        forward_ref_binop! { impl Rem, rem for Saturating<$t>, $t,
-                #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] }
-
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl RemAssign for Saturating<$t> {
             #[inline]
@@ -448,7 +370,7 @@ macro_rules! saturating_impl {
         impl RemAssign<$t> for Saturating<$t> {
             #[inline]
             fn rem_assign(&mut self, other: $t) {
-                *self = *self % other;
+                *self = *self % Saturating(other);
             }
         }
         forward_ref_op_assign! { impl RemAssign, rem_assign for Saturating<$t>, $t }
@@ -477,18 +399,6 @@ macro_rules! saturating_impl {
         forward_ref_binop! { impl BitXor, bitxor for Saturating<$t>, Saturating<$t>,
                 #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 
-        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
-        impl BitXor<$t> for Saturating<$t> {
-            type Output = Saturating<$t>;
-
-            #[inline]
-            fn bitxor(self, other: $t) -> Saturating<$t> {
-                Saturating(self.0 ^ other)
-            }
-        }
-        forward_ref_binop! { impl BitXor, bitxor for Saturating<$t>, $t,
-                #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] }
-
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl BitXorAssign for Saturating<$t> {
             #[inline]
@@ -502,7 +412,7 @@ macro_rules! saturating_impl {
         impl BitXorAssign<$t> for Saturating<$t> {
             #[inline]
             fn bitxor_assign(&mut self, other: $t) {
-                *self = *self ^ other;
+                *self = *self ^ Saturating(other);
             }
         }
         forward_ref_op_assign! { impl BitXorAssign, bitxor_assign for Saturating<$t>, $t }
@@ -519,18 +429,6 @@ macro_rules! saturating_impl {
         forward_ref_binop! { impl BitOr, bitor for Saturating<$t>, Saturating<$t>,
                 #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 
-        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
-        impl BitOr<$t> for Saturating<$t> {
-            type Output = Saturating<$t>;
-
-            #[inline]
-            fn bitor(self, other: $t) -> Saturating<$t> {
-                Saturating(self.0 | other)
-            }
-        }
-        forward_ref_binop! { impl BitOr, bitor for Saturating<$t>, $t,
-                #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] }
-
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl BitOrAssign for Saturating<$t> {
             #[inline]
@@ -544,7 +442,7 @@ macro_rules! saturating_impl {
         impl BitOrAssign<$t> for Saturating<$t> {
             #[inline]
             fn bitor_assign(&mut self, other: $t) {
-                *self = *self | other;
+                *self = *self | Saturating(other);
             }
         }
         forward_ref_op_assign! { impl BitOrAssign, bitor_assign for Saturating<$t>, $t }
@@ -561,18 +459,6 @@ macro_rules! saturating_impl {
         forward_ref_binop! { impl BitAnd, bitand for Saturating<$t>, Saturating<$t>,
                 #[unstable(feature = "saturating_int_impl", issue = "87920")] }
 
-        #[unstable(feature = "saturating_int_assign_impl", issue = "92354")]
-        impl BitAnd<$t> for Saturating<$t> {
-            type Output = Saturating<$t>;
-
-            #[inline]
-            fn bitand(self, other: $t) -> Saturating<$t> {
-                Saturating(self.0 & other)
-            }
-        }
-        forward_ref_binop! { impl BitAnd, bitand for Saturating<$t>, $t,
-                #[unstable(feature = "saturating_int_assign_impl", issue = "92354")] }
-
         #[unstable(feature = "saturating_int_impl", issue = "87920")]
         impl BitAndAssign for Saturating<$t> {
             #[inline]
@@ -586,7 +472,7 @@ macro_rules! saturating_impl {
         impl BitAndAssign<$t> for Saturating<$t> {
             #[inline]
             fn bitand_assign(&mut self, other: $t) {
-                *self = *self & other;
+                *self = *self & Saturating(other);
             }
         }
         forward_ref_op_assign! { impl BitAndAssign, bitand_assign for Saturating<$t>, $t }
diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs
index e9547429389..e367be8c167 100644
--- a/library/core/src/ops/arith.rs
+++ b/library/core/src/ops/arith.rs
@@ -65,11 +65,36 @@
 /// ```
 #[lang = "add"]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_on_unimplemented(
-    on(all(_Self = "{integer}", Rhs = "{float}"), message = "cannot add a float to an integer",),
-    on(all(_Self = "{float}", Rhs = "{integer}"), message = "cannot add an integer to a float",),
-    message = "cannot add `{Rhs}` to `{Self}`",
-    label = "no implementation for `{Self} + {Rhs}`"
+#[cfg_attr(
+    bootstrap,
+    rustc_on_unimplemented(
+        on(
+            all(_Self = "{integer}", Rhs = "{float}"),
+            message = "cannot add a float to an integer",
+        ),
+        on(
+            all(_Self = "{float}", Rhs = "{integer}"),
+            message = "cannot add an integer to a float",
+        ),
+        message = "cannot add `{Rhs}` to `{Self}`",
+        label = "no implementation for `{Self} + {Rhs}`"
+    )
+)]
+#[cfg_attr(
+    not(bootstrap),
+    rustc_on_unimplemented(
+        on(
+            all(_Self = "{integer}", Rhs = "{float}"),
+            message = "cannot add a float to an integer",
+        ),
+        on(
+            all(_Self = "{float}", Rhs = "{integer}"),
+            message = "cannot add an integer to a float",
+        ),
+        message = "cannot add `{Rhs}` to `{Self}`",
+        label = "no implementation for `{Self} + {Rhs}`",
+        append_const_msg,
+    )
 )]
 #[doc(alias = "+")]
 pub trait Add<Rhs = Self> {
diff --git a/library/core/src/ops/bit.rs b/library/core/src/ops/bit.rs
index 255f6cb7933..7c664226fc2 100644
--- a/library/core/src/ops/bit.rs
+++ b/library/core/src/ops/bit.rs
@@ -68,6 +68,17 @@ macro_rules! not_impl {
 
 not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 }
 
+#[stable(feature = "not_never", since = "1.60.0")]
+#[rustc_const_unstable(feature = "const_ops", issue = "90080")]
+impl const Not for ! {
+    type Output = !;
+
+    #[inline]
+    fn not(self) -> ! {
+        match self {}
+    }
+}
+
 /// The bitwise AND operator `&`.
 ///
 /// Note that `Rhs` is `Self` by default, but this is not mandatory.
diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs
index d8e421df5de..405224f8fb0 100644
--- a/library/core/src/panic/panic_info.rs
+++ b/library/core/src/panic/panic_info.rs
@@ -31,6 +31,7 @@ pub struct PanicInfo<'a> {
     payload: &'a (dyn Any + Send),
     message: Option<&'a fmt::Arguments<'a>>,
     location: &'a Location<'a>,
+    can_unwind: bool,
 }
 
 impl<'a> PanicInfo<'a> {
@@ -44,9 +45,10 @@ impl<'a> PanicInfo<'a> {
     pub fn internal_constructor(
         message: Option<&'a fmt::Arguments<'a>>,
         location: &'a Location<'a>,
+        can_unwind: bool,
     ) -> Self {
         struct NoPayload;
-        PanicInfo { location, message, payload: &NoPayload }
+        PanicInfo { location, message, payload: &NoPayload, can_unwind }
     }
 
     #[unstable(
@@ -127,6 +129,18 @@ impl<'a> PanicInfo<'a> {
         // deal with that case in std::panicking::default_hook and core::panicking::panic_fmt.
         Some(&self.location)
     }
+
+    /// Returns whether the panic handler is allowed to unwind the stack from
+    /// the point where the panic occurred.
+    ///
+    /// This is true for most kinds of panics with the exception of panics
+    /// caused by trying to unwind out of a `Drop` implementation or a function
+    /// whose ABI does not support unwinding.
+    #[must_use]
+    #[unstable(feature = "panic_can_unwind", issue = "92988")]
+    pub fn can_unwind(&self) -> bool {
+        self.can_unwind
+    }
 }
 
 #[stable(feature = "panic_hook_display", since = "1.26.0")]
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index ccb82cda54e..5078eea07a1 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -77,6 +77,31 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
     panic!("index out of bounds: the len is {} but the index is {}", len, index)
 }
 
+#[cfg(not(bootstrap))]
+#[cold]
+#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))]
+#[track_caller]
+#[lang = "panic_no_unwind"] // needed by codegen for panic in nounwind function
+fn panic_no_unwind() -> ! {
+    if cfg!(feature = "panic_immediate_abort") {
+        super::intrinsics::abort()
+    }
+
+    // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
+    // that gets resolved to the `#[panic_handler]` function.
+    extern "Rust" {
+        #[lang = "panic_impl"]
+        fn panic_impl(pi: &PanicInfo<'_>) -> !;
+    }
+
+    // PanicInfo with the `can_unwind` flag set to false forces an abort.
+    let fmt = format_args!("panic in a function that cannot unwind");
+    let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), false);
+
+    // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
+    unsafe { panic_impl(&pi) }
+}
+
 /// The entry point for panicking with a formatted message.
 ///
 /// This is designed to reduce the amount of code required at the call
@@ -104,7 +129,7 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
         fn panic_impl(pi: &PanicInfo<'_>) -> !;
     }
 
-    let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller());
+    let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), true);
 
     // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
     unsafe { panic_impl(&pi) }
diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs
index d91289fad20..b566e211cd8 100644
--- a/library/core/src/prelude/v1.rs
+++ b/library/core/src/prelude/v1.rs
@@ -65,7 +65,6 @@ pub use crate::{
     issue = "87555",
     reason = "`concat_bytes` is not stable enough for use and is subject to change"
 )]
-#[cfg(not(bootstrap))]
 #[doc(no_inline)]
 pub use crate::concat_bytes;
 
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 3a7e99faccf..3f5d3f62c96 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -211,8 +211,9 @@ impl<T: ?Sized> NonNull<T> {
     /// }
     /// ```
     #[stable(feature = "nonnull", since = "1.25.0")]
+    #[rustc_const_unstable(feature = "const_nonnull_new", issue = "93235")]
     #[inline]
-    pub fn new(ptr: *mut T) -> Option<Self> {
+    pub const fn new(ptr: *mut T) -> Option<Self> {
         if !ptr.is_null() {
             // SAFETY: The pointer is already checked and is not null
             Some(unsafe { Self::new_unchecked(ptr) })
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index 746d1cacfd0..243c044b5d9 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -711,14 +711,28 @@ impl Duration {
     /// as `f64`.
     ///
     /// # Panics
-    /// This constructor will panic if `secs` is not finite, negative or overflows `Duration`.
+    /// This constructor will panic if `secs` is negative, overflows `Duration` or not finite.
     ///
     /// # Examples
     /// ```
     /// use std::time::Duration;
     ///
-    /// let dur = Duration::from_secs_f64(2.7);
-    /// assert_eq!(dur, Duration::new(2, 700_000_000));
+    /// let res = Duration::from_secs_f64(0.0);
+    /// assert_eq!(res, Duration::new(0, 0));
+    /// let res = Duration::from_secs_f64(1e-20);
+    /// assert_eq!(res, Duration::new(0, 0));
+    /// let res = Duration::from_secs_f64(4.2e-7);
+    /// assert_eq!(res, Duration::new(0, 420));
+    /// let res = Duration::from_secs_f64(2.7);
+    /// assert_eq!(res, Duration::new(2, 700_000_000));
+    /// let res = Duration::from_secs_f64(3e10);
+    /// assert_eq!(res, Duration::new(30_000_000_000, 0));
+    /// // subnormal float
+    /// let res = Duration::from_secs_f64(f64::from_bits(1));
+    /// assert_eq!(res, Duration::new(0, 0));
+    /// // conversion uses truncation, not rounding
+    /// let res = Duration::from_secs_f64(0.999e-9);
+    /// assert_eq!(res, Duration::new(0, 0));
     /// ```
     #[stable(feature = "duration_float", since = "1.38.0")]
     #[must_use]
@@ -731,55 +745,32 @@ impl Duration {
         }
     }
 
-    /// The checked version of [`from_secs_f64`].
-    ///
-    /// [`from_secs_f64`]: Duration::from_secs_f64
-    ///
-    /// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`.
-    ///
-    /// # Examples
-    /// ```
-    /// #![feature(duration_checked_float)]
-    /// use std::time::Duration;
-    ///
-    /// let dur = Duration::try_from_secs_f64(2.7);
-    /// assert_eq!(dur, Ok(Duration::new(2, 700_000_000)));
-    ///
-    /// let negative = Duration::try_from_secs_f64(-5.0);
-    /// assert!(negative.is_err());
-    /// ```
-    #[unstable(feature = "duration_checked_float", issue = "83400")]
-    #[inline]
-    pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, FromSecsError> {
-        const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f64;
-        let nanos = secs * (NANOS_PER_SEC as f64);
-        if !nanos.is_finite() {
-            Err(FromSecsError { kind: FromSecsErrorKind::NonFinite })
-        } else if nanos >= MAX_NANOS_F64 {
-            Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
-        } else if nanos < 0.0 {
-            Err(FromSecsError { kind: FromSecsErrorKind::Negative })
-        } else {
-            let nanos = nanos as u128;
-            Ok(Duration {
-                secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
-                nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
-            })
-        }
-    }
-
     /// Creates a new `Duration` from the specified number of seconds represented
     /// as `f32`.
     ///
     /// # Panics
-    /// This constructor will panic if `secs` is not finite, negative or overflows `Duration`.
+    /// This constructor will panic if `secs` is negative, overflows `Duration` or not finite.
     ///
     /// # Examples
     /// ```
     /// use std::time::Duration;
     ///
-    /// let dur = Duration::from_secs_f32(2.7);
-    /// assert_eq!(dur, Duration::new(2, 700_000_000));
+    /// let res = Duration::from_secs_f32(0.0);
+    /// assert_eq!(res, Duration::new(0, 0));
+    /// let res = Duration::from_secs_f32(1e-20);
+    /// assert_eq!(res, Duration::new(0, 0));
+    /// let res = Duration::from_secs_f32(4.2e-7);
+    /// assert_eq!(res, Duration::new(0, 419));
+    /// let res = Duration::from_secs_f32(2.7);
+    /// assert_eq!(res, Duration::new(2, 700_000_047));
+    /// let res = Duration::from_secs_f32(3e10);
+    /// assert_eq!(res, Duration::new(30_000_001_024, 0));
+    /// // subnormal float
+    /// let res = Duration::from_secs_f32(f32::from_bits(1));
+    /// assert_eq!(res, Duration::new(0, 0));
+    /// // conversion uses truncation, not rounding
+    /// let res = Duration::from_secs_f32(0.999e-9);
+    /// assert_eq!(res, Duration::new(0, 0));
     /// ```
     #[stable(feature = "duration_float", since = "1.38.0")]
     #[must_use]
@@ -792,47 +783,10 @@ impl Duration {
         }
     }
 
-    /// The checked version of [`from_secs_f32`].
-    ///
-    /// [`from_secs_f32`]: Duration::from_secs_f32
-    ///
-    /// This constructor will return an `Err` if `secs` is not finite, negative or overflows `Duration`.
-    ///
-    /// # Examples
-    /// ```
-    /// #![feature(duration_checked_float)]
-    /// use std::time::Duration;
-    ///
-    /// let dur = Duration::try_from_secs_f32(2.7);
-    /// assert_eq!(dur, Ok(Duration::new(2, 700_000_000)));
-    ///
-    /// let negative = Duration::try_from_secs_f32(-5.0);
-    /// assert!(negative.is_err());
-    /// ```
-    #[unstable(feature = "duration_checked_float", issue = "83400")]
-    #[inline]
-    pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, FromSecsError> {
-        const MAX_NANOS_F32: f32 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f32;
-        let nanos = secs * (NANOS_PER_SEC as f32);
-        if !nanos.is_finite() {
-            Err(FromSecsError { kind: FromSecsErrorKind::NonFinite })
-        } else if nanos >= MAX_NANOS_F32 {
-            Err(FromSecsError { kind: FromSecsErrorKind::Overflow })
-        } else if nanos < 0.0 {
-            Err(FromSecsError { kind: FromSecsErrorKind::Negative })
-        } else {
-            let nanos = nanos as u128;
-            Ok(Duration {
-                secs: (nanos / (NANOS_PER_SEC as u128)) as u64,
-                nanos: (nanos % (NANOS_PER_SEC as u128)) as u32,
-            })
-        }
-    }
-
     /// Multiplies `Duration` by `f64`.
     ///
     /// # Panics
-    /// This method will panic if result is not finite, negative or overflows `Duration`.
+    /// This method will panic if result is negative, overflows `Duration` or not finite.
     ///
     /// # Examples
     /// ```
@@ -854,17 +808,15 @@ impl Duration {
     /// Multiplies `Duration` by `f32`.
     ///
     /// # Panics
-    /// This method will panic if result is not finite, negative or overflows `Duration`.
+    /// This method will panic if result is negative, overflows `Duration` or not finite.
     ///
     /// # Examples
     /// ```
     /// use std::time::Duration;
     ///
     /// let dur = Duration::new(2, 700_000_000);
-    /// // note that due to rounding errors result is slightly different
-    /// // from 8.478 and 847800.0
     /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_640));
-    /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847799, 969_120_256));
+    /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847800, 0));
     /// ```
     #[stable(feature = "duration_float", since = "1.38.0")]
     #[must_use = "this returns the result of the operation, \
@@ -878,7 +830,7 @@ impl Duration {
     /// Divide `Duration` by `f64`.
     ///
     /// # Panics
-    /// This method will panic if result is not finite, negative or overflows `Duration`.
+    /// This method will panic if result is negative, overflows `Duration` or not finite.
     ///
     /// # Examples
     /// ```
@@ -901,7 +853,7 @@ impl Duration {
     /// Divide `Duration` by `f32`.
     ///
     /// # Panics
-    /// This method will panic if result is not finite, negative or overflows `Duration`.
+    /// This method will panic if result is negative, overflows `Duration` or not finite.
     ///
     /// # Examples
     /// ```
@@ -910,7 +862,7 @@ impl Duration {
     /// let dur = Duration::new(2, 700_000_000);
     /// // note that due to rounding errors result is slightly
     /// // different from 0.859_872_611
-    /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_576));
+    /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_579));
     /// // note that truncation is used, not rounding
     /// assert_eq!(dur.div_f32(3.14e5), Duration::new(0, 8_598));
     /// ```
@@ -1267,33 +1219,180 @@ impl fmt::Debug for Duration {
 /// ```
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[unstable(feature = "duration_checked_float", issue = "83400")]
-pub struct FromSecsError {
-    kind: FromSecsErrorKind,
+pub struct FromFloatSecsError {
+    kind: FromFloatSecsErrorKind,
 }
 
-impl FromSecsError {
+impl FromFloatSecsError {
     const fn description(&self) -> &'static str {
         match self.kind {
-            FromSecsErrorKind::NonFinite => "non-finite value when converting float to duration",
-            FromSecsErrorKind::Overflow => "overflow when converting float to duration",
-            FromSecsErrorKind::Negative => "negative value when converting float to duration",
+            FromFloatSecsErrorKind::Negative => {
+                "can not convert float seconds to Duration: value is negative"
+            }
+            FromFloatSecsErrorKind::OverflowOrNan => {
+                "can not convert float seconds to Duration: value is either too big or NaN"
+            }
         }
     }
 }
 
 #[unstable(feature = "duration_checked_float", issue = "83400")]
-impl fmt::Display for FromSecsError {
+impl fmt::Display for FromFloatSecsError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        fmt::Display::fmt(self.description(), f)
+        self.description().fmt(f)
     }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
-enum FromSecsErrorKind {
-    // Value is not a finite value (either + or - infinity or NaN).
-    NonFinite,
-    // Value is too large to store in a `Duration`.
-    Overflow,
+enum FromFloatSecsErrorKind {
     // Value is negative.
     Negative,
+    // Value is either too big to be represented as `Duration` or `NaN`.
+    OverflowOrNan,
+}
+
+macro_rules! try_from_secs {
+    (
+        secs = $secs: expr,
+        mantissa_bits = $mant_bits: literal,
+        exponent_bits = $exp_bits: literal,
+        offset = $offset: literal,
+        bits_ty = $bits_ty:ty,
+        double_ty = $double_ty:ty,
+    ) => {{
+        const MIN_EXP: i16 = 1 - (1i16 << $exp_bits) / 2;
+        const MANT_MASK: $bits_ty = (1 << $mant_bits) - 1;
+        const EXP_MASK: $bits_ty = (1 << $exp_bits) - 1;
+
+        if $secs.is_sign_negative() {
+            return Err(FromFloatSecsError { kind: FromFloatSecsErrorKind::Negative });
+        }
+
+        let bits = $secs.to_bits();
+        let mant = (bits & MANT_MASK) | (MANT_MASK + 1);
+        let exp = ((bits >> $mant_bits) & EXP_MASK) as i16 + MIN_EXP;
+
+        let (secs, nanos) = if exp < -30 {
+            // the input represents less than 1ns.
+            (0u64, 0u32)
+        } else if exp < 0 {
+            // the input is less than 1 second
+            let t = <$double_ty>::from(mant) << ($offset + exp);
+            let nanos = (u128::from(NANOS_PER_SEC) * u128::from(t)) >> ($mant_bits + $offset);
+            (0, nanos as u32)
+        } else if exp < $mant_bits {
+            let secs = mant >> ($mant_bits - exp);
+            let t = <$double_ty>::from((mant << exp) & MANT_MASK);
+            let nanos = (<$double_ty>::from(NANOS_PER_SEC) * t) >> $mant_bits;
+            (u64::from(secs), nanos as u32)
+        } else if exp < 64 {
+            // the input has no fractional part
+            let secs = u64::from(mant) << (exp - $mant_bits);
+            (secs, 0)
+        } else {
+            return Err(FromFloatSecsError { kind: FromFloatSecsErrorKind::OverflowOrNan });
+        };
+
+        Ok(Duration { secs, nanos })
+    }};
+}
+
+impl Duration {
+    /// The checked version of [`from_secs_f32`].
+    ///
+    /// [`from_secs_f32`]: Duration::from_secs_f32
+    ///
+    /// This constructor will return an `Err` if `secs` is negative, overflows `Duration` or not finite.
+    ///
+    /// # Examples
+    /// ```
+    /// #![feature(duration_checked_float)]
+    ///
+    /// use std::time::Duration;
+    ///
+    /// let res = Duration::try_from_secs_f32(0.0);
+    /// assert_eq!(res, Ok(Duration::new(0, 0)));
+    /// let res = Duration::try_from_secs_f32(1e-20);
+    /// assert_eq!(res, Ok(Duration::new(0, 0)));
+    /// let res = Duration::try_from_secs_f32(4.2e-7);
+    /// assert_eq!(res, Ok(Duration::new(0, 419)));
+    /// let res = Duration::try_from_secs_f32(2.7);
+    /// assert_eq!(res, Ok(Duration::new(2, 700_000_047)));
+    /// let res = Duration::try_from_secs_f32(3e10);
+    /// assert_eq!(res, Ok(Duration::new(30_000_001_024, 0)));
+    /// // subnormal float:
+    /// let res = Duration::try_from_secs_f32(f32::from_bits(1));
+    /// assert_eq!(res, Ok(Duration::new(0, 0)));
+    /// // conversion uses truncation, not rounding
+    /// let res = Duration::try_from_secs_f32(0.999e-9);
+    /// assert_eq!(res, Ok(Duration::new(0, 0)));
+    ///
+    /// let res = Duration::try_from_secs_f32(-5.0);
+    /// assert!(res.is_err());
+    /// let res = Duration::try_from_secs_f32(f32::NAN);
+    /// assert!(res.is_err());
+    /// let res = Duration::try_from_secs_f32(2e19);
+    /// assert!(res.is_err());
+    /// ```
+    #[unstable(feature = "duration_checked_float", issue = "83400")]
+    #[inline]
+    pub const fn try_from_secs_f32(secs: f32) -> Result<Duration, FromFloatSecsError> {
+        try_from_secs!(
+            secs = secs,
+            mantissa_bits = 23,
+            exponent_bits = 8,
+            offset = 41,
+            bits_ty = u32,
+            double_ty = u64,
+        )
+    }
+
+    /// The checked version of [`from_secs_f64`].
+    ///
+    /// [`from_secs_f64`]: Duration::from_secs_f64
+    ///
+    /// This constructor will return an `Err` if `secs` is negative, overflows `Duration` or not finite.
+    ///
+    /// # Examples
+    /// ```
+    /// #![feature(duration_checked_float)]
+    ///
+    /// use std::time::Duration;
+    ///
+    /// let res = Duration::try_from_secs_f64(0.0);
+    /// assert_eq!(res, Ok(Duration::new(0, 0)));
+    /// let res = Duration::try_from_secs_f64(1e-20);
+    /// assert_eq!(res, Ok(Duration::new(0, 0)));
+    /// let res = Duration::try_from_secs_f64(4.2e-7);
+    /// assert_eq!(res, Ok(Duration::new(0, 420)));
+    /// let res = Duration::try_from_secs_f64(2.7);
+    /// assert_eq!(res, Ok(Duration::new(2, 700_000_000)));
+    /// let res = Duration::try_from_secs_f64(3e10);
+    /// assert_eq!(res, Ok(Duration::new(30_000_000_000, 0)));
+    /// // subnormal float
+    /// let res = Duration::try_from_secs_f64(f64::from_bits(1));
+    /// assert_eq!(res, Ok(Duration::new(0, 0)));
+    /// // conversion uses truncation, not rounding
+    /// let res = Duration::try_from_secs_f32(0.999e-9);
+    /// assert_eq!(res, Ok(Duration::new(0, 0)));
+    ///
+    /// let res = Duration::try_from_secs_f64(-5.0);
+    /// assert!(res.is_err());
+    /// let res = Duration::try_from_secs_f64(f64::NAN);
+    /// assert!(res.is_err());
+    /// let res = Duration::try_from_secs_f64(2e19);
+    /// assert!(res.is_err());
+    /// ```
+    #[unstable(feature = "duration_checked_float", issue = "83400")]
+    #[inline]
+    pub const fn try_from_secs_f64(secs: f64) -> Result<Duration, FromFloatSecsError> {
+        try_from_secs!(
+            secs = secs,
+            mantissa_bits = 52,
+            exponent_bits = 11,
+            offset = 44,
+            bits_ty = u64,
+            double_ty = u128,
+        )
+    }
 }
diff --git a/library/core/tests/cmp.rs b/library/core/tests/cmp.rs
index 58fee19ca74..2b234de6795 100644
--- a/library/core/tests/cmp.rs
+++ b/library/core/tests/cmp.rs
@@ -204,7 +204,6 @@ fn cmp_default() {
     assert_eq!(Fool(false), Fool(true));
 }
 
-#[cfg(not(bootstrap))]
 mod const_cmp {
     use super::*;
 
diff --git a/library/core/tests/intrinsics.rs b/library/core/tests/intrinsics.rs
index 7a2e4e29065..e050e810375 100644
--- a/library/core/tests/intrinsics.rs
+++ b/library/core/tests/intrinsics.rs
@@ -37,7 +37,6 @@ fn test_assume_can_be_in_const_contexts() {
 }
 
 #[test]
-#[cfg(not(bootstrap))]
 const fn test_write_bytes_in_const_contexts() {
     use core::intrinsics::write_bytes;
 
@@ -80,3 +79,25 @@ fn test_hints_in_const_contexts() {
         assert!(42u32 == core::hint::black_box(42u32));
     }
 }
+
+#[cfg(not(bootstrap))]
+#[test]
+fn test_const_allocate_at_runtime() {
+    use core::intrinsics::const_allocate;
+    unsafe {
+        assert!(const_allocate(4, 4).is_null());
+    }
+}
+
+#[cfg(not(bootstrap))]
+#[test]
+fn test_const_deallocate_at_runtime() {
+    use core::intrinsics::const_deallocate;
+    const X: &u32 = &42u32;
+    let x = &0u32;
+    unsafe {
+        const_deallocate(X as *const _ as *mut u8, 4, 4); // nop
+        const_deallocate(x as *const _ as *mut u8, 4, 4); // nop
+        const_deallocate(core::ptr::null_mut(), 1, 1); // nop
+    }
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 841c114063d..a2bef2012cf 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -13,10 +13,13 @@
 #![feature(const_bool_to_option)]
 #![feature(const_cell_into_inner)]
 #![feature(const_convert)]
+#![feature(const_heap)]
 #![feature(const_maybe_uninit_as_mut_ptr)]
 #![feature(const_maybe_uninit_assume_init)]
 #![feature(const_maybe_uninit_assume_init_read)]
+#![feature(const_nonnull_new)]
 #![feature(const_num_from_num)]
+#![feature(const_ptr_as_ref)]
 #![feature(const_ptr_read)]
 #![feature(const_ptr_write)]
 #![feature(const_ptr_offset)]
diff --git a/library/core/tests/ops.rs b/library/core/tests/ops.rs
index aa79dbac8f3..0c81cba35b3 100644
--- a/library/core/tests/ops.rs
+++ b/library/core/tests/ops.rs
@@ -232,3 +232,9 @@ fn deref_on_ref() {
     let y = deref(&mut x);
     assert_eq!(y, 4);
 }
+
+#[test]
+#[allow(unreachable_code)]
+fn test_not_never() {
+    if !return () {}
+}
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
index b9c0d75b702..9c65871ac4b 100644
--- a/library/core/tests/ptr.rs
+++ b/library/core/tests/ptr.rs
@@ -251,7 +251,6 @@ fn test_set_memory() {
 }
 
 #[test]
-#[cfg(not(bootstrap))]
 fn test_set_memory_const() {
     const XS: [u8; 20] = {
         let mut xs = [0u8; 20];
@@ -275,6 +274,21 @@ fn test_unsized_nonnull() {
 }
 
 #[test]
+fn test_const_nonnull_new() {
+    const {
+        assert!(NonNull::new(core::ptr::null_mut::<()>()).is_none());
+
+        let value = &mut 0u32;
+        let mut ptr = NonNull::new(value).unwrap();
+        unsafe { *ptr.as_mut() = 42 };
+
+        let reference = unsafe { &*ptr.as_ref() };
+        assert!(*reference == *value);
+        assert!(*reference == 42);
+    };
+}
+
+#[test]
 #[allow(warnings)]
 // Have a symbol for the test below. It doesn’t need to be an actual variadic function, match the
 // ABI, or even point to an actual executable code, because the function itself is never invoked.
diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs
index e5753ccae2d..7f05c82ac28 100644
--- a/library/panic_unwind/src/lib.rs
+++ b/library/panic_unwind/src/lib.rs
@@ -39,6 +39,10 @@ cfg_if::cfg_if! {
     } else if #[cfg(target_os = "hermit")] {
         #[path = "hermit.rs"]
         mod real_imp;
+    } else if #[cfg(target_os = "l4re")] {
+        // L4Re is unix family but does not yet support unwinding.
+        #[path = "dummy.rs"]
+        mod real_imp;
     } else if #[cfg(target_env = "msvc")] {
         #[path = "seh.rs"]
         mod real_imp;
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 232ccdf39d4..83cb119dbf9 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -15,11 +15,11 @@ cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] }
 panic_unwind = { path = "../panic_unwind", optional = true }
 panic_abort = { path = "../panic_abort" }
 core = { path = "../core" }
-libc = { version = "0.2.108", default-features = false, features = ['rustc-dep-of-std'] }
+libc = { version = "0.2.116", default-features = false, features = ['rustc-dep-of-std'] }
 compiler_builtins = { version = "0.1.66" }
 profiler_builtins = { path = "../profiler_builtins", optional = true }
 unwind = { path = "../unwind" }
-hashbrown = { version = "0.11", default-features = false, features = ['rustc-dep-of-std'] }
+hashbrown = { version = "0.12", default-features = false, features = ['rustc-dep-of-std'] }
 std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = ['rustc-dep-of-std'] }
 
 # Dependencies of the `backtrace` crate
@@ -45,7 +45,7 @@ fortanix-sgx-abi = { version = "0.3.2", features = ['rustc-dep-of-std'] }
 hermit-abi = { version = "0.1.19", features = ['rustc-dep-of-std'] }
 
 [target.wasm32-wasi.dependencies]
-wasi = { version = "0.9.0", features = ['rustc-dep-of-std'], default-features = false }
+wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false }
 
 [features]
 backtrace = [
diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs
index eac884bfe0f..30da22b8084 100644
--- a/library/std/src/collections/hash/map/tests.rs
+++ b/library/std/src/collections/hash/map/tests.rs
@@ -817,6 +817,7 @@ fn test_retain() {
 }
 
 #[test]
+#[cfg_attr(target_os = "android", ignore)] // Android used in CI has a broken dlmalloc
 fn test_try_reserve() {
     let mut empty_bytes: HashMap<u8, u8> = HashMap::new();
 
@@ -828,11 +829,21 @@ fn test_try_reserve() {
         "usize::MAX should trigger an overflow!"
     );
 
-    assert_matches!(
-        empty_bytes.try_reserve(MAX_USIZE / 8).map_err(|e| e.kind()),
-        Err(AllocError { .. }),
-        "usize::MAX / 8 should trigger an OOM!"
-    );
+    if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 16).map_err(|e| e.kind()) {
+    } else {
+        // This may succeed if there is enough free memory. Attempt to
+        // allocate a few more hashmaps to ensure the allocation will fail.
+        let mut empty_bytes2: HashMap<u8, u8> = HashMap::new();
+        let _ = empty_bytes2.try_reserve(MAX_USIZE / 16);
+        let mut empty_bytes3: HashMap<u8, u8> = HashMap::new();
+        let _ = empty_bytes3.try_reserve(MAX_USIZE / 16);
+        let mut empty_bytes4: HashMap<u8, u8> = HashMap::new();
+        assert_matches!(
+            empty_bytes4.try_reserve(MAX_USIZE / 16).map_err(|e| e.kind()),
+            Err(AllocError { .. }),
+            "usize::MAX / 16 should trigger an OOM!"
+        );
+    }
 }
 
 #[test]
diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index 643108b88bf..1a96b9c9282 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -602,7 +602,7 @@ impl Error for char::ParseCharError {
 impl Error for alloc::collections::TryReserveError {}
 
 #[unstable(feature = "duration_checked_float", issue = "83400")]
-impl Error for time::FromSecsError {}
+impl Error for time::FromFloatSecsError {}
 
 // Copied from `any.rs`.
 impl dyn Error + 'static {
diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs
index d859bff1a45..66fee2fe548 100644
--- a/library/std/src/ffi/c_str.rs
+++ b/library/std/src/ffi/c_str.rs
@@ -973,7 +973,8 @@ impl<'a> From<&'a CString> for Cow<'a, CStr> {
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
 impl From<CString> for Arc<CStr> {
-    /// Converts a [`CString`] into an <code>[Arc]<[CStr]></code> without copying or allocating.
+    /// Converts a [`CString`] into an <code>[Arc]<[CStr]></code> by moving the [`CString`]
+    /// data into a new [`Arc`] buffer.
     #[inline]
     fn from(s: CString) -> Arc<CStr> {
         let arc: Arc<[u8]> = Arc::from(s.into_inner());
@@ -992,7 +993,8 @@ impl From<&CStr> for Arc<CStr> {
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
 impl From<CString> for Rc<CStr> {
-    /// Converts a [`CString`] into an <code>[Rc]<[CStr]></code> without copying or allocating.
+    /// Converts a [`CString`] into an <code>[Rc]<[CStr]></code> by moving the [`CString`]
+    /// data into a new [`Arc`] buffer.
     #[inline]
     fn from(s: CString) -> Rc<CStr> {
         let rc: Rc<[u8]> = Rc::from(s.into_inner());
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index 982ad189878..81f72e34d93 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -989,7 +989,8 @@ impl Clone for Box<OsStr> {
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
 impl From<OsString> for Arc<OsStr> {
-    /// Converts an [`OsString`] into an <code>[Arc]<[OsStr]></code> without copying or allocating.
+    /// Converts an [`OsString`] into an <code>[Arc]<[OsStr]></code> by moving the [`OsString`]
+    /// data into a new [`Arc`] buffer.
     #[inline]
     fn from(s: OsString) -> Arc<OsStr> {
         let arc = s.inner.into_arc();
@@ -1008,7 +1009,8 @@ impl From<&OsStr> for Arc<OsStr> {
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
 impl From<OsString> for Rc<OsStr> {
-    /// Converts an [`OsString`] into an <code>[Rc]<[OsStr]></code> without copying or allocating.
+    /// Converts an [`OsString`] into an <code>[Rc]<[OsStr]></code> by moving the [`OsString`]
+    /// data into a new [`Rc`] buffer.
     #[inline]
     fn from(s: OsString) -> Rc<OsStr> {
         let rc = s.inner.into_rc();
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index a62c01ef29b..16b8bf68242 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -1504,3 +1504,19 @@ fn create_dir_long_paths() {
     let path = Path::new("");
     assert_eq!(path.canonicalize().unwrap_err().kind(), crate::io::ErrorKind::NotFound);
 }
+
+/// Ensure ReadDir works on large directories.
+/// Regression test for https://github.com/rust-lang/rust/issues/93384.
+#[test]
+fn read_large_dir() {
+    let tmpdir = tmpdir();
+
+    let count = 32 * 1024;
+    for i in 0..count {
+        check!(fs::File::create(tmpdir.join(&i.to_string())));
+    }
+
+    for entry in fs::read_dir(tmpdir.path()).unwrap() {
+        entry.unwrap();
+    }
+}
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index c072f0cafe4..3d6de20d860 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -7,7 +7,7 @@ use crate::io::prelude::*;
 
 use crate::cell::{Cell, RefCell};
 use crate::fmt;
-use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines, Split};
+use crate::io::{self, BufReader, IoSlice, IoSliceMut, LineWriter, Lines};
 use crate::lazy::SyncOnceCell;
 use crate::pin::Pin;
 use crate::sync::atomic::{AtomicBool, Ordering};
@@ -465,29 +465,6 @@ impl Stdin {
     pub fn lines(self) -> Lines<StdinLock<'static>> {
         self.into_locked().lines()
     }
-
-    /// Consumes this handle and returns an iterator over input bytes,
-    /// split at the specified byte value.
-    ///
-    /// For detailed semantics of this method, see the documentation on
-    /// [`BufRead::split`].
-    ///
-    /// # Examples
-    ///
-    /// ```no_run
-    /// #![feature(stdin_forwarders)]
-    /// use std::io;
-    ///
-    /// let splits = io::stdin().split(b'-');
-    /// for split in splits {
-    ///     println!("got a chunk: {}", String::from_utf8_lossy(&split.unwrap()));
-    /// }
-    /// ```
-    #[must_use = "`self` will be dropped if the result is not used"]
-    #[unstable(feature = "stdin_forwarders", issue = "87096")]
-    pub fn split(self, byte: u8) -> Split<StdinLock<'static>> {
-        self.into_locked().split(byte)
-    }
 }
 
 #[stable(feature = "std_debug", since = "1.16.0")]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 17fe0011569..3a6b931f53b 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -195,15 +195,12 @@
     test(no_crate_inject, attr(deny(warnings))),
     test(attr(allow(dead_code, deprecated, unused_variables, unused_mut)))
 )]
-#![cfg_attr(
-    not(bootstrap),
-    doc(cfg_hide(
-        not(test),
-        not(any(test, bootstrap)),
-        no_global_oom_handling,
-        not(no_global_oom_handling)
-    ))
-)]
+#![doc(cfg_hide(
+    not(test),
+    not(any(test, bootstrap)),
+    no_global_oom_handling,
+    not(no_global_oom_handling)
+))]
 // Don't link to std. We are std.
 #![no_std]
 #![warn(deprecated_in_future)]
@@ -249,7 +246,7 @@
 #![feature(cfg_target_thread_local)]
 #![feature(char_error_internals)]
 #![feature(char_internals)]
-#![cfg_attr(not(bootstrap), feature(concat_bytes))]
+#![feature(concat_bytes)]
 #![feature(concat_idents)]
 #![feature(const_fn_floating_point_arithmetic)]
 #![feature(const_fn_fn_ptr_basics)]
@@ -311,6 +308,7 @@
 #![feature(once_cell)]
 #![feature(panic_info_message)]
 #![feature(panic_internals)]
+#![feature(panic_can_unwind)]
 #![feature(panic_unwind)]
 #![feature(pin_static_ref)]
 #![feature(portable_simd)]
@@ -402,13 +400,6 @@ pub use alloc_crate::string;
 pub use alloc_crate::vec;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::any;
-#[stable(feature = "simd_arch", since = "1.27.0")]
-// The `no_inline`-attribute is required to make the documentation of all
-// targets available.
-// See https://github.com/rust-lang/rust/pull/57808#issuecomment-457390549 for
-// more information.
-#[doc(no_inline)] // Note (#82861): required for correct documentation
-pub use core::arch;
 #[stable(feature = "core_array", since = "1.36.0")]
 pub use core::array;
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -526,6 +517,31 @@ pub mod task {
     pub use alloc::task::*;
 }
 
+#[doc = include_str!("../../stdarch/crates/core_arch/src/core_arch_docs.md")]
+#[stable(feature = "simd_arch", since = "1.27.0")]
+pub mod arch {
+    #[stable(feature = "simd_arch", since = "1.27.0")]
+    // The `no_inline`-attribute is required to make the documentation of all
+    // targets available.
+    // See https://github.com/rust-lang/rust/pull/57808#issuecomment-457390549 for
+    // more information.
+    #[doc(no_inline)] // Note (#82861): required for correct documentation
+    pub use core::arch::*;
+
+    #[stable(feature = "simd_x86", since = "1.27.0")]
+    pub use std_detect::is_x86_feature_detected;
+    #[unstable(feature = "stdsimd", issue = "48556")]
+    pub use std_detect::{
+        is_aarch64_feature_detected, is_arm_feature_detected, is_mips64_feature_detected,
+        is_mips_feature_detected, is_powerpc64_feature_detected, is_powerpc_feature_detected,
+        is_riscv_feature_detected,
+    };
+}
+
+// This was stabilized in the crate root so we have to keep it there.
+#[stable(feature = "simd_x86", since = "1.27.0")]
+pub use std_detect::is_x86_feature_detected;
+
 // The runtime entry point and a few unstable public functions used by the
 // compiler
 #[macro_use]
@@ -544,18 +560,6 @@ mod panicking;
 #[allow(dead_code, unused_attributes)]
 mod backtrace_rs;
 
-#[stable(feature = "simd_x86", since = "1.27.0")]
-pub use std_detect::is_x86_feature_detected;
-#[doc(hidden)]
-#[unstable(feature = "stdsimd", issue = "48556")]
-pub use std_detect::*;
-#[unstable(feature = "stdsimd", issue = "48556")]
-pub use std_detect::{
-    is_aarch64_feature_detected, is_arm_feature_detected, is_mips64_feature_detected,
-    is_mips_feature_detected, is_powerpc64_feature_detected, is_powerpc_feature_detected,
-    is_riscv_feature_detected,
-};
-
 // Re-export macros defined in libcore.
 #[stable(feature = "rust1", since = "1.0.0")]
 #[allow(deprecated, deprecated_in_future)]
@@ -578,7 +582,6 @@ pub use core::{
     issue = "87555",
     reason = "`concat_bytes` is not stable enough for use and is subject to change"
 )]
-#[cfg(not(bootstrap))]
 pub use core::concat_bytes;
 
 #[stable(feature = "core_primitive", since = "1.43.0")]
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index 52d7d4690d3..0b6588db92c 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -8,6 +8,8 @@ use crate::fmt;
 use crate::fs;
 use crate::marker::PhantomData;
 use crate::mem::forget;
+#[cfg(not(target_os = "wasi"))]
+use crate::sys::cvt;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 
 /// A borrowed file descriptor.
@@ -67,6 +69,37 @@ impl BorrowedFd<'_> {
     }
 }
 
+impl OwnedFd {
+    /// Creates a new `OwnedFd` instance that shares the same underlying file handle
+    /// as the existing `OwnedFd` instance.
+    #[cfg(not(target_os = "wasi"))]
+    pub fn try_clone(&self) -> crate::io::Result<Self> {
+        // We want to atomically duplicate this file descriptor and set the
+        // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
+        // is a POSIX flag that was added to Linux in 2.6.24.
+        #[cfg(not(target_os = "espidf"))]
+        let cmd = libc::F_DUPFD_CLOEXEC;
+
+        // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
+        // will never be supported, as this is a bare metal framework with
+        // no capabilities for multi-process execution.  While F_DUPFD is also
+        // not supported yet, it might be (currently it returns ENOSYS).
+        #[cfg(target_os = "espidf")]
+        let cmd = libc::F_DUPFD;
+
+        let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?;
+        Ok(unsafe { Self::from_raw_fd(fd) })
+    }
+
+    #[cfg(target_os = "wasi")]
+    pub fn try_clone(&self) -> crate::io::Result<Self> {
+        Err(crate::io::Error::new_const(
+            crate::io::ErrorKind::Unsupported,
+            &"operation not supported on WASI yet",
+        ))
+    }
+}
+
 #[unstable(feature = "io_safety", issue = "87074")]
 impl AsRawFd for BorrowedFd<'_> {
     #[inline]
diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs
index f0b38d29845..b6d5199341c 100644
--- a/library/std/src/os/raw/mod.rs
+++ b/library/std/src/os/raw/mod.rs
@@ -45,94 +45,13 @@ macro_rules! type_alias {
     }
 }
 
-type_alias! { "char.md", c_char = u8, NonZero_c_char = NonZeroU8;
-#[doc(cfg(all()))]
-#[cfg(any(
-    all(
-        target_os = "linux",
-        any(
-            target_arch = "aarch64",
-            target_arch = "arm",
-            target_arch = "hexagon",
-            target_arch = "powerpc",
-            target_arch = "powerpc64",
-            target_arch = "s390x",
-            target_arch = "riscv64",
-            target_arch = "riscv32"
-        )
-    ),
-    all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")),
-    all(target_os = "l4re", target_arch = "x86_64"),
-    all(
-        target_os = "freebsd",
-        any(
-            target_arch = "aarch64",
-            target_arch = "arm",
-            target_arch = "powerpc",
-            target_arch = "powerpc64",
-            target_arch = "riscv64"
-        )
-    ),
-    all(
-        target_os = "netbsd",
-        any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")
-    ),
-    all(target_os = "openbsd", target_arch = "aarch64"),
-    all(
-        target_os = "vxworks",
-        any(
-            target_arch = "aarch64",
-            target_arch = "arm",
-            target_arch = "powerpc64",
-            target_arch = "powerpc"
-        )
-    ),
-    all(target_os = "fuchsia", target_arch = "aarch64")
-))]}
-type_alias! { "char.md", c_char = i8, NonZero_c_char = NonZeroI8;
-#[doc(cfg(all()))]
-#[cfg(not(any(
-    all(
-        target_os = "linux",
-        any(
-            target_arch = "aarch64",
-            target_arch = "arm",
-            target_arch = "hexagon",
-            target_arch = "powerpc",
-            target_arch = "powerpc64",
-            target_arch = "s390x",
-            target_arch = "riscv64",
-            target_arch = "riscv32"
-        )
-    ),
-    all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")),
-    all(target_os = "l4re", target_arch = "x86_64"),
-    all(
-        target_os = "freebsd",
-        any(
-            target_arch = "aarch64",
-            target_arch = "arm",
-            target_arch = "powerpc",
-            target_arch = "powerpc64",
-            target_arch = "riscv64"
-        )
-    ),
-    all(
-        target_os = "netbsd",
-        any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")
-    ),
-    all(target_os = "openbsd", target_arch = "aarch64"),
-    all(
-        target_os = "vxworks",
-        any(
-            target_arch = "aarch64",
-            target_arch = "arm",
-            target_arch = "powerpc64",
-            target_arch = "powerpc"
-        )
-    ),
-    all(target_os = "fuchsia", target_arch = "aarch64")
-)))]}
+type_alias! { "char.md", c_char = c_char_definition::c_char, NonZero_c_char = c_char_definition::NonZero_c_char;
+// Make this type alias appear cfg-dependent so that Clippy does not suggest
+// replacing `0 as c_char` with `0_i8`/`0_u8`. This #[cfg(all())] can be removed
+// after the false positive in https://github.com/rust-lang/rust-clippy/issues/8093
+// is fixed.
+#[cfg(all())]
+#[doc(cfg(all()))] }
 type_alias! { "schar.md", c_schar = i8, NonZero_c_schar = NonZeroI8; }
 type_alias! { "uchar.md", c_uchar = u8, NonZero_c_uchar = NonZeroU8; }
 type_alias! { "short.md", c_short = i16, NonZero_c_short = NonZeroI16; }
@@ -180,3 +99,58 @@ pub type c_ptrdiff_t = isize;
 /// platforms where this is not the case.
 #[unstable(feature = "c_size_t", issue = "88345")]
 pub type c_ssize_t = isize;
+
+mod c_char_definition {
+    cfg_if::cfg_if! {
+        // These are the targets on which c_char is unsigned.
+        if #[cfg(any(
+            all(
+                target_os = "linux",
+                any(
+                    target_arch = "aarch64",
+                    target_arch = "arm",
+                    target_arch = "hexagon",
+                    target_arch = "powerpc",
+                    target_arch = "powerpc64",
+                    target_arch = "s390x",
+                    target_arch = "riscv64",
+                    target_arch = "riscv32"
+                )
+            ),
+            all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")),
+            all(target_os = "l4re", target_arch = "x86_64"),
+            all(
+                target_os = "freebsd",
+                any(
+                    target_arch = "aarch64",
+                    target_arch = "arm",
+                    target_arch = "powerpc",
+                    target_arch = "powerpc64",
+                    target_arch = "riscv64"
+                )
+            ),
+            all(
+                target_os = "netbsd",
+                any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")
+            ),
+            all(target_os = "openbsd", target_arch = "aarch64"),
+            all(
+                target_os = "vxworks",
+                any(
+                    target_arch = "aarch64",
+                    target_arch = "arm",
+                    target_arch = "powerpc64",
+                    target_arch = "powerpc"
+                )
+            ),
+            all(target_os = "fuchsia", target_arch = "aarch64")
+        ))] {
+            pub type c_char = u8;
+            pub type NonZero_c_char = core::num::NonZeroU8;
+        } else {
+            // On every other target, c_char is signed.
+            pub type c_char = i8;
+            pub type NonZero_c_char = core::num::NonZeroI8;
+        }
+    }
+}
diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs
index f450e41bfea..9dbd4548bc9 100644
--- a/library/std/src/os/unix/net/addr.rs
+++ b/library/std/src/os/unix/net/addr.rs
@@ -2,7 +2,7 @@ use crate::ffi::OsStr;
 use crate::os::unix::ffi::OsStrExt;
 use crate::path::Path;
 use crate::sys::cvt;
-use crate::{ascii, fmt, io, iter, mem};
+use crate::{ascii, fmt, io, mem, ptr};
 
 // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here?
 #[cfg(not(unix))]
@@ -22,8 +22,9 @@ fn sun_path_offset(addr: &libc::sockaddr_un) -> usize {
     path - base
 }
 
-pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
-    let mut addr: libc::sockaddr_un = mem::zeroed();
+pub(super) fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un, libc::socklen_t)> {
+    // SAFETY: All zeros is a valid representation for `sockaddr_un`.
+    let mut addr: libc::sockaddr_un = unsafe { mem::zeroed() };
     addr.sun_family = libc::AF_UNIX as libc::sa_family_t;
 
     let bytes = path.as_os_str().as_bytes();
@@ -41,11 +42,13 @@ pub(super) unsafe fn sockaddr_un(path: &Path) -> io::Result<(libc::sockaddr_un,
             &"path must be shorter than SUN_LEN",
         ));
     }
-    for (dst, src) in iter::zip(&mut addr.sun_path, bytes) {
-        *dst = *src as libc::c_char;
-    }
-    // null byte for pathname addresses is already there because we zeroed the
-    // struct
+    // SAFETY: `bytes` and `addr.sun_path` are not overlapping and
+    // both point to valid memory.
+    // NOTE: We zeroed the memory above, so the path is already null
+    // terminated.
+    unsafe {
+        ptr::copy_nonoverlapping(bytes.as_ptr(), addr.sun_path.as_mut_ptr().cast(), bytes.len())
+    };
 
     let mut len = sun_path_offset(&addr) + bytes.len();
     match bytes.get(0) {
@@ -127,6 +130,43 @@ impl SocketAddr {
         Ok(SocketAddr { addr, len })
     }
 
+    /// Constructs a `SockAddr` with the family `AF_UNIX` and the provided path.
+    ///
+    /// # Errors
+    ///
+    /// Returns an error if the path is longer than `SUN_LEN` or if it contains
+    /// NULL bytes.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(unix_socket_creation)]
+    /// use std::os::unix::net::SocketAddr;
+    /// use std::path::Path;
+    ///
+    /// # fn main() -> std::io::Result<()> {
+    /// let address = SocketAddr::from_path("/path/to/socket")?;
+    /// assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket")));
+    /// # Ok(())
+    /// # }
+    /// ```
+    ///
+    /// Creating a `SocketAddr` with a NULL byte results in an error.
+    ///
+    /// ```
+    /// #![feature(unix_socket_creation)]
+    /// use std::os::unix::net::SocketAddr;
+    ///
+    /// assert!(SocketAddr::from_path("/path/with/\0/bytes").is_err());
+    /// ```
+    #[unstable(feature = "unix_socket_creation", issue = "93423")]
+    pub fn from_path<P>(path: P) -> io::Result<SocketAddr>
+    where
+        P: AsRef<Path>,
+    {
+        sockaddr_un(path.as_ref()).map(|(addr, len)| SocketAddr { addr, len })
+    }
+
     /// Returns `true` if the address is unnamed.
     ///
     /// # Examples
diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs
index 5c62679f552..37126069f94 100644
--- a/library/std/src/os/wasi/fs.rs
+++ b/library/std/src/os/wasi/fs.rs
@@ -250,6 +250,21 @@ impl FileExt for fs::File {
     }
 
     fn advise(&self, offset: u64, len: u64, advice: u8) -> io::Result<()> {
+        let advice = match advice {
+            a if a == wasi::ADVICE_NORMAL.raw() => wasi::ADVICE_NORMAL,
+            a if a == wasi::ADVICE_SEQUENTIAL.raw() => wasi::ADVICE_SEQUENTIAL,
+            a if a == wasi::ADVICE_RANDOM.raw() => wasi::ADVICE_RANDOM,
+            a if a == wasi::ADVICE_WILLNEED.raw() => wasi::ADVICE_WILLNEED,
+            a if a == wasi::ADVICE_DONTNEED.raw() => wasi::ADVICE_DONTNEED,
+            a if a == wasi::ADVICE_NOREUSE.raw() => wasi::ADVICE_NOREUSE,
+            _ => {
+                return Err(io::Error::new_const(
+                    io::ErrorKind::InvalidInput,
+                    &"invalid parameter 'advice'",
+                ));
+            }
+        };
+
         self.as_inner().as_inner().advise(offset, len, advice)
     }
 
diff --git a/library/std/src/os/wasi/net/mod.rs b/library/std/src/os/wasi/net/mod.rs
index e6bcf87887f..73c097d4a50 100644
--- a/library/std/src/os/wasi/net/mod.rs
+++ b/library/std/src/os/wasi/net/mod.rs
@@ -1,3 +1,23 @@
 //! WASI-specific networking functionality
 
 #![unstable(feature = "wasi_ext", issue = "71213")]
+
+use crate::io;
+use crate::net;
+use crate::sys_common::AsInner;
+
+/// WASI-specific extensions to [`std::net::TcpListener`].
+///
+/// [`std::net::TcpListener`]: crate::net::TcpListener
+pub trait TcpListenerExt {
+    /// Accept a socket.
+    ///
+    /// This corresponds to the `sock_accept` syscall.
+    fn sock_accept(&self, flags: u16) -> io::Result<u32>;
+}
+
+impl TcpListenerExt for net::TcpListener {
+    fn sock_accept(&self, flags: u16) -> io::Result<u32> {
+        self.as_inner().as_inner().as_inner().sock_accept(flags)
+    }
+}
diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs
index 1527f5b6b07..e37ce633a12 100644
--- a/library/std/src/os/windows/io/handle.rs
+++ b/library/std/src/os/windows/io/handle.rs
@@ -6,9 +6,11 @@ use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
 use crate::convert::TryFrom;
 use crate::fmt;
 use crate::fs;
+use crate::io;
 use crate::marker::PhantomData;
 use crate::mem::forget;
 use crate::sys::c;
+use crate::sys::cvt;
 use crate::sys_common::{AsInner, FromInner, IntoInner};
 
 /// A borrowed handle.
@@ -144,6 +146,36 @@ impl TryFrom<HandleOrNull> for OwnedHandle {
     }
 }
 
+impl OwnedHandle {
+    /// Creates a new `OwnedHandle` instance that shares the same underlying file handle
+    /// as the existing `OwnedHandle` instance.
+    pub fn try_clone(&self) -> crate::io::Result<Self> {
+        self.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)
+    }
+
+    pub(crate) fn duplicate(
+        &self,
+        access: c::DWORD,
+        inherit: bool,
+        options: c::DWORD,
+    ) -> io::Result<Self> {
+        let mut ret = 0 as c::HANDLE;
+        cvt(unsafe {
+            let cur_proc = c::GetCurrentProcess();
+            c::DuplicateHandle(
+                cur_proc,
+                self.as_raw_handle(),
+                cur_proc,
+                &mut ret,
+                access,
+                inherit as c::BOOL,
+                options,
+            )
+        })?;
+        unsafe { Ok(Self::from_raw_handle(ret)) }
+    }
+}
+
 impl TryFrom<HandleOrInvalid> for OwnedHandle {
     type Error = ();
 
diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs
index 23db66df09f..26b569bcdd3 100644
--- a/library/std/src/os/windows/io/socket.rs
+++ b/library/std/src/os/windows/io/socket.rs
@@ -4,9 +4,13 @@
 
 use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket};
 use crate::fmt;
+use crate::io;
 use crate::marker::PhantomData;
+use crate::mem;
 use crate::mem::forget;
+use crate::sys;
 use crate::sys::c;
+use crate::sys::cvt;
 
 /// A borrowed socket.
 ///
@@ -69,6 +73,77 @@ impl BorrowedSocket<'_> {
     }
 }
 
+impl OwnedSocket {
+    /// Creates a new `OwnedSocket` instance that shares the same underlying socket
+    /// as the existing `OwnedSocket` instance.
+    pub fn try_clone(&self) -> io::Result<Self> {
+        let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() };
+        let result = unsafe {
+            c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info)
+        };
+        sys::net::cvt(result)?;
+        let socket = unsafe {
+            c::WSASocketW(
+                info.iAddressFamily,
+                info.iSocketType,
+                info.iProtocol,
+                &mut info,
+                0,
+                c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT,
+            )
+        };
+
+        if socket != c::INVALID_SOCKET {
+            unsafe { Ok(OwnedSocket::from_raw_socket(socket)) }
+        } else {
+            let error = unsafe { c::WSAGetLastError() };
+
+            if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL {
+                return Err(io::Error::from_raw_os_error(error));
+            }
+
+            let socket = unsafe {
+                c::WSASocketW(
+                    info.iAddressFamily,
+                    info.iSocketType,
+                    info.iProtocol,
+                    &mut info,
+                    0,
+                    c::WSA_FLAG_OVERLAPPED,
+                )
+            };
+
+            if socket == c::INVALID_SOCKET {
+                return Err(last_error());
+            }
+
+            unsafe {
+                let socket = OwnedSocket::from_raw_socket(socket);
+                socket.set_no_inherit()?;
+                Ok(socket)
+            }
+        }
+    }
+
+    #[cfg(not(target_vendor = "uwp"))]
+    pub(crate) fn set_no_inherit(&self) -> io::Result<()> {
+        cvt(unsafe {
+            c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0)
+        })
+        .map(drop)
+    }
+
+    #[cfg(target_vendor = "uwp")]
+    pub(crate) fn set_no_inherit(&self) -> io::Result<()> {
+        Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Unavailable on UWP"))
+    }
+}
+
+/// Returns the last error from the Windows socket interface.
+fn last_error() -> io::Error {
+    io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() })
+}
+
 impl AsRawSocket for BorrowedSocket<'_> {
     #[inline]
     fn as_raw_socket(&self) -> RawSocket {
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index d0f332fe5e8..83ab13c963d 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -576,9 +576,14 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
     let msg = info.message().unwrap(); // The current implementation always returns Some
     crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
         if let Some(msg) = msg.as_str() {
-            rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc);
+            rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc, info.can_unwind());
         } else {
-            rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc);
+            rust_panic_with_hook(
+                &mut PanicPayload::new(msg),
+                info.message(),
+                loc,
+                info.can_unwind(),
+            );
         }
     })
 }
@@ -602,7 +607,7 @@ pub const fn begin_panic<M: Any + Send>(msg: M) -> ! {
 
     let loc = Location::caller();
     return crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
-        rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc)
+        rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc, true)
     });
 
     struct PanicPayload<A> {
@@ -647,6 +652,7 @@ fn rust_panic_with_hook(
     payload: &mut dyn BoxMeUp,
     message: Option<&fmt::Arguments<'_>>,
     location: &Location<'_>,
+    can_unwind: bool,
 ) -> ! {
     let (must_abort, panics) = panic_count::increase();
 
@@ -663,14 +669,14 @@ fn rust_panic_with_hook(
         } 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);
+            let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind);
             rtprintpanic!("{}\npanicked after panic::always_abort(), aborting.\n", panicinfo);
         }
-        intrinsics::abort()
+        crate::sys::abort_internal();
     }
 
     unsafe {
-        let mut info = PanicInfo::internal_constructor(message, location);
+        let mut info = PanicInfo::internal_constructor(message, location, can_unwind);
         let _guard = HOOK_LOCK.read();
         match HOOK {
             // Some platforms (like wasm) know that printing to stderr won't ever actually
@@ -691,13 +697,13 @@ fn rust_panic_with_hook(
         };
     }
 
-    if panics > 1 {
+    if panics > 1 || !can_unwind {
         // If a thread panics while it's already unwinding then we
         // have limited options. Currently our preference is to
         // just abort. In the future we may consider resuming
         // unwinding or otherwise exiting the thread cleanly.
         rtprintpanic!("thread panicked while panicking. aborting.\n");
-        intrinsics::abort()
+        crate::sys::abort_internal();
     }
 
     rust_panic(payload)
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index f509403fe2e..e540f860160 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -72,6 +72,7 @@ mod tests;
 
 use crate::borrow::{Borrow, Cow};
 use crate::cmp;
+use crate::collections::TryReserveError;
 use crate::error::Error;
 use crate::fmt;
 use crate::fs;
@@ -1512,6 +1513,15 @@ impl PathBuf {
         self.inner.reserve(additional)
     }
 
+    /// Invokes [`try_reserve`] on the underlying instance of [`OsString`].
+    ///
+    /// [`try_reserve`]: OsString::try_reserve
+    #[unstable(feature = "try_reserve_2", issue = "91789")]
+    #[inline]
+    pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
+        self.inner.try_reserve(additional)
+    }
+
     /// Invokes [`reserve_exact`] on the underlying instance of [`OsString`].
     ///
     /// [`reserve_exact`]: OsString::reserve_exact
@@ -1521,6 +1531,15 @@ impl PathBuf {
         self.inner.reserve_exact(additional)
     }
 
+    /// Invokes [`try_reserve_exact`] on the underlying instance of [`OsString`].
+    ///
+    /// [`try_reserve_exact`]: OsString::try_reserve_exact
+    #[unstable(feature = "try_reserve_2", issue = "91789")]
+    #[inline]
+    pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> {
+        self.inner.try_reserve_exact(additional)
+    }
+
     /// Invokes [`shrink_to_fit`] on the underlying instance of [`OsString`].
     ///
     /// [`shrink_to_fit`]: OsString::shrink_to_fit
@@ -1766,7 +1785,8 @@ impl<'a> From<Cow<'a, Path>> for PathBuf {
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
 impl From<PathBuf> for Arc<Path> {
-    /// Converts a [`PathBuf`] into an [`Arc`] by moving the [`PathBuf`] data into a new [`Arc`] buffer.
+    /// Converts a [`PathBuf`] into an <code>[Arc]<[Path]></code> by moving the [`PathBuf`] data
+    /// into a new [`Arc`] buffer.
     #[inline]
     fn from(s: PathBuf) -> Arc<Path> {
         let arc: Arc<OsStr> = Arc::from(s.into_os_string());
@@ -1786,7 +1806,8 @@ impl From<&Path> for Arc<Path> {
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
 impl From<PathBuf> for Rc<Path> {
-    /// Converts a [`PathBuf`] into an [`Rc`] by moving the [`PathBuf`] data into a new `Rc` buffer.
+    /// Converts a [`PathBuf`] into an <code>[Rc]<[Path]></code> by moving the [`PathBuf`] data into
+    /// a new [`Rc`] buffer.
     #[inline]
     fn from(s: PathBuf) -> Rc<Path> {
         let rc: Rc<OsStr> = Rc::from(s.into_os_string());
@@ -1796,7 +1817,7 @@ impl From<PathBuf> for Rc<Path> {
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
 impl From<&Path> for Rc<Path> {
-    /// Converts a [`Path`] into an [`Rc`] by copying the [`Path`] data into a new `Rc` buffer.
+    /// Converts a [`Path`] into an [`Rc`] by copying the [`Path`] data into a new [`Rc`] buffer.
     #[inline]
     fn from(s: &Path) -> Rc<Path> {
         let rc: Rc<OsStr> = Rc::from(s.as_os_str());
diff --git a/library/std/src/prelude/v1.rs b/library/std/src/prelude/v1.rs
index 53124daa3a6..0226c4d7a25 100644
--- a/library/std/src/prelude/v1.rs
+++ b/library/std/src/prelude/v1.rs
@@ -49,7 +49,6 @@ pub use core::prelude::v1::{
     issue = "87555",
     reason = "`concat_bytes` is not stable enough for use and is subject to change"
 )]
-#[cfg(not(bootstrap))]
 #[doc(no_inline)]
 pub use core::prelude::v1::concat_bytes;
 
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index 57f1dcca30e..3ea0a6c3937 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -188,12 +188,9 @@ unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
 /// [`lock`]: Mutex::lock
 /// [`try_lock`]: Mutex::try_lock
 #[must_use = "if unused the Mutex will immediately unlock"]
-#[cfg_attr(
-    not(bootstrap),
-    must_not_suspend = "holding a MutexGuard across suspend \
+#[must_not_suspend = "holding a MutexGuard across suspend \
                       points can cause deadlocks, delays, \
-                      and cause Futures to not implement `Send`"
-)]
+                      and cause Futures to not implement `Send`"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct MutexGuard<'a, T: ?Sized + 'a> {
     lock: &'a Mutex<T>,
diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs
index 2f4395ceefd..2e72a9ef54e 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -95,12 +95,9 @@ unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
 /// [`read`]: RwLock::read
 /// [`try_read`]: RwLock::try_read
 #[must_use = "if unused the RwLock will immediately unlock"]
-#[cfg_attr(
-    not(bootstrap),
-    must_not_suspend = "holding a RwLockReadGuard across suspend \
+#[must_not_suspend = "holding a RwLockReadGuard across suspend \
                       points can cause deadlocks, delays, \
-                      and cause Futures to not implement `Send`"
-)]
+                      and cause Futures to not implement `Send`"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
     lock: &'a RwLock<T>,
@@ -121,12 +118,9 @@ unsafe impl<T: ?Sized + Sync> Sync for RwLockReadGuard<'_, T> {}
 /// [`write`]: RwLock::write
 /// [`try_write`]: RwLock::try_write
 #[must_use = "if unused the RwLock will immediately unlock"]
-#[cfg_attr(
-    not(bootstrap),
-    must_not_suspend = "holding a RwLockWriteGuard across suspend \
+#[must_not_suspend = "holding a RwLockWriteGuard across suspend \
                       points can cause deadlocks, delays, \
-                      and cause Future's to not implement `Send`"
-)]
+                      and cause Future's to not implement `Send`"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
     lock: &'a RwLock<T>,
diff --git a/library/std/src/sys/common/alloc.rs b/library/std/src/sys/common/alloc.rs
index 9665d1fa892..e06eaf6db1a 100644
--- a/library/std/src/sys/common/alloc.rs
+++ b/library/std/src/sys/common/alloc.rs
@@ -14,8 +14,8 @@ use crate::ptr;
     target_arch = "asmjs",
     target_arch = "wasm32",
     target_arch = "hexagon",
-    target_arch = "riscv32",
-    target_arch = "xtensa"
+    all(target_arch = "riscv32", not(target_os = "espidf")),
+    all(target_arch = "xtensa", not(target_os = "espidf")),
 )))]
 pub const MIN_ALIGN: usize = 8;
 #[cfg(all(any(
@@ -28,6 +28,12 @@ pub const MIN_ALIGN: usize = 8;
     target_arch = "wasm64",
 )))]
 pub const MIN_ALIGN: usize = 16;
+// The allocator on the esp-idf platform guarentees 4 byte alignment.
+#[cfg(all(any(
+    all(target_arch = "riscv32", target_os = "espidf"),
+    all(target_arch = "xtensa", target_os = "espidf"),
+)))]
+pub const MIN_ALIGN: usize = 4;
 
 pub unsafe fn realloc_fallback(
     alloc: &System,
diff --git a/library/std/src/sys/solid/abi/sockets.rs b/library/std/src/sys/solid/abi/sockets.rs
index 7c21d0dd25e..eb06a6dd927 100644
--- a/library/std/src/sys/solid/abi/sockets.rs
+++ b/library/std/src/sys/solid/abi/sockets.rs
@@ -175,6 +175,9 @@ extern "C" {
     #[link_name = "SOLID_NET_Close"]
     pub fn close(s: c_int) -> c_int;
 
+    #[link_name = "SOLID_NET_Dup"]
+    pub fn dup(s: c_int) -> c_int;
+
     #[link_name = "SOLID_NET_GetPeerName"]
     pub fn getpeername(s: c_int, name: *mut sockaddr, namelen: *mut socklen_t) -> c_int;
 
diff --git a/library/std/src/sys/solid/net.rs b/library/std/src/sys/solid/net.rs
index 63ba6341c79..c91ecce4d72 100644
--- a/library/std/src/sys/solid/net.rs
+++ b/library/std/src/sys/solid/net.rs
@@ -107,7 +107,7 @@ impl FileDesc {
     }
 
     fn duplicate(&self) -> io::Result<FileDesc> {
-        super::unsupported()
+        cvt(unsafe { netc::dup(self.fd) }).map(Self::new)
     }
 }
 
diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs
index 2362bff913f..3de7c68a686 100644
--- a/library/std/src/sys/unix/fd.rs
+++ b/library/std/src/sys/unix/fd.rs
@@ -259,22 +259,9 @@ impl FileDesc {
         }
     }
 
+    #[inline]
     pub fn duplicate(&self) -> io::Result<FileDesc> {
-        // We want to atomically duplicate this file descriptor and set the
-        // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
-        // is a POSIX flag that was added to Linux in 2.6.24.
-        #[cfg(not(target_os = "espidf"))]
-        let cmd = libc::F_DUPFD_CLOEXEC;
-
-        // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics
-        // will never be supported, as this is a bare metal framework with
-        // no capabilities for multi-process execution.  While F_DUPFD is also
-        // not supported yet, it might be (currently it returns ENOSYS).
-        #[cfg(target_os = "espidf")]
-        let cmd = libc::F_DUPFD;
-
-        let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?;
-        Ok(unsafe { FileDesc::from_raw_fd(fd) })
+        Ok(Self(self.0.try_clone()?))
     }
 }
 
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index f8deda93fe2..65e000d9215 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -34,7 +34,20 @@ use libc::c_char;
 use libc::dirfd;
 #[cfg(any(target_os = "linux", target_os = "emscripten"))]
 use libc::fstatat64;
+#[cfg(any(
+    target_os = "android",
+    target_os = "solaris",
+    target_os = "fuchsia",
+    target_os = "redox",
+    target_os = "illumos"
+))]
+use libc::readdir as readdir64;
+#[cfg(target_os = "linux")]
+use libc::readdir64;
+#[cfg(any(target_os = "emscripten", target_os = "l4re"))]
+use libc::readdir64_r;
 #[cfg(not(any(
+    target_os = "android",
     target_os = "linux",
     target_os = "emscripten",
     target_os = "solaris",
@@ -60,9 +73,7 @@ use libc::{
     lstat as lstat64, off_t as off64_t, open as open64, stat as stat64,
 };
 #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))]
-use libc::{
-    dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, readdir64_r, stat64,
-};
+use libc::{dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, stat64};
 
 pub use crate::sys_common::fs::try_exists;
 
@@ -202,6 +213,8 @@ struct InnerReadDir {
 pub struct ReadDir {
     inner: Arc<InnerReadDir>,
     #[cfg(not(any(
+        target_os = "android",
+        target_os = "linux",
         target_os = "solaris",
         target_os = "illumos",
         target_os = "fuchsia",
@@ -218,11 +231,12 @@ unsafe impl Sync for Dir {}
 pub struct DirEntry {
     entry: dirent64,
     dir: Arc<InnerReadDir>,
-    // We need to store an owned copy of the entry name
-    // on Solaris and Fuchsia because a) it uses a zero-length
-    // array to store the name, b) its lifetime between readdir
-    // calls is not guaranteed.
+    // We need to store an owned copy of the entry name on platforms that use
+    // readdir() (not readdir_r()), because a) struct dirent may use a flexible
+    // array to store the name, b) it lives only until the next readdir() call.
     #[cfg(any(
+        target_os = "android",
+        target_os = "linux",
         target_os = "solaris",
         target_os = "illumos",
         target_os = "fuchsia",
@@ -449,6 +463,8 @@ impl Iterator for ReadDir {
     type Item = io::Result<DirEntry>;
 
     #[cfg(any(
+        target_os = "android",
+        target_os = "linux",
         target_os = "solaris",
         target_os = "fuchsia",
         target_os = "redox",
@@ -457,12 +473,13 @@ impl Iterator for ReadDir {
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
         unsafe {
             loop {
-                // Although readdir_r(3) would be a correct function to use here because
-                // of the thread safety, on Illumos and Fuchsia the readdir(3C) function
-                // is safe to use in threaded applications and it is generally preferred
-                // over the readdir_r(3C) function.
+                // As of POSIX.1-2017, readdir() is not required to be thread safe; only
+                // readdir_r() is. However, readdir_r() cannot correctly handle platforms
+                // with unlimited or variable NAME_MAX.  Many modern platforms guarantee
+                // thread safety for readdir() as long an individual DIR* is not accessed
+                // concurrently, which is sufficient for Rust.
                 super::os::set_errno(0);
-                let entry_ptr = libc::readdir(self.inner.dirp.0);
+                let entry_ptr = readdir64(self.inner.dirp.0);
                 if entry_ptr.is_null() {
                     // null can mean either the end is reached or an error occurred.
                     // So we had to clear errno beforehand to check for an error now.
@@ -472,10 +489,18 @@ impl Iterator for ReadDir {
                     };
                 }
 
+                // Only d_reclen bytes of *entry_ptr are valid, so we can't just copy the
+                // whole thing (#93384).  Instead, copy everything except the name.
+                let entry_bytes = entry_ptr as *const u8;
+                let entry_name = ptr::addr_of!((*entry_ptr).d_name) as *const u8;
+                let name_offset = entry_name.offset_from(entry_bytes) as usize;
+                let mut entry: dirent64 = mem::zeroed();
+                ptr::copy_nonoverlapping(entry_bytes, &mut entry as *mut _ as *mut u8, name_offset);
+
                 let ret = DirEntry {
-                    entry: *entry_ptr,
+                    entry,
                     // d_name is guaranteed to be null-terminated.
-                    name: CStr::from_ptr((*entry_ptr).d_name.as_ptr()).to_owned(),
+                    name: CStr::from_ptr(entry_name as *const _).to_owned(),
                     dir: Arc::clone(&self.inner),
                 };
                 if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
@@ -486,6 +511,8 @@ impl Iterator for ReadDir {
     }
 
     #[cfg(not(any(
+        target_os = "android",
+        target_os = "linux",
         target_os = "solaris",
         target_os = "fuchsia",
         target_os = "redox",
@@ -531,17 +558,17 @@ impl Drop for Dir {
 
 impl DirEntry {
     pub fn path(&self) -> PathBuf {
-        self.dir.root.join(OsStr::from_bytes(self.name_bytes()))
+        self.dir.root.join(self.file_name_os_str())
     }
 
     pub fn file_name(&self) -> OsString {
-        OsStr::from_bytes(self.name_bytes()).to_os_string()
+        self.file_name_os_str().to_os_string()
     }
 
     #[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))]
     pub fn metadata(&self) -> io::Result<FileAttr> {
         let fd = cvt(unsafe { dirfd(self.dir.dirp.0) })?;
-        let name = self.entry.d_name.as_ptr();
+        let name = self.name_cstr().as_ptr();
 
         cfg_has_statx! {
             if let Some(ret) = unsafe { try_statx(
@@ -639,29 +666,21 @@ impl DirEntry {
             )
         }
     }
-    #[cfg(any(
-        target_os = "android",
-        target_os = "linux",
-        target_os = "emscripten",
-        target_os = "l4re",
-        target_os = "haiku",
-        target_os = "vxworks",
-        target_os = "espidf"
-    ))]
-    fn name_bytes(&self) -> &[u8] {
-        unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() }
-    }
-    #[cfg(any(
-        target_os = "solaris",
-        target_os = "illumos",
-        target_os = "fuchsia",
-        target_os = "redox"
-    ))]
+    #[cfg(not(any(
+        target_os = "macos",
+        target_os = "ios",
+        target_os = "netbsd",
+        target_os = "openbsd",
+        target_os = "freebsd",
+        target_os = "dragonfly"
+    )))]
     fn name_bytes(&self) -> &[u8] {
-        self.name.as_bytes()
+        self.name_cstr().to_bytes()
     }
 
     #[cfg(not(any(
+        target_os = "android",
+        target_os = "linux",
         target_os = "solaris",
         target_os = "illumos",
         target_os = "fuchsia",
@@ -670,7 +689,14 @@ impl DirEntry {
     fn name_cstr(&self) -> &CStr {
         unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }
     }
-    #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "fuchsia"))]
+    #[cfg(any(
+        target_os = "android",
+        target_os = "linux",
+        target_os = "solaris",
+        target_os = "illumos",
+        target_os = "fuchsia",
+        target_os = "redox"
+    ))]
     fn name_cstr(&self) -> &CStr {
         &self.name
     }
@@ -1076,6 +1102,8 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
             Ok(ReadDir {
                 inner: Arc::new(inner),
                 #[cfg(not(any(
+                    target_os = "android",
+                    target_os = "linux",
                     target_os = "solaris",
                     target_os = "illumos",
                     target_os = "fuchsia",
@@ -1448,8 +1476,8 @@ pub fn chroot(dir: &Path) -> io::Result<()> {
 
 pub use remove_dir_impl::remove_dir_all;
 
-// Fallback for REDOX
-#[cfg(target_os = "redox")]
+// Fallback for REDOX and ESP-IDF
+#[cfg(any(target_os = "redox", target_os = "espidf"))]
 mod remove_dir_impl {
     pub use crate::sys_common::fs::remove_dir_all;
 }
@@ -1573,7 +1601,11 @@ mod remove_dir_impl {
 }
 
 // Modern implementation using openat(), unlinkat() and fdopendir()
-#[cfg(not(any(all(target_os = "macos", target_arch = "x86_64"), target_os = "redox")))]
+#[cfg(not(any(
+    all(target_os = "macos", target_arch = "x86_64"),
+    target_os = "redox",
+    target_os = "espidf"
+)))]
 mod remove_dir_impl {
     use super::{cstr, lstat, Dir, DirEntry, InnerReadDir, ReadDir};
     use crate::ffi::CStr;
@@ -1611,6 +1643,8 @@ mod remove_dir_impl {
             ReadDir {
                 inner: Arc::new(InnerReadDir { dirp, root: dummy_root }),
                 #[cfg(not(any(
+                    target_os = "android",
+                    target_os = "linux",
                     target_os = "solaris",
                     target_os = "illumos",
                     target_os = "fuchsia",
@@ -1627,7 +1661,6 @@ mod remove_dir_impl {
         target_os = "illumos",
         target_os = "haiku",
         target_os = "vxworks",
-        target_os = "fuchsia"
     ))]
     fn is_dir(_ent: &DirEntry) -> Option<bool> {
         None
@@ -1638,7 +1671,6 @@ mod remove_dir_impl {
         target_os = "illumos",
         target_os = "haiku",
         target_os = "vxworks",
-        target_os = "fuchsia"
     )))]
     fn is_dir(ent: &DirEntry) -> Option<bool> {
         match ent.entry.d_type {
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 8a028d99306..7466c77356c 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -75,7 +75,7 @@ pub fn errno() -> i32 {
 }
 
 /// Sets the platform-specific value of errno
-#[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall!
+#[cfg(all(not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall!
 #[allow(dead_code)] // but not all target cfgs actually end up using it
 pub fn set_errno(e: i32) {
     unsafe { *errno_location() = e as c_int }
diff --git a/library/std/src/sys/unix/process/process_unix/tests.rs b/library/std/src/sys/unix/process/process_unix/tests.rs
index 157debf2d25..560c62155d9 100644
--- a/library/std/src/sys/unix/process/process_unix/tests.rs
+++ b/library/std/src/sys/unix/process/process_unix/tests.rs
@@ -53,5 +53,10 @@ fn test_command_fork_no_unwind() {
     let status = got.expect("panic unexpectedly propagated");
     dbg!(status);
     let signal = status.signal().expect("expected child process to die of signal");
-    assert!(signal == libc::SIGABRT || signal == libc::SIGILL || signal == libc::SIGTRAP);
+    assert!(
+        signal == libc::SIGABRT
+            || signal == libc::SIGILL
+            || signal == libc::SIGTRAP
+            || signal == libc::SIGSEGV
+    );
 }
diff --git a/library/std/src/sys/wasi/fd.rs b/library/std/src/sys/wasi/fd.rs
index e4f4456611c..0b9c8e61db8 100644
--- a/library/std/src/sys/wasi/fd.rs
+++ b/library/std/src/sys/wasi/fd.rs
@@ -228,6 +228,10 @@ impl WasiFd {
         unsafe { wasi::path_remove_directory(self.as_raw_fd() as wasi::Fd, path).map_err(err2io) }
     }
 
+    pub fn sock_accept(&self, flags: wasi::Fdflags) -> io::Result<wasi::Fd> {
+        unsafe { wasi::sock_accept(self.as_raw_fd() as wasi::Fd, flags).map_err(err2io) }
+    }
+
     pub fn sock_recv(
         &self,
         ri_data: &mut [IoSliceMut<'_>],
diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs
index 8d62335aae5..f878941939c 100644
--- a/library/std/src/sys/wasi/mod.rs
+++ b/library/std/src/sys/wasi/mod.rs
@@ -61,23 +61,26 @@ pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind {
     if errno > u16::MAX as i32 || errno < 0 {
         return Uncategorized;
     }
-    match errno as u16 {
-        wasi::ERRNO_CONNREFUSED => ConnectionRefused,
-        wasi::ERRNO_CONNRESET => ConnectionReset,
-        wasi::ERRNO_PERM | wasi::ERRNO_ACCES => PermissionDenied,
-        wasi::ERRNO_PIPE => BrokenPipe,
-        wasi::ERRNO_NOTCONN => NotConnected,
-        wasi::ERRNO_CONNABORTED => ConnectionAborted,
-        wasi::ERRNO_ADDRNOTAVAIL => AddrNotAvailable,
-        wasi::ERRNO_ADDRINUSE => AddrInUse,
-        wasi::ERRNO_NOENT => NotFound,
-        wasi::ERRNO_INTR => Interrupted,
-        wasi::ERRNO_INVAL => InvalidInput,
-        wasi::ERRNO_TIMEDOUT => TimedOut,
-        wasi::ERRNO_EXIST => AlreadyExists,
-        wasi::ERRNO_AGAIN => WouldBlock,
-        wasi::ERRNO_NOSYS => Unsupported,
-        wasi::ERRNO_NOMEM => OutOfMemory,
+
+    match errno {
+        e if e == wasi::ERRNO_CONNREFUSED.raw().into() => ConnectionRefused,
+        e if e == wasi::ERRNO_CONNRESET.raw().into() => ConnectionReset,
+        e if e == wasi::ERRNO_PERM.raw().into() || e == wasi::ERRNO_ACCES.raw().into() => {
+            PermissionDenied
+        }
+        e if e == wasi::ERRNO_PIPE.raw().into() => BrokenPipe,
+        e if e == wasi::ERRNO_NOTCONN.raw().into() => NotConnected,
+        e if e == wasi::ERRNO_CONNABORTED.raw().into() => ConnectionAborted,
+        e if e == wasi::ERRNO_ADDRNOTAVAIL.raw().into() => AddrNotAvailable,
+        e if e == wasi::ERRNO_ADDRINUSE.raw().into() => AddrInUse,
+        e if e == wasi::ERRNO_NOENT.raw().into() => NotFound,
+        e if e == wasi::ERRNO_INTR.raw().into() => Interrupted,
+        e if e == wasi::ERRNO_INVAL.raw().into() => InvalidInput,
+        e if e == wasi::ERRNO_TIMEDOUT.raw().into() => TimedOut,
+        e if e == wasi::ERRNO_EXIST.raw().into() => AlreadyExists,
+        e if e == wasi::ERRNO_AGAIN.raw().into() => WouldBlock,
+        e if e == wasi::ERRNO_NOSYS.raw().into() => Unsupported,
+        e if e == wasi::ERRNO_NOMEM.raw().into() => OutOfMemory,
         _ => Uncategorized,
     }
 }
@@ -96,6 +99,6 @@ pub fn hashmap_random_keys() -> (u64, u64) {
     return ret;
 }
 
-fn err2io(err: wasi::Error) -> std_io::Error {
-    std_io::Error::from_raw_os_error(err.raw_error().into())
+fn err2io(err: wasi::Errno) -> std_io::Error {
+    std_io::Error::from_raw_os_error(err.raw().into())
 }
diff --git a/library/std/src/sys/wasi/net.rs b/library/std/src/sys/wasi/net.rs
index a4dbb225376..c66e0e4d328 100644
--- a/library/std/src/sys/wasi/net.rs
+++ b/library/std/src/sys/wasi/net.rs
@@ -1,5 +1,6 @@
 #![deny(unsafe_op_in_unsafe_fn)]
 
+use super::err2io;
 use super::fd::WasiFd;
 use crate::convert::TryFrom;
 use crate::fmt;
@@ -87,24 +88,24 @@ impl TcpStream {
         unsupported()
     }
 
-    pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
-        unsupported()
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.read_vectored(&mut [IoSliceMut::new(buf)])
     }
 
-    pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        unsupported()
+    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        self.socket().as_inner().read(bufs)
     }
 
     pub fn is_read_vectored(&self) -> bool {
         true
     }
 
-    pub fn write(&self, _: &[u8]) -> io::Result<usize> {
-        unsupported()
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        self.write_vectored(&[IoSlice::new(buf)])
     }
 
-    pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> {
-        unsupported()
+    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        self.socket().as_inner().write(bufs)
     }
 
     pub fn is_write_vectored(&self) -> bool {
@@ -155,8 +156,23 @@ impl TcpStream {
         unsupported()
     }
 
-    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
-        unsupported()
+    pub fn set_nonblocking(&self, state: bool) -> io::Result<()> {
+        let fdstat = unsafe {
+            wasi::fd_fdstat_get(self.socket().as_inner().as_raw_fd() as wasi::Fd).map_err(err2io)?
+        };
+
+        let mut flags = fdstat.fs_flags;
+
+        if state {
+            flags |= wasi::FDFLAGS_NONBLOCK;
+        } else {
+            flags &= !wasi::FDFLAGS_NONBLOCK;
+        }
+
+        unsafe {
+            wasi::fd_fdstat_set_flags(self.socket().as_inner().as_raw_fd() as wasi::Fd, flags)
+                .map_err(err2io)
+        }
     }
 
     pub fn socket(&self) -> &Socket {
@@ -194,7 +210,16 @@ impl TcpListener {
     }
 
     pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
-        unsupported()
+        let fd = unsafe {
+            wasi::sock_accept(self.as_inner().as_inner().as_raw_fd() as _, 0).map_err(err2io)?
+        };
+
+        Ok((
+            TcpStream::from_inner(unsafe { Socket::from_raw_fd(fd as _) }),
+            // WASI has no concept of SocketAddr yet
+            // return an unspecified IPv4Addr
+            SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 0),
+        ))
     }
 
     pub fn duplicate(&self) -> io::Result<TcpListener> {
@@ -221,8 +246,23 @@ impl TcpListener {
         unsupported()
     }
 
-    pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
-        unsupported()
+    pub fn set_nonblocking(&self, state: bool) -> io::Result<()> {
+        let fdstat = unsafe {
+            wasi::fd_fdstat_get(self.socket().as_inner().as_raw_fd() as wasi::Fd).map_err(err2io)?
+        };
+
+        let mut flags = fdstat.fs_flags;
+
+        if state {
+            flags |= wasi::FDFLAGS_NONBLOCK;
+        } else {
+            flags &= !wasi::FDFLAGS_NONBLOCK;
+        }
+
+        unsafe {
+            wasi::fd_fdstat_set_flags(self.socket().as_inner().as_raw_fd() as wasi::Fd, flags)
+                .map_err(err2io)
+        }
     }
 
     pub fn socket(&self) -> &Socket {
diff --git a/library/std/src/sys/wasi/stdio.rs b/library/std/src/sys/wasi/stdio.rs
index 2c8f394cd47..4cc0e4ed5a4 100644
--- a/library/std/src/sys/wasi/stdio.rs
+++ b/library/std/src/sys/wasi/stdio.rs
@@ -104,7 +104,7 @@ impl io::Write for Stderr {
 pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE;
 
 pub fn is_ebadf(err: &io::Error) -> bool {
-    err.raw_os_error() == Some(wasi::ERRNO_BADF.into())
+    err.raw_os_error() == Some(wasi::ERRNO_BADF.raw().into())
 }
 
 pub fn panic_output() -> Option<impl io::Write> {
diff --git a/library/std/src/sys/wasi/thread.rs b/library/std/src/sys/wasi/thread.rs
index 2e4e474c449..e7a6ab4be82 100644
--- a/library/std/src/sys/wasi/thread.rs
+++ b/library/std/src/sys/wasi/thread.rs
@@ -41,8 +41,7 @@ impl Thread {
 
         let in_ = wasi::Subscription {
             userdata: USERDATA,
-            r#type: wasi::EVENTTYPE_CLOCK,
-            u: wasi::SubscriptionU { clock },
+            u: wasi::SubscriptionU { tag: 0, u: wasi::SubscriptionUU { clock } },
         };
         unsafe {
             let mut event: wasi::Event = mem::zeroed();
@@ -51,7 +50,10 @@ impl Thread {
                 (
                     Ok(1),
                     wasi::Event {
-                        userdata: USERDATA, error: 0, r#type: wasi::EVENTTYPE_CLOCK, ..
+                        userdata: USERDATA,
+                        error: wasi::ERRNO_SUCCESS,
+                        type_: wasi::EVENTTYPE_CLOCK,
+                        ..
                     },
                 ) => {}
                 _ => panic!("thread::sleep(): unexpected result of poll_oneoff"),
diff --git a/library/std/src/sys/wasi/time.rs b/library/std/src/sys/wasi/time.rs
index 2e720d11603..db0ddecf0c6 100644
--- a/library/std/src/sys/wasi/time.rs
+++ b/library/std/src/sys/wasi/time.rs
@@ -10,7 +10,7 @@ pub struct SystemTime(Duration);
 
 pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
 
-fn current_time(clock: u32) -> Duration {
+fn current_time(clock: wasi::Clockid) -> Duration {
     let ts = unsafe {
         wasi::clock_time_get(
             clock, 1, // precision... seems ignored though?
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index dd21c6b4389..028b6b30099 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -460,7 +460,7 @@ impl File {
     }
 
     pub fn duplicate(&self) -> io::Result<File> {
-        Ok(File { handle: self.handle.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)? })
+        Ok(Self { handle: self.handle.try_clone()? })
     }
 
     fn reparse_point<'a>(
diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs
index c3a3482f910..daab39bb00c 100644
--- a/library/std/src/sys/windows/handle.rs
+++ b/library/std/src/sys/windows/handle.rs
@@ -262,26 +262,17 @@ impl Handle {
         Ok(written as usize)
     }
 
+    pub fn try_clone(&self) -> io::Result<Self> {
+        Ok(Self(self.0.try_clone()?))
+    }
+
     pub fn duplicate(
         &self,
         access: c::DWORD,
         inherit: bool,
         options: c::DWORD,
-    ) -> io::Result<Handle> {
-        let mut ret = 0 as c::HANDLE;
-        cvt(unsafe {
-            let cur_proc = c::GetCurrentProcess();
-            c::DuplicateHandle(
-                cur_proc,
-                self.as_raw_handle(),
-                cur_proc,
-                &mut ret,
-                access,
-                inherit as c::BOOL,
-                options,
-            )
-        })?;
-        unsafe { Ok(Handle::from_raw_handle(ret)) }
+    ) -> io::Result<Self> {
+        Ok(Self(self.0.duplicate(access, inherit, options)?))
     }
 }
 
diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs
index 084af4325e7..ad4492f9d1f 100644
--- a/library/std/src/sys/windows/mod.rs
+++ b/library/std/src/sys/windows/mod.rs
@@ -285,6 +285,7 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD {
 #[allow(unreachable_code)]
 pub fn abort_internal() -> ! {
     const FAST_FAIL_FATAL_APP_EXIT: usize = 7;
+    #[cfg(not(miri))] // inline assembly does not work in Miri
     unsafe {
         cfg_if::cfg_if! {
             if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs
index 9c631e7e51c..14d5f15d202 100644
--- a/library/std/src/sys/windows/net.rs
+++ b/library/std/src/sys/windows/net.rs
@@ -134,7 +134,7 @@ impl Socket {
 
             unsafe {
                 let socket = Self::from_raw_socket(socket);
-                socket.set_no_inherit()?;
+                socket.0.set_no_inherit()?;
                 Ok(socket)
             }
         }
@@ -213,52 +213,7 @@ impl Socket {
     }
 
     pub fn duplicate(&self) -> io::Result<Socket> {
-        let mut info = unsafe { mem::zeroed::<c::WSAPROTOCOL_INFO>() };
-        let result = unsafe {
-            c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info)
-        };
-        cvt(result)?;
-        let socket = unsafe {
-            c::WSASocketW(
-                info.iAddressFamily,
-                info.iSocketType,
-                info.iProtocol,
-                &mut info,
-                0,
-                c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT,
-            )
-        };
-
-        if socket != c::INVALID_SOCKET {
-            unsafe { Ok(Self::from_inner(OwnedSocket::from_raw_socket(socket))) }
-        } else {
-            let error = unsafe { c::WSAGetLastError() };
-
-            if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL {
-                return Err(io::Error::from_raw_os_error(error));
-            }
-
-            let socket = unsafe {
-                c::WSASocketW(
-                    info.iAddressFamily,
-                    info.iSocketType,
-                    info.iProtocol,
-                    &mut info,
-                    0,
-                    c::WSA_FLAG_OVERLAPPED,
-                )
-            };
-
-            if socket == c::INVALID_SOCKET {
-                return Err(last_error());
-            }
-
-            unsafe {
-                let socket = Self::from_inner(OwnedSocket::from_raw_socket(socket));
-                socket.set_no_inherit()?;
-                Ok(socket)
-            }
-        }
+        Ok(Self(self.0.try_clone()?))
     }
 
     fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
@@ -421,19 +376,6 @@ impl Socket {
         }
     }
 
-    #[cfg(not(target_vendor = "uwp"))]
-    fn set_no_inherit(&self) -> io::Result<()> {
-        sys::cvt(unsafe {
-            c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0)
-        })
-        .map(drop)
-    }
-
-    #[cfg(target_vendor = "uwp")]
-    fn set_no_inherit(&self) -> io::Result<()> {
-        Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Unavailable on UWP"))
-    }
-
     pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
         let how = match how {
             Shutdown::Write => c::SD_SEND,
diff --git a/library/std/src/sys_common/io.rs b/library/std/src/sys_common/io.rs
index ea9108f1713..d1e9fed41fc 100644
--- a/library/std/src/sys_common/io.rs
+++ b/library/std/src/sys_common/io.rs
@@ -8,6 +8,7 @@ pub mod test {
     use crate::env;
     use crate::fs;
     use crate::path::{Path, PathBuf};
+    use crate::thread;
     use rand::RngCore;
 
     pub struct TempDir(PathBuf);
@@ -29,7 +30,12 @@ pub mod test {
             // Gee, seeing how we're testing the fs module I sure hope that we
             // at least implement this correctly!
             let TempDir(ref p) = *self;
-            fs::remove_dir_all(p).unwrap();
+            let result = fs::remove_dir_all(p);
+            // Avoid panicking while panicking as this causes the process to
+            // immediately abort, without displaying test results.
+            if !thread::panicking() {
+                result.unwrap();
+            }
         }
     }
 
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 546f8a15b70..f8d790c3785 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -180,6 +180,12 @@ use crate::time::Duration;
 #[macro_use]
 mod local;
 
+#[unstable(feature = "scoped_threads", issue = "93203")]
+mod scoped;
+
+#[unstable(feature = "scoped_threads", issue = "93203")]
+pub use scoped::{scope, Scope, ScopedJoinHandle};
+
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::local::{AccessError, LocalKey};
 
@@ -447,6 +453,20 @@ impl Builder {
         F: Send + 'a,
         T: Send + 'a,
     {
+        Ok(JoinHandle(unsafe { self.spawn_unchecked_(f, None) }?))
+    }
+
+    unsafe fn spawn_unchecked_<'a, 'scope, F, T>(
+        self,
+        f: F,
+        scope_data: Option<&'scope scoped::ScopeData>,
+    ) -> io::Result<JoinInner<'scope, T>>
+    where
+        F: FnOnce() -> T,
+        F: Send + 'a,
+        T: Send + 'a,
+        'scope: 'a,
+    {
         let Builder { name, stack_size } = self;
 
         let stack_size = stack_size.unwrap_or_else(thread::min_stack);
@@ -456,7 +476,8 @@ impl Builder {
         }));
         let their_thread = my_thread.clone();
 
-        let my_packet: Arc<UnsafeCell<Option<Result<T>>>> = Arc::new(UnsafeCell::new(None));
+        let my_packet: Arc<Packet<'scope, T>> =
+            Arc::new(Packet { scope: scope_data, result: UnsafeCell::new(None) });
         let their_packet = my_packet.clone();
 
         let output_capture = crate::io::set_output_capture(None);
@@ -480,10 +501,14 @@ impl Builder {
             // closure (it is an Arc<...>) and `my_packet` will be stored in the
             // same `JoinInner` as this closure meaning the mutation will be
             // safe (not modify it and affect a value far away).
-            unsafe { *their_packet.get() = Some(try_result) };
+            unsafe { *their_packet.result.get() = Some(try_result) };
         };
 
-        Ok(JoinHandle(JoinInner {
+        if let Some(scope_data) = scope_data {
+            scope_data.increment_num_running_threads();
+        }
+
+        Ok(JoinInner {
             // SAFETY:
             //
             // `imp::Thread::new` takes a closure with a `'static` lifetime, since it's passed
@@ -506,8 +531,8 @@ impl Builder {
                 )?
             },
             thread: my_thread,
-            packet: Packet(my_packet),
-        }))
+            packet: my_packet,
+        })
     }
 }
 
@@ -1242,34 +1267,48 @@ impl fmt::Debug for Thread {
 #[stable(feature = "rust1", since = "1.0.0")]
 pub type Result<T> = crate::result::Result<T, Box<dyn Any + Send + 'static>>;
 
-// This packet is used to communicate the return value between the spawned thread
-// and the rest of the program. Memory is shared through the `Arc` within and there's
-// no need for a mutex here because synchronization happens with `join()` (the
-// caller will never read this packet until the thread has exited).
+// This packet is used to communicate the return value between the spawned
+// thread and the rest of the program. It is shared through an `Arc` and
+// there's no need for a mutex here because synchronization happens with `join()`
+// (the caller will never read this packet until the thread has exited).
 //
-// This packet itself is then stored into a `JoinInner` which in turns is placed
-// in `JoinHandle` and `JoinGuard`. Due to the usage of `UnsafeCell` we need to
-// manually worry about impls like Send and Sync. The type `T` should
-// already always be Send (otherwise the thread could not have been created) and
-// this type is inherently Sync because no methods take &self. Regardless,
-// however, we add inheriting impls for Send/Sync to this type to ensure it's
-// Send/Sync and that future modifications will still appropriately classify it.
-struct Packet<T>(Arc<UnsafeCell<Option<Result<T>>>>);
-
-unsafe impl<T: Send> Send for Packet<T> {}
-unsafe impl<T: Sync> Sync for Packet<T> {}
+// An Arc to the packet is stored into a `JoinInner` which in turns is placed
+// in `JoinHandle`.
+struct Packet<'scope, T> {
+    scope: Option<&'scope scoped::ScopeData>,
+    result: UnsafeCell<Option<Result<T>>>,
+}
+
+// Due to the usage of `UnsafeCell` we need to manually implement Sync.
+// The type `T` should already always be Send (otherwise the thread could not
+// have been created) and the Packet is Sync because all access to the
+// `UnsafeCell` synchronized (by the `join()` boundary), and `ScopeData` is Sync.
+unsafe impl<'scope, T: Sync> Sync for Packet<'scope, T> {}
+
+impl<'scope, T> Drop for Packet<'scope, T> {
+    fn drop(&mut self) {
+        // Book-keeping so the scope knows when it's done.
+        if let Some(scope) = self.scope {
+            // If this packet was for a thread that ran in a scope, the thread
+            // panicked, and nobody consumed the panic payload, we make sure
+            // the scope function will panic.
+            let unhandled_panic = matches!(self.result.get_mut(), Some(Err(_)));
+            scope.decrement_num_running_threads(unhandled_panic);
+        }
+    }
+}
 
 /// Inner representation for JoinHandle
-struct JoinInner<T> {
+struct JoinInner<'scope, T> {
     native: imp::Thread,
     thread: Thread,
-    packet: Packet<T>,
+    packet: Arc<Packet<'scope, T>>,
 }
 
-impl<T> JoinInner<T> {
+impl<'scope, T> JoinInner<'scope, T> {
     fn join(mut self) -> Result<T> {
         self.native.join();
-        Arc::get_mut(&mut self.packet.0).unwrap().get_mut().take().unwrap()
+        Arc::get_mut(&mut self.packet).unwrap().result.get_mut().take().unwrap()
     }
 }
 
@@ -1336,7 +1375,7 @@ impl<T> JoinInner<T> {
 /// [`thread::Builder::spawn`]: Builder::spawn
 /// [`thread::spawn`]: spawn
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct JoinHandle<T>(JoinInner<T>);
+pub struct JoinHandle<T>(JoinInner<'static, T>);
 
 #[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")]
 unsafe impl<T> Send for JoinHandle<T> {}
@@ -1404,13 +1443,13 @@ impl<T> JoinHandle<T> {
         self.0.join()
     }
 
-    /// Checks if the the associated thread is still running its main function.
+    /// Checks if the associated thread is still running its main function.
     ///
     /// This might return `false` for a brief moment after the thread's main
     /// function has returned, but before the thread itself has stopped running.
     #[unstable(feature = "thread_is_running", issue = "90470")]
     pub fn is_running(&self) -> bool {
-        Arc::strong_count(&self.0.packet.0) > 1
+        Arc::strong_count(&self.0.packet) > 1
     }
 }
 
diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs
new file mode 100644
index 00000000000..9dd7c15fc59
--- /dev/null
+++ b/library/std/src/thread/scoped.rs
@@ -0,0 +1,316 @@
+use super::{current, park, Builder, JoinInner, Result, Thread};
+use crate::fmt;
+use crate::io;
+use crate::marker::PhantomData;
+use crate::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
+use crate::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
+use crate::sync::Arc;
+
+/// A scope to spawn scoped threads in.
+///
+/// See [`scope`] for details.
+pub struct Scope<'env> {
+    data: ScopeData,
+    /// Invariance over 'env, to make sure 'env cannot shrink,
+    /// which is necessary for soundness.
+    ///
+    /// Without invariance, this would compile fine but be unsound:
+    ///
+    /// ```compile_fail
+    /// #![feature(scoped_threads)]
+    ///
+    /// std::thread::scope(|s| {
+    ///     s.spawn(|s| {
+    ///         let a = String::from("abcd");
+    ///         s.spawn(|_| println!("{:?}", a)); // might run after `a` is dropped
+    ///     });
+    /// });
+    /// ```
+    env: PhantomData<&'env mut &'env ()>,
+}
+
+/// An owned permission to join on a scoped thread (block on its termination).
+///
+/// See [`Scope::spawn`] for details.
+pub struct ScopedJoinHandle<'scope, T>(JoinInner<'scope, T>);
+
+pub(super) struct ScopeData {
+    num_running_threads: AtomicUsize,
+    a_thread_panicked: AtomicBool,
+    main_thread: Thread,
+}
+
+impl ScopeData {
+    pub(super) fn increment_num_running_threads(&self) {
+        // We check for 'overflow' with usize::MAX / 2, to make sure there's no
+        // chance it overflows to 0, which would result in unsoundness.
+        if self.num_running_threads.fetch_add(1, Ordering::Relaxed) > usize::MAX / 2 {
+            // This can only reasonably happen by mem::forget()'ing many many ScopedJoinHandles.
+            self.decrement_num_running_threads(false);
+            panic!("too many running threads in thread scope");
+        }
+    }
+    pub(super) fn decrement_num_running_threads(&self, panic: bool) {
+        if panic {
+            self.a_thread_panicked.store(true, Ordering::Relaxed);
+        }
+        if self.num_running_threads.fetch_sub(1, Ordering::Release) == 1 {
+            self.main_thread.unpark();
+        }
+    }
+}
+
+/// Create a scope for spawning scoped threads.
+///
+/// The function passed to `scope` will be provided a [`Scope`] object,
+/// through which scoped threads can be [spawned][`Scope::spawn`].
+///
+/// Unlike non-scoped threads, scoped threads can borrow non-`'static` data,
+/// as the scope guarantees all threads will be joined at the end of the scope.
+///
+/// All threads spawned within the scope that haven't been manually joined
+/// will be automatically joined before this function returns.
+///
+/// # Panics
+///
+/// If any of the automatically joined threads panicked, this function will panic.
+///
+/// If you want to handle panics from spawned threads,
+/// [`join`][ScopedJoinHandle::join] them before the end of the scope.
+///
+/// # Example
+///
+/// ```
+/// #![feature(scoped_threads)]
+/// use std::thread;
+///
+/// let mut a = vec![1, 2, 3];
+/// let mut x = 0;
+///
+/// thread::scope(|s| {
+///     s.spawn(|_| {
+///         println!("hello from the first scoped thread");
+///         // We can borrow `a` here.
+///         dbg!(&a);
+///     });
+///     s.spawn(|_| {
+///         println!("hello from the second scoped thread");
+///         // We can even mutably borrow `x` here,
+///         // because no other threads are using it.
+///         x += a[0] + a[2];
+///     });
+///     println!("hello from the main thread");
+/// });
+///
+/// // After the scope, we can modify and access our variables again:
+/// a.push(4);
+/// assert_eq!(x, a.len());
+/// ```
+#[track_caller]
+pub fn scope<'env, F, T>(f: F) -> T
+where
+    F: FnOnce(&Scope<'env>) -> T,
+{
+    let scope = Scope {
+        data: ScopeData {
+            num_running_threads: AtomicUsize::new(0),
+            main_thread: current(),
+            a_thread_panicked: AtomicBool::new(false),
+        },
+        env: PhantomData,
+    };
+
+    // Run `f`, but catch panics so we can make sure to wait for all the threads to join.
+    let result = catch_unwind(AssertUnwindSafe(|| f(&scope)));
+
+    // Wait until all the threads are finished.
+    while scope.data.num_running_threads.load(Ordering::Acquire) != 0 {
+        park();
+    }
+
+    // Throw any panic from `f`, or the return value of `f` if no thread panicked.
+    match result {
+        Err(e) => resume_unwind(e),
+        Ok(_) if scope.data.a_thread_panicked.load(Ordering::Relaxed) => {
+            panic!("a scoped thread panicked")
+        }
+        Ok(result) => result,
+    }
+}
+
+impl<'env> Scope<'env> {
+    /// Spawns a new thread within a scope, returning a [`ScopedJoinHandle`] for it.
+    ///
+    /// Unlike non-scoped threads, threads spawned with this function may
+    /// borrow non-`'static` data from the outside the scope. See [`scope`] for
+    /// details.
+    ///
+    /// The join handle provides a [`join`] method that can be used to join the spawned
+    /// thread. If the spawned thread panics, [`join`] will return an [`Err`] containing
+    /// the panic payload.
+    ///
+    /// If the join handle is dropped, the spawned thread will implicitly joined at the
+    /// end of the scope. In that case, if the spawned thread panics, [`scope`] will
+    /// panic after all threads are joined.
+    ///
+    /// This call will create a thread using default parameters of [`Builder`].
+    /// If you want to specify the stack size or the name of the thread, use
+    /// [`Builder::spawn_scoped`] instead.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the OS fails to create a thread; use [`Builder::spawn_scoped`]
+    /// to recover from such errors.
+    ///
+    /// [`join`]: ScopedJoinHandle::join
+    pub fn spawn<'scope, F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T>
+    where
+        F: FnOnce(&Scope<'env>) -> T + Send + 'env,
+        T: Send + 'env,
+    {
+        Builder::new().spawn_scoped(self, f).expect("failed to spawn thread")
+    }
+}
+
+impl Builder {
+    /// Spawns a new scoped thread using the settings set through this `Builder`.
+    ///
+    /// Unlike [`Scope::spawn`], this method yields an [`io::Result`] to
+    /// capture any failure to create the thread at the OS level.
+    ///
+    /// [`io::Result`]: crate::io::Result
+    ///
+    /// # Panics
+    ///
+    /// Panics if a thread name was set and it contained null bytes.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// #![feature(scoped_threads)]
+    /// use std::thread;
+    ///
+    /// let mut a = vec![1, 2, 3];
+    /// let mut x = 0;
+    ///
+    /// thread::scope(|s| {
+    ///     thread::Builder::new()
+    ///         .name("first".to_string())
+    ///         .spawn_scoped(s, |_|
+    ///     {
+    ///         println!("hello from the {:?} scoped thread", thread::current().name());
+    ///         // We can borrow `a` here.
+    ///         dbg!(&a);
+    ///     })
+    ///     .unwrap();
+    ///     thread::Builder::new()
+    ///         .name("second".to_string())
+    ///         .spawn_scoped(s, |_|
+    ///     {
+    ///         println!("hello from the {:?} scoped thread", thread::current().name());
+    ///         // We can even mutably borrow `x` here,
+    ///         // because no other threads are using it.
+    ///         x += a[0] + a[2];
+    ///     })
+    ///     .unwrap();
+    ///     println!("hello from the main thread");
+    /// });
+    ///
+    /// // After the scope, we can modify and access our variables again:
+    /// a.push(4);
+    /// assert_eq!(x, a.len());
+    /// ```
+    pub fn spawn_scoped<'scope, 'env, F, T>(
+        self,
+        scope: &'scope Scope<'env>,
+        f: F,
+    ) -> io::Result<ScopedJoinHandle<'scope, T>>
+    where
+        F: FnOnce(&Scope<'env>) -> T + Send + 'env,
+        T: Send + 'env,
+    {
+        Ok(ScopedJoinHandle(unsafe { self.spawn_unchecked_(|| f(scope), Some(&scope.data)) }?))
+    }
+}
+
+impl<'scope, T> ScopedJoinHandle<'scope, T> {
+    /// Extracts a handle to the underlying thread.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(scoped_threads)]
+    /// #![feature(thread_is_running)]
+    ///
+    /// use std::thread;
+    ///
+    /// thread::scope(|s| {
+    ///     let t = s.spawn(|_| {
+    ///         println!("hello");
+    ///     });
+    ///     println!("thread id: {:?}", t.thread().id());
+    /// });
+    /// ```
+    #[must_use]
+    pub fn thread(&self) -> &Thread {
+        &self.0.thread
+    }
+
+    /// Waits for the associated thread to finish.
+    ///
+    /// This function will return immediately if the associated thread has already finished.
+    ///
+    /// In terms of [atomic memory orderings], the completion of the associated
+    /// thread synchronizes with this function returning.
+    /// In other words, all operations performed by that thread
+    /// [happen before](https://doc.rust-lang.org/nomicon/atomics.html#data-accesses)
+    /// all operations that happen after `join` returns.
+    ///
+    /// If the associated thread panics, [`Err`] is returned with the panic payload.
+    ///
+    /// [atomic memory orderings]: crate::sync::atomic
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(scoped_threads)]
+    /// #![feature(thread_is_running)]
+    ///
+    /// use std::thread;
+    ///
+    /// thread::scope(|s| {
+    ///     let t = s.spawn(|_| {
+    ///         panic!("oh no");
+    ///     });
+    ///     assert!(t.join().is_err());
+    /// });
+    /// ```
+    pub fn join(self) -> Result<T> {
+        self.0.join()
+    }
+
+    /// Checks if the associated thread is still running its main function.
+    ///
+    /// This might return `false` for a brief moment after the thread's main
+    /// function has returned, but before the thread itself has stopped running.
+    #[unstable(feature = "thread_is_running", issue = "90470")]
+    pub fn is_running(&self) -> bool {
+        Arc::strong_count(&self.0.packet) > 1
+    }
+}
+
+impl<'env> fmt::Debug for Scope<'env> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Scope")
+            .field("num_running_threads", &self.data.num_running_threads.load(Ordering::Relaxed))
+            .field("a_thread_panicked", &self.data.a_thread_panicked.load(Ordering::Relaxed))
+            .field("main_thread", &self.data.main_thread)
+            .finish_non_exhaustive()
+    }
+}
+
+impl<'scope, T> fmt::Debug for ScopedJoinHandle<'scope, T> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("ScopedJoinHandle").finish_non_exhaustive()
+    }
+}
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index b6867e68df7..b4f9d8ea28d 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -45,7 +45,7 @@ use crate::sys_common::FromInner;
 pub use core::time::Duration;
 
 #[unstable(feature = "duration_checked_float", issue = "83400")]
-pub use core::time::FromSecsError;
+pub use core::time::FromFloatSecsError;
 
 /// A measurement of a monotonically nondecreasing clock.
 /// Opaque and useful only with [`Duration`].
diff --git a/library/std/tests/run-time-detect.rs b/library/std/tests/run-time-detect.rs
index 079f00a5753..14a9e3acca4 100644
--- a/library/std/tests/run-time-detect.rs
+++ b/library/std/tests/run-time-detect.rs
@@ -14,6 +14,7 @@
 #[test]
 #[cfg(all(target_arch = "arm", any(target_os = "linux", target_os = "android")))]
 fn arm_linux() {
+    use std::arch::is_arm_feature_detected;
     println!("neon: {}", is_arm_feature_detected!("neon"));
     println!("pmull: {}", is_arm_feature_detected!("pmull"));
     println!("crypto: {}", is_arm_feature_detected!("crypto"));
@@ -25,6 +26,7 @@ fn arm_linux() {
 #[test]
 #[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))]
 fn aarch64_linux() {
+    use std::arch::is_aarch64_feature_detected;
     println!("neon: {}", is_aarch64_feature_detected!("neon"));
     println!("asimd: {}", is_aarch64_feature_detected!("asimd"));
     println!("pmull: {}", is_aarch64_feature_detected!("pmull"));
@@ -71,6 +73,7 @@ fn aarch64_linux() {
 #[test]
 #[cfg(all(target_arch = "powerpc", target_os = "linux"))]
 fn powerpc_linux() {
+    use std::arch::is_powerpc_feature_detected;
     println!("altivec: {}", is_powerpc_feature_detected!("altivec"));
     println!("vsx: {}", is_powerpc_feature_detected!("vsx"));
     println!("power8: {}", is_powerpc_feature_detected!("power8"));
@@ -79,6 +82,7 @@ fn powerpc_linux() {
 #[test]
 #[cfg(all(target_arch = "powerpc64", target_os = "linux"))]
 fn powerpc64_linux() {
+    use std::arch::is_powerpc64_feature_detected;
     println!("altivec: {}", is_powerpc64_feature_detected!("altivec"));
     println!("vsx: {}", is_powerpc64_feature_detected!("vsx"));
     println!("power8: {}", is_powerpc64_feature_detected!("power8"));
@@ -87,6 +91,8 @@ fn powerpc64_linux() {
 #[test]
 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
 fn x86_all() {
+    use std::arch::is_x86_feature_detected;
+
     // the below is the set of features we can test at runtime, but don't actually
     // use to gate anything and are thus not part of the X86_ALLOWED_FEATURES list
 
diff --git a/library/stdarch b/library/stdarch
-Subproject 11c98f6eb9c4ba48b2362ad4960343b312d056b
+Subproject eaee02ffdf5d820729ccdf2f95fa08b08c7d24d
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 6ccf8b1d522..4f88b5854b6 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -7,7 +7,7 @@ use std::fmt::Debug;
 use std::fs;
 use std::hash::Hash;
 use std::ops::Deref;
-use std::path::{Path, PathBuf};
+use std::path::{Component, Path, PathBuf};
 use std::process::Command;
 use std::time::{Duration, Instant};
 
@@ -105,6 +105,44 @@ struct StepDescription {
     should_run: fn(ShouldRun<'_>) -> ShouldRun<'_>,
     make_run: fn(RunConfig<'_>),
     name: &'static str,
+    kind: Kind,
+}
+
+#[derive(Clone, PartialOrd, Ord, PartialEq, Eq)]
+pub struct TaskPath {
+    pub path: PathBuf,
+    pub kind: Option<Kind>,
+}
+
+impl TaskPath {
+    pub fn parse(path: impl Into<PathBuf>) -> TaskPath {
+        let mut kind = None;
+        let mut path = path.into();
+
+        let mut components = path.components();
+        if let Some(Component::Normal(os_str)) = components.next() {
+            if let Some(str) = os_str.to_str() {
+                if let Some((found_kind, found_prefix)) = str.split_once("::") {
+                    if found_kind.is_empty() {
+                        panic!("empty kind in task path {}", path.display());
+                    }
+                    kind = Some(Kind::parse(found_kind));
+                    path = Path::new(found_prefix).join(components.as_path());
+                }
+            }
+        }
+
+        TaskPath { path, kind }
+    }
+}
+
+impl Debug for TaskPath {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        if let Some(kind) = &self.kind {
+            write!(f, "{}::", kind.as_str())?;
+        }
+        write!(f, "{}", self.path.display())
+    }
 }
 
 /// Collection of paths used to match a task rule.
@@ -115,14 +153,14 @@ pub enum PathSet {
     /// These are generally matched as a path suffix. For example, a
     /// command-line value of `libstd` will match if `src/libstd` is in the
     /// set.
-    Set(BTreeSet<PathBuf>),
+    Set(BTreeSet<TaskPath>),
     /// A "suite" of paths.
     ///
     /// These can match as a path suffix (like `Set`), or as a prefix. For
     /// example, a command-line value of `src/test/ui/abi/variadic-ffi.rs`
     /// will match `src/test/ui`. A command-line value of `ui` would also
     /// match `src/test/ui`.
-    Suite(PathBuf),
+    Suite(TaskPath),
 }
 
 impl PathSet {
@@ -130,35 +168,46 @@ impl PathSet {
         PathSet::Set(BTreeSet::new())
     }
 
-    fn one<P: Into<PathBuf>>(path: P) -> PathSet {
+    fn one<P: Into<PathBuf>>(path: P, kind: Kind) -> PathSet {
         let mut set = BTreeSet::new();
-        set.insert(path.into());
+        set.insert(TaskPath { path: path.into(), kind: Some(kind.into()) });
         PathSet::Set(set)
     }
 
-    fn has(&self, needle: &Path) -> bool {
+    fn has(&self, needle: &Path, module: Option<Kind>) -> bool {
+        let check = |p: &TaskPath| {
+            if let (Some(p_kind), Some(kind)) = (&p.kind, module) {
+                p.path.ends_with(needle) && *p_kind == kind
+            } else {
+                p.path.ends_with(needle)
+            }
+        };
+
         match self {
-            PathSet::Set(set) => set.iter().any(|p| p.ends_with(needle)),
-            PathSet::Suite(suite) => suite.ends_with(needle),
+            PathSet::Set(set) => set.iter().any(check),
+            PathSet::Suite(suite) => check(suite),
         }
     }
 
     fn path(&self, builder: &Builder<'_>) -> PathBuf {
         match self {
-            PathSet::Set(set) => set.iter().next().unwrap_or(&builder.build.src).to_path_buf(),
-            PathSet::Suite(path) => PathBuf::from(path),
+            PathSet::Set(set) => {
+                set.iter().next().map(|p| &p.path).unwrap_or(&builder.build.src).clone()
+            }
+            PathSet::Suite(path) => path.path.clone(),
         }
     }
 }
 
 impl StepDescription {
-    fn from<S: Step>() -> StepDescription {
+    fn from<S: Step>(kind: Kind) -> StepDescription {
         StepDescription {
             default: S::DEFAULT,
             only_hosts: S::ONLY_HOSTS,
             should_run: S::should_run,
             make_run: S::make_run,
             name: std::any::type_name::<S>(),
+            kind,
         }
     }
 
@@ -177,7 +226,7 @@ impl StepDescription {
     }
 
     fn is_excluded(&self, builder: &Builder<'_>, pathset: &PathSet) -> bool {
-        if builder.config.exclude.iter().any(|e| pathset.has(e)) {
+        if builder.config.exclude.iter().any(|e| pathset.has(&e.path, e.kind)) {
             eprintln!("Skipping {:?} because it is excluded", pathset);
             return true;
         }
@@ -192,8 +241,10 @@ impl StepDescription {
     }
 
     fn run(v: &[StepDescription], builder: &Builder<'_>, paths: &[PathBuf]) {
-        let should_runs =
-            v.iter().map(|desc| (desc.should_run)(ShouldRun::new(builder))).collect::<Vec<_>>();
+        let should_runs = v
+            .iter()
+            .map(|desc| (desc.should_run)(ShouldRun::new(builder, desc.kind)))
+            .collect::<Vec<_>>();
 
         // sanity checks on rules
         for (desc, should_run) in v.iter().zip(&should_runs) {
@@ -226,7 +277,7 @@ impl StepDescription {
                 if let Some(suite) = should_run.is_suite_path(path) {
                     attempted_run = true;
                     desc.maybe_run(builder, suite);
-                } else if let Some(pathset) = should_run.pathset_for_path(path) {
+                } else if let Some(pathset) = should_run.pathset_for_path(path, desc.kind) {
                     attempted_run = true;
                     desc.maybe_run(builder, pathset);
                 }
@@ -246,6 +297,8 @@ enum ReallyDefault<'a> {
 
 pub struct ShouldRun<'a> {
     pub builder: &'a Builder<'a>,
+    kind: Kind,
+
     // use a BTreeSet to maintain sort order
     paths: BTreeSet<PathSet>,
 
@@ -255,9 +308,10 @@ pub struct ShouldRun<'a> {
 }
 
 impl<'a> ShouldRun<'a> {
-    fn new(builder: &'a Builder<'_>) -> ShouldRun<'a> {
+    fn new(builder: &'a Builder<'_>, kind: Kind) -> ShouldRun<'a> {
         ShouldRun {
             builder,
+            kind,
             paths: BTreeSet::new(),
             is_really_default: ReallyDefault::Bool(true), // by default no additional conditions
         }
@@ -293,7 +347,7 @@ impl<'a> ShouldRun<'a> {
         let mut set = BTreeSet::new();
         for krate in self.builder.in_tree_crates(name, None) {
             let path = krate.local_path(self.builder);
-            set.insert(path);
+            set.insert(TaskPath { path, kind: Some(self.kind) });
         }
         self.paths.insert(PathSet::Set(set));
         self
@@ -306,7 +360,7 @@ impl<'a> ShouldRun<'a> {
     pub fn krate(mut self, name: &str) -> Self {
         for krate in self.builder.in_tree_crates(name, None) {
             let path = krate.local_path(self.builder);
-            self.paths.insert(PathSet::one(path));
+            self.paths.insert(PathSet::one(path, self.kind));
         }
         self
     }
@@ -318,19 +372,25 @@ impl<'a> ShouldRun<'a> {
 
     // multiple aliases for the same job
     pub fn paths(mut self, paths: &[&str]) -> Self {
-        self.paths.insert(PathSet::Set(paths.iter().map(PathBuf::from).collect()));
+        self.paths.insert(PathSet::Set(
+            paths
+                .iter()
+                .map(|p| TaskPath { path: p.into(), kind: Some(self.kind.into()) })
+                .collect(),
+        ));
         self
     }
 
     pub fn is_suite_path(&self, path: &Path) -> Option<&PathSet> {
         self.paths.iter().find(|pathset| match pathset {
-            PathSet::Suite(p) => path.starts_with(p),
+            PathSet::Suite(p) => path.starts_with(&p.path),
             PathSet::Set(_) => false,
         })
     }
 
     pub fn suite_path(mut self, suite: &str) -> Self {
-        self.paths.insert(PathSet::Suite(PathBuf::from(suite)));
+        self.paths
+            .insert(PathSet::Suite(TaskPath { path: suite.into(), kind: Some(self.kind.into()) }));
         self
     }
 
@@ -340,12 +400,12 @@ impl<'a> ShouldRun<'a> {
         self
     }
 
-    fn pathset_for_path(&self, path: &Path) -> Option<&PathSet> {
-        self.paths.iter().find(|pathset| pathset.has(path))
+    fn pathset_for_path(&self, path: &Path, kind: Kind) -> Option<&PathSet> {
+        self.paths.iter().find(|pathset| pathset.has(path, Some(kind)))
     }
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
 pub enum Kind {
     Build,
     Check,
@@ -359,11 +419,44 @@ pub enum Kind {
     Run,
 }
 
+impl Kind {
+    fn parse(string: &str) -> Kind {
+        match string {
+            "build" => Kind::Build,
+            "check" => Kind::Check,
+            "clippy" => Kind::Clippy,
+            "fix" => Kind::Fix,
+            "test" => Kind::Test,
+            "bench" => Kind::Bench,
+            "dist" => Kind::Dist,
+            "doc" => Kind::Doc,
+            "install" => Kind::Install,
+            "run" => Kind::Run,
+            other => panic!("unknown kind: {}", other),
+        }
+    }
+
+    fn as_str(&self) -> &'static str {
+        match self {
+            Kind::Build => "build",
+            Kind::Check => "check",
+            Kind::Clippy => "clippy",
+            Kind::Fix => "fix",
+            Kind::Test => "test",
+            Kind::Bench => "bench",
+            Kind::Dist => "dist",
+            Kind::Doc => "doc",
+            Kind::Install => "install",
+            Kind::Run => "run",
+        }
+    }
+}
+
 impl<'a> Builder<'a> {
     fn get_step_descriptions(kind: Kind) -> Vec<StepDescription> {
         macro_rules! describe {
             ($($rule:ty),+ $(,)?) => {{
-                vec![$(StepDescription::from::<$rule>()),+]
+                vec![$(StepDescription::from::<$rule>(kind)),+]
             }};
         }
         match kind {
@@ -495,7 +588,6 @@ impl<'a> Builder<'a> {
                 dist::RustcDev,
                 dist::Analysis,
                 dist::Src,
-                dist::PlainSourceTarball,
                 dist::Cargo,
                 dist::Rls,
                 dist::RustAnalyzer,
@@ -506,6 +598,11 @@ impl<'a> Builder<'a> {
                 dist::LlvmTools,
                 dist::RustDev,
                 dist::Extended,
+                // It seems that PlainSourceTarball somehow changes how some of the tools
+                // perceive their dependencies (see #93033) which would invaliate fingerprints
+                // and force us to rebuild tools after vendoring dependencies.
+                // To work around this, create the Tarball after building all the tools.
+                dist::PlainSourceTarball,
                 dist::BuildManifest,
                 dist::ReproducibleArtifacts,
             ),
@@ -540,8 +637,11 @@ impl<'a> Builder<'a> {
 
         let builder = Self::new_internal(build, kind, vec![]);
         let builder = &builder;
-        let mut should_run = ShouldRun::new(builder);
+        // The "build" kind here is just a placeholder, it will be replaced with something else in
+        // the following statement.
+        let mut should_run = ShouldRun::new(builder, Kind::Build);
         for desc in Builder::get_step_descriptions(builder.kind) {
+            should_run.kind = desc.kind;
             should_run = (desc.should_run)(should_run);
         }
         let mut help = String::from("Available paths:\n");
@@ -552,11 +652,11 @@ impl<'a> Builder<'a> {
             match pathset {
                 PathSet::Set(set) => {
                     for path in set {
-                        add_path(&path);
+                        add_path(&path.path);
                     }
                 }
                 PathSet::Suite(path) => {
-                    add_path(&path.join("..."));
+                    add_path(&path.path.join("..."));
                 }
             }
         }
@@ -988,20 +1088,11 @@ impl<'a> Builder<'a> {
             }
         };
 
-        // cfg(bootstrap) -- drop the compiler.stage == 0 branch.
-        if compiler.stage == 0 {
-            if use_new_symbol_mangling {
-                rustflags.arg("-Zsymbol-mangling-version=v0");
-            } else {
-                rustflags.arg("-Zsymbol-mangling-version=legacy");
-            }
+        if use_new_symbol_mangling {
+            rustflags.arg("-Csymbol-mangling-version=v0");
         } else {
-            if use_new_symbol_mangling {
-                rustflags.arg("-Csymbol-mangling-version=v0");
-            } else {
-                rustflags.arg("-Csymbol-mangling-version=legacy");
-                rustflags.arg("-Zunstable-options");
-            }
+            rustflags.arg("-Csymbol-mangling-version=legacy");
+            rustflags.arg("-Zunstable-options");
         }
 
         // FIXME: It might be better to use the same value for both `RUSTFLAGS` and `RUSTDOCFLAGS`,
@@ -1626,9 +1717,10 @@ impl<'a> Builder<'a> {
     pub(crate) fn ensure_if_default<T, S: Step<Output = Option<T>>>(
         &'a self,
         step: S,
+        kind: Kind,
     ) -> S::Output {
-        let desc = StepDescription::from::<S>();
-        let should_run = (desc.should_run)(ShouldRun::new(self));
+        let desc = StepDescription::from::<S>(kind);
+        let should_run = (desc.should_run)(ShouldRun::new(self, desc.kind));
 
         // Avoid running steps contained in --exclude
         for pathset in &should_run.paths {
@@ -1642,13 +1734,16 @@ impl<'a> Builder<'a> {
     }
 
     /// Checks if any of the "should_run" paths is in the `Builder` paths.
-    pub(crate) fn was_invoked_explicitly<S: Step>(&'a self) -> bool {
-        let desc = StepDescription::from::<S>();
-        let should_run = (desc.should_run)(ShouldRun::new(self));
+    pub(crate) fn was_invoked_explicitly<S: Step>(&'a self, kind: Kind) -> bool {
+        let desc = StepDescription::from::<S>(kind);
+        let should_run = (desc.should_run)(ShouldRun::new(self, desc.kind));
 
         for path in &self.paths {
-            if should_run.paths.iter().any(|s| s.has(path))
-                && !desc.is_excluded(self, &PathSet::Suite(path.clone()))
+            if should_run.paths.iter().any(|s| s.has(path, Some(desc.kind)))
+                && !desc.is_excluded(
+                    self,
+                    &PathSet::Suite(TaskPath { path: path.clone(), kind: Some(desc.kind.into()) }),
+                )
             {
                 return true;
             }
diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs
index bb3ea04d4ac..bc710344969 100644
--- a/src/bootstrap/builder/tests.rs
+++ b/src/bootstrap/builder/tests.rs
@@ -499,7 +499,7 @@ mod dist {
         let host = TargetSelection::from_user("A");
 
         builder.run_step_descriptions(
-            &[StepDescription::from::<test::Crate>()],
+            &[StepDescription::from::<test::Crate>(Kind::Test)],
             &["library/std".into()],
         );
 
@@ -520,7 +520,7 @@ mod dist {
     #[test]
     fn test_exclude() {
         let mut config = configure(&["A"], &["A"]);
-        config.exclude = vec!["src/tools/tidy".into()];
+        config.exclude = vec![TaskPath::parse("src/tools/tidy")];
         config.cmd = Subcommand::Test {
             paths: Vec::new(),
             test_args: Vec::new(),
diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs
index 5af9248583c..683cfc630e7 100644
--- a/src/bootstrap/config.rs
+++ b/src/bootstrap/config.rs
@@ -12,6 +12,7 @@ use std::fs;
 use std::path::{Path, PathBuf};
 use std::str::FromStr;
 
+use crate::builder::TaskPath;
 use crate::cache::{Interned, INTERNER};
 use crate::channel::GitInfo;
 pub use crate::flags::Subcommand;
@@ -62,7 +63,7 @@ pub struct Config {
     pub sanitizers: bool,
     pub profiler: bool,
     pub ignore_git: bool,
-    pub exclude: Vec<PathBuf>,
+    pub exclude: Vec<TaskPath>,
     pub include_default_paths: bool,
     pub rustc_error_format: Option<String>,
     pub json_output: bool,
@@ -635,7 +636,7 @@ impl Config {
         let flags = Flags::parse(&args);
 
         let mut config = Config::default_opts();
-        config.exclude = flags.exclude;
+        config.exclude = flags.exclude.into_iter().map(|path| TaskPath::parse(path)).collect();
         config.include_default_paths = flags.include_default_paths;
         config.rustc_error_format = flags.rustc_error_format;
         config.json_output = flags.json_output;
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index a46a4e63714..66b63cd1278 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -16,7 +16,7 @@ use std::process::Command;
 
 use build_helper::{output, t};
 
-use crate::builder::{Builder, RunConfig, ShouldRun, Step};
+use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
 use crate::cache::{Interned, INTERNER};
 use crate::compile;
 use crate::config::TargetSelection;
@@ -1368,7 +1368,7 @@ impl Step for Extended {
         let mut built_tools = HashSet::new();
         macro_rules! add_component {
             ($name:expr => $step:expr) => {
-                if let Some(tarball) = builder.ensure_if_default($step) {
+                if let Some(tarball) = builder.ensure_if_default($step, Kind::Dist) {
                     tarballs.push(tarball);
                     built_tools.insert($name);
                 }
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index f0f31c447bd..23b5ddcd47a 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -15,7 +15,7 @@ use std::path::{Path, PathBuf};
 use crate::Mode;
 use build_helper::{t, up_to_date};
 
-use crate::builder::{Builder, Compiler, RunConfig, ShouldRun, Step};
+use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
 use crate::cache::{Interned, INTERNER};
 use crate::compile;
 use crate::config::{Config, TargetSelection};
@@ -240,7 +240,7 @@ impl Step for TheBook {
             invoke_rustdoc(builder, compiler, target, path);
         }
 
-        if builder.was_invoked_explicitly::<Self>() {
+        if builder.was_invoked_explicitly::<Self>(Kind::Doc) {
             let out = builder.doc_out(target);
             let index = out.join("book").join("index.html");
             open(builder, &index);
@@ -400,7 +400,7 @@ impl Step for Standalone {
 
         // We open doc/index.html as the default if invoked as `x.py doc --open`
         // with no particular explicit doc requested (e.g. library/core).
-        if builder.paths.is_empty() || builder.was_invoked_explicitly::<Self>() {
+        if builder.paths.is_empty() || builder.was_invoked_explicitly::<Self>(Kind::Doc) {
             let index = out.join("index.html");
             open(builder, &index);
         }
@@ -902,7 +902,7 @@ impl Step for RustcBook {
             name: INTERNER.intern_str("rustc"),
             src: INTERNER.intern_path(out_base),
         });
-        if builder.was_invoked_explicitly::<Self>() {
+        if builder.was_invoked_explicitly::<Self>(Kind::Doc) {
             let out = builder.doc_out(self.target);
             let index = out.join("rustc").join("index.html");
             open(builder, &index);
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index cb1b0ebf8db..176c06114e0 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -1540,6 +1540,9 @@ note: if you're sure you want to do this, please open an issue as to why. In the
             }
         }
         cmd.env("RUSTC_BOOTSTRAP", "1");
+        // Override the rustc version used in symbol hashes to reduce the amount of normalization
+        // needed when diffing test output.
+        cmd.env("RUSTC_FORCE_RUSTC_VERSION", "compiletest");
         cmd.env("DOC_RUST_LANG_ORG_CHANNEL", builder.doc_rust_lang_org_channel());
         builder.add_rust_test_threads(&mut cmd);
 
diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs
index ee58bedcc87..2c78ceb1e5b 100644
--- a/src/bootstrap/util.rs
+++ b/src/bootstrap/util.rs
@@ -282,9 +282,10 @@ pub fn is_valid_test_suite_arg<'a, P: AsRef<Path>>(
     if !path.starts_with(suite_path) {
         return None;
     }
-    let exists = path.is_dir() || path.is_file();
+    let abs_path = builder.src.join(path);
+    let exists = abs_path.is_dir() || abs_path.is_file();
     if !exists {
-        if let Some(p) = path.to_str() {
+        if let Some(p) = abs_path.to_str() {
             builder.info(&format!("Warning: Skipping \"{}\": not a regular file or directory", p));
         }
         return None;
diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs
index b1ec072f3f8..28e95d81bb7 100644
--- a/src/build_helper/lib.rs
+++ b/src/build_helper/lib.rs
@@ -55,12 +55,6 @@ pub fn restore_library_path() {
     }
 }
 
-/// Run the command, printing what we are running.
-pub fn run_verbose(cmd: &mut Command) {
-    println!("running: {:?}", cmd);
-    run(cmd);
-}
-
 pub fn run(cmd: &mut Command) {
     if !try_run(cmd) {
         std::process::exit(1);
@@ -108,16 +102,6 @@ pub fn try_run_suppressed(cmd: &mut Command) -> bool {
     output.status.success()
 }
 
-pub fn gnu_target(target: &str) -> &str {
-    match target {
-        "i686-pc-windows-msvc" => "i686-pc-win32",
-        "x86_64-pc-windows-msvc" => "x86_64-pc-win32",
-        "i686-pc-windows-gnu" => "i686-w64-mingw32",
-        "x86_64-pc-windows-gnu" => "x86_64-w64-mingw32",
-        s => s,
-    }
-}
-
 pub fn make(host: &str) -> PathBuf {
     if host.contains("dragonfly")
         || host.contains("freebsd")
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 d4701a25614..c547e12f5b6 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
@@ -72,7 +72,7 @@ ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}"
 # 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.5.3 --unsafe-perm=true
+RUN npm install -g browser-ui-test@0.5.8 --unsafe-perm=true
 
 ENV RUST_CONFIGURE_ARGS \
   --build=x86_64-unknown-linux-gnu \
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 80348468976..1a1472ea861 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -452,12 +452,10 @@ jobs:
           #  macOS Builders  #
           ####################
 
-          # Only generate documentation for x86_64-apple-darwin, not other
-          # tier 2 targets produced by this builder.
           - name: dist-x86_64-apple
             env:
-              SCRIPT: ./x.py dist --exclude rust-docs --exclude extended && ./x.py dist --target=x86_64-apple-darwin rust-docs && ./x.py dist extended
-              RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
+              SCRIPT: ./x.py dist --host=x86_64-apple-darwin --target=x86_64-apple-darwin
+              RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.7
               NO_LLVM_ASSERTIONS: 1
@@ -466,6 +464,17 @@ jobs:
               DIST_REQUIRE_ALL_TOOLS: 1
             <<: *job-macos-xl
 
+          - name: dist-apple-various
+            env:
+              SCRIPT: ./x.py dist --host='' --target=aarch64-apple-ios,x86_64-apple-ios,aarch64-apple-ios-sim
+              RUST_CONFIGURE_ARGS: --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false
+              RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
+              MACOSX_DEPLOYMENT_TARGET: 10.7
+              NO_LLVM_ASSERTIONS: 1
+              NO_DEBUG_ASSERTIONS: 1
+              NO_OVERFLOW_CHECKS: 1
+            <<: *job-macos-xl
+
           - name: dist-x86_64-apple-alt
             env:
               SCRIPT: ./x.py dist
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 1ca6a7bd1d73edc4a3e6c7d6a40f5d4b66c1e51
+Subproject 18c0055b8aea49391e8f758a4400097999c9cf1
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 53f7108aca3..146408900ab 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -15,7 +15,9 @@
 - [Platform Support](platform-support.md)
     - [Template for target-specific documentation](platform-support/TEMPLATE.md)
     - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md)
+    - [armv7-unknown-linux-uclibceabihf](platform-support/armv7-unknown-linux-uclibceabihf.md)
     - [\*-kmc-solid_\*](platform-support/kmc-solid.md)
+    - [*-unknown-openbsd](platform-support/openbsd.md)
     - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md)
     - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md)
 - [Target Tier Policy](target-tier-policy.md)
diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md
index 18f1be6a1fa..941c65922d8 100644
--- a/src/doc/rustc/src/linker-plugin-lto.md
+++ b/src/doc/rustc/src/linker-plugin-lto.md
@@ -86,6 +86,48 @@ option:
 rustc -Clinker-plugin-lto="/path/to/LLVMgold.so" -L. -Copt-level=2 ./main.rs
 ```
 
+### Usage with clang-cl and x86_64-pc-windows-msvc
+
+Cross language LTO can be used with the x86_64-pc-windows-msvc target, but this requires using the
+clang-cl compiler instead of the MSVC cl.exe included with Visual Studio Build Tools, and linking
+with lld-link. Both clang-cl and lld-link can be downloaded from [LLVM's download page](https://releases.llvm.org/download.html).
+Note that most crates in the ecosystem are likely to assume you are using cl.exe if using this target
+and that some things, like for example vcpkg, [don't work very well with clang-cl](https://github.com/microsoft/vcpkg/issues/2087).
+
+You will want to make sure your rust major LLVM version matches your installed LLVM tooling version,
+otherwise it is likely you will get linker errors:
+
+```bat
+rustc -V --verbose
+clang-cl --version
+```
+
+If you are compiling any proc-macros, you will get this error:
+
+```bash
+error: Linker plugin based LTO is not supported together with `-C prefer-dynamic` when
+targeting Windows-like targets
+```
+
+This is fixed if you explicitly set the target, for example
+`cargo build --target x86_64-pc-windows-msvc`
+Without an explicit --target the flags will be passed to all compiler invocations (including build
+scripts and proc macros), see [cargo docs on rustflags](https://doc.rust-lang.org/cargo/reference/config.html#buildrustflags)
+
+If you have dependencies using the `cc` crate, you will need to set these
+environment variables:
+```bat
+set CC=clang-cl
+set CXX=clang-cl
+set CFLAGS=/clang:-flto=thin /clang:-fuse-ld=lld-link
+set CXXFLAGS=/clang:-flto=thin /clang:-fuse-ld=lld-link
+REM Needed because msvc's lib.exe crashes on LLVM LTO .obj files
+set AR=llvm-lib
+```
+
+If you are specifying lld-link as your linker by setting `linker = "lld-link.exe"` in your cargo config,
+you may run into issues with some crates that compile code with separate cargo invocations. You should be
+able to get around this problem by setting `-Clinker=lld-link` in RUSTFLAGS
 
 ## Toolchain Compatibility
 
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index f4f659ffa27..a31e08f0d12 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -208,7 +208,7 @@ target | std | host | notes
 `aarch64-unknown-uefi` | * |  | ARM64 UEFI
 `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI)
 `aarch64-unknown-netbsd` | ✓ | ✓ |
-`aarch64-unknown-openbsd` | ✓ | ✓ | ARM64 OpenBSD
+[`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD
 `aarch64-unknown-redox` | ? |  | ARM64 Redox OS
 `aarch64-uwp-windows-msvc` | ? |  |
 `aarch64-wrs-vxworks` | ? |  |
@@ -220,7 +220,7 @@ target | std | host | notes
 `armv6-unknown-netbsd-eabihf` | ? |  |
 `armv6k-nintendo-3ds` | * |  | ARMv6K Nintendo 3DS, Horizon (Requires devkitARM toolchain)
 `armv7-apple-ios` | ✓ |  | ARMv7 iOS, Cortex-a8
-`armv7-unknown-linux-uclibceabihf` | ✓ | ? | ARMv7 Linux uClibc
+[`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | ARMv7 Linux uClibc
 `armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD
 `armv7-unknown-netbsd-eabihf` | ✓ | ✓ |
 `armv7-wrs-vxworks-eabihf` | ? |  |
@@ -237,7 +237,7 @@ target | std | host | notes
 `i686-pc-windows-msvc` | ✓ |  | 32-bit Windows XP support
 `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku
 `i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2
-`i686-unknown-openbsd` | ✓ | ✓ | 32-bit OpenBSD
+[`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD
 `i686-unknown-uefi` | * |  | 32-bit UEFI
 `i686-uwp-windows-gnu` | ? |  |
 `i686-uwp-windows-msvc` | ? |  |
@@ -272,7 +272,7 @@ target | std | host | notes
 `s390x-unknown-linux-musl` |  |  | S390x Linux (kernel 2.6.32, MUSL)
 `sparc-unknown-linux-gnu` | ✓ |  | 32-bit SPARC Linux
 `sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64
-`sparc64-unknown-openbsd` | ? |  |
+[`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64
 `thumbv4t-none-eabi` | * |  | ARMv4T T32
 `thumbv7a-pc-windows-msvc` | ? |  |
 `thumbv7a-uwp-windows-msvc` | ✓ |  |
@@ -289,7 +289,7 @@ target | std | host | notes
 [`x86_64-unknown-none`](platform-support/x86_64-unknown-none.md) | * |  | Freestanding/bare-metal x86_64, softfloat
 `x86_64-unknown-none-hermitkernel` | ? |  | HermitCore kernel
 `x86_64-unknown-none-linuxkernel` | * |  | Linux kernel modules
-`x86_64-unknown-openbsd` | ✓ | ✓ | 64-bit OpenBSD
+[`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD
 `x86_64-unknown-uefi` | * |  | 64-bit UEFI
 `x86_64-uwp-windows-gnu` | ✓ |  |
 `x86_64-uwp-windows-msvc` | ✓ |  |
diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md
index b3a4275c6ee..1f029406367 100644
--- a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md
+++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md
@@ -18,7 +18,7 @@ This target is cross compiled, and requires a cross toolchain.  You can find sui
 
 Compiling rust for this target has been tested on `x86_64` linux hosts.  Other host types have not been tested, but may work, if you can find a suitable cross compilation toolchain for them.
 
-If you don't already have a suitable toolchain, download one [here](https://toolchains.bootlin.com/downloads/releases/toolchains/armv7-eabihf/tarballs/armv7-eabihf--uclibc--bleeding-edge-2020.08-1.tar.bz2), and unpack it into a directory.
+If you don't already have a suitable toolchain, download one [here](https://toolchains.bootlin.com/downloads/releases/toolchains/armv7-eabihf/tarballs/armv7-eabihf--uclibc--bleeding-edge-2021.11-1.tar.bz2), and unpack it into a directory.
 
 ### Configure rust
 
diff --git a/src/doc/rustc/src/platform-support/openbsd.md b/src/doc/rustc/src/platform-support/openbsd.md
new file mode 100644
index 00000000000..b2ac776eada
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/openbsd.md
@@ -0,0 +1,56 @@
+# \*-unknown-openbsd
+
+**Tier: 3**
+
+[OpenBSD] multi-platform 4.4BSD-based UNIX-like operating system.
+
+[OpenBSD]: https://www.openbsd.org/
+
+The target names follow this format: `$ARCH-unknown-openbsd`, where `$ARCH` specifies the target processor architecture. The following targets are currently defined:
+
+|          Target name           | C++ library | OpenBSD Platform |
+|--------------------------------|-------------|------------------|
+| `aarch64-unknown-openbsd`      | libc++      | [64-bit ARM systems](https://www.openbsd.org/arm64.html)  |
+| `i686-unknown-openbsd`         | libc++      | [Standard PC and clones based on the Intel i386 architecture and compatible processors](https://www.openbsd.org/i386.html) |
+| `sparc64-unknown-openbsd`      | estdc++     | [Sun UltraSPARC and Fujitsu SPARC64 systems](https://www.openbsd.org/sparc64.html) |
+| `x86_64-unknown-openbsd`       | libc++      | [AMD64-based systems](https://www.openbsd.org/amd64.html) |
+
+Note that all OS versions are *major* even if using X.Y notation (`6.8` and `6.9` are different major versions) and could be binary incompatibles (with breaking changes).
+
+
+## Designated Developers
+
+- [@semarie](https://github.com/semarie), `semarie@openbsd.org`
+- [lang/rust](https://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/lang/rust/Makefile?rev=HEAD&content-type=text/x-cvsweb-markup) maintainer (see MAINTAINER variable)
+
+Fallback to ports@openbsd.org, OpenBSD third parties public mailing-list (with openbsd developers readers)
+
+
+## Requirements
+
+These targets are natively compiled and could be cross-compiled.
+C compiler toolchain is required for the purpose of building Rust and functional binaries.
+
+## Building
+
+The target can be built by enabling it for a `rustc` build.
+
+```toml
+[build]
+target = ["$ARCH-unknown-openbsd"]
+
+[target.$ARCH-unknown-openbsd]
+cc = "$ARCH-openbsd-cc"
+```
+
+## Cross-compilation
+
+These targets can be cross-compiled, but LLVM might not build out-of-box.
+
+## Testing
+
+The Rust testsuite could be run natively.
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for these targets.
diff --git a/src/doc/rustdoc/src/references.md b/src/doc/rustdoc/src/references.md
index b0e2437392c..45cf4e88eef 100644
--- a/src/doc/rustdoc/src/references.md
+++ b/src/doc/rustdoc/src/references.md
@@ -16,13 +16,13 @@ If you know of other great resources, please submit a pull request!
 - [Github tagged RFCs]
 - [Github tagged issues]
 - [RFC (stalled) front page styleguide]
-- [Guide on how to write documenation for a Rust crate]
+- [Guide on how to write documentation for a Rust crate]
 
 
 [API Guidelines]: https://rust-lang.github.io/api-guidelines/documentation.html
 [Github tagged RFCs]: https://github.com/rust-lang/rfcs/issues?q=label%3AT-rustdoc
 [Github tagged issues]: https://github.com/rust-lang/rust/issues?q=is%3Aissue+is%3Aopen+label%3AT-rustdoc
-[Guide on how to write documenation for a Rust crate]: https://blog.guillaume-gomez.fr/articles/2020-03-12+Guide+on+how+to+write+documentation+for+a+Rust+crate
+[Guide on how to write documentation for a Rust crate]: https://blog.guillaume-gomez.fr/articles/2020-03-12+Guide+on+how+to+write+documentation+for+a+Rust+crate
 [Learn Rust]: https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html#making-useful-documentation-comments
 [RFC 1574: More API Documentation Conventions]: https://rust-lang.github.io/rfcs/1574-more-api-documentation-conventions.html
 [RFC 1946: Intra Rustdoc Links]: https://rust-lang.github.io/rfcs/1946-intra-rustdoc-links.html
diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
index ec97eaa8b2b..37fd67447c1 100644
--- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
+++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
@@ -15,6 +15,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 - BPF
 - SPIR-V
 - AVR
+- MSP430
 
 ## Register classes
 
@@ -39,6 +40,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | AVR          | `reg_pair`     | `r3r2` .. `r25r24`, `X`, `Z`       | `r`                  |
 | AVR          | `reg_iw`       | `r25r24`, `X`, `Z`                 | `w`                  |
 | AVR          | `reg_ptr`      | `X`, `Z`                           | `e`                  |
+| MSP430       | `reg`          | `r[0-15]`                          | `r`                  |
 
 > **Notes**:
 > - NVPTX doesn't have a fixed register set, so named registers are not supported.
@@ -67,6 +69,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | BPF          | `wreg`                          | `alu32`        | `i8` `i16` `i32`                        |
 | AVR          | `reg`, `reg_upper`              | None           | `i8`                                    |
 | AVR          | `reg_pair`, `reg_iw`, `reg_ptr` | None           | `i16`                                   |
+| MSP430       | `reg`                           | None           | `i8`, `i16`                             |
 
 ## Register aliases
 
@@ -80,13 +83,22 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | AVR          | `XL`          | `r26`     |
 | AVR          | `ZH`          | `r31`     |
 | AVR          | `ZL`          | `r30`     |
+| MSP430       | `r0`          | `pc`      |
+| MSP430       | `r1`          | `sp`      |
+| MSP430       | `r2`          | `sr`      |
+| MSP430       | `r3`          | `cg`      |
+| MSP430       | `r4`          | `fp`      |
+
+> **Notes**:
+> - TI does not mandate a frame pointer for MSP430, but toolchains are allowed
+    to use one; LLVM uses `r4`.
 
 ## Unsupported registers
 
 | Architecture | Unsupported register                    | Reason                                                                                                                                                                              |
 | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
 | All          | `sp`                                    | The stack pointer must be restored to its original value at the end of an asm code block.                                                                                           |
-| All          | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR) | The frame pointer cannot be used as an input or output.                                                                                                                             |
+| All          | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430) | The frame pointer cannot be used as an input or output.                                                                                                                             |
 | All          | `r19` (Hexagon)                         | This is used internally by LLVM as a "base pointer" for functions with complex stack frames.                                                                                        |
 | MIPS         | `$0` or `$zero`                         | This is a constant zero register which can't be modified.                                                                                                                           |
 | MIPS         | `$1` or `$at`                           | Reserved for assembler.                                                                                                                                                             |
@@ -95,6 +107,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | MIPS         | `$ra`                                   | Return address cannot be used as inputs or outputs.                                                                                                                                 |
 | Hexagon      | `lr`                                    | This is the link register which cannot be used as an input or output.                                                                                                               |
 | AVR          | `r0`, `r1`, `r1r0`                      | Due to an issue in LLVM, the `r0` and `r1` registers cannot be used as inputs or outputs.  If modified, they must be restored to their original values before the end of the block. |
+|MSP430        | `r0`, `r2`, `r3`                        | These are the program counter, status register, and constant generator respectively. Neither the status register nor constant generator can be written to.                          |
 
 ## Template modifiers
 
@@ -115,3 +128,5 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 These flags registers must be restored upon exiting the asm block if the `preserves_flags` option is set:
 - AVR
   - The status register `SREG`.
+- MSP430
+  - The status register `r2`.
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index 67d167e86df..45285c1f442 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -11,7 +11,7 @@ arrayvec = { version = "0.7", default-features = false }
 askama = { version = "0.11", default-features = false, features = ["config"] }
 atty = "0.2"
 pulldown-cmark = { version = "0.9", default-features = false }
-minifier = "0.0.41"
+minifier = "0.0.42"
 rayon = "1.5.1"
 serde = { version = "1.0", features = ["derive"] }
 serde_json = "1.0"
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index eafc74b9945..75ee663b926 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -101,6 +101,27 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
 
                     cx.generated_synthetics.insert((ty, trait_def_id));
 
+                    let hir_imp = impl_def_id.as_local()
+                        .map(|local| cx.tcx.hir().expect_item(local))
+                        .and_then(|item| if let hir::ItemKind::Impl(i) = &item.kind {
+                            Some(i)
+                        } else {
+                            None
+                        });
+
+                    let items = match hir_imp {
+                        Some(imp) => imp
+                            .items
+                            .iter()
+                            .map(|ii| cx.tcx.hir().impl_item(ii.id).clean(cx))
+                            .collect::<Vec<_>>(),
+                        None => cx.tcx
+                            .associated_items(impl_def_id)
+                            .in_definition_order()
+                            .map(|x| x.clean(cx))
+                            .collect::<Vec<_>>(),
+                    };
+
                     impls.push(Item {
                         name: None,
                         attrs: Default::default(),
@@ -117,12 +138,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                             // the post-inference `trait_ref`, as it's more accurate.
                             trait_: Some(trait_ref.clean(cx)),
                             for_: ty.clean(cx),
-                            items: cx
-                                .tcx
-                                .associated_items(impl_def_id)
-                                .in_definition_order()
-                                .map(|x| x.clean(cx))
-                                .collect::<Vec<_>>(),
+                            items,
                             polarity: ty::ImplPolarity::Positive,
                             kind: ImplKind::Blanket(box trait_ref.self_ty().clean(cx)),
                         }),
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index e759baa0458..7d209accec9 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -5,6 +5,7 @@ mod auto_trait;
 mod blanket_impl;
 crate mod cfg;
 crate mod inline;
+mod render_macro_matchers;
 mod simplify;
 crate mod types;
 crate mod utils;
@@ -387,7 +388,7 @@ impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> {
         let trait_ = lifted.trait_ref(cx.tcx).clean(cx);
         let self_type = self.self_ty().clean(cx);
         Type::QPath {
-            name: cx.tcx.associated_item(self.item_def_id).ident.name,
+            name: cx.tcx.associated_item(self.item_def_id).name,
             self_def_id: self_type.def_id(&cx.cache),
             self_type: box self_type,
             trait_,
@@ -1131,7 +1132,7 @@ impl Clean<Item> for ty::AssocItem {
                 }
             }
             ty::AssocKind::Type => {
-                let my_name = self.ident.name;
+                let my_name = self.name;
 
                 if let ty::TraitContainer(_) = self.container {
                     let bounds = tcx.explicit_item_bounds(self.def_id);
@@ -1197,7 +1198,7 @@ impl Clean<Item> for ty::AssocItem {
             }
         };
 
-        Item::from_def_id_and_parts(self.def_id, Some(self.ident.name), kind, cx)
+        Item::from_def_id_and_parts(self.def_id, Some(self.name), kind, cx)
     }
 }
 
@@ -1521,7 +1522,7 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                 let mut bindings = vec![];
                 for pb in obj.projection_bounds() {
                     bindings.push(TypeBinding {
-                        name: cx.tcx.associated_item(pb.item_def_id()).ident.name,
+                        name: cx.tcx.associated_item(pb.item_def_id()).name,
                         kind: TypeBindingKind::Equality {
                             term: pb.skip_binder().term.clean(cx).into(),
                         },
@@ -1592,7 +1593,6 @@ impl<'tcx> Clean<Type> for Ty<'tcx> {
                                             name: cx
                                                 .tcx
                                                 .associated_item(proj.projection_ty.item_def_id)
-                                                .ident
                                                 .name,
                                             kind: TypeBindingKind::Equality {
                                                 term: proj.term.clean(cx),
diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs
new file mode 100644
index 00000000000..dff370ab750
--- /dev/null
+++ b/src/librustdoc/clean/render_macro_matchers.rs
@@ -0,0 +1,240 @@
+use rustc_ast::token::{self, BinOpToken, DelimToken};
+use rustc_ast::tokenstream::{TokenStream, TokenTree};
+use rustc_ast_pretty::pprust::state::State as Printer;
+use rustc_ast_pretty::pprust::PrintState;
+use rustc_middle::ty::TyCtxt;
+use rustc_session::parse::ParseSess;
+use rustc_span::source_map::FilePathMapping;
+use rustc_span::symbol::{kw, Ident, Symbol};
+use rustc_span::Span;
+
+/// Render a macro matcher in a format suitable for displaying to the user
+/// as part of an item declaration.
+pub(super) fn render_macro_matcher(tcx: TyCtxt<'_>, matcher: &TokenTree) -> String {
+    if let Some(snippet) = snippet_equal_to_token(tcx, matcher) {
+        // If the original source code is known, we display the matcher exactly
+        // as present in the source code.
+        return snippet;
+    }
+
+    // If the matcher is macro-generated or some other reason the source code
+    // snippet is not available, we attempt to nicely render the token tree.
+    let mut printer = Printer::new();
+
+    // If the inner ibox fits on one line, we get:
+    //
+    //     macro_rules! macroname {
+    //         (the matcher) => {...};
+    //     }
+    //
+    // If the inner ibox gets wrapped, the cbox will break and get indented:
+    //
+    //     macro_rules! macroname {
+    //         (
+    //             the matcher ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    //             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~!
+    //         ) => {...};
+    //     }
+    printer.cbox(8);
+    printer.word("(");
+    printer.zerobreak();
+    printer.ibox(0);
+    match matcher {
+        TokenTree::Delimited(_span, _delim, tts) => print_tts(&mut printer, tts),
+        // Matcher which is not a Delimited is unexpected and should've failed
+        // to compile, but we render whatever it is wrapped in parens.
+        TokenTree::Token(_) => print_tt(&mut printer, matcher),
+    }
+    printer.end();
+    printer.break_offset_if_not_bol(0, -4);
+    printer.word(")");
+    printer.end();
+    printer.s.eof()
+}
+
+/// Find the source snippet for this token's Span, reparse it, and return the
+/// snippet if the reparsed TokenTree matches the argument TokenTree.
+fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option<String> {
+    // Find what rustc thinks is the source snippet.
+    // This may not actually be anything meaningful if this matcher was itself
+    // generated by a macro.
+    let source_map = tcx.sess.source_map();
+    let span = matcher.span();
+    let snippet = source_map.span_to_snippet(span).ok()?;
+
+    // Create a Parser.
+    let sess = ParseSess::new(FilePathMapping::empty());
+    let file_name = source_map.span_to_filename(span);
+    let mut parser =
+        match rustc_parse::maybe_new_parser_from_source_str(&sess, file_name, snippet.clone()) {
+            Ok(parser) => parser,
+            Err(diagnostics) => {
+                for mut diagnostic in diagnostics {
+                    diagnostic.cancel();
+                }
+                return None;
+            }
+        };
+
+    // Reparse a single token tree.
+    let mut reparsed_trees = match parser.parse_all_token_trees() {
+        Ok(reparsed_trees) => reparsed_trees,
+        Err(mut diagnostic) => {
+            diagnostic.cancel();
+            return None;
+        }
+    };
+    if reparsed_trees.len() != 1 {
+        return None;
+    }
+    let reparsed_tree = reparsed_trees.pop().unwrap();
+
+    // Compare against the original tree.
+    if reparsed_tree.eq_unspanned(matcher) { Some(snippet) } else { None }
+}
+
+fn print_tt(printer: &mut Printer<'_>, tt: &TokenTree) {
+    match tt {
+        TokenTree::Token(token) => {
+            let token_str = printer.token_to_string(token);
+            printer.word(token_str);
+            if let token::DocComment(..) = token.kind {
+                printer.hardbreak()
+            }
+        }
+        TokenTree::Delimited(_span, delim, tts) => {
+            let open_delim = printer.token_kind_to_string(&token::OpenDelim(*delim));
+            printer.word(open_delim);
+            if !tts.is_empty() {
+                if *delim == DelimToken::Brace {
+                    printer.space();
+                }
+                print_tts(printer, tts);
+                if *delim == DelimToken::Brace {
+                    printer.space();
+                }
+            }
+            let close_delim = printer.token_kind_to_string(&token::CloseDelim(*delim));
+            printer.word(close_delim);
+        }
+    }
+}
+
+fn print_tts(printer: &mut Printer<'_>, tts: &TokenStream) {
+    #[derive(Copy, Clone, PartialEq)]
+    enum State {
+        Start,
+        Dollar,
+        DollarIdent,
+        DollarIdentColon,
+        DollarParen,
+        DollarParenSep,
+        Pound,
+        PoundBang,
+        Ident,
+        Other,
+    }
+
+    use State::*;
+
+    let mut state = Start;
+    for tt in tts.trees() {
+        let (needs_space, next_state) = match &tt {
+            TokenTree::Token(tt) => match (state, &tt.kind) {
+                (Dollar, token::Ident(..)) => (false, DollarIdent),
+                (DollarIdent, token::Colon) => (false, DollarIdentColon),
+                (DollarIdentColon, token::Ident(..)) => (false, Other),
+                (
+                    DollarParen,
+                    token::BinOp(BinOpToken::Plus | BinOpToken::Star) | token::Question,
+                ) => (false, Other),
+                (DollarParen, _) => (false, DollarParenSep),
+                (DollarParenSep, token::BinOp(BinOpToken::Plus | BinOpToken::Star)) => {
+                    (false, Other)
+                }
+                (Pound, token::Not) => (false, PoundBang),
+                (_, token::Ident(symbol, /* is_raw */ false))
+                    if !usually_needs_space_between_keyword_and_open_delim(*symbol, tt.span) =>
+                {
+                    (true, Ident)
+                }
+                (_, token::Comma | token::Semi) => (false, Other),
+                (_, token::Dollar) => (true, Dollar),
+                (_, token::Pound) => (true, Pound),
+                (_, _) => (true, Other),
+            },
+            TokenTree::Delimited(_, delim, _) => match (state, delim) {
+                (Dollar, DelimToken::Paren) => (false, DollarParen),
+                (Pound | PoundBang, DelimToken::Bracket) => (false, Other),
+                (Ident, DelimToken::Paren | DelimToken::Bracket) => (false, Other),
+                (_, _) => (true, Other),
+            },
+        };
+        if state != Start && needs_space {
+            printer.space();
+        }
+        print_tt(printer, &tt);
+        state = next_state;
+    }
+}
+
+fn usually_needs_space_between_keyword_and_open_delim(symbol: Symbol, span: Span) -> bool {
+    let ident = Ident { name: symbol, span };
+    let is_keyword = ident.is_used_keyword() || ident.is_unused_keyword();
+    if !is_keyword {
+        // An identifier that is not a keyword usually does not need a space
+        // before an open delim. For example: `f(0)` or `f[0]`.
+        return false;
+    }
+
+    match symbol {
+        // No space after keywords that are syntactically an expression. For
+        // example: a tuple struct created with `let _ = Self(0, 0)`, or if
+        // someone has `impl Index<MyStruct> for bool` then `true[MyStruct]`.
+        kw::False | kw::SelfLower | kw::SelfUpper | kw::True => false,
+
+        // No space, as in `let _: fn();`
+        kw::Fn => false,
+
+        // No space, as in `pub(crate) type T;`
+        kw::Pub => false,
+
+        // No space for keywords that can end an expression, as in `fut.await()`
+        // where fut's Output type is `fn()`.
+        kw::Await => false,
+
+        // Otherwise space after keyword. Some examples:
+        //
+        // `expr as [T; 2]`
+        //         ^
+        // `box (tuple,)`
+        //     ^
+        // `break (tuple,)`
+        //       ^
+        // `type T = dyn (Fn() -> dyn Trait) + Send;`
+        //              ^
+        // `for (tuple,) in iter {}`
+        //     ^
+        // `if (tuple,) == v {}`
+        //    ^
+        // `impl [T] {}`
+        //      ^
+        // `for x in [..] {}`
+        //          ^
+        // `let () = unit;`
+        //     ^
+        // `match [x, y] {...}`
+        //       ^
+        // `&mut (x as T)`
+        //      ^
+        // `return [];`
+        //        ^
+        // `fn f<T>() where (): Into<T>`
+        //                 ^
+        // `while (a + b).what() {}`
+        //       ^
+        // `yield [];`
+        //       ^
+        _ => true,
+    }
+}
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 993503005d7..02633698273 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -5,7 +5,7 @@ use std::lazy::SyncOnceCell as OnceCell;
 use std::path::PathBuf;
 use std::rc::Rc;
 use std::sync::Arc;
-use std::{slice, vec};
+use std::vec;
 
 use arrayvec::ArrayVec;
 
@@ -338,6 +338,7 @@ impl ExternalCrate {
 }
 
 /// Indicates where an external crate can be found.
+#[derive(Debug)]
 crate enum ExternalLocation {
     /// Remote URL root of the external crate
     Remote(String),
@@ -429,7 +430,7 @@ impl Item {
 
     /// Convenience wrapper around [`Self::from_def_id_and_parts`] which converts
     /// `hir_id` to a [`DefId`]
-    pub fn from_hir_id_and_parts(
+    crate fn from_hir_id_and_parts(
         hir_id: hir::HirId,
         name: Option<Symbol>,
         kind: ItemKind,
@@ -438,7 +439,7 @@ impl Item {
         Item::from_def_id_and_parts(cx.tcx.hir().local_def_id(hir_id).to_def_id(), name, kind, cx)
     }
 
-    pub fn from_def_id_and_parts(
+    crate fn from_def_id_and_parts(
         def_id: DefId,
         name: Option<Symbol>,
         kind: ItemKind,
@@ -456,7 +457,7 @@ impl Item {
         )
     }
 
-    pub fn from_def_id_and_attrs_and_parts(
+    crate fn from_def_id_and_attrs_and_parts(
         def_id: DefId,
         name: Option<Symbol>,
         kind: ItemKind,
@@ -733,43 +734,12 @@ crate struct Module {
     crate span: Span,
 }
 
-crate struct ListAttributesIter<'a> {
-    attrs: slice::Iter<'a, ast::Attribute>,
-    current_list: vec::IntoIter<ast::NestedMetaItem>,
-    name: Symbol,
-}
-
-impl<'a> Iterator for ListAttributesIter<'a> {
-    type Item = ast::NestedMetaItem;
-
-    fn next(&mut self) -> Option<Self::Item> {
-        if let Some(nested) = self.current_list.next() {
-            return Some(nested);
-        }
-
-        for attr in &mut self.attrs {
-            if let Some(list) = attr.meta_item_list() {
-                if attr.has_name(self.name) {
-                    self.current_list = list.into_iter();
-                    if let Some(nested) = self.current_list.next() {
-                        return Some(nested);
-                    }
-                }
-            }
-        }
-
-        None
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let lower = self.current_list.len();
-        (lower, None)
-    }
-}
-
 crate trait AttributesExt {
-    /// Finds an attribute as List and returns the list of attributes nested inside.
-    fn lists(&self, name: Symbol) -> ListAttributesIter<'_>;
+    type AttributeIterator<'a>: Iterator<Item = ast::NestedMetaItem>
+    where
+        Self: 'a;
+
+    fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a>;
 
     fn span(&self) -> Option<rustc_span::Span>;
 
@@ -781,8 +751,13 @@ crate trait AttributesExt {
 }
 
 impl AttributesExt for [ast::Attribute] {
-    fn lists(&self, name: Symbol) -> ListAttributesIter<'_> {
-        ListAttributesIter { attrs: self.iter(), current_list: Vec::new().into_iter(), name }
+    type AttributeIterator<'a> = impl Iterator<Item = ast::NestedMetaItem> + 'a;
+
+    fn lists<'a>(&'a self, name: Symbol) -> Self::AttributeIterator<'a> {
+        self.iter()
+            .filter(move |attr| attr.has_name(name))
+            .filter_map(ast::Attribute::meta_item_list)
+            .flatten()
     }
 
     /// Return the span of the first doc-comment, if it exists.
@@ -902,12 +877,9 @@ crate trait NestedAttributesExt {
     fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem>;
 }
 
-impl<I> NestedAttributesExt for I
-where
-    I: IntoIterator<Item = ast::NestedMetaItem>,
-{
-    fn get_word_attr(self, word: Symbol) -> Option<ast::NestedMetaItem> {
-        self.into_iter().find(|attr| attr.is_word() && attr.has_name(word))
+impl<I: Iterator<Item = ast::NestedMetaItem>> NestedAttributesExt for I {
+    fn get_word_attr(mut self, word: Symbol) -> Option<ast::NestedMetaItem> {
+        self.find(|attr| attr.is_word() && attr.has_name(word))
     }
 }
 
@@ -984,26 +956,26 @@ crate fn collapse_doc_fragments(doc_strings: &[DocFragment]) -> String {
 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
 crate struct ItemLink {
     /// The original link written in the markdown
-    pub(crate) link: String,
+    crate link: String,
     /// The link text displayed in the HTML.
     ///
     /// This may not be the same as `link` if there was a disambiguator
     /// in an intra-doc link (e.g. \[`fn@f`\])
-    pub(crate) link_text: String,
-    pub(crate) did: DefId,
+    crate link_text: String,
+    crate did: DefId,
     /// The url fragment to append to the link
-    pub(crate) fragment: Option<UrlFragment>,
+    crate fragment: Option<UrlFragment>,
 }
 
 pub struct RenderedLink {
     /// The text the link was original written as.
     ///
     /// This could potentially include disambiguators and backticks.
-    pub(crate) original_text: String,
+    crate original_text: String,
     /// The text to display in the HTML
-    pub(crate) new_text: String,
+    crate new_text: String,
     /// The URL to put in the `href`
-    pub(crate) href: String,
+    crate href: String,
 }
 
 /// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`,
@@ -1015,7 +987,7 @@ crate struct Attributes {
 }
 
 impl Attributes {
-    crate fn lists(&self, name: Symbol) -> ListAttributesIter<'_> {
+    crate fn lists(&self, name: Symbol) -> impl Iterator<Item = ast::NestedMetaItem> + '_ {
         self.other_attrs.lists(name)
     }
 
@@ -1568,23 +1540,10 @@ impl Type {
 
     /// Use this method to get the [DefId] of a [clean] AST node, including [PrimitiveType]s.
     ///
-    /// See [`Self::def_id_no_primitives`] for more.
-    ///
     /// [clean]: crate::clean
     crate fn def_id(&self, cache: &Cache) -> Option<DefId> {
         self.inner_def_id(Some(cache))
     }
-
-    /// Use this method to get the [`DefId`] of a [`clean`] AST node.
-    /// This will return [`None`] when called on a primitive [`clean::Type`].
-    /// Use [`Self::def_id`] if you want to include primitives.
-    ///
-    /// [`clean`]: crate::clean
-    /// [`clean::Type`]: crate::clean::Type
-    // FIXME: get rid of this function and always use `def_id`
-    crate fn def_id_no_primitives(&self) -> Option<DefId> {
-        self.inner_def_id(None)
-    }
 }
 
 /// A primitive (aka, builtin) type.
@@ -2223,7 +2182,7 @@ impl Impl {
         self.trait_
             .as_ref()
             .map(|t| t.def_id())
-            .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.ident.name).collect())
+            .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name).collect())
             .unwrap_or_default()
     }
 }
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 38da9a4635d..dabf1e878c9 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -1,5 +1,6 @@
 use crate::clean::auto_trait::AutoTraitFinder;
 use crate::clean::blanket_impl::BlanketImplFinder;
+use crate::clean::render_macro_matchers::render_macro_matcher;
 use crate::clean::{
     inline, Clean, Crate, ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item,
     ItemKind, Lifetime, Path, PathSegment, Primitive, PrimitiveType, Type, TypeBinding, Visibility,
@@ -17,8 +18,6 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
 use rustc_middle::ty::{self, DefIdTree, TyCtxt};
-use rustc_session::parse::ParseSess;
-use rustc_span::source_map::FilePathMapping;
 use rustc_span::symbol::{kw, sym, Symbol};
 use std::fmt::Write as _;
 use std::mem;
@@ -500,57 +499,6 @@ pub(super) fn render_macro_arms<'a>(
     out
 }
 
-/// Render a macro matcher in a format suitable for displaying to the user
-/// as part of an item declaration.
-pub(super) fn render_macro_matcher(tcx: TyCtxt<'_>, matcher: &TokenTree) -> String {
-    if let Some(snippet) = snippet_equal_to_token(tcx, matcher) {
-        snippet
-    } else {
-        rustc_ast_pretty::pprust::tt_to_string(matcher)
-    }
-}
-
-/// Find the source snippet for this token's Span, reparse it, and return the
-/// snippet if the reparsed TokenTree matches the argument TokenTree.
-fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option<String> {
-    // Find what rustc thinks is the source snippet.
-    // This may not actually be anything meaningful if this matcher was itself
-    // generated by a macro.
-    let source_map = tcx.sess.source_map();
-    let span = matcher.span();
-    let snippet = source_map.span_to_snippet(span).ok()?;
-
-    // Create a Parser.
-    let sess = ParseSess::new(FilePathMapping::empty());
-    let file_name = source_map.span_to_filename(span);
-    let mut parser =
-        match rustc_parse::maybe_new_parser_from_source_str(&sess, file_name, snippet.clone()) {
-            Ok(parser) => parser,
-            Err(diagnostics) => {
-                for mut diagnostic in diagnostics {
-                    diagnostic.cancel();
-                }
-                return None;
-            }
-        };
-
-    // Reparse a single token tree.
-    let mut reparsed_trees = match parser.parse_all_token_trees() {
-        Ok(reparsed_trees) => reparsed_trees,
-        Err(mut diagnostic) => {
-            diagnostic.cancel();
-            return None;
-        }
-    };
-    if reparsed_trees.len() != 1 {
-        return None;
-    }
-    let reparsed_tree = reparsed_trees.pop().unwrap();
-
-    // Compare against the original tree.
-    if reparsed_tree.eq_unspanned(matcher) { Some(snippet) } else { None }
-}
-
 pub(super) fn display_macro_source(
     cx: &mut DocContext<'_>,
     name: Symbol,
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 3b926e44403..1f14a333c00 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -4,9 +4,9 @@ use rustc_errors::emitter::{Emitter, EmitterWriter};
 use rustc_errors::json::JsonEmitter;
 use rustc_feature::UnstableFeatures;
 use rustc_hir::def::Res;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{HirId, Path};
+use rustc_hir::{HirId, Path, TraitCandidate};
 use rustc_interface::interface;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::privacy::AccessLevels;
@@ -33,8 +33,11 @@ use crate::passes::{self, Condition::*};
 crate use rustc_session::config::{DebuggingOptions, Input, Options};
 
 crate struct ResolverCaches {
-    pub all_traits: Option<Vec<DefId>>,
-    pub all_trait_impls: Option<Vec<DefId>>,
+    /// Traits in scope for a given module.
+    /// See `collect_intra_doc_links::traits_implemented_by` for more details.
+    crate traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
+    crate all_traits: Option<Vec<DefId>>,
+    crate all_trait_impls: Option<Vec<DefId>>,
 }
 
 crate struct DocContext<'tcx> {
@@ -67,11 +70,6 @@ crate struct DocContext<'tcx> {
     crate auto_traits: Vec<DefId>,
     /// The options given to rustdoc that could be relevant to a pass.
     crate render_options: RenderOptions,
-    /// The traits in scope for a given module.
-    ///
-    /// See `collect_intra_doc_links::traits_implemented_by` for more details.
-    /// `map<module, set<trait>>`
-    crate module_trait_cache: FxHashMap<DefId, FxHashSet<DefId>>,
     /// This same cache is used throughout rustdoc, including in [`crate::html::render`].
     crate cache: Cache,
     /// Used by [`clean::inline`] to tell if an item has already been inlined.
@@ -350,7 +348,6 @@ crate fn run_global_ctxt(
         impl_trait_bounds: Default::default(),
         generated_synthetics: Default::default(),
         auto_traits,
-        module_trait_cache: FxHashMap::default(),
         cache: Cache::new(access_levels, render_options.document_private),
         inlined: FxHashSet::default(),
         output_format,
diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs
index a8fef4a3178..53159709586 100644
--- a/src/librustdoc/formats/cache.rs
+++ b/src/librustdoc/formats/cache.rs
@@ -303,7 +303,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> {
                             desc,
                             parent,
                             parent_idx: None,
-                            search_type: get_function_type_for_search(&item, self.tcx),
+                            search_type: get_function_type_for_search(&item, self.tcx, self.cache),
                             aliases: item.attrs.get_doc_aliases(),
                         });
                     }
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 8badce8226f..cc12b7ba05b 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -175,14 +175,14 @@ crate struct StylePath {
 }
 
 impl StylePath {
-    pub fn basename(&self) -> Result<String, Error> {
+    crate fn basename(&self) -> Result<String, Error> {
         Ok(try_none!(try_none!(self.path.file_stem(), &self.path).to_str(), &self.path).to_string())
     }
 }
 
 fn write_srclink(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer) {
     if let Some(l) = cx.src_href(item) {
-        write!(buf, "<a class=\"srclink\" href=\"{}\" title=\"goto source code\">source</a>", l)
+        write!(buf, "<a class=\"srclink\" href=\"{}\">source</a>", l)
     }
 }
 
@@ -376,25 +376,21 @@ impl Setting {
                 description,
             ),
             Setting::Select { js_data_name, description, default_value, ref options } => format!(
-                "<div class=\"setting-line\">\
-                     <div>{}</div>\
-                     <label class=\"select-wrapper\">\
-                         <select id=\"{}\" autocomplete=\"off\">{}</select>\
-                         <img src=\"{}down-arrow{}.svg\" alt=\"Select item\">\
-                     </label>\
-                 </div>",
-                description,
+                "<div class=\"setting-line\"><div class=\"radio-line\" id=\"{}\"><span class=\"setting-name\">{}</span>{}</div></div>",
                 js_data_name,
+                description,
                 options
                     .iter()
                     .map(|opt| format!(
-                        "<option value=\"{name}\" {}>{name}</option>",
-                        if opt == default_value { "selected" } else { "" },
+                        "<label for=\"{js_data_name}-{name}\" class=\"choice\">
+                           <input type=\"radio\" name=\"{js_data_name}\" id=\"{js_data_name}-{name}\" value=\"{name}\" {checked}>\
+                           {name}\
+                         </label>",
+                        js_data_name = js_data_name,
                         name = opt,
+                        checked = if opt == default_value { "checked" } else { "" },
                     ))
                     .collect::<String>(),
-                root_path,
-                suffix,
             ),
         }
     }
@@ -418,31 +414,25 @@ impl<T: Into<Setting>> From<(&'static str, Vec<T>)> for Setting {
 fn settings(root_path: &str, suffix: &str, theme_names: Vec<String>) -> Result<String, Error> {
     // (id, explanation, default value)
     let settings: &[Setting] = &[
-        (
-            "Theme preferences",
-            vec![
-                Setting::from(("use-system-theme", "Use system theme", true)),
-                Setting::Select {
-                    js_data_name: "theme",
-                    description: "Theme",
-                    default_value: "light",
-                    options: theme_names.clone(),
-                },
-                Setting::Select {
-                    js_data_name: "preferred-dark-theme",
-                    description: "Preferred dark theme",
-                    default_value: "dark",
-                    options: theme_names.clone(),
-                },
-                Setting::Select {
-                    js_data_name: "preferred-light-theme",
-                    description: "Preferred light theme",
-                    default_value: "light",
-                    options: theme_names,
-                },
-            ],
-        )
-            .into(),
+        Setting::from(("use-system-theme", "Use system theme", true)),
+        Setting::Select {
+            js_data_name: "theme",
+            description: "Theme",
+            default_value: "light",
+            options: theme_names.clone(),
+        },
+        Setting::Select {
+            js_data_name: "preferred-light-theme",
+            description: "Preferred light theme",
+            default_value: "light",
+            options: theme_names.clone(),
+        },
+        Setting::Select {
+            js_data_name: "preferred-dark-theme",
+            description: "Preferred dark theme",
+            default_value: "dark",
+            options: theme_names,
+        },
         ("auto-hide-large-items", "Auto-hide item contents for large items.", true).into(),
         ("auto-hide-method-docs", "Auto-hide item methods' documentation", false).into(),
         ("auto-hide-trait-implementations", "Auto-hide trait implementation documentation", false)
@@ -454,9 +444,14 @@ fn settings(root_path: &str, suffix: &str, theme_names: Vec<String>) -> Result<S
     ];
 
     Ok(format!(
-        "<h1 class=\"fqn\">\
-            <span class=\"in-band\">Rustdoc settings</span>\
-        </h1>\
+        "<div class=\"main-heading\">
+            <h1 class=\"fqn\">\
+                <span class=\"in-band\">Rustdoc settings</span>\
+            </h1>\
+            <span class=\"out-of-band\">\
+            <a id=\"back\" href=\"javascript:void(0)\">Back</a>\
+            </span>\
+        </div>\
         <div class=\"settings\">{}</div>\
         <link rel=\"stylesheet\" href=\"{root_path}settings{suffix}.css\">\
         <script src=\"{root_path}settings{suffix}.js\"></script>",
@@ -1681,11 +1676,12 @@ fn render_rightside(
         containing_item.stable_since(tcx),
         const_stable_since,
     );
-    if has_stability {
+    let mut tmp_buf = Buffer::empty_from(w);
+    write_srclink(cx, item, &mut tmp_buf);
+    if has_stability && !tmp_buf.is_empty() {
         w.write_str(" · ");
     }
-
-    write_srclink(cx, item, w);
+    w.push_buffer(tmp_buf);
     w.write_str("</div>");
 }
 
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index 87138b9571c..0ee67467c38 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -3,7 +3,7 @@ use std::collections::BTreeMap;
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::ty::TyCtxt;
-use rustc_span::symbol::Symbol;
+use rustc_span::symbol::{kw, Symbol};
 use serde::ser::{Serialize, SerializeStruct, Serializer};
 
 use crate::clean;
@@ -33,7 +33,7 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
                 desc,
                 parent: Some(did),
                 parent_idx: None,
-                search_type: get_function_type_for_search(item, tcx),
+                search_type: get_function_type_for_search(item, tcx, &cache),
                 aliases: item.attrs.get_doc_aliases(),
             });
         }
@@ -188,11 +188,12 @@ crate fn build_index<'tcx>(krate: &clean::Crate, cache: &mut Cache, tcx: TyCtxt<
 crate fn get_function_type_for_search<'tcx>(
     item: &clean::Item,
     tcx: TyCtxt<'tcx>,
+    cache: &Cache,
 ) -> Option<IndexItemFunctionType> {
     let (mut inputs, mut output) = match *item.kind {
-        clean::FunctionItem(ref f) => get_fn_inputs_and_outputs(f, tcx),
-        clean::MethodItem(ref m, _) => get_fn_inputs_and_outputs(m, tcx),
-        clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, tcx),
+        clean::FunctionItem(ref f) => get_fn_inputs_and_outputs(f, tcx, cache),
+        clean::MethodItem(ref m, _) => get_fn_inputs_and_outputs(m, tcx, cache),
+        clean::TyMethodItem(ref m) => get_fn_inputs_and_outputs(m, tcx, cache),
         _ => return None,
     };
 
@@ -219,7 +220,8 @@ fn get_index_type_name(clean_type: &clean::Type) -> Option<Symbol> {
             let path = &bounds[0].trait_;
             Some(path.segments.last().unwrap().name)
         }
-        clean::Generic(s) => Some(s),
+        // We return an empty name because we don't care about the generic name itself.
+        clean::Generic(_) => Some(kw::Empty),
         clean::Primitive(ref p) => Some(p.as_sym()),
         clean::BorrowedRef { ref type_, .. } => get_index_type_name(type_),
         clean::BareFunction(_)
@@ -240,24 +242,27 @@ fn get_index_type_name(clean_type: &clean::Type) -> Option<Symbol> {
 ///
 /// Important note: It goes through generics recursively. So if you have
 /// `T: Option<Result<(), ()>>`, it'll go into `Option` and then into `Result`.
-#[instrument(level = "trace", skip(tcx, res))]
+#[instrument(level = "trace", skip(tcx, res, cache))]
 fn add_generics_and_bounds_as_types<'tcx>(
     generics: &Generics,
     arg: &Type,
     tcx: TyCtxt<'tcx>,
     recurse: usize,
     res: &mut Vec<TypeWithKind>,
+    cache: &Cache,
 ) {
     fn insert_ty(
         res: &mut Vec<TypeWithKind>,
         tcx: TyCtxt<'_>,
         ty: Type,
         mut generics: Vec<TypeWithKind>,
+        cache: &Cache,
     ) {
         let is_full_generic = ty.is_full_generic();
+        let generics_empty = generics.is_empty();
 
         if is_full_generic {
-            if generics.is_empty() {
+            if generics_empty {
                 // This is a type parameter with no trait bounds (for example: `T` in
                 // `fn f<T>(p: T)`, so not useful for the rustdoc search because we would end up
                 // with an empty type with an empty name. Let's just discard it.
@@ -304,14 +309,14 @@ fn add_generics_and_bounds_as_types<'tcx>(
             }
         }
         let mut index_ty = get_index_type(&ty, generics);
-        if index_ty.name.as_ref().map(|s| s.is_empty()).unwrap_or(true) {
+        if index_ty.name.as_ref().map(|s| s.is_empty() && generics_empty).unwrap_or(true) {
             return;
         }
         if is_full_generic {
             // We remove the name of the full generic because we have no use for it.
             index_ty.name = Some(String::new());
             res.push(TypeWithKind::from((index_ty, ItemType::Generic)));
-        } else if let Some(kind) = ty.def_id_no_primitives().map(|did| tcx.def_kind(did).into()) {
+        } else if let Some(kind) = ty.def_id(cache).map(|did| tcx.def_kind(did).into()) {
             res.push(TypeWithKind::from((index_ty, kind)));
         } else if ty.is_primitive() {
             // This is a primitive, let's store it as such.
@@ -330,9 +335,7 @@ fn add_generics_and_bounds_as_types<'tcx>(
     if let Type::Generic(arg_s) = *arg {
         // First we check if the bounds are in a `where` predicate...
         if let Some(where_pred) = generics.where_predicates.iter().find(|g| match g {
-            WherePredicate::BoundPredicate { ty, .. } => {
-                ty.def_id_no_primitives() == arg.def_id_no_primitives()
-            }
+            WherePredicate::BoundPredicate { ty, .. } => ty.def_id(cache) == arg.def_id(cache),
             _ => false,
         }) {
             let mut ty_generics = Vec::new();
@@ -348,6 +351,7 @@ fn add_generics_and_bounds_as_types<'tcx>(
                                     tcx,
                                     recurse + 1,
                                     &mut ty_generics,
+                                    cache,
                                 )
                             }
                             _ => {}
@@ -355,7 +359,7 @@ fn add_generics_and_bounds_as_types<'tcx>(
                     }
                 }
             }
-            insert_ty(res, tcx, arg.clone(), ty_generics);
+            insert_ty(res, tcx, arg.clone(), ty_generics, cache);
         }
         // Otherwise we check if the trait bounds are "inlined" like `T: Option<u32>`...
         if let Some(bound) = generics.params.iter().find(|g| g.is_type() && g.name == arg_s) {
@@ -369,10 +373,11 @@ fn add_generics_and_bounds_as_types<'tcx>(
                         tcx,
                         recurse + 1,
                         &mut ty_generics,
+                        cache,
                     );
                 }
             }
-            insert_ty(res, tcx, arg.clone(), ty_generics);
+            insert_ty(res, tcx, arg.clone(), ty_generics, cache);
         }
     } else {
         // This is not a type parameter. So for example if we have `T, U: Option<T>`, and we're
@@ -383,10 +388,17 @@ fn add_generics_and_bounds_as_types<'tcx>(
         let mut ty_generics = Vec::new();
         if let Some(arg_generics) = arg.generics() {
             for gen in arg_generics.iter() {
-                add_generics_and_bounds_as_types(generics, gen, tcx, recurse + 1, &mut ty_generics);
+                add_generics_and_bounds_as_types(
+                    generics,
+                    gen,
+                    tcx,
+                    recurse + 1,
+                    &mut ty_generics,
+                    cache,
+                );
             }
         }
-        insert_ty(res, tcx, arg.clone(), ty_generics);
+        insert_ty(res, tcx, arg.clone(), ty_generics, cache);
     }
 }
 
@@ -397,6 +409,7 @@ fn add_generics_and_bounds_as_types<'tcx>(
 fn get_fn_inputs_and_outputs<'tcx>(
     func: &Function,
     tcx: TyCtxt<'tcx>,
+    cache: &Cache,
 ) -> (Vec<TypeWithKind>, Vec<TypeWithKind>) {
     let decl = &func.decl;
     let generics = &func.generics;
@@ -407,12 +420,11 @@ fn get_fn_inputs_and_outputs<'tcx>(
             continue;
         }
         let mut args = Vec::new();
-        add_generics_and_bounds_as_types(generics, &arg.type_, tcx, 0, &mut args);
+        add_generics_and_bounds_as_types(generics, &arg.type_, tcx, 0, &mut args, cache);
         if !args.is_empty() {
             all_types.extend(args);
         } else {
-            if let Some(kind) = arg.type_.def_id_no_primitives().map(|did| tcx.def_kind(did).into())
-            {
+            if let Some(kind) = arg.type_.def_id(cache).map(|did| tcx.def_kind(did).into()) {
                 all_types.push(TypeWithKind::from((get_index_type(&arg.type_, vec![]), kind)));
             }
         }
@@ -421,11 +433,9 @@ fn get_fn_inputs_and_outputs<'tcx>(
     let mut ret_types = Vec::new();
     match decl.output {
         FnRetTy::Return(ref return_type) => {
-            add_generics_and_bounds_as_types(generics, return_type, tcx, 0, &mut ret_types);
+            add_generics_and_bounds_as_types(generics, return_type, tcx, 0, &mut ret_types, cache);
             if ret_types.is_empty() {
-                if let Some(kind) =
-                    return_type.def_id_no_primitives().map(|did| tcx.def_kind(did).into())
-                {
+                if let Some(kind) = return_type.def_id(cache).map(|did| tcx.def_kind(did).into()) {
                     ret_types.push(TypeWithKind::from((get_index_type(return_type, vec![]), kind)));
                 }
             }
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index 586f34cd2c8..731e18b1eec 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -134,11 +134,13 @@ impl<'tcx> Visitor<'tcx> for SpanMapVisitor<'tcx> {
             if let Some(hir_id) = segment.hir_id {
                 let hir = self.tcx.hir();
                 let body_id = hir.enclosing_body_owner(hir_id);
-                let typeck_results = self.tcx.sess.with_disabled_diagnostic(|| {
-                    self.tcx.typeck_body(
-                        hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"),
-                    )
-                });
+                // FIXME: this is showing error messages for parts of the code that are not
+                // compiled (because of cfg)!
+                //
+                // See discussion in https://github.com/rust-lang/rust/issues/69426#issuecomment-1019412352
+                let typeck_results = self.tcx.typeck_body(
+                    hir.maybe_body_owned_by(body_id).expect("a body which isn't a body"),
+                );
                 if let Some(def_id) = typeck_results.type_dependent_def_id(expr.hir_id) {
                     self.matches.insert(
                         segment.ident.span,
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index bdd8aa430b2..87403a8b834 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -150,7 +150,6 @@ h1.fqn {
 	display: flex;
 	flex-wrap: wrap;
 	justify-content: space-between;
-	border-bottom: 1px dashed #DDDDDD;
 	padding-bottom: 6px;
 	margin-bottom: 15px;
 }
@@ -398,7 +397,7 @@ nav.sub {
 }
 
 .source .sidebar > *:not(:first-child) {
-	transition: opacity 0.5s, visibility 0.2s;
+	transition: opacity 0.5s;
 	opacity: 0;
 	visibility: hidden;
 }
@@ -485,6 +484,10 @@ nav.sub {
 	overflow: hidden;
 }
 
+.sidebar-links a {
+	white-space: nowrap;
+}
+
 .sidebar h2 {
 	border-bottom: none;
 	font-weight: 500;
@@ -671,7 +674,6 @@ nav.sub {
 	margin: .5em 0;
 	width: calc(100% - 2px);
 	overflow-x: auto;
-	overflow-wrap: normal;
 	display: block;
 }
 
@@ -858,6 +860,31 @@ h2.small-section-header > .anchor {
 
 .block a.current.crate { font-weight: 500; }
 
+/*  In most contexts we use `overflow-wrap: anywhere` to ensure that we can wrap
+	as much as needed on mobile (see
+	src/test/rustdoc-gui/type-declaration-overflow.goml for an example of why
+	this matters). The `anywhere` value means:
+
+	"Soft wrap opportunities introduced by the word break are considered when
+	 calculating min-content intrinsic sizes."
+
+	https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-wrap#values
+
+	For table layouts, that becomes a problem: the browser tries to make each
+	column as narrow as possible, and `overflow-wrap: anywhere` means it can do
+	so by breaking words - even if some other column could be shrunk without
+	breaking words! This shows up, for instance, in the `Structs` / `Modules` /
+	`Functions` (etcetera) sections of a module page, and when a docblock
+	contains a table.
+
+	So, for table layouts, override the default with break-word, which does
+	_not_ affect min-content intrinsic sizes.
+*/
+table,
+.item-table {
+	overflow-wrap: break-word;
+}
+
 .item-table {
 	display: table;
 }
@@ -873,11 +900,11 @@ h2.small-section-header > .anchor {
 
 .search-container {
 	position: relative;
-	max-width: 960px;
+	display: flex;
+	height: 34px;
 }
-.search-container > div {
-	display: inline-flex;
-	width: calc(100% - 63px);
+.search-container > * {
+	height: 100%;
 }
 .search-results-title {
 	display: inline;
@@ -908,10 +935,8 @@ h2.small-section-header > .anchor {
 	background-position: calc(100% - 1px) 56%;
 	background-image: /* AUTOREPLACE: */url("down-arrow.svg");
 }
-.search-container > .top-button {
-	position: absolute;
-	right: 0;
-	top: 10px;
+.search-container {
+	margin-top: 4px;
 }
 .search-input {
 	/* Override Normalize.css: it has a rule that sets
@@ -924,23 +949,14 @@ h2.small-section-header > .anchor {
 	-moz-box-sizing: border-box !important;
 	box-sizing: border-box !important;
 	outline: none;
-	border: none;
-	border-radius: 1px;
-	margin-top: 5px;
-	padding: 10px 16px;
+	border: 1px solid;
+	border-radius: 2px;
+	padding: 5px 8px;
 	font-size: 1.0625rem;
 	transition: border-color 300ms ease;
-	transition: border-radius 300ms ease-in-out;
-	transition: box-shadow 300ms ease-in-out;
 	width: 100%;
 }
 
-.search-input:focus {
-	border-radius: 2px;
-	border: 0;
-	outline: 0;
-}
-
 .search-results {
 	display: none;
 	padding-bottom: 2em;
@@ -1176,7 +1192,6 @@ a.test-arrow:hover{
 .out-of-band > span.since {
 	position: initial;
 	font-size: 1.25rem;
-	margin-right: 5px;
 }
 
 h3.variant {
@@ -1414,8 +1429,8 @@ pre.rust {
 
 .theme-picker {
 	position: absolute;
-	left: -34px;
-	top: 9px;
+	left: -38px;
+	top: 4px;
 }
 
 .theme-picker button {
@@ -1423,34 +1438,27 @@ pre.rust {
 }
 
 #settings-menu, #help-button {
-	position: absolute;
-	top: 10px;
-}
-
-#settings-menu {
-	right: 0;
+	margin-left: 4px;
 	outline: none;
 }
 
+#theme-picker, #copy-path {
+	height: 34px;
+}
 #theme-picker, #settings-menu, #help-button, #copy-path {
-	padding: 4px;
-	/* Rare exception to specifying font sizes in rem. Since these are acting
-	   as icons, it's okay to specify their sizes in pixels. */
-	font-size: 16px;
-	width: 27px;
-	height: 29px;
+	padding: 5px;
+	width: 33px;
 	border: 1px solid;
-	border-radius: 3px;
+	border-radius: 2px;
 	cursor: pointer;
 }
 
 #help-button {
-	right: 30px;
 	font-family: "Fira Sans", Arial, sans-serif;
 	text-align: center;
 	/* Rare exception to specifying font sizes in rem. Since this is acting
 	   as an icon, it's okay to specify their sizes in pixels. */
-	font-size: 16px;
+	font-size: 20px;
 	padding-top: 2px;
 }
 
@@ -1791,8 +1799,9 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 		background-color: rgba(0,0,0,0);
 		margin: 0;
 		padding: 0;
-		padding-left: 15px;
 		z-index: 11;
+		/* Reduce height slightly to account for mobile topbar. */
+		height: calc(100vh - 45px);
 	}
 
 	/* The source view uses a different design for the sidebar toggle, and doesn't have a topbar,
@@ -1823,7 +1832,13 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 		padding: 0.3em;
 		padding-right: 0.6em;
 		text-overflow: ellipsis;
-		overflow-x: hidden;
+		overflow: hidden;
+		white-space: nowrap;
+		/* Rare exception to specifying font sizes in rem. Since the topbar
+		   height is specified in pixels, this also has to be specified in
+		   pixels to avoid overflowing the topbar when the user sets a bigger
+		   font size. */
+		font-size: 22.4px;
 	}
 
 	.mobile-topbar .logo-container {
@@ -1844,7 +1859,6 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 		position: sticky;
 		z-index: 10;
 		font-size: 2rem;
-		cursor: pointer;
 		height: 45px;
 		width: 100%;
 		left: 0;
@@ -1857,6 +1871,9 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 
 	.sidebar-menu-toggle {
 		width: 45px;
+		/* Rare exception to specifying font sizes in rem. Since this is acting
+		   as an icon, it's okay to specify its sizes in pixels. */
+		font-size: 32px;
 		border: none;
 	}
 
@@ -1887,10 +1904,6 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 		display: none !important;
 	}
 
-	.theme-picker {
-		z-index: 1;
-	}
-
 	.notable-traits {
 		position: absolute;
 		left: -22px;
@@ -1977,10 +1990,6 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 		width: 100%;
 	}
 
-	.search-container > div {
-		width: calc(100% - 32px);
-	}
-
 	/* Display an alternating layout on tablets and phones */
 	.search-results > a {
 		border-bottom: 1px solid #aaa9;
@@ -2025,30 +2034,11 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 		width: 50%;
 	}
 
-	.search-container > div {
-		display: block;
-		width: calc(100% - 37px);
-	}
-
 	#crate-search {
 		border-radius: 4px;
 		border: 0;
 	}
 
-	#theme-picker, #settings-menu {
-		padding: 5px;
-		width: 31px;
-		height: 31px;
-	}
-
-	#theme-picker {
-		margin-top: -2px;
-	}
-
-	#settings-menu {
-		top: 7px;
-	}
-
 	.docblock {
 		margin-left: 12px;
 	}
@@ -2058,10 +2048,6 @@ details.rustdoc-toggle[open] > summary.hideme::after {
 		overflow-wrap: anywhere;
 	}
 
-	.docblock table code {
-		overflow-wrap: normal;
-	}
-
 	.sub-container {
 		flex-direction: column;
 	}
diff --git a/src/librustdoc/html/static/css/settings.css b/src/librustdoc/html/static/css/settings.css
index fb8990b30e2..932000487b0 100644
--- a/src/librustdoc/html/static/css/settings.css
+++ b/src/librustdoc/html/static/css/settings.css
@@ -17,6 +17,30 @@
 	border-bottom: 1px solid;
 }
 
+.setting-line .radio-line {
+	display: flex;
+	flex-wrap: wrap;
+}
+
+.setting-line .radio-line > * {
+	padding: 0.3em;
+}
+
+.setting-line .radio-line .setting-name {
+	flex-grow: 1;
+}
+
+.setting-line .radio-line input {
+	margin-right: 0.3em;
+}
+
+.radio-line .choice {
+	border-radius: 0.1em;
+	border: 1px solid;
+	margin-left: 0.5em;
+	min-width: 3.5em;
+}
+
 .toggle {
 	position: relative;
 	display: inline-block;
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index 69097b81b9f..cee45e1de39 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -191,6 +191,10 @@ pre, .rustdoc.source .example-wrap {
 	color: #a37acc;
 }
 
+.sidebar a { color: #53b1db; }
+.sidebar a.current.type { color: #53b1db; }
+.sidebar a.current.associatedtype { color: #53b1db; }
+
 pre.rust .comment { color: #788797; }
 pre.rust .doccomment { color: #a1ac88; }
 
@@ -212,6 +216,7 @@ a.anchor,
 pre.rust a,
 .sidebar h2 a,
 .sidebar h3 a,
+.mobile-topbar h2 a,
 .in-band a {
 	color: #c5c5c5;
 }
@@ -233,22 +238,14 @@ details.undocumented > summary::before {
 	filter: invert(100%);
 }
 
-#crate-search {
-	color: #c5c5c5;
+#crate-search, .search-input {
 	background-color: #141920;
-	box-shadow: 0 0 0 1px #424c57,0 0 0 2px transparent;
 	border-color: #424c57;
+	color: #c5c5c5;
 }
 
 .search-input {
 	color: #ffffff;
-	background-color: #141920;
-	box-shadow: 0 0 0 1px #424c57,0 0 0 2px transparent;
-	transition: box-shadow 150ms ease-in-out;
-}
-
-#crate-search+.search-input:focus {
-	box-shadow: 0 0 0 1px #148099,0 0 0 2px transparent;
 }
 
 .module-item .stab,
@@ -493,6 +490,25 @@ a.result-static:focus {}
 a.result-primitive:focus {}
 a.result-keyword:focus {}
 
+.sidebar a.current.enum {}
+.sidebar a.current.struct {}
+.sidebar a.current.foreigntype {}
+.sidebar a.current.attr,
+.sidebar a.current.derive,
+.sidebar a.current.macro {}
+.sidebar a.current.union {}
+.sidebar a.current.constant
+.sidebar a.current.static {}
+.sidebar a.current.primitive {}
+.sidebar a.current.externcrate
+.sidebar a.current.mod {}
+.sidebar a.current.trait {}
+.sidebar a.current.traitalias {}
+.sidebar a.current.fn,
+.sidebar a.current.method,
+.sidebar a.current.tymethod {}
+.sidebar a.current.keyword {}
+
 @media (max-width: 700px) {
 	.sidebar-menu {
 		background-color: #14191f;
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index 39165b2fc05..c5817ba4e73 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -148,6 +148,28 @@ a.result-keyword:focus { background-color: #884719; }
 .content .fnname{ color: #2BAB63; }
 .content span.keyword, .content a.keyword, .block a.current.keyword { color: #D2991D; }
 
+.sidebar a { color: #fdbf35; }
+.sidebar a.current.enum { color: #12ece2; }
+.sidebar a.current.struct { color: #12ece2; }
+.sidebar a.current.type { color: #12ece2; }
+.sidebar a.current.associatedtype { color: #fdbf35; }
+.sidebar a.current.foreigntype { color: #12ece2; }
+.sidebar a.current.attr,
+.sidebar a.current.derive,
+.sidebar a.current.macro { color: #0be900; }
+.sidebar a.current.union { color: #12ece2; }
+.sidebar a.current.constant
+.sidebar a.current.static { color: #fdbf35; }
+.sidebar a.current.primitive { color: #12ece2; }
+.sidebar a.current.externcrate
+.sidebar a.current.mod { color: #fdbf35; }
+.sidebar a.current.trait { color: #cca7ff; }
+.sidebar a.current.traitalias { color: #cca7ff; }
+.sidebar a.current.fn,
+.sidebar a.current.method,
+.sidebar a.current.tymethod { color: #32d479; }
+.sidebar a.current.keyword { color: #fdbf35; }
+
 pre.rust .comment { color: #8d8d8b; }
 pre.rust .doccomment { color: #8ca375; }
 
@@ -170,6 +192,7 @@ a.anchor,
 pre.rust a,
 .sidebar h2 a,
 .sidebar h3 a,
+.mobile-topbar h2 a,
 .in-band a {
 	color: #ddd;
 }
@@ -194,27 +217,20 @@ details.undocumented > summary::before {
 	filter: invert(100%);
 }
 
-#crate-search {
+#crate-search, .search-input {
 	color: #111;
 	background-color: #f0f0f0;
 	border-color: #000;
-	box-shadow: 0 0 0 1px #000, 0 0 0 2px transparent;
 }
 
 .search-input {
-	color: #111;
-	background-color: #f0f0f0;
-	box-shadow: 0 0 0 1px #000, 0 0 0 2px transparent;
+	border-color: #e0e0e0;
 }
 
 .search-input:focus {
 	border-color: #008dfd;
 }
 
-#crate-search + .search-input:focus {
-	box-shadow: 0 0 8px 4px #078dd8;
-}
-
 .module-item .stab,
 .import-item .stab {
 	color: #ddd;
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index 448c9ac603c..3d2cd23ae3a 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -148,6 +148,28 @@ a.result-keyword:focus { background-color: #afc6e4; }
 .content .fnname { color: #AD7C37; }
 .content span.keyword, .content a.keyword, .block a.current.keyword { color: #3873AD; }
 
+.sidebar a { color: #356da4; }
+.sidebar a.current.enum { color: #a63283; }
+.sidebar a.current.struct { color: #a63283; }
+.sidebar a.current.type { color: #a63283; }
+.sidebar a.current.associatedtype { color: #356da4; }
+.sidebar a.current.foreigntype { color: #356da4; }
+.sidebar a.current.attr,
+.sidebar a.current.derive,
+.sidebar a.current.macro { color: #067901; }
+.sidebar a.current.union { color: #a63283; }
+.sidebar a.current.constant
+.sidebar a.current.static { color: #356da4; }
+.sidebar a.current.primitive { color: #a63283; }
+.sidebar a.current.externcrate
+.sidebar a.current.mod { color: #356da4; }
+.sidebar a.current.trait { color: #6849c3; }
+.sidebar a.current.traitalias { color: #4b349e; }
+.sidebar a.current.fn,
+.sidebar a.current.method,
+.sidebar a.current.tymethod { color: #a67736; }
+.sidebar a.current.keyword { color: #356da4; }
+
 nav.main .current {
 	border-top-color: #000;
 	border-bottom-color: #000;
@@ -167,6 +189,7 @@ a.anchor,
 pre.rust a,
 .sidebar h2 a,
 .sidebar h3 a,
+.mobile-topbar h2 a,
 .in-band a {
 	color: #000;
 }
@@ -186,27 +209,16 @@ details.undocumented > summary::before {
 	color: #999;
 }
 
-#crate-search {
+#crate-search, .search-input {
 	color: #555;
 	background-color: white;
 	border-color: #e0e0e0;
-	box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent;
-}
-
-.search-input {
-	color: #555;
-	background-color: white;
-	box-shadow: 0 0 0 1px #e0e0e0, 0 0 0 2px transparent;
 }
 
 .search-input:focus {
 	border-color: #66afe9;
 }
 
-#crate-search + .search-input:focus {
-	box-shadow: 0 0 8px #078dd8;
-}
-
 .module-item .stab,
 .import-item .stab {
 	color: #000;
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 161b95d9993..3c21a96cef0 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -72,7 +72,7 @@ function resourcePath(basename, extension) {
         var mobileLocationTitle = document.querySelector(".mobile-topbar h2.location");
         var locationTitle = document.querySelector(".sidebar h2.location");
         if (mobileLocationTitle && locationTitle) {
-            mobileLocationTitle.innerText = locationTitle.innerText;
+            mobileLocationTitle.innerHTML = locationTitle.innerHTML;
         }
     }
 }());
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
index e5c7e1ea1a0..47a8fcdfd5e 100644
--- a/src/librustdoc/html/static/js/settings.js
+++ b/src/librustdoc/html/static/js/settings.js
@@ -33,19 +33,15 @@
     }
 
     function showLightAndDark() {
-        addClass(document.getElementById("theme").parentElement.parentElement, "hidden");
-        removeClass(document.getElementById("preferred-light-theme").parentElement.parentElement,
-            "hidden");
-        removeClass(document.getElementById("preferred-dark-theme").parentElement.parentElement,
-            "hidden");
+        addClass(document.getElementById("theme").parentElement, "hidden");
+        removeClass(document.getElementById("preferred-light-theme").parentElement, "hidden");
+        removeClass(document.getElementById("preferred-dark-theme").parentElement, "hidden");
     }
 
     function hideLightAndDark() {
-        addClass(document.getElementById("preferred-light-theme").parentElement.parentElement,
-            "hidden");
-        addClass(document.getElementById("preferred-dark-theme").parentElement.parentElement,
-            "hidden");
-        removeClass(document.getElementById("theme").parentElement.parentElement, "hidden");
+        addClass(document.getElementById("preferred-light-theme").parentElement, "hidden");
+        addClass(document.getElementById("preferred-dark-theme").parentElement, "hidden");
+        removeClass(document.getElementById("theme").parentElement, "hidden");
     }
 
     function updateLightAndDark() {
@@ -82,6 +78,19 @@
                 changeSetting(this.id, this.value);
             };
         });
+        onEachLazy(document.querySelectorAll("input[type=\"radio\"]"), function(elem) {
+            const settingId = elem.name;
+            const settingValue = getSettingValue(settingId);
+            if (settingValue !== null && settingValue !== "null") {
+                elem.checked = settingValue === elem.value;
+            }
+            elem.addEventListener("change", function(ev) {
+                changeSetting(ev.target.name, ev.target.value);
+            });
+        });
+        document.getElementById("back").addEventListener("click", function() {
+            history.back();
+        });
     }
 
     window.addEventListener("DOMContentLoaded", setEvents);
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index 2394df4c715..06bb34eb115 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -216,6 +216,15 @@ var updateSystemTheme = (function() {
     };
 })();
 
+function switchToSavedTheme() {
+    switchTheme(
+        window.currentTheme,
+        window.mainTheme,
+        getSettingValue("theme") || "light",
+        false
+    );
+}
+
 if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) {
     // update the preferred dark theme if the user is already using a dark theme
     // See https://github.com/rust-lang/rust/pull/77809#issuecomment-707875732
@@ -228,10 +237,20 @@ if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) {
     // call the function to initialize the theme at least once!
     updateSystemTheme();
 } else {
-    switchTheme(
-        window.currentTheme,
-        window.mainTheme,
-        getSettingValue("theme") || "light",
-        false
-    );
+    switchToSavedTheme();
 }
+
+// If we navigate away (for example to a settings page), and then use the back or
+// forward button to get back to a page, the theme may have changed in the meantime.
+// But scripts may not be re-loaded in such a case due to the bfcache
+// (https://web.dev/bfcache/). The "pageshow" event triggers on such navigations.
+// Use that opportunity to update the theme.
+// We use a setTimeout with a 0 timeout here to put the change on the event queue.
+// For some reason, if we try to change the theme while the `pageshow` event is
+// running, it sometimes fails to take effect. The problem manifests on Chrome,
+// specifically when talking to a remote website with no caching.
+window.addEventListener("pageshow", function(ev) {
+    if (ev.persisted) {
+        setTimeout(switchToSavedTheme, 0);
+    }
+});
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index 1322b854b7f..baadd3c27b4 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -110,25 +110,24 @@
                 <nav class="sub"> {#- -#}
                     <div class="theme-picker hidden"> {#- -#}
                         <button id="theme-picker" aria-label="Pick another theme!" aria-haspopup="menu" title="themes"> {#- -#}
-                            <img width="18" height="18" alt="Pick another theme!" {# -#}
+                            <img width="22" height="22" alt="Pick another theme!" {# -#}
                              src="{{static_root_path|safe}}brush{{page.resource_suffix}}.svg"> {#- -#}
                         </button> {#- -#}
                         <div id="theme-choices" role="menu"></div> {#- -#}
                     </div> {#- -#}
                     <form class="search-form"> {#- -#}
                         <div class="search-container"> {#- -#}
-                            <div>
-                                <input {# -#}
-                                    class="search-input" {# -#}
-                                    name="search" {# -#}
-                                    autocomplete="off" {# -#}
-                                    spellcheck="false" {# -#}
-                                    placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
-                                    type="search"> {#- -#}
-                            </div> {#- -#}
+                            <span></span> {#- This empty span is a hacky fix for Safari - See #93184 -#}
+                            <input {# -#}
+                                class="search-input" {# -#}
+                                name="search" {# -#}
+                                autocomplete="off" {# -#}
+                                spellcheck="false" {# -#}
+                                placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
+                                type="search"> {#- -#}
                             <button type="button" id="help-button" title="help">?</button> {#- -#}
                             <a id="settings-menu" href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#}
-                                <img width="18" height="18" alt="Change settings" {# -#}
+                                <img width="22" height="22" alt="Change settings" {# -#}
                                      src="{{static_root_path|safe}}wheel{{page.resource_suffix}}.svg"> {#- -#}
                             </a> {#- -#}
                         </div> {#- -#}
diff --git a/src/librustdoc/html/templates/print_item.html b/src/librustdoc/html/templates/print_item.html
index 459b01a9960..62b1b7ca729 100644
--- a/src/librustdoc/html/templates/print_item.html
+++ b/src/librustdoc/html/templates/print_item.html
@@ -16,11 +16,11 @@
     </h1> {#- -#}
     <span class="out-of-band"> {#- -#}
         {% if !stability_since_raw.is_empty() %}
-        {{- stability_since_raw|safe -}} · {# -#}
+        {{- stability_since_raw|safe }} · {# -#}
         {% endif %}
         {%- match src_href -%}
             {%- when Some with (href) -%}
-                <a class="srclink" href="{{href|safe}}" title="goto source code">source</a> · {# -#}
+                <a class="srclink" href="{{href|safe}}">source</a> · {# -#}
             {%- else -%}
         {%- endmatch -%}
         <a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs"> {#- -#}
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 8f484766d9a..f9e9fe0d3cf 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -172,21 +172,8 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
     /// the hashmap because certain items (traits and types) need to have their mappings for trait
     /// implementations filled out before they're inserted.
     fn item(&mut self, item: clean::Item) -> Result<(), Error> {
-        let local_blanket_impl = match item.def_id {
-            clean::ItemId::Blanket { impl_id, .. } => impl_id.is_local(),
-            clean::ItemId::Auto { .. }
-            | clean::ItemId::DefId(_)
-            | clean::ItemId::Primitive(_, _) => false,
-        };
-
         // Flatten items that recursively store other items
-        // FIXME(CraftSpider): We skip children of local blanket implementations, as we'll have
-        //     already seen the actual generic impl, and the generated ones don't need documenting.
-        //     This is necessary due to the visibility, return type, and self arg of the generated
-        //     impls not quite matching, and will no longer be necessary when the mismatch is fixed.
-        if !local_blanket_impl {
-            item.kind.inner_items().for_each(|i| self.item(i.clone()).unwrap());
-        }
+        item.kind.inner_items().for_each(|i| self.item(i.clone()).unwrap());
 
         let id = item.def_id;
         if let Some(mut new_item) = self.convert_item(item) {
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index d854aa86b3a..a7c3c0bb606 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -16,6 +16,8 @@
 #![feature(once_cell)]
 #![feature(type_ascription)]
 #![feature(iter_intersperse)]
+#![feature(type_alias_impl_trait)]
+#![feature(generic_associated_types)]
 #![recursion_limit = "256"]
 #![warn(rustc::internal)]
 #![allow(clippy::collapsible_if, clippy::collapsible_else_if)]
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index 7dbf00420de..86662ebaaca 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -16,7 +16,7 @@ use rustc_middle::ty::{DefIdTree, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug, ty};
 use rustc_resolve::ParentScope;
 use rustc_session::lint::Lint;
-use rustc_span::hygiene::{MacroKind, SyntaxContext};
+use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{BytePos, DUMMY_SP};
 use smallvec::{smallvec, SmallVec};
@@ -362,7 +362,7 @@ struct DiagnosticInfo<'a> {
 
 #[derive(Clone, Debug, Hash)]
 struct CachedLink {
-    pub res: (Res, Option<UrlFragment>),
+    res: (Res, Option<UrlFragment>),
 }
 
 struct LinkCollector<'a, 'tcx> {
@@ -427,7 +427,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
                     .inherent_impls(did)
                     .iter()
                     .flat_map(|imp| tcx.associated_items(*imp).in_definition_order())
-                    .any(|item| item.ident.name == variant_name)
+                    .any(|item| item.name == variant_name)
                 {
                     // This is just to let `fold_item` know that this shouldn't be considered;
                     // it's a bug for the error to make it to the user
@@ -920,25 +920,15 @@ fn trait_assoc_to_impl_assoc_item<'tcx>(
 ///
 /// NOTE: this cannot be a query because more traits could be available when more crates are compiled!
 /// So it is not stable to serialize cross-crate.
+#[instrument(level = "debug", skip(cx))]
 fn trait_impls_for<'a>(
     cx: &mut DocContext<'a>,
     ty: Ty<'a>,
     module: DefId,
 ) -> FxHashSet<(DefId, DefId)> {
-    let mut resolver = cx.resolver.borrow_mut();
-    let in_scope_traits = cx.module_trait_cache.entry(module).or_insert_with(|| {
-        resolver.access(|resolver| {
-            let parent_scope = &ParentScope::module(resolver.expect_module(module), resolver);
-            resolver
-                .traits_in_scope(None, parent_scope, SyntaxContext::root(), None)
-                .into_iter()
-                .map(|candidate| candidate.def_id)
-                .collect()
-        })
-    });
-
     let tcx = cx.tcx;
-    let iter = in_scope_traits.iter().flat_map(|&trait_| {
+    let iter = cx.resolver_caches.traits_in_scope[&module].iter().flat_map(|trait_candidate| {
+        let trait_ = trait_candidate.def_id;
         trace!("considering explicit impl for trait {:?}", trait_);
 
         // Look at each trait implementation to see if it's an impl for `did`
diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs
index 31d6ac44a94..edd4e9da66d 100644
--- a/src/librustdoc/passes/collect_intra_doc_links/early.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs
@@ -7,11 +7,15 @@ use rustc_ast::visit::{self, AssocCtxt, Visitor};
 use rustc_ast::{self as ast, ItemKind};
 use rustc_ast_lowering::ResolverAstLowering;
 use rustc_hir::def::Namespace::TypeNS;
-use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
-use rustc_resolve::Resolver;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LocalDefId, CRATE_DEF_ID};
+use rustc_hir::TraitCandidate;
+use rustc_middle::ty::{DefIdTree, Visibility};
+use rustc_resolve::{ParentScope, Resolver};
 use rustc_session::config::Externs;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{Span, SyntaxContext, DUMMY_SP};
 
+use std::collections::hash_map::Entry;
 use std::mem;
 
 crate fn early_resolve_intra_doc_links(
@@ -22,15 +26,23 @@ crate fn early_resolve_intra_doc_links(
     let mut loader = IntraLinkCrateLoader {
         resolver,
         current_mod: CRATE_DEF_ID,
+        visited_mods: Default::default(),
+        traits_in_scope: Default::default(),
         all_traits: Default::default(),
         all_trait_impls: Default::default(),
     };
 
+    // Because of the `crate::` prefix, any doc comment can reference
+    // the crate root's set of in-scope traits. This line makes sure
+    // it's available.
+    loader.add_traits_in_scope(CRATE_DEF_ID.to_def_id());
+
     // Overridden `visit_item` below doesn't apply to the crate root,
-    // so we have to visit its attributes and exports separately.
+    // so we have to visit its attributes and reexports separately.
     loader.load_links_in_attrs(&krate.attrs, krate.span);
+    loader.process_module_children_or_reexports(CRATE_DEF_ID.to_def_id());
     visit::walk_crate(&mut loader, krate);
-    loader.fill_resolver_caches();
+    loader.add_foreign_traits_in_scope();
 
     // FIXME: somehow rustdoc is still missing crates even though we loaded all
     // the known necessary crates. Load them all unconditionally until we find a way to fix this.
@@ -46,6 +58,7 @@ crate fn early_resolve_intra_doc_links(
     }
 
     ResolverCaches {
+        traits_in_scope: loader.traits_in_scope,
         all_traits: Some(loader.all_traits),
         all_trait_impls: Some(loader.all_trait_impls),
     }
@@ -54,27 +67,87 @@ crate fn early_resolve_intra_doc_links(
 struct IntraLinkCrateLoader<'r, 'ra> {
     resolver: &'r mut Resolver<'ra>,
     current_mod: LocalDefId,
+    visited_mods: DefIdSet,
+    traits_in_scope: DefIdMap<Vec<TraitCandidate>>,
     all_traits: Vec<DefId>,
     all_trait_impls: Vec<DefId>,
 }
 
 impl IntraLinkCrateLoader<'_, '_> {
-    fn fill_resolver_caches(&mut self) {
-        for cnum in self.resolver.cstore().crates_untracked() {
-            let all_traits = self.resolver.cstore().traits_in_crate_untracked(cnum);
-            let all_trait_impls = self.resolver.cstore().trait_impls_in_crate_untracked(cnum);
+    fn add_traits_in_scope(&mut self, def_id: DefId) {
+        // Calls to `traits_in_scope` are expensive, so try to avoid them if only possible.
+        // Keys in the `traits_in_scope` cache are always module IDs.
+        if let Entry::Vacant(entry) = self.traits_in_scope.entry(def_id) {
+            let module = self.resolver.get_nearest_non_block_module(def_id);
+            let module_id = module.def_id();
+            let entry = if module_id == def_id {
+                Some(entry)
+            } else if let Entry::Vacant(entry) = self.traits_in_scope.entry(module_id) {
+                Some(entry)
+            } else {
+                None
+            };
+            if let Some(entry) = entry {
+                entry.insert(self.resolver.traits_in_scope(
+                    None,
+                    &ParentScope::module(module, self.resolver),
+                    SyntaxContext::root(),
+                    None,
+                ));
+            }
+        }
+    }
+
+    fn add_traits_in_parent_scope(&mut self, def_id: DefId) {
+        if let Some(module_id) = self.resolver.parent(def_id) {
+            self.add_traits_in_scope(module_id);
+        }
+    }
+
+    /// Add traits in scope for links in impls collected by the `collect-intra-doc-links` pass.
+    /// That pass filters impls using type-based information, but we don't yet have such
+    /// information here, so we just conservatively calculate traits in scope for *all* modules
+    /// having impls in them.
+    fn add_foreign_traits_in_scope(&mut self) {
+        for cnum in Vec::from_iter(self.resolver.cstore().crates_untracked()) {
+            // FIXME: Due to #78696 rustdoc can query traits in scope for any crate root.
+            self.add_traits_in_scope(cnum.as_def_id());
+
+            let all_traits = Vec::from_iter(self.resolver.cstore().traits_in_crate_untracked(cnum));
+            let all_trait_impls =
+                Vec::from_iter(self.resolver.cstore().trait_impls_in_crate_untracked(cnum));
+
+            // Querying traits in scope is expensive so we try to prune the impl and traits lists
+            // using privacy, private traits and impls from other crates are never documented in
+            // the current crate, and links in their doc comments are not resolved.
+            for &def_id in &all_traits {
+                if self.resolver.cstore().visibility_untracked(def_id) == Visibility::Public {
+                    self.add_traits_in_parent_scope(def_id);
+                }
+            }
+            for &(trait_def_id, impl_def_id, simplified_self_ty) in &all_trait_impls {
+                if self.resolver.cstore().visibility_untracked(trait_def_id) == Visibility::Public
+                    && simplified_self_ty.and_then(|ty| ty.def()).map_or(true, |ty_def_id| {
+                        self.resolver.cstore().visibility_untracked(ty_def_id) == Visibility::Public
+                    })
+                {
+                    self.add_traits_in_parent_scope(impl_def_id);
+                }
+            }
 
             self.all_traits.extend(all_traits);
-            self.all_trait_impls.extend(all_trait_impls.into_iter().map(|(def_id, _)| def_id));
+            self.all_trait_impls.extend(all_trait_impls.into_iter().map(|(_, def_id, _)| def_id));
         }
     }
 
     fn load_links_in_attrs(&mut self, attrs: &[ast::Attribute], span: Span) {
-        // FIXME: this needs to consider export inlining.
+        // FIXME: this needs to consider reexport inlining.
         let attrs = clean::Attributes::from_ast(attrs, None);
         for (parent_module, doc) in attrs.collapsed_doc_value_by_module_level() {
             let module_id = parent_module.unwrap_or(self.current_mod.to_def_id());
 
+            self.add_traits_in_scope(module_id);
+
             for link in markdown_links(&doc.as_str()) {
                 let path_str = if let Some(Ok(x)) = preprocess_link(&link) {
                     x.path_str
@@ -85,6 +158,26 @@ impl IntraLinkCrateLoader<'_, '_> {
             }
         }
     }
+
+    /// When reexports are inlined, they are replaced with item which they refer to, those items
+    /// may have links in their doc comments, those links are resolved at the item definition site,
+    /// so we need to know traits in scope at that definition site.
+    fn process_module_children_or_reexports(&mut self, module_id: DefId) {
+        if !self.visited_mods.insert(module_id) {
+            return; // avoid infinite recursion
+        }
+
+        for child in self.resolver.module_children_or_reexports(module_id) {
+            if child.vis == Visibility::Public {
+                if let Some(def_id) = child.res.opt_def_id() {
+                    self.add_traits_in_parent_scope(def_id);
+                }
+                if let Res::Def(DefKind::Mod, module_id) = child.res {
+                    self.process_module_children_or_reexports(module_id);
+                }
+            }
+        }
+    }
 }
 
 impl Visitor<'_> for IntraLinkCrateLoader<'_, '_> {
@@ -92,7 +185,13 @@ impl Visitor<'_> for IntraLinkCrateLoader<'_, '_> {
         if let ItemKind::Mod(..) = item.kind {
             let old_mod = mem::replace(&mut self.current_mod, self.resolver.local_def_id(item.id));
 
+            // A module written with a outline doc comments will resolve traits relative
+            // to the parent module. Make sure the parent module's traits-in-scope are
+            // loaded, even if the module itself has no doc comments.
+            self.add_traits_in_parent_scope(self.current_mod.to_def_id());
+
             self.load_links_in_attrs(&item.attrs, item.span);
+            self.process_module_children_or_reexports(self.current_mod.to_def_id());
             visit::walk_item(self, item);
 
             self.current_mod = old_mod;
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index 66ac612ea37..53280b3df13 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -4,6 +4,7 @@
 use super::Pass;
 use crate::clean::*;
 use crate::core::DocContext;
+use crate::formats::cache::Cache;
 use crate::visit::DocVisitor;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -57,14 +58,14 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
         }
     });
 
-    let mut cleaner = BadImplStripper { prims, items: crate_items };
+    let mut cleaner = BadImplStripper { prims, items: crate_items, cache: &cx.cache };
     let mut type_did_to_deref_target: FxHashMap<DefId, &Type> = FxHashMap::default();
 
     // Follow all `Deref` targets of included items and recursively add them as valid
     fn add_deref_target(
         cx: &DocContext<'_>,
         map: &FxHashMap<DefId, &Type>,
-        cleaner: &mut BadImplStripper,
+        cleaner: &mut BadImplStripper<'_>,
         type_did: DefId,
     ) {
         if let Some(target) = map.get(&type_did) {
@@ -102,7 +103,7 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
                 } else if let Some(did) = target.def_id(&cx.cache) {
                     cleaner.items.insert(did.into());
                 }
-                if let Some(for_did) = for_.def_id_no_primitives() {
+                if let Some(for_did) = for_.def_id(&cx.cache) {
                     if type_did_to_deref_target.insert(for_did, target).is_none() {
                         // Since only the `DefId` portion of the `Type` instances is known to be same for both the
                         // `Deref` target type and the impl for type positions, this map of types is keyed by
@@ -204,19 +205,20 @@ impl DocVisitor for ItemCollector {
     }
 }
 
-struct BadImplStripper {
+struct BadImplStripper<'a> {
     prims: FxHashSet<PrimitiveType>,
     items: FxHashSet<ItemId>,
+    cache: &'a Cache,
 }
 
-impl BadImplStripper {
+impl<'a> BadImplStripper<'a> {
     fn keep_impl(&self, ty: &Type, is_deref: bool) -> bool {
         if let Generic(_) = ty {
             // keep impls made on generics
             true
         } else if let Some(prim) = ty.primitive_type() {
             self.prims.contains(&prim)
-        } else if let Some(did) = ty.def_id_no_primitives() {
+        } else if let Some(did) = ty.def_id(self.cache) {
             is_deref || self.keep_impl_with_def_id(did.into())
         } else {
             false
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
index e63534659ad..e7a99ee7bfd 100644
--- a/src/librustdoc/passes/strip_hidden.rs
+++ b/src/librustdoc/passes/strip_hidden.rs
@@ -15,7 +15,7 @@ crate const STRIP_HIDDEN: Pass = Pass {
 };
 
 /// Strip items marked `#[doc(hidden)]`
-crate fn strip_hidden(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Crate {
+crate fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
     let mut retained = ItemIdSet::default();
 
     // strip all #[doc(hidden)] items
@@ -25,7 +25,7 @@ crate fn strip_hidden(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Cra
     };
 
     // strip all impls referencing stripped items
-    let mut stripper = ImplStripper { retained: &retained };
+    let mut stripper = ImplStripper { retained: &retained, cache: &cx.cache };
     stripper.fold_crate(krate)
 }
 
diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs
index c6b5bec4692..ef7e768a511 100644
--- a/src/librustdoc/passes/strip_private.rs
+++ b/src/librustdoc/passes/strip_private.rs
@@ -29,6 +29,6 @@ crate fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> clea
     }
 
     // strip all impls referencing private items
-    let mut stripper = ImplStripper { retained: &retained };
+    let mut stripper = ImplStripper { retained: &retained, cache: &cx.cache };
     stripper.fold_crate(krate)
 }
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index 7b07974ae01..717dc078b34 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -5,6 +5,7 @@ use std::mem;
 
 use crate::clean::{self, Item, ItemIdSet};
 use crate::fold::{strip_item, DocFolder};
+use crate::formats::cache::Cache;
 
 crate struct Stripper<'a> {
     crate retained: &'a mut ItemIdSet,
@@ -118,6 +119,7 @@ impl<'a> DocFolder for Stripper<'a> {
 /// This stripper discards all impls which reference stripped items
 crate struct ImplStripper<'a> {
     crate retained: &'a ItemIdSet,
+    crate cache: &'a Cache,
 }
 
 impl<'a> DocFolder for ImplStripper<'a> {
@@ -127,7 +129,7 @@ impl<'a> DocFolder for ImplStripper<'a> {
             if imp.trait_.is_none() && imp.items.is_empty() {
                 return None;
             }
-            if let Some(did) = imp.for_.def_id_no_primitives() {
+            if let Some(did) = imp.for_.def_id(self.cache) {
                 if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into())
                 {
                     debug!("ImplStripper: impl item for stripped type; removing");
@@ -142,7 +144,7 @@ impl<'a> DocFolder for ImplStripper<'a> {
             }
             if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
                 for typaram in generics {
-                    if let Some(did) = typaram.def_id_no_primitives() {
+                    if let Some(did) = typaram.def_id(self.cache) {
                         if did.is_local() && !self.retained.contains(&did.into()) {
                             debug!(
                                 "ImplStripper: stripped item in trait's generics; removing impl"
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
index 47fc666da9a..899c9e4c629 100644
--- a/src/librustdoc/scrape_examples.rs
+++ b/src/librustdoc/scrape_examples.rs
@@ -292,7 +292,7 @@ crate fn load_call_locations(
         for path in with_examples {
             let bytes = fs::read(&path).map_err(|e| format!("{} (for path {})", e, path))?;
             let mut decoder = Decoder::new(&bytes, 0);
-            let calls = AllCallLocations::decode(&mut decoder)?;
+            let calls = AllCallLocations::decode(&mut decoder);
 
             for (function, fn_calls) in calls.into_iter() {
                 all_calls.entry(function).or_default().extend(fn_calls.into_iter());
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 6b3dbcc81a470e5da84576d63fcfc19e3b1154c
+Subproject b6b46f596a7d2523ee1acd1c00e699615849da6
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 618c8aab86a..600833664be 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -8,6 +8,9 @@ use std::path::PathBuf;
 
 use serde::{Deserialize, Serialize};
 
+/// rustdoc format-version.
+pub const FORMAT_VERSION: u32 = 10;
+
 /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
 /// about the language items in the local crate, as well as info about external items to allow
 /// tools to find or link to them.
@@ -517,8 +520,5 @@ pub struct Static {
     pub expr: String,
 }
 
-/// rustdoc format-version.
-pub const FORMAT_VERSION: u32 = 9;
-
 #[cfg(test)]
 mod tests;
diff --git a/src/stage0.json b/src/stage0.json
index 6c1b95b4145..525902be852 100644
--- a/src/stage0.json
+++ b/src/stage0.json
@@ -2,347 +2,347 @@
   "__comment": "Generated by `./x.py run src/tools/bump-stage0`. Run that command again to update the bootstrap compiler.",
   "dist_server": "https://static.rust-lang.org",
   "compiler": {
-    "date": "2021-11-30",
+    "date": "2022-01-28",
     "version": "beta"
   },
   "rustfmt": {
-    "date": "2021-11-30",
+    "date": "2022-01-28",
     "version": "nightly"
   },
   "checksums_sha256": {
-    "dist/2021-11-30/cargo-beta-aarch64-apple-darwin.tar.gz": "f7dadcadc22aab3ed9ddd737a9c2af05f42ffe48b431bbad5d43128130480279",
-    "dist/2021-11-30/cargo-beta-aarch64-apple-darwin.tar.xz": "0ee7c052bb1fd3f3655d9ff74b3f38ebb256d3f523750dbde1be9bceb207cda9",
-    "dist/2021-11-30/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "68d914f773b122bd1ceae13a55d3c8365753d09d4371e3962401b9a48945cf20",
-    "dist/2021-11-30/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "b0204e516f0c22b956f227555be5665df96c4e0f60281592b00678b4ea8ad4e9",
-    "dist/2021-11-30/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "77b771198aaf78c039df9c08493a9af5d1eb02e6b88bd4fc3b42269cdbf582d0",
-    "dist/2021-11-30/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "6f6465db2c726cc3d2db73150377ed17cbe164297f8cbffc51c8194494cb0384",
-    "dist/2021-11-30/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "76a8001adffd5d7a607459f1726f3d68c95e6eb4925eac9ccb77b213c37d2385",
-    "dist/2021-11-30/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "07dac7cfe68cb6b0a1872728c1dfb3fde0f9fa27a08933494faaf58a5e35865a",
-    "dist/2021-11-30/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "d2d6d2b56cbcc8bb5b2139818770fc155146d6b4469678de8a1e8249f15137d7",
-    "dist/2021-11-30/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "5f97d1449b9c4461be47615ab49ec408d8f1981b7a1bc0d7b7cce606c14cd5ed",
-    "dist/2021-11-30/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "097d346e828a37ae5be077f0896796ab6238194846f8ae279cd9e2f510645625",
-    "dist/2021-11-30/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "71a7906aea42e1048fc43828ece3da720eea4f9d4ff59e970e273f0fe9191e12",
-    "dist/2021-11-30/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "20e49a6995503dd8215dc9f56ffb87dc9f07fe85a1b0d2f409313836dc0dda3f",
-    "dist/2021-11-30/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "b9388524cec65e789bb5eaf22cfd63ce837b9a98d1b769901597c6f061f1b93d",
-    "dist/2021-11-30/cargo-beta-i686-pc-windows-gnu.tar.gz": "7b0bf29bc67904a64560402891d60506a29b7cd64007d7c1f4e168a574009a9c",
-    "dist/2021-11-30/cargo-beta-i686-pc-windows-gnu.tar.xz": "c580c17566e36cbb91945e0fb9e592ac7578d32da948c70aabb90de80000f5c8",
-    "dist/2021-11-30/cargo-beta-i686-pc-windows-msvc.tar.gz": "e34436449fb69b8ca696b4bcba8e18a612fee189ad8069d765813d39c708ad58",
-    "dist/2021-11-30/cargo-beta-i686-pc-windows-msvc.tar.xz": "322836c74da2b221426782e4b5e174571d1da1935d478b4b8b948608a28a20e8",
-    "dist/2021-11-30/cargo-beta-i686-unknown-linux-gnu.tar.gz": "ab2361cb4cbe44331e34a50728dd56a3db220e08f1b29452f781ee075b236c33",
-    "dist/2021-11-30/cargo-beta-i686-unknown-linux-gnu.tar.xz": "6375ef38e8e6270d6d932d176a7e62014daf153e873667f6d4a5335fa15f8bf3",
-    "dist/2021-11-30/cargo-beta-mips-unknown-linux-gnu.tar.gz": "3e80c94aef4511090e6a83f64b304b835ae2a8e769d3beec96e3f08c0faca01c",
-    "dist/2021-11-30/cargo-beta-mips-unknown-linux-gnu.tar.xz": "af954c96c823d711b372c94a2f2bab32536a4e39bcdd0351674252837096f8b4",
-    "dist/2021-11-30/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "92464fb6d0691a591637cf342842b42b940f8a84525f1e1f51493734f2ad7b1b",
-    "dist/2021-11-30/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "5ddeb87b53749bc532322ee8435fd442adbfaa5e80f3b614b7153c40f46d63d1",
-    "dist/2021-11-30/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "1c60eccc658664853232131fb48dc5d2c66340bb95d242084c211c59407fa667",
-    "dist/2021-11-30/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "257aab89cd0d5d9af408fc346aeccb8d51e1eba5dc0db074db1f4b57a8d4aab2",
-    "dist/2021-11-30/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "20b1fa2138a547f5f6644acfbca9e73f8d228578a600c7710cb2fc34a20eb058",
-    "dist/2021-11-30/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "134dde13eb7dedb8fc608acae62d715937c168a9fe5a449262e9ac9b3f042396",
-    "dist/2021-11-30/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "4ffca03462b91b9cbb02a022546aa0e16118eb1950a8f040929e5bfceee2b9f7",
-    "dist/2021-11-30/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "14bfd567241f969de712240f78d83d21dab0bd11ac42da38a2b02da7a59a9dc9",
-    "dist/2021-11-30/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "f44113175429958961148bef66d0ec1b52850c19c035ac83b0d20139e1116d97",
-    "dist/2021-11-30/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "3e5f05f0f5aa2fb8b2e63eed7b29ce67831158648f64c2892b477b318a86e300",
-    "dist/2021-11-30/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "76258605464ea434a2c28c2fd05f1947b2165fa10a2810958397d8352e20215d",
-    "dist/2021-11-30/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "c4f2e0756f8571ed7b1bd82702d91b32cc40af58e0697c2f307feeb5755f93ae",
-    "dist/2021-11-30/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "c466a280084c164ca4a120b184eab6403c80db962c0d2d1f2cb5b662746ec4da",
-    "dist/2021-11-30/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "b6f97111eeab0403c67965d57f9bee2ecdf5f39eb44941070d3cd06745f235a3",
-    "dist/2021-11-30/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "2ab5f013205446852a06f27b326f6454a5b3fb958413a7e00e1d8402413155b5",
-    "dist/2021-11-30/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "49dd5e7e3b8091546ef932f359fc4260e3f0b7ec851f43dd10f471c6fe50a5cd",
-    "dist/2021-11-30/cargo-beta-x86_64-apple-darwin.tar.gz": "ac20e50e745914c8431a5c6993b9dbb6bf7b745e4b45283b230207e7be1bb167",
-    "dist/2021-11-30/cargo-beta-x86_64-apple-darwin.tar.xz": "dec91c3f6eda827d3976b96da8def71ad3cc0b71fbe1b4e5387a464a8bbd85c3",
-    "dist/2021-11-30/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "e11e26ad4fde6109808f4cd752c2a810c8ca81b890b0c09902be981a72c43723",
-    "dist/2021-11-30/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "fb49db7bce2376335f4fda11cc454b3d762bd7f95c5dba85596100bd0c1e148a",
-    "dist/2021-11-30/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "7703eb725703aeffb57d6a2c0c95c44b6e4eed09b4a99b37346ea895a1d51088",
-    "dist/2021-11-30/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "65e0f34d9b4af3b270d8d4752c94b58e54895d180fddc3f4b535406e16b8a356",
-    "dist/2021-11-30/cargo-beta-x86_64-unknown-freebsd.tar.gz": "4624bd8e93bc1c36bccd15b44f484059f485df1c0cd1b8bcf21c4855c85b7ea4",
-    "dist/2021-11-30/cargo-beta-x86_64-unknown-freebsd.tar.xz": "a277a3fccfba30db2942c8303db16e5112d72c7721fe7a777cf24a301b68ad2c",
-    "dist/2021-11-30/cargo-beta-x86_64-unknown-illumos.tar.gz": "37e034e5c83bab47ac5cd502d4f6385af270040fb7eb59221bc02cdbcf949d0b",
-    "dist/2021-11-30/cargo-beta-x86_64-unknown-illumos.tar.xz": "d26eda6fd5533defbf3983f2bb9c07c0cba00abf4c346443080059c4810ef1b6",
-    "dist/2021-11-30/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "909f8bc8dce0276695f1e88994bd21ba2ad4a3ff66b8172e566b7907d9f2531c",
-    "dist/2021-11-30/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "52807fac650c03c9d398ce6e5987ecfd5e8e30b5c4e94c320ebc2a6fd665740c",
-    "dist/2021-11-30/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "3158dcde7e05e9871572dd7044b3c8466687d8afadbbffa4021a443f4973a4ac",
-    "dist/2021-11-30/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "551ef92e71c001fe48804587e8532b5032d419bd139b2f59cbd8c2e308e3c2ae",
-    "dist/2021-11-30/cargo-beta-x86_64-unknown-netbsd.tar.gz": "9dd630b19f6c9ce26d2ed6a1f46c383d6bc3eecf1efb80f15a651ef4408197c0",
-    "dist/2021-11-30/cargo-beta-x86_64-unknown-netbsd.tar.xz": "1f128e4e8f9e98839caf64e68fbd163de1d5323abf40f718643a815081f898ac",
-    "dist/2021-11-30/rust-std-beta-aarch64-apple-darwin.tar.gz": "3aecc61fe4e056326182db5942cd472039f95788d165940df8b53742f70fb051",
-    "dist/2021-11-30/rust-std-beta-aarch64-apple-darwin.tar.xz": "db3cdaf50925184df6a79914cd1c0df0c9782f96829d23428b1a0ebc814fb468",
-    "dist/2021-11-30/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "61df5ab32d3e11243bc2b8506c65af9d8a84a2bc93fc1315d046e20eb048c62e",
-    "dist/2021-11-30/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "42603c786c02ce754b4c756ac0fe4d88574231f5a8d31b6f9a1192680f8eb180",
-    "dist/2021-11-30/rust-std-beta-aarch64-apple-ios.tar.gz": "49e5d2df9b1019e21c14a1b7f8e69515c16d810dc354ddbe2429857214b3c33e",
-    "dist/2021-11-30/rust-std-beta-aarch64-apple-ios.tar.xz": "5323762166729cc7c3c5045b484ea2f50ec0dbdca15d8c7e82f0c29e1247f8e2",
-    "dist/2021-11-30/rust-std-beta-aarch64-fuchsia.tar.gz": "7510b5b538c735362ec6b12beaa9d3c8720c4ea1f686c643fcc40c5dabca5435",
-    "dist/2021-11-30/rust-std-beta-aarch64-fuchsia.tar.xz": "19b4d188923a820bc8424fed062bab64a56d33f8f00d9ba6792331f06eb0cbc0",
-    "dist/2021-11-30/rust-std-beta-aarch64-linux-android.tar.gz": "77a5e84c97f83ea8263fd147e5f5781a61bb5bdbf1cc40a3a8a72becc8dd486d",
-    "dist/2021-11-30/rust-std-beta-aarch64-linux-android.tar.xz": "c17f843d951d9fa72760e3a071557635da83c0dc279887648979277bcef66aff",
-    "dist/2021-11-30/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "6e86b78826f5e3d18b2f2aa4f274a5d7bacadbde8d7cfc72cc89dbcb0455fec3",
-    "dist/2021-11-30/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "e1b1e9eb09e851c8125319432b9fb52a6aa815b7f5bc82efbba7e375aab44764",
-    "dist/2021-11-30/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "a6589e628f03fc7c39345cfa23827be6cf26391848bc576a66c7701f18a01669",
-    "dist/2021-11-30/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "a0cb9706216575748a953b6e36b59875c6bf9b9410d4a8085974e324c0cbb7e0",
-    "dist/2021-11-30/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "c803cfd7c803de2b210d5e9800d44f3365a0b4ae581d987b415fdfb990de1a30",
-    "dist/2021-11-30/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "a93310d2102699602c348901186992c1305a1a20fd0a2e5d8985a4f32e61eb28",
-    "dist/2021-11-30/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "2ce3460b436c8c44e074ce1cb8c81bb2cd37ec8ea8fde1b766f113b39412d71c",
-    "dist/2021-11-30/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "5e65f8409d2a8eb366f29fe994469f257b18e70ad0707be2ca9c144a0b6f9a78",
-    "dist/2021-11-30/rust-std-beta-aarch64-unknown-none.tar.gz": "a4b73dfbf9df497883b2f5ea3053c256838e1e706f312ee02e1b018b9a7f6099",
-    "dist/2021-11-30/rust-std-beta-aarch64-unknown-none.tar.xz": "a70bd19ae1fa41a3413f0a0b6b2beff569c1b16829cd675967a6d1cd92d8dd54",
-    "dist/2021-11-30/rust-std-beta-arm-linux-androideabi.tar.gz": "46eabf68836f62fe8dfb39c54ee63e9fe211ab84443ff17c46b5240e0d08e723",
-    "dist/2021-11-30/rust-std-beta-arm-linux-androideabi.tar.xz": "9a4e53e3e867e9e18959cba32078c4f7d588247b74e156cc68345808d7b7ecc4",
-    "dist/2021-11-30/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "66d9e4de284d7a221f66a2c615d6ec0805dc8f1a91a184cc96701cf98116be60",
-    "dist/2021-11-30/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "1af2fd7a16d51e2f4bd6e1840b935e2cdc7a8f3b3b1144d22b42cea52b9bd185",
-    "dist/2021-11-30/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "cb479e676240ef682d3ad27390bc2498f80a421d321e9423cb923b972ea86675",
-    "dist/2021-11-30/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "0011ba4db5a8310199011d37818818867703bf6fbbcd7e1a7bead621eda1e5f2",
-    "dist/2021-11-30/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "8b192e6f0263d925aac1436887f67b24fa02f31c0fc708c30827f0363f032ceb",
-    "dist/2021-11-30/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "688755d433c1227db1125ee52e7aa643f27f922b21fbe3a5fcaf70467d159a79",
-    "dist/2021-11-30/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "b336cef0e11136ccf5c41669869426a376d570042d3c99eed6c448cfe165818e",
-    "dist/2021-11-30/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "1be7d7f0de2ae63b9dd282efc24531f1146fbc7831b84d9c0cd2c8cbdff32fe3",
-    "dist/2021-11-30/rust-std-beta-armebv7r-none-eabi.tar.gz": "33d49bd069b9fdbae8a6868e2cce6fcea26cfd0248372d3d3c977828b3fc51cd",
-    "dist/2021-11-30/rust-std-beta-armebv7r-none-eabi.tar.xz": "e204295b8b17388d8b4cfc04de5690b4b6a377da12df7c24f930c064da787200",
-    "dist/2021-11-30/rust-std-beta-armebv7r-none-eabihf.tar.gz": "07584d1a4f4979ff86aa8b8be820810366c4fdbda4e5dec93c0a5883804a2103",
-    "dist/2021-11-30/rust-std-beta-armebv7r-none-eabihf.tar.xz": "4f73d8af677409960ac480c254f25547752ffe08b80785dceb6b6f1fdc0b6646",
-    "dist/2021-11-30/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "fb998ae84f383f1ee93fb946f396545a60d4a58f1f0107653f3dcf97e2cfb4f7",
-    "dist/2021-11-30/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "8d8fdc9404422d0519328d6a622262833c5465b1cba62a59951a05f59d6cb15a",
-    "dist/2021-11-30/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "c8abc1c472326419065caed5567bffc4bcfac2af45fafb7f1327b468f26a0112",
-    "dist/2021-11-30/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "d905b6339363b2538bc39607c0fc58dae2b8023b1c3c1f745654a839ec178988",
-    "dist/2021-11-30/rust-std-beta-armv7-linux-androideabi.tar.gz": "69dbb3e17dcdfa9e6acc465fae4427a2596e8bfc024cc18d30201f41bcdd1be2",
-    "dist/2021-11-30/rust-std-beta-armv7-linux-androideabi.tar.xz": "f012832da820d59a791bf39c25e282c2b92bee75377e4fca7e9520162be62b83",
-    "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "bb742536d0d7b664ac7277bc5e45f40d64001da0ff1f9e088edc5240e1b35dcf",
-    "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "6d4c050229400ef1f2e384a4a360569309d1a0828ff07f97c73ca294ef114ca1",
-    "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "c7c354d1bd4071ef69e8d91ee5c020c9aac613ddb2565c9a3a01fa41903e3715",
-    "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "1bfe9acf4bc7f1e58f1e5a721172df69be65e049894046561bc94ed6ed67c24c",
-    "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "96fe9952332d7aee42e61445226793af32995d0f21fde7ebfe751ef2f9acfd90",
-    "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "2f85ea745f03f779306f78ddff9389f4417d826258a90740a76b37bd14b8fca6",
-    "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "434b6eaffa2a4c798b4a6f00997d65c55d9fad24d176bbc54dc045339e654432",
-    "dist/2021-11-30/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "955fd83cc57de91fea9aea3f563c4cb5a2611e6dd24406845f7e8be5b7f25f3c",
-    "dist/2021-11-30/rust-std-beta-armv7a-none-eabi.tar.gz": "45a4818cc22f80252264309263994270b2e15ec8db7ced500cef838f09260fa5",
-    "dist/2021-11-30/rust-std-beta-armv7a-none-eabi.tar.xz": "8748379556a312b31788b5458b74d5d7fb2fa61f29e5528e449d216c21f4e9ed",
-    "dist/2021-11-30/rust-std-beta-armv7r-none-eabi.tar.gz": "928a6b77d3e6e8030c6ee454d648c5f6eb0b79a8beda3d11fc3578cc4556ac45",
-    "dist/2021-11-30/rust-std-beta-armv7r-none-eabi.tar.xz": "428526e30a28a9dba01943800a179b7ba144866f36dd69171a4fd1804345b75f",
-    "dist/2021-11-30/rust-std-beta-armv7r-none-eabihf.tar.gz": "e1e43b61b7826fe4f8063d89896e7b86a13e41ed3a17ef2684d1bded5252b7b6",
-    "dist/2021-11-30/rust-std-beta-armv7r-none-eabihf.tar.xz": "5f6478a196f1eabd6d4b58ebacf89c3635a9488f4b2f145283e9352cff5da7b8",
-    "dist/2021-11-30/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "65b23ab952ed313cc9de94eae473a28eb9b7d9ca8aa432f4d3a08c30484e30c7",
-    "dist/2021-11-30/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "949e3b832f70c3effa2b78363b42caf0720ede57722c360b710773bd7f3e1502",
-    "dist/2021-11-30/rust-std-beta-i586-pc-windows-msvc.tar.gz": "06667714b168e2e0d6e0f3e81cc3fb68940f77aa3cd3495d91ce9ff15502ab9f",
-    "dist/2021-11-30/rust-std-beta-i586-pc-windows-msvc.tar.xz": "9794592856633299de53e697579c75bcf6009c6f05c7bfcadf8c63dfa383b3f9",
-    "dist/2021-11-30/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "ffb8b8ec98f9732602edcf3e4e628327f8ef80712c59ebaab5392503ed04460c",
-    "dist/2021-11-30/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "7f60c2798023bdf3993b443783d3d6dd350abfa3bbdce58ada3e9b3d3c4391f0",
-    "dist/2021-11-30/rust-std-beta-i586-unknown-linux-musl.tar.gz": "f086f349faf5f44b0fbd060f3c40b553aa5a6309a02c08e8a45d27cb3a820926",
-    "dist/2021-11-30/rust-std-beta-i586-unknown-linux-musl.tar.xz": "05ebd51df4b17c22569d69a65d9542b5010beea023e545859a23bb244162b537",
-    "dist/2021-11-30/rust-std-beta-i686-linux-android.tar.gz": "0f2a192b970209d10f2ffb4f88dcb6637e1ed822e47fef8e0d3daf4ca8b250d9",
-    "dist/2021-11-30/rust-std-beta-i686-linux-android.tar.xz": "3aee7e88fbcc0290219a8d980efb1c6d8a1642a1576393fe3b5d400a68b17f8b",
-    "dist/2021-11-30/rust-std-beta-i686-pc-windows-gnu.tar.gz": "251780731ee8c996dc1adb59148d7a0307642e11f3bf767c0caaf5f37b70b395",
-    "dist/2021-11-30/rust-std-beta-i686-pc-windows-gnu.tar.xz": "76c8cd535a4ab4f9c0ccca19986f483de63e7c6c0708e37de653acb80621bce0",
-    "dist/2021-11-30/rust-std-beta-i686-pc-windows-msvc.tar.gz": "ce1b7c98f381f207a26ca3fa5937f5e276eb8f91ef6ae2e0e082370e9ca1c21e",
-    "dist/2021-11-30/rust-std-beta-i686-pc-windows-msvc.tar.xz": "106f655c10d182b6581e87cff881bf081efe9404b52885b6efed4eb0f09a3a04",
-    "dist/2021-11-30/rust-std-beta-i686-unknown-freebsd.tar.gz": "2cac777f7178954e5c19e266d57927ddf68b74aa5a0161e35e096569d0a6946c",
-    "dist/2021-11-30/rust-std-beta-i686-unknown-freebsd.tar.xz": "abd915c242fdd2e8f7d53291b2d84d269f9c6f4c4059c725770c3e47e50c4758",
-    "dist/2021-11-30/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "f680956e937e421c7868a22ec3ac2a6de7bc8203fae17937793914f4a9fd1657",
-    "dist/2021-11-30/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "15c71b8a2e8604a49240f5d6d0da65c40c8c207f1ebec943cb8c50cd7a51d879",
-    "dist/2021-11-30/rust-std-beta-i686-unknown-linux-musl.tar.gz": "71c15bbabb5bcadb603513c73e40a96026fc8f6d5c82e9ea9b6569fcc22d5af2",
-    "dist/2021-11-30/rust-std-beta-i686-unknown-linux-musl.tar.xz": "4a9af011d4a2b63a0357c6367210fbf4b6e116b5388ed3a62b758a4bad1fa77f",
-    "dist/2021-11-30/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "c44531c5467c1e01739f3796db1f59c4b6d6483f4bb8c398c751dbc30ed550ed",
-    "dist/2021-11-30/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "0ec54d445e3c24bf7aa8ecdca45f49abfc2e4013c7af682d7134a5e52e752d23",
-    "dist/2021-11-30/rust-std-beta-mips-unknown-linux-musl.tar.gz": "3ea1a25b04112d83771e7b713ff8d33418bd18a7adcaaf6cce68f537cb27fefb",
-    "dist/2021-11-30/rust-std-beta-mips-unknown-linux-musl.tar.xz": "c904834d0fa015d24ba0e929e900ad06bfe773bc4a439f9bbcd8862a5065171c",
-    "dist/2021-11-30/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "498cda7a23e81ed7563650deb320361c8cffdc10de13ce143175e77f720600ed",
-    "dist/2021-11-30/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "bb0e95d7fad089cc84e826adffc416757df4480ffdfd09547625950b13b9e934",
-    "dist/2021-11-30/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "87ae1f563963370eeaa3f46d568339d5589e4fd509d21087db43ca2f1d6a1daf",
-    "dist/2021-11-30/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "da6268585d69c9c71c92dadb658bc7c055b5ce4c87abc52b5451d1111c1675dd",
-    "dist/2021-11-30/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "93c67427050266f49dc367a1f8e694989424664f740ae3911f78f1cc53faf35c",
-    "dist/2021-11-30/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "03f9a6e921555954b33fd7f446e9093ad4b631c86d001303e4c47078d0e1d385",
-    "dist/2021-11-30/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "6c96a53e86f71965f1922585469501504b79c3347d09409033f871b1c9cdc856",
-    "dist/2021-11-30/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "000e43f7e40abecd402242455f8a3d60692043ddb80bd15dd6f52acd1c5af096",
-    "dist/2021-11-30/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "7ee55e1f5a63b52d7b87882fa4131fe848d18dba819d46e16ea2435889d84722",
-    "dist/2021-11-30/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "b8fc28ffd7d97e76913755bedc2f9e7cec7150e036d13fcf7e50dc5a2422d1dd",
-    "dist/2021-11-30/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "af81aaa9bd624f57168762dfbae39853ada92043809bff953e108e97169e5732",
-    "dist/2021-11-30/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "37357e40af421ca5b4d2b95f19eca41ce016404ffcce8abea45e08721664f0e3",
-    "dist/2021-11-30/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "cbbd98fd3ee6bdd3c01e590c2f10367ec38d799e02ddbc1b0e31027684a356f6",
-    "dist/2021-11-30/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "defda4e2ef2f3baf8c7d2a9159d17ca439004687f0b6714826408b94d4f0aed0",
-    "dist/2021-11-30/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "201c5bdc1dba11e039bea9257e17ddd2f50b29448b070fc0edb4a7a9f4e45f45",
-    "dist/2021-11-30/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "0319b07244f443e254e10a04e75633b293faffc5896ade44c05dde0739356f38",
-    "dist/2021-11-30/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "54e7cb5a1534ecdbd484ef304f608eb48464ae2c2330958b65b8101f81291319",
-    "dist/2021-11-30/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "aecedf5ca4d91e98ba3c4faba64699d79b3fd4877f880840d492b4872ccb924a",
-    "dist/2021-11-30/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "a4cf3bde61d46484e36fd41386840250e0c031414ee422bbb3d37f7ac7489ca3",
-    "dist/2021-11-30/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "d93e2a290aea3075cd61b950ded4c3756611acc6a59ba7efb9ce2e4dbac76c59",
-    "dist/2021-11-30/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "69c9f09416b788d93f54734a953ed8dead2a31e1dacd6e67a6550529385b338f",
-    "dist/2021-11-30/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "808a02952a31ae3a171849dc217763f5cd142622e92ae2b383014bbe37e9b551",
-    "dist/2021-11-30/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "67e6b61d822cfc9f95a2808917601cf3d2560d636b12a19ee29a790cc06e8235",
-    "dist/2021-11-30/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "7310493bc6f184b401650fb399015be29a8df009e55fa1cbfbcf9d9608fe61e2",
-    "dist/2021-11-30/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "fd4db925d7eb598f210ab2d96f692cbdb627acbd6a8976259411a4d2356b8728",
-    "dist/2021-11-30/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "b5b0394ef612188fd094e355892aafe4530758fe38dc8859ba917cb2febe028e",
-    "dist/2021-11-30/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "3b7c3ad97393bc702dbd71bc819c0e5f6164cf471171c7c48cfffdf5477b35b6",
-    "dist/2021-11-30/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "21e6f247a6663918c6e38782e43211224d50d4de22a9162be0c5f6d6d0a9afea",
-    "dist/2021-11-30/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "d0c9bd56dcac12d7174e11f2acdb16fba41ffb3aba71b6b1b4b49ce7fa115f6e",
-    "dist/2021-11-30/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "c89adc1cbdb7bfa27f5bfdac38b5ff084eafe081b27548dc243bbff378ec7118",
-    "dist/2021-11-30/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "3e6f8a86901c1350c54bd89e156af029978f4a25f578ea26f49a1f3332da2187",
-    "dist/2021-11-30/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "43e74dbeb89547be1b3ad1b532bef97b577530a8b19b825342efb72d91d4b0bd",
-    "dist/2021-11-30/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "c8c7a22e63353e7c7766e254c3fc0b0277bc8265f1123a38705bf319a7d99a19",
-    "dist/2021-11-30/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "1759ca2de0ff890918a0f634782557ae2b3181e543790878093f303ede45e215",
-    "dist/2021-11-30/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "a9ac36f2b4e88ce2f2789e9df46ae679879c111594cfe82b538e4067adad2b5e",
-    "dist/2021-11-30/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "6260f0616828d79898165bf42875881dc5253143d940ac951b7f295553afb8c9",
-    "dist/2021-11-30/rust-std-beta-sparcv9-sun-solaris.tar.gz": "42d3e5acf2475d732ce5afe3c2ebea6d332c137d061aa256df75b7ce54c16b16",
-    "dist/2021-11-30/rust-std-beta-sparcv9-sun-solaris.tar.xz": "7f84ff29dc36a224961e87d40cd6e531c9309bdafaec5de2b043aa89af511552",
-    "dist/2021-11-30/rust-std-beta-thumbv6m-none-eabi.tar.gz": "6bfdf4e59ac3f9dbde2fa46797bd9bb9cbda232c0d507f04bafd937e88945cb7",
-    "dist/2021-11-30/rust-std-beta-thumbv6m-none-eabi.tar.xz": "d12901a4efc8395df3c1ac137f86c3da07477277fad138edb49d5c4382a3a114",
-    "dist/2021-11-30/rust-std-beta-thumbv7em-none-eabi.tar.gz": "38718b50fa2acacc0fac98931a5714df38feb8370fccf8d7a955de3b2c117dd0",
-    "dist/2021-11-30/rust-std-beta-thumbv7em-none-eabi.tar.xz": "9753c00de1117a5fb9bff4ce2a4434ac6d3d06a1b4b3d0cc44ddb590739b9a0b",
-    "dist/2021-11-30/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "c1eb35c914ad1a762cf550d54b7ec80cb3a8ab6ab39f5c89709f88e04eeba46f",
-    "dist/2021-11-30/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "3c092ac130633f327a0afc8bdf8ba252f05d9b0050383122d7ba31cc3f5ddfc5",
-    "dist/2021-11-30/rust-std-beta-thumbv7m-none-eabi.tar.gz": "fb391d1199eab0854228323d08dd8b27709175697532e4b47e9dab6f26f24a8f",
-    "dist/2021-11-30/rust-std-beta-thumbv7m-none-eabi.tar.xz": "82347d3a0a123c430a526486dbd8c424732181eede038e2f91f1504d510a755b",
-    "dist/2021-11-30/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "0cb559fff7f8dc35e5279217ef6fe7c2b5fa3d68f5ca82f258b6885f42e8d144",
-    "dist/2021-11-30/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "ee1fe1dc9fe620743022939cdeac3ab34135e61897f0707c3b1a0a1b7d730360",
-    "dist/2021-11-30/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "bb8de6fe10aa624fdd63484403e228a5c592b94d4aac95e2b2401cd8b9472f0a",
-    "dist/2021-11-30/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "1bb7f7ac88e250534d89f0b0dc74f13ca563bad53956be74418d2aef28d250a5",
-    "dist/2021-11-30/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "0aea9f5cddb136591d105ebd3607a2e1f402f1c707cf33f21fb5cf1d30101ee0",
-    "dist/2021-11-30/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "f547622b8f052c6290c530d506d8ee314f90c81ace562a0a533b6ad2ba00b987",
-    "dist/2021-11-30/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "80f8f7c613c7ff2097f5c346b3ac4a5cf750167277f28655e0263b05a231668d",
-    "dist/2021-11-30/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "a57b4489a1d46ad3fc303a3b2dd478df66407a3e2dfeb9c12860a543ae5210eb",
-    "dist/2021-11-30/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "6c4264b2bcecc951c39626fc1cf8de36f1eadbda31a552e14274f728978e16a5",
-    "dist/2021-11-30/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "ec72f8e861eed6b5e2518b46cd8008d3bd2b6f2a7a42784a2dc8a6184d3ecc62",
-    "dist/2021-11-30/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "0fc209babd43546d04b3fdd27ce77c96d75aa5eb6595f00586a19a17e4530b59",
-    "dist/2021-11-30/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "ecdb8152992b4a9779aeda2b4cc638163ac24faf45c484f27316a6b3ff0eb297",
-    "dist/2021-11-30/rust-std-beta-wasm32-unknown-unknown.tar.gz": "52bbea99f2405f35f58d5448c353c605c2a87e7546e95b86d8baa39b4fc7a9a2",
-    "dist/2021-11-30/rust-std-beta-wasm32-unknown-unknown.tar.xz": "47ea301d79eada8898907af226b39b4c73ac1fe974963139aee78c3567ee53e4",
-    "dist/2021-11-30/rust-std-beta-wasm32-wasi.tar.gz": "dc9ccfa3e46e4f3b0e11de8a83885695ab154a2211fa89a20670db116d63a4c2",
-    "dist/2021-11-30/rust-std-beta-wasm32-wasi.tar.xz": "52d890b402c7e7bb7c0f9b34f2e216f0937453ab42e7c4ce205739bd64ba7dc7",
-    "dist/2021-11-30/rust-std-beta-x86_64-apple-darwin.tar.gz": "0ccbff8a582047cd6d2a6b30387ea73cfce7e0c61eddf516126836b9f9ca86ff",
-    "dist/2021-11-30/rust-std-beta-x86_64-apple-darwin.tar.xz": "cab55f71575d58aa7213a7dc4cfb0704ca7faec7203c545aeaff178eebe40436",
-    "dist/2021-11-30/rust-std-beta-x86_64-apple-ios.tar.gz": "6863523669b65464bd52e1a47f6decf868cc93d2111ffc222bb4a032a0095e3f",
-    "dist/2021-11-30/rust-std-beta-x86_64-apple-ios.tar.xz": "d5c6e65a656621891f387861c8259116dd9a8ab14e13ea10e93b78834e1d334a",
-    "dist/2021-11-30/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "ec7130bfff74b7226fb5d0f311dd399f7628cb59ce06b4bc9a9f394067855eda",
-    "dist/2021-11-30/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "0f52f00f03126aed0260cbfdd9790a62f9f4ceb24e2a3a6d80e8a15a1b4a09c2",
-    "dist/2021-11-30/rust-std-beta-x86_64-fuchsia.tar.gz": "1a3f4c6c1528050820b85e07aa96af6588c7d61935108cb5110d1e0c964142e8",
-    "dist/2021-11-30/rust-std-beta-x86_64-fuchsia.tar.xz": "fe9488c3476e931440ad487a4cf265fdd3c01e18c9e43b33f51b9eb078821282",
-    "dist/2021-11-30/rust-std-beta-x86_64-linux-android.tar.gz": "c7205b1cdcdff00d91a3991b1f40674b075c34dc0877de4786da5ab85e3b6cfa",
-    "dist/2021-11-30/rust-std-beta-x86_64-linux-android.tar.xz": "87a3cfe8992ad615d5522d97ace91dcc86057d060d82b581df206f2802225a0e",
-    "dist/2021-11-30/rust-std-beta-x86_64-pc-solaris.tar.gz": "cd9eeb26fe909e38d8d8129829d19b4d04d96014496cc7f2f4ae077b94f2aae3",
-    "dist/2021-11-30/rust-std-beta-x86_64-pc-solaris.tar.xz": "b6e59180ff89f7e460fcbc246802e6441c71600774ae5cb2d9af464365a642cb",
-    "dist/2021-11-30/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "45e07be14211ec7c9f3c1ad0eb9f7a9b422b10c842d5d0e8b0b498751ab7ae0f",
-    "dist/2021-11-30/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "593f70209f3b5b4e126d57ece0b1adefb4bc1055cfd168779d854369985b2b2e",
-    "dist/2021-11-30/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "6e14f3431da08f63d82e5b1e2c56fdf13f93ea7b6660dc64b1c855d00c008257",
-    "dist/2021-11-30/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "6e6355686d22213d27f5dbec0b7ded38532e79ac904bae978a8eb5fc880916cf",
-    "dist/2021-11-30/rust-std-beta-x86_64-sun-solaris.tar.gz": "39bdaa250d8f17914602a2185c51014f7fbfb1e30991816a432c3897338b52a1",
-    "dist/2021-11-30/rust-std-beta-x86_64-sun-solaris.tar.xz": "ebab0e4b13e0b3bdbe0ac858d5a4ca28bb813854aea1d8ec86d8e220c68b3442",
-    "dist/2021-11-30/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "a700f1736b96c4e7237305dc98a79163b07127f0aac1f436415c233b8495a5af",
-    "dist/2021-11-30/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "e94ecf7d1c9a5144577fdb14b7232b11dff0ebbfa8aae8cb4884d4ed9c5bae77",
-    "dist/2021-11-30/rust-std-beta-x86_64-unknown-illumos.tar.gz": "209dc9917790c2be8777c597e19a9f43301aaaaac3c9731e9d0512e6918334b9",
-    "dist/2021-11-30/rust-std-beta-x86_64-unknown-illumos.tar.xz": "6e4810c7484c231f0edb15ae5acea822ed5d868eaf041438afea4b6ba38be35e",
-    "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "df952ee1385da9457c4e95dc08ab59ca915f5f211738982f8db3684cf80967fc",
-    "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "62d7383ee21b0a7d072b15a9877a922f8dbcea42d910c2cb3c4129152b26ea9a",
-    "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "be28225516fa38edd34e1af5f051d7c8ab5f433cc5814df199bc451285d95e0c",
-    "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "1a6fdfac24feb34744daced6c6545c844ff13d5e5f14620520d5ed4b85be8742",
-    "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "c0f098faa0c9de6a8e82b80dfe44bfa9d4482e118259c33452ef025885ceab6e",
-    "dist/2021-11-30/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "1d1ed7cf8fc16efab3faab9ef5abadac9ab98d3b60522fde0612ac0b256de528",
-    "dist/2021-11-30/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "1ed41e8019480cd151a9ddd0f080afc56ed0afe47cfb7c6b5a6a2473ff6e7e81",
-    "dist/2021-11-30/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "849c04115660abdf1d4460aef2d87021c6ad52423c83dfed3c2cec8e380ae6fe",
-    "dist/2021-11-30/rust-std-beta-x86_64-unknown-redox.tar.gz": "e3a35d33b3282fd156482c85e19817f78dcd964de8b712a6e46b965dc60d5204",
-    "dist/2021-11-30/rust-std-beta-x86_64-unknown-redox.tar.xz": "d5bfbb1415a62547b9e2a24b770a3c6e4d531101cfb2360b7a7de34d0bf18974",
-    "dist/2021-11-30/rustc-beta-aarch64-apple-darwin.tar.gz": "28beba0ff958b93f85618e49f13f4062cefacc82f6b5911d42f00515f99c5abe",
-    "dist/2021-11-30/rustc-beta-aarch64-apple-darwin.tar.xz": "07c6a43130112c93745e729c91669243cd28b73fafc7d9b32b4f22650db7bcad",
-    "dist/2021-11-30/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "9e70dc74c4428438716d14861797380ce7f6617bc93b83c74fc1a6f8aca99392",
-    "dist/2021-11-30/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "8f61ec8129b7b0bcc6b329337e5e0323054a438e999615687a18fdc42a8d0692",
-    "dist/2021-11-30/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "bba3cbfdd2842cdf8f2698b709401db6a641227d1742595e3959f1f0ace37c5f",
-    "dist/2021-11-30/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "fe74ad76a2cffdff0a2fb953f31b73d80a0bce75402bf65f01d250fcae6ff779",
-    "dist/2021-11-30/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "cde952fb3c38a969c0743d2f9d90e256db8613c463a4b23d6119656570978eb5",
-    "dist/2021-11-30/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "f2dd88f1b4ec97aaaebb601d20751d50536e85b2cac36740abbc03fa8a4d0d06",
-    "dist/2021-11-30/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "1a4414987e4da2c8086590fe4ad531f78862443eede3bc9069efb424900746d2",
-    "dist/2021-11-30/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "1682f8bde2562d4b9183fa512bc1e54d2a821fd9f63208a51489f21deeb7fcfd",
-    "dist/2021-11-30/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "ca40f3c5e8fd8bd6d89d3c0a3ad4d767353c1b4138e2720371a275c9c52c9117",
-    "dist/2021-11-30/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "c7afe4eba5cdb02a2e8ae224a0970c8aa36ef429ac298b0f98ff41a0d911aad1",
-    "dist/2021-11-30/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "6acd677fda38aea2b960f2af6438b30c3b6bd759bb3e56228a1096445ddd100f",
-    "dist/2021-11-30/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "451a2e139771f39ec09a7cefd48885ec30f732668d50c750d42e6c58c250f8fe",
-    "dist/2021-11-30/rustc-beta-i686-pc-windows-gnu.tar.gz": "a1df7d105231d4941a55a9f850d39acc201a99dd408d523935799b70fec30c6a",
-    "dist/2021-11-30/rustc-beta-i686-pc-windows-gnu.tar.xz": "3005718736a2a0fa3a4f1be10239cfb467e9cabe6ce366f9909826bd3c06a990",
-    "dist/2021-11-30/rustc-beta-i686-pc-windows-msvc.tar.gz": "695039c6737fb3bfd325fbebdab61aeef80ec427ae3d40d8b82e8b317e147fc8",
-    "dist/2021-11-30/rustc-beta-i686-pc-windows-msvc.tar.xz": "7a5038b7299de71d3677042647fca501984d1f2a52c1d84052956ff7854622b3",
-    "dist/2021-11-30/rustc-beta-i686-unknown-linux-gnu.tar.gz": "d21dd4c98d38186544aee9b22b439d67d77c0a740357dfad7fea3c4a9b8d1332",
-    "dist/2021-11-30/rustc-beta-i686-unknown-linux-gnu.tar.xz": "e62a7c9809de668343323eb9fa1a1f6cc302a6e161e64826e9d31bd202f2f472",
-    "dist/2021-11-30/rustc-beta-mips-unknown-linux-gnu.tar.gz": "b85eb1bff16384b4f6ad268a01bdcec539b9ea412abb6d64618521cb0e63985d",
-    "dist/2021-11-30/rustc-beta-mips-unknown-linux-gnu.tar.xz": "ce79b36723a65419e03ec77ea14680791d683e5e04332eebdf59550bdaaa164d",
-    "dist/2021-11-30/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "e778edd911e09c5c3b46aeccbabcd8ead78dd38086206d03406fc8dce52806e7",
-    "dist/2021-11-30/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "10afe035ca7d3a967b467875b1345dde8bdcd3f8c4af1e917bfa2c676e0fec70",
-    "dist/2021-11-30/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "6b6c3386ebec138ff07a21d3f5631263219c226ca146bf97fe0a7bb9fee9d0c5",
-    "dist/2021-11-30/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "5ff6430623d0f3aa14748f371e34072aba126a16429928f8f99172190f369fee",
-    "dist/2021-11-30/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "369ad16e85e4f2956e400105e6d8374ff64c473c3c3b61ae4d916214d5f922da",
-    "dist/2021-11-30/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "1c8adfb22f724fa98f30f23378a28729e144f6ab9bba54adf13111ca4648ed78",
-    "dist/2021-11-30/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "b3e270c6272420c31ee7bed8ed36c113c879a384fa5b85af0deb7d43a355ca2c",
-    "dist/2021-11-30/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "a21cdd8d182cc64ceaa83e522299860c2710dee780e8f49ff107a73fbd73c3ca",
-    "dist/2021-11-30/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "1a81076b8e49647b61761a38ed283a9a71b326dc321920f7be453e0e15ae2465",
-    "dist/2021-11-30/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "3f8ce23f81623a00de63ce7e82e448eec0901a92f908e6aff362807bae14ff84",
-    "dist/2021-11-30/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "eaa3b365bd91a5770db85e8541ee28c99988635521c0f2dfea05218172f11a55",
-    "dist/2021-11-30/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "3f856ae24c4737bf1928025a10712b6d856788d988fb5018631c525d13b68e29",
-    "dist/2021-11-30/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "c672cbf2caef81f7ab923ff7c6a05f1865057278180a686f810ddc71dacc49d0",
-    "dist/2021-11-30/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "bda5d2234aebdc175c87da3b77d050c56bced21a794c416bb9090c0ae3374be2",
-    "dist/2021-11-30/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "59e01371664f8d39c7a06c205af0f5ab9aabdb3942be4f493d05ab71047619e8",
-    "dist/2021-11-30/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "de956b5275e38e0b4223819973e85f5f65c409addd786f7ac2d525a79c3f0c92",
-    "dist/2021-11-30/rustc-beta-x86_64-apple-darwin.tar.gz": "4f78d90362488a866ea7b1cccbc61f925d94034b46dfa775dea75223e67d755a",
-    "dist/2021-11-30/rustc-beta-x86_64-apple-darwin.tar.xz": "3520d028e9370087cfa57eb7225dd76c008cb08ffb01c8101aaa86104f427f12",
-    "dist/2021-11-30/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "f954349daa7dfd819ec0a7335a47b1d3b2ed0138eae31c56288d9c523cdf56b2",
-    "dist/2021-11-30/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "ca046d8fca5fa48117c61c70a21176d9220a3c62af9fdc9b899c157bb196a5b5",
-    "dist/2021-11-30/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "61ae4421bdf798a5ca1a8bc8c8521dfb29a707e40d382dbd2e155f134956ac33",
-    "dist/2021-11-30/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "495076dfc2fa0b8d96613e34f867de9d43483984a8bd6839bf273c2be38039b6",
-    "dist/2021-11-30/rustc-beta-x86_64-unknown-freebsd.tar.gz": "828526bc23ad8802071bf4f2984faf3549139eb4ce8ebb9ba8711c196d2bf437",
-    "dist/2021-11-30/rustc-beta-x86_64-unknown-freebsd.tar.xz": "fa2464350b2ac29bec6751c551cc45b7af92c25d2cf1109397e724802d4859cf",
-    "dist/2021-11-30/rustc-beta-x86_64-unknown-illumos.tar.gz": "a1d9719668ea1887d6202c25b9dd2b7d40bdd240f3f753af77ac93f126c84c38",
-    "dist/2021-11-30/rustc-beta-x86_64-unknown-illumos.tar.xz": "4b36f5d448bf022f90e284c22a44e0b87ef8518ec93a297ceb703eb612ef80d8",
-    "dist/2021-11-30/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "63e654f5e8707a0536381025bdbb43d498c70a29a5ada0ecdb12e23844cc9a9f",
-    "dist/2021-11-30/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "6b5b74abdcb1cae42620cabc142a119b58823e9f2ac0c3151e087a76323c5cae",
-    "dist/2021-11-30/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "f3aa2d52ce5da066c59de609ebd5df60ac908c7e0db23ac4afe69b927ef2a974",
-    "dist/2021-11-30/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "6e8858dbaf50a8211516e5afa83e4133d878e0d4b19ba4a3e4c3e51cb80210b7",
-    "dist/2021-11-30/rustc-beta-x86_64-unknown-netbsd.tar.gz": "9028dd44728092ccaec86f415abdb3733f3ea58ab7c3d736e96e27540cc66a2d",
-    "dist/2021-11-30/rustc-beta-x86_64-unknown-netbsd.tar.xz": "c6720fd231b54a04e1ba3ed3fe333b1d8ef5b771ce341b4c112169a293bf713a",
-    "dist/2021-11-30/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "d987783ba5117529b325bcf6f5e7abd9eee42b5ea86ce5109a4fd3f450af8062",
-    "dist/2021-11-30/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "5d5838733dc64e302991465c1f371fde855ee410d42d1713ddc1c471b469e1a8",
-    "dist/2021-11-30/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "8593ab35bb800312d6fe4c4a4d151feb26187c6db0d0d5ca5e3e98a007f8a4ff",
-    "dist/2021-11-30/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "a2ded0420cc1d98df255c7ef93247b9a6d3d9ec22e42c477305dc15ef35fd329",
-    "dist/2021-11-30/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "652275e77d73f122c12eb952338661562a48fc76164d6549158abc14fb4e4a4a",
-    "dist/2021-11-30/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "fbb49b56bb11348e07124d8216b8f8b6e26d8697abb05afec0ddb07a456b29e5",
-    "dist/2021-11-30/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "817c7ed90ab8cdec1dcfc8571391a714002b49fd20da0ae32135f57d233ffbfb",
-    "dist/2021-11-30/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "cbd8674c65babce944bab6a6f013d44a2c7d6829434a6b97edb1f1e1df1c076f",
-    "dist/2021-11-30/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "66b13ffad073bc624ebdef219e61f8972fc6be354aaf1f8ede58a3acc01314c3",
-    "dist/2021-11-30/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "11ecfef218376fd2232ad552526b39173c5269130f02e408a7492762cde87a6a",
-    "dist/2021-11-30/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "07ad99e019141843f5d6f8c302b9d20c7453ebead79e9711af33c9c8081b9e22",
-    "dist/2021-11-30/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "6656be84a9b5a63083d63e3a87bc928b424109efff48e3a6770e026c6ea7c2e8",
-    "dist/2021-11-30/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "155422628d41ce9730f4503bffa12e396b58692c906828acf15f0dd39b3d491e",
-    "dist/2021-11-30/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "fc75c3836489bda30d340132d0d5ab8ee7f7c67617e4dc66a9eae559bbdb0421",
-    "dist/2021-11-30/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "181d557c8f73c8f22ed63a8f98e53f6d88871fd694173aea70c53d42c0c55ae2",
-    "dist/2021-11-30/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "5defc562a2f0ced4539006692cc969cf89756637f5f5c62be0276dfedd6f3db6",
-    "dist/2021-11-30/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "f28b3fdf5425e7b782d0f78ca95613efd87b2b0d14d44c4490f17d4eb452f183",
-    "dist/2021-11-30/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "b6cebd5a23bcc504d05c8dd79654baf2ab45b162c59b7b843e24efb7e2344011",
-    "dist/2021-11-30/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "c59850b28fcfb1608c7e91890b8628ac201b87b4d9af7e9fd019e3e4a137c033",
-    "dist/2021-11-30/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "ad808569083691ba31b0e10222f9dd01822ade91689bcb060544f28b99f2a299",
-    "dist/2021-11-30/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "8fca357226b91cc712b888c0a62f9e52b121ab6d9815ea5f53bbfd243b895b69",
-    "dist/2021-11-30/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "7f5451fe6946c16a7ba404c8bab33816d58d478b1dc0ea1ce6b85befe26ddf77",
-    "dist/2021-11-30/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "7cc76ce31cf59f1cbeca87a46c996e905f048acfc70d438eae2a32bb67fc60c1",
-    "dist/2021-11-30/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "429bacebe2a9f1478a00b1573fe4e1b071c6348d800182993c8b5d8ba54d9615",
-    "dist/2021-11-30/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "701a12b5a4a689e6b2ef260e35ed2d22c00452cde5e18ce0d886ace37e81964f",
-    "dist/2021-11-30/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "0ef78c91a3220226619f20b28bf67947a56ff31f369d5ea7bfc2aef356060e42",
-    "dist/2021-11-30/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "0765a3b65315bbb1381927eaf6f65f16fd09dddab41d7398e483bf001ee7bc3e",
-    "dist/2021-11-30/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "c74b0833f995ffad5c812ba130f423485bd8297eca0c4eae227852a88ece8521",
-    "dist/2021-11-30/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "3c9d5a35ef1e459ded4dcdcad40bc5e3bcd5b2821cf4f46dbaf2c2c3259fa3ff",
-    "dist/2021-11-30/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "0aa8975a6dbd103a4764ad643de6094bd6911bd3a90d46e24ad1eafcea2870e7",
-    "dist/2021-11-30/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "a0ee2ec59ed07ba9c9e48076c954f5c6e4d39809d9e4923337db2627ea279c6f",
-    "dist/2021-11-30/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "e712fa72a41dedcd50c6531433220904b9627fa78bfa15cdd96d97161981cb77",
-    "dist/2021-11-30/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "fc7809520a4a41ccb0ffb303c7bbc96443308387890ebdb65a25c3697a5c3eb4",
-    "dist/2021-11-30/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "84a8fa7468b9e59465f85607f84960e11faf0f37bd766d55b6be985db89d0d17",
-    "dist/2021-11-30/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "2703dff8cb1c0ca08787f1c7715885c5b09919c040783ba98bd74f8fe3af704d",
-    "dist/2021-11-30/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "a3e25cc857e990b467c804f41e23bfbe8ef02630b48703fc1c7fae692e16eb80",
-    "dist/2021-11-30/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "659a9ca0e1296f817cd9f90fed9ccd7d3c7c3e7eea7e9c437bbeb2d951a2669c",
-    "dist/2021-11-30/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "21e83ac3b148f0f690cb9a39b385fb0d5a82d6eea9ec46d4d4445b5a660c6d7c",
-    "dist/2021-11-30/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "c8e3300a426cc4a80ba4f1cf0c6822d9b883f24c486b991f2056938be778d43f",
-    "dist/2021-11-30/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "55f1f7d84828b3cc5d13b10e549a74f2f1df11057ed48e75fbafc0d3538daf03",
-    "dist/2021-11-30/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "99bf70cee39b2ce73dbe5827fe3d93e45241faea284acb3f8004cf7e700e1704",
-    "dist/2021-11-30/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "dfc569d57211eae74a2cde5db180d2f2f44bca04f811655ef1f8d8c2154b97ef",
-    "dist/2021-11-30/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "679d69ba6a4b460f9672f1ec1c2939ac41ee7f911a2a74eaf6db477aa088e6e3",
-    "dist/2021-11-30/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "3b9a899fcf40db84be8bd14e7c767c572c7d8c7c85f90997b8278fe8726413ae",
-    "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "19be469ab711dcee7a7243e865efc5addf8b2cdbdf15150a2c367692c45b9f94",
-    "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "789c7129e235b65860a514fdb38f01ac195af610d4ac6a296d272a6f36d72344",
-    "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "18657363783d0967d871ee1ed8905b3db0c3b761910fb06ea10980ec6b5ca082",
-    "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "8b272546a9eb8b23724fbec5577fc0c917a23e994befc38ebfa797957df03b9d",
-    "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "4e1de312f07fb98845a881b44c2a76ec9abf61e5aba46e8e384de1cd297957a3",
-    "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "a13ad29e2d06c9df233882d009ba8354d92d2fb29239cadaf858b9abc8b477d9",
-    "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "aae38bbf1eb7e0da50eb7f226897dc85e88b5e008ef901a93dadb0550f4055ac",
-    "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "757564eaa1a339d37b59da304bbc7a846bb883a73c62b78df39dacd947606ec9",
-    "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "5f3a83079cb1fd7d8b9be44d0df7b57c6dc79da8e1762eace67c122cffc2d4ca",
-    "dist/2021-11-30/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "e47ee14a1e679ee5f23936ba7d7de13dcba082c7f32e366be7a990503c91f6ad"
+    "dist/2022-01-28/cargo-beta-aarch64-apple-darwin.tar.gz": "8c62238c1d0a6ce177f59f5fb92f535433bd4be45d146def6527d0cdadd35422",
+    "dist/2022-01-28/cargo-beta-aarch64-apple-darwin.tar.xz": "bc6b381296fc6c882af149f39f2a3b9de35fa4c89ce95f41a2ce1aee2fba051c",
+    "dist/2022-01-28/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "ca2ae341b04e558315d74b62d63ea860aaaec633d5fa604a0af73cf197e540fd",
+    "dist/2022-01-28/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "f570b2a8902931e49374ca326a2fdb3294d688dcbd053e767e3b01e2fe749dd5",
+    "dist/2022-01-28/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "d22d886ff0017682c27aed6e43e0a3519864847a36ea7546bc7924340098ebbb",
+    "dist/2022-01-28/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "cb2221cd5c4e6251bcfb5e1d6ae49bbdb3d6463258866cb3971f86db4e4221de",
+    "dist/2022-01-28/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "64046c814a93d4771e6c835afe30303afeb4c511282d2fbec1a716334ab1d630",
+    "dist/2022-01-28/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "1f3ebb839986c3548dfff2da3c716e954bb0eb40abf823e1f1933ba79425b85e",
+    "dist/2022-01-28/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "50c894bf151d8d8073d667712097c1dbb254c99ac1fcdadd495a7928d21a957a",
+    "dist/2022-01-28/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "e6a52d5cccf994e65240983924f6b8469669dc710715060730e94e67dbd74877",
+    "dist/2022-01-28/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "91c47a849fd1ffb764508d8a287bb717627d3a6fb12171df7bd427490e826dda",
+    "dist/2022-01-28/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "a493a29a384a9573ab29ce9f366dc419907500a01e389e8486a5f5aa57c8394b",
+    "dist/2022-01-28/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "c55187e202b699570db7ae49a1fbd615696f30008be60a3bd5c9ee708925e4a5",
+    "dist/2022-01-28/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "288ea72dff7dc1882b51b4d4e73ac8d05f351da44a99d3ad5ee50b231f189f1b",
+    "dist/2022-01-28/cargo-beta-i686-pc-windows-gnu.tar.gz": "a746316d99b1943cd63c485180c512ddfc7d394fd76a51f9ed56dd2dcadc032a",
+    "dist/2022-01-28/cargo-beta-i686-pc-windows-gnu.tar.xz": "4395f831aa0a9413b5733902df58c6474913c53f46600ffe6f694c4312dc9d70",
+    "dist/2022-01-28/cargo-beta-i686-pc-windows-msvc.tar.gz": "d1f3441addc86e7b5bc21fbb2550e6a3e59a818027137ce2bac1b3208168726b",
+    "dist/2022-01-28/cargo-beta-i686-pc-windows-msvc.tar.xz": "4081e7ab2bb2208d636812f74a9f5b7d3c057f694d40589aa3affe3df35d0981",
+    "dist/2022-01-28/cargo-beta-i686-unknown-linux-gnu.tar.gz": "ab9bc43f20705cf5899d35381f3bd432a346c85762182a8f3b61adb93149910c",
+    "dist/2022-01-28/cargo-beta-i686-unknown-linux-gnu.tar.xz": "b50084926003b1e7b8f3a6a60f41a7c1dce764b1ce367567c112293aee16c244",
+    "dist/2022-01-28/cargo-beta-mips-unknown-linux-gnu.tar.gz": "79bebb05444b1288ad6faabc9ed7365206aa8321195285565130017cba61e3d9",
+    "dist/2022-01-28/cargo-beta-mips-unknown-linux-gnu.tar.xz": "ee12f3ae5a08329a482aaa0764e4b674337c659fcc10132220d67313ba663634",
+    "dist/2022-01-28/cargo-beta-mips64-unknown-linux-gnuabi64.tar.gz": "597e2021c3d56d821f91ff26b65ca31c837e6451d7f12d04494208f0b0dac847",
+    "dist/2022-01-28/cargo-beta-mips64-unknown-linux-gnuabi64.tar.xz": "23976bfa23b9a4d0e211daa4fa50fc34e57af95c05c2cae061782b180c9cb308",
+    "dist/2022-01-28/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "e9b7393951081be935b6f97a0bb5d974975e555eea291d256913f07c9a8ea21e",
+    "dist/2022-01-28/cargo-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "c12b8d1711078cfe2506dc069bdc6a823b8720f10f5f927d2fe0d8a4dac09fd9",
+    "dist/2022-01-28/cargo-beta-mipsel-unknown-linux-gnu.tar.gz": "dd810231860fa9d925a641a9928b05917a697cb205acd6636e11c5d60cc3badf",
+    "dist/2022-01-28/cargo-beta-mipsel-unknown-linux-gnu.tar.xz": "2d36e70cd07a97a92f23b26984cd8a1310c9762cc61e629c69a66a3deb53884b",
+    "dist/2022-01-28/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "65187ba25062e668abf1b401364f99553ebf8d61d26a5e4a833a00a3dec38f64",
+    "dist/2022-01-28/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "d5237004a0d161cbbc99c0c36072b2b4ce1112ce2ac26c8dd1770711c5cad8fa",
+    "dist/2022-01-28/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "56722110c9436681db0946e6b66883323c077cac33ef666c8f4d79dea3b0f073",
+    "dist/2022-01-28/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "d3957129b72dce1d1ab4666b8aa826d93ad938ac42ace1fbc055c97148b5f217",
+    "dist/2022-01-28/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "0b8e012c149c64a163cb22bd0a980cbf30cccd260bd4244a67c64e6adb250cc1",
+    "dist/2022-01-28/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "cfd05fd445176914d90e2f8f6ac4db60b6adaca32551b0290a06dd18dbdfe768",
+    "dist/2022-01-28/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "ba7b03932cdc6d25b1c85e0ceb35360fb41837904283910aa7452ff41ce7b40b",
+    "dist/2022-01-28/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "d036966c31e6f89c52a40889094042454f848d51a371167fde5a99a7d37d95b4",
+    "dist/2022-01-28/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "383957085d629e7a64afc3a560a8cfb9dea25b7deed71b9bb0e172a1218713fb",
+    "dist/2022-01-28/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "eba3a543082a934403ee72222f397831394633f092fbfe34aba21da2f5a3f6ff",
+    "dist/2022-01-28/cargo-beta-x86_64-apple-darwin.tar.gz": "fc8f6ce885d9fa29b71ed8be24da9bf718ed581e4738c167952b68667acb8daf",
+    "dist/2022-01-28/cargo-beta-x86_64-apple-darwin.tar.xz": "47560ce1cefeca1b1b80f4df3a8bc01cda9de6aaa9c46e64c5fb051e1e221e08",
+    "dist/2022-01-28/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "281c046114664c1df3629bd2001d4785e930d7f86a743acf21d2a2b117b9e857",
+    "dist/2022-01-28/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "66207bd42c186fd52c1ab4156343842f5e561770142762dc7f553460d689b444",
+    "dist/2022-01-28/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "949de6cd5b2856d4c70162bb6a5321ec193430fa0120e69bf6af9851f9e0d17d",
+    "dist/2022-01-28/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "796f3cee5426cf482da4e065351ad1b7208cfe03addb721433594ff7321d0611",
+    "dist/2022-01-28/cargo-beta-x86_64-unknown-freebsd.tar.gz": "2e587bbe22cfb0a8f62822279611505d31498bcce1e85578fb7ac092ae88007d",
+    "dist/2022-01-28/cargo-beta-x86_64-unknown-freebsd.tar.xz": "800ac9e61fdff1e046c8bf5708fde53a8ea96ebb9c74d1268dbb15518fa1a2cb",
+    "dist/2022-01-28/cargo-beta-x86_64-unknown-illumos.tar.gz": "8d543d45cc1770ba6d7591c65aa9fe20ec7d877e227e5d9fd3778b8dfa1fa073",
+    "dist/2022-01-28/cargo-beta-x86_64-unknown-illumos.tar.xz": "dfb18af670d92c55539bb99df1b48e834dcd3ac080c2a93b66d86785e01d7784",
+    "dist/2022-01-28/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "21539d224d42f19d6ac44824c13c2a81a33695239d6c9903921ac89ebedf1608",
+    "dist/2022-01-28/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "a9b81e05c3341d89e14cce58af2334c4a09ecf7e468141aaa74f7d32383b4a41",
+    "dist/2022-01-28/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "cd0b693001a83b24e31b380f02b02cbd92365b1398884e174bbafc4991470747",
+    "dist/2022-01-28/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "5755a6a61d233c097e99b5b6597f70e42f79feb3e661daecade9847fbf322019",
+    "dist/2022-01-28/cargo-beta-x86_64-unknown-netbsd.tar.gz": "807f8fec9df54aab2bc2b70d8fe581922ed9f6210608bb3c06ca919c4ce18c77",
+    "dist/2022-01-28/cargo-beta-x86_64-unknown-netbsd.tar.xz": "29defeeaa32612bef8b0fc54cf70ce7b472dab9a0bc3bd4516dfbcfad682adec",
+    "dist/2022-01-28/rust-std-beta-aarch64-apple-darwin.tar.gz": "bf8adfd2906d4fbf2e86700a2d753afb6397a0a8cbb3249977fb5b5c63cb7fea",
+    "dist/2022-01-28/rust-std-beta-aarch64-apple-darwin.tar.xz": "eb45b62563528fe2eb53e8a4b21bd94f818c6d7e053a6d467854bb4870d97124",
+    "dist/2022-01-28/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "fc0218862447e94362de8b4c0537ab3e52715dd3becd3a467d2b8b772379eafa",
+    "dist/2022-01-28/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "290440ff743ad923ab3dadbec37b5f8f32bf0fb71cd52348932045a358a7c79d",
+    "dist/2022-01-28/rust-std-beta-aarch64-apple-ios.tar.gz": "c2d73f7b0bc523ffbaca6b996d3739d7504d49197a3f43660ef0b60b43e0d372",
+    "dist/2022-01-28/rust-std-beta-aarch64-apple-ios.tar.xz": "8aedb963e75125eb73f0cfb5fca4c1e687f9c05bda1829faf2feca67644b3f05",
+    "dist/2022-01-28/rust-std-beta-aarch64-fuchsia.tar.gz": "9a54522ddbb3d013584374123bf9af94529880641b1a06de95f60b003e4cebb8",
+    "dist/2022-01-28/rust-std-beta-aarch64-fuchsia.tar.xz": "2fa07e359705959879b53d2384ba4b1cdbf5cf9d2d4de09f7e1951a7f762233d",
+    "dist/2022-01-28/rust-std-beta-aarch64-linux-android.tar.gz": "55e1116809e6b6a2e2284496ab5295687ad5ea78b258425fdfb1408463b5e13a",
+    "dist/2022-01-28/rust-std-beta-aarch64-linux-android.tar.xz": "a28d4e982f7e9be7d77a56aaa2a2cb56d8d9e973abf53251b17c9304702d0501",
+    "dist/2022-01-28/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "d764bee67fb0b03649c3d66d969cbc164d0e3044745dd03df9618cb6fadc18c1",
+    "dist/2022-01-28/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "b955936e318bc72118a28b90049507b515f252b2cb2e7b13ebdfd0b7e26fa160",
+    "dist/2022-01-28/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "6f73c34ce381c71f9d4b26eb68180fe4095d6093aa3cefd8247bc1752df9180d",
+    "dist/2022-01-28/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "ca82c0aa61c59b29f02f5dfd4ca6ef2836d145944b39e24f4d257eef4765ef46",
+    "dist/2022-01-28/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "a369a6f079274e0e8604616bd911dced66e3557a109aef5d8a2495c657d51f30",
+    "dist/2022-01-28/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "ce8e9ce1c71ecc704830df274df4eab48c1bb431bc0a2260208e80bd7c9f0ce9",
+    "dist/2022-01-28/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "8a331a2e9e90260ccd31c8868d321badfc499adf875492c6b3fc89cd6bb30108",
+    "dist/2022-01-28/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "fb17a241fd1b05c1c63ecf0f2318106f5992fb90eab5c4128186e1f7a232fdcc",
+    "dist/2022-01-28/rust-std-beta-aarch64-unknown-none.tar.gz": "892fc92ff90f729e1cd72db18c9b33a4a534f960e8ccf25b99e098b9c7bd1fe9",
+    "dist/2022-01-28/rust-std-beta-aarch64-unknown-none.tar.xz": "f781f4f9c7528860c720ac89a8c883bd9ae0ef515a9110a15588d2ea4ceffaa7",
+    "dist/2022-01-28/rust-std-beta-arm-linux-androideabi.tar.gz": "1767a44aa4999d4cbbb0f99ee79c02f1afe573e93c9fd8326090fe250ff05c4b",
+    "dist/2022-01-28/rust-std-beta-arm-linux-androideabi.tar.xz": "bfdef77cb3101b83881069b3cf908f119c1611b547c1620a2e9b06b63e18706c",
+    "dist/2022-01-28/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "8cb857bc6779224fb9ff3fdbdc21b770814a02a93cbad96c19bd155f007efea5",
+    "dist/2022-01-28/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "5a708abe835aab411885c13a5d47584b279f5955a971729084f869f0e9f05c14",
+    "dist/2022-01-28/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "c214aa4109e2b2069c3e739524570d5412475f65741a6eeca3e54fa8cd8486c5",
+    "dist/2022-01-28/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "6c957c577b75d8b2f1b0f7a8e7b0eae8256bec71c93b7cc69a1231754890cff9",
+    "dist/2022-01-28/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "14ddf068ecc33aba42de9cab00a52498691564c1c83b4e043024a9b093942533",
+    "dist/2022-01-28/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "2950de6376f7ee9c05145fbd8143c61a7344fb748f540c835d0523cd645176f0",
+    "dist/2022-01-28/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "94ca02d2b03e71b9a6515a296a958ceeeb2fa0f3b6f14d46ff455e5adfdbd167",
+    "dist/2022-01-28/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "7b48e5e497dd82144e2e9d2b718855ddcbacb91c5a7544762d57fc18024b2b5d",
+    "dist/2022-01-28/rust-std-beta-armebv7r-none-eabi.tar.gz": "afd44d9aee954a7f5c1b744862c7e62ebc4812192deffc06052e4c5f23fbb1b4",
+    "dist/2022-01-28/rust-std-beta-armebv7r-none-eabi.tar.xz": "2cbcd24628de62d41b18fbf2434104dc8815edcf4d4fc895cf0fdbe91d920ea7",
+    "dist/2022-01-28/rust-std-beta-armebv7r-none-eabihf.tar.gz": "4dd22c4893a31d58dbdda4c60bca249fb261a49f64c0dd33b93916924b301668",
+    "dist/2022-01-28/rust-std-beta-armebv7r-none-eabihf.tar.xz": "f51031ffcee2cfc0720a5a39a2fc319df099c829eba0bc9d57758dabad2901c6",
+    "dist/2022-01-28/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "c5fb7b66c2b4f5cae789895a6670548fc14a71626b4962fcf973191b3408b6e7",
+    "dist/2022-01-28/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "0ce55128a439376a176e36b96615ff6d595fec18acb3f1e72d97a48fba52d9e1",
+    "dist/2022-01-28/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "e1ce999a808d0c3046b5aac0abc494b37d15256d91acfc0031f7409e03c37cef",
+    "dist/2022-01-28/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "8c1990aa82d0cb1081918500967669a3026bbdb14cb72114305253a03e38b89e",
+    "dist/2022-01-28/rust-std-beta-armv7-linux-androideabi.tar.gz": "0d7ca26d9c90df9657eb01829e8536d2d5493a79ce785eb025e5b09c180a0bbd",
+    "dist/2022-01-28/rust-std-beta-armv7-linux-androideabi.tar.xz": "89a7e989fbac5b272840635f7deb1d0b65079a1b97e5b055c22306ead886b2dd",
+    "dist/2022-01-28/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "45746a4f15d418902ba608ca5992f207277f3b591c440839f6c89fdabc4c3330",
+    "dist/2022-01-28/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "625d0dac58197517630362f993712c0e7706e43be5d5ef36159321ce3cc6b20e",
+    "dist/2022-01-28/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "aca7527de247595d7c7a240f093d66ffb4e2d11282f1df2fde9531096d4fe9b0",
+    "dist/2022-01-28/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "0c0e620d4fea01054af6fdf28c8b2f15eac40acd41b0ae0a8ed9520b72d2c5ac",
+    "dist/2022-01-28/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "084b0f9a065821c2996da457c67ddca54219f39788b22f6b24a4be6c4cad07f7",
+    "dist/2022-01-28/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "eec6022b0123e24c97a453fbf40eb3a9ee606aa5f797a790f2bde9b2eea2bb5d",
+    "dist/2022-01-28/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "343fea5dcc3e75db9577d2955e6e1c4bf75aa622f741456d64843d927491ed90",
+    "dist/2022-01-28/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "37d9a42c59374785f05bb478b0af26e80e212a229720a3f2f59db7157d5a028e",
+    "dist/2022-01-28/rust-std-beta-armv7a-none-eabi.tar.gz": "f35390f75f201567458b43b76affa4bbc677adb3ebf0e3f07513ca707bbd832d",
+    "dist/2022-01-28/rust-std-beta-armv7a-none-eabi.tar.xz": "38a2776f222485a7381e35ed4f50a9756f0615e83b1143dffa7a6f1aa47e7001",
+    "dist/2022-01-28/rust-std-beta-armv7r-none-eabi.tar.gz": "2c3730bc1d7cd878cd9f0070697ae0a64f209b74bd2442afb1ea536b11f92da1",
+    "dist/2022-01-28/rust-std-beta-armv7r-none-eabi.tar.xz": "0bdd8d03334ff042fa693eaa27afddf1afc670aab89293e5baec57ce9e5c6c57",
+    "dist/2022-01-28/rust-std-beta-armv7r-none-eabihf.tar.gz": "b1f1088d554a06bc30b5c9bfd2043d952c80f8ff972c824760911dd0fa487a2d",
+    "dist/2022-01-28/rust-std-beta-armv7r-none-eabihf.tar.xz": "0cc2026f2968ce7f4e262e0899251fb6ee0dc84b49d3d9bd496e00795070d842",
+    "dist/2022-01-28/rust-std-beta-asmjs-unknown-emscripten.tar.gz": "858c4a3660ef76c3fe792881638e67563c2290d9a81c3b0f49963b252e1e493a",
+    "dist/2022-01-28/rust-std-beta-asmjs-unknown-emscripten.tar.xz": "10fcf8c290e936a4ff78163d5e0fb9827176a9860578f9352094026e85a81c14",
+    "dist/2022-01-28/rust-std-beta-i586-pc-windows-msvc.tar.gz": "7d5e5fe1c399e58a889c861864278d2d4641a888be548ae55d3b6734b6490c15",
+    "dist/2022-01-28/rust-std-beta-i586-pc-windows-msvc.tar.xz": "f53c2713dbeb793e8564fc222c4ec90263eb2a908c938e4e9ca06aff40e24a84",
+    "dist/2022-01-28/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "0519f54f0f3829e7d0a26dabe0450de23189fd771a33720d71e17ef7017d27e7",
+    "dist/2022-01-28/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "ab2d89d1be4b2c5076a4d83108ac5785178e2726362a8f76d4d4eabffc016ba7",
+    "dist/2022-01-28/rust-std-beta-i586-unknown-linux-musl.tar.gz": "873a4c495f57514224fa25a67e4c714b5d37cf760c18aae38bea6b7b8c8f089f",
+    "dist/2022-01-28/rust-std-beta-i586-unknown-linux-musl.tar.xz": "01bb0327a8f63fe2a42a6af07a743253974fcbfecab3bdd739be58e96e0d0c0c",
+    "dist/2022-01-28/rust-std-beta-i686-linux-android.tar.gz": "630d53d2eb46c63cd183f5d130af45e2641313d1b1c607c41f7a4a507fca16e4",
+    "dist/2022-01-28/rust-std-beta-i686-linux-android.tar.xz": "323660e7d58d468ddc33dbbd0fa37621fe78713091ba2ef178d4a8fe01bf81e1",
+    "dist/2022-01-28/rust-std-beta-i686-pc-windows-gnu.tar.gz": "0d687096fcf757434d07db355f96eddd8e07a90d952d123f2af30a0f63dffaf4",
+    "dist/2022-01-28/rust-std-beta-i686-pc-windows-gnu.tar.xz": "22fb93f31abf9f7d9e4cdfd5a7ddd03705ecc48db22d7a4ebd58e421891fb998",
+    "dist/2022-01-28/rust-std-beta-i686-pc-windows-msvc.tar.gz": "1c644591da0698df4a40977c9db8a00a002c1a34cb828a4038c5c17d1a3aae58",
+    "dist/2022-01-28/rust-std-beta-i686-pc-windows-msvc.tar.xz": "e0220fd4ee5f36b29f605f9a8bcdea1bd7721c40787b59e1fb63915e5da0668f",
+    "dist/2022-01-28/rust-std-beta-i686-unknown-freebsd.tar.gz": "eb9faa1d7492d92cffec3495937c7682e3c578d9c6ac5d9074efea0d1097d63b",
+    "dist/2022-01-28/rust-std-beta-i686-unknown-freebsd.tar.xz": "10732369b289fc92ea0566cbf8494fa267ac551e682921f1824d76b70170d73c",
+    "dist/2022-01-28/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "355c6c1178d34e687a071081dddd093a1d6edd3e93cd73aac46f425797c6c541",
+    "dist/2022-01-28/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "4904406365f855ed10cf113f04cbeaaf29842789afb91d84396ba3953125d873",
+    "dist/2022-01-28/rust-std-beta-i686-unknown-linux-musl.tar.gz": "832737bfc8c70f07a8463d1db39f260829de67dc8c588cf11170f2dcb2b0dc28",
+    "dist/2022-01-28/rust-std-beta-i686-unknown-linux-musl.tar.xz": "8220b586c8cbe913db4d00699f7821fdf40ca8da85faf4fbfc84ae56916460e9",
+    "dist/2022-01-28/rust-std-beta-mips-unknown-linux-gnu.tar.gz": "82939695d5bfe904481e3858e2d203d56f0877683ebfb33326ab9d0699ff2c5f",
+    "dist/2022-01-28/rust-std-beta-mips-unknown-linux-gnu.tar.xz": "f337c7caee2e964926801811a282e4f18f4e196521ddfa81417ff6dca46927c4",
+    "dist/2022-01-28/rust-std-beta-mips-unknown-linux-musl.tar.gz": "e7256b993f54fc5b7aa68c8aa5e5f1294d82681f0b8b38c7f7ed6e1d57064af4",
+    "dist/2022-01-28/rust-std-beta-mips-unknown-linux-musl.tar.xz": "00bf1b30ac924ca221569fb2febf34593ca435540163d12ec4e433a7406c2819",
+    "dist/2022-01-28/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.gz": "6d2c2d9b82d95d808a23e99e0f9b828d9087fe82efeabce200ea7634636857da",
+    "dist/2022-01-28/rust-std-beta-mips64-unknown-linux-gnuabi64.tar.xz": "e504cbcda58085ad283dcccf4aa5160a117aeef01f4017ffb4350a6e3b18113f",
+    "dist/2022-01-28/rust-std-beta-mips64-unknown-linux-muslabi64.tar.gz": "c382edfa08997d2c5d400ca9c93eee9457fdabf157da2306187af68a11cd3705",
+    "dist/2022-01-28/rust-std-beta-mips64-unknown-linux-muslabi64.tar.xz": "616d4daf1ed58c7718a204da636d96597d184ecdc71b414a9b20e5fef710c078",
+    "dist/2022-01-28/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "5d24d7be185cb8fb8bdb1a89a63be323491284d2e9bb191104ef59a547e3899e",
+    "dist/2022-01-28/rust-std-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "c055f2f3d77354a9d03276f7af8221e3c8a337b11198143a31b6b654e8bc4f28",
+    "dist/2022-01-28/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.gz": "ae730a78c7382af9c16f0b4bc157f339bf8befced1748b955e29e0db751cd5cb",
+    "dist/2022-01-28/rust-std-beta-mips64el-unknown-linux-muslabi64.tar.xz": "18f02642733d06bfad35e6d383e6634a22c79dfc56f6b6f1976a5bf71ca36478",
+    "dist/2022-01-28/rust-std-beta-mipsel-unknown-linux-gnu.tar.gz": "cf162ecf50f6edddff265f5e051719f8c15c730f3826cecff3477d5c63f3f28b",
+    "dist/2022-01-28/rust-std-beta-mipsel-unknown-linux-gnu.tar.xz": "f82bf7eac361cfd2b255c3eb1f2ba4e6349fe5f88d6e6e9edee0aa7e9ae4e721",
+    "dist/2022-01-28/rust-std-beta-mipsel-unknown-linux-musl.tar.gz": "30e48dc0b5c8cfb1d3fd18e06ca19f7136aae366cc9e2b142999d8a0430e3513",
+    "dist/2022-01-28/rust-std-beta-mipsel-unknown-linux-musl.tar.xz": "7db67dfd175d398f4e922be87002cee22e7badc661ab3ee4aba7c7e9673ecf0e",
+    "dist/2022-01-28/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "d72d9066354bf5f2daddd8ca00f2221c897142e68b7e8343c6c965e5537ccb10",
+    "dist/2022-01-28/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "eb5f848052e0ab07de8aec5f767d6d4413da0c135ce02e766d125da5850a585f",
+    "dist/2022-01-28/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "6cf15da4eee99e1b89f2306ffebebce537543f08ef36f3a8aad38b0202bf1378",
+    "dist/2022-01-28/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "b35d2296994172b05ffd0bb3bb59cddc007ad93cc089aeb1f8b4a2d7a1d716d4",
+    "dist/2022-01-28/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "819327e4a040bea527712ac2d935b2db9539262a9e552450144b9829038db48f",
+    "dist/2022-01-28/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "68cd8c861a62931feae04eef5a3ecbb9bdd97433d082cae060e005f1da6523f5",
+    "dist/2022-01-28/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "fc1459aa99a44895a0631a35cadd7c8683b7570fe0a743e0bdc7f397936a377a",
+    "dist/2022-01-28/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "702b008b7390df74ed639b99133abbc5c0441c002d4d99594c9c56f46e13e518",
+    "dist/2022-01-28/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "45dea87501465e6ec421f7a9a6a364fb4bbe7f6e6c00aef16bd66b58a204ed18",
+    "dist/2022-01-28/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "f7d5178e5b2514e52336dd3d4dd7ebe7f452e6427ff578d19f955d611625c2ac",
+    "dist/2022-01-28/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "9c7b727799288d289f7569823b4f75c691d42a2c25066f742e74efcb1e9e7c31",
+    "dist/2022-01-28/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "536397a308e268b30a6bd1a2a869ade61e0d048aba76b9787b130c5d8ede7d12",
+    "dist/2022-01-28/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "21397afe74f4a3611e91c4e9efede79d3cf982a13d1b864c878be7d3436e3129",
+    "dist/2022-01-28/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "3c61d50eb15c56087ab9f9cfe765586a2fbcdff93d60740a75bb435dcd18619f",
+    "dist/2022-01-28/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "7f654430af17b09cd974e35f6c99b1ff88fad706e659fe9d48ed9cb765722278",
+    "dist/2022-01-28/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "9d7ee3d8dd1e93c754e2991f656acc2a03e88b9ee2deaa865c83fabe05aa5618",
+    "dist/2022-01-28/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "47ea53de8215c251bb206f81ff6e8ad2d632e9f74e793d36db00d8329e7f4dea",
+    "dist/2022-01-28/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "56c033b71340b5379a59dfc0219bb5350a3e95aa22983c0bbfe1cad6b347718c",
+    "dist/2022-01-28/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "3902efc5f212d815a77d39211a7ad662c2826857bde89ec7c0f6411745531e6a",
+    "dist/2022-01-28/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "f9631edc7899d7f71230483caff7215a423b4ced12a963e41dc0e268301c4565",
+    "dist/2022-01-28/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "e1006abf94a35dc9eed587cde1eef3bf35ce0e685f4040176c2460df4ef71f69",
+    "dist/2022-01-28/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "34f5901fef0845b5da92f3a49a20d533b6bcdb77cbfd9d8432eac8aa47b28675",
+    "dist/2022-01-28/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "d3a63e5ba55d291045562d95d27cfaa6f116ecc72ebba39ff97ee8e960030de1",
+    "dist/2022-01-28/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "f9b7b16aa77ac7ca1e8384d74c5cfcb66626cc57eede7aff1da4cdb7ac13942d",
+    "dist/2022-01-28/rust-std-beta-sparcv9-sun-solaris.tar.gz": "9af8b18ab6089bb2e06ea33a17a44ee98cd0ac3c54b688f5848d4cd141ff2389",
+    "dist/2022-01-28/rust-std-beta-sparcv9-sun-solaris.tar.xz": "1809d88ac573ea265f3d21d4142d0176ba9ab51e789911825a9d72ca917ddfd1",
+    "dist/2022-01-28/rust-std-beta-thumbv6m-none-eabi.tar.gz": "5a1aeb44ca3b92a37eced85edf374d2ffe17ba6f6da748580baaf3af1c3a8a36",
+    "dist/2022-01-28/rust-std-beta-thumbv6m-none-eabi.tar.xz": "7d3cdc3b7b3d9d47aa0d1d6de4fc5f520ee99c52b4678fc3987823efe4e1ca98",
+    "dist/2022-01-28/rust-std-beta-thumbv7em-none-eabi.tar.gz": "a950ffaf7228864eb2fd9570bb86a5544f89f8293a3e96f794d36eaa7e9f8825",
+    "dist/2022-01-28/rust-std-beta-thumbv7em-none-eabi.tar.xz": "527be16c3474ab25c3ac56aab6278a3d4f1b535bee0c226dbf63e52f5ea2acf7",
+    "dist/2022-01-28/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "fc864b408f7d8688733b260b7ca2f476f148a0c04cef15b4b99348fb59627ce9",
+    "dist/2022-01-28/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "3a966b6343c75933d00ead88f54e797aa81abc1b521902d15c22d44791b33e71",
+    "dist/2022-01-28/rust-std-beta-thumbv7m-none-eabi.tar.gz": "4ab03955b4b787f5d2b1096e03aa4b0948a2a53562107ef6f9cf0ae122668b86",
+    "dist/2022-01-28/rust-std-beta-thumbv7m-none-eabi.tar.xz": "2c0e443dcda563ff4cad6285ea648797bca6ce828bfed66f3b868fa386a0a693",
+    "dist/2022-01-28/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "831e7af7924d20ba5289a67d6f0d55942f624ad1abb997a90e05fe303c442870",
+    "dist/2022-01-28/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "e99648317cc93eb4e3e807dc85b28bc6336136750caa9ae000a8041e93d1a9e1",
+    "dist/2022-01-28/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "37db1b82732ee477e4bd8f1d430ca0f7b50f9699285188cc4c55efc024c760f3",
+    "dist/2022-01-28/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "5dfd285234f1f9da127b7ae7f823facac9f6f281713b5502268ff75668ae8a6e",
+    "dist/2022-01-28/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "22c21d88398dcc6dff166270e455e6a4be8bc06b1932f4138ce8c931e3a900f6",
+    "dist/2022-01-28/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "2eb7e4dbd9984ca60746af13c631871c3d872b95239c422d135de2bda203707a",
+    "dist/2022-01-28/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "97e6b0834227d725660d6f9729b198ddb70ba238640f2a43de4568230ac7bf5d",
+    "dist/2022-01-28/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "e9b06591f4769bed69b6be6647deded3991125c0a5bec5486126e6572707fd7c",
+    "dist/2022-01-28/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "6afa229d0a1159f853a13f0ea36c4dcb8bf964bd699ecafc57539a1391861591",
+    "dist/2022-01-28/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "5811a551c8c19b09f6928aeaa655c69f32657775b9149e4fa37a5003be15faec",
+    "dist/2022-01-28/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "522e98515cbedd4b75cd2a3151d16517d71d8078005c3a1133e6e222dad163a1",
+    "dist/2022-01-28/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "2654caa437d1f1871db5400652287597bec88eb366e099b03d7cca70367d3722",
+    "dist/2022-01-28/rust-std-beta-wasm32-unknown-unknown.tar.gz": "c18dfcedf25851f446271979b868bcd8dbdad2ca2a4762f3594385d65811d449",
+    "dist/2022-01-28/rust-std-beta-wasm32-unknown-unknown.tar.xz": "0dc5da1073e3df2899909045c33c4aceb9b159faf7a20c2e32affca7e7587554",
+    "dist/2022-01-28/rust-std-beta-wasm32-wasi.tar.gz": "e6e03121c99326cb56bb3a6f6eb352cadfcc487b20f5a7e1b95c5c7f1c97feb0",
+    "dist/2022-01-28/rust-std-beta-wasm32-wasi.tar.xz": "8cf642cc54d22908a3db701a1beb13aa43143857596f4965261cdfa35812cfeb",
+    "dist/2022-01-28/rust-std-beta-x86_64-apple-darwin.tar.gz": "e3065e70fcea7f03ce4ae41742bc6540ee2e0df50501d8ed81215d0ca4c63f9d",
+    "dist/2022-01-28/rust-std-beta-x86_64-apple-darwin.tar.xz": "e5e683cc14760ab0f94c4f02b721e3cb2c0c780ab68e63c971de70355c30d2cb",
+    "dist/2022-01-28/rust-std-beta-x86_64-apple-ios.tar.gz": "b31791d217e4868caf88fa4c96c3476a4c65bb8ab59e8846f7e2f4f003be7cc9",
+    "dist/2022-01-28/rust-std-beta-x86_64-apple-ios.tar.xz": "24dd9d59c9ecfd0c7a56143a9e0368b077d61ac7d9c56cb940e8b195fb5ccde8",
+    "dist/2022-01-28/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "15bad901b51a039c70dda2379eb1cbfb7098ed00415924ad19fb9318f176d34f",
+    "dist/2022-01-28/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "6fd144e0d7cf510f5df11798d9e8f2faeee52d9dd5134fdfb90fac2adb9c1d21",
+    "dist/2022-01-28/rust-std-beta-x86_64-fuchsia.tar.gz": "f22276c2c07074dd8f3634f95eb4422ca1a2ddb89e22e05450c77e59676445f9",
+    "dist/2022-01-28/rust-std-beta-x86_64-fuchsia.tar.xz": "fa745d421e36d9255da6e69ae4adf968910200f99394a8ca88aa2917b0931758",
+    "dist/2022-01-28/rust-std-beta-x86_64-linux-android.tar.gz": "b6924656e61295d96c5c792cd482435248867a846000d232f8895b983f2fd68a",
+    "dist/2022-01-28/rust-std-beta-x86_64-linux-android.tar.xz": "58b981335322b7f5f11ecf71411b9b7fe045d160fb99b1f8a452d0d833926461",
+    "dist/2022-01-28/rust-std-beta-x86_64-pc-solaris.tar.gz": "559721b2bf60bbd7688b8aeeccdd3d6c92eee2eaf29082f42ec53689f2fddb92",
+    "dist/2022-01-28/rust-std-beta-x86_64-pc-solaris.tar.xz": "c6341953f2a9d11159e3bf398b90cf9e76af4b6af7cd6d828b22661bc4f3fc5c",
+    "dist/2022-01-28/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "59b91baee1eeee88c78b55ac3a32ce1cdf59107715a3db7c3476843ea981b70c",
+    "dist/2022-01-28/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "2f7bd143bb9f40a06e69b5f9908ab14e364db254918dd1c984c272a853a56f0b",
+    "dist/2022-01-28/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "1258d1207468450556a0a265342e5155474a7f87e8c33b5233c72a959b13421c",
+    "dist/2022-01-28/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "907d14ff6bb742f2bf12f4b51054c8c6bb128cdaee957918e4fdeda61ac18c53",
+    "dist/2022-01-28/rust-std-beta-x86_64-sun-solaris.tar.gz": "ca0cef7d3497ae9714537bbdd2469b48afb20ba1dfecf03d680e801871a3ec97",
+    "dist/2022-01-28/rust-std-beta-x86_64-sun-solaris.tar.xz": "73eaceff8046cdb76ccb7a6739f01dfff5b740ffdf5366067e92814be5ff97a0",
+    "dist/2022-01-28/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "bb8671bf78ee0c8840d453af9ca0d337c167d69c293e4710d6aac2d19c3a044b",
+    "dist/2022-01-28/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "87cdacf1caa7fb3656be04fb3b37f21541b2e8eed214bb5822c0723fe9f23067",
+    "dist/2022-01-28/rust-std-beta-x86_64-unknown-illumos.tar.gz": "7dd006b93c449864bc3c6e024e0f0903db1c422b6bccb1bd1ee8187fcbb4e3d4",
+    "dist/2022-01-28/rust-std-beta-x86_64-unknown-illumos.tar.xz": "7d77712a5d07578e2f9947ef11ced00a84b22d3075f747781b6c0e0483bd7fc8",
+    "dist/2022-01-28/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "5f6fb2124a40f0a7ed2631b59f67762d701c9fd8ede051dc922d99ac6fe29c97",
+    "dist/2022-01-28/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "e00f0da85fb8378dac3ae76f235f54cca568680d4208fed065143e1ecde1b87d",
+    "dist/2022-01-28/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "d2d0222ba528a42d8804423c15cac59a5c37e36b76248605dfcf9d732cceb1de",
+    "dist/2022-01-28/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "d2c8cf8510369513fd79107bd450df429a97f5bfbc59ef8a7fea5fbd75462a65",
+    "dist/2022-01-28/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "a7934e15342434f242ea7eb9c9c853a984f70befaf1cf2266cc5a198233a2337",
+    "dist/2022-01-28/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "bc5de5c3df04aa3aaf4866e432b3b50dafaf790345587eaf066334f7f52ff34a",
+    "dist/2022-01-28/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "9827751229decaf827c8bbbbeebe868c86d7002a82d776f0ecf310d539eb285b",
+    "dist/2022-01-28/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "88d41e6fa0d290fd39470f824045abdf3557e0028ae877c9c4081231531dc8cd",
+    "dist/2022-01-28/rust-std-beta-x86_64-unknown-redox.tar.gz": "5b1c8bed24c4bee0cfffbf54029e39673545a314102be2281018f8bbd05a9d17",
+    "dist/2022-01-28/rust-std-beta-x86_64-unknown-redox.tar.xz": "3bc2a98b43bda5080734ba0ad1235e72a3e12e3bbb5c603193aae3a18feeee1c",
+    "dist/2022-01-28/rustc-beta-aarch64-apple-darwin.tar.gz": "be36422d10d4dcbc618eec2dc33ebd62c16e366a0bcf8a4a3b9ddf5bfe236bf2",
+    "dist/2022-01-28/rustc-beta-aarch64-apple-darwin.tar.xz": "cf6e5b5475733dc71f68c8d8b08556d410c3f2bc87813565cb9a69d0984fdf48",
+    "dist/2022-01-28/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "c2eff28806e697087a39da7922ede30b937110d1e492ab839644c695c02ea467",
+    "dist/2022-01-28/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "ea9fda833ade80ef87afcf3cfdc0ace851c01b66b00701d70722ba9aab1c9d0f",
+    "dist/2022-01-28/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "e9e37df47dfb3bcbae3110e0b372ae661aff82d5e6a6837deff78978a85dd2f3",
+    "dist/2022-01-28/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "f11adc9a47432ab4ecd0e95c8fbde21c493dcac730ac9bcc924e096eacce6b94",
+    "dist/2022-01-28/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "6279fd872148c28c0684d7dbfd6e96838fff8acbec83c45e235e85f3d68802de",
+    "dist/2022-01-28/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "c969e5c760dda90fe23cf8df764601c38ada25a2d7bed0d497f31701c7bcc62d",
+    "dist/2022-01-28/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "d4025f62b09f94d5c464fa6bb614186e9968c6b34f5a12544ee35323426eae19",
+    "dist/2022-01-28/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "992d055af2f888d2c61e5aa1670ef40a8bf7ac761cf6ecf76d7a8d13b3eb9a0c",
+    "dist/2022-01-28/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "ab153065e0db468cdcab3a3a251d0f80a7d94940f3455db419b3a3ae5bffb651",
+    "dist/2022-01-28/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "2501ad4358112e7acc736f9820d6f822bd985acd577e56c124573082a8e26cec",
+    "dist/2022-01-28/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "3e145f4111fc7835949b6ba34d0ed7a58605166cfcde22d96d2e8dad3f8c65ff",
+    "dist/2022-01-28/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "948f13b6f988072c707cf8c730abf970d6b47d4fb6044d4f6b615b48c21369c1",
+    "dist/2022-01-28/rustc-beta-i686-pc-windows-gnu.tar.gz": "997ba934c0bc912df01906b547f240f4cf7036300cd34ff341e72b69502b1cab",
+    "dist/2022-01-28/rustc-beta-i686-pc-windows-gnu.tar.xz": "c0ef12248f08da0f88629e55ab805b637289e7a29a92bdec5cdbf138df272baf",
+    "dist/2022-01-28/rustc-beta-i686-pc-windows-msvc.tar.gz": "94e6df381784d4f7bd9c8cbff39fe3066d636c64257093563f84a59ee84b686b",
+    "dist/2022-01-28/rustc-beta-i686-pc-windows-msvc.tar.xz": "ce392e7c1942f3267b029faa1f06a4162c3a21316ad819fa218a0ddbd9993b79",
+    "dist/2022-01-28/rustc-beta-i686-unknown-linux-gnu.tar.gz": "0809b22fc64166ed66a32090c3af49bf3b1515d9aa37958d1bf4d8edeef67bac",
+    "dist/2022-01-28/rustc-beta-i686-unknown-linux-gnu.tar.xz": "6a24a429d45b5558ebf069b0ea730a8b2c0f8cb8e8247d3e50739b5c6a06f45c",
+    "dist/2022-01-28/rustc-beta-mips-unknown-linux-gnu.tar.gz": "af3ff96546ae18359f529f35430c4faec41e411357a74e420b5eb6e939e56f9d",
+    "dist/2022-01-28/rustc-beta-mips-unknown-linux-gnu.tar.xz": "40e578de34500ac7bfd1513187894787b9a2a13e1cffbfb4a3fc04779e8f564e",
+    "dist/2022-01-28/rustc-beta-mips64-unknown-linux-gnuabi64.tar.gz": "9b4eeabf21940541791b768db2995c2fcd0f3aa4077f741df941892e65c03e1a",
+    "dist/2022-01-28/rustc-beta-mips64-unknown-linux-gnuabi64.tar.xz": "15940aaeb1da2bd7c3a5f4a3a76c90018a5d38bb933fa516b9833d3b5c9bc465",
+    "dist/2022-01-28/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.gz": "e2d93d8ab7f3a43be6bed773a5afc1ce0b43c15ddb6390a34facb920dcac6980",
+    "dist/2022-01-28/rustc-beta-mips64el-unknown-linux-gnuabi64.tar.xz": "1ce438ec11c7d5912a348bd08fd9a81cd77e7ae9b221ded4473dd203fa5507e7",
+    "dist/2022-01-28/rustc-beta-mipsel-unknown-linux-gnu.tar.gz": "537928c967794a4b0b6fb3c6df138aafec1c26a5bc608089cba5b2ee2fb3679c",
+    "dist/2022-01-28/rustc-beta-mipsel-unknown-linux-gnu.tar.xz": "1ac3144f0ed01c686adb813e5f59ba9f07522161269928d852abf886f8beaa8f",
+    "dist/2022-01-28/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "23d6bddd60b9615b9b2dcc711587eb73022905f4f84db0b85433fb018db9fa90",
+    "dist/2022-01-28/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "172bf1d122830c06caae2879b0f175829938a6a043c39fba39ae2684632cec8f",
+    "dist/2022-01-28/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "df0f58797083a0fb07072237932d6ef30035df227f347976e766dfba0b4d16c7",
+    "dist/2022-01-28/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "951a378b2bd9e8dd60cc5813664c6a7b020e256b5efe88dc9ffc776c9bb9aa5f",
+    "dist/2022-01-28/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "93fb7cd91ff9e530d6eae0496d6456aa48cb6a7e81dc118d40fa5db84324e0ef",
+    "dist/2022-01-28/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "e0facee99193bcc891feb961a2eded35b4bd40f80b5fff977fcc48f7e7b26b84",
+    "dist/2022-01-28/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "d6c9a1014fe73d03ba7fe5248e84fba7abe46b96f61cc45a8972d0c85f577cc4",
+    "dist/2022-01-28/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "1f9f65bd07e075d4c7065d860ffa09441210a220abc4f6c0302de1cba4b56ebc",
+    "dist/2022-01-28/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "0f73fe2bda02e6b9e0f17b8907571d11c622df6b9349ecb60b8d28fab0090f45",
+    "dist/2022-01-28/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "8b1b8cb25ab0a00213b4272390175d91b486cb08e45425f52a8ee1104bc11efe",
+    "dist/2022-01-28/rustc-beta-x86_64-apple-darwin.tar.gz": "a6fa895d1debcbce04c68c64fac8ddf875f6c4e8d7298ec4e46e79cb702e103a",
+    "dist/2022-01-28/rustc-beta-x86_64-apple-darwin.tar.xz": "a0dc92f6a544b215f1b8cf71dc21fb26423883baa24c551c96c250bf05b21c99",
+    "dist/2022-01-28/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "867038c72a56f889420bba6f1946ea560a328a79dd54b70caa8d7ae83712ad54",
+    "dist/2022-01-28/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "a59d3409f4ca6f534608f5fe709ec6442e253f8d9400b9169814c5273765bb72",
+    "dist/2022-01-28/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "e07ee24da341ae8fb8fe55f895ca5fdbedfc392454906396c61d79f1f5cac631",
+    "dist/2022-01-28/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "668aa9303bf8a90c90167b6ca4a9a8a885d5ba21bcbacc379c3ce9b5c1a2f7d7",
+    "dist/2022-01-28/rustc-beta-x86_64-unknown-freebsd.tar.gz": "5e9b6a14feaf665839070f20a795ce2ed1c11824a56264fb35de5e894f7e2c13",
+    "dist/2022-01-28/rustc-beta-x86_64-unknown-freebsd.tar.xz": "3506fc1b57f8da75e93f48d00c49f4d0cdf61b459955449a87d1a7fc051c40dd",
+    "dist/2022-01-28/rustc-beta-x86_64-unknown-illumos.tar.gz": "b30f734100da20382605a98a70d3b6c34febdb11e105fc1a1639ab7b1338545f",
+    "dist/2022-01-28/rustc-beta-x86_64-unknown-illumos.tar.xz": "0b1ca988d1e25423d49f92acb123e8f91ca6772418d2bf4411e4fc1387410c5b",
+    "dist/2022-01-28/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "9320b51f221d9f875a98455fee8494d09318aa0aa90946e1fc03b73173738bb8",
+    "dist/2022-01-28/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "374ba55f3b7d1c6dfaa3385e7b033612335eaf01fa0d06eaeab95cc00503617b",
+    "dist/2022-01-28/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "556428fed3c5b92e001fa9b762915583004e0e3384d1eb17d08bdbb07eff1a91",
+    "dist/2022-01-28/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "5122a66d96e89e7f31e04604792cd26f7cf687d007d839732ad8ec3c32546014",
+    "dist/2022-01-28/rustc-beta-x86_64-unknown-netbsd.tar.gz": "689e0892a575b507032bf4948319fb0706f3d58da7ac55c40560edfb85fb617b",
+    "dist/2022-01-28/rustc-beta-x86_64-unknown-netbsd.tar.xz": "8b1fda9cb3779af899b6988225a4d89a4b3b5f5ab696c0178c82ea5730f4503d",
+    "dist/2022-01-28/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "d10e91d44175ed8841bfaa0ac36641e5b5fd9f562a69634e1dc8e74937f6b910",
+    "dist/2022-01-28/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "26ddf37786bf057527b1ef72580b09f5ab2954046699e5ea8d773ff833d938c8",
+    "dist/2022-01-28/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "59482a7e368c63812aec689c9b9575c267273c1e2096bcc5a1bb0e4fe87f9703",
+    "dist/2022-01-28/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "b7aae7502c13cff81125b8960b06eb808b1ad51fecc311f7cfb02b5aeed8a0d9",
+    "dist/2022-01-28/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "28dcc5231402b7c71d0a741878ff0c64fcd37537889f0a0ab5e04fdb2001c3c5",
+    "dist/2022-01-28/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "24d0e5ef0a8b5c7359243a0ed06801281782ba2fe4ee315ebcc53ce78e84d338",
+    "dist/2022-01-28/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "4f7ed5c1e05a7e903bcbcdccae8da1f296ec182f56c4bd29c38cdee2c022b20a",
+    "dist/2022-01-28/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "c5bbefb41d4ca4f376431d64fb15e250d5dedb8d4ff220f19532fbf7c24fb627",
+    "dist/2022-01-28/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "ccb65098e45ead43ef62b4b0b10dd552d4cf23786b9639ac665612d458c4eea1",
+    "dist/2022-01-28/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "5674d7e984b0fbb51e927d991296411cf0da46465eaaf86a58b2ba81d801cc92",
+    "dist/2022-01-28/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "a6f868aa17cf4c8734f800451f33bc55d38bf6fe4d658714f469416b86fdf911",
+    "dist/2022-01-28/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "acf5681ce5f75bd807aeb23964958d77b5c77a3cabe51d102aeab22c99bd1d24",
+    "dist/2022-01-28/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "e973affc0149d03981875496ae8aea5d7eb5b5a8fcf42380589a3c5f49e7f9f3",
+    "dist/2022-01-28/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "7a00e48bae6d388c0514537429d17b31a316ffddc1bd3d2c6651babec8d2787d",
+    "dist/2022-01-28/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "e3169c339cd6cd1a9355c4f55281f32ab78e60ccad46129b1848135cdbab1f25",
+    "dist/2022-01-28/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "0ae17e2d2ad1a03de08f8462c462888e6c72e36d9d7e4737e85ad9890eff3a4e",
+    "dist/2022-01-28/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "c884249be750942fb19da009dabc296438be4e25c872b548c7cd501135367030",
+    "dist/2022-01-28/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "8b92f8cf72c3289d4be864dd44ce230ff3098f52b16215464f34451dd16f4b9e",
+    "dist/2022-01-28/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "31e97a0e6b1078a2bd78ac92c5861ad5a6dd91c4f819c69e2c07e3941ab893d7",
+    "dist/2022-01-28/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "d36fbd52792645198dd0d2b8fd7b5389931e101313ed0c3793370120a58f5ff6",
+    "dist/2022-01-28/rustfmt-nightly-mips-unknown-linux-gnu.tar.gz": "b3384f0e386aa2b77def7cb36906a3fdbc4ada92fab50deb923561cf6043b98a",
+    "dist/2022-01-28/rustfmt-nightly-mips-unknown-linux-gnu.tar.xz": "f728634605fd782ca173c6be41c4ab9eac5b036419e2d33513d1cae197367834",
+    "dist/2022-01-28/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.gz": "07404280a97ac98597ced7de15856dc05b855123058984aac3f0b2ab896bccf7",
+    "dist/2022-01-28/rustfmt-nightly-mips64-unknown-linux-gnuabi64.tar.xz": "02de9fa0ee4334af980cd25a4bd467ffbc275ee0871224b84f9549c23f922bc1",
+    "dist/2022-01-28/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.gz": "81bfb88af8c591d32508986d7ff96261b0d84eacb8303f614fcae9095a25fbdb",
+    "dist/2022-01-28/rustfmt-nightly-mips64el-unknown-linux-gnuabi64.tar.xz": "e7bff69f544d999c4b2c27071c049dc092df47431e658a9a8f07c7e2cc08c8d4",
+    "dist/2022-01-28/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.gz": "d1d7081173f89fdd287f6b5010ab5787198c504cba5de4bf54f8473777e20bfa",
+    "dist/2022-01-28/rustfmt-nightly-mipsel-unknown-linux-gnu.tar.xz": "d77625ec03a2e0101fcb743c440dd8e21fdafbd04bb652ee4db6c365e0e0ad49",
+    "dist/2022-01-28/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "80143957513b49c7d3f4e113e86a9181cda78f2b928f765b3f4060fbd9bf44f7",
+    "dist/2022-01-28/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "7d9ad14154b99fe9e82e6fd59884b9bc1c3d379c16c376f990dda859d3b86fdf",
+    "dist/2022-01-28/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "897629dc734984e2ff984fd911f6b02fb8d3d9e4ac70bb209981226d27800392",
+    "dist/2022-01-28/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "9bf72e0f71a81f2afb66ecb5bc242b349d92e8b9f51249f52de172e12281fcfd",
+    "dist/2022-01-28/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "89893ed9bd3c2ec611d54d44aac79379db78dd1c4994747e5a6e55cb779a1d1e",
+    "dist/2022-01-28/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "f7b8ca2f4afcabc178f166161c0c006fe0b8eb16455fa8a2fe7d8429718d65b3",
+    "dist/2022-01-28/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "90aafc241355240df41729288bcd61aeb61c792528570f643f5e9fe34a33ccc6",
+    "dist/2022-01-28/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "7018db141ad7b1960640245034efc233a267b05cc412a7969ccb26d87b46c49d",
+    "dist/2022-01-28/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "b986c3ecf6d5e6683f44efbc24ccb1486e42514c695e3401082c396caf26a69d",
+    "dist/2022-01-28/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "8c4d895c603bb875f24fadef68f0b19b5c390640ee170dcf41bdba07d79a4f03",
+    "dist/2022-01-28/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "7c95e4d7c161eea4af6f59f6ff69829eba791dae1fe18cd2a18a5b2c1fb1190d",
+    "dist/2022-01-28/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "51f32b5abbaefb3590cc174c909ea2b80cb15fc1c2cd6c60e749035d9899c5dc",
+    "dist/2022-01-28/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "aaff3042d48acefad9fd012a7c44148e6503dce61c2eedbd06d025d35d086ff6",
+    "dist/2022-01-28/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "8811d63c78d7b3bd6ee4b7b735fbce58cb13783d1d12b16c6cd584f518934a4b",
+    "dist/2022-01-28/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "7d526137c7437d9d2bdfa8e87790b038b053805e9528a8b8b9c6827d5d0ce64e",
+    "dist/2022-01-28/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "84c8c33267286b65acbb8c1a692d410ee49ebfec708cd3cf35013b76c87ec292",
+    "dist/2022-01-28/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "4e52381a3c7acd8435bfcdd45de3a238916985dc7c746615847381b7c2f3fab0",
+    "dist/2022-01-28/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "4979e2ca9e1bb42635b0d633b26dcd9d9265698bbe10320daf464243a803d100",
+    "dist/2022-01-28/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "aea87359d72f23a27bee9763074301d4e4c85c5e91cc1c18c16c8477b52ff9c2",
+    "dist/2022-01-28/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "6bcf6b03d018964d63c20782d01f8fa832f5f22a8eb719d59c93fc18510804a5",
+    "dist/2022-01-28/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "651db4ab2e12f46771ca41f1344d145d8163d5fa02b974b0ad07fe011219040c",
+    "dist/2022-01-28/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "d774f9b51f5a25b32b37b933c898eaa420d51a7ccf0277d1b980ba69a128db59",
+    "dist/2022-01-28/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "39c5c15b939ca8d41af51945e4c9aea6a8011564bfac8e71dee7141a237e7499",
+    "dist/2022-01-28/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "3fd188964c03825728fd6691210a44c715651010305436056977b15a03989b75",
+    "dist/2022-01-28/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "835877a13df7d811f5cf6f5d983a43be03a7cf831a0135900e484c1c6cb2da33",
+    "dist/2022-01-28/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "616f16ce1e5c4b50a7bc19550886cab1b861d0b925a7fab4b4d73a37e40552ed"
   }
 }
diff --git a/src/test/assembly/asm/msp430-types.rs b/src/test/assembly/asm/msp430-types.rs
new file mode 100644
index 00000000000..6cfb86e276e
--- /dev/null
+++ b/src/test/assembly/asm/msp430-types.rs
@@ -0,0 +1,158 @@
+// min-llvm-version: 13.0
+// assembly-output: emit-asm
+// compile-flags: --target msp430-none-elf
+// needs-llvm-components: msp430
+
+#![feature(no_core, lang_items, rustc_attrs, asm_sym, asm_experimental_arch, asm_const)]
+#![crate_type = "rlib"]
+#![no_core]
+#![allow(non_camel_case_types)]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+    () => {};
+}
+#[rustc_builtin_macro]
+macro_rules! concat {
+    () => {};
+}
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+type ptr = *const i16;
+
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+impl Copy for i64 {}
+impl Copy for ptr {}
+
+macro_rules! check {
+    ($func:ident $ty:ident $class:ident) => {
+        #[no_mangle]
+        pub unsafe fn $func(x: $ty) -> $ty {
+            let y;
+            asm!("mov {}, {}", lateout($class) y, in($class) x);
+            y
+        }
+    };
+}
+
+macro_rules! checkb {
+    ($func:ident $ty:ident $class:ident) => {
+        #[no_mangle]
+        pub unsafe fn $func(x: $ty) -> $ty {
+            let y;
+            asm!("mov.b {}, {}", lateout($class) y, in($class) x);
+            y
+        }
+    };
+}
+
+macro_rules! check_reg {
+    ($func:ident $ty:ident $reg:tt) => {
+        #[no_mangle]
+        pub unsafe fn $func(x: $ty) -> $ty {
+            let y;
+            asm!(concat!("mov ", $reg, ", ", $reg), lateout($reg) y, in($reg) x);
+            y
+        }
+    };
+}
+
+macro_rules! check_regb {
+    ($func:ident $ty:ident $reg:tt) => {
+        #[no_mangle]
+        pub unsafe fn $func(x: $ty) -> $ty {
+            let y;
+            asm!(concat!("mov.b ", $reg, ", ", $reg), lateout($reg) y, in($reg) x);
+            y
+        }
+    };
+}
+
+extern "C" {
+    fn extern_func();
+    static extern_static: i8;
+}
+
+// CHECK-LABEL: sym_fn
+// CHECK: ;APP
+// CHECK: call extern_func
+// CHECK: ;NO_APP
+#[no_mangle]
+pub unsafe fn sym_fn() {
+    asm!("call {}", sym extern_func);
+}
+
+// CHECK-LABEL: sym_static
+// CHECK: ;APP
+// CHECK: mov.b extern_static, r{{[0-9]+}}
+// CHECK: ;NO_APP
+#[no_mangle]
+pub unsafe fn sym_static() -> i8 {
+    let y;
+    asm!("mov.b {1}, {0}", lateout(reg) y, sym extern_static);
+    y
+}
+
+// CHECK-LABEL: add_const:
+// CHECK: ;APP
+// CHECK: add.b #5, r{{[0-9]+}}
+// CHECK: ;NO_APP
+#[no_mangle]
+pub unsafe fn add_const() -> i8 {
+    let y;
+    asm!("add.b #{number}, {}", out(reg) y, number = const 5);
+    y
+}
+
+// CHECK-LABEL: mov_postincrement:
+// CHECK: ;APP
+// CHECK: mov @r5+, r{{[0-9]+}}
+// CHECK: ;NO_APP
+#[no_mangle]
+pub unsafe fn mov_postincrement(mut x: *const i16) -> (i16, *const i16) {
+    let y;
+    asm!("mov @r5+, {0}", out(reg) y, inlateout("r5") x);
+    (y, x)
+}
+
+// CHECK-LABEL: reg_i8:
+// CHECK: ;APP
+// CHECK: mov r{{[0-9]+}}, r{{[0-9]+}}
+// CHECK: ;NO_APP
+check!(reg_i8 i8 reg);
+
+// CHECK-LABEL: reg_i16:
+// CHECK: ;APP
+// CHECK: mov r{{[0-9]+}}, r{{[0-9]+}}
+// CHECK: ;NO_APP
+check!(reg_i16 i16 reg);
+
+// CHECK-LABEL: reg_i8b:
+// CHECK: ;APP
+// CHECK: mov.b r{{[0-9]+}}, r{{[0-9]+}}
+// CHECK: ;NO_APP
+checkb!(reg_i8b i8 reg);
+
+// CHECK-LABEL: r5_i8:
+// CHECK: ;APP
+// CHECK: mov r5, r5
+// CHECK: ;NO_APP
+check_reg!(r5_i8 i8 "r5");
+
+// CHECK-LABEL: r5_i16:
+// CHECK: ;APP
+// CHECK: mov r5, r5
+// CHECK: ;NO_APP
+check_reg!(r5_i16 i16 "r5");
+
+// CHECK-LABEL: r5_i8b:
+// CHECK: ;APP
+// CHECK: mov.b r5, r5
+// CHECK: ;NO_APP
+check_regb!(r5_i8b i8 "r5");
diff --git a/src/test/codegen/naked-functions.rs b/src/test/codegen/naked-functions.rs
index c8cd6923282..51c7a0c615d 100644
--- a/src/test/codegen/naked-functions.rs
+++ b/src/test/codegen/naked-functions.rs
@@ -1,42 +1,32 @@
 // compile-flags: -C no-prepopulate-passes
+// needs-asm-support
+// only-x86_64
 
 #![crate_type = "lib"]
 #![feature(naked_functions)]
+use std::arch::asm;
 
 // CHECK: Function Attrs: naked
 // CHECK-NEXT: define{{.*}}void @naked_empty()
 #[no_mangle]
 #[naked]
-pub fn naked_empty() {
+pub unsafe extern "C" fn naked_empty() {
     // CHECK-NEXT: {{.+}}:
-    // CHECK-NEXT: ret void
+    // CHECK-NEXT: call void asm
+    // CHECK-NEXT: unreachable
+    asm!("ret",
+         options(noreturn));
 }
 
 // CHECK: Function Attrs: naked
+// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_args_and_return(i64 %a, i64 %b)
 #[no_mangle]
 #[naked]
-// CHECK-NEXT: define{{.*}}void @naked_with_args(i{{[0-9]+( %a)?}})
-pub fn naked_with_args(a: isize) {
+pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize {
     // CHECK-NEXT: {{.+}}:
-    // CHECK: ret void
-}
-
-// CHECK: Function Attrs: naked
-// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_return()
-#[no_mangle]
-#[naked]
-pub fn naked_with_return() -> isize {
-    // CHECK-NEXT: {{.+}}:
-    // CHECK-NEXT: ret i{{[0-9]+}} 0
-    0
-}
-
-// CHECK: Function Attrs: naked
-// CHECK-NEXT: define{{.*}}i{{[0-9]+}} @naked_with_args_and_return(i{{[0-9]+( %a)?}})
-#[no_mangle]
-#[naked]
-pub fn naked_with_args_and_return(a: isize) -> isize {
-    // CHECK-NEXT: {{.+}}:
-    // CHECK: ret i{{[0-9]+}} 0
-    0
+    // CHECK-NEXT: call void asm
+    // CHECK-NEXT: unreachable
+    asm!("lea rax, [rdi + rsi]",
+         "ret",
+         options(noreturn));
 }
diff --git a/src/test/codegen/naked-noinline.rs b/src/test/codegen/naked-noinline.rs
index e34ccf5c5fe..13bc139ecd0 100644
--- a/src/test/codegen/naked-noinline.rs
+++ b/src/test/codegen/naked-noinline.rs
@@ -7,7 +7,6 @@
 
 use std::arch::asm;
 
-#[inline(always)]
 #[naked]
 #[no_mangle]
 pub unsafe extern "C" fn f() {
diff --git a/src/test/codegen/unwind-and-panic-abort.rs b/src/test/codegen/unwind-and-panic-abort.rs
index 05d97f3256a..f238741e599 100644
--- a/src/test/codegen/unwind-and-panic-abort.rs
+++ b/src/test/codegen/unwind-and-panic-abort.rs
@@ -9,7 +9,7 @@ extern "C-unwind" {
 
 // CHECK: Function Attrs:{{.*}}nounwind
 // CHECK-NEXT: define{{.*}}void @foo
-// CHECK: call void @llvm.trap()
+// CHECK: call void @_ZN4core9panicking15panic_no_unwind
 #[no_mangle]
 pub unsafe extern "C" fn foo() {
     bar();
diff --git a/src/test/debuginfo/function-names.rs b/src/test/debuginfo/function-names.rs
index ac9a02cce04..61d5fc93cd2 100644
--- a/src/test/debuginfo/function-names.rs
+++ b/src/test/debuginfo/function-names.rs
@@ -37,7 +37,7 @@
 // Const generic parameter
 // gdb-command:info functions -q function_names::const_generic_fn.*
 // gdb-check:[...]static fn function_names::const_generic_fn_bool<false>();
-// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#3fcd7c34c1555be6}>();
+// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#fe3cfa0214ac55c7}>();
 // gdb-check:[...]static fn function_names::const_generic_fn_signed_int<-7>();
 // gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int<14>();
 
@@ -76,7 +76,7 @@
 // Const generic parameter
 // cdb-command:x a!function_names::const_generic_fn*
 // cdb-check:[...] a!function_names::const_generic_fn_bool<false> (void)
-// cdb-check:[...] a!function_names::const_generic_fn_non_int<CONST$3fcd7c34c1555be6> (void)
+// cdb-check:[...] a!function_names::const_generic_fn_non_int<CONST$fe3cfa0214ac55c7> (void)
 // cdb-check:[...] a!function_names::const_generic_fn_unsigned_int<14> (void)
 // cdb-check:[...] a!function_names::const_generic_fn_signed_int<-7> (void)
 
diff --git a/src/test/debuginfo/unsized.rs b/src/test/debuginfo/unsized.rs
index c27fe61dc8b..ebd40f9dda2 100644
--- a/src/test/debuginfo/unsized.rs
+++ b/src/test/debuginfo/unsized.rs
@@ -4,32 +4,56 @@
 
 // gdb-command:run
 
-// gdb-command:print *a
-// gdbg-check:$1 = {value = [...] "abc"}
-// gdbr-check:$1 = unsized::Foo<[u8]> {value: [...]}
+// gdb-command:print a
+// gdbg-check:$1 = {data_ptr = [...], length = 4}
+// gdbr-check:$1 = &unsized::Foo<[u8]> {data_ptr: [...], length: 4}
 
-// gdb-command:print *b
-// gdbg-check:$2 = {value = {value = [...] "abc"}}
-// gdbr-check:$2 = unsized::Foo<unsized::Foo<[u8]>> {value: unsized::Foo<[u8]> {value: [...]}}
+// gdb-command:print b
+// gdbg-check:$2 = {data_ptr = [...], length = 4}
+// gdbr-check:$2 = &unsized::Foo<unsized::Foo<[u8]>> {data_ptr: [...], length: 4}
 
+// gdb-command:print c
+// gdbg-check:$3 = {pointer = [...], vtable = [...]}
+// gdbr-check:$3 = &unsized::Foo<dyn core::fmt::Debug> {pointer: [...], vtable: [...]}
+
+// === CDB TESTS ===================================================================================
+
+// cdb-command: g
+// cdb-command:dx a
+// cdb-check:a                [Type: ref$<unsized::Foo<slice$<u8> > >]
+// cdb-check:    [+0x000] data_ptr         : 0x[...] [Type: unsized::Foo<slice$<u8> > *]
+// cdb-check:    [...] length           : 0x4 [Type: unsigned [...]int[...]
+
+// cdb-command:dx b
+// cdb-check:b                [Type: ref$<unsized::Foo<unsized::Foo<slice$<u8> > > >]
+// cdb-check:    [+0x000] data_ptr         : 0x[...] [Type: unsized::Foo<unsized::Foo<slice$<u8> > > *]
+// cdb-check:    [...] length           : 0x4 [Type: unsigned [...]int[...]
+
+// cdb-command:dx c
+// cdb-check:c                [Type: ref$<unsized::Foo<dyn$<core::fmt::Debug> > >]
+// cdb-check:    [+0x000] pointer          : 0x[...] [Type: unsized::Foo<dyn$<core::fmt::Debug> > *]
+// cdb-check:    [...] vtable           : 0x[...] [Type: unsigned [...]int[...] (*)[3]]
 
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
 struct Foo<T: ?Sized> {
-    value: T
+    value: T,
 }
 
 fn main() {
-    let foo: Foo<Foo<[u8; 4]>> = Foo {
-        value: Foo {
-            value: *b"abc\0"
-        }
-    };
+    let foo: Foo<Foo<[u8; 4]>> = Foo { value: Foo { value: *b"abc\0" } };
+
+    // We expect `a`, `b`, and `c` to all be fat pointers.
+    // `a` and `b` should be slice-like and thus have a `data_ptr` and `length` field.
+    // `c` should be trait-object-like and thus have a `pointer` and `vtable` field.
     let a: &Foo<[u8]> = &foo.value;
     let b: &Foo<Foo<[u8]>> = &foo;
+    let c: &Foo<dyn std::fmt::Debug> = &Foo { value: 7i32 };
 
     zzz(); // #break
 }
 
-fn zzz() { () }
+fn zzz() {
+    ()
+}
diff --git a/src/test/debuginfo/vec-slices.rs b/src/test/debuginfo/vec-slices.rs
index e109b1bf2ae..7d88e45caf2 100644
--- a/src/test/debuginfo/vec-slices.rs
+++ b/src/test/debuginfo/vec-slices.rs
@@ -1,5 +1,4 @@
 // ignore-windows
-// ignore-gdb // Test temporarily ignored due to debuginfo tests being disabled, see PR 47155
 // min-lldb-version: 310
 
 // compile-flags:-g
@@ -13,21 +12,21 @@
 // gdb-command:print singleton.length
 // gdb-check:$2 = 1
 // gdbg-command:print *((i64[1]*)(singleton.data_ptr))
-// gdbr-command:print *(singleton.data_ptr as &[i64; 1])
+// gdbr-command:print *(singleton.data_ptr as *const [i64; 1])
 // gdbg-check:$3 = {1}
 // gdbr-check:$3 = [1]
 
 // gdb-command:print multiple.length
 // gdb-check:$4 = 4
 // gdbg-command:print *((i64[4]*)(multiple.data_ptr))
-// gdbr-command:print *(multiple.data_ptr as &[i64; 4])
+// gdbr-command:print *(multiple.data_ptr as *const [i64; 4])
 // gdbg-check:$5 = {2, 3, 4, 5}
 // gdbr-check:$5 = [2, 3, 4, 5]
 
 // gdb-command:print slice_of_slice.length
 // gdb-check:$6 = 2
 // gdbg-command:print *((i64[2]*)(slice_of_slice.data_ptr))
-// gdbr-command:print *(slice_of_slice.data_ptr as &[i64; 2])
+// gdbr-command:print *(slice_of_slice.data_ptr as *const [i64; 2])
 // gdbg-check:$7 = {3, 4}
 // gdbr-check:$7 = [3, 4]
 
@@ -49,21 +48,24 @@
 // gdbg-check:$13 = {x = 13, y = 14, z = 15}
 // gdbr-check:$13 = vec_slices::AStruct {x: 13, y: 14, z: 15}
 
-// gdbg-command:print 'vec_slices::MUT_VECT_SLICE'.length
-// gdbr-command:print MUT_VECT_SLICE.length
-// gdb-check:$14 = 2
-// gdbg-command:print *((i64[2]*)('vec_slices::MUT_VECT_SLICE'.data_ptr))
-// gdbr-command:print *(MUT_VECT_SLICE.data_ptr as &[i64; 2])
-// gdbg-check:$15 = {64, 65}
-// gdbr-check:$15 = [64, 65]
+// gdb-command:print mut_slice.length
+// gdb-check:$14 = 5
+// gdbg-command:print *((i64[5]*)(mut_slice.data_ptr))
+// gdbr-command:print *(mut_slice.data_ptr as *const [i64; 5])
+// gdbg-check:$15 = {1, 2, 3, 4, 5}
+// gdbr-check:$15 = [1, 2, 3, 4, 5]
 
-//gdb-command:print mut_slice.length
-//gdb-check:$16 = 5
-//gdbg-command:print *((i64[5]*)(mut_slice.data_ptr))
-//gdbr-command:print *(mut_slice.data_ptr as &[i64; 5])
-//gdbg-check:$17 = {1, 2, 3, 4, 5}
-//gdbr-check:$17 = [1, 2, 3, 4, 5]
+// Some lines below are marked with [ignored] because old GDB versions seem to have trouble
+// accessing globals.
 
+// [ignored] gdbg-command:print 'vec_slices::MUT_VECT_SLICE'.length
+// gdbr-command:print MUT_VECT_SLICE.length
+// [ignored] gdbg-check:$16 = 2
+// gdbr-check:$16 = 2
+// [ignored] gdbg-command:print *((i64[2]*)('vec_slices::MUT_VECT_SLICE'.data_ptr))
+// gdbr-command:print *(MUT_VECT_SLICE.data_ptr as *const [i64; 2])
+// [ignored] gdbg-check:$17 = {64, 65}
+// gdbr-check:$17 = [64, 65]
 
 // === LLDB TESTS ==================================================================================
 
@@ -100,7 +102,7 @@
 struct AStruct {
     x: i16,
     y: i32,
-    z: i16
+    z: i16,
 }
 
 static VECT_SLICE: &'static [i64] = &[64, 65];
@@ -114,10 +116,8 @@ fn main() {
 
     let padded_tuple: &[(i32, i16)] = &[(6, 7), (8, 9)];
 
-    let padded_struct: &[AStruct] = &[
-        AStruct { x: 10, y: 11, z: 12 },
-        AStruct { x: 13, y: 14, z: 15 }
-    ];
+    let padded_struct: &[AStruct] =
+        &[AStruct { x: 10, y: 11, z: 12 }, AStruct { x: 13, y: 14, z: 15 }];
 
     unsafe {
         MUT_VECT_SLICE = VECT_SLICE;
@@ -128,4 +128,6 @@ fn main() {
     zzz(); // #break
 }
 
-fn zzz() {()}
+fn zzz() {
+    ()
+}
diff --git a/src/test/incremental/hashes/extern_mods.rs b/src/test/incremental/hashes/extern_mods.rs
index 4bc98fd7cd0..142780bbc85 100644
--- a/src/test/incremental/hashes/extern_mods.rs
+++ b/src/test/incremental/hashes/extern_mods.rs
@@ -27,9 +27,9 @@ extern "C" {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg = "cfail2", except = "hir_owner")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg = "cfail3")]
-#[rustc_clean(cfg = "cfail5", except = "hir_owner")]
+#[rustc_clean(cfg = "cfail5", except = "hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg = "cfail6")]
 extern "C" {
     pub fn change_function_name2(c: i64) -> i32;
@@ -132,9 +132,9 @@ extern "C" {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg = "cfail2", except = "hir_owner")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg = "cfail3")]
-#[rustc_clean(cfg = "cfail5", except = "hir_owner")]
+#[rustc_clean(cfg = "cfail5", except = "hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg = "cfail6")]
 extern "rust-call" {
     pub fn change_calling_convention(c: i32);
@@ -162,9 +162,9 @@ extern "C" {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg = "cfail2", except = "hir_owner")]
+#[rustc_clean(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg = "cfail3")]
-#[rustc_clean(cfg = "cfail5", except = "hir_owner")]
+#[rustc_clean(cfg = "cfail5", except = "hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg = "cfail6")]
 extern "C" {
     pub fn add_function1(c: i32);
diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs
index 3a59377e819..22508e41bf8 100644
--- a/src/test/incremental/hashes/inherent_impls.rs
+++ b/src/test/incremental/hashes/inherent_impls.rs
@@ -29,9 +29,9 @@ impl Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,associated_item_def_ids")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,associated_item_def_ids")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner,associated_item_def_ids")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,associated_item_def_ids")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
     #[rustc_clean(cfg="cfail3")]
@@ -54,9 +54,9 @@ impl Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
     #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir,promoted_mir,typeck")]
@@ -91,9 +91,9 @@ impl Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
     #[rustc_clean(
@@ -153,9 +153,9 @@ impl Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
     #[rustc_clean(
@@ -182,9 +182,9 @@ impl Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
     #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir")]
@@ -203,9 +203,9 @@ impl Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner,associated_item_def_ids")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,associated_item_def_ids")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner,associated_item_def_ids")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes,associated_item_def_ids")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
     #[rustc_clean(cfg="cfail2")]
@@ -232,9 +232,9 @@ impl Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
     #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir")]
@@ -257,9 +257,9 @@ impl Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
     #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
@@ -282,9 +282,9 @@ impl Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
     #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,optimized_mir,typeck")]
@@ -308,9 +308,9 @@ impl Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
     #[rustc_clean(cfg="cfail2")]
@@ -334,9 +334,9 @@ impl Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
     #[rustc_clean(cfg="cfail2", except="hir_owner_nodes,optimized_mir")]
@@ -359,9 +359,9 @@ impl Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
     #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir")]
@@ -384,9 +384,9 @@ impl Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
     #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck")]
@@ -409,9 +409,9 @@ impl Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
     #[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,fn_sig,typeck")]
@@ -443,9 +443,9 @@ impl Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
     // Warning: Note that `typeck` are coming up clean here.
@@ -492,9 +492,9 @@ impl Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
     // Warning: Note that `typeck` are coming up clean here.
@@ -538,9 +538,9 @@ impl Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
     #[rustc_clean(
@@ -584,9 +584,9 @@ impl Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
     // Warning: Note that `typeck` are coming up clean here.
@@ -633,9 +633,9 @@ impl Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
     // Warning: Note that `typeck` are coming up clean here.
@@ -668,9 +668,9 @@ impl Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl Foo {
     #[rustc_clean(cfg="cfail2")]
@@ -719,9 +719,9 @@ impl Bar<u32> {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(cfg="cfail2", except="hir_owner")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="hir_owner")]
+#[rustc_clean(cfg="cfail5", except="hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg="cfail6")]
 impl Bar<u64> {
     #[rustc_clean(cfg="cfail2", except="fn_sig,optimized_mir,typeck")]
diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs
index 14d6fc87198..279449fce5e 100644
--- a/src/test/incremental/hashes/trait_defs.rs
+++ b/src/test/incremental/hashes/trait_defs.rs
@@ -31,9 +31,9 @@
 trait TraitVisibility { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 pub trait TraitVisibility { }
 
@@ -44,9 +44,9 @@ pub trait TraitVisibility { }
 trait TraitUnsafety { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 unsafe trait TraitUnsafety { }
 
@@ -58,9 +58,9 @@ trait TraitAddMethod {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 pub trait TraitAddMethod {
     fn method();
@@ -75,9 +75,9 @@ trait TraitChangeMethodName {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitChangeMethodName {
     fn methodChanged();
@@ -88,9 +88,9 @@ trait TraitChangeMethodName {
 // Add return type to method
 #[cfg(any(cfail1,cfail4))]
 trait TraitAddReturnType {
-    //-----------------------------------------------------
+    //---------------------------------------------------------------------
     //--------------------------
-    //-----------------------------------------------------
+    //---------------------------------------------------------------------
     //--------------------------
     fn method()       ;
 }
@@ -101,9 +101,9 @@ trait TraitAddReturnType {
 #[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddReturnType {
-    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     fn method() -> u32;
 }
@@ -138,9 +138,9 @@ trait TraitChangeReturnType {
 // Add parameter to method
 #[cfg(any(cfail1,cfail4))]
 trait TraitAddParameterToMethod {
-    // ----------------------------------------------------
+    // --------------------------------------------------------------------
     // -------------------------
-    // ----------------------------------------------------
+    // --------------------------------------------------------------------
     // -------------------------
     fn method(      );
 }
@@ -151,9 +151,9 @@ trait TraitAddParameterToMethod {
 #[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddParameterToMethod {
-    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     fn method(a: u32);
 }
@@ -164,9 +164,9 @@ trait TraitAddParameterToMethod {
 #[cfg(any(cfail1,cfail4))]
 trait TraitChangeMethodParameterName {
     //------------------------------------------------------
-    //----------------------------------------------
+    //--------------------------------------------------------------
     //--------------------------
-    //----------------------------------------------
+    //--------------------------------------------------------------
     //--------------------------
     fn method(a: u32);
 
@@ -184,9 +184,9 @@ trait TraitChangeMethodParameterName {
 #[rustc_clean(cfg="cfail6")]
 trait TraitChangeMethodParameterName {
     // FIXME(#38501) This should preferably always be clean.
-    #[rustc_clean(except="hir_owner", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     fn method(b: u32);
 
@@ -202,9 +202,9 @@ trait TraitChangeMethodParameterName {
 // Change type of method parameter (i32 => i64)
 #[cfg(any(cfail1,cfail4))]
 trait TraitChangeMethodParameterType {
-    // ----------------------------------------------------
+    // --------------------------------------------------------------------
     // -------------------------
-    // ----------------------------------------------------
+    // --------------------------------------------------------------------
     // -------------------------
     fn method(a: i32);
 }
@@ -215,9 +215,9 @@ trait TraitChangeMethodParameterType {
 #[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitChangeMethodParameterType {
-    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     fn method(a: i64);
 }
@@ -227,9 +227,9 @@ trait TraitChangeMethodParameterType {
 // Change type of method parameter (&i32 => &mut i32)
 #[cfg(any(cfail1,cfail4))]
 trait TraitChangeMethodParameterTypeRef {
-    // ----------------------------------------------------
+    // --------------------------------------------------------------------
     // -------------------------
-    // ----------------------------------------------------
+    // --------------------------------------------------------------------
     // -------------------------
     fn method(a: &    i32);
 }
@@ -240,9 +240,9 @@ trait TraitChangeMethodParameterTypeRef {
 #[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitChangeMethodParameterTypeRef {
-    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     fn method(a: &mut i32);
 }
@@ -252,9 +252,9 @@ trait TraitChangeMethodParameterTypeRef {
 // Change order of method parameters
 #[cfg(any(cfail1,cfail4))]
 trait TraitChangeMethodParametersOrder {
-    // ----------------------------------------------------
+    // --------------------------------------------------------------------
     // -------------------------
-    // ----------------------------------------------------
+    // --------------------------------------------------------------------
     // -------------------------
     fn method(a: i32, b: i64);
 }
@@ -265,9 +265,9 @@ trait TraitChangeMethodParametersOrder {
 #[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitChangeMethodParametersOrder {
-    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     fn method(b: i64, a: i32);
 }
@@ -277,20 +277,24 @@ trait TraitChangeMethodParametersOrder {
 // Add default implementation to method
 #[cfg(any(cfail1,cfail4))]
 trait TraitAddMethodAutoImplementation {
-    fn method();
+    // -----------------------------------------------------------------------------
+    // -------------------------
+    // -----------------------------------------------------------------------------
+    // -------------------------
+    fn method()  ;
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddMethodAutoImplementation {
-    #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,associated_item", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
-    fn method() { }
+    fn method() {}
 }
 
 
@@ -303,9 +307,9 @@ trait TraitChangeOrderOfMethods {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitChangeOrderOfMethods {
     fn method1();
@@ -317,9 +321,9 @@ trait TraitChangeOrderOfMethods {
 // Change mode of self parameter
 #[cfg(any(cfail1,cfail4))]
 trait TraitChangeModeSelfRefToMut {
-    // ----------------------------------------------------
+    // --------------------------------------------------------------------
     // -------------------------
-    // ----------------------------------------------------
+    // --------------------------------------------------------------------
     // -------------------------
     fn method(&    self);
 }
@@ -330,9 +334,9 @@ trait TraitChangeModeSelfRefToMut {
 #[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitChangeModeSelfRefToMut {
-    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     fn method(&mut self);
 }
@@ -365,9 +369,9 @@ trait TraitChangeModeSelfOwnToMut: Sized {
 
 #[cfg(any(cfail1,cfail4))]
 trait TraitChangeModeSelfOwnToRef {
-    // ----------------------------------------------------------------
+    // --------------------------------------------------------------------------------
     // -------------------------
-    // ----------------------------------------------------------------
+    // --------------------------------------------------------------------------------
     // -------------------------
     fn method( self);
 }
@@ -378,9 +382,9 @@ trait TraitChangeModeSelfOwnToRef {
 #[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitChangeModeSelfOwnToRef {
-    #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,generics_of", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,generics_of", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     fn method(&self);
 }
@@ -390,9 +394,9 @@ trait TraitChangeModeSelfOwnToRef {
 // Add unsafe modifier to method
 #[cfg(any(cfail1,cfail4))]
 trait TraitAddUnsafeModifier {
-    // ----------------------------------------------------
+    // --------------------------------------------------------------------
     // -------------------------
-    // ----------------------------------------------------
+    // --------------------------------------------------------------------
     // -------------------------
     fn method()       ;
 }
@@ -403,9 +407,9 @@ trait TraitAddUnsafeModifier {
 #[rustc_clean(except="hir_owner", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddUnsafeModifier {
-    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     unsafe fn method();
 }
@@ -415,9 +419,9 @@ trait TraitAddUnsafeModifier {
 // Add extern modifier to method
 #[cfg(any(cfail1,cfail4))]
 trait TraitAddExternModifier {
-    // ----------------------------------------------------
+    // --------------------------------------------------------------------
     // -------------------------
-    // ----------------------------------------------------
+    // --------------------------------------------------------------------
     // -------------------------
     fn method()           ;
 }
@@ -428,9 +432,9 @@ trait TraitAddExternModifier {
 #[rustc_clean(except="hir_owner", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddExternModifier {
-    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     extern "C" fn method();
 }
@@ -440,9 +444,9 @@ trait TraitAddExternModifier {
 // Change extern "C" to extern "stdcall"
 #[cfg(any(cfail1,cfail4))]
 trait TraitChangeExternCToRustIntrinsic {
-    // ----------------------------------------------------
+    // --------------------------------------------------------------------
     // -------------------------
-    // ----------------------------------------------------
+    // --------------------------------------------------------------------
     // -------------------------
     extern "C"       fn method();
 }
@@ -453,9 +457,9 @@ trait TraitChangeExternCToRustIntrinsic {
 #[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitChangeExternCToRustIntrinsic {
-    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     extern "stdcall" fn method();
 }
@@ -465,9 +469,11 @@ trait TraitChangeExternCToRustIntrinsic {
 // Add type parameter to method
 #[cfg(any(cfail1,cfail4))]
 trait TraitAddTypeParameterToMethod {
-    // -------------------------------------------------------------------------------
+    // --------------------------------------------------------------------------------
+    // ---------------
     // -------------------------
-    // -------------------------------------------------------------------------------
+    // --------------------------------------------------------------------------------
+    // ---------------
     // -------------------------
     fn method   ();
 }
@@ -478,9 +484,11 @@ trait TraitAddTypeParameterToMethod {
 #[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddTypeParameterToMethod {
-    #[rustc_clean(except="hir_owner,generics_of,predicates_of,type_of", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of",
+        cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,generics_of,predicates_of,type_of", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of",
+        cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     fn method<T>();
 }
@@ -490,9 +498,9 @@ trait TraitAddTypeParameterToMethod {
 // Add lifetime parameter to method
 #[cfg(any(cfail1,cfail4))]
 trait TraitAddLifetimeParameterToMethod {
-    // ----------------------------------------------------------------
+    // --------------------------------------------------------------------------------
     // -------------------------
-    // ----------------------------------------------------------------
+    // --------------------------------------------------------------------------------
     // -------------------------
     fn method    ();
 }
@@ -503,9 +511,9 @@ trait TraitAddLifetimeParameterToMethod {
 #[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddLifetimeParameterToMethod {
-    #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,generics_of", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,generics_of", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     fn method<'a>();
 }
@@ -705,9 +713,9 @@ trait TraitAddAssociatedType {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddAssociatedType {
     #[rustc_clean(cfg="cfail3")]
@@ -726,9 +734,9 @@ trait TraitAddAssociatedType {
 // Add trait bound to associated type
 #[cfg(any(cfail1,cfail4))]
 trait TraitAddTraitBoundToAssociatedType {
-    // ---------------------------------------------
+    // -------------------------------------------------------------
     // -------------------------
-    // ---------------------------------------------
+    // -------------------------------------------------------------
     // -------------------------
     type Associated                  ;
 
@@ -744,9 +752,9 @@ trait TraitAddTraitBoundToAssociatedType {
 #[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddTraitBoundToAssociatedType {
-    #[rustc_clean(except="hir_owner", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     type Associated: ReferencedTrait0;
 
@@ -758,9 +766,9 @@ trait TraitAddTraitBoundToAssociatedType {
 // Add lifetime bound to associated type
 #[cfg(any(cfail1,cfail4))]
 trait TraitAddLifetimeBoundToAssociatedType<'a> {
-    // ---------------------------------------------
+    // -------------------------------------------------------------
     // -------------------------
-    // ---------------------------------------------
+    // -------------------------------------------------------------
     // -------------------------
     type Associated    ;
 
@@ -773,9 +781,9 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> {
 #[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddLifetimeBoundToAssociatedType<'a> {
-    #[rustc_clean(except="hir_owner", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     type Associated: 'a;
 
@@ -793,14 +801,14 @@ trait TraitAddDefaultToAssociatedType {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddDefaultToAssociatedType {
-    #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,associated_item", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     type Associated = ReferenceType0;
 
@@ -816,9 +824,9 @@ trait TraitAddAssociatedConstant {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddAssociatedConstant {
     const Value: u32;
@@ -837,14 +845,14 @@ trait TraitAddInitializerToAssociatedConstant {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddInitializerToAssociatedConstant {
-    #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,associated_item", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     const Value: u32 = 1;
 
@@ -860,9 +868,9 @@ trait TraitAddInitializerToAssociatedConstant {
 // Change type of associated constant
 #[cfg(any(cfail1,cfail4))]
 trait TraitChangeTypeOfAssociatedConstant {
-    // -----------------------------------------------------
+    // ---------------------------------------------------------------------
     // -------------------------
-    // -----------------------------------------------------
+    // ---------------------------------------------------------------------
     // -------------------------
     const Value: u32;
 
@@ -879,9 +887,9 @@ trait TraitChangeTypeOfAssociatedConstant {
 #[rustc_clean(cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitChangeTypeOfAssociatedConstant {
-    #[rustc_clean(except="hir_owner,type_of", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,type_of", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     const Value: f64;
 
@@ -899,9 +907,9 @@ trait TraitChangeTypeOfAssociatedConstant {
 trait TraitAddSuperTrait { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddSuperTrait : ReferencedTrait0 { }
 
@@ -912,9 +920,9 @@ trait TraitAddSuperTrait : ReferencedTrait0 { }
 trait TraitAddBuiltiBound { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddBuiltiBound : Send { }
 
@@ -925,9 +933,9 @@ trait TraitAddBuiltiBound : Send { }
 trait TraitAddStaticLifetimeBound { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddStaticLifetimeBound : 'static { }
 
@@ -938,9 +946,9 @@ trait TraitAddStaticLifetimeBound : 'static { }
 trait TraitAddTraitAsSecondBound : ReferencedTrait0 { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddTraitAsSecondBound : ReferencedTrait0 + ReferencedTrait1 { }
 
@@ -948,9 +956,9 @@ trait TraitAddTraitAsSecondBound : ReferencedTrait0 + ReferencedTrait1 { }
 trait TraitAddTraitAsSecondBoundFromBuiltin : Send { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { }
 
@@ -961,9 +969,9 @@ trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { }
 trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 + Send { }
 
@@ -971,9 +979,9 @@ trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 + Send { }
 trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin : Send { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { }
 
@@ -984,9 +992,9 @@ trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { }
 trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 + 'static { }
 
@@ -994,9 +1002,9 @@ trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 + 'static { }
 trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { }
 
@@ -1007,9 +1015,9 @@ trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { }
 trait TraitAddTypeParameterToTrait { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddTypeParameterToTrait<T> { }
 
@@ -1020,9 +1028,9 @@ trait TraitAddTypeParameterToTrait<T> { }
 trait TraitAddLifetimeParameterToTrait { }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddLifetimeParameterToTrait<'a> { }
 
@@ -1298,9 +1306,13 @@ mod change_method_parameter_type_indirectly_by_use {
 
     #[rustc_clean(cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
+    #[rustc_clean(cfg="cfail5")]
+    #[rustc_clean(cfg="cfail6")]
     trait TraitChangeArgType {
-        #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")]
+        #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")]
         #[rustc_clean(cfg="cfail3")]
+        #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail5")]
+        #[rustc_clean(cfg="cfail6")]
         fn method(a: ArgType);
     }
 }
@@ -1316,9 +1328,13 @@ mod change_method_parameter_type_bound_indirectly_by_use {
 
     #[rustc_clean(cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
+    #[rustc_clean(cfg="cfail5")]
+    #[rustc_clean(cfg="cfail6")]
     trait TraitChangeBoundOfMethodTypeParameter {
         #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
         #[rustc_clean(cfg="cfail3")]
+        #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")]
+        #[rustc_clean(cfg="cfail6")]
         fn method<T: Bound>(a: T);
     }
 }
@@ -1357,6 +1373,8 @@ mod change_method_type_parameter_bound_indirectly {
 
     #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail5")]
+    #[rustc_clean(cfg="cfail6")]
     trait TraitChangeTraitBound<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 d623810115e..75c93b73f85 100644
--- a/src/test/incremental/hashes/trait_impls.rs
+++ b/src/test/incremental/hashes/trait_impls.rs
@@ -35,9 +35,9 @@ impl ChangeMethodNameTrait for Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 pub trait ChangeMethodNameTrait {
     #[rustc_clean(cfg="cfail3")]
@@ -46,9 +46,9 @@ pub trait ChangeMethodNameTrait {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl ChangeMethodNameTrait for Foo {
     #[rustc_clean(cfg="cfail3")]
@@ -144,9 +144,9 @@ pub trait ChangeMethodSelfnessTrait {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl ChangeMethodSelfnessTrait for Foo {
     #[rustc_clean(
@@ -182,9 +182,9 @@ pub trait RemoveMethodSelfnessTrait {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl RemoveMethodSelfnessTrait for Foo {
     #[rustc_clean(
@@ -252,9 +252,9 @@ pub trait ChangeItemKindTrait {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl ChangeItemKindTrait for Foo {
     type name = ();
@@ -280,9 +280,9 @@ pub trait RemoveItemTrait {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl RemoveItemTrait for Foo {
     type TypeName = ();
@@ -307,9 +307,9 @@ pub trait AddItemTrait {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item_def_ids", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl AddItemTrait for Foo {
     type TypeName = ();
@@ -329,14 +329,14 @@ impl ChangeHasValueTrait for Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 pub trait ChangeHasValueTrait {
-    #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
     #[rustc_clean(cfg="cfail3")]
-    #[rustc_clean(except="hir_owner,associated_item", cfg="cfail5")]
+    #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
     fn method_name() { }
 }
@@ -364,9 +364,9 @@ impl AddDefaultTrait for Foo {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl AddDefaultTrait for Foo {
     #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")]
@@ -459,9 +459,9 @@ impl AddTypeParameterToImpl<u32> for Bar<u32> {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,generics_of,impl_trait_ref", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,impl_trait_ref", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,generics_of,impl_trait_ref", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,impl_trait_ref", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl<TTT> AddTypeParameterToImpl<TTT> for Bar<TTT> {
     #[rustc_clean(
@@ -490,9 +490,9 @@ impl ChangeSelfTypeOfImpl for u32 {
 }
 
 #[cfg(not(any(cfail1,cfail4)))]
-#[rustc_clean(except="hir_owner,impl_trait_ref", cfg="cfail2")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,impl_trait_ref", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="hir_owner,impl_trait_ref", cfg="cfail5")]
+#[rustc_clean(except="hir_owner,hir_owner_nodes,impl_trait_ref", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 impl ChangeSelfTypeOfImpl for u64 {
     #[rustc_clean(except="fn_sig,typeck,optimized_mir", cfg="cfail2")]
diff --git a/src/test/incremental/hashes/type_defs.rs b/src/test/incremental/hashes/type_defs.rs
index 70c199bc3be..1d278c4efa9 100644
--- a/src/test/incremental/hashes/type_defs.rs
+++ b/src/test/incremental/hashes/type_defs.rs
@@ -24,7 +24,7 @@
 type ChangePrimitiveType = i32;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
 type ChangePrimitiveType = i64;
 
@@ -35,7 +35,7 @@ type ChangePrimitiveType = i64;
 type ChangeMutability = &'static i32;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
 type ChangeMutability = &'static mut i32;
 
@@ -60,7 +60,7 @@ struct Struct2;
 type ChangeTypeStruct = Struct1;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
 type ChangeTypeStruct = Struct2;
 
@@ -71,7 +71,7 @@ type ChangeTypeStruct = Struct2;
 type ChangeTypeTuple = (u32, u64);
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
 type ChangeTypeTuple = (u32, i64);
 
@@ -91,7 +91,7 @@ enum Enum2 {
 type ChangeTypeEnum = Enum1;
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
 type ChangeTypeEnum = Enum2;
 
@@ -102,7 +102,7 @@ type ChangeTypeEnum = Enum2;
 type AddTupleField = (i32, i64);
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
 type AddTupleField = (i32, i64, i16);
 
@@ -113,7 +113,7 @@ type AddTupleField = (i32, i64, i16);
 type ChangeNestedTupleField = (i32, (i64, i16));
 
 #[cfg(not(cfail1))]
-#[rustc_clean(cfg="cfail2", except="hir_owner")]
+#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes")]
 #[rustc_clean(cfg="cfail3")]
 type ChangeNestedTupleField = (i32, (i64, i8));
 
diff --git a/src/test/incremental/issue-92987-provisional-dep-node.rs b/src/test/incremental/issue-92987-provisional-dep-node.rs
new file mode 100644
index 00000000000..a48a8373c2b
--- /dev/null
+++ b/src/test/incremental/issue-92987-provisional-dep-node.rs
@@ -0,0 +1,24 @@
+// revisions: rpass1 rpass2
+
+// Regression test for issue #92987
+// Tests that we properly manage `DepNode`s during trait evaluation
+// involing an auto-trait cycle.
+
+#[cfg(rpass1)]
+struct CycleOne(Box<CycleTwo>);
+
+#[cfg(rpass2)]
+enum CycleOne {
+    Variant(Box<CycleTwo>)
+}
+
+struct CycleTwo(CycleOne);
+
+fn assert_send<T: Send>() {}
+
+fn bar() {
+    assert_send::<CycleOne>();
+    assert_send::<CycleTwo>();
+}
+
+fn main() {}
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 1e531365638..b480b257825 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:44
 +                                          // + span: $DIR/const-promotion-extern-static.rs:9:31: 9:44
-+                                          // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[HASH]::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[e01c]::BAR), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
 +         _2 = &(*_6);                     // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44
           _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44
 -         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 a012285c7ec..ed48f5dc9dc 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:55
 +                                          // + span: $DIR/const-promotion-extern-static.rs:13:31: 13:55
-+                                          // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[HASH]::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[e01c]::FOO), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
 +         _2 = &(*_6);                     // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55
           _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55
 -         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 7627ed54623..553011f1aaa 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[HASH]::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[fbcf]::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 7627ed54623..553011f1aaa 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[HASH]::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[fbcf]::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 e6220176778..44273b763be 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[HASH]::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[809a]::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 d602e12a370..2864e01d9dc 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[HASH]::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[d561]::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 35916d90e56..5a678616f63 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[HASH]::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[d561]::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 39651884e77..53f9daa09da 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[HASH]::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[d1f7]::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 501d7205679..d5235a1d025 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[HASH]::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[d1f7]::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 6a580278d5f..339c3d13b8d 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
@@ -25,7 +25,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[HASH]::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[7261]::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
           StorageLive(_10);                // 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 6a580278d5f..339c3d13b8d 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
@@ -25,7 +25,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[HASH]::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[7261]::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
           StorageLive(_10);                // scope 0 at $DIR/slice_len.rs:5:6: 5:19
diff --git a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
index c1591e5d729..3fe23633852 100644
--- a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
+++ b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
@@ -12,8 +12,8 @@
       let mut _7: isize;                   // in scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17
       let _8: u32;                         // in scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16
       let _9: u32;                         // in scope 0 at $DIR/early_otherwise_branch.rs:5:24: 5:25
-+     let mut _10: isize;                  // in scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26
-+     let mut _11: bool;                   // in scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26
++     let mut _10: isize;                  // in scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17
++     let mut _11: bool;                   // in scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17
       scope 1 {
           debug a => _8;                   // in scope 1 at $DIR/early_otherwise_branch.rs:5:15: 5:16
           debug b => _9;                   // in scope 1 at $DIR/early_otherwise_branch.rs:5:24: 5:25
@@ -34,7 +34,7 @@
 +         StorageLive(_10);                // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17
 +         _10 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17
 +         StorageLive(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17
-+         _11 = Ne(_10, _7);               // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17
++         _11 = Ne(_7, move _10);          // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17
 +         StorageDead(_10);                // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17
 +         switchInt(move _11) -> [false: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17
       }
@@ -70,8 +70,8 @@
 +     }
 + 
 +     bb4: {
-+         StorageDead(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26
-+         switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26
++         StorageDead(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17
++         switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 4:17
       }
   }
   
diff --git a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
index b949d307e20..6d149b89edb 100644
--- a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
+++ b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff
@@ -13,8 +13,8 @@
       let mut _8: isize;                   // in scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17
       let _9: u32;                         // in scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16
       let _10: u32;                        // in scope 0 at $DIR/early_otherwise_branch.rs:13:24: 13:25
-+     let mut _11: isize;                  // in scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20
-+     let mut _12: bool;                   // in scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20
++     let mut _11: isize;                  // in scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
++     let mut _12: bool;                   // in scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
       scope 1 {
           debug a => _9;                   // in scope 1 at $DIR/early_otherwise_branch.rs:13:15: 13:16
           debug b => _10;                  // in scope 1 at $DIR/early_otherwise_branch.rs:13:24: 13:25
@@ -35,7 +35,7 @@
 +         StorageLive(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
 +         _11 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
 +         StorageLive(_12);                // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
-+         _12 = Ne(_11, _8);               // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
++         _12 = Ne(_8, move _11);          // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
 +         StorageDead(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
 +         switchInt(move _12) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
       }
@@ -84,8 +84,8 @@
 +     }
 + 
 +     bb5: {
-+         StorageDead(_12);                // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20
-+         switchInt(_8) -> [0_isize: bb3, 1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20
++         StorageDead(_12);                // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
++         switchInt(_8) -> [0_isize: bb3, 1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 12:17
       }
   }
   
diff --git a/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
new file mode 100644
index 00000000000..2aa22737bde
--- /dev/null
+++ b/src/test/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
@@ -0,0 +1,77 @@
+- // MIR for `opt3` before EarlyOtherwiseBranch
++ // MIR for `opt3` after EarlyOtherwiseBranch
+  
+  fn opt3(_1: Option<u32>, _2: Option<bool>) -> u32 {
+      debug x => _1;                       // in scope 0 at $DIR/early_otherwise_branch.rs:21:9: 21:10
+      debug y => _2;                       // in scope 0 at $DIR/early_otherwise_branch.rs:21:25: 21:26
+      let mut _0: u32;                     // return place in scope 0 at $DIR/early_otherwise_branch.rs:21:45: 21:48
+      let mut _3: (std::option::Option<u32>, std::option::Option<bool>); // in scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17
+      let mut _4: std::option::Option<u32>; // in scope 0 at $DIR/early_otherwise_branch.rs:22:12: 22:13
+      let mut _5: std::option::Option<bool>; // in scope 0 at $DIR/early_otherwise_branch.rs:22:15: 22:16
+      let mut _6: isize;                   // in scope 0 at $DIR/early_otherwise_branch.rs:23:19: 23:26
+      let mut _7: isize;                   // in scope 0 at $DIR/early_otherwise_branch.rs:23:10: 23:17
+      let _8: u32;                         // in scope 0 at $DIR/early_otherwise_branch.rs:23:15: 23:16
+      let _9: bool;                        // in scope 0 at $DIR/early_otherwise_branch.rs:23:24: 23:25
++     let mut _10: isize;                  // in scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17
++     let mut _11: bool;                   // in scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17
+      scope 1 {
+          debug a => _8;                   // in scope 1 at $DIR/early_otherwise_branch.rs:23:15: 23:16
+          debug b => _9;                   // in scope 1 at $DIR/early_otherwise_branch.rs:23:24: 23:25
+      }
+  
+      bb0: {
+          StorageLive(_3);                 // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17
+          StorageLive(_4);                 // scope 0 at $DIR/early_otherwise_branch.rs:22:12: 22:13
+          _4 = _1;                         // scope 0 at $DIR/early_otherwise_branch.rs:22:12: 22:13
+          StorageLive(_5);                 // scope 0 at $DIR/early_otherwise_branch.rs:22:15: 22:16
+          _5 = _2;                         // scope 0 at $DIR/early_otherwise_branch.rs:22:15: 22:16
+          (_3.0: std::option::Option<u32>) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17
+          (_3.1: std::option::Option<bool>) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17
+          StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch.rs:22:16: 22:17
+          StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch.rs:22:16: 22:17
+          _7 = discriminant((_3.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17
+-         switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17
++         StorageLive(_10);                // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17
++         _10 = discriminant((_3.1: std::option::Option<bool>)); // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17
++         StorageLive(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17
++         _11 = Ne(_7, move _10);          // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17
++         StorageDead(_10);                // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17
++         switchInt(move _11) -> [false: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17
+      }
+  
+      bb1: {
++         StorageDead(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:24:14: 24:15
+          _0 = const 1_u32;                // scope 0 at $DIR/early_otherwise_branch.rs:24:14: 24:15
+-         goto -> bb4;                     // scope 0 at $DIR/early_otherwise_branch.rs:24:14: 24:15
++         goto -> bb3;                     // scope 0 at $DIR/early_otherwise_branch.rs:24:14: 24:15
+      }
+  
+      bb2: {
+-         _6 = discriminant((_3.1: std::option::Option<bool>)); // scope 0 at $DIR/early_otherwise_branch.rs:22:11: 22:17
+-         switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17
+-     }
+- 
+-     bb3: {
+          StorageLive(_8);                 // scope 0 at $DIR/early_otherwise_branch.rs:23:15: 23:16
+          _8 = (((_3.0: std::option::Option<u32>) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:23:15: 23:16
+          StorageLive(_9);                 // scope 0 at $DIR/early_otherwise_branch.rs:23:24: 23:25
+          _9 = (((_3.1: std::option::Option<bool>) as Some).0: bool); // scope 0 at $DIR/early_otherwise_branch.rs:23:24: 23:25
+          _0 = const 0_u32;                // scope 1 at $DIR/early_otherwise_branch.rs:23:31: 23:32
+          StorageDead(_9);                 // scope 0 at $DIR/early_otherwise_branch.rs:23:31: 23:32
+          StorageDead(_8);                 // scope 0 at $DIR/early_otherwise_branch.rs:23:31: 23:32
+-         goto -> bb4;                     // scope 0 at $DIR/early_otherwise_branch.rs:23:31: 23:32
++         goto -> bb3;                     // scope 0 at $DIR/early_otherwise_branch.rs:23:31: 23:32
+      }
+  
+-     bb4: {
++     bb3: {
+          StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch.rs:26:1: 26:2
+          return;                          // scope 0 at $DIR/early_otherwise_branch.rs:26:2: 26:2
++     }
++ 
++     bb4: {
++         StorageDead(_11);                // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17
++         switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:22:5: 22:17
+      }
+  }
+  
diff --git a/src/test/mir-opt/early_otherwise_branch.rs b/src/test/mir-opt/early_otherwise_branch.rs
index b2caf7d7b8f..e0ebcfeebfc 100644
--- a/src/test/mir-opt/early_otherwise_branch.rs
+++ b/src/test/mir-opt/early_otherwise_branch.rs
@@ -16,7 +16,17 @@ fn opt2(x: Option<u32>, y: Option<u32>) -> u32 {
     }
 }
 
+// optimize despite different types
+// EMIT_MIR early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
+fn opt3(x: Option<u32>, y: Option<bool>) -> u32 {
+    match (x, y) {
+        (Some(a), Some(b)) => 0,
+        _ => 1,
+    }
+}
+
 fn main() {
     opt1(None, Some(0));
     opt2(None, Some(0));
+    opt3(None, Some(false));
 }
diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
index 5b9ec1e53d9..8b78f3ce202 100644
--- a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
+++ b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
@@ -16,10 +16,10 @@
       let _11: u32;                        // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16
       let _12: u32;                        // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25
       let _13: u32;                        // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:33: 6:34
-+     let mut _14: isize;                  // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26
-+     let mut _15: bool;                   // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26
-+     let mut _16: isize;                  // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35
-+     let mut _17: bool;                   // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35
++     let mut _14: isize;                  // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
++     let mut _15: bool;                   // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
++     let mut _16: isize;                  // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
++     let mut _17: bool;                   // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
       scope 1 {
           debug a => _11;                  // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16
           debug b => _12;                  // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25
@@ -45,7 +45,7 @@
 +         StorageLive(_14);                // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
 +         _14 = discriminant((_4.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
 +         StorageLive(_15);                // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
-+         _15 = Ne(_14, _10);              // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
++         _15 = Ne(_10, move _14);         // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
 +         StorageDead(_14);                // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
 +         switchInt(move _15) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
       }
@@ -92,8 +92,8 @@
 +     }
 + 
 +     bb5: {
-+         StorageDead(_15);                // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26
-+         switchInt(_10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26
++         StorageDead(_15);                // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
++         switchInt(_10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 5:20
       }
   }
   
diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff
index 44294030439..fc2dcb25109 100644
--- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff
+++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyConstCondition-final.after.diff
@@ -36,8 +36,8 @@
       let mut _31: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
       let mut _32: !;                      // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:14: 26:28
       let mut _33: ();                     // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
-+     let mut _34: isize;                  // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30
-+     let mut _35: bool;                   // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30
++     let mut _34: isize;                  // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
++     let mut _35: bool;                   // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
       scope 1 {
 -         debug one => _12;                // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
 -         debug other => _13;              // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
@@ -85,7 +85,7 @@
 +         StorageLive(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
 +         _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
 +         StorageLive(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+         _35 = Ne(_34, _11);              // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
++         _35 = Ne(_11, move _34);         // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
 +         StorageDead(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
 +         switchInt(move _35) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
       }
@@ -293,8 +293,8 @@
 -         StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:6: 27:7
 -         StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:1: 28:2
 -         return;                          // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:2: 28:2
-+         StorageDead(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30
-+         switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30
++         StorageDead(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
++         switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
       }
   }
   
diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
index af32d4d2d14..28c650d72dc 100644
--- a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
+++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff
@@ -36,8 +36,8 @@
       let mut _31: f32;                    // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55
       let mut _32: !;                      // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:14: 26:28
       let mut _33: ();                     // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:25: 26:27
-+     let mut _34: isize;                  // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30
-+     let mut _35: bool;                   // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30
++     let mut _34: isize;                  // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
++     let mut _35: bool;                   // in scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
       scope 1 {
           debug one => _12;                // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:17
           debug other => _13;              // in scope 1 at $DIR/early_otherwise_branch_68867.rs:22:24: 22:29
@@ -71,7 +71,7 @@
 +         StorageLive(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
 +         _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
 +         StorageLive(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
-+         _35 = Ne(_34, _11);              // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
++         _35 = Ne(_11, move _34);         // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
 +         StorageDead(_34);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
 +         switchInt(move _35) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
       }
@@ -209,8 +209,8 @@
 +     }
 + 
 +     bb7: {
-+         StorageDead(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30
-+         switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:21: 22:30
++         StorageDead(_35);                // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
++         switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:21:8: 21:24
       }
   }
   
diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff
deleted file mode 100644
index 66ea828bf68..00000000000
--- a/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff
+++ /dev/null
@@ -1,60 +0,0 @@
-- // MIR for `noopt2` before EarlyOtherwiseBranch
-+ // MIR for `noopt2` after EarlyOtherwiseBranch
-  
-  fn noopt2(_1: Option<u32>, _2: Option<bool>) -> u32 {
-      debug x => _1;                       // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:18:11: 18:12
-      debug y => _2;                       // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:18:27: 18:28
-      let mut _0: u32;                     // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:18:47: 18:50
-      let mut _3: (std::option::Option<u32>, std::option::Option<bool>); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17
-      let mut _4: std::option::Option<u32>; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:12: 19:13
-      let mut _5: std::option::Option<bool>; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:15: 19:16
-      let mut _6: isize;                   // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:19: 20:26
-      let mut _7: isize;                   // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:10: 20:17
-      let _8: u32;                         // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16
-      let _9: bool;                        // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25
-      scope 1 {
-          debug a => _8;                   // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16
-          debug b => _9;                   // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25
-      }
-  
-      bb0: {
-          StorageLive(_3);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17
-          StorageLive(_4);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:12: 19:13
-          _4 = _1;                         // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:12: 19:13
-          StorageLive(_5);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:15: 19:16
-          _5 = _2;                         // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:15: 19:16
-          (_3.0: std::option::Option<u32>) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17
-          (_3.1: std::option::Option<bool>) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17
-          StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:16: 19:17
-          StorageDead(_4);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:16: 19:17
-          _7 = discriminant((_3.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17
-          switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:5: 19:17
-      }
-  
-      bb1: {
-          _0 = const 1_u32;                // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:14: 21:15
-          goto -> bb4;                     // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:14: 21:15
-      }
-  
-      bb2: {
-          _6 = discriminant((_3.1: std::option::Option<bool>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17
-          switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:5: 19:17
-      }
-  
-      bb3: {
-          StorageLive(_8);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16
-          _8 = (((_3.0: std::option::Option<u32>) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16
-          StorageLive(_9);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25
-          _9 = (((_3.1: std::option::Option<bool>) as Some).0: bool); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25
-          _0 = const 0_u32;                // scope 1 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32
-          StorageDead(_9);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32
-          StorageDead(_8);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32
-          goto -> bb4;                     // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32
-      }
-  
-      bb4: {
-          StorageDead(_3);                 // scope 0 at $DIR/early_otherwise_branch_noopt.rs:23:1: 23:2
-          return;                          // scope 0 at $DIR/early_otherwise_branch_noopt.rs:23:2: 23:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.rs b/src/test/mir-opt/early_otherwise_branch_noopt.rs
index d04e2a0429d..1f8c59df35f 100644
--- a/src/test/mir-opt/early_otherwise_branch_noopt.rs
+++ b/src/test/mir-opt/early_otherwise_branch_noopt.rs
@@ -13,16 +13,6 @@ fn noopt1(x: Option<u32>, y: Option<u32>) -> u32 {
     }
 }
 
-// must not optimize as the types being matched on are not identical
-// EMIT_MIR early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff
-fn noopt2(x: Option<u32>, y: Option<bool>) -> u32 {
-    match (x, y) {
-        (Some(a), Some(b)) => 0,
-        _ => 1,
-    }
-}
-
 fn main() {
     noopt1(None, Some(0));
-    noopt2(None, Some(true));
 }
diff --git a/src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff
new file mode 100644
index 00000000000..a2722660662
--- /dev/null
+++ b/src/test/mir-opt/early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff
@@ -0,0 +1,43 @@
+- // MIR for `no_deref_ptr` before EarlyOtherwiseBranch
++ // MIR for `no_deref_ptr` after EarlyOtherwiseBranch
+  
+  fn no_deref_ptr(_1: Option<i32>, _2: *const Option<i32>) -> i32 {
+      debug a => _1;                       // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:18:24: 18:25
+      debug b => _2;                       // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:18:40: 18:41
+      let mut _0: i32;                     // return place in scope 0 at $DIR/early_otherwise_branch_soundness.rs:18:66: 18:69
+      let mut _3: isize;                   // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:21:9: 21:16
+      let mut _4: isize;                   // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:13: 22:20
+      let _5: i32;                         // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:18: 22:19
+      scope 1 {
+          debug v => _5;                   // in scope 1 at $DIR/early_otherwise_branch_soundness.rs:22:18: 22:19
+      }
+  
+      bb0: {
+          _3 = discriminant(_1);           // scope 0 at $DIR/early_otherwise_branch_soundness.rs:19:11: 19:12
+          switchInt(move _3) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:19:5: 19:12
+      }
+  
+      bb1: {
+          _0 = const 0_i32;                // scope 0 at $DIR/early_otherwise_branch_soundness.rs:25:14: 25:15
+          return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:25:14: 25:15
+      }
+  
+      bb2: {
+          _4 = discriminant((*_2));        // scope 0 at $DIR/early_otherwise_branch_soundness.rs:21:26: 21:28
+          switchInt(move _4) -> [1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:21:20: 21:28
+      }
+  
+      bb3: {
+          _0 = const 0_i32;                // scope 0 at $DIR/early_otherwise_branch_soundness.rs:23:18: 23:19
+          return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:23:18: 23:19
+      }
+  
+      bb4: {
+          StorageLive(_5);                 // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:18: 22:19
+          _5 = (((*_2) as Some).0: i32);   // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:18: 22:19
+          _0 = _5;                         // scope 1 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25
+          StorageDead(_5);                 // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25
+          return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:22:24: 22:25
+      }
+  }
+  
diff --git a/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff
new file mode 100644
index 00000000000..56b7c9a2db4
--- /dev/null
+++ b/src/test/mir-opt/early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff
@@ -0,0 +1,30 @@
+- // MIR for `no_downcast` before EarlyOtherwiseBranch
++ // MIR for `no_downcast` after EarlyOtherwiseBranch
+  
+  fn no_downcast(_1: &E) -> u32 {
+      debug e => _1;                       // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:12:16: 12:17
+      let mut _0: u32;                     // return place in scope 0 at $DIR/early_otherwise_branch_soundness.rs:12:26: 12:29
+      let mut _2: isize;                   // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:20: 13:30
+      let mut _3: isize;                   // in scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
+  
+      bb0: {
+          _3 = discriminant((*_1));        // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
+          switchInt(move _3) -> [1_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
+      }
+  
+      bb1: {
+          _2 = discriminant((*(((*_1) as Some).0: &E))); // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
+          switchInt(move _2) -> [1_isize: bb2, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:12: 13:31
+      }
+  
+      bb2: {
+          _0 = const 1_u32;                // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:38: 13:39
+          return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:5: 13:52
+      }
+  
+      bb3: {
+          _0 = const 2_u32;                // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:49: 13:50
+          return;                          // scope 0 at $DIR/early_otherwise_branch_soundness.rs:13:5: 13:52
+      }
+  }
+  
diff --git a/src/test/mir-opt/early_otherwise_branch_soundness.rs b/src/test/mir-opt/early_otherwise_branch_soundness.rs
new file mode 100644
index 00000000000..d2513213d79
--- /dev/null
+++ b/src/test/mir-opt/early_otherwise_branch_soundness.rs
@@ -0,0 +1,32 @@
+// compile-flags: -Z mir-opt-level=4 -Zunsound-mir-opts
+
+// Tests various cases that the `early_otherwise_branch` opt should *not* optimize
+
+// From #78496
+enum E<'a> {
+    Empty,
+    Some(&'a E<'a>),
+}
+
+// EMIT_MIR early_otherwise_branch_soundness.no_downcast.EarlyOtherwiseBranch.diff
+fn no_downcast(e: &E) -> u32 {
+    if let E::Some(E::Some(_)) = e { 1 } else { 2 }
+}
+
+// SAFETY: if `a` is `Some`, `b` must point to a valid, initialized value
+// EMIT_MIR early_otherwise_branch_soundness.no_deref_ptr.EarlyOtherwiseBranch.diff
+unsafe fn no_deref_ptr(a: Option<i32>, b: *const Option<i32>) -> i32 {
+    match a {
+        // `*b` being correct depends on `a == Some(_)`
+        Some(_) => match *b {
+            Some(v) => v,
+            _ => 0,
+        },
+        _ => 0,
+    }
+}
+
+fn main() {
+    no_downcast(&E::Empty);
+    unsafe { no_deref_ptr(None, std::ptr::null()) };
+}
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 486fc7541c3..5e3ec0889e9 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[HASH]::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[86d7]::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[HASH]::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[86d7]::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_73223.main.PreCodegen.32bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
index 7938c0a23e8..016e0cb5901 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[HASH]::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[9565]::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 7938c0a23e8..016e0cb5901 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[HASH]::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[9565]::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 20771bf4231..59daeb1e997 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[HASH]::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[9565]::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 20771bf4231..59daeb1e997 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[HASH]::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[9565]::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 75d0e75f5b1..644a5593a9d 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:75:42: 75:44
-                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[HASH]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[2]) }) }
+                                           // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[49eb]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[2]) }) }
           _7 = &(*_19);                    // scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44
           _6 = &(*_7);                     // scope 0 at $DIR/lower_intrinsics.rs:75:42: 75:44
 -         _5 = discriminant_value::<i32>(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:75:5: 75:45
@@ -74,7 +74,7 @@
                                            // + val: Unevaluated(discriminant, [T], Some(promoted[1]))
                                            // mir::Constant
                                            // + span: $DIR/lower_intrinsics.rs:76:42: 76:45
-                                           // + literal: Const { ty: &(), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[HASH]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[1]) }) }
+                                           // + literal: Const { ty: &(), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[49eb]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[1]) }) }
           _11 = &(*_18);                   // scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45
           _10 = &(*_11);                   // scope 0 at $DIR/lower_intrinsics.rs:76:42: 76:45
 -         _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:76:5: 76:46
@@ -98,7 +98,7 @@
                                            // + val: Unevaluated(discriminant, [T], Some(promoted[0]))
                                            // mir::Constant
                                            // + span: $DIR/lower_intrinsics.rs:77:42: 77:47
-                                           // + literal: Const { ty: &E, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[HASH]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[0]) }) }
+                                           // + literal: Const { ty: &E, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:29 ~ lower_intrinsics[49eb]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[0]) }) }
           _15 = &(*_17);                   // scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47
           _14 = &(*_15);                   // scope 0 at $DIR/lower_intrinsics.rs:77:42: 77:47
 -         _13 = discriminant_value::<E>(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:77:5: 77: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 51425af4bdf..b3a9365396c 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[HASH]::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[5411]::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/nll/named_lifetimes_basic.use_x.nll.0.mir b/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir
index bfc85e98786..975e2ffbf01 100644
--- a/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir
+++ b/src/test/mir-opt/nll/named_lifetimes_basic.use_x.nll.0.mir
@@ -2,8 +2,8 @@
 
 | Free Region Mapping
 | '_#0r | Global | ['_#2r, '_#1r, '_#0r, '_#4r, '_#3r]
-| '_#1r | External | ['_#1r, '_#4r]
-| '_#2r | External | ['_#2r, '_#1r, '_#4r]
+| '_#1r | Local | ['_#1r, '_#4r]
+| '_#2r | Local | ['_#2r, '_#1r, '_#4r]
 | '_#3r | Local | ['_#4r, '_#3r]
 | '_#4r | Local | ['_#4r]
 |
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 1db36c352ff..54d836ba609 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[HASH]::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[4622]::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 cffe7238987..29a72feed7d 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[HASH]::main::{closure#0})
+                                         // + def_id: DefId(0:14 ~ retag[4622]::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[HASH]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) }
+                                         // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:13 ~ retag[4622]::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/pretty/ast-stmt-expr-attr.rs b/src/test/pretty/ast-stmt-expr-attr.rs
index e32f5ca24ea..2404b321942 100644
--- a/src/test/pretty/ast-stmt-expr-attr.rs
+++ b/src/test/pretty/ast-stmt-expr-attr.rs
@@ -28,67 +28,67 @@ fn syntax() {
     let _ = #[attr] (x as Y);
     let _ =
         #[attr] while true {
-                    #![attr]
-                };
+            #![attr]
+        };
     let _ =
         #[attr] while let Some(false) = true {
-                    #![attr]
-                };
+            #![attr]
+        };
     let _ =
         #[attr] for x in y {
-                    #![attr]
-                };
+            #![attr]
+        };
     let _ =
         #[attr] loop {
-                    #![attr]
-                };
+            #![attr]
+        };
     let _ =
         #[attr] match true {
-                    #![attr]
-                            #[attr]
-                            _ => false,
-                };
+            #![attr]
+                #[attr]
+                _ => false,
+        };
     let _ = #[attr] || #[attr] foo;
     let _ = #[attr] move || #[attr] foo;
     let _ =
         #[attr] ||
-                    #[attr] {
-                                #![attr]
-                                foo
-                            };
+            #[attr] {
+                #![attr]
+                foo
+            };
     let _ =
         #[attr] move ||
-                    #[attr] {
-                                #![attr]
-                                foo
-                            };
+            #[attr] {
+                #![attr]
+                foo
+            };
     let _ =
         #[attr] ||
-                    {
-                        #![attr]
-                        foo
-                    };
+            {
+                #![attr]
+                foo
+            };
     let _ =
         #[attr] move ||
-                    {
-                        #![attr]
-                        foo
-                    };
+            {
+                #![attr]
+                foo
+            };
     let _ =
         #[attr] {
-                    #![attr]
-                };
+            #![attr]
+        };
     let _ =
         #[attr] {
-                    #![attr]
-                    let _ = ();
-                };
+            #![attr]
+            let _ = ();
+        };
     let _ =
         #[attr] {
-                    #![attr]
-                    let _ = ();
-                    foo
-                };
+            #![attr]
+            let _ = ();
+            foo
+        };
     let _ = #[attr] x = y;
     let _ = #[attr] (x = y);
     let _ = #[attr] x += y;
diff --git a/src/test/pretty/block-comment-wchar.pp b/src/test/pretty/block-comment-wchar.pp
index 385afa4f33e..8c8580b07c2 100644
--- a/src/test/pretty/block-comment-wchar.pp
+++ b/src/test/pretty/block-comment-wchar.pp
@@ -93,9 +93,9 @@ fn main() {
     // Taken from https://www.unicode.org/Public/UNIDATA/PropList.txt
     let chars =
         ['\x0A', '\x0B', '\x0C', '\x0D', '\x20', '\u{85}', '\u{A0}',
-         '\u{1680}', '\u{2000}', '\u{2001}', '\u{2002}', '\u{2003}',
-         '\u{2004}', '\u{2005}', '\u{2006}', '\u{2007}', '\u{2008}',
-         '\u{2009}', '\u{200A}', '\u{2028}', '\u{2029}', '\u{202F}',
-         '\u{205F}', '\u{3000}'];
+                '\u{1680}', '\u{2000}', '\u{2001}', '\u{2002}', '\u{2003}',
+                '\u{2004}', '\u{2005}', '\u{2006}', '\u{2007}', '\u{2008}',
+                '\u{2009}', '\u{200A}', '\u{2028}', '\u{2029}', '\u{202F}',
+                '\u{205F}', '\u{3000}'];
     for c in &chars { let ws = c.is_whitespace(); println!("{} {}", c, ws); }
 }
diff --git a/src/test/pretty/delimited-token-groups.rs b/src/test/pretty/delimited-token-groups.rs
index 1137d804564..c7c9277faf6 100644
--- a/src/test/pretty/delimited-token-groups.rs
+++ b/src/test/pretty/delimited-token-groups.rs
@@ -17,9 +17,9 @@ mac! {
 
 mac! {
     a(aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa
-      aaaaaaaa aaaaaaaa) a
+    aaaaaaaa aaaaaaaa) a
     [aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa
-     aaaaaaaa aaaaaaaa] a
+    aaaaaaaa aaaaaaaa] a
     {
         aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa
         aaaaaaaa aaaaaaaa aaaaaaaa
@@ -27,22 +27,22 @@ mac! {
 }
 
 mac!(aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa
-     aaaaaaaa aaaaaaaa);
+aaaaaaaa aaaaaaaa);
 mac![aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa
-     aaaaaaaa aaaaaaaa];
+aaaaaaaa aaaaaaaa];
 mac! {
     aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa
     aaaaaaaa aaaaaaaa
 }
 
 #[rustc_dummy(aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa
-              aaaaaaaa aaaaaaaa aaaaaaaa)]
+aaaaaaaa aaaaaaaa aaaaaaaa)]
 #[rustc_dummy[aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa
-              aaaaaaaa aaaaaaaa aaaaaaaa]]
+aaaaaaaa aaaaaaaa aaaaaaaa]]
 #[rustc_dummy {
-      aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa
-      aaaaaaaa aaaaaaaa
-  }]
+    aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa
+    aaaaaaaa aaaaaaaa
+}]
 #[rustc_dummy =
-  "aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa"]
+"aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa"]
 fn main() {}
diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp
index 93967e720c1..3830c3aa6c9 100644
--- a/src/test/pretty/issue-4264.pp
+++ b/src/test/pretty/issue-4264.pp
@@ -11,15 +11,15 @@ extern crate std;
 pub fn foo(_: [i32; (3 as usize)]) ({ } as ())
 
 pub fn bar() ({
-                  const FOO: usize = ((5 as usize) - (4 as usize) as usize);
-                  let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]);
+        const FOO: usize = ((5 as usize) - (4 as usize) as usize);
+        let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]);
 
-                  let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]);
+        let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]);
 
-                  let _ =
-                      (((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3])
-                            as &[i32; 3]) as *const _ as *const [i32; 3]) as
-                          *const [i32; (3 as usize)] as *const [i32; 3]);
+        let _ =
+            (((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3]) as
+                        &[i32; 3]) as *const _ as *const [i32; 3]) as
+                *const [i32; (3 as usize)] as *const [i32; 3]);
 
 
 
@@ -29,29 +29,19 @@ pub fn bar() ({
 
 
 
-                  ({
-                       let res =
-                           ((::alloc::fmt::format as
-                                for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_v1
-                                                                                   as
-                                                                                   fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test"
-                                                                                                                                                                as
-                                                                                                                                                                &str)]
-                                                                                                                                                              as
-                                                                                                                                                              [&str; 1])
-                                                                                                                                                            as
-                                                                                                                                                            &[&str; 1]),
-                                                                                                                                                        (&([]
-                                                                                                                                                              as
-                                                                                                                                                              [ArgumentV1; 0])
-                                                                                                                                                            as
-                                                                                                                                                            &[ArgumentV1; 0]))
-                                                                                  as
-                                                                                  Arguments))
-                               as String);
-                       (res as String)
-                   } as String);
-              } as ())
+        ({
+                let res =
+                    ((::alloc::fmt::format as
+                            for<'r> fn(Arguments<'r>) -> String {format})(((::core::fmt::Arguments::new_v1
+                                as
+                                fn(&[&'static str], &[ArgumentV1]) -> Arguments {Arguments::new_v1})((&([("test"
+                                            as &str)] as [&str; 1]) as
+                                &[&str; 1]),
+                            (&([] as [ArgumentV1; 0]) as &[ArgumentV1; 0])) as
+                            Arguments)) as String);
+                (res as String)
+            } as String);
+    } as ())
 pub type Foo = [i32; (3 as usize)];
 pub struct Bar {
     pub x: [i32; (3 as usize)],
@@ -60,19 +50,9 @@ pub struct TupleBar([i32; (4 as usize)]);
 pub enum Baz { BazVariant([i32; (5 as usize)]), }
 pub fn id<T>(x: T) -> T ({ (x as T) } as T)
 pub fn use_id() ({
-                     let _ =
-                         ((id::<[i32; (3 as usize)]> as
-                              fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1
-                                                                               as
-                                                                               i32),
-                                                                           (2
-                                                                               as
-                                                                               i32),
-                                                                           (3
-                                                                               as
-                                                                               i32)]
-                                                                             as
-                                                                             [i32; 3]))
-                             as [i32; 3]);
-                 } as ())
+        let _ =
+            ((id::<[i32; (3 as usize)]> as
+                    fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 as i32),
+                        (2 as i32), (3 as i32)] as [i32; 3])) as [i32; 3]);
+    } as ())
 fn main() ({ } as ())
diff --git a/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs b/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs
index ed7879001d5..87f525a6178 100644
--- a/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs
+++ b/src/test/pretty/issue-68710-field-attr-proc-mac-lost.rs
@@ -9,8 +9,8 @@ struct C {
 #[allow()]
 const C: C =
     C{
-      #[cfg(debug_assertions)]
-      field: 0,
+        #[cfg(debug_assertions)]
+        field: 0,
 
-      #[cfg(not(debug_assertions))]
-      field: 1,};
+        #[cfg(not(debug_assertions))]
+        field: 1,};
diff --git a/src/test/pretty/macro_rules.rs b/src/test/pretty/macro_rules.rs
index fb66e4a7758..01adb14133b 100644
--- a/src/test/pretty/macro_rules.rs
+++ b/src/test/pretty/macro_rules.rs
@@ -12,8 +12,8 @@ macro_rules! matcher_brackets {
 
 macro_rules! all_fragments {
     ($b : block, $e : expr, $i : ident, $it : item, $l : lifetime, $lit :
-     literal, $m : meta, $p : pat, $pth : path, $s : stmt, $tt : tt, $ty : ty,
-     $vis : vis) => {} ;
+    literal, $m : meta, $p : pat, $pth : path, $s : stmt, $tt : tt, $ty : ty,
+    $vis : vis) => {} ;
 }
 
 fn main() {}
diff --git a/src/test/pretty/match-naked-expr-medium.rs b/src/test/pretty/match-naked-expr-medium.rs
index a124fdff390..836af99002d 100644
--- a/src/test/pretty/match-naked-expr-medium.rs
+++ b/src/test/pretty/match-naked-expr-medium.rs
@@ -5,10 +5,10 @@ fn main() {
     let _y =
         match x {
             Some(_) =>
-            ["some(_)".to_string(), "not".to_string(), "SO".to_string(),
-             "long".to_string(), "string".to_string()],
+                ["some(_)".to_string(), "not".to_string(), "SO".to_string(),
+                        "long".to_string(), "string".to_string()],
             None =>
-            ["none".to_string(), "a".to_string(), "a".to_string(),
-             "a".to_string(), "a".to_string()],
+                ["none".to_string(), "a".to_string(), "a".to_string(),
+                        "a".to_string(), "a".to_string()],
         };
 }
diff --git a/src/test/pretty/stmt_expr_attributes.rs b/src/test/pretty/stmt_expr_attributes.rs
index 01533cd8107..96bde96200a 100644
--- a/src/test/pretty/stmt_expr_attributes.rs
+++ b/src/test/pretty/stmt_expr_attributes.rs
@@ -48,9 +48,9 @@ fn _4() {
 
     let _ =
         #[rustc_dummy] match () {
-                           #![rustc_dummy]
-                           () => (),
-                       };
+            #![rustc_dummy]
+            () => (),
+        };
 }
 
 fn _5() {
@@ -156,56 +156,56 @@ fn _11() {
     let _ = #[rustc_dummy] 0 as usize;
     let _ =
         #[rustc_dummy] while false {
-                           #![rustc_dummy]
-                       };
+            #![rustc_dummy]
+        };
     let _ =
         #[rustc_dummy] while let None = Some(()) {
-                           #![rustc_dummy]
-                       };
+            #![rustc_dummy]
+        };
     let _ =
         #[rustc_dummy] for _ in 0..0 {
-                           #![rustc_dummy]
-                       };
+            #![rustc_dummy]
+        };
     let _ =
         #[rustc_dummy] loop {
-                           #![rustc_dummy]
-                       };
+            #![rustc_dummy]
+        };
     let _ =
         #[rustc_dummy] match false {
-                           #![rustc_dummy]
-                           _ => (),
-                       };
+            #![rustc_dummy]
+            _ => (),
+        };
     let _ = #[rustc_dummy] || #[rustc_dummy] ();
     let _ = #[rustc_dummy] move || #[rustc_dummy] ();
     let _ =
         #[rustc_dummy] ||
-                           {
-                               #![rustc_dummy]
-                               #[rustc_dummy]
-                               ()
-                           };
+            {
+                #![rustc_dummy]
+                #[rustc_dummy]
+                ()
+            };
     let _ =
         #[rustc_dummy] move ||
-                           {
-                               #![rustc_dummy]
-                               #[rustc_dummy]
-                               ()
-                           };
+            {
+                #![rustc_dummy]
+                #[rustc_dummy]
+                ()
+            };
     let _ =
         #[rustc_dummy] {
-                           #![rustc_dummy]
-                       };
+            #![rustc_dummy]
+        };
     let _ =
         #[rustc_dummy] {
-                           #![rustc_dummy]
-                           let _ = ();
-                       };
+            #![rustc_dummy]
+            let _ = ();
+        };
     let _ =
         #[rustc_dummy] {
-                           #![rustc_dummy]
-                           let _ = ();
-                           ()
-                       };
+            #![rustc_dummy]
+            let _ = ();
+            ()
+        };
     let mut x = 0;
     let _ = #[rustc_dummy] x = 15;
     let _ = #[rustc_dummy] x += 15;
diff --git a/src/test/pretty/vec-comments.pp b/src/test/pretty/vec-comments.pp
index a150cf0b8ea..f2f807c59de 100644
--- a/src/test/pretty/vec-comments.pp
+++ b/src/test/pretty/vec-comments.pp
@@ -4,26 +4,26 @@
 fn main() {
     let _v1 =
         [
-         // Comment
-         0,
-         // Comment
-         1,
-         // Comment
-         2];
+                // Comment
+                0,
+                // Comment
+                1,
+                // Comment
+                2];
     let _v2 =
         [0, // Comment
-         1, // Comment
-         2]; // Comment
+                1, // Comment
+                2]; // Comment
     let _v3 =
         [
-         /* Comment */
-         0,
-         /* Comment */
-         1,
-         /* Comment */
-         2];
+                /* Comment */
+                0,
+                /* Comment */
+                1,
+                /* Comment */
+                2];
     let _v4 =
         [0, /* Comment */
-         1, /* Comment */
-         2]; /* Comment */
+                1, /* Comment */
+                2]; /* Comment */
 }
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt
index 7eb393bb448..e463099a5ee 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.closure.txt
@@ -29,8 +29,8 @@
    29|      1|    some_string = Some(String::from("the string content"));
    30|      1|    let
    31|      1|        a
-   32|       |    =
-   33|       |        ||
+   32|      1|    =
+   33|      1|        ||
    34|      0|    {
    35|      0|        let mut countdown = 0;
    36|      0|        if is_false {
@@ -116,8 +116,8 @@
   116|      1|
   117|      1|    let
   118|      1|        _unused_closure
-  119|      1|    =
-  120|      1|        |
+  119|       |    =
+  120|       |        |
   121|       |            mut countdown
   122|       |        |
   123|      0|    {
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-93054.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-93054.txt
new file mode 100644
index 00000000000..a1655adedd4
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.issue-93054.txt
@@ -0,0 +1,29 @@
+    1|       |// Regression test for #93054: Functions using uninhabited types often only have a single,
+    2|       |// unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail.
+    3|       |// Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them.
+    4|       |
+    5|       |// compile-flags: --edition=2021
+    6|       |
+    7|       |enum Never { }
+    8|       |
+    9|       |impl Never {
+   10|       |    fn foo(self) {
+   11|       |        match self { }
+   12|       |        make().map(|never| match never { });
+   13|       |    }
+   14|       |
+   15|       |    fn bar(&self) {
+   16|       |        match *self { }
+   17|       |    }
+   18|       |}
+   19|       |
+   20|      0|async fn foo2(never: Never) {
+   21|       |    match never { }
+   22|       |}
+   23|       |
+   24|      0|fn make() -> Option<Never> {
+   25|      0|    None
+   26|      0|}
+   27|       |
+   28|      1|fn main() { }
+
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt
index 768dcb2f608..c2d5143a618 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_crate.txt
@@ -19,12 +19,12 @@
    18|      2|    println!("used_only_from_bin_crate_generic_function with {:?}", arg);
    19|      2|}
   ------------------
-  | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
+  | used_crate::used_only_from_bin_crate_generic_function::<&str>:
   |   17|      1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
   |   18|      1|    println!("used_only_from_bin_crate_generic_function with {:?}", arg);
   |   19|      1|}
   ------------------
-  | used_crate::used_only_from_bin_crate_generic_function::<&str>:
+  | used_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
   |   17|      1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
   |   18|      1|    println!("used_only_from_bin_crate_generic_function with {:?}", arg);
   |   19|      1|}
@@ -36,12 +36,12 @@
    22|      2|    println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
    23|      2|}
   ------------------
-  | used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
+  | used_crate::used_only_from_this_lib_crate_generic_function::<&str>:
   |   21|      1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
   |   22|      1|    println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
   |   23|      1|}
   ------------------
-  | used_crate::used_only_from_this_lib_crate_generic_function::<&str>:
+  | used_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
   |   21|      1|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
   |   22|      1|    println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
   |   23|      1|}
diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt
index 89636294035..dab31cbf4ac 100644
--- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt
+++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.uses_inline_crate.txt
@@ -42,12 +42,12 @@
    40|      2|    println!("used_only_from_bin_crate_generic_function with {:?}", arg);
    41|      2|}
   ------------------
-  | used_inline_crate::used_only_from_bin_crate_generic_function::<&str>:
+  | used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
   |   39|      1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
   |   40|      1|    println!("used_only_from_bin_crate_generic_function with {:?}", arg);
   |   41|      1|}
   ------------------
-  | used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>:
+  | used_inline_crate::used_only_from_bin_crate_generic_function::<&str>:
   |   39|      1|pub fn used_only_from_bin_crate_generic_function<T: Debug>(arg: T) {
   |   40|      1|    println!("used_only_from_bin_crate_generic_function with {:?}", arg);
   |   41|      1|}
@@ -61,12 +61,12 @@
    46|      4|    println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
    47|      4|}
   ------------------
-  | used_inline_crate::used_only_from_this_lib_crate_generic_function::<&str>:
+  | used_inline_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
   |   45|      2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
   |   46|      2|    println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
   |   47|      2|}
   ------------------
-  | used_inline_crate::used_only_from_this_lib_crate_generic_function::<alloc::vec::Vec<i32>>:
+  | used_inline_crate::used_only_from_this_lib_crate_generic_function::<&str>:
   |   45|      2|pub fn used_only_from_this_lib_crate_generic_function<T: Debug>(arg: T) {
   |   46|      2|    println!("used_only_from_this_lib_crate_generic_function with {:?}", arg);
   |   47|      2|}
diff --git a/src/test/run-make-fulldeps/coverage/issue-93054.rs b/src/test/run-make-fulldeps/coverage/issue-93054.rs
new file mode 100644
index 00000000000..c160b3db03f
--- /dev/null
+++ b/src/test/run-make-fulldeps/coverage/issue-93054.rs
@@ -0,0 +1,28 @@
+// Regression test for #93054: Functions using uninhabited types often only have a single,
+// unreachable basic block which doesn't get instrumented. This should not cause llvm-cov to fail.
+// Since these kinds functions can't be invoked anyway, it's ok to not have coverage data for them.
+
+// compile-flags: --edition=2021
+
+enum Never { }
+
+impl Never {
+    fn foo(self) {
+        match self { }
+        make().map(|never| match never { });
+    }
+
+    fn bar(&self) {
+        match *self { }
+    }
+}
+
+async fn foo2(never: Never) {
+    match never { }
+}
+
+fn make() -> Option<Never> {
+    None
+}
+
+fn main() { }
diff --git a/src/test/run-make/const_fn_mir/dump.mir b/src/test/run-make/const_fn_mir/dump.mir
index 724b2630083..f02bccc4b2d 100644
--- a/src/test/run-make/const_fn_mir/dump.mir
+++ b/src/test/run-make/const_fn_mir/dump.mir
@@ -1,21 +1,5 @@
 // WARNING: This output format is intended for human consumers only
 // and is subject to change without notice. Knock yourself out.
-fn main() -> () {
-    let mut _0: ();                      // return place in scope 0 at main.rs:8:11: 8:11
-    let _1: i32;                         // in scope 0 at main.rs:9:5: 9:10
-
-    bb0: {
-        _1 = foo() -> bb1;               // scope 0 at main.rs:9:5: 9:10
-                                         // mir::Constant
-                                         // + span: main.rs:9:5: 9:8
-                                         // + literal: Const { ty: fn() -> i32 {foo}, val: Value(Scalar(<ZST>)) }
-    }
-
-    bb1: {
-        return;                          // scope 0 at main.rs:10:2: 10:2
-    }
-}
-
 fn foo() -> i32 {
     let mut _0: i32;                     // return place in scope 0 at main.rs:4:19: 4:22
 
@@ -40,3 +24,19 @@ fn foo() -> i32 {
         return;                          // scope 0 at main.rs:6:2: 6:2
     }
 }
+
+fn main() -> () {
+    let mut _0: ();                      // return place in scope 0 at main.rs:8:11: 8:11
+    let _1: i32;                         // in scope 0 at main.rs:9:5: 9:10
+
+    bb0: {
+        _1 = foo() -> bb1;               // scope 0 at main.rs:9:5: 9:10
+                                         // mir::Constant
+                                         // + span: main.rs:9:5: 9:8
+                                         // + literal: Const { ty: fn() -> i32 {foo}, val: Value(Scalar(<ZST>)) }
+    }
+
+    bb1: {
+        return;                          // scope 0 at main.rs:10:2: 10:2
+    }
+}
diff --git a/src/test/rustdoc-gui/anchors.goml b/src/test/rustdoc-gui/anchors.goml
index 2d48d21dc1b..26e4503a5d0 100644
--- a/src/test/rustdoc-gui/anchors.goml
+++ b/src/test/rustdoc-gui/anchors.goml
@@ -20,7 +20,7 @@ assert-css: (".srclink", {"text-decoration": "underline solid rgb(56, 115, 173)"
 
 assert-css: ("#top-doc-prose-title", {"color": "rgb(0, 0, 0)"})
 
-assert-css: (".sidebar a", {"color": "rgb(56, 115, 173)"})
+assert-css: (".sidebar a", {"color": "rgb(53, 109, 164)"})
 assert-css: (".in-band a", {"color": "rgb(0, 0, 0)"})
 
 // We move the cursor over the "Implementations" title so the anchor is displayed.
diff --git a/src/test/rustdoc-gui/check_info_sign_position.goml b/src/test/rustdoc-gui/check_info_sign_position.goml
index 94e3fe79c94..3bed7a0a03e 100644
--- a/src/test/rustdoc-gui/check_info_sign_position.goml
+++ b/src/test/rustdoc-gui/check_info_sign_position.goml
@@ -1,3 +1,5 @@
+// This test checks the position of the information on the code blocks (like
+// `compile_fail` or `ignore`).
 goto: file://|DOC_PATH|/test_docs/index.html
 goto: ./fn.check_list_code_block.html
 // If the codeblock is the first element of the docblock, the information tooltip must have
diff --git a/src/test/rustdoc-gui/code-sidebar-toggle.goml b/src/test/rustdoc-gui/code-sidebar-toggle.goml
index 6fb92e19660..1818f0dbcdf 100644
--- a/src/test/rustdoc-gui/code-sidebar-toggle.goml
+++ b/src/test/rustdoc-gui/code-sidebar-toggle.goml
@@ -1,3 +1,4 @@
+// This test checks that the source code pages sidebar toggle is working as expected.
 goto: file://|DOC_PATH|/test_docs/index.html
 click: ".srclink"
 wait-for: "#sidebar-toggle"
diff --git a/src/test/rustdoc-gui/escape-key.goml b/src/test/rustdoc-gui/escape-key.goml
index 712920b16a9..9cff12f3e41 100644
--- a/src/test/rustdoc-gui/escape-key.goml
+++ b/src/test/rustdoc-gui/escape-key.goml
@@ -1,3 +1,5 @@
+// This test ensures that the "Escape" shortcut is handled correctly based on the
+// current content displayed.
 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")
diff --git a/src/test/rustdoc-gui/font-weight.goml b/src/test/rustdoc-gui/font-weight.goml
index a64ac8b422f..5f29fde6689 100644
--- a/src/test/rustdoc-gui/font-weight.goml
+++ b/src/test/rustdoc-gui/font-weight.goml
@@ -1,5 +1,5 @@
-goto: file://|DOC_PATH|/lib2/struct.Foo.html
 // This test checks that the font weight is correctly applied.
+goto: file://|DOC_PATH|/lib2/struct.Foo.html
 assert-css: ("//*[@class='docblock item-decl']//a[text()='Alias']", {"font-weight": "400"})
 assert-css: (
     "//*[@class='structfield small-section-header']//a[text()='Alias']",
diff --git a/src/test/rustdoc-gui/huge-collection-of-constants.goml b/src/test/rustdoc-gui/huge-collection-of-constants.goml
index 4f7fe7a212c..4f75b5841ee 100644
--- a/src/test/rustdoc-gui/huge-collection-of-constants.goml
+++ b/src/test/rustdoc-gui/huge-collection-of-constants.goml
@@ -1,7 +1,7 @@
-goto: file://|DOC_PATH|/test_docs/huge_amount_of_consts/index.html
-
 // Make sure that the last two entries are more than 12 pixels apart and not stacked on each other.
 
+goto: file://|DOC_PATH|/test_docs/huge_amount_of_consts/index.html
+
 compare-elements-position-near-false: (
     "//*[@class='item-table']//div[last()-1]",
     "//*[@class='item-table']//div[last()-3]",
diff --git a/src/test/rustdoc-gui/list_code_block.goml b/src/test/rustdoc-gui/list_code_block.goml
index 7d3490e9d94..eba1a662b9f 100644
--- a/src/test/rustdoc-gui/list_code_block.goml
+++ b/src/test/rustdoc-gui/list_code_block.goml
@@ -1,3 +1,4 @@
+// This test checks that code blocks in list are supported.
 goto: file://|DOC_PATH|/test_docs/index.html
 goto: ./fn.check_list_code_block.html
 assert: ("pre.rust.fn")
diff --git a/src/test/rustdoc-gui/mobile.goml b/src/test/rustdoc-gui/mobile.goml
index acde1123925..8f9c9248f5f 100644
--- a/src/test/rustdoc-gui/mobile.goml
+++ b/src/test/rustdoc-gui/mobile.goml
@@ -2,6 +2,8 @@
 goto: file://|DOC_PATH|/staged_api/struct.Foo.html
 size: (400, 600)
 
+font-size: 18
+
 // The out-of-band info (source, stable version, collapse) should be below the
 // h1 when the screen gets narrow enough.
 assert-css: (".main-heading", {
@@ -9,6 +11,8 @@ assert-css: (".main-heading", {
   "flex-direction": "column"
 })
 
+assert-property: (".mobile-topbar h2.location", {"offsetHeight": 45})
+
 // Note: We can't use assert-text here because the 'Since' is set by CSS and
 // is therefore not part of the DOM.
 assert-css: (".content .out-of-band .since::before", { "content": "\"Since \"" })
diff --git a/src/test/rustdoc-gui/search-filter.goml b/src/test/rustdoc-gui/search-filter.goml
index e5cdf3ea7a1..98ca40512ee 100644
--- a/src/test/rustdoc-gui/search-filter.goml
+++ b/src/test/rustdoc-gui/search-filter.goml
@@ -1,3 +1,4 @@
+// Checks that the crate search filtering is handled correctly and changes the results.
 goto: file://|DOC_PATH|/test_docs/index.html
 show-text: true
 write: (".search-input", "test")
diff --git a/src/test/rustdoc-gui/search-result-colors.goml b/src/test/rustdoc-gui/search-result-colors.goml
index b4eb896af1c..872df5fc3f9 100644
--- a/src/test/rustdoc-gui/search-result-colors.goml
+++ b/src/test/rustdoc-gui/search-result-colors.goml
@@ -1,3 +1,4 @@
+// Checks that the result colors are as expected.
 goto: file://|DOC_PATH|/test_docs/index.html
 // We set the theme so we're sure that the correct values will be used, whatever the computer
 // this test is running on.
diff --git a/src/test/rustdoc-gui/search-result-display.goml b/src/test/rustdoc-gui/search-result-display.goml
index 3162a067d21..823ea67b1b0 100644
--- a/src/test/rustdoc-gui/search-result-display.goml
+++ b/src/test/rustdoc-gui/search-result-display.goml
@@ -1,3 +1,4 @@
+// Checks that the search results have the expected width.
 goto: file://|DOC_PATH|/test_docs/index.html
 size: (900, 1000)
 write: (".search-input", "test")
diff --git a/src/test/rustdoc-gui/search-result-keyword.goml b/src/test/rustdoc-gui/search-result-keyword.goml
index 5342d431d99..8b50c5c5e1a 100644
--- a/src/test/rustdoc-gui/search-result-keyword.goml
+++ b/src/test/rustdoc-gui/search-result-keyword.goml
@@ -1,3 +1,4 @@
+// Checks that the "keyword" results have the expected text alongside them.
 goto: file://|DOC_PATH|/test_docs/index.html
 write: (".search-input", "CookieMonster")
 // Waiting for the search results to appear...
diff --git a/src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml b/src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml
index a61ec672ae6..52b3ceae7b1 100644
--- a/src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml
+++ b/src/test/rustdoc-gui/search-tab-selection-if-current-is-empty.goml
@@ -1,3 +1,5 @@
+// Checks that the first non-empty search result tab is selected if the default/currently selected
+// one is empty.
 goto: file://|DOC_PATH|/test_docs/index.html
 write: (".search-input", "Foo")
 // Waiting for the search results to appear...
diff --git a/src/test/rustdoc-gui/sidebar-mobile.goml b/src/test/rustdoc-gui/sidebar-mobile.goml
index 680822b6ecb..60bcffe120b 100644
--- a/src/test/rustdoc-gui/sidebar-mobile.goml
+++ b/src/test/rustdoc-gui/sidebar-mobile.goml
@@ -35,3 +35,8 @@ assert-property: (".mobile-topbar", {"clientHeight": "45"})
 click: ".sidebar-menu-toggle"
 click: ".sidebar-links a"
 assert-position: ("#method\.must_use", {"y": 45})
+
+// Check that the bottom-most item on the sidebar menu can be scrolled fully into view.
+click: ".sidebar-menu-toggle"
+scroll-to: ".block.keyword li:nth-child(1)"
+assert-position: (".block.keyword li:nth-child(1)", {"y": 542.96875})
diff --git a/src/test/rustdoc-gui/sidebar.goml b/src/test/rustdoc-gui/sidebar.goml
index a1175525858..ef3a92ad7a6 100644
--- a/src/test/rustdoc-gui/sidebar.goml
+++ b/src/test/rustdoc-gui/sidebar.goml
@@ -1,3 +1,4 @@
+// Checks multiple things on the sidebar display (width of its elements, colors, etc).
 goto: file://|DOC_PATH|/test_docs/index.html
 show-text: true
 local-storage: {"rustdoc-theme": "light"}
@@ -8,7 +9,7 @@ assert-text: (".sidebar > .location", "Crate test_docs")
 // In modules, we only have one "location" element.
 assert-count: (".sidebar .location", 1)
 assert-text: ("#all-types", "All Items")
-assert-css: ("#all-types", {"color": "rgb(56, 115, 173)"})
+assert-css: ("#all-types", {"color": "rgb(53, 109, 164)"})
 // We check that we have the crates list and that the "current" on is "test_docs".
 assert-text: (".sidebar-elems .crate > ul > li > a.current", "test_docs")
 // And we're also supposed to have the list of items in the current module.
@@ -37,7 +38,7 @@ assert-property: ("html", {"scrollTop": "0"})
 
 // We now go back to the crate page to click on the "lib2" crate link.
 goto: file://|DOC_PATH|/test_docs/index.html
-assert-css: (".sidebar-elems .crate > ul > li:first-child > a", {"color": "rgb(56, 115, 173)"})
+assert-css: (".sidebar-elems .crate > ul > li:first-child > a", {"color": "rgb(53, 109, 164)"})
 click: ".sidebar-elems .crate > ul > li:first-child > a"
 
 // PAGE: lib2/index.html
@@ -73,3 +74,7 @@ assert-text: (".sidebar > .location", "Module sub_sub_module")
 assert-false: ".sidebar-elems .crate"
 assert-text: (".sidebar-elems .items > ul > li:nth-child(1)", "Functions")
 assert-text: ("#functions + .item-table .item-left > a", "foo")
+
+// Links to trait implementations in the sidebar should not wrap even if they are long.
+goto: file://|DOC_PATH|/lib2/struct.HasALongTraitWithParams.html
+assert-property: (".sidebar-links a", {"offsetHeight": 29})
diff --git a/src/test/rustdoc-gui/source-code-page.goml b/src/test/rustdoc-gui/source-code-page.goml
index f3682f59d21..375ff4878e5 100644
--- a/src/test/rustdoc-gui/source-code-page.goml
+++ b/src/test/rustdoc-gui/source-code-page.goml
@@ -1,3 +1,4 @@
+// Checks that the interactions with the source code pages are workined as expected.
 goto: file://|DOC_PATH|/src/test_docs/lib.rs.html
 // Check that we can click on the line number.
 click: ".line-numbers > span:nth-child(4)" // This is the span for line 4.
diff --git a/src/test/rustdoc-gui/src/lib2/lib.rs b/src/test/rustdoc-gui/src/lib2/lib.rs
index 79354ec8745..5b6d236e8e0 100644
--- a/src/test/rustdoc-gui/src/lib2/lib.rs
+++ b/src/test/rustdoc-gui/src/lib2/lib.rs
@@ -39,7 +39,6 @@ impl Trait for Foo {
     const Y: u32 = 0;
 }
 
-
 impl implementors::Whatever for Foo {
     type Foo = u32;
 }
@@ -58,8 +57,10 @@ pub mod sub_mod {
 pub mod long_trait {
     use std::ops::DerefMut;
 
-    pub trait ALongNameBecauseItHelpsTestingTheCurrentProblem: DerefMut<Target = u32>
-        + From<u128> + Send + Sync + AsRef<str> + 'static {}
+    pub trait ALongNameBecauseItHelpsTestingTheCurrentProblem:
+        DerefMut<Target = u32> + From<u128> + Send + Sync + AsRef<str> + 'static
+    {
+    }
 }
 
 pub mod long_table {
@@ -88,18 +89,34 @@ pub mod summary_table {
 }
 
 pub mod too_long {
-pub type ReallyLongTypeNameLongLongLong = Option<unsafe extern "C" fn(a: *const u8, b: *const u8) -> *const u8>;
-
-pub const ReallyLongTypeNameLongLongLongConstBecauseWhyNotAConstRightGigaGigaSupraLong: u32 = 0;
-
-pub struct SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName {
-    pub a: u32,
-}
+    pub type ReallyLongTypeNameLongLongLong =
+        Option<unsafe extern "C" fn(a: *const u8, b: *const u8) -> *const u8>;
+
+    pub const ReallyLongTypeNameLongLongLongConstBecauseWhyNotAConstRightGigaGigaSupraLong: u32 = 0;
+
+    /// This also has a really long doccomment. Lorem ipsum dolor sit amet,
+    /// consectetur adipiscing elit. Suspendisse id nibh malesuada, hendrerit
+    /// massa vel, tincidunt est. Nulla interdum, sem ac efficitur ornare, arcu
+    /// nunc dignissim nibh, at rutrum diam augue ac mauris. Fusce tincidunt et
+    /// ligula sed viverra. Aenean sed facilisis dui, non volutpat felis. In
+    /// vitae est dui. Donec felis nibh, blandit at nibh eu, tempor suscipit
+    /// nisl. Vestibulum ornare porta libero, eu faucibus purus iaculis ut. Ut
+    /// quis tincidunt nunc, in mollis purus. Nulla sed interdum quam. Nunc
+    /// vitae cursus ex.
+    pub struct SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName {
+        pub a: u32,
+    }
 
-impl SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName {
-    /// ```
-    /// let x = SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName { a: 0 };
-    /// ```
+    impl SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName {
+        /// ```
+        /// let x = SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName { a: 0 };
+        /// ```
         pub fn foo(&self) {}
     }
 }
+
+pub struct HasALongTraitWithParams {}
+
+pub trait LongTraitWithParamsBananaBananaBanana<T> {}
+
+impl LongTraitWithParamsBananaBananaBanana<usize> for HasALongTraitWithParams {}
diff --git a/src/test/rustdoc-gui/theme-change.goml b/src/test/rustdoc-gui/theme-change.goml
index 5221cda2f1f..73edee64e43 100644
--- a/src/test/rustdoc-gui/theme-change.goml
+++ b/src/test/rustdoc-gui/theme-change.goml
@@ -1,3 +1,4 @@
+// Ensures that the theme change is working as expected.
 goto: file://|DOC_PATH|/test_docs/index.html
 click: "#theme-picker"
 click: "#theme-choices > button:first-child"
@@ -8,3 +9,19 @@ click: "#theme-choices > button:last-child"
 wait-for: 500
 // should be the light theme so let's check the color
 assert-css: ("body", { "background-color": "rgb(255, 255, 255)" })
+
+goto: file://|DOC_PATH|/settings.html
+click: "#theme-light"
+wait-for: 500
+assert-css: ("body", { "background-color": "rgb(255, 255, 255)" })
+assert-local-storage: { "rustdoc-theme": "light" }
+
+click: "#theme-dark"
+wait-for: 500
+assert-css: ("body", { "background-color": "rgb(53, 53, 53)" })
+assert-local-storage: { "rustdoc-theme": "dark" }
+
+click: "#theme-ayu"
+wait-for: 500
+assert-css: ("body", { "background-color": "rgb(15, 20, 25)" })
+assert-local-storage: { "rustdoc-theme": "ayu" }
diff --git a/src/test/rustdoc-gui/theme-in-history.goml b/src/test/rustdoc-gui/theme-in-history.goml
new file mode 100644
index 00000000000..b53799188ef
--- /dev/null
+++ b/src/test/rustdoc-gui/theme-in-history.goml
@@ -0,0 +1,25 @@
+// Ensures that the theme is working when going back in history.
+goto: file://|DOC_PATH|/test_docs/index.html
+// Set the theme to dark.
+local-storage: {"rustdoc-theme": "dark", "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false"}
+// We reload the page so the local storage settings are being used.
+reload:
+assert-css: ("body", { "background-color": "rgb(53, 53, 53)" })
+assert-local-storage: { "rustdoc-theme": "dark" }
+
+// Now we go to the settings page.
+click: "#settings-menu"
+wait-for: ".settings"
+// We change the theme to "light".
+click: "#theme-light"
+wait-for: 250
+assert-css: ("body", { "background-color": "rgb(255, 255, 255)" })
+assert-local-storage: { "rustdoc-theme": "light" }
+
+// We go back in history.
+history-go-back:
+// Confirm that we're not on the settings page.
+assert-false: ".settings"
+// Check that the current theme is still "light".
+assert-css: ("body", { "background-color": "rgb(255, 255, 255)" })
+assert-local-storage: { "rustdoc-theme": "light" }
diff --git a/src/test/rustdoc-gui/toggle-docs-mobile.goml b/src/test/rustdoc-gui/toggle-docs-mobile.goml
index e7a75b43c5a..b5026923001 100644
--- a/src/test/rustdoc-gui/toggle-docs-mobile.goml
+++ b/src/test/rustdoc-gui/toggle-docs-mobile.goml
@@ -1,3 +1,5 @@
+// Checks that the documentation toggles on mobile have the correct position, style and work
+// as expected.
 goto: file://|DOC_PATH|/test_docs/struct.Foo.html
 size: (433, 600)
 assert-attribute: (".top-doc", {"open": ""})
diff --git a/src/test/rustdoc-gui/toggle-docs.goml b/src/test/rustdoc-gui/toggle-docs.goml
index e11aae21e3f..480d6242ac6 100644
--- a/src/test/rustdoc-gui/toggle-docs.goml
+++ b/src/test/rustdoc-gui/toggle-docs.goml
@@ -1,3 +1,4 @@
+// Checks that the documentation toggles have the correct position, style and work as expected.
 goto: file://|DOC_PATH|/test_docs/index.html
 assert-attribute: ("#main-content > details.top-doc", {"open": ""})
 assert-text: ("#toggle-all-docs", "[−]")
diff --git a/src/test/rustdoc-gui/trait-sidebar-item-order.goml b/src/test/rustdoc-gui/trait-sidebar-item-order.goml
index 739745792c2..38942baa0b5 100644
--- a/src/test/rustdoc-gui/trait-sidebar-item-order.goml
+++ b/src/test/rustdoc-gui/trait-sidebar-item-order.goml
@@ -1,3 +1,4 @@
+// Checks that the elements in the sidebar are alphabetically sorted.
 goto: file://|DOC_PATH|/test_docs/trait.AnotherOne.html
 assert-text: (".sidebar-links a:nth-of-type(1)", "another")
 assert-text: (".sidebar-links a:nth-of-type(2)", "func1")
diff --git a/src/test/rustdoc-gui/type-declation-overflow.goml b/src/test/rustdoc-gui/type-declation-overflow.goml
index 21874f786f1..229c6d6ba6b 100644
--- a/src/test/rustdoc-gui/type-declation-overflow.goml
+++ b/src/test/rustdoc-gui/type-declation-overflow.goml
@@ -7,6 +7,10 @@ assert-property: ("body", {"scrollWidth": "1100"})
 // However, since there is overflow in the type declaration, its scroll width is bigger.
 assert-property: (".item-decl pre", {"scrollWidth": "1324"})
 
+// In the table-ish view on the module index, the name should not be wrapped more than necessary.
+goto: file://|DOC_PATH|/lib2/too_long/index.html
+assert-property: (".item-table .struct", {"offsetWidth": "684"})
+
 // We now make the same check on type declaration...
 goto: file://|DOC_PATH|/lib2/too_long/type.ReallyLongTypeNameLongLongLong.html
 assert-property: ("body", {"scrollWidth": "1100"})
@@ -27,6 +31,6 @@ assert-property: (".item-decl pre", {"scrollWidth": "950"})
 // On mobile:
 size: (600, 600)
 goto: file://|DOC_PATH|/lib2/too_long/struct.SuperIncrediblyLongLongLongLongLongLongLongGigaGigaGigaMegaLongLongLongStructName.html
-assert-property: (".mobile-topbar .location", {"scrollWidth": "504"})
+assert-property: (".mobile-topbar .location", {"scrollWidth": "986"})
 assert-property: (".mobile-topbar .location", {"clientWidth": "504"})
 assert-css: (".mobile-topbar .location", {"overflow-x": "hidden"})
diff --git a/src/test/rustdoc-js/generics-multi-trait.js b/src/test/rustdoc-js/generics-multi-trait.js
new file mode 100644
index 00000000000..e7fcea876c8
--- /dev/null
+++ b/src/test/rustdoc-js/generics-multi-trait.js
@@ -0,0 +1,32 @@
+// exact-check
+
+const QUERY = [
+    'Result<SomeTrait>',
+    'Zzzzzzzzzzzzzzzzzz',
+    'Nonononononononono',
+];
+
+const EXPECTED = [
+    // check one of the generic items
+    {
+        'in_args': [
+            { 'path': 'generics_multi_trait', 'name': 'beta' },
+        ],
+        'returned': [
+            { 'path': 'generics_multi_trait', 'name': 'bet' },
+        ],
+    },
+    {
+        'in_args': [
+            { 'path': 'generics_multi_trait', 'name': 'beta' },
+        ],
+        'returned': [
+            { 'path': 'generics_multi_trait', 'name': 'bet' },
+        ],
+    },
+    // ignore the name of the generic itself
+    {
+        'in_args': [],
+        'returned': [],
+    },
+];
diff --git a/src/test/rustdoc-js/generics-multi-trait.rs b/src/test/rustdoc-js/generics-multi-trait.rs
new file mode 100644
index 00000000000..e6fd06d254c
--- /dev/null
+++ b/src/test/rustdoc-js/generics-multi-trait.rs
@@ -0,0 +1,12 @@
+pub trait SomeTrait {}
+pub trait Zzzzzzzzzzzzzzzzzz {}
+
+pub fn bet<Nonononononononono: SomeTrait + Zzzzzzzzzzzzzzzzzz>() -> Result<Nonononononononono, ()> {
+    loop {}
+}
+
+pub fn beta<Nonononononononono: SomeTrait + Zzzzzzzzzzzzzzzzzz>(
+    _param: Result<Nonononononononono, ()>,
+) {
+    loop {}
+}
diff --git a/src/test/rustdoc-json/impls/blanket_with_local.rs b/src/test/rustdoc-json/impls/blanket_with_local.rs
index 963ea2fe5ae..a3d55b35f00 100644
--- a/src/test/rustdoc-json/impls/blanket_with_local.rs
+++ b/src/test/rustdoc-json/impls/blanket_with_local.rs
@@ -3,11 +3,15 @@
 
 // @has blanket_with_local.json "$.index[*][?(@.name=='Load')]"
 pub trait Load {
+    // @has - "$.index[*][?(@.name=='load')]"
     fn load() {}
+    // @has - "$.index[*][?(@.name=='write')]"
+    fn write(self) {}
 }
 
 impl<P> Load for P {
     fn load() {}
+    fn write(self) {}
 }
 
 // @has - "$.index[*][?(@.name=='Wrapper')]"
diff --git a/src/test/rustdoc/intra-doc/crate-relative.rs b/src/test/rustdoc/intra-doc/crate-relative.rs
new file mode 100644
index 00000000000..bacbcabfc60
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/crate-relative.rs
@@ -0,0 +1,13 @@
+pub struct Test<'a> {
+    data: &'a (),
+}
+
+impl<'a> Test<'a> {
+    pub fn do_test(&self) {}
+}
+
+// @has crate_relative/demo/index.html
+// @has - '//a/@href' '../struct.Test.html#method.do_test'
+pub mod demo {
+    //! [`crate::Test::do_test`]
+}
diff --git a/src/test/rustdoc/intra-doc/mod-relative.rs b/src/test/rustdoc/intra-doc/mod-relative.rs
new file mode 100644
index 00000000000..49d3399b972
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/mod-relative.rs
@@ -0,0 +1,17 @@
+pub mod wrapper {
+
+    pub struct Test<'a> {
+        data: &'a (),
+    }
+
+    impl<'a> Test<'a> {
+        pub fn do_test(&self) {}
+    }
+
+    // @has mod_relative/wrapper/demo/index.html
+    // @has - '//a/@href' '../struct.Test.html#method.do_test'
+    /// [`Test::do_test`]
+    pub mod demo {
+    }
+
+}
diff --git a/src/test/rustdoc/macro-generated-macro.macro_linebreak_pre.html b/src/test/rustdoc/macro-generated-macro.macro_linebreak_pre.html
new file mode 100644
index 00000000000..ce5d3a8461b
--- /dev/null
+++ b/src/test/rustdoc/macro-generated-macro.macro_linebreak_pre.html
@@ -0,0 +1,6 @@
+macro_rules! linebreak {
+    (
+        <= 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
+        26 27 28 =>
+    ) => { ... };
+}
\ No newline at end of file
diff --git a/src/test/rustdoc/macro-generated-macro.macro_morestuff_pre.html b/src/test/rustdoc/macro-generated-macro.macro_morestuff_pre.html
new file mode 100644
index 00000000000..28f15522a82
--- /dev/null
+++ b/src/test/rustdoc/macro-generated-macro.macro_morestuff_pre.html
@@ -0,0 +1,15 @@
+macro_rules! morestuff {
+    (
+        <= "space between most kinds of tokens" : 1 $x + @ :: >>= 'static
+        "no space inside paren or bracket" : (2 a) [2 a] $(2 $a:tt)*
+        "space inside curly brace" : { 2 a }
+        "no space inside empty delimiters" : () [] {}
+        "no space before comma or semicolon" : a, (a), { a }, a; [T; 0];
+        "the three repetition specifiers" : $(@)*, $(@)+, $(@)?
+        "repetition separators" : $(@)|*, $(@)|+, $(@)==*, $(@)static*
+        "plus or star cannot be a repetition separator" : $(@)+ * $(@)* +
+        "no space between ident and paren" : let _ = f(0) + f[0] + Struct {};
+        "space between keyword and paren" : return (a,) & for x in (..)
+        "some special case keywords" : pub(crate), fn() -> u8, Self(0, 0) =>
+    ) => { ... };
+}
\ No newline at end of file
diff --git a/src/test/rustdoc/macro-generated-macro.rs b/src/test/rustdoc/macro-generated-macro.rs
index 25d8bc3ec62..1a423cac1b5 100644
--- a/src/test/rustdoc/macro-generated-macro.rs
+++ b/src/test/rustdoc/macro-generated-macro.rs
@@ -1,14 +1,39 @@
-macro_rules! outer {
-    ($($matcher:tt)*) => {
+macro_rules! make_macro {
+    ($macro_name:ident $($matcher:tt)*) => {
         #[macro_export]
-        macro_rules! inner {
+        macro_rules! $macro_name {
             (<= $($matcher)* =>) => {};
         }
     }
 }
 
-// @has macro_generated_macro/macro.inner.html //pre 'macro_rules! inner {'
-// @has - //pre '(<= type $($i : ident) :: * + $e : expr =>) => { ... };'
-outer!(type $($i:ident)::* + $e:expr);
+// @has macro_generated_macro/macro.interpolations.html //pre 'macro_rules! interpolations {'
+// @has - //pre '(<= type $($i:ident)::* + $e:expr =>) => { ... };'
+make_macro!(interpolations type $($i:ident)::* + $e:expr);
+interpolations!(<= type foo::bar + x.sort() =>);
 
-inner!(<= type foo::bar + x.sort() =>);
+// @has macro_generated_macro/macro.attributes.html //pre 'macro_rules! attributes {'
+// @has - //pre '(<= #![no_std] #[cfg(feature = "alloc")] =>) => { ... };'
+make_macro!(attributes #![no_std] #[cfg(feature = "alloc")]);
+
+// @has macro_generated_macro/macro.groups.html //pre 'macro_rules! groups {'
+// @has - //pre '(<= fn {} () { foo[0] } =>) => { ... };'
+make_macro!(groups fn {}() {foo[0]});
+
+// @snapshot macro_linebreak_pre macro_generated_macro/macro.linebreak.html //pre/text()
+make_macro!(linebreak 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28);
+
+// @snapshot macro_morestuff_pre macro_generated_macro/macro.morestuff.html //pre/text()
+make_macro!(morestuff
+    "space between most kinds of tokens": 1 $x + @ :: >>= 'static
+    "no space inside paren or bracket": (2 a) [2 a] $(2 $a:tt)*
+    "space inside curly brace": { 2 a }
+    "no space inside empty delimiters": () [] {}
+    "no space before comma or semicolon": a, (a), { a }, a; [T; 0];
+    "the three repetition specifiers": $(@)*, $(@)+, $(@)?
+    "repetition separators": $(@)|*, $(@)|+, $(@)==*, $(@)static*
+    "plus or star cannot be a repetition separator": $(@)+ * $(@)* +
+    "no space between ident and paren": let _ = f(0) + f[0] + Struct {};
+    "space between keyword and paren": return (a,) & for x in (..)
+    "some special case keywords": pub(crate), fn() -> u8, Self(0, 0)
+);
diff --git a/src/test/rustdoc/source-version-separator.rs b/src/test/rustdoc/source-version-separator.rs
index 45a555eaa15..8d23ca91801 100644
--- a/src/test/rustdoc/source-version-separator.rs
+++ b/src/test/rustdoc/source-version-separator.rs
@@ -1,10 +1,9 @@
 #![stable(feature = "bar", since = "1.0")]
 #![crate_name = "foo"]
-
 #![feature(staged_api)]
 
 // @has foo/trait.Bar.html
-// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0· source · '
+// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
 #[stable(feature = "bar", since = "1.0")]
 pub trait Bar {
     // @has - '//div[@id="tymethod.foo"]/*[@class="rightside"]' '3.0 · source'
@@ -15,7 +14,7 @@ pub trait Bar {
 // @has - '//div[@id="implementors-list"]//*[@class="rightside"]' '4.0 · source'
 
 // @has foo/struct.Foo.html
-// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0· source · '
+// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
 #[stable(feature = "baz", since = "1.0")]
 pub struct Foo;
 
diff --git a/src/test/rustdoc/version-separator-without-source.rs b/src/test/rustdoc/version-separator-without-source.rs
new file mode 100644
index 00000000000..bffe5030a84
--- /dev/null
+++ b/src/test/rustdoc/version-separator-without-source.rs
@@ -0,0 +1,23 @@
+#![doc(html_no_source)]
+#![feature(staged_api)]
+#![stable(feature = "bar", since = "1.0")]
+#![crate_name = "foo"]
+
+// @has foo/fn.foo.html
+// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · '
+// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
+#[stable(feature = "bar", since = "1.0")]
+pub fn foo() {}
+
+// @has foo/struct.Bar.html
+// @has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · '
+// @!has - '//div[@class="main-heading"]/*[@class="out-of-band"]' '1.0 · source · '
+#[stable(feature = "bar", since = "1.0")]
+pub struct Bar;
+
+impl Bar {
+    // @has - '//div[@id="method.bar"]/*[@class="rightside"]' '2.0'
+    // @!has - '//div[@id="method.bar"]/*[@class="rightside"]' '2.0 ·'
+    #[stable(feature = "foobar", since = "2.0")]
+    pub fn bar() {}
+}
diff --git a/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs b/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs
index fab2031d952..dd20eef0700 100644
--- a/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs
+++ b/src/test/ui-fulldeps/deriving-encodable-decodable-box.rs
@@ -18,6 +18,6 @@ struct A {
 fn main() {
     let obj = A { foo: Box::new([true, false]) };
     let s = json::encode(&obj).unwrap();
-    let obj2: A = json::decode(&s).unwrap();
+    let obj2: A = json::decode(&s);
     assert_eq!(obj.foo, obj2.foo);
 }
diff --git a/src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs b/src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs
index 9dedf990f25..18aa974c31d 100644
--- a/src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs
+++ b/src/test/ui-fulldeps/deriving-encodable-decodable-cell-refcell.rs
@@ -27,7 +27,7 @@ struct B {
 fn main() {
     let obj = B { foo: Cell::new(true), bar: RefCell::new(A { baz: 2 }) };
     let s = json::encode(&obj).unwrap();
-    let obj2: B = json::decode(&s).unwrap();
+    let obj2: B = json::decode(&s);
     assert_eq!(obj.foo.get(), obj2.foo.get());
     assert_eq!(obj.bar.borrow().baz, obj2.bar.borrow().baz);
 }
diff --git a/src/test/ui-fulldeps/internal-lints/qualified_ty_ty_ctxt.stderr b/src/test/ui-fulldeps/internal-lints/qualified_ty_ty_ctxt.stderr
index 59732cd84e5..a1056cf85d3 100644
--- a/src/test/ui-fulldeps/internal-lints/qualified_ty_ty_ctxt.stderr
+++ b/src/test/ui-fulldeps/internal-lints/qualified_ty_ty_ctxt.stderr
@@ -2,7 +2,7 @@ error: usage of qualified `ty::Ty<'_>`
   --> $DIR/qualified_ty_ty_ctxt.rs:25:11
    |
 LL |     ty_q: ty::Ty<'_>,
-   |           ^^^^^^^^^^ help: try using it unqualified: `Ty<'_>`
+   |           ^^^^^^^^^^ help: try importing it and using it unqualified: `Ty<'_>`
    |
 note: the lint level is defined here
   --> $DIR/qualified_ty_ty_ctxt.rs:4:9
@@ -14,7 +14,7 @@ error: usage of qualified `ty::TyCtxt<'_>`
   --> $DIR/qualified_ty_ty_ctxt.rs:27:16
    |
 LL |     ty_ctxt_q: ty::TyCtxt<'_>,
-   |                ^^^^^^^^^^^^^^ help: try using it unqualified: `TyCtxt<'_>`
+   |                ^^^^^^^^^^^^^^ help: try importing it and using it unqualified: `TyCtxt<'_>`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui-fulldeps/issue-14021.rs b/src/test/ui-fulldeps/issue-14021.rs
index be88a593962..acd75170d68 100644
--- a/src/test/ui-fulldeps/issue-14021.rs
+++ b/src/test/ui-fulldeps/issue-14021.rs
@@ -20,7 +20,7 @@ pub fn main() {
 
     let json_object = json::from_str(&json_str);
     let mut decoder = json::Decoder::new(json_object.unwrap());
-    let mut decoded_obj: UnitLikeStruct = Decodable::decode(&mut decoder).unwrap();
+    let mut decoded_obj: UnitLikeStruct = Decodable::decode(&mut decoder);
 
     assert_eq!(obj, decoded_obj);
 }
diff --git a/src/test/ui-fulldeps/issue-4016.rs b/src/test/ui-fulldeps/issue-4016.rs
index 4fd192497a0..65dab8d7704 100644
--- a/src/test/ui-fulldeps/issue-4016.rs
+++ b/src/test/ui-fulldeps/issue-4016.rs
@@ -12,7 +12,7 @@ trait JD: Decodable<json::Decoder> {}
 fn exec<T: JD>() {
     let doc = json::from_str("").unwrap();
     let mut decoder = json::Decoder::new(doc);
-    let _v: T = Decodable::decode(&mut decoder).unwrap();
+    let _v: T = Decodable::decode(&mut decoder);
     panic!()
 }
 
diff --git a/src/test/ui-fulldeps/issue-4036.rs b/src/test/ui-fulldeps/issue-4036.rs
index 05a7a30140a..702bb2d6ef6 100644
--- a/src/test/ui-fulldeps/issue-4036.rs
+++ b/src/test/ui-fulldeps/issue-4036.rs
@@ -13,5 +13,5 @@ use rustc_serialize::{json, Decodable};
 pub fn main() {
     let json = json::from_str("[1]").unwrap();
     let mut decoder = json::Decoder::new(json);
-    let _x: Vec<isize> = Decodable::decode(&mut decoder).unwrap();
+    let _x: Vec<isize> = Decodable::decode(&mut decoder);
 }
diff --git a/src/test/ui/asm/naked-functions.rs b/src/test/ui/asm/naked-functions.rs
index 32431d9e7c6..5b4293972ea 100644
--- a/src/test/ui/asm/naked-functions.rs
+++ b/src/test/ui/asm/naked-functions.rs
@@ -5,7 +5,7 @@
 
 #![feature(naked_functions)]
 #![feature(or_patterns)]
-#![feature(asm_const, asm_sym)]
+#![feature(asm_const, asm_sym, asm_unwind)]
 #![crate_type = "lib"]
 
 use std::arch::asm;
@@ -32,8 +32,7 @@ pub unsafe extern "C" fn patterns(
 
 #[naked]
 pub unsafe extern "C" fn inc(a: u32) -> u32 {
-    //~^ WARN naked functions must contain a single asm block
-    //~| WARN this was previously accepted
+    //~^ ERROR naked functions must contain a single asm block
     a + 1
     //~^ ERROR referencing function parameters is not allowed in naked functions
 }
@@ -42,21 +41,18 @@ pub unsafe extern "C" fn inc(a: u32) -> u32 {
 pub unsafe extern "C" fn inc_asm(a: u32) -> u32 {
     asm!("/* {0} */", in(reg) a, options(noreturn));
     //~^ ERROR referencing function parameters is not allowed in naked functions
-    //~| WARN only `const` and `sym` operands are supported in naked functions
-    //~| WARN this was previously accepted
+    //~| ERROR only `const` and `sym` operands are supported in naked functions
 }
 
 #[naked]
 pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
-    //~^ WARN naked functions must contain a single asm block
-    //~| WARN this was previously accepted
+    //~^ ERROR naked functions must contain a single asm block
     (|| a + 1)()
 }
 
 #[naked]
 pub unsafe extern "C" fn unsupported_operands() {
-    //~^ WARN naked functions must contain a single asm block
-    //~| WARN this was previously accepted
+    //~^ ERROR naked functions must contain a single asm block
     let mut a = 0usize;
     let mut b = 0usize;
     let mut c = 0usize;
@@ -65,11 +61,9 @@ pub unsafe extern "C" fn unsupported_operands() {
     const F: usize = 0usize;
     static G: usize = 0usize;
     asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
-         //~^ WARN asm in naked functions must use `noreturn` option
-         //~| WARN this was previously accepted
+         //~^ ERROR asm in naked functions must use `noreturn` option
          in(reg) a,
-         //~^ WARN only `const` and `sym` operands are supported in naked functions
-         //~| WARN this was previously accepted
+         //~^ ERROR only `const` and `sym` operands are supported in naked functions
          inlateout(reg) b,
          inout(reg) c,
          lateout(reg) d,
@@ -81,31 +75,25 @@ pub unsafe extern "C" fn unsupported_operands() {
 
 #[naked]
 pub extern "C" fn missing_assembly() {
-    //~^ WARN naked functions must contain a single asm block
-    //~| WARN this was previously accepted
+    //~^ ERROR naked functions must contain a single asm block
 }
 
 #[naked]
 pub extern "C" fn too_many_asm_blocks() {
-    //~^ WARN naked functions must contain a single asm block
-    //~| WARN this was previously accepted
+    //~^ ERROR naked functions must contain a single asm block
     asm!("");
-    //~^ WARN asm in naked functions must use `noreturn` option
-    //~| WARN this was previously accepted
+    //~^ ERROR asm in naked functions must use `noreturn` option
     asm!("");
-    //~^ WARN asm in naked functions must use `noreturn` option
-    //~| WARN this was previously accepted
+    //~^ ERROR asm in naked functions must use `noreturn` option
     asm!("");
-    //~^ WARN asm in naked functions must use `noreturn` option
-    //~| WARN this was previously accepted
+    //~^ ERROR asm in naked functions must use `noreturn` option
     asm!("", options(noreturn));
 }
 
 pub fn outer(x: u32) -> extern "C" fn(usize) -> usize {
     #[naked]
     pub extern "C" fn inner(y: usize) -> usize {
-        //~^ WARN naked functions must contain a single asm block
-        //~| WARN this was previously accepted
+        //~^ ERROR naked functions must contain a single asm block
         *&y
         //~^ ERROR referencing function parameters is not allowed in naked functions
     }
@@ -115,18 +103,21 @@ pub fn outer(x: u32) -> extern "C" fn(usize) -> usize {
 #[naked]
 unsafe extern "C" fn invalid_options() {
     asm!("", options(nomem, preserves_flags, noreturn));
-    //~^ WARN asm options unsupported in naked functions: `nomem`, `preserves_flags`
-    //~| WARN this was previously accepted
+    //~^ ERROR asm options unsupported in naked functions: `nomem`, `preserves_flags`
 }
 
 #[naked]
 unsafe extern "C" fn invalid_options_continued() {
     asm!("", options(readonly, nostack), options(pure));
     //~^ ERROR asm with the `pure` option must have at least one output
-    //~| WARN asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
-    //~| WARN this was previously accepted
-    //~| WARN asm in naked functions must use `noreturn` option
-    //~| WARN this was previously accepted
+    //~| ERROR asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
+    //~| ERROR asm in naked functions must use `noreturn` option
+}
+
+#[naked]
+unsafe extern "C" fn invalid_may_unwind() {
+    asm!("", options(noreturn, may_unwind));
+    //~^ ERROR asm options unsupported in naked functions: `may_unwind`
 }
 
 #[naked]
@@ -177,38 +168,32 @@ pub unsafe extern "C" fn inline_none() {
 
 #[naked]
 #[inline]
-//~^ WARN naked functions cannot be inlined
-//~| WARN this was previously accepted
+//~^ ERROR naked functions cannot be inlined
 pub unsafe extern "C" fn inline_hint() {
     asm!("", options(noreturn));
 }
 
 #[naked]
 #[inline(always)]
-//~^ WARN naked functions cannot be inlined
-//~| WARN this was previously accepted
+//~^ ERROR naked functions cannot be inlined
 pub unsafe extern "C" fn inline_always() {
     asm!("", options(noreturn));
 }
 
 #[naked]
 #[inline(never)]
-//~^ WARN naked functions cannot be inlined
-//~| WARN this was previously accepted
+//~^ ERROR naked functions cannot be inlined
 pub unsafe extern "C" fn inline_never() {
     asm!("", options(noreturn));
 }
 
 #[naked]
 #[inline]
-//~^ WARN naked functions cannot be inlined
-//~| WARN this was previously accepted
+//~^ ERROR naked functions cannot be inlined
 #[inline(always)]
-//~^ WARN naked functions cannot be inlined
-//~| WARN this was previously accepted
+//~^ ERROR naked functions cannot be inlined
 #[inline(never)]
-//~^ WARN naked functions cannot be inlined
-//~| WARN this was previously accepted
+//~^ ERROR naked functions cannot be inlined
 pub unsafe extern "C" fn inline_all() {
     asm!("", options(noreturn));
 }
diff --git a/src/test/ui/asm/naked-functions.stderr b/src/test/ui/asm/naked-functions.stderr
index c2dfe443d60..c1dcc433db6 100644
--- a/src/test/ui/asm/naked-functions.stderr
+++ b/src/test/ui/asm/naked-functions.stderr
@@ -1,5 +1,5 @@
 error: asm with the `pure` option must have at least one output
-  --> $DIR/naked-functions.rs:124:14
+  --> $DIR/naked-functions.rs:111:14
    |
 LL |     asm!("", options(readonly, nostack), options(pure));
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^
@@ -29,66 +29,54 @@ LL |     P { x, y }: P,
    |     ^^^^^^^^^^
 
 error: referencing function parameters is not allowed in naked functions
-  --> $DIR/naked-functions.rs:37:5
+  --> $DIR/naked-functions.rs:36:5
    |
 LL |     a + 1
    |     ^
    |
    = help: follow the calling convention in asm block to use parameters
 
-warning: naked functions must contain a single asm block
+error[E0787]: naked functions must contain a single asm block
   --> $DIR/naked-functions.rs:34:1
    |
 LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 {
 LL | |
-LL | |
 LL | |     a + 1
    | |     ----- non-asm is unsupported in naked functions
 LL | |
 LL | | }
    | |_^
-   |
-   = note: `#[warn(unsupported_naked_functions)]` 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 error: referencing function parameters is not allowed in naked functions
-  --> $DIR/naked-functions.rs:43:31
+  --> $DIR/naked-functions.rs:42:31
    |
 LL |     asm!("/* {0} */", in(reg) a, options(noreturn));
    |                               ^
    |
    = help: follow the calling convention in asm block to use parameters
 
-warning: only `const` and `sym` operands are supported in naked functions
-  --> $DIR/naked-functions.rs:43:23
+error[E0787]: only `const` and `sym` operands are supported in naked functions
+  --> $DIR/naked-functions.rs:42:23
    |
 LL |     asm!("/* {0} */", in(reg) a, options(noreturn));
    |                       ^^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:50:1
+error[E0787]: naked functions must contain a single asm block
+  --> $DIR/naked-functions.rs:48:1
    |
 LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
 LL | |
-LL | |
 LL | |     (|| a + 1)()
    | |     ------------ non-asm is unsupported in naked functions
 LL | | }
    | |_^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: only `const` and `sym` operands are supported in naked functions
-  --> $DIR/naked-functions.rs:70:10
+error[E0787]: only `const` and `sym` operands are supported in naked functions
+  --> $DIR/naked-functions.rs:65:10
    |
 LL |          in(reg) a,
    |          ^^^^^^^^^
-...
+LL |
 LL |          inlateout(reg) b,
    |          ^^^^^^^^^^^^^^^^
 LL |          inout(reg) c,
@@ -97,31 +85,24 @@ LL |          lateout(reg) d,
    |          ^^^^^^^^^^^^^^
 LL |          out(reg) e,
    |          ^^^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:67:5
+error[E0787]: asm in naked functions must use `noreturn` option
+  --> $DIR/naked-functions.rs:63:5
    |
 LL | /     asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
 LL | |
-LL | |
 LL | |          in(reg) a,
+LL | |
 ...  |
 LL | |          sym G,
 LL | |     );
    | |_____^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:57:1
+error[E0787]: naked functions must contain a single asm block
+  --> $DIR/naked-functions.rs:54:1
    |
 LL | / pub unsafe extern "C" fn unsupported_operands() {
 LL | |
-LL | |
 LL | |     let mut a = 0usize;
    | |     ------------------- non-asm is unsupported in naked functions
 LL | |     let mut b = 0usize;
@@ -136,123 +117,96 @@ LL | |     let mut e = 0usize;
 LL | |     );
 LL | | }
    | |_^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:83:1
+error[E0787]: naked functions must contain a single asm block
+  --> $DIR/naked-functions.rs:77:1
    |
 LL | / pub extern "C" fn missing_assembly() {
 LL | |
-LL | |
 LL | | }
    | |_^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:92:5
+error[E0787]: asm in naked functions must use `noreturn` option
+  --> $DIR/naked-functions.rs:84:5
    |
 LL |     asm!("");
    |     ^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:95:5
+error[E0787]: asm in naked functions must use `noreturn` option
+  --> $DIR/naked-functions.rs:86:5
    |
 LL |     asm!("");
    |     ^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:98:5
+error[E0787]: asm in naked functions must use `noreturn` option
+  --> $DIR/naked-functions.rs:88:5
    |
 LL |     asm!("");
    |     ^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:89:1
+error[E0787]: naked functions must contain a single asm block
+  --> $DIR/naked-functions.rs:82:1
    |
 LL | / pub extern "C" fn too_many_asm_blocks() {
 LL | |
-LL | |
 LL | |     asm!("");
-...  |
+LL | |
 LL | |     asm!("");
    | |     -------- multiple asm blocks are unsupported in naked functions
-...  |
+LL | |
 LL | |     asm!("");
    | |     -------- multiple asm blocks are unsupported in naked functions
-...  |
+LL | |
 LL | |     asm!("", options(noreturn));
    | |     --------------------------- multiple asm blocks are unsupported in naked functions
 LL | | }
    | |_^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 error: referencing function parameters is not allowed in naked functions
-  --> $DIR/naked-functions.rs:109:11
+  --> $DIR/naked-functions.rs:97:11
    |
 LL |         *&y
    |           ^
    |
    = help: follow the calling convention in asm block to use parameters
 
-warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:106:5
+error[E0787]: naked functions must contain a single asm block
+  --> $DIR/naked-functions.rs:95:5
    |
 LL | /     pub extern "C" fn inner(y: usize) -> usize {
 LL | |
-LL | |
 LL | |         *&y
    | |         --- non-asm is unsupported in naked functions
 LL | |
 LL | |     }
    | |_____^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: asm options unsupported in naked functions: `nomem`, `preserves_flags`
-  --> $DIR/naked-functions.rs:117:5
+error[E0787]: asm options unsupported in naked functions: `nomem`, `preserves_flags`
+  --> $DIR/naked-functions.rs:105:5
    |
 LL |     asm!("", options(nomem, preserves_flags, noreturn));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
-  --> $DIR/naked-functions.rs:124:5
+error[E0787]: asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
+  --> $DIR/naked-functions.rs:111:5
    |
 LL |     asm!("", options(readonly, nostack), options(pure));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:124:5
+error[E0787]: asm in naked functions must use `noreturn` option
+  --> $DIR/naked-functions.rs:111:5
    |
 LL |     asm!("", options(readonly, nostack), options(pure));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0787]: asm options unsupported in naked functions: `may_unwind`
+  --> $DIR/naked-functions.rs:119:5
    |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
+LL |     asm!("", options(noreturn, may_unwind));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: Rust ABI is unsupported in naked functions
-  --> $DIR/naked-functions.rs:133:15
+  --> $DIR/naked-functions.rs:124:15
    |
 LL | pub unsafe fn default_abi() {
    |               ^^^^^^^^^^^
@@ -260,64 +214,47 @@ LL | pub unsafe fn default_abi() {
    = note: `#[warn(undefined_naked_function_abi)]` on by default
 
 warning: Rust ABI is unsupported in naked functions
-  --> $DIR/naked-functions.rs:139:15
+  --> $DIR/naked-functions.rs:130:15
    |
 LL | pub unsafe fn rust_abi() {
    |               ^^^^^^^^
 
-warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:179:1
+error: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:170:1
    |
 LL | #[inline]
    | ^^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:187:1
+error: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:177:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:195:1
+error: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:184:1
    |
 LL | #[inline(never)]
    | ^^^^^^^^^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:203:1
+error: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:191:1
    |
 LL | #[inline]
    | ^^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:206:1
+error: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:193:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:209:1
+error: naked functions cannot be inlined
+  --> $DIR/naked-functions.rs:195:1
    |
 LL | #[inline(never)]
    | ^^^^^^^^^^^^^^^^
-   |
-   = 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 #32408 <https://github.com/rust-lang/rust/issues/32408>
 
-error: aborting due to 8 previous errors; 23 warnings emitted
+error: aborting due to 30 previous errors; 2 warnings emitted
 
+For more information about this error, try `rustc --explain E0787`.
diff --git a/src/test/ui/asm/named-asm-labels.stderr b/src/test/ui/asm/named-asm-labels.stderr
index b8ff42d86b5..001601497a2 100644
--- a/src/test/ui/asm/named-asm-labels.stderr
+++ b/src/test/ui/asm/named-asm-labels.stderr
@@ -6,6 +6,7 @@ LL |         asm!("bar: nop");
    |
    = note: `#[deny(named_asm_labels)]` on by default
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:27:15
@@ -14,6 +15,7 @@ LL |         asm!("abcd:");
    |               ^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:30:15
@@ -22,6 +24,7 @@ LL |         asm!("foo: bar1: nop");
    |               ^^^  ^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:34:15
@@ -30,6 +33,7 @@ LL |         asm!("foo1: nop", "nop");
    |               ^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:35:15
@@ -38,6 +42,7 @@ LL |         asm!("foo2: foo3: nop", "nop");
    |               ^^^^  ^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:37:22
@@ -46,6 +51,7 @@ LL |         asm!("nop", "foo4: nop");
    |                      ^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:38:15
@@ -54,6 +60,7 @@ LL |         asm!("foo5: nop", "foo6: nop");
    |               ^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:38:28
@@ -62,6 +69,7 @@ LL |         asm!("foo5: nop", "foo6: nop");
    |                            ^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:43:15
@@ -70,6 +78,7 @@ LL |         asm!("foo7: nop; foo8: nop");
    |               ^^^^       ^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:45:15
@@ -78,6 +87,7 @@ LL |         asm!("foo9: nop; nop");
    |               ^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:46:20
@@ -86,6 +96,7 @@ LL |         asm!("nop; foo10: nop");
    |                    ^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:49:15
@@ -94,6 +105,7 @@ LL |         asm!("bar2: nop\n bar3: nop");
    |               ^^^^        ^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:51:15
@@ -102,6 +114,7 @@ LL |         asm!("bar4: nop\n nop");
    |               ^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:52:21
@@ -110,6 +123,7 @@ LL |         asm!("nop\n bar5: nop");
    |                     ^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:53:21
@@ -118,6 +132,7 @@ LL |         asm!("nop\n bar6: bar7: nop");
    |                     ^^^^  ^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:59:13
@@ -128,6 +143,7 @@ LL |             blah3: nop
    |             ^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:68:19
@@ -136,6 +152,7 @@ LL |             nop ; blah4: nop
    |                   ^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:82:15
@@ -144,6 +161,7 @@ LL |         asm!("blah1: 2bar: nop");
    |               ^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:85:15
@@ -152,6 +170,7 @@ LL |         asm!("def: def: nop");
    |               ^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:86:15
@@ -160,6 +179,7 @@ LL |         asm!("def: nop\ndef: nop");
    |               ^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:87:15
@@ -168,6 +188,7 @@ LL |         asm!("def: nop; def: nop");
    |               ^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:95:15
@@ -176,6 +197,7 @@ LL |         asm!("fooo\u{003A} nop");
    |               ^^^^^^^^^^^^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:96:15
@@ -184,6 +206,7 @@ LL |         asm!("foooo\x3A nop");
    |               ^^^^^^^^^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:99:15
@@ -192,6 +215,7 @@ LL |         asm!("fooooo:\u{000A} nop");
    |               ^^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:100:15
@@ -200,6 +224,7 @@ LL |         asm!("foooooo:\x0A nop");
    |               ^^^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:104:14
@@ -208,6 +233,7 @@ LL |         asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70");
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:112:13
@@ -216,6 +242,7 @@ LL |             ab: nop // ab: does foo
    |             ^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:124:14
@@ -224,6 +251,7 @@ LL |         asm!(include_str!("named-asm-labels.s"));
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 warning: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:134:19
@@ -237,6 +265,7 @@ note: the lint level is defined here
 LL |         #[warn(named_asm_labels)]
    |                ^^^^^^^^^^^^^^^^
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:143:20
@@ -245,6 +274,7 @@ LL |     unsafe { asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1, options(noret
    |                    ^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:149:20
@@ -253,6 +283,7 @@ LL |     unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noret
    |                    ^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:157:20
@@ -261,6 +292,7 @@ LL |     unsafe { asm!(".Laaa: nop; ret;", options(noreturn)) }
    |                    ^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:167:24
@@ -269,6 +301,7 @@ LL |         unsafe { asm!(".Lbbb: nop; ret;", options(noreturn)) }
    |                        ^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:176:15
@@ -277,6 +310,7 @@ LL |         asm!("closure1: nop");
    |               ^^^^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:180:15
@@ -285,6 +319,7 @@ LL |         asm!("closure2: nop");
    |               ^^^^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
   --> $DIR/named-asm-labels.rs:190:19
@@ -293,6 +328,7 @@ LL |             asm!("closure3: nop");
    |                   ^^^^^^^^
    |
    = help: only local labels of the form `<number>:` should be used in inline asm
+   = note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 error: aborting due to 35 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/async-await/async-fn-nonsend.rs b/src/test/ui/async-await/async-fn-nonsend.rs
index c5453b67ef5..a1a05c0acba 100644
--- a/src/test/ui/async-await/async-fn-nonsend.rs
+++ b/src/test/ui/async-await/async-fn-nonsend.rs
@@ -1,6 +1,10 @@
 // edition:2018
 // compile-flags: --crate-type lib
 
+// FIXME(eholk): temporarily disabled while drop range tracking is disabled
+// (see generator_interior.rs:27)
+// ignore-test
+
 use std::{cell::RefCell, fmt::Debug, rc::Rc};
 
 fn non_sync() -> impl Debug {
diff --git a/src/test/ui/async-await/proper-span-for-type-error.fixed b/src/test/ui/async-await/proper-span-for-type-error.fixed
new file mode 100644
index 00000000000..1f1e1184dcc
--- /dev/null
+++ b/src/test/ui/async-await/proper-span-for-type-error.fixed
@@ -0,0 +1,11 @@
+// edition:2021
+// run-rustfix
+#![allow(dead_code)]
+
+async fn a() {}
+
+async fn foo() -> Result<(), i32> {
+    Ok(a().await) //~ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/proper-span-for-type-error.rs b/src/test/ui/async-await/proper-span-for-type-error.rs
new file mode 100644
index 00000000000..00ccde1bf99
--- /dev/null
+++ b/src/test/ui/async-await/proper-span-for-type-error.rs
@@ -0,0 +1,11 @@
+// edition:2021
+// run-rustfix
+#![allow(dead_code)]
+
+async fn a() {}
+
+async fn foo() -> Result<(), i32> {
+    a().await //~ ERROR mismatched types
+}
+
+fn main() {}
diff --git a/src/test/ui/async-await/proper-span-for-type-error.stderr b/src/test/ui/async-await/proper-span-for-type-error.stderr
new file mode 100644
index 00000000000..611dc0407bf
--- /dev/null
+++ b/src/test/ui/async-await/proper-span-for-type-error.stderr
@@ -0,0 +1,16 @@
+error[E0308]: mismatched types
+  --> $DIR/proper-span-for-type-error.rs:8:5
+   |
+LL |     a().await
+   |     ^^^^^^^^^ expected enum `Result`, found `()`
+   |
+   = note:   expected enum `Result<(), i32>`
+           found unit type `()`
+help: try wrapping the expression in `Ok`
+   |
+LL |     Ok(a().await)
+   |     +++         +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/async-await/unresolved_type_param.rs b/src/test/ui/async-await/unresolved_type_param.rs
index d313691b388..187356ca140 100644
--- a/src/test/ui/async-await/unresolved_type_param.rs
+++ b/src/test/ui/async-await/unresolved_type_param.rs
@@ -3,6 +3,10 @@
 // (rather than give a general error message)
 // edition:2018
 
+// FIXME(eholk): temporarily disabled while drop range tracking is disabled
+// (see generator_interior.rs:27)
+// ignore-test
+
 async fn bar<T>() -> () {}
 
 async fn foo() {
diff --git a/src/test/ui/attributes/key-value-expansion.stderr b/src/test/ui/attributes/key-value-expansion.stderr
index 268e382327e..1b7cb76b553 100644
--- a/src/test/ui/attributes/key-value-expansion.stderr
+++ b/src/test/ui/attributes/key-value-expansion.stderr
@@ -16,12 +16,11 @@ LL | bug!();
    = note: this error originates in the macro `bug` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: unexpected token: `{
-           let res =
-               ::alloc::fmt::format(::core::fmt::Arguments::new_v1(&[""],
-                                                                   &[::core::fmt::ArgumentV1::new(&"u8",
-                                                                                                  ::core::fmt::Display::fmt)]));
-           res
-       }.as_str()`
+               let res =
+                   ::alloc::fmt::format(::core::fmt::Arguments::new_v1(&[""],
+                           &[::core::fmt::ArgumentV1::new_display(&"u8")]));
+               res
+           }.as_str()`
   --> $DIR/key-value-expansion.rs:48:23
    |
 LL |         doc_comment! {format!("{coor}", coor = stringify!($t1)).as_str()}
diff --git a/src/test/ui/c-variadic/variadic-ffi-4.stderr b/src/test/ui/c-variadic/variadic-ffi-4.stderr
index 4b03fe15494..ff4da5251a9 100644
--- a/src/test/ui/c-variadic/variadic-ffi-4.stderr
+++ b/src/test/ui/c-variadic/variadic-ffi-4.stderr
@@ -20,7 +20,7 @@ LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f
    |                                     |
    |                                     lifetime `'f` defined here
 LL |     ap
-   |     ^^ returning this value requires that `'1` must outlive `'f`
+   |     ^^ function was supposed to return data with lifetime `'f` but it is returning data with lifetime `'1`
    |
    = note: requirement occurs because of the type VaListImpl<'_>, which makes the generic argument '_ invariant
    = note: the struct VaListImpl<'f> is invariant over the parameter 'f
diff --git a/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs b/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs
index ef12b05fab2..6cb2ff9d813 100644
--- a/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs
+++ b/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.rs
@@ -5,8 +5,12 @@
 #![cfg_attr(foo, crate_type="bin")]
 //~^ERROR `crate_type` within
 //~| WARN this was previously accepted
+//~|ERROR `crate_type` within
+//~| WARN this was previously accepted
 #![cfg_attr(foo, crate_name="bar")]
 //~^ERROR `crate_name` within
 //~| WARN this was previously accepted
+//~|ERROR `crate_name` within
+//~| WARN this was previously accepted
 
 fn main() {}
diff --git a/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr b/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr
index 5df2eacc96e..5609f8e9d9f 100644
--- a/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr
+++ b/src/test/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr
@@ -14,7 +14,7 @@ LL | #![deny(warnings)]
    = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632>
 
 error: `crate_name` within an `#![cfg_attr] attribute is deprecated`
-  --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:8:18
+  --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:10:18
    |
 LL | #![cfg_attr(foo, crate_name="bar")]
    |                  ^^^^^^^^^^^^^^^^
@@ -22,5 +22,23 @@ LL | #![cfg_attr(foo, crate_name="bar")]
    = 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 #91632 <https://github.com/rust-lang/rust/issues/91632>
 
-error: aborting due to 2 previous errors
+error: `crate_type` within an `#![cfg_attr] attribute is deprecated`
+  --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:5:18
+   |
+LL | #![cfg_attr(foo, crate_type="bin")]
+   |                  ^^^^^^^^^^^^^^^^
+   |
+   = 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 #91632 <https://github.com/rust-lang/rust/issues/91632>
+
+error: `crate_name` within an `#![cfg_attr] attribute is deprecated`
+  --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:10:18
+   |
+LL | #![cfg_attr(foo, crate_name="bar")]
+   |                  ^^^^^^^^^^^^^^^^
+   |
+   = 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 #91632 <https://github.com/rust-lang/rust/issues/91632>
+
+error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/closures/issue-84044-drop-non-mut.rs b/src/test/ui/closures/issue-84044-drop-non-mut.rs
new file mode 100644
index 00000000000..aed7750f1b9
--- /dev/null
+++ b/src/test/ui/closures/issue-84044-drop-non-mut.rs
@@ -0,0 +1,6 @@
+// #84044: This used to ICE.
+
+fn main() {
+    let f = || {};
+    drop(&mut f); //~ ERROR cannot borrow `f` as mutable, as it is not declared as mutable
+}
diff --git a/src/test/ui/closures/issue-84044-drop-non-mut.stderr b/src/test/ui/closures/issue-84044-drop-non-mut.stderr
new file mode 100644
index 00000000000..c0bfad263f1
--- /dev/null
+++ b/src/test/ui/closures/issue-84044-drop-non-mut.stderr
@@ -0,0 +1,11 @@
+error[E0596]: cannot borrow `f` as mutable, as it is not declared as mutable
+  --> $DIR/issue-84044-drop-non-mut.rs:5:10
+   |
+LL |     let f = || {};
+   |         - help: consider changing this to be mutable: `mut f`
+LL |     drop(&mut f);
+   |          ^^^^^^ cannot borrow as mutable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr
index bdc71b8dcaa..aee782a1c5b 100644
--- a/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr
+++ b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr
@@ -9,7 +9,7 @@ LL |         let c1 : () = c;
    |                  expected due to this
    |
    = note: expected unit type `()`
-                found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#19t, extern "rust-call" fn(()), _#20t]]`
+                found closure `[mod1::f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#16t, extern "rust-call" fn(()), _#15t]]`
 help: use parentheses to call this closure
    |
 LL |         let c1 : () = c();
diff --git a/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr b/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr
index 453f18891d3..6a994ce718e 100644
--- a/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr
+++ b/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr
@@ -9,7 +9,7 @@ LL |         let c1 : () = c;
    |                  expected due to this
    |
    = note: expected unit type `()`
-                found closure `[f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#19t, extern "rust-call" fn(()), _#20t]]`
+                found closure `[f<T>::{closure#0} closure_substs=(unavailable) substs=[T, _#16t, extern "rust-call" fn(()), _#15t]]`
 help: use parentheses to call this closure
    |
 LL |         let c1 : () = c();
diff --git a/src/test/ui/coherence/auxiliary/option_future.rs b/src/test/ui/coherence/auxiliary/option_future.rs
new file mode 100644
index 00000000000..f71df1b87fc
--- /dev/null
+++ b/src/test/ui/coherence/auxiliary/option_future.rs
@@ -0,0 +1,8 @@
+#![crate_type = "lib"]
+#![feature(negative_impls)]
+#![feature(rustc_attrs)]
+
+pub trait Future {}
+
+#[rustc_with_negative_coherence]
+impl<E> !Future for Option<E> where E: Sized {}
diff --git a/src/test/ui/coherence/coherence-overlap-negative-trait2.rs b/src/test/ui/coherence/coherence-overlap-negative-trait2.rs
new file mode 100644
index 00000000000..1f47b5ba46e
--- /dev/null
+++ b/src/test/ui/coherence/coherence-overlap-negative-trait2.rs
@@ -0,0 +1,18 @@
+// check-pass
+// aux-build:option_future.rs
+//
+// Check that if we promise to not impl what would overlap it doesn't actually overlap
+
+#![feature(rustc_attrs)]
+
+extern crate option_future as lib;
+use lib::Future;
+
+trait Termination {}
+
+#[rustc_with_negative_coherence]
+impl<E> Termination for Option<E> where E: Sized {}
+#[rustc_with_negative_coherence]
+impl<F> Termination for F where F: Future + Sized {}
+
+fn main() {}
diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-1.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-1.rs
index 36dd78dd2b1..d20e79b9db3 100644
--- a/src/test/ui/conditional-compilation/cfg-arg-invalid-1.rs
+++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-1.rs
@@ -1,3 +1,3 @@
 // compile-flags: --cfg a(b=c)
-// error-pattern: invalid `--cfg` argument: `a(b=c)` (expected `key` or `key="value"`)
+// error-pattern: invalid `--cfg` argument: `a(b=c)` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\")
 fn main() {}
diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-1.stderr b/src/test/ui/conditional-compilation/cfg-arg-invalid-1.stderr
index 1e7922a9ff1..3a12e978680 100644
--- a/src/test/ui/conditional-compilation/cfg-arg-invalid-1.stderr
+++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-1.stderr
@@ -1,2 +1,2 @@
-error: invalid `--cfg` argument: `a(b=c)` (expected `key` or `key="value"`)
+error: invalid `--cfg` argument: `a(b=c)` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\")
 
diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-9.rs b/src/test/ui/conditional-compilation/cfg-arg-invalid-9.rs
new file mode 100644
index 00000000000..628b335c873
--- /dev/null
+++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-9.rs
@@ -0,0 +1,4 @@
+// Test for missing quotes around value, issue #66450.
+// compile-flags: --cfg key=value
+// error-pattern: invalid `--cfg` argument: `key=value` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\")
+fn main() {}
diff --git a/src/test/ui/conditional-compilation/cfg-arg-invalid-9.stderr b/src/test/ui/conditional-compilation/cfg-arg-invalid-9.stderr
new file mode 100644
index 00000000000..985b5252258
--- /dev/null
+++ b/src/test/ui/conditional-compilation/cfg-arg-invalid-9.stderr
@@ -0,0 +1,2 @@
+error: invalid `--cfg` argument: `key=value` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\")
+
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 99fe9d2e4b3..121138605f1 100644
--- a/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout
+++ b/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout
@@ -15,4 +15,4 @@ trait Foo<const KIND : bool = true> {}
 fn foo<const SIZE : usize = 5>() {}
 
 struct Range<const FROM : usize = 0, const LEN : usize = 0, const TO : usize =
-             FROM>;
+    FROM>;
diff --git a/src/test/ui/consts/const-block-const-bound.rs b/src/test/ui/consts/const-block-const-bound.rs
index 3d7e171f18c..f3c82c5f968 100644
--- a/src/test/ui/consts/const-block-const-bound.rs
+++ b/src/test/ui/consts/const-block-const-bound.rs
@@ -16,8 +16,8 @@ impl !Drop for NonDrop {}
 fn main() {
     const {
         f(UnconstDrop);
-        //~^ ERROR the trait bound `UnconstDrop: Drop` is not satisfied
+        //~^ ERROR the trait bound `UnconstDrop: ~const Drop` is not satisfied
         f(NonDrop);
-        //~^ ERROR the trait bound `NonDrop: Drop` is not satisfied
+        //~^ ERROR the trait bound `NonDrop: ~const Drop` is not satisfied
     }
 }
diff --git a/src/test/ui/consts/const-block-const-bound.stderr b/src/test/ui/consts/const-block-const-bound.stderr
index 5f912c66bb9..b5f5694ba83 100644
--- a/src/test/ui/consts/const-block-const-bound.stderr
+++ b/src/test/ui/consts/const-block-const-bound.stderr
@@ -1,8 +1,8 @@
-error[E0277]: the trait bound `UnconstDrop: Drop` is not satisfied
+error[E0277]: the trait bound `UnconstDrop: ~const Drop` is not satisfied
   --> $DIR/const-block-const-bound.rs:18:11
    |
 LL |         f(UnconstDrop);
-   |         - ^^^^^^^^^^^ the trait `Drop` is not implemented for `UnconstDrop`
+   |         - ^^^^^^^^^^^ expected an implementor of trait `~const Drop`
    |         |
    |         required by a bound introduced by this call
    |
@@ -11,16 +11,18 @@ note: required by a bound in `f`
    |
 LL | const fn f<T: ~const Drop>(x: T) {}
    |               ^^^^^^^^^^^ required by this bound in `f`
-help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+help: consider borrowing here
    |
-LL | fn main() where UnconstDrop: Drop {
-   |           +++++++++++++++++++++++
+LL |         f(&UnconstDrop);
+   |           +
+LL |         f(&mut UnconstDrop);
+   |           ++++
 
-error[E0277]: the trait bound `NonDrop: Drop` is not satisfied
+error[E0277]: the trait bound `NonDrop: ~const Drop` is not satisfied
   --> $DIR/const-block-const-bound.rs:20:11
    |
 LL |         f(NonDrop);
-   |         - ^^^^^^^ the trait `Drop` is not implemented for `NonDrop`
+   |         - ^^^^^^^ expected an implementor of trait `~const Drop`
    |         |
    |         required by a bound introduced by this call
    |
@@ -29,6 +31,12 @@ note: required by a bound in `f`
    |
 LL | const fn f<T: ~const Drop>(x: T) {}
    |               ^^^^^^^^^^^ required by this bound in `f`
+help: consider borrowing here
+   |
+LL |         f(&NonDrop);
+   |           +
+LL |         f(&mut NonDrop);
+   |           ++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs
index 1a1d9a6d540..ac9e8b64b48 100644
--- a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs
+++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.rs
@@ -6,11 +6,10 @@ use std::intrinsics;
 const FOO: i32 = foo();
 const fn foo() -> i32 {
     unsafe {
-        let _ = intrinsics::const_allocate(4, 3) as * mut i32;
+        let _ = intrinsics::const_allocate(4, 3) as *mut i32;
         //~^ error: evaluation of constant value failed
     }
     1
-
 }
 
 fn main() {}
diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr
index 74fb65ca1a6..2628a78455c 100644
--- a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr
+++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_errors.stderr
@@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
 LL | const FOO: i32 = foo();
    |                  ----- inside `FOO` at $DIR/alloc_intrinsic_errors.rs:6:18
 ...
-LL |         let _ = intrinsics::const_allocate(4, 3) as * mut i32;
+LL |         let _ = intrinsics::const_allocate(4, 3) as *mut i32;
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |                 |
    |                 align has to be a power of 2, `3` is not a power of 2
diff --git a/src/test/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs
new file mode 100644
index 00000000000..407e69d41a0
--- /dev/null
+++ b/src/test/ui/consts/const-eval/heap/alloc_intrinsic_zero_sized.rs
@@ -0,0 +1,16 @@
+// run-pass
+#![feature(core_intrinsics)]
+#![feature(const_heap)]
+#![feature(inline_const)]
+
+use std::intrinsics;
+
+struct ZST;
+
+fn main() {
+    const {
+        unsafe {
+            let _ = intrinsics::const_allocate(0, 0) as *mut ZST;
+        }
+    }
+}
diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic.rs
new file mode 100644
index 00000000000..aac90cd54cc
--- /dev/null
+++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic.rs
@@ -0,0 +1,36 @@
+// run-pass
+#![feature(core_intrinsics)]
+#![feature(const_heap)]
+#![feature(const_mut_refs)]
+
+use std::intrinsics;
+
+const _X: () = unsafe {
+    let ptr = intrinsics::const_allocate(4, 4);
+    intrinsics::const_deallocate(ptr, 4, 4);
+};
+
+const Y: &u32 = unsafe {
+    let ptr = intrinsics::const_allocate(4, 4) as *mut u32;
+    *ptr = 42;
+    &*ptr
+};
+
+const Z: &u32 = &42;
+
+const _Z: () = unsafe {
+    let ptr1 = Y as *const _ as *mut u8;
+    intrinsics::const_deallocate(ptr1, 4, 4); // nop
+    intrinsics::const_deallocate(ptr1, 2, 4); // nop
+    intrinsics::const_deallocate(ptr1, 4, 2); // nop
+
+    let ptr2 = Z as *const _ as *mut u8;
+    intrinsics::const_deallocate(ptr2, 4, 4); // nop
+    intrinsics::const_deallocate(ptr2, 2, 4); // nop
+    intrinsics::const_deallocate(ptr2, 4, 2); // nop
+};
+
+fn main() {
+    assert_eq!(*Y, 42);
+    assert_eq!(*Z, 42);
+}
diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs
new file mode 100644
index 00000000000..b6d89a58dce
--- /dev/null
+++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.rs
@@ -0,0 +1,22 @@
+#![feature(core_intrinsics)]
+#![feature(const_heap)]
+#![feature(const_mut_refs)]
+
+use std::intrinsics;
+
+const _X: &'static u8 = unsafe {
+    let ptr = intrinsics::const_allocate(4, 4);
+    intrinsics::const_deallocate(ptr, 4, 4);
+    &*ptr
+    //~^ error: evaluation of constant value failed
+};
+
+const _Y: u8 = unsafe {
+    let ptr = intrinsics::const_allocate(4, 4);
+    let reference = &*ptr;
+    intrinsics::const_deallocate(ptr, 4, 4);
+    *reference
+    //~^ error: evaluation of constant value failed
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr
new file mode 100644
index 00000000000..4eb1c42e1f7
--- /dev/null
+++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_dangling.stderr
@@ -0,0 +1,15 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/dealloc_intrinsic_dangling.rs:10:5
+   |
+LL |     &*ptr
+   |     ^^^^^ pointer to alloc2 was dereferenced after this allocation got freed
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/dealloc_intrinsic_dangling.rs:18:5
+   |
+LL |     *reference
+   |     ^^^^^^^^^^ pointer to alloc4 was dereferenced after this allocation got freed
+
+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/heap/dealloc_intrinsic_duplicate.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs
new file mode 100644
index 00000000000..4010b476990
--- /dev/null
+++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.rs
@@ -0,0 +1,13 @@
+#![feature(core_intrinsics)]
+#![feature(const_heap)]
+
+use std::intrinsics;
+
+const _X: () = unsafe {
+    let ptr = intrinsics::const_allocate(4, 4);
+    intrinsics::const_deallocate(ptr, 4, 4);
+    intrinsics::const_deallocate(ptr, 4, 4);
+    //~^ error: evaluation of constant value failed
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr
new file mode 100644
index 00000000000..8177a08504b
--- /dev/null
+++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_duplicate.stderr
@@ -0,0 +1,9 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/dealloc_intrinsic_duplicate.rs:9:5
+   |
+LL |     intrinsics::const_deallocate(ptr, 4, 4);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to alloc2 was dereferenced after this allocation got freed
+
+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/heap/dealloc_intrinsic_incorrect_layout.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs
new file mode 100644
index 00000000000..031d70fdc88
--- /dev/null
+++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.rs
@@ -0,0 +1,29 @@
+#![feature(core_intrinsics)]
+#![feature(const_heap)]
+
+use std::intrinsics;
+
+const _X: () = unsafe {
+    let ptr = intrinsics::const_allocate(4, 4);
+    intrinsics::const_deallocate(ptr, 4, 2);
+    //~^ error: evaluation of constant value failed
+};
+const _Y: () = unsafe {
+    let ptr = intrinsics::const_allocate(4, 4);
+    intrinsics::const_deallocate(ptr, 2, 4);
+    //~^ error: evaluation of constant value failed
+};
+
+const _Z: () = unsafe {
+    let ptr = intrinsics::const_allocate(4, 4);
+    intrinsics::const_deallocate(ptr, 3, 4);
+    //~^ error: evaluation of constant value failed
+};
+
+const _W: () = unsafe {
+    let ptr = intrinsics::const_allocate(4, 4);
+    intrinsics::const_deallocate(ptr, 4, 3);
+    //~^ error: evaluation of constant value failed
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr
new file mode 100644
index 00000000000..650b409b190
--- /dev/null
+++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_incorrect_layout.stderr
@@ -0,0 +1,27 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/dealloc_intrinsic_incorrect_layout.rs:8:5
+   |
+LL |     intrinsics::const_deallocate(ptr, 4, 2);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: alloc2 has size 4 and alignment 4, but gave size 4 and alignment 2
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/dealloc_intrinsic_incorrect_layout.rs:13:5
+   |
+LL |     intrinsics::const_deallocate(ptr, 2, 4);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: alloc4 has size 4 and alignment 4, but gave size 2 and alignment 4
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/dealloc_intrinsic_incorrect_layout.rs:19:5
+   |
+LL |     intrinsics::const_deallocate(ptr, 3, 4);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: alloc6 has size 4 and alignment 4, but gave size 3 and alignment 4
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/dealloc_intrinsic_incorrect_layout.rs:25:5
+   |
+LL |     intrinsics::const_deallocate(ptr, 4, 3);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ align has to be a power of 2, `3` is not a power of 2
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs
new file mode 100644
index 00000000000..84fb4d2ea87
--- /dev/null
+++ b/src/test/ui/consts/const-eval/heap/dealloc_intrinsic_zero_sized.rs
@@ -0,0 +1,17 @@
+// run-pass
+#![feature(core_intrinsics)]
+#![feature(const_heap)]
+#![feature(inline_const)]
+
+use std::intrinsics;
+
+fn main() {
+    const {
+        unsafe {
+            let ptr1 = intrinsics::const_allocate(0, 0);
+            let ptr2 = intrinsics::const_allocate(0, 0);
+            intrinsics::const_deallocate(ptr1, 0, 0);
+            intrinsics::const_deallocate(ptr2, 0, 0);
+        }
+    }
+}
diff --git a/src/test/ui/consts/miri_unleashed/tls.stderr b/src/test/ui/consts/miri_unleashed/tls.stderr
index ebe20348830..a49e50a3eaa 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[HASH]::A))
+   |                         ^ cannot access thread local static (DefId(0:6 ~ tls[78b0]::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[HASH]::A))
+   |                          ^ cannot access thread local static (DefId(0:6 ~ tls[78b0]::A))
 
 warning: skipping const checks
    |
diff --git a/src/test/ui/fmt/ifmt-unimpl.stderr b/src/test/ui/fmt/ifmt-unimpl.stderr
index bee165437cb..6e8dd792191 100644
--- a/src/test/ui/fmt/ifmt-unimpl.stderr
+++ b/src/test/ui/fmt/ifmt-unimpl.stderr
@@ -5,6 +5,11 @@ LL |     format!("{:X}", "3");
    |                     ^^^ the trait `UpperHex` is not implemented for `str`
    |
    = note: required because of the requirements on the impl of `UpperHex` for `&str`
+note: required by a bound in `ArgumentV1::<'a>::new_upper_hex`
+  --> $SRC_DIR/core/src/fmt/mod.rs:LL:COL
+   |
+LL |     arg_new!(new_upper_hex, UpperHex);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `ArgumentV1::<'a>::new_upper_hex`
    = note: this error originates in the macro `$crate::__export::format_args` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr
index e37ec7f2665..8096f08385c 100644
--- a/src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr
+++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type.nll.stderr
@@ -6,7 +6,7 @@ LL | fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str {
    |      |
    |      lifetime `'a` defined here
 LL |     s
-   |     ^ returning this value requires that `'b` must outlive `'a`
+   |     ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'a`
 
diff --git a/src/test/ui/generator/drop-control-flow.rs b/src/test/ui/generator/drop-control-flow.rs
index 6319a29f5b7..8540f7617ac 100644
--- a/src/test/ui/generator/drop-control-flow.rs
+++ b/src/test/ui/generator/drop-control-flow.rs
@@ -1,5 +1,9 @@
 // build-pass
 
+// FIXME(eholk): temporarily disabled while drop range tracking is disabled
+// (see generator_interior.rs:27)
+// ignore-test
+
 // A test to ensure generators capture values that were conditionally dropped,
 // and also that values that are dropped along all paths to a yield do not get
 // included in the generator type.
diff --git a/src/test/ui/generator/issue-57478.rs b/src/test/ui/generator/issue-57478.rs
index 39710febdb9..5c23ecbae32 100644
--- a/src/test/ui/generator/issue-57478.rs
+++ b/src/test/ui/generator/issue-57478.rs
@@ -1,5 +1,9 @@
 // check-pass
 
+// FIXME(eholk): temporarily disabled while drop range tracking is disabled
+// (see generator_interior.rs:27)
+// ignore-test
+
 #![feature(negative_impls, generators)]
 
 struct Foo;
diff --git a/src/test/ui/generator/issue-93161.rs b/src/test/ui/generator/issue-93161.rs
new file mode 100644
index 00000000000..9988acbcb73
--- /dev/null
+++ b/src/test/ui/generator/issue-93161.rs
@@ -0,0 +1,93 @@
+// edition:2021
+// run-pass
+
+#![feature(never_type)]
+
+use std::future::Future;
+
+// See if we can run a basic `async fn`
+pub async fn foo(x: &u32, y: u32) -> u32 {
+    let y = &y;
+    let z = 9;
+    let z = &z;
+    let y = async { *y + *z }.await;
+    let a = 10;
+    let a = &a;
+    *x + y + *a
+}
+
+async fn add(x: u32, y: u32) -> u32 {
+    let a = async { x + y };
+    a.await
+}
+
+async fn build_aggregate(a: u32, b: u32, c: u32, d: u32) -> u32 {
+    let x = (add(a, b).await, add(c, d).await);
+    x.0 + x.1
+}
+
+enum Never {}
+fn never() -> Never {
+    panic!()
+}
+
+async fn includes_never(crash: bool, x: u32) -> u32 {
+    let mut result = async { x * x }.await;
+    if !crash {
+        return result;
+    }
+    #[allow(unused)]
+    let bad = never();
+    result *= async { x + x }.await;
+    drop(bad);
+    result
+}
+
+async fn partial_init(x: u32) -> u32 {
+    #[allow(unreachable_code)]
+    let _x: (String, !) = (String::new(), return async { x + x }.await);
+}
+
+async fn read_exact(_from: &mut &[u8], _to: &mut [u8]) -> Option<()> {
+    Some(())
+}
+
+async fn hello_world() {
+    let data = [0u8; 1];
+    let mut reader = &data[..];
+
+    let mut marker = [0u8; 1];
+    read_exact(&mut reader, &mut marker).await.unwrap();
+}
+
+fn run_fut<T>(fut: impl Future<Output = T>) -> T {
+    use std::sync::Arc;
+    use std::task::{Context, Poll, Wake, Waker};
+
+    struct MyWaker;
+    impl Wake for MyWaker {
+        fn wake(self: Arc<Self>) {
+            unimplemented!()
+        }
+    }
+
+    let waker = Waker::from(Arc::new(MyWaker));
+    let mut context = Context::from_waker(&waker);
+
+    let mut pinned = Box::pin(fut);
+    loop {
+        match pinned.as_mut().poll(&mut context) {
+            Poll::Pending => continue,
+            Poll::Ready(v) => return v,
+        }
+    }
+}
+
+fn main() {
+    let x = 5;
+    assert_eq!(run_fut(foo(&x, 7)), 31);
+    assert_eq!(run_fut(build_aggregate(1, 2, 3, 4)), 10);
+    assert_eq!(run_fut(includes_never(false, 4)), 16);
+    assert_eq!(run_fut(partial_init(4)), 8);
+    run_fut(hello_world());
+}
diff --git a/src/test/ui/generator/partial-drop.rs b/src/test/ui/generator/partial-drop.rs
index 36f6e78cb3b..e89e4b61bbf 100644
--- a/src/test/ui/generator/partial-drop.rs
+++ b/src/test/ui/generator/partial-drop.rs
@@ -1,3 +1,7 @@
+// FIXME(eholk): temporarily disabled while drop range tracking is disabled
+// (see generator_interior.rs:27)
+// ignore-test
+
 #![feature(negative_impls, generators)]
 
 struct Foo;
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 2b9bcb1bf8a..2f7faf520d9 100644
--- a/src/test/ui/generator/print/generator-print-verbose-1.stderr
+++ b/src/test/ui/generator/print/generator-print-verbose-1.stderr
@@ -9,7 +9,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[HASH]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
+   |             ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[749a]::make_non_send_generator::{opaque#0}), [])` which is not `Send`
 LL |         yield;
    |         ^^^^^ yield occurs here, with `_non_send_gen` maybe used later
 LL |     };
@@ -29,10 +29,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[HASH]::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[HASH]::make_non_send_generator2::{opaque#0}), [])`
-   = note: required because it appears within the type `{Opaque(DefId(0:42 ~ generator_print_verbose_1[HASH]::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[HASH]::make_non_send_generator2::{opaque#0}), []), ()}]`
+   = note: required because it appears within the type `Opaque(DefId(0:39 ~ generator_print_verbose_1[749a]::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[749a]::make_non_send_generator2::{opaque#0}), [])`
+   = note: required because it appears within the type `{Opaque(DefId(0:42 ~ generator_print_verbose_1[749a]::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[749a]::make_non_send_generator2::{opaque#0}), []), ()}]`
 note: required by a bound in `require_send`
   --> $DIR/generator-print-verbose-1.rs:26:25
    |
diff --git a/src/test/ui/generic-associated-types/elided-in-expr-position.rs b/src/test/ui/generic-associated-types/elided-in-expr-position.rs
new file mode 100644
index 00000000000..482d0d5c00a
--- /dev/null
+++ b/src/test/ui/generic-associated-types/elided-in-expr-position.rs
@@ -0,0 +1,38 @@
+#![feature(generic_associated_types)]
+#![allow(unused)]
+
+pub trait Trait  {
+    type Assoc<'a> where Self: 'a;
+
+    fn f(&self) -> Self::Assoc<'_>;
+
+    // Disallow elision in return position, for now
+    fn g(&self) -> Self::Assoc;
+    //~^ ERROR missing generics for associated type `Trait::Assoc`
+}
+
+pub struct Struct {
+    item: f32
+}
+
+pub struct GenericStruct<'a> {
+    ref_item: &'a f32
+}
+
+impl Trait for Struct {
+    type Assoc<'a> = GenericStruct<'a>;
+
+    fn f(&self) -> Self::Assoc<'_> {
+        Self::Assoc {
+            ref_item: &self.item
+        }
+    }
+
+    // Disallow elision in return position, for now
+    fn g(&self) -> Self::Assoc {
+    //~^ ERROR missing generics for associated type `Trait::Assoc`
+        todo!()
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/elided-in-expr-position.stderr b/src/test/ui/generic-associated-types/elided-in-expr-position.stderr
new file mode 100644
index 00000000000..9263f3d67e3
--- /dev/null
+++ b/src/test/ui/generic-associated-types/elided-in-expr-position.stderr
@@ -0,0 +1,35 @@
+error[E0107]: missing generics for associated type `Trait::Assoc`
+  --> $DIR/elided-in-expr-position.rs:10:26
+   |
+LL |     fn g(&self) -> Self::Assoc;
+   |                          ^^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/elided-in-expr-position.rs:5:10
+   |
+LL |     type Assoc<'a> where Self: 'a;
+   |          ^^^^^ --
+help: add missing lifetime argument
+   |
+LL |     fn g(&self) -> Self::Assoc<'_>;
+   |                          ~~~~~~~~~
+
+error[E0107]: missing generics for associated type `Trait::Assoc`
+  --> $DIR/elided-in-expr-position.rs:32:26
+   |
+LL |     fn g(&self) -> Self::Assoc {
+   |                          ^^^^^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/elided-in-expr-position.rs:5:10
+   |
+LL |     type Assoc<'a> where Self: 'a;
+   |          ^^^^^ --
+help: add missing lifetime argument
+   |
+LL |     fn g(&self) -> Self::Assoc<'_> {
+   |                          ~~~~~~~~~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/src/test/ui/generic-associated-types/issue-92954.rs b/src/test/ui/generic-associated-types/issue-92954.rs
new file mode 100644
index 00000000000..95c090ff4e9
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-92954.rs
@@ -0,0 +1,10 @@
+// check-pass
+
+#![feature(generic_associated_types)]
+
+pub trait Foo {
+    type Assoc<'c>;
+    fn function() -> for<'x> fn(Self::Assoc<'x>);
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-93141.rs b/src/test/ui/generic-associated-types/issue-93141.rs
new file mode 100644
index 00000000000..39ca77d13db
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-93141.rs
@@ -0,0 +1,25 @@
+// check-pass
+
+#![feature(generic_associated_types)]
+
+pub trait Fooey: Sized {
+    type Context<'c> where Self: 'c;
+}
+
+pub struct Handle<E: Fooey>(Option<Box<dyn for<'c> Fn(&mut E::Context<'c>)>>);
+
+fn tuple<T>() -> (Option<T>,) { (Option::None,) }
+
+pub struct FooImpl {}
+impl Fooey for FooImpl {
+    type Context<'c> = &'c ();
+}
+
+impl FooImpl {
+    pub fn fail1() -> Handle<Self> {
+        let (tx,) = tuple();
+        Handle(tx)
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/generic-associated-types/issue-93340.rs b/src/test/ui/generic-associated-types/issue-93340.rs
new file mode 100644
index 00000000000..d065bde88c4
--- /dev/null
+++ b/src/test/ui/generic-associated-types/issue-93340.rs
@@ -0,0 +1,20 @@
+// check-pass
+
+#![feature(generic_associated_types)]
+
+pub trait Scalar: 'static {
+    type RefType<'a>: ScalarRef<'a>;
+}
+
+pub trait ScalarRef<'a>: 'a {}
+
+fn cmp_eq<'a, 'b, A: Scalar, B: Scalar, O: Scalar>(a: A::RefType<'a>, b: B::RefType<'b>) -> O {
+    todo!()
+}
+
+fn build_expression<A: Scalar, B: Scalar, O: Scalar>(
+) -> impl Fn(A::RefType<'_>, B::RefType<'_>) -> O {
+    cmp_eq
+}
+
+fn main() {}
diff --git a/src/test/ui/intrinsics/const-eval-select-bad.rs b/src/test/ui/intrinsics/const-eval-select-bad.rs
index a3171187e69..7d924e2b7f3 100644
--- a/src/test/ui/intrinsics/const-eval-select-bad.rs
+++ b/src/test/ui/intrinsics/const-eval-select-bad.rs
@@ -4,9 +4,9 @@ use std::intrinsics::const_eval_select;
 
 const fn not_fn_items() {
     const_eval_select((), || {}, || {});
-    //~^ ERROR expected a `FnOnce<()>` closure
+    //~^ ERROR the trait bound
     const_eval_select((), 42, 0xDEADBEEF);
-    //~^ ERROR expected a `FnOnce<()>` closure
+    //~^ ERROR the trait bound
     //~| ERROR expected a `FnOnce<()>` closure
 }
 
diff --git a/src/test/ui/intrinsics/const-eval-select-bad.stderr b/src/test/ui/intrinsics/const-eval-select-bad.stderr
index 5e1ab584d80..06a7a2f63cf 100644
--- a/src/test/ui/intrinsics/const-eval-select-bad.stderr
+++ b/src/test/ui/intrinsics/const-eval-select-bad.stderr
@@ -1,4 +1,4 @@
-error[E0277]: expected a `FnOnce<()>` closure, found `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`
+error[E0277]: the trait bound `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]: ~const FnOnce<()>` is not satisfied
   --> $DIR/const-eval-select-bad.rs:6:27
    |
 LL |     const_eval_select((), || {}, || {});
@@ -6,7 +6,12 @@ LL |     const_eval_select((), || {}, || {});
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `FnOnce<()>` is not implemented for `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`
+   = help: the trait `~const FnOnce<()>` is not implemented for `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`
+note: the trait `FnOnce<()>` is implemented for `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]`, but that implementation is not `const`
+  --> $DIR/const-eval-select-bad.rs:6:27
+   |
+LL |     const_eval_select((), || {}, || {});
+   |                           ^^^^^
    = note: wrap the `[closure@$DIR/const-eval-select-bad.rs:6:27: 6:32]` in a closure with no arguments: `|| { /* code */ }`
 note: required by a bound in `const_eval_select`
   --> $SRC_DIR/core/src/intrinsics.rs:LL:COL
@@ -14,7 +19,7 @@ note: required by a bound in `const_eval_select`
 LL |     F: ~const FnOnce<ARG, Output = RET>,
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `const_eval_select`
 
-error[E0277]: expected a `FnOnce<()>` closure, found `{integer}`
+error[E0277]: the trait bound `{integer}: ~const FnOnce<()>` is not satisfied
   --> $DIR/const-eval-select-bad.rs:8:27
    |
 LL |     const_eval_select((), 42, 0xDEADBEEF);
@@ -22,7 +27,7 @@ LL |     const_eval_select((), 42, 0xDEADBEEF);
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `FnOnce<()>` is not implemented for `{integer}`
+   = help: the trait `~const FnOnce<()>` is not implemented for `{integer}`
    = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }`
 note: required by a bound in `const_eval_select`
   --> $SRC_DIR/core/src/intrinsics.rs:LL:COL
diff --git a/src/test/ui/issues/issue-16683.nll.stderr b/src/test/ui/issues/issue-16683.nll.stderr
index 0e8f520353f..fff681b2e0b 100644
--- a/src/test/ui/issues/issue-16683.nll.stderr
+++ b/src/test/ui/issues/issue-16683.nll.stderr
@@ -1,20 +1,13 @@
-error[E0521]: borrowed data escapes outside of associated function
+error: lifetime may not live long enough
   --> $DIR/issue-16683.rs:4:9
    |
 LL | trait T<'a> {
    |         -- lifetime `'a` defined here
 LL |     fn a(&'a self) -> &'a bool;
 LL |     fn b(&self) {
-   |          -----
-   |          |
-   |          `self` is a reference that is only valid in the associated function body
-   |          let's call the lifetime of this reference `'1`
+   |          - let's call the lifetime of this reference `'1`
 LL |         self.a();
-   |         ^^^^^^^^
-   |         |
-   |         `self` escapes the associated function body here
-   |         argument requires that `'1` must outlive `'a`
+   |         ^^^^^^^^ argument requires that `'1` must outlive `'a`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0521`.
diff --git a/src/test/ui/issues/issue-17758.nll.stderr b/src/test/ui/issues/issue-17758.nll.stderr
index b929fdbf368..613ef6b907c 100644
--- a/src/test/ui/issues/issue-17758.nll.stderr
+++ b/src/test/ui/issues/issue-17758.nll.stderr
@@ -1,20 +1,13 @@
-error[E0521]: borrowed data escapes outside of associated function
+error: lifetime may not live long enough
   --> $DIR/issue-17758.rs:7:9
    |
 LL | trait Foo<'a> {
    |           -- lifetime `'a` defined here
 LL |     fn foo(&'a self);
 LL |     fn bar(&self) {
-   |            -----
-   |            |
-   |            `self` is a reference that is only valid in the associated function body
-   |            let's call the lifetime of this reference `'1`
+   |            - let's call the lifetime of this reference `'1`
 LL |         self.foo();
-   |         ^^^^^^^^^^
-   |         |
-   |         `self` escapes the associated function body here
-   |         argument requires that `'1` must outlive `'a`
+   |         ^^^^^^^^^^ argument requires that `'1` must outlive `'a`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0521`.
diff --git a/src/test/ui/issues/issue-47377.stderr b/src/test/ui/issues/issue-47377.stderr
index a7b8b1ca861..4f0fd948e76 100644
--- a/src/test/ui/issues/issue-47377.stderr
+++ b/src/test/ui/issues/issue-47377.stderr
@@ -7,10 +7,11 @@ LL |      let _a = b + ", World!";
    |               | `+` cannot be used to concatenate two `&str` strings
    |               &str
    |
-help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+   = note: string concatenation requires an owned `String` on the left
+help: create an owned `String` from a string reference
    |
 LL |      let _a = b.to_owned() + ", World!";
-   |               ~~~~~~~~~~~~
+   |                +++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-47380.stderr b/src/test/ui/issues/issue-47380.stderr
index f6222c77e2e..b04ac5536c4 100644
--- a/src/test/ui/issues/issue-47380.stderr
+++ b/src/test/ui/issues/issue-47380.stderr
@@ -7,10 +7,11 @@ LL |     println!("🦀🦀🦀🦀🦀"); let _a = b + ", World!";
    |                                      | `+` cannot be used to concatenate two `&str` strings
    |                                      &str
    |
-help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+   = note: string concatenation requires an owned `String` on the left
+help: create an owned `String` from a string reference
    |
 LL |     println!("🦀🦀🦀🦀🦀"); let _a = b.to_owned() + ", World!";
-   |                                      ~~~~~~~~~~~~
+   |                                       +++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-5100.stderr b/src/test/ui/issues/issue-5100.stderr
index de71e1d1a66..c87a3e348a2 100644
--- a/src/test/ui/issues/issue-5100.stderr
+++ b/src/test/ui/issues/issue-5100.stderr
@@ -59,10 +59,8 @@ LL |         &(true, false) => ()
 error[E0618]: expected function, found `(char, char)`
   --> $DIR/issue-5100.rs:48:14
    |
-LL |       let v = [('a', 'b')
-   |  ______________-^^^^^^^^^
-LL | |              ('c', 'd'),
-   | |_______________________- call expression requires function
+LL |     let v = [('a', 'b')
+   |              ^^^^^^^^^^- help: consider separating array elements with a comma: `,`
 
 error[E0308]: mismatched types
   --> $DIR/issue-5100.rs:55:19
diff --git a/src/test/ui/issues/issue-52213.nll.stderr b/src/test/ui/issues/issue-52213.nll.stderr
index 359f91309d4..da31bcd5475 100644
--- a/src/test/ui/issues/issue-52213.nll.stderr
+++ b/src/test/ui/issues/issue-52213.nll.stderr
@@ -7,7 +7,7 @@ LL | fn transmute_lifetime<'a, 'b, T>(t: &'a (T,)) -> &'b T {
    |                       lifetime `'a` defined here
 LL |     match (&t,) {
 LL |         ((u,),) => u,
-   |                    ^ returning this value requires that `'a` must outlive `'b`
+   |                    ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
diff --git a/src/test/ui/issues/issue-69455.stderr b/src/test/ui/issues/issue-69455.stderr
index 95617e4ecc8..378fdc97dd3 100644
--- a/src/test/ui/issues/issue-69455.stderr
+++ b/src/test/ui/issues/issue-69455.stderr
@@ -1,14 +1,14 @@
 error[E0282]: type annotations needed
-  --> $DIR/issue-69455.rs:29:5
+  --> $DIR/issue-69455.rs:29:20
    |
 LL |     type Output;
    |     ------------ `<Self as Test<Rhs>>::Output` defined here
 ...
 LL |     println!("{}", 23u64.test(xs.iter().sum()));
-   |     ^^^^^^^^^^^^^^^---------------------------^
-   |     |              |
-   |     |              this method call resolves to `<Self as Test<Rhs>>::Output`
-   |     cannot infer type for type parameter `T` declared on the associated function `new`
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                    |
+   |                    this method call resolves to `<Self as Test<Rhs>>::Output`
+   |                    cannot infer type for type parameter `T` declared on the associated function `new_display`
    |
    = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/src/test/ui/lint/lint-unconditional-recursion.rs b/src/test/ui/lint/lint-unconditional-recursion.rs
index d2a0329585b..ad052d36f20 100644
--- a/src/test/ui/lint/lint-unconditional-recursion.rs
+++ b/src/test/ui/lint/lint-unconditional-recursion.rs
@@ -149,4 +149,46 @@ pub fn panics(x: bool) {
     }
 }
 
+pub fn unreachable1() {
+    panic!();
+    unreachable1(); // WARN unreachable statement
+}
+
+pub fn unreachable2() {
+    loop {}
+    unreachable2(); // WARN unreachable statement
+}
+
+pub fn drop_and_replace(mut a: Option<String>) { //~ ERROR function cannot return without recursing
+    a = None;
+    drop_and_replace(a);
+}
+
+// Calls are assumed to return normally.
+pub fn call() -> String { //~ ERROR function cannot return without recursing
+    let s = String::new();
+    call();
+    s
+}
+
+// Arithmetic operations are assumed not to overflow.
+pub fn overflow_check(a: i32, b: i32) { //~ ERROR function cannot return without recursing
+    let _ = a + b;
+    overflow_check(a, b);
+}
+
+pub struct Point {
+    pub x: f32,
+    pub y: f32,
+}
+
+impl Default for Point {
+    fn default() -> Self { //~ ERROR function cannot return without recursing
+        Point {
+            x: Default::default(),
+            ..Default::default()
+        }
+    }
+}
+
 fn main() {}
diff --git a/src/test/ui/lint/lint-unconditional-recursion.stderr b/src/test/ui/lint/lint-unconditional-recursion.stderr
index fb884e31299..c11b73f41ca 100644
--- a/src/test/ui/lint/lint-unconditional-recursion.stderr
+++ b/src/test/ui/lint/lint-unconditional-recursion.stderr
@@ -153,5 +153,49 @@ LL |         self.as_ref()
    |
    = help: a `loop` may express intention better if this is on purpose
 
-error: aborting due to 14 previous errors
+error: function cannot return without recursing
+  --> $DIR/lint-unconditional-recursion.rs:162:1
+   |
+LL | pub fn drop_and_replace(mut a: Option<String>) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |     a = None;
+LL |     drop_and_replace(a);
+   |     ------------------- recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+
+error: function cannot return without recursing
+  --> $DIR/lint-unconditional-recursion.rs:168:1
+   |
+LL | pub fn call() -> String {
+   | ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |     let s = String::new();
+LL |     call();
+   |     ------ recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+
+error: function cannot return without recursing
+  --> $DIR/lint-unconditional-recursion.rs:175:1
+   |
+LL | pub fn overflow_check(a: i32, b: i32) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |     let _ = a + b;
+LL |     overflow_check(a, b);
+   |     -------------------- recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+
+error: function cannot return without recursing
+  --> $DIR/lint-unconditional-recursion.rs:186:5
+   |
+LL |     fn default() -> Self {
+   |     ^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+...
+LL |             ..Default::default()
+   |               ------------------ recursive call site
+   |
+   = help: a `loop` may express intention better if this is on purpose
+
+error: aborting due to 18 previous errors
 
diff --git a/src/test/ui/match/issue-82392.stdout b/src/test/ui/match/issue-82392.stdout
index 4f46e32dc30..2054d43c409 100644
--- a/src/test/ui/match/issue-82392.stdout
+++ b/src/test/ui/match/issue-82392.stdout
@@ -7,13 +7,11 @@ extern crate std;
 // check-pass
 
 pub fn main() ({
-                   (if (true as bool)
-                       ({ } as
-                           ()) else if (let Some(a) =
-                                           ((Some as
-                                                fn(i32) -> Option<i32> {Option::<i32>::Some})((3
-                                                                                                  as
-                                                                                                  i32))
-                                               as Option<i32>) as bool)
-                              ({ } as ()) as ())
-                             } as ())
+        (if (true as bool)
+                ({ } as
+                    ()) else if (let Some(a) =
+                       ((Some as
+                               fn(i32) -> Option<i32> {Option::<i32>::Some})((3
+                               as i32)) as Option<i32>) as bool) ({ } as ())
+                   as ())
+               } as ())
diff --git a/src/test/ui/match/match-ref-mut-invariance.nll.stderr b/src/test/ui/match/match-ref-mut-invariance.nll.stderr
index 1dc29d2088c..c8a7876dc54 100644
--- a/src/test/ui/match/match-ref-mut-invariance.nll.stderr
+++ b/src/test/ui/match/match-ref-mut-invariance.nll.stderr
@@ -6,7 +6,7 @@ LL | impl<'b> S<'b> {
 LL |     fn bar<'a>(&'a mut self) -> &'a mut &'a i32 {
    |            -- lifetime `'a` defined here
 LL |         match self.0 { ref mut x => x }
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b`
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
    = note: requirement occurs because of a mutable reference to &i32
diff --git a/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr b/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr
index 8b87c3da28b..11ddf1487dd 100644
--- a/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr
+++ b/src/test/ui/match/match-ref-mut-let-invariance.nll.stderr
@@ -7,7 +7,7 @@ LL |     fn bar<'a>(&'a mut self) -> &'a mut &'a i32 {
    |            -- lifetime `'a` defined here
 LL |         let ref mut x = self.0;
 LL |         x
-   |         ^ returning this value requires that `'a` must outlive `'b`
+   |         ^ associated function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
    = note: requirement occurs because of a mutable reference to &i32
diff --git a/src/test/ui/mismatched_types/overloaded-calls-bad.rs b/src/test/ui/mismatched_types/overloaded-calls-bad.rs
index 902a6ec81d6..d62625faaaa 100644
--- a/src/test/ui/mismatched_types/overloaded-calls-bad.rs
+++ b/src/test/ui/mismatched_types/overloaded-calls-bad.rs
@@ -30,4 +30,5 @@ fn main() {
     //~^ ERROR this function takes 1 argument but 0 arguments were supplied
     let ans = s("burma", "shave");
     //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+    //~| ERROR mismatched types
 }
diff --git a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr
index 264d7cbb9b1..9ae9c474162 100644
--- a/src/test/ui/mismatched_types/overloaded-calls-bad.stderr
+++ b/src/test/ui/mismatched_types/overloaded-calls-bad.stderr
@@ -18,6 +18,12 @@ note: associated function defined here
 LL |     extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
    |                           ^^^^^^^^
 
+error[E0308]: mismatched types
+  --> $DIR/overloaded-calls-bad.rs:31:17
+   |
+LL |     let ans = s("burma", "shave");
+   |                 ^^^^^^^ expected `isize`, found `&str`
+
 error[E0057]: this function takes 1 argument but 2 arguments were supplied
   --> $DIR/overloaded-calls-bad.rs:31:15
    |
@@ -32,7 +38,7 @@ note: associated function defined here
 LL |     extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
    |                           ^^^^^^^^
 
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0057, E0308.
 For more information about an error, try `rustc --explain E0057`.
diff --git a/src/test/ui/nll/issue-52113.stderr b/src/test/ui/nll/issue-52113.stderr
index dcf03386734..f70ae2edd7f 100644
--- a/src/test/ui/nll/issue-52113.stderr
+++ b/src/test/ui/nll/issue-52113.stderr
@@ -7,7 +7,7 @@ LL | fn produce_err<'a, 'b: 'a>(data: &'b mut Vec<&'b u32>, value: &'a u32) -> i
    |                lifetime `'a` defined here
 ...
 LL |     x
-   |     ^ returning this value requires that `'a` must outlive `'b`
+   |     ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
diff --git a/src/test/ui/nll/issue-55394.nll.stderr b/src/test/ui/nll/issue-55394.nll.stderr
index d0723047ac0..24b8c84b4a9 100644
--- a/src/test/ui/nll/issue-55394.nll.stderr
+++ b/src/test/ui/nll/issue-55394.nll.stderr
@@ -6,7 +6,7 @@ LL |     fn new(bar: &mut Bar) -> Self {
    |                 |
    |                 let's call the lifetime of this reference `'1`
 LL |         Foo { bar }
-   |         ^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
+   |         ^^^^^^^^^^^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/issue-67007-escaping-data.rs b/src/test/ui/nll/issue-67007-escaping-data.rs
index 8c21737e05f..99b6d512261 100644
--- a/src/test/ui/nll/issue-67007-escaping-data.rs
+++ b/src/test/ui/nll/issue-67007-escaping-data.rs
@@ -14,7 +14,7 @@ struct Consumer<'tcx>(&'tcx ());
 
 impl<'tcx> Consumer<'tcx> {
     fn bad_method<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) {
-        let other = self.use_fcx(fcx); //~ ERROR borrowed data
+        let other = self.use_fcx(fcx); //~ ERROR lifetime may not live long enough
         fcx.use_it(other);
     }
 
diff --git a/src/test/ui/nll/issue-67007-escaping-data.stderr b/src/test/ui/nll/issue-67007-escaping-data.stderr
index 2834d6fb0d2..ce067e23aa3 100644
--- a/src/test/ui/nll/issue-67007-escaping-data.stderr
+++ b/src/test/ui/nll/issue-67007-escaping-data.stderr
@@ -1,21 +1,14 @@
-error[E0521]: borrowed data escapes outside of associated function
+error: lifetime may not live long enough
   --> $DIR/issue-67007-escaping-data.rs:17:21
    |
 LL | impl<'tcx> Consumer<'tcx> {
    |      ---- lifetime `'tcx` defined here
 LL |     fn bad_method<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) {
-   |                   --  -----  --- `fcx` is a reference that is only valid in the associated function body
-   |                   |   |
-   |                   |   `self` declared here, outside of the associated function body
-   |                   lifetime `'a` defined here
+   |                   -- lifetime `'a` defined here
 LL |         let other = self.use_fcx(fcx);
-   |                     ^^^^^^^^^^^^^^^^^
-   |                     |
-   |                     `fcx` escapes the associated function body here
-   |                     argument requires that `'a` must outlive `'tcx`
+   |                     ^^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'tcx`
    |
    = help: consider adding the following bound: `'a: 'tcx`
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0521`.
diff --git a/src/test/ui/nll/mir_check_cast_closure.stderr b/src/test/ui/nll/mir_check_cast_closure.stderr
index 113e220e513..f34cafe308d 100644
--- a/src/test/ui/nll/mir_check_cast_closure.stderr
+++ b/src/test/ui/nll/mir_check_cast_closure.stderr
@@ -7,7 +7,7 @@ LL | fn bar<'a, 'b>() -> fn(&'a u32, &'b u32) -> &'a u32 {
    |        lifetime `'a` defined here
 LL |     let g: fn(_, _) -> _ = |_x, y| y;
 LL |     g
-   |     ^ returning this value requires that `'b` must outlive `'a`
+   |     ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'a`
 
diff --git a/src/test/ui/nll/outlives-suggestion-more.stderr b/src/test/ui/nll/outlives-suggestion-more.stderr
index a80e59d4822..7f98aa5801d 100644
--- a/src/test/ui/nll/outlives-suggestion-more.stderr
+++ b/src/test/ui/nll/outlives-suggestion-more.stderr
@@ -6,7 +6,7 @@ LL | fn foo1<'a, 'b, 'c, 'd>(x: &'a usize, y: &'b usize) -> (&'c usize, &'d usiz
    |         |
    |         lifetime `'a` defined here
 LL |     (x, y)
-   |     ^^^^^^ returning this value requires that `'a` must outlive `'c`
+   |     ^^^^^^ function was supposed to return data with lifetime `'c` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'c`
 
@@ -18,7 +18,7 @@ LL | fn foo1<'a, 'b, 'c, 'd>(x: &'a usize, y: &'b usize) -> (&'c usize, &'d usiz
    |             |
    |             lifetime `'b` defined here
 LL |     (x, y)
-   |     ^^^^^^ returning this value requires that `'b` must outlive `'d`
+   |     ^^^^^^ function was supposed to return data with lifetime `'d` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'd`
 
@@ -35,7 +35,7 @@ LL | fn foo2<'a, 'b, 'c>(x: &'a usize, y: &'b usize) -> (&'c usize, &'static usi
    |         |
    |         lifetime `'a` defined here
 LL |     (x, y)
-   |     ^^^^^^ returning this value requires that `'a` must outlive `'c`
+   |     ^^^^^^ function was supposed to return data with lifetime `'c` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'c`
 
diff --git a/src/test/ui/nll/outlives-suggestion-simple.rs b/src/test/ui/nll/outlives-suggestion-simple.rs
index 41e4d83aa92..496cf92400c 100644
--- a/src/test/ui/nll/outlives-suggestion-simple.rs
+++ b/src/test/ui/nll/outlives-suggestion-simple.rs
@@ -70,7 +70,7 @@ pub struct Foo2<'a> {
 impl<'a> Foo2<'a> {
     // should not produce outlives suggestions to name 'self
     fn get_bar(&self) -> Bar2 {
-        Bar2::new(&self) //~ERROR borrowed data escapes outside of associated function
+        Bar2::new(&self) //~ERROR lifetime may not live long enough
     }
 }
 
diff --git a/src/test/ui/nll/outlives-suggestion-simple.stderr b/src/test/ui/nll/outlives-suggestion-simple.stderr
index 3b2017d2d03..8e6e4f1a476 100644
--- a/src/test/ui/nll/outlives-suggestion-simple.stderr
+++ b/src/test/ui/nll/outlives-suggestion-simple.stderr
@@ -6,7 +6,7 @@ LL | fn foo1<'a, 'b>(x: &'a usize) -> &'b usize {
    |         |
    |         lifetime `'a` defined here
 LL |     x
-   |     ^ returning this value requires that `'a` must outlive `'b`
+   |     ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
@@ -53,7 +53,7 @@ LL | fn foo4<'a, 'b, 'c>(x: &'a usize) -> (&'b usize, &'c usize) {
    |         lifetime `'a` defined here
 ...
 LL |     (x, x)
-   |     ^^^^^^ returning this value requires that `'a` must outlive `'b`
+   |     ^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
@@ -73,7 +73,7 @@ LL | impl<'a> Bar<'a> {
 LL |     pub fn get<'b>(&self) -> &'b usize {
    |                -- lifetime `'b` defined here
 LL |         self.x
-   |         ^^^^^^ returning this value requires that `'a` must outlive `'b`
+   |         ^^^^^^ associated function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
@@ -85,28 +85,20 @@ LL | impl<'a> Baz<'a> {
 LL |     fn get<'b>(&'b self) -> &'a i32 {
    |            -- lifetime `'b` defined here
 LL |         self.x
-   |         ^^^^^^ returning this value requires that `'b` must outlive `'a`
+   |         ^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'a`
 
-error[E0521]: borrowed data escapes outside of associated function
+error: lifetime may not live long enough
   --> $DIR/outlives-suggestion-simple.rs:73:9
    |
 LL | impl<'a> Foo2<'a> {
    |      -- lifetime `'a` defined here
 LL |     // should not produce outlives suggestions to name 'self
 LL |     fn get_bar(&self) -> Bar2 {
-   |                -----
-   |                |
-   |                `self` declared here, outside of the associated function body
-   |                `self` is a reference that is only valid in the associated function body
-   |                let's call the lifetime of this reference `'1`
+   |                - let's call the lifetime of this reference `'1`
 LL |         Bar2::new(&self)
-   |         ^^^^^^^^^^^^^^^^
-   |         |
-   |         `self` escapes the associated function body here
-   |         argument requires that `'1` must outlive `'a`
+   |         ^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'a`
 
 error: aborting due to 9 previous errors
 
-For more information about this error, try `rustc --explain E0521`.
diff --git a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
index 5e56e12eda0..3e6fe789a8b 100644
--- a/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
+++ b/src/test/ui/nll/ty-outlives/impl-trait-captures.stderr
@@ -4,11 +4,11 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea
 LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> {
    |                  --     ^^^^^^^^^^^^
    |                  |
-   |                  hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[HASH]::foo), BrAnon(0)) T` captures the anonymous lifetime defined here
+   |                  hidden type `&ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0)) T` captures the anonymous lifetime defined here
    |
-help: to declare that the `impl Trait` captures `ReFree(DefId(0:8 ~ impl_trait_captures[HASH]::foo), BrAnon(0))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[HASH]::foo), BrAnon(0))` lifetime bound
+help: to declare that the `impl Trait` captures `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0))`, you can add an explicit `ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0))` lifetime bound
    |
-LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[HASH]::foo), BrAnon(0)) {
+LL | fn foo<'a, T>(x: &T) -> impl Foo<'a> + ReFree(DefId(0:8 ~ impl_trait_captures[1afc]::foo), BrAnon(0)) {
    |                                      ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 error: aborting due to previous error
diff --git a/src/test/ui/nll/type-alias-free-regions.nll.stderr b/src/test/ui/nll/type-alias-free-regions.nll.stderr
index bde73b05894..45fd5a2f1d6 100644
--- a/src/test/ui/nll/type-alias-free-regions.nll.stderr
+++ b/src/test/ui/nll/type-alias-free-regions.nll.stderr
@@ -6,7 +6,7 @@ LL | impl<'a> FromBox<'a> for C<'a> {
 LL |     fn from_box(b: Box<B>) -> Self {
    |                 - has type `Box<Box<&'1 isize>>`
 LL |         C { f: b }
-   |         ^^^^^^^^^^ returning this value requires that `'1` must outlive `'a`
+   |         ^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
 
 error: lifetime may not live long enough
   --> $DIR/type-alias-free-regions.rs:27:9
@@ -16,7 +16,7 @@ LL | impl<'a> FromTuple<'a> for C<'a> {
 LL |     fn from_tuple(b: (B,)) -> Self {
    |                   - has type `(Box<&'1 isize>,)`
 LL |         C { f: Box::new(b.0) }
-   |         ^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'a`
+   |         ^^^^^^^^^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/nll/type-check-pointer-coercions.stderr b/src/test/ui/nll/type-check-pointer-coercions.stderr
index ccb3d33ac40..b392c2007d3 100644
--- a/src/test/ui/nll/type-check-pointer-coercions.stderr
+++ b/src/test/ui/nll/type-check-pointer-coercions.stderr
@@ -6,7 +6,7 @@ LL | fn shared_to_const<'a, 'b>(x: &&'a i32) -> *const &'b i32 {
    |                    |
    |                    lifetime `'a` defined here
 LL |     x
-   |     ^ returning this value requires that `'a` must outlive `'b`
+   |     ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
@@ -18,7 +18,7 @@ LL | fn unique_to_const<'a, 'b>(x: &mut &'a i32) -> *const &'b i32 {
    |                    |
    |                    lifetime `'a` defined here
 LL |     x
-   |     ^ returning this value requires that `'a` must outlive `'b`
+   |     ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
@@ -47,7 +47,7 @@ LL | fn unique_to_mut<'a, 'b>(x: &mut &'a i32) -> *mut &'b i32 {
    |                  lifetime `'a` defined here
 LL |     // Two errors because *mut is invariant
 LL |     x
-   |     ^ returning this value requires that `'a` must outlive `'b`
+   |     ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
    = note: requirement occurs because of a mutable pointer to &i32
@@ -64,7 +64,7 @@ LL | fn mut_to_const<'a, 'b>(x: *mut &'a i32) -> *const &'b i32 {
    |                 |
    |                 lifetime `'a` defined here
 LL |     x
-   |     ^ returning this value requires that `'a` must outlive `'b`
+   |     ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
@@ -77,7 +77,7 @@ LL | fn array_elem<'a, 'b>(x: &'a i32) -> *const &'b i32 {
    |               lifetime `'a` defined here
 ...
 LL |     y
-   |     ^ returning this value requires that `'a` must outlive `'b`
+   |     ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
@@ -90,7 +90,7 @@ LL | fn array_coerce<'a, 'b>(x: &'a i32) -> *const [&'b i32; 3] {
    |                 lifetime `'a` defined here
 ...
 LL |     y
-   |     ^ returning this value requires that `'a` must outlive `'b`
+   |     ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
@@ -103,7 +103,7 @@ LL | fn nested_array<'a, 'b>(x: &'a i32) -> *const [&'b i32; 2] {
    |                 lifetime `'a` defined here
 ...
 LL |     y
-   |     ^ returning this value requires that `'a` must outlive `'b`
+   |     ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
diff --git a/src/test/ui/nll/user-annotations/wf-self-type.stderr b/src/test/ui/nll/user-annotations/wf-self-type.stderr
index 33bb1c519b1..902b4c68755 100644
--- a/src/test/ui/nll/user-annotations/wf-self-type.stderr
+++ b/src/test/ui/nll/user-annotations/wf-self-type.stderr
@@ -6,7 +6,7 @@ LL | pub fn foo<'a, 'b>(u: &'b ()) -> &'a () {
    |            |
    |            lifetime `'a` defined here
 LL |     Foo::xmute(u)
-   |     ^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a`
+   |     ^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'a`
 
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr
index 900cdfca244..61e96f59fed 100644
--- a/src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr
+++ b/src/test/ui/object-lifetime/object-lifetime-default-elision.nll.stderr
@@ -7,7 +7,7 @@ LL | fn load3<'a,'b>(ss: &'a dyn SomeTrait) -> &'b dyn SomeTrait {
    |          lifetime `'a` defined here
 ...
 LL |     ss
-   |     ^^ returning this value requires that `'a` must outlive `'b`
+   |     ^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
diff --git a/src/test/ui/parser/issues/issue-93282.rs b/src/test/ui/parser/issues/issue-93282.rs
new file mode 100644
index 00000000000..7be8b25363e
--- /dev/null
+++ b/src/test/ui/parser/issues/issue-93282.rs
@@ -0,0 +1,4 @@
+fn main() {
+    f<'a,>
+    //~^ ERROR expected
+}
diff --git a/src/test/ui/parser/issues/issue-93282.stderr b/src/test/ui/parser/issues/issue-93282.stderr
new file mode 100644
index 00000000000..20e6c3ed8a8
--- /dev/null
+++ b/src/test/ui/parser/issues/issue-93282.stderr
@@ -0,0 +1,13 @@
+error: expected one of `.`, `:`, `;`, `?`, `for`, `loop`, `while`, `{`, `}`, or an operator, found `,`
+  --> $DIR/issue-93282.rs:2:9
+   |
+LL |     f<'a,>
+   |         ^ expected one of 10 possible tokens
+   |
+help: use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+   |
+LL |     f::<'a,>
+   |      ++
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/proc-macro/cfg-eval-inner.stdout b/src/test/ui/proc-macro/cfg-eval-inner.stdout
index debbad57a86..9d25def587c 100644
--- a/src/test/ui/proc-macro/cfg-eval-inner.stdout
+++ b/src/test/ui/proc-macro/cfg-eval-inner.stdout
@@ -1,9 +1,9 @@
 PRINT-ATTR INPUT (DISPLAY): impl Foo <
 [u8 ;
- {
-     #! [rustc_dummy(cursed_inner)] #! [allow(unused)] struct Inner
-     { field : [u8 ; { #! [rustc_dummy(another_cursed_inner)] 1 }] } 0
- }] > { #! [rustc_dummy(evaluated_attr)] fn bar() {} }
+{
+    #! [rustc_dummy(cursed_inner)] #! [allow(unused)] struct Inner
+    { field : [u8 ; { #! [rustc_dummy(another_cursed_inner)] 1 }] } 0
+}] > { #! [rustc_dummy(evaluated_attr)] fn bar() {} }
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "impl",
diff --git a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.rs b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.rs
index 113235051b2..0c1c51c01a8 100644
--- a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.rs
+++ b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.rs
@@ -4,7 +4,14 @@
 extern crate test_macros;
 
 #[derive(Print)]
-enum ProceduralMasqueradeDummyType { //~ ERROR using
+enum ProceduralMasqueradeDummyType {
+//~^ ERROR using
+//~| WARN this was previously
+//~| ERROR using
+//~| WARN this was previously
+//~| ERROR using
+//~| WARN this was previously
+//~| ERROR using
 //~| WARN this was previously
     Input
 }
diff --git a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stderr b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stderr
index dff71c9eacd..554613be65a 100644
--- a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stderr
+++ b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stderr
@@ -9,7 +9,37 @@ LL | enum ProceduralMasqueradeDummyType {
    = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling.
 
-error: aborting due to previous error
+error: using `procedural-masquerade` crate
+  --> $DIR/issue-73933-procedural-masquerade.rs:7:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
+   = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling.
+
+error: using `procedural-masquerade` crate
+  --> $DIR/issue-73933-procedural-masquerade.rs:7:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
+   = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling.
+
+error: using `procedural-masquerade` crate
+  --> $DIR/issue-73933-procedural-masquerade.rs:7:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
+   = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling.
+
+error: aborting due to 4 previous errors
 
 Future incompatibility report: Future breakage diagnostic:
 error: using `procedural-masquerade` crate
@@ -23,3 +53,36 @@ LL | enum ProceduralMasqueradeDummyType {
    = note: for more information, see issue #83125 <https://github.com/rust-lang/rust/issues/83125>
    = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling.
 
+Future breakage diagnostic:
+error: using `procedural-masquerade` crate
+  --> $DIR/issue-73933-procedural-masquerade.rs:7:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
+   = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling.
+
+Future breakage diagnostic:
+error: using `procedural-masquerade` crate
+  --> $DIR/issue-73933-procedural-masquerade.rs:7:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
+   = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling.
+
+Future breakage diagnostic:
+error: using `procedural-masquerade` crate
+  --> $DIR/issue-73933-procedural-masquerade.rs:7:6
+   |
+LL | enum ProceduralMasqueradeDummyType {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #83125 <https://github.com/rust-lang/rust/issues/83125>
+   = note: The `procedural-masquerade` crate has been unnecessary since Rust 1.30.0. Versions of this crate below 0.1.7 will eventually stop compiling.
+
diff --git a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stdout b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stdout
index 8a8fbf06824..50334589d0b 100644
--- a/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stdout
+++ b/src/test/ui/proc-macro/issue-73933-procedural-masquerade.stdout
@@ -14,9 +14,9 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
         stream: TokenStream [
             Ident {
                 ident: "Input",
-                span: #0 bytes(173..178),
+                span: #0 bytes(315..320),
             },
         ],
-        span: #0 bytes(121..180),
+        span: #0 bytes(121..322),
     },
 ]
diff --git a/src/test/ui/proc-macro/issue-75930-derive-cfg.stderr b/src/test/ui/proc-macro/issue-75930-derive-cfg.stderr
index 25f36108001..69d72b55cdf 100644
--- a/src/test/ui/proc-macro/issue-75930-derive-cfg.stderr
+++ b/src/test/ui/proc-macro/issue-75930-derive-cfg.stderr
@@ -11,5 +11,17 @@ LL | #[derive(Print)]
    = 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 #79202 <https://github.com/rust-lang/rust/issues/79202>
 
-warning: 1 warning emitted
+warning: derive helper attribute is used before it is introduced
+  --> $DIR/issue-75930-derive-cfg.rs:19:3
+   |
+LL | #[print_helper(a)]
+   |   ^^^^^^^^^^^^
+...
+LL | #[derive(Print)]
+   |          ----- the attribute is introduced here
+   |
+   = 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 #79202 <https://github.com/rust-lang/rust/issues/79202>
+
+warning: 2 warnings emitted
 
diff --git a/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout b/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout
index fdd178a5229..c81fa201cbc 100644
--- a/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout
+++ b/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout
@@ -4,23 +4,23 @@ struct Foo < #[cfg(FALSE)] A, B >
     #[cfg(FALSE)] first : String, #[cfg_attr(FALSE, deny(warnings))] second :
     bool, third :
     [u8 ;
-     {
-         #[cfg(FALSE)] struct Bar ; #[cfg(not(FALSE))] struct Inner ;
-         #[cfg(FALSE)] let a = 25 ; match true
-         {
-             #[cfg(FALSE)] true => {},
-             #[cfg_attr(not(FALSE), allow(warnings))] false => {}, _ => {}
-         } ; #[print_helper(should_be_removed)] fn removed_fn()
-         { #! [cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn
-         kept_fn() { #! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum
-         {
-             Foo(#[cfg(FALSE)] u8, #[cfg(FALSE)] bool, #[cfg(not(FALSE))] i32,
-                 #[cfg(FALSE)] String, u8)
-         } struct
-         TupleStruct(#[cfg(FALSE)] String, #[cfg(not(FALSE))] i32,
-                     #[cfg(FALSE)] bool, u8) ; fn plain_removed_fn()
-         { #! [cfg_attr(not(FALSE), cfg(FALSE))] } 0
-     }], #[print_helper(d)] fourth : B
+    {
+        #[cfg(FALSE)] struct Bar ; #[cfg(not(FALSE))] struct Inner ;
+        #[cfg(FALSE)] let a = 25 ; match true
+        {
+            #[cfg(FALSE)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))]
+            false => {}, _ => {}
+        } ; #[print_helper(should_be_removed)] fn removed_fn()
+        { #! [cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn()
+        { #! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum
+        {
+            Foo(#[cfg(FALSE)] u8, #[cfg(FALSE)] bool, #[cfg(not(FALSE))] i32,
+            #[cfg(FALSE)] String, u8)
+        } struct
+        TupleStruct(#[cfg(FALSE)] String, #[cfg(not(FALSE))] i32,
+        #[cfg(FALSE)] bool, u8) ; fn plain_removed_fn()
+        { #! [cfg_attr(not(FALSE), cfg(FALSE))] } 0
+    }], #[print_helper(d)] fourth : B
 }
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Punct {
@@ -1276,14 +1276,14 @@ PRINT-DERIVE INPUT (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[print_hel
 {
     second : bool, third :
     [u8 ;
-     {
-         #[cfg(not(FALSE))] struct Inner ; match true
-         { #[allow(warnings)] false => {}, _ => {} } ; #[print_helper(c)]
-         #[cfg(not(FALSE))] fn kept_fn()
-         { #! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum
-         { Foo(#[cfg(not(FALSE))] i32, u8) } struct
-         TupleStruct(#[cfg(not(FALSE))] i32, u8) ; 0
-     }], #[print_helper(d)] fourth : B
+    {
+        #[cfg(not(FALSE))] struct Inner ; match true
+        { #[allow(warnings)] false => {}, _ => {} } ; #[print_helper(c)]
+        #[cfg(not(FALSE))] fn kept_fn()
+        { #! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum
+        { Foo(#[cfg(not(FALSE))] i32, u8) } struct
+        TupleStruct(#[cfg(not(FALSE))] i32, u8) ; 0
+    }], #[print_helper(d)] fourth : B
 }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Punct {
diff --git a/src/test/ui/proc-macro/macro-rules-derive-cfg.stdout b/src/test/ui/proc-macro/macro-rules-derive-cfg.stdout
index 6e2b6a2e5bd..74641058ef3 100644
--- a/src/test/ui/proc-macro/macro-rules-derive-cfg.stdout
+++ b/src/test/ui/proc-macro/macro-rules-derive-cfg.stdout
@@ -2,10 +2,10 @@ PRINT-DERIVE INPUT (DISPLAY): struct Foo
 {
     val :
     [bool ;
-     {
-         let a = #[rustc_dummy(first)] #[rustc_dummy(second)]
-         { #! [allow(unused)] 30 } ; 0
-     }]
+    {
+        let a = #[rustc_dummy(first)] #[rustc_dummy(second)]
+        { #! [allow(unused)] 30 } ; 0
+    }]
 }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
diff --git a/src/test/ui/proc-macro/quote-debug.stdout b/src/test/ui/proc-macro/quote-debug.stdout
index 4bdc04b9ac4..79651f01b95 100644
--- a/src/test/ui/proc-macro/quote-debug.stdout
+++ b/src/test/ui/proc-macro/quote-debug.stdout
@@ -19,29 +19,27 @@ extern crate proc_macro;
 
 fn main() {
     [crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("let",
-                                                                        crate::Span::recover_proc_macro_span(0)))),
-     crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("hello",
-                                                                        crate::Span::recover_proc_macro_span(1)))),
-     crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('\u{3d}',
-                                                                        crate::Spacing::Alone))),
-     crate::TokenStream::from(crate::TokenTree::Literal({
-                                                            let mut iter =
-                                                                "\"world\"".parse::<crate::TokenStream>().unwrap().into_iter();
-                                                            if let (Some(crate::TokenTree::Literal(mut lit)),
-                                                                    None) =
-                                                                   (iter.next(),
-                                                                    iter.next())
-                                                               {
-                                                                lit.set_span(crate::Span::recover_proc_macro_span(2));
-                                                                lit
-                                                            } else {
-                                                                {
-                                                                    ::core::panicking::panic("internal error: entered unreachable code")
-                                                                }
-                                                            }
-                                                        })),
-     crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('\u{3b}',
-                                                                        crate::Spacing::Alone)))].iter().cloned().collect::<crate::TokenStream>()
+                                    crate::Span::recover_proc_macro_span(0)))),
+                        crate::TokenStream::from(crate::TokenTree::Ident(crate::Ident::new("hello",
+                                    crate::Span::recover_proc_macro_span(1)))),
+                        crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('\u{3d}',
+                                    crate::Spacing::Alone))),
+                        crate::TokenStream::from(crate::TokenTree::Literal({
+                                    let mut iter =
+                                        "\"world\"".parse::<crate::TokenStream>().unwrap().into_iter();
+                                    if let (Some(crate::TokenTree::Literal(mut lit)),
+                                                None) =
+                                                (iter.next(), iter.next()) {
+                                            lit.set_span(crate::Span::recover_proc_macro_span(2));
+                                            lit
+                                        } else {
+                                           {
+                                               ::core::panicking::panic("internal error: entered unreachable code")
+                                           }
+                                       }
+                                })),
+                        crate::TokenStream::from(crate::TokenTree::Punct(crate::Punct::new('\u{3b}',
+                                    crate::Spacing::Alone)))].iter().cloned().collect::<crate::TokenStream>()
 }
 const _: () =
     {
diff --git a/src/test/ui/reachable/expr_unary.rs b/src/test/ui/reachable/expr_unary.rs
index e229d22ebc7..190c7447dcc 100644
--- a/src/test/ui/reachable/expr_unary.rs
+++ b/src/test/ui/reachable/expr_unary.rs
@@ -5,8 +5,8 @@
 #![deny(unreachable_code)]
 
 fn foo() {
-    let x: ! = ! { return; }; //~ ERROR unreachable
-    //~| ERROR cannot apply unary operator `!` to type `!`
+    let x: ! = * { return; }; //~ ERROR unreachable
+    //~| ERROR type `!` cannot be dereferenced
 }
 
 fn main() { }
diff --git a/src/test/ui/reachable/expr_unary.stderr b/src/test/ui/reachable/expr_unary.stderr
index 063d841c25e..0a763087c6f 100644
--- a/src/test/ui/reachable/expr_unary.stderr
+++ b/src/test/ui/reachable/expr_unary.stderr
@@ -1,13 +1,13 @@
-error[E0600]: cannot apply unary operator `!` to type `!`
+error[E0614]: type `!` cannot be dereferenced
   --> $DIR/expr_unary.rs:8:16
    |
-LL |     let x: ! = ! { return; };
-   |                ^^^^^^^^^^^^^ cannot apply unary operator `!`
+LL |     let x: ! = * { return; };
+   |                ^^^^^^^^^^^^^
 
 error: unreachable expression
   --> $DIR/expr_unary.rs:8:16
    |
-LL |     let x: ! = ! { return; };
+LL |     let x: ! = * { return; };
    |                ^^^^------^^^
    |                |   |
    |                |   any code following this expression is unreachable
@@ -21,4 +21,4 @@ LL | #![deny(unreachable_code)]
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0600`.
+For more information about this error, try `rustc --explain E0614`.
diff --git a/src/test/ui/recursion/issue-83150.rs b/src/test/ui/recursion/issue-83150.rs
index 650ad22d206..dc25004f89b 100644
--- a/src/test/ui/recursion/issue-83150.rs
+++ b/src/test/ui/recursion/issue-83150.rs
@@ -6,6 +6,6 @@ fn main() {
     func(&mut iter)
 }
 
-fn func<T: Iterator<Item = u8>>(iter: &mut T) {
+fn func<T: Iterator<Item = u8>>(iter: &mut T) { //~ WARN function cannot return without recursing
     func(&mut iter.map(|x| x + 1))
 }
diff --git a/src/test/ui/recursion/issue-83150.stderr b/src/test/ui/recursion/issue-83150.stderr
index d45bfc3ca55..4c8469be626 100644
--- a/src/test/ui/recursion/issue-83150.stderr
+++ b/src/test/ui/recursion/issue-83150.stderr
@@ -1,8 +1,19 @@
+warning: function cannot return without recursing
+  --> $DIR/issue-83150.rs:9:1
+   |
+LL | fn func<T: Iterator<Item = u8>>(iter: &mut T) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |     func(&mut iter.map(|x| x + 1))
+   |     ------------------------------ recursive call site
+   |
+   = note: `#[warn(unconditional_recursion)]` on by default
+   = help: a `loop` may express intention better if this is on purpose
+
 error[E0275]: overflow evaluating the requirement `Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>: Iterator`
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`issue_83150`)
    = note: required because of the requirements on the impl of `Iterator` for `&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut Map<&mut std::ops::Range<u8>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>, [closure@$DIR/issue-83150.rs:10:24: 10:33]>`
 
-error: aborting due to previous error
+error: aborting due to previous error; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0275`.
diff --git a/src/test/ui/regions/region-object-lifetime-2.nll.stderr b/src/test/ui/regions/region-object-lifetime-2.nll.stderr
index db45a03ad18..d95289f3f9d 100644
--- a/src/test/ui/regions/region-object-lifetime-2.nll.stderr
+++ b/src/test/ui/regions/region-object-lifetime-2.nll.stderr
@@ -6,7 +6,7 @@ LL | fn borrowed_receiver_different_lifetimes<'a,'b>(x: &'a dyn Foo) -> &'b () {
    |                                          |
    |                                          lifetime `'a` defined here
 LL |     x.borrowed()
-   |     ^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b`
+   |     ^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr
index 7e8f78067e0..92588819076 100644
--- a/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr
+++ b/src/test/ui/regions/region-object-lifetime-in-coercion.nll.stderr
@@ -31,7 +31,7 @@ LL | fn d<'a,'b>(v: &'a [u8]) -> Box<dyn Foo+'b> {
    |      |
    |      lifetime `'a` defined here
 LL |     Box::new(v)
-   |     ^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b`
+   |     ^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr
index 62032bcb609..246b6483c21 100644
--- a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr
+++ b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr
@@ -1,18 +1,13 @@
-error[E0521]: borrowed data escapes outside of function
+error: lifetime may not live long enough
   --> $DIR/regions-bounded-method-type-parameters-trait-bound.rs:20:5
    |
 LL | fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) {
-   |            -- --            -           - `b` is a reference that is only valid in the function body
-   |            |  |             |
-   |            |  |             `a` declared here, outside of the function body
-   |            |  lifetime `'b` defined here
+   |            -- -- lifetime `'b` defined here
+   |            |
    |            lifetime `'a` defined here
 LL |     // Here the value provided for 'y is 'b, and hence 'b:'a does not hold.
 LL |     f.method(b);
-   |     ^^^^^^^^^^^
-   |     |
-   |     `b` escapes the function body here
-   |     argument requires that `'b` must outlive `'a`
+   |     ^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
    = note: requirement occurs because of the type Inv<'_>, which makes the generic argument '_ invariant
@@ -21,4 +16,3 @@ LL |     f.method(b);
 
 error: aborting due to previous error
 
-For more information about this error, try `rustc --explain E0521`.
diff --git a/src/test/ui/regions/regions-bounds.nll.stderr b/src/test/ui/regions/regions-bounds.nll.stderr
index dd702755c7e..84226a57553 100644
--- a/src/test/ui/regions/regions-bounds.nll.stderr
+++ b/src/test/ui/regions/regions-bounds.nll.stderr
@@ -6,7 +6,7 @@ LL | fn a_fn1<'a,'b>(e: TupleStruct<'a>) -> TupleStruct<'b> {
    |          |
    |          lifetime `'a` defined here
 LL |     return e;
-   |            ^ returning this value requires that `'a` must outlive `'b`
+   |            ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
@@ -18,7 +18,7 @@ LL | fn a_fn3<'a,'b>(e: Struct<'a>) -> Struct<'b> {
    |          |
    |          lifetime `'a` defined here
 LL |     return e;
-   |            ^ returning this value requires that `'a` must outlive `'b`
+   |            ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr b/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr
index c2bd3bbf823..25566742099 100644
--- a/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr
+++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr
@@ -7,7 +7,7 @@ LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait +
    |                    lifetime `'a` defined here
 LL |     // A outlives 'a AND 'b...but not 'c.
 LL |     Box::new(v) as Box<dyn SomeTrait + 'a>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'c`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'c` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'c`
 
diff --git a/src/test/ui/regions/regions-creating-enums4.nll.stderr b/src/test/ui/regions/regions-creating-enums4.nll.stderr
index dda374c90d9..91cf57e099d 100644
--- a/src/test/ui/regions/regions-creating-enums4.nll.stderr
+++ b/src/test/ui/regions/regions-creating-enums4.nll.stderr
@@ -6,7 +6,7 @@ LL | fn mk_add_bad2<'a,'b>(x: &'a Ast<'a>, y: &'a Ast<'a>, z: &Ast) -> Ast<'b> {
    |                |
    |                lifetime `'a` defined here
 LL |     Ast::Add(x, y)
-   |     ^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'b`
+   |     ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
diff --git a/src/test/ui/regions/regions-early-bound-error-method.nll.stderr b/src/test/ui/regions/regions-early-bound-error-method.nll.stderr
index 4957bcf3f73..7f10c051f29 100644
--- a/src/test/ui/regions/regions-early-bound-error-method.nll.stderr
+++ b/src/test/ui/regions/regions-early-bound-error-method.nll.stderr
@@ -6,7 +6,7 @@ LL | impl<'a> Box<'a> {
 LL |     fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a isize {
    |           -- lifetime `'b` defined here
 LL |         g2.get()
-   |         ^^^^^^^^ returning this value requires that `'b` must outlive `'a`
+   |         ^^^^^^^^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'a`
 
diff --git a/src/test/ui/regions/regions-free-region-ordering-incorrect.nll.stderr b/src/test/ui/regions/regions-free-region-ordering-incorrect.nll.stderr
index 106d3df2744..f7c75033c04 100644
--- a/src/test/ui/regions/regions-free-region-ordering-incorrect.nll.stderr
+++ b/src/test/ui/regions/regions-free-region-ordering-incorrect.nll.stderr
@@ -9,7 +9,7 @@ LL | /         match self.next {
 LL | |             Some(ref next) => next.get(),
 LL | |             None => &self.val
 LL | |         }
-   | |_________^ returning this value requires that `'a` must outlive `'b`
+   | |_________^ associated function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
 
diff --git a/src/test/ui/regions/regions-infer-not-param.nll.stderr b/src/test/ui/regions/regions-infer-not-param.nll.stderr
index e211f9d1391..3183aee23d9 100644
--- a/src/test/ui/regions/regions-infer-not-param.nll.stderr
+++ b/src/test/ui/regions/regions-infer-not-param.nll.stderr
@@ -2,7 +2,7 @@ error: lifetime may not live long enough
   --> $DIR/regions-infer-not-param.rs:15:54
    |
 LL | fn take_direct<'a,'b>(p: Direct<'a>) -> Direct<'b> { p }
-   |                -- -- lifetime `'b` defined here      ^ returning this value requires that `'a` must outlive `'b`
+   |                -- -- lifetime `'b` defined here      ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |                |
    |                lifetime `'a` defined here
    |
@@ -25,7 +25,7 @@ error: lifetime may not live long enough
   --> $DIR/regions-infer-not-param.rs:19:63
    |
 LL | fn take_indirect2<'a,'b>(p: Indirect2<'a>) -> Indirect2<'b> { p }
-   |                   -- -- lifetime `'b` defined here            ^ returning this value requires that `'a` must outlive `'b`
+   |                   -- -- lifetime `'b` defined here            ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |                   |
    |                   lifetime `'a` defined here
    |
diff --git a/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr b/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr
index bf325d56013..26f0fcae638 100644
--- a/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr
+++ b/src/test/ui/regions/regions-trait-object-subtyping.nll.stderr
@@ -7,7 +7,7 @@ LL | fn foo3<'a,'b>(x: &'a mut dyn Dummy) -> &'b mut dyn Dummy {
    |         lifetime `'a` defined here
 LL |     // Without knowing 'a:'b, we can't coerce
 LL |     x
-   |     ^ returning this value requires that `'a` must outlive `'b`
+   |     ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
    |
    = help: consider adding the following bound: `'a: 'b`
    = note: requirement occurs because of a mutable reference to dyn Dummy
@@ -23,7 +23,7 @@ LL | fn foo4<'a:'b,'b>(x: Wrapper<&'a mut dyn Dummy>) -> Wrapper<&'b mut dyn Dum
    |         lifetime `'a` defined here
 LL |     // We can't coerce because it is packed in `Wrapper`
 LL |     x
-   |     ^ returning this value requires that `'b` must outlive `'a`
+   |     ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'a`
    = note: requirement occurs because of a mutable reference to dyn Dummy
diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs
index 34d2d84da93..4a36515b991 100644
--- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs
+++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.rs
@@ -14,10 +14,12 @@ fn _if_let_guard() {
         //~^ ERROR `let` expressions in this position are unstable
 
         () if true && let 0 = 1 => {}
-        //~^ ERROR `let` expressions in this position are unstable
+        //~^ ERROR `if let` guards are experimental
+        //~| ERROR `let` expressions in this position are unstable
 
         () if let 0 = 1 && true => {}
-        //~^ ERROR `let` expressions in this position are unstable
+        //~^ ERROR `if let` guards are experimental
+        //~| ERROR `let` expressions in this position are unstable
 
         () if (let 0 = 1) && true => {}
         //~^ ERROR `let` expressions in this position are unstable
@@ -30,14 +32,17 @@ fn _if_let_guard() {
         //~| ERROR `let` expressions in this position are unstable
 
         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
-        //~^ ERROR `let` expressions in this position are unstable
+        //~^ ERROR `if let` guards are experimental
+        //~| ERROR `let` expressions in this position are unstable
         //~| ERROR `let` expressions in this position are unstable
         //~| ERROR `let` expressions in this position are unstable
         //~| ERROR `let` expressions in this position are unstable
         //~| ERROR `let` expressions in this position are unstable
 
         () if let Range { start: _, end: _ } = (true..true) && false => {}
-        //~^ ERROR `let` expressions in this position are unstable
+        //~^ ERROR `if let` guards are experimental
+        //~| ERROR `let` expressions in this position are unstable
+
         _ => {}
     }
 }
diff --git a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr
index 0cda6ba9a99..8d93fb87f7a 100644
--- a/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr
+++ b/src/test/ui/rfc-2294-if-let-guard/feature-gate.stderr
@@ -1,5 +1,5 @@
 error: no rules expected the token `let`
-  --> $DIR/feature-gate.rs:64:15
+  --> $DIR/feature-gate.rs:69:15
    |
 LL |     macro_rules! use_expr {
    |     --------------------- when calling this macro
@@ -18,7 +18,47 @@ LL |         () if let 0 = 1 => {}
    = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
 
 error[E0658]: `if let` guards are experimental
-  --> $DIR/feature-gate.rs:60:12
+  --> $DIR/feature-gate.rs:16:12
+   |
+LL |         () if true && let 0 = 1 => {}
+   |            ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information
+   = help: add `#![feature(if_let_guard)]` to the crate attributes to enable
+   = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
+
+error[E0658]: `if let` guards are experimental
+  --> $DIR/feature-gate.rs:20:12
+   |
+LL |         () if let 0 = 1 && true => {}
+   |            ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information
+   = help: add `#![feature(if_let_guard)]` to the crate attributes to enable
+   = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
+
+error[E0658]: `if let` guards are experimental
+  --> $DIR/feature-gate.rs:34:12
+   |
+LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information
+   = help: add `#![feature(if_let_guard)]` to the crate attributes to enable
+   = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
+
+error[E0658]: `if let` guards are experimental
+  --> $DIR/feature-gate.rs:42:12
+   |
+LL |         () if let Range { start: _, end: _ } = (true..true) && false => {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information
+   = help: add `#![feature(if_let_guard)]` to the crate attributes to enable
+   = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
+
+error[E0658]: `if let` guards are experimental
+  --> $DIR/feature-gate.rs:65:12
    |
 LL |         () if let 0 = 1 => {}
    |            ^^^^^^^^^^^^
@@ -55,7 +95,7 @@ LL |         () if true && let 0 = 1 => {}
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:19:15
+  --> $DIR/feature-gate.rs:20:15
    |
 LL |         () if let 0 = 1 && true => {}
    |               ^^^^^^^^^
@@ -64,7 +104,7 @@ LL |         () if let 0 = 1 && true => {}
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:22:16
+  --> $DIR/feature-gate.rs:24:16
    |
 LL |         () if (let 0 = 1) && true => {}
    |                ^^^^^^^^^
@@ -73,7 +113,7 @@ LL |         () if (let 0 = 1) && true => {}
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:25:24
+  --> $DIR/feature-gate.rs:27:24
    |
 LL |         () if true && (let 0 = 1) => {}
    |                        ^^^^^^^^^
@@ -82,7 +122,7 @@ LL |         () if true && (let 0 = 1) => {}
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:28:16
+  --> $DIR/feature-gate.rs:30:16
    |
 LL |         () if (let 0 = 1) && (let 0 = 1) => {}
    |                ^^^^^^^^^
@@ -91,7 +131,7 @@ LL |         () if (let 0 = 1) && (let 0 = 1) => {}
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:28:31
+  --> $DIR/feature-gate.rs:30:31
    |
 LL |         () if (let 0 = 1) && (let 0 = 1) => {}
    |                               ^^^^^^^^^
@@ -100,7 +140,7 @@ LL |         () if (let 0 = 1) && (let 0 = 1) => {}
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:32:15
+  --> $DIR/feature-gate.rs:34:15
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
    |               ^^^^^^^^^
@@ -109,7 +149,7 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:32:28
+  --> $DIR/feature-gate.rs:34:28
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
    |                            ^^^^^^^^^
@@ -118,7 +158,7 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:32:42
+  --> $DIR/feature-gate.rs:34:42
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
    |                                          ^^^^^^^^^
@@ -127,7 +167,7 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:32:55
+  --> $DIR/feature-gate.rs:34:55
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
    |                                                       ^^^^^^^^^
@@ -136,7 +176,7 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:32:68
+  --> $DIR/feature-gate.rs:34:68
    |
 LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
    |                                                                    ^^^^^^^^^
@@ -145,7 +185,7 @@ LL |         () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 =
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:39:15
+  --> $DIR/feature-gate.rs:42:15
    |
 LL |         () if let Range { start: _, end: _ } = (true..true) && false => {}
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -154,7 +194,7 @@ LL |         () if let Range { start: _, end: _ } = (true..true) && false => {}
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:54:16
+  --> $DIR/feature-gate.rs:59:16
    |
 LL |     use_expr!((let 0 = 1 && 0 == 0));
    |                ^^^^^^^^^
@@ -163,7 +203,7 @@ LL |     use_expr!((let 0 = 1 && 0 == 0));
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
 error[E0658]: `let` expressions in this position are unstable
-  --> $DIR/feature-gate.rs:56:16
+  --> $DIR/feature-gate.rs:61:16
    |
 LL |     use_expr!((let 0 = 1));
    |                ^^^^^^^^^
@@ -171,6 +211,6 @@ LL |     use_expr!((let 0 = 1));
    = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
    = help: add `#![feature(let_chains)]` to the crate attributes to enable
 
-error: aborting due to 19 previous errors
+error: aborting due to 23 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-93150.rs b/src/test/ui/rfc-2497-if-let-chains/issue-93150.rs
new file mode 100644
index 00000000000..f90b9ab0d40
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/issue-93150.rs
@@ -0,0 +1,8 @@
+fn main() {
+    match true {
+        _ if let true = true && true => {}
+        //~^ ERROR `if let` guards are
+        //~| ERROR `let` expressions in this
+        _ => {}
+    }
+}
diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-93150.stderr b/src/test/ui/rfc-2497-if-let-chains/issue-93150.stderr
new file mode 100644
index 00000000000..b25f299a219
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/issue-93150.stderr
@@ -0,0 +1,22 @@
+error[E0658]: `if let` guards are experimental
+  --> $DIR/issue-93150.rs:3:11
+   |
+LL |         _ if let true = true && true => {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #51114 <https://github.com/rust-lang/rust/issues/51114> for more information
+   = help: add `#![feature(if_let_guard)]` to the crate attributes to enable
+   = help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
+
+error[E0658]: `let` expressions in this position are unstable
+  --> $DIR/issue-93150.rs:3:14
+   |
+LL |         _ if let true = true && true => {}
+   |              ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+   = help: add `#![feature(let_chains)]` to the crate attributes to enable
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs b/src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs
index 8800d3e66f9..82c4120b4c7 100644
--- a/src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs
+++ b/src/test/ui/rfc-2565-param-attrs/auxiliary/param-attrs.rs
@@ -37,7 +37,7 @@ checker!(rename_params, r#"impl Foo
     fn hello(#[angery(true)] a : i32, #[a2] b : i32, #[what = "how"] c : u32)
     {} fn
     hello2(#[a1] #[a2] a : i32, #[what = "how"] b : i32, #[angery(true)] c :
-           u32) {} fn
+    u32) {} fn
     hello_self(#[a1] #[a2] & self, #[a1] #[a2] a : i32, #[what = "how"] b :
-               i32, #[angery(true)] c : u32) {}
+    i32, #[angery(true)] c : u32) {}
 }"#);
diff --git a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs
index 7b012083c5a..99eacaa837f 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.rs
@@ -1,5 +1,5 @@
-// FIXME(fee1-dead): this should have a better error message
 #![feature(const_trait_impl)]
+
 struct NonConstAdd(i32);
 
 impl std::ops::Add for NonConstAdd {
@@ -16,7 +16,7 @@ trait Foo {
 
 impl const Foo for NonConstAdd {
     type Bar = NonConstAdd;
-    //~^ ERROR
+    //~^ ERROR: cannot add `NonConstAdd` to `NonConstAdd` in const contexts
 }
 
 trait Baz {
diff --git a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr
index 4a4b4de4758..0788b17a1c0 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/assoc-type.stderr
@@ -1,10 +1,15 @@
-error[E0277]: cannot add `NonConstAdd` to `NonConstAdd`
+error[E0277]: cannot add `NonConstAdd` to `NonConstAdd` in const contexts
   --> $DIR/assoc-type.rs:18:16
    |
 LL |     type Bar = NonConstAdd;
    |                ^^^^^^^^^^^ no implementation for `NonConstAdd + NonConstAdd`
    |
-   = help: the trait `Add` is not implemented for `NonConstAdd`
+   = help: the trait `~const Add` is not implemented for `NonConstAdd`
+note: the trait `Add` is implemented for `NonConstAdd`, but that implementation is not `const`
+  --> $DIR/assoc-type.rs:18:16
+   |
+LL |     type Bar = NonConstAdd;
+   |                ^^^^^^^^^^^
 note: required by a bound in `Foo::Bar`
   --> $DIR/assoc-type.rs:14:15
    |
@@ -12,8 +17,8 @@ LL |     type Bar: ~const std::ops::Add;
    |               ^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::Bar`
 help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
    |
-LL | impl const Foo for NonConstAdd where NonConstAdd: Add {
-   |                                ++++++++++++++++++++++
+LL | impl const Foo for NonConstAdd where NonConstAdd: ~const Add {
+   |                                +++++++++++++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr
index 0440f17a704..35b7fe8e401 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/call-generic-method-nonconst.stderr
@@ -1,4 +1,4 @@
-error[E0277]: can't compare `S` with `S`
+error[E0277]: can't compare `S` with `S` in const contexts
   --> $DIR/call-generic-method-nonconst.rs:19:34
    |
 LL | pub const EQ: bool = equals_self(&S);
@@ -6,7 +6,12 @@ LL | pub const EQ: bool = equals_self(&S);
    |                      |
    |                      required by a bound introduced by this call
    |
-   = help: the trait `PartialEq` is not implemented for `S`
+   = help: the trait `~const PartialEq` is not implemented for `S`
+note: the trait `PartialEq` is implemented for `S`, but that implementation is not `const`
+  --> $DIR/call-generic-method-nonconst.rs:19:34
+   |
+LL | pub const EQ: bool = equals_self(&S);
+   |                                  ^^
 note: required by a bound in `equals_self`
   --> $DIR/call-generic-method-nonconst.rs:12:25
    |
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr
index 04c21101e75..d280cd2556f 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.precise.stderr
@@ -1,65 +1,75 @@
-error: `~const` is not allowed here
-  --> $DIR/const-drop-fail.rs:27:35
-   |
-LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
-   |                                   ^^^^^^^^
-   |
-   = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions
-
-error[E0277]: the trait bound `NonTrivialDrop: Drop` is not satisfied
-  --> $DIR/const-drop-fail.rs:45:5
+error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied
+  --> $DIR/const-drop-fail.rs:44:5
    |
 LL |         const _: () = check($exp);
    |                       ----- required by a bound introduced by this call
 ...
 LL |     NonTrivialDrop,
-   |     ^^^^^^^^^^^^^^ the trait `Drop` is not implemented for `NonTrivialDrop`
+   |     ^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop`
    |
 note: required by a bound in `check`
-  --> $DIR/const-drop-fail.rs:36:19
+  --> $DIR/const-drop-fail.rs:35:19
    |
 LL | const fn check<T: ~const Drop>(_: T) {}
    |                   ^^^^^^^^^^^ required by this bound in `check`
+help: consider borrowing here
+   |
+LL |     &NonTrivialDrop,
+   |     +
+LL |     &mut NonTrivialDrop,
+   |     ++++
 
-error[E0277]: the trait bound `ConstImplWithDropGlue: Drop` is not satisfied
-  --> $DIR/const-drop-fail.rs:47:5
+error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied in `ConstImplWithDropGlue`
+  --> $DIR/const-drop-fail.rs:46:5
    |
 LL |         const _: () = check($exp);
    |                       ----- required by a bound introduced by this call
 ...
 LL |     ConstImplWithDropGlue(NonTrivialDrop),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Drop` is not implemented for `ConstImplWithDropGlue`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `ConstImplWithDropGlue`, the trait `~const Drop` is not implemented for `NonTrivialDrop`
    |
+note: the trait `Drop` is implemented for `NonTrivialDrop`, but that implementation is not `const`
+  --> $DIR/const-drop-fail.rs:46:5
+   |
+LL |     ConstImplWithDropGlue(NonTrivialDrop),
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required because it appears within the type `ConstImplWithDropGlue`
+  --> $DIR/const-drop-fail.rs:17:8
+   |
+LL | struct ConstImplWithDropGlue(NonTrivialDrop);
+   |        ^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
-  --> $DIR/const-drop-fail.rs:36:19
+  --> $DIR/const-drop-fail.rs:35:19
    |
 LL | const fn check<T: ~const Drop>(_: T) {}
    |                   ^^^^^^^^^^^ required by this bound in `check`
 
-error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied
-  --> $DIR/const-drop-fail.rs:49:5
+error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: ~const Drop` is not satisfied
+  --> $DIR/const-drop-fail.rs:48:5
    |
+LL |         const _: () = check($exp);
+   |                       ----- required by a bound introduced by this call
+...
 LL |     ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop`
    |
-note: required by a bound in `ConstDropImplWithBounds`
-  --> $DIR/const-drop-fail.rs:27:35
-   |
-LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
-   |                                   ^^^^^^^^ required by this bound in `ConstDropImplWithBounds`
-
-error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied
-  --> $DIR/const-drop-fail.rs:49:5
+note: required because of the requirements on the impl of `~const Drop` for `ConstDropImplWithBounds<NonTrivialDrop>`
+  --> $DIR/const-drop-fail.rs:29:25
    |
-LL |     ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop`
+LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
+   |                         ^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `check`
+  --> $DIR/const-drop-fail.rs:35:19
    |
-note: required by a bound in `ConstDropImplWithBounds`
-  --> $DIR/const-drop-fail.rs:27:35
+LL | const fn check<T: ~const Drop>(_: T) {}
+   |                   ^^^^^^^^^^^ required by this bound in `check`
+help: consider borrowing here
    |
-LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
-   |                                   ^^^^^^^^ required by this bound in `ConstDropImplWithBounds`
+LL |     &ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
+   |     +
+LL |     &mut ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
+   |     ++++
 
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs
index 3d4de088f55..4622723c189 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.rs
@@ -24,8 +24,7 @@ trait A { fn a() { println!("A"); } }
 
 impl A for NonTrivialDrop {}
 
-struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
-//~^ ERROR `~const` is not allowed
+struct ConstDropImplWithBounds<T: A>(PhantomData<T>);
 
 impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
     fn drop(&mut self) {
@@ -48,7 +47,6 @@ check_all! {
     //~^ ERROR the trait bound
     ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
     //~^ ERROR the trait bound
-    //~| ERROR the trait bound
 }
 
 fn main() {}
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr
index 04c21101e75..d280cd2556f 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop-fail.stock.stderr
@@ -1,65 +1,75 @@
-error: `~const` is not allowed here
-  --> $DIR/const-drop-fail.rs:27:35
-   |
-LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
-   |                                   ^^^^^^^^
-   |
-   = note: only allowed on bounds on traits' associated types and functions, const fns, const impls and its associated functions
-
-error[E0277]: the trait bound `NonTrivialDrop: Drop` is not satisfied
-  --> $DIR/const-drop-fail.rs:45:5
+error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied
+  --> $DIR/const-drop-fail.rs:44:5
    |
 LL |         const _: () = check($exp);
    |                       ----- required by a bound introduced by this call
 ...
 LL |     NonTrivialDrop,
-   |     ^^^^^^^^^^^^^^ the trait `Drop` is not implemented for `NonTrivialDrop`
+   |     ^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop`
    |
 note: required by a bound in `check`
-  --> $DIR/const-drop-fail.rs:36:19
+  --> $DIR/const-drop-fail.rs:35:19
    |
 LL | const fn check<T: ~const Drop>(_: T) {}
    |                   ^^^^^^^^^^^ required by this bound in `check`
+help: consider borrowing here
+   |
+LL |     &NonTrivialDrop,
+   |     +
+LL |     &mut NonTrivialDrop,
+   |     ++++
 
-error[E0277]: the trait bound `ConstImplWithDropGlue: Drop` is not satisfied
-  --> $DIR/const-drop-fail.rs:47:5
+error[E0277]: the trait bound `NonTrivialDrop: ~const Drop` is not satisfied in `ConstImplWithDropGlue`
+  --> $DIR/const-drop-fail.rs:46:5
    |
 LL |         const _: () = check($exp);
    |                       ----- required by a bound introduced by this call
 ...
 LL |     ConstImplWithDropGlue(NonTrivialDrop),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Drop` is not implemented for `ConstImplWithDropGlue`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `ConstImplWithDropGlue`, the trait `~const Drop` is not implemented for `NonTrivialDrop`
    |
+note: the trait `Drop` is implemented for `NonTrivialDrop`, but that implementation is not `const`
+  --> $DIR/const-drop-fail.rs:46:5
+   |
+LL |     ConstImplWithDropGlue(NonTrivialDrop),
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required because it appears within the type `ConstImplWithDropGlue`
+  --> $DIR/const-drop-fail.rs:17:8
+   |
+LL | struct ConstImplWithDropGlue(NonTrivialDrop);
+   |        ^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `check`
-  --> $DIR/const-drop-fail.rs:36:19
+  --> $DIR/const-drop-fail.rs:35:19
    |
 LL | const fn check<T: ~const Drop>(_: T) {}
    |                   ^^^^^^^^^^^ required by this bound in `check`
 
-error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied
-  --> $DIR/const-drop-fail.rs:49:5
+error[E0277]: the trait bound `ConstDropImplWithBounds<NonTrivialDrop>: ~const Drop` is not satisfied
+  --> $DIR/const-drop-fail.rs:48:5
    |
+LL |         const _: () = check($exp);
+   |                       ----- required by a bound introduced by this call
+...
 LL |     ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected an implementor of trait `~const Drop`
    |
-note: required by a bound in `ConstDropImplWithBounds`
-  --> $DIR/const-drop-fail.rs:27:35
-   |
-LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
-   |                                   ^^^^^^^^ required by this bound in `ConstDropImplWithBounds`
-
-error[E0277]: the trait bound `NonTrivialDrop: A` is not satisfied
-  --> $DIR/const-drop-fail.rs:49:5
+note: required because of the requirements on the impl of `~const Drop` for `ConstDropImplWithBounds<NonTrivialDrop>`
+  --> $DIR/const-drop-fail.rs:29:25
    |
-LL |     ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `A` is not implemented for `NonTrivialDrop`
+LL | impl<T: ~const A> const Drop for ConstDropImplWithBounds<T> {
+   |                         ^^^^     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `check`
+  --> $DIR/const-drop-fail.rs:35:19
    |
-note: required by a bound in `ConstDropImplWithBounds`
-  --> $DIR/const-drop-fail.rs:27:35
+LL | const fn check<T: ~const Drop>(_: T) {}
+   |                   ^^^^^^^^^^^ required by this bound in `check`
+help: consider borrowing here
    |
-LL | struct ConstDropImplWithBounds<T: ~const A>(PhantomData<T>);
-   |                                   ^^^^^^^^ required by this bound in `ConstDropImplWithBounds`
+LL |     &ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
+   |     +
+LL |     &mut ConstDropImplWithBounds::<NonTrivialDrop>(PhantomData),
+   |     ++++
 
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs b/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs
index 292017a1de2..13363c506d5 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/const-drop.rs
@@ -3,6 +3,7 @@
 #![feature(const_trait_impl)]
 #![feature(const_fn_trait_bound)]
 #![feature(const_mut_refs)]
+#![feature(never_type)]
 #![cfg_attr(precise, feature(const_precise_live_drops))]
 
 struct S<'a>(&'a mut u8);
@@ -45,6 +46,33 @@ mod t {
 
     pub struct HasConstDrop(pub ConstDrop);
     pub struct TrivialFields(pub u8, pub i8, pub usize, pub isize);
+
+    pub trait SomeTrait {
+        fn foo();
+    }
+    impl const SomeTrait for () {
+        fn foo() {}
+    }
+    // non-const impl
+    impl SomeTrait for i32 {
+        fn foo() {}
+    }
+
+    pub struct ConstDropWithBound<T: SomeTrait>(pub core::marker::PhantomData<T>);
+
+    impl<T: ~const SomeTrait> const Drop for ConstDropWithBound<T> {
+        fn drop(&mut self) {
+            T::foo();
+        }
+    }
+
+    pub struct ConstDropWithNonconstBound<T: SomeTrait>(pub core::marker::PhantomData<T>);
+
+    impl<T: SomeTrait> const Drop for ConstDropWithNonconstBound<T> {
+        fn drop(&mut self) {
+            // Note: we DON'T use the `T: SomeTrait` bound
+        }
+    }
 }
 
 use t::*;
@@ -61,6 +89,9 @@ implements_const_drop! {
     TrivialFields(1, 2, 3, 4),
     &1,
     &1 as *const i32,
+    ConstDropWithBound::<()>,
+    ConstDropWithNonconstBound::<i32>,
+    Result::<i32, !>::Ok(1),
 }
 
 fn main() {
diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs
index 7db04fe1ac3..76ea17159ac 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs
+++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.rs
@@ -10,7 +10,7 @@ pub trait Foo {
     #[default_method_body_is_const]
     fn foo() {
         foo::<()>();
-        //~^ ERROR the trait bound `(): Tr` is not satisfied
+        //~^ ERROR the trait bound `(): ~const Tr` is not satisfied
     }
 }
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr
index 6e7e4b3a472..bc807507fd6 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/default-method-body-is-const-body-checking.stderr
@@ -1,9 +1,14 @@
-error[E0277]: the trait bound `(): Tr` is not satisfied
+error[E0277]: the trait bound `(): ~const Tr` is not satisfied
   --> $DIR/default-method-body-is-const-body-checking.rs:12:15
    |
 LL |         foo::<()>();
-   |               ^^ the trait `Tr` is not implemented for `()`
+   |               ^^ the trait `~const Tr` is not implemented for `()`
    |
+note: the trait `Tr` is implemented for `()`, but that implementation is not `const`
+  --> $DIR/default-method-body-is-const-body-checking.rs:12:15
+   |
+LL |         foo::<()>();
+   |               ^^
 note: required by a bound in `foo`
   --> $DIR/default-method-body-is-const-body-checking.rs:7:28
    |
@@ -11,8 +16,8 @@ LL | const fn foo<T>() where T: ~const Tr {}
    |                            ^^^^^^^^^ required by this bound in `foo`
 help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
    |
-LL | pub trait Foo where (): Tr {
-   |               ++++++++++++
+LL | pub trait Foo where (): ~const Tr {
+   |               +++++++++++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr
index 08d91d7daf8..f9b5d81c63b 100644
--- a/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr
+++ b/src/test/ui/rfc-2632-const-trait-impl/trait-where-clause.stderr
@@ -1,9 +1,14 @@
-error[E0277]: the trait bound `T: Bar` is not satisfied
+error[E0277]: the trait bound `T: ~const Bar` is not satisfied
   --> $DIR/trait-where-clause.rs:14:5
    |
 LL |     T::b();
-   |     ^^^^ the trait `Bar` is not implemented for `T`
+   |     ^^^^ the trait `~const Bar` is not implemented for `T`
    |
+note: the trait `Bar` is implemented for `T`, but that implementation is not `const`
+  --> $DIR/trait-where-clause.rs:14:5
+   |
+LL |     T::b();
+   |     ^^^^
 note: required by a bound in `Foo::b`
   --> $DIR/trait-where-clause.rs:8:24
    |
@@ -11,15 +16,20 @@ LL |     fn b() where Self: ~const Bar;
    |                        ^^^^^^^^^^ required by this bound in `Foo::b`
 help: consider further restricting this bound
    |
-LL | const fn test1<T: ~const Foo + Bar + Bar>() {
-   |                                    +++++
+LL | const fn test1<T: ~const Foo + Bar + ~const Bar>() {
+   |                                    ++++++++++++
 
-error[E0277]: the trait bound `T: Bar` is not satisfied
+error[E0277]: the trait bound `T: ~const Bar` is not satisfied
   --> $DIR/trait-where-clause.rs:16:5
    |
 LL |     T::c::<T>();
-   |     ^^^^^^^^^ the trait `Bar` is not implemented for `T`
+   |     ^^^^^^^^^ the trait `~const Bar` is not implemented for `T`
    |
+note: the trait `Bar` is implemented for `T`, but that implementation is not `const`
+  --> $DIR/trait-where-clause.rs:16:5
+   |
+LL |     T::c::<T>();
+   |     ^^^^^^^^^
 note: required by a bound in `Foo::c`
   --> $DIR/trait-where-clause.rs:9:13
    |
@@ -27,8 +37,8 @@ LL |     fn c<T: ~const Bar>();
    |             ^^^^^^^^^^ required by this bound in `Foo::c`
 help: consider further restricting this bound
    |
-LL | const fn test1<T: ~const Foo + Bar + Bar>() {
-   |                                    +++++
+LL | const fn test1<T: ~const Foo + Bar + ~const Bar>() {
+   |                                    ++++++++++++
 
 error[E0277]: the trait bound `T: Bar` is not satisfied
   --> $DIR/trait-where-clause.rs:28:5
diff --git a/src/test/ui/rust-2018/edition-lint-nested-empty-paths.fixed b/src/test/ui/rust-2018/edition-lint-nested-empty-paths.fixed
index 03d15cea280..acb0aa420ab 100644
--- a/src/test/ui/rust-2018/edition-lint-nested-empty-paths.fixed
+++ b/src/test/ui/rust-2018/edition-lint-nested-empty-paths.fixed
@@ -17,14 +17,28 @@ crate mod foo {
 use crate::foo::{bar::{baz::{}}};
 //~^ ERROR absolute paths must start with
 //~| WARN this is accepted in the current edition
+//~| ERROR absolute paths must start with
+//~| WARN this is accepted in the current edition
 
 use crate::foo::{bar::{XX, baz::{}}};
 //~^ ERROR absolute paths must start with
 //~| WARN this is accepted in the current edition
+//~| ERROR absolute paths must start with
+//~| WARN this is accepted in the current edition
+//~| ERROR absolute paths must start with
+//~| WARN this is accepted in the current edition
+//~| ERROR absolute paths must start with
+//~| WARN this is accepted in the current edition
 
 use crate::foo::{bar::{baz::{}, baz1::{}}};
 //~^ ERROR absolute paths must start with
 //~| WARN this is accepted in the current edition
+//~| ERROR absolute paths must start with
+//~| WARN this is accepted in the current edition
+//~| ERROR absolute paths must start with
+//~| WARN this is accepted in the current edition
+//~| ERROR absolute paths must start with
+//~| WARN this is accepted in the current edition
 
 fn main() {
 }
diff --git a/src/test/ui/rust-2018/edition-lint-nested-empty-paths.rs b/src/test/ui/rust-2018/edition-lint-nested-empty-paths.rs
index d898daaba59..4825528e97f 100644
--- a/src/test/ui/rust-2018/edition-lint-nested-empty-paths.rs
+++ b/src/test/ui/rust-2018/edition-lint-nested-empty-paths.rs
@@ -17,14 +17,28 @@ crate mod foo {
 use foo::{bar::{baz::{}}};
 //~^ ERROR absolute paths must start with
 //~| WARN this is accepted in the current edition
+//~| ERROR absolute paths must start with
+//~| WARN this is accepted in the current edition
 
 use foo::{bar::{XX, baz::{}}};
 //~^ ERROR absolute paths must start with
 //~| WARN this is accepted in the current edition
+//~| ERROR absolute paths must start with
+//~| WARN this is accepted in the current edition
+//~| ERROR absolute paths must start with
+//~| WARN this is accepted in the current edition
+//~| ERROR absolute paths must start with
+//~| WARN this is accepted in the current edition
 
 use foo::{bar::{baz::{}, baz1::{}}};
 //~^ ERROR absolute paths must start with
 //~| WARN this is accepted in the current edition
+//~| ERROR absolute paths must start with
+//~| WARN this is accepted in the current edition
+//~| ERROR absolute paths must start with
+//~| WARN this is accepted in the current edition
+//~| ERROR absolute paths must start with
+//~| WARN this is accepted in the current edition
 
 fn main() {
 }
diff --git a/src/test/ui/rust-2018/edition-lint-nested-empty-paths.stderr b/src/test/ui/rust-2018/edition-lint-nested-empty-paths.stderr
index 54a4fed5cf9..8a3113729b4 100644
--- a/src/test/ui/rust-2018/edition-lint-nested-empty-paths.stderr
+++ b/src/test/ui/rust-2018/edition-lint-nested-empty-paths.stderr
@@ -13,7 +13,16 @@ LL | #![deny(absolute_paths_not_starting_with_crate)]
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-nested-empty-paths.rs:21:5
+  --> $DIR/edition-lint-nested-empty-paths.rs:17:5
+   |
+LL | use foo::{bar::{baz::{}}};
+   |     ^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}}}`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-nested-empty-paths.rs:23:5
    |
 LL | use foo::{bar::{XX, baz::{}}};
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{XX, baz::{}}}`
@@ -22,7 +31,61 @@ LL | use foo::{bar::{XX, baz::{}}};
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-nested-empty-paths.rs:25:5
+  --> $DIR/edition-lint-nested-empty-paths.rs:23:5
+   |
+LL | use foo::{bar::{XX, baz::{}}};
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{XX, baz::{}}}`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-nested-empty-paths.rs:23:5
+   |
+LL | use foo::{bar::{XX, baz::{}}};
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{XX, baz::{}}}`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-nested-empty-paths.rs:23:5
+   |
+LL | use foo::{bar::{XX, baz::{}}};
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{XX, baz::{}}}`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-nested-empty-paths.rs:33:5
+   |
+LL | use foo::{bar::{baz::{}, baz1::{}}};
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}, baz1::{}}}`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-nested-empty-paths.rs:33:5
+   |
+LL | use foo::{bar::{baz::{}, baz1::{}}};
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}, baz1::{}}}`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-nested-empty-paths.rs:33:5
+   |
+LL | use foo::{bar::{baz::{}, baz1::{}}};
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}, baz1::{}}}`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-nested-empty-paths.rs:33:5
    |
 LL | use foo::{bar::{baz::{}, baz1::{}}};
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}, baz1::{}}}`
@@ -30,5 +93,5 @@ LL | use foo::{bar::{baz::{}, baz1::{}}};
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
-error: aborting due to 3 previous errors
+error: aborting due to 10 previous errors
 
diff --git a/src/test/ui/rust-2018/edition-lint-nested-paths.fixed b/src/test/ui/rust-2018/edition-lint-nested-paths.fixed
index 7c6e4a71a37..4eb1184cb6d 100644
--- a/src/test/ui/rust-2018/edition-lint-nested-paths.fixed
+++ b/src/test/ui/rust-2018/edition-lint-nested-paths.fixed
@@ -6,6 +6,12 @@
 use crate::foo::{a, b};
 //~^ ERROR absolute paths must start with
 //~| this is accepted in the current edition
+//~| ERROR absolute paths must start with
+//~| this is accepted in the current edition
+//~| ERROR absolute paths must start with
+//~| this is accepted in the current edition
+//~| ERROR absolute paths must start with
+//~| this is accepted in the current edition
 
 mod foo {
     crate fn a() {}
@@ -21,6 +27,10 @@ fn main() {
         use crate::foo::{self as x, c};
         //~^ ERROR absolute paths must start with
         //~| this is accepted in the current edition
+        //~| ERROR absolute paths must start with
+        //~| this is accepted in the current edition
+        //~| ERROR absolute paths must start with
+        //~| this is accepted in the current edition
         x::a();
         c();
     }
diff --git a/src/test/ui/rust-2018/edition-lint-nested-paths.rs b/src/test/ui/rust-2018/edition-lint-nested-paths.rs
index 3925f76391a..2a358224d9b 100644
--- a/src/test/ui/rust-2018/edition-lint-nested-paths.rs
+++ b/src/test/ui/rust-2018/edition-lint-nested-paths.rs
@@ -6,6 +6,12 @@
 use foo::{a, b};
 //~^ ERROR absolute paths must start with
 //~| this is accepted in the current edition
+//~| ERROR absolute paths must start with
+//~| this is accepted in the current edition
+//~| ERROR absolute paths must start with
+//~| this is accepted in the current edition
+//~| ERROR absolute paths must start with
+//~| this is accepted in the current edition
 
 mod foo {
     crate fn a() {}
@@ -21,6 +27,10 @@ fn main() {
         use foo::{self as x, c};
         //~^ ERROR absolute paths must start with
         //~| this is accepted in the current edition
+        //~| ERROR absolute paths must start with
+        //~| this is accepted in the current edition
+        //~| ERROR absolute paths must start with
+        //~| this is accepted in the current edition
         x::a();
         c();
     }
diff --git a/src/test/ui/rust-2018/edition-lint-nested-paths.stderr b/src/test/ui/rust-2018/edition-lint-nested-paths.stderr
index c2f91e342f5..3d596022b0a 100644
--- a/src/test/ui/rust-2018/edition-lint-nested-paths.stderr
+++ b/src/test/ui/rust-2018/edition-lint-nested-paths.stderr
@@ -13,7 +13,52 @@ LL | #![deny(absolute_paths_not_starting_with_crate)]
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-nested-paths.rs:21:13
+  --> $DIR/edition-lint-nested-paths.rs:6:5
+   |
+LL | use foo::{a, b};
+   |     ^^^^^^^^^^^ help: use `crate`: `crate::foo::{a, b}`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-nested-paths.rs:6:5
+   |
+LL | use foo::{a, b};
+   |     ^^^^^^^^^^^ help: use `crate`: `crate::foo::{a, b}`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-nested-paths.rs:6:5
+   |
+LL | use foo::{a, b};
+   |     ^^^^^^^^^^^ help: use `crate`: `crate::foo::{a, b}`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-nested-paths.rs:27:13
+   |
+LL |         use foo::{self as x, c};
+   |             ^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{self as x, c}`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-nested-paths.rs:27:13
+   |
+LL |         use foo::{self as x, c};
+   |             ^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{self as x, c}`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-nested-paths.rs:27:13
    |
 LL |         use foo::{self as x, c};
    |             ^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{self as x, c}`
@@ -21,5 +66,5 @@ LL |         use foo::{self as x, c};
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
-error: aborting due to 2 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/rust-2018/edition-lint-paths.fixed b/src/test/ui/rust-2018/edition-lint-paths.fixed
index f91405929ee..46adf02a391 100644
--- a/src/test/ui/rust-2018/edition-lint-paths.fixed
+++ b/src/test/ui/rust-2018/edition-lint-paths.fixed
@@ -12,17 +12,25 @@ pub mod foo {
     use crate::bar::Bar;
     //~^ ERROR absolute
     //~| WARN this is accepted in the current edition
+    //~| ERROR absolute
+    //~| WARN this is accepted in the current edition
+
     use super::bar::Bar2;
     use crate::bar::Bar3;
 
     use crate::bar;
     //~^ ERROR absolute
     //~| WARN this is accepted in the current edition
+
     use crate::bar as something_else;
 
     use crate::{main, Bar as SomethingElse};
     //~^ ERROR absolute
     //~| WARN this is accepted in the current edition
+    //~| ERROR absolute
+    //~| WARN this is accepted in the current edition
+    //~| ERROR absolute
+    //~| WARN this is accepted in the current edition
 
     use crate::{main as another_main, Bar as SomethingElse2};
 
@@ -34,6 +42,8 @@ pub mod foo {
 use crate::bar::Bar;
 //~^ ERROR absolute
 //~| WARN this is accepted in the current edition
+//~| ERROR absolute
+//~| WARN this is accepted in the current edition
 
 pub mod bar {
     use edition_lint_paths as foo;
@@ -51,11 +61,14 @@ mod baz {
 impl crate::foo::SomeTrait for u32 {}
 //~^ ERROR absolute
 //~| WARN this is accepted in the current edition
+//~| ERROR absolute
+//~| WARN this is accepted in the current edition
 
 fn main() {
     let x = crate::bar::Bar;
     //~^ ERROR absolute
     //~| WARN this is accepted in the current edition
+
     let x = bar::Bar;
     let x = crate::bar::Bar;
     let x = self::bar::Bar;
diff --git a/src/test/ui/rust-2018/edition-lint-paths.rs b/src/test/ui/rust-2018/edition-lint-paths.rs
index 52c97c7a253..f70bf90d681 100644
--- a/src/test/ui/rust-2018/edition-lint-paths.rs
+++ b/src/test/ui/rust-2018/edition-lint-paths.rs
@@ -12,17 +12,25 @@ pub mod foo {
     use bar::Bar;
     //~^ ERROR absolute
     //~| WARN this is accepted in the current edition
+    //~| ERROR absolute
+    //~| WARN this is accepted in the current edition
+
     use super::bar::Bar2;
     use crate::bar::Bar3;
 
     use bar;
     //~^ ERROR absolute
     //~| WARN this is accepted in the current edition
+
     use crate::bar as something_else;
 
     use {main, Bar as SomethingElse};
     //~^ ERROR absolute
     //~| WARN this is accepted in the current edition
+    //~| ERROR absolute
+    //~| WARN this is accepted in the current edition
+    //~| ERROR absolute
+    //~| WARN this is accepted in the current edition
 
     use crate::{main as another_main, Bar as SomethingElse2};
 
@@ -34,6 +42,8 @@ pub mod foo {
 use bar::Bar;
 //~^ ERROR absolute
 //~| WARN this is accepted in the current edition
+//~| ERROR absolute
+//~| WARN this is accepted in the current edition
 
 pub mod bar {
     use edition_lint_paths as foo;
@@ -51,11 +61,14 @@ mod baz {
 impl ::foo::SomeTrait for u32 {}
 //~^ ERROR absolute
 //~| WARN this is accepted in the current edition
+//~| ERROR absolute
+//~| WARN this is accepted in the current edition
 
 fn main() {
     let x = ::bar::Bar;
     //~^ ERROR absolute
     //~| WARN this is accepted in the current edition
+
     let x = bar::Bar;
     let x = crate::bar::Bar;
     let x = self::bar::Bar;
diff --git a/src/test/ui/rust-2018/edition-lint-paths.stderr b/src/test/ui/rust-2018/edition-lint-paths.stderr
index 23deeda14a4..481c68e1033 100644
--- a/src/test/ui/rust-2018/edition-lint-paths.stderr
+++ b/src/test/ui/rust-2018/edition-lint-paths.stderr
@@ -13,7 +13,16 @@ LL | #![deny(absolute_paths_not_starting_with_crate)]
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-paths.rs:18:9
+  --> $DIR/edition-lint-paths.rs:12:9
+   |
+LL |     use bar::Bar;
+   |         ^^^^^^^^ help: use `crate`: `crate::bar::Bar`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-paths.rs:21:9
    |
 LL |     use bar;
    |         ^^^ help: use `crate`: `crate::bar`
@@ -22,7 +31,7 @@ LL |     use bar;
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-paths.rs:23:9
+  --> $DIR/edition-lint-paths.rs:27:9
    |
 LL |     use {main, Bar as SomethingElse};
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::{main, Bar as SomethingElse}`
@@ -31,7 +40,34 @@ LL |     use {main, Bar as SomethingElse};
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-paths.rs:34:5
+  --> $DIR/edition-lint-paths.rs:27:9
+   |
+LL |     use {main, Bar as SomethingElse};
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::{main, Bar as SomethingElse}`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-paths.rs:27:9
+   |
+LL |     use {main, Bar as SomethingElse};
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::{main, Bar as SomethingElse}`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-paths.rs:42:5
+   |
+LL | use bar::Bar;
+   |     ^^^^^^^^ help: use `crate`: `crate::bar::Bar`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-paths.rs:42:5
    |
 LL | use bar::Bar;
    |     ^^^^^^^^ help: use `crate`: `crate::bar::Bar`
@@ -40,7 +76,7 @@ LL | use bar::Bar;
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-paths.rs:46:9
+  --> $DIR/edition-lint-paths.rs:56:9
    |
 LL |     use *;
    |         ^ help: use `crate`: `crate::*`
@@ -49,7 +85,16 @@ LL |     use *;
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-paths.rs:51:6
+  --> $DIR/edition-lint-paths.rs:61:6
+   |
+LL | impl ::foo::SomeTrait for u32 {}
+   |      ^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::SomeTrait`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
+
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/edition-lint-paths.rs:61:6
    |
 LL | impl ::foo::SomeTrait for u32 {}
    |      ^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::SomeTrait`
@@ -58,7 +103,7 @@ LL | impl ::foo::SomeTrait for u32 {}
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-paths.rs:56:13
+  --> $DIR/edition-lint-paths.rs:68:13
    |
 LL |     let x = ::bar::Bar;
    |             ^^^^^^^^^^ help: use `crate`: `crate::bar::Bar`
@@ -66,5 +111,5 @@ LL |     let x = ::bar::Bar;
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
-error: aborting due to 7 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/src/test/ui/rust-2018/extern-crate-rename.fixed b/src/test/ui/rust-2018/extern-crate-rename.fixed
index ea832ef3e7d..05b881a9b08 100644
--- a/src/test/ui/rust-2018/extern-crate-rename.fixed
+++ b/src/test/ui/rust-2018/extern-crate-rename.fixed
@@ -12,6 +12,8 @@ extern crate edition_lint_paths as my_crate;
 use crate::my_crate::foo;
 //~^ ERROR absolute paths must start
 //~| WARNING this is accepted in the current edition
+//~| ERROR absolute paths must start
+//~| WARNING this is accepted in the current edition
 
 fn main() {
     foo();
diff --git a/src/test/ui/rust-2018/extern-crate-rename.rs b/src/test/ui/rust-2018/extern-crate-rename.rs
index b1f617dd884..6e327be193b 100644
--- a/src/test/ui/rust-2018/extern-crate-rename.rs
+++ b/src/test/ui/rust-2018/extern-crate-rename.rs
@@ -12,6 +12,8 @@ extern crate edition_lint_paths as my_crate;
 use my_crate::foo;
 //~^ ERROR absolute paths must start
 //~| WARNING this is accepted in the current edition
+//~| ERROR absolute paths must start
+//~| WARNING this is accepted in the current edition
 
 fn main() {
     foo();
diff --git a/src/test/ui/rust-2018/extern-crate-rename.stderr b/src/test/ui/rust-2018/extern-crate-rename.stderr
index 4bccbc51223..f2f379ca396 100644
--- a/src/test/ui/rust-2018/extern-crate-rename.stderr
+++ b/src/test/ui/rust-2018/extern-crate-rename.stderr
@@ -12,5 +12,14 @@ LL | #![deny(absolute_paths_not_starting_with_crate)]
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
-error: aborting due to previous error
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/extern-crate-rename.rs:12:5
+   |
+LL | use my_crate::foo;
+   |     ^^^^^^^^^^^^^ help: use `crate`: `crate::my_crate::foo`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/rust-2018/extern-crate-submod.fixed b/src/test/ui/rust-2018/extern-crate-submod.fixed
index 9b0b0dd8ee1..fdbd893abed 100644
--- a/src/test/ui/rust-2018/extern-crate-submod.fixed
+++ b/src/test/ui/rust-2018/extern-crate-submod.fixed
@@ -19,6 +19,9 @@ mod m {
 use crate::m::edition_lint_paths::foo;
 //~^ ERROR absolute paths must start
 //~| WARNING this is accepted in the current edition
+//~| ERROR absolute paths must start
+//~| WARNING this is accepted in the current edition
+
 
 fn main() {
     foo();
diff --git a/src/test/ui/rust-2018/extern-crate-submod.rs b/src/test/ui/rust-2018/extern-crate-submod.rs
index dfce9128c51..c2b915849f0 100644
--- a/src/test/ui/rust-2018/extern-crate-submod.rs
+++ b/src/test/ui/rust-2018/extern-crate-submod.rs
@@ -19,6 +19,9 @@ mod m {
 use m::edition_lint_paths::foo;
 //~^ ERROR absolute paths must start
 //~| WARNING this is accepted in the current edition
+//~| ERROR absolute paths must start
+//~| WARNING this is accepted in the current edition
+
 
 fn main() {
     foo();
diff --git a/src/test/ui/rust-2018/extern-crate-submod.stderr b/src/test/ui/rust-2018/extern-crate-submod.stderr
index 3c75319aeda..c4c3168bc97 100644
--- a/src/test/ui/rust-2018/extern-crate-submod.stderr
+++ b/src/test/ui/rust-2018/extern-crate-submod.stderr
@@ -12,5 +12,14 @@ LL | #![deny(absolute_paths_not_starting_with_crate)]
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
-error: aborting due to previous error
+error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+  --> $DIR/extern-crate-submod.rs:19:5
+   |
+LL | use m::edition_lint_paths::foo;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::m::edition_lint_paths::foo`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
+
+error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/save-analysis/issue-89066.rs b/src/test/ui/save-analysis/issue-89066.rs
new file mode 100644
index 00000000000..2873f5237d4
--- /dev/null
+++ b/src/test/ui/save-analysis/issue-89066.rs
@@ -0,0 +1,28 @@
+// compile-flags: -Zsave-analysis
+
+// Check that this does not ICE.
+// Stolen from src/test/ui/const-generics/generic_arg_infer/infer-arg-test.rs
+
+#![feature(generic_arg_infer)]
+
+struct All<'a, T, const N: usize> {
+  v: &'a T,
+}
+
+struct BadInfer<_>;
+//~^ ERROR expected identifier
+//~| ERROR parameter `_` is never used
+
+fn all_fn<'a, T, const N: usize>() {}
+
+fn bad_infer_fn<_>() {}
+//~^ ERROR expected identifier
+
+
+fn main() {
+  let a: All<_, _, _>;
+  //~^ ERROR this struct takes 2 generic arguments but 3 generic arguments were supplied
+  all_fn();
+  let v: [u8; _];
+  let v: [u8; 10] = [0; _];
+}
diff --git a/src/test/ui/save-analysis/issue-89066.stderr b/src/test/ui/save-analysis/issue-89066.stderr
new file mode 100644
index 00000000000..a3ff1c02b2a
--- /dev/null
+++ b/src/test/ui/save-analysis/issue-89066.stderr
@@ -0,0 +1,39 @@
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/issue-89066.rs:12:17
+   |
+LL | struct BadInfer<_>;
+   |                 ^ expected identifier, found reserved identifier
+
+error: expected identifier, found reserved identifier `_`
+  --> $DIR/issue-89066.rs:18:17
+   |
+LL | fn bad_infer_fn<_>() {}
+   |                 ^ expected identifier, found reserved identifier
+
+error[E0392]: parameter `_` is never used
+  --> $DIR/issue-89066.rs:12:17
+   |
+LL | struct BadInfer<_>;
+   |                 ^ unused parameter
+   |
+   = help: consider removing `_`, referring to it in a field, or using a marker such as `PhantomData`
+   = help: if you intended `_` to be a const parameter, use `const _: usize` instead
+
+error[E0107]: this struct takes 2 generic arguments but 3 generic arguments were supplied
+  --> $DIR/issue-89066.rs:23:10
+   |
+LL |   let a: All<_, _, _>;
+   |          ^^^       - help: remove this generic argument
+   |          |
+   |          expected 2 generic arguments
+   |
+note: struct defined here, with 2 generic parameters: `T`, `N`
+  --> $DIR/issue-89066.rs:8:8
+   |
+LL | struct All<'a, T, const N: usize> {
+   |        ^^^     -        -
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0107, E0392.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr
index 92e86bf5d6c..e2e7ce1ed18 100644
--- a/src/test/ui/span/issue-39018.stderr
+++ b/src/test/ui/span/issue-39018.stderr
@@ -7,10 +7,11 @@ LL |     let x = "Hello " + "World!";
    |             |        `+` cannot be used to concatenate two `&str` strings
    |             &str
    |
-help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+   = note: string concatenation requires an owned `String` on the left
+help: create an owned `String` from a string reference
    |
 LL |     let x = "Hello ".to_owned() + "World!";
-   |             ~~~~~~~~~~~~~~~~~~~
+   |                     +++++++++++
 
 error[E0369]: cannot add `World` to `World`
   --> $DIR/issue-39018.rs:8:26
@@ -46,10 +47,10 @@ LL |     let x = "Hello " + "World!".to_owned();
    |             |        `+` cannot be used to concatenate a `&str` with a `String`
    |             &str
    |
-help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+help: create an owned `String` on the left and add a borrow on the right
    |
 LL |     let x = "Hello ".to_owned() + &"World!".to_owned();
-   |             ~~~~~~~~~~~~~~~~~~~   ~~~~~~~~~~~~~~~~~~~~
+   |                     +++++++++++   +
 
 error[E0369]: cannot add `&String` to `&String`
   --> $DIR/issue-39018.rs:26:16
@@ -60,10 +61,12 @@ LL |     let _ = &a + &b;
    |             |  `+` cannot be used to concatenate two `&str` strings
    |             &String
    |
-help: String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+   = note: string concatenation requires an owned `String` on the left
+help: remove the borrow to obtain an owned `String`
    |
-LL |     let _ = a + &b;
-   |             ~
+LL -     let _ = &a + &b;
+LL +     let _ = a + &b;
+   | 
 
 error[E0369]: cannot add `String` to `&String`
   --> $DIR/issue-39018.rs:27:16
@@ -74,10 +77,11 @@ LL |     let _ = &a + b;
    |             |  `+` cannot be used to concatenate a `&str` with a `String`
    |             &String
    |
-help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+help: remove the borrow on the left and add one on the right
    |
-LL |     let _ = a + &b;
-   |             ~   ~~
+LL -     let _ = &a + b;
+LL +     let _ = a + &b;
+   | 
 
 error[E0308]: mismatched types
   --> $DIR/issue-39018.rs:29:17
@@ -97,10 +101,10 @@ LL |     let _ = e + b;
    |             | `+` cannot be used to concatenate a `&str` with a `String`
    |             &String
    |
-help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+help: create an owned `String` on the left and add a borrow on the right
    |
 LL |     let _ = e.to_owned() + &b;
-   |             ~~~~~~~~~~~~   ~~
+   |              +++++++++++   +
 
 error[E0369]: cannot add `&String` to `&String`
   --> $DIR/issue-39018.rs:31:15
@@ -111,10 +115,11 @@ LL |     let _ = e + &b;
    |             | `+` cannot be used to concatenate two `&str` strings
    |             &String
    |
-help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+   = note: string concatenation requires an owned `String` on the left
+help: create an owned `String` from a string reference
    |
 LL |     let _ = e.to_owned() + &b;
-   |             ~~~~~~~~~~~~
+   |              +++++++++++
 
 error[E0369]: cannot add `&str` to `&String`
   --> $DIR/issue-39018.rs:32:15
@@ -125,10 +130,11 @@ LL |     let _ = e + d;
    |             | `+` cannot be used to concatenate two `&str` strings
    |             &String
    |
-help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+   = note: string concatenation requires an owned `String` on the left
+help: create an owned `String` from a string reference
    |
 LL |     let _ = e.to_owned() + d;
-   |             ~~~~~~~~~~~~
+   |              +++++++++++
 
 error[E0369]: cannot add `&&str` to `&String`
   --> $DIR/issue-39018.rs:33:15
@@ -139,10 +145,11 @@ LL |     let _ = e + &d;
    |             | `+` cannot be used to concatenate two `&str` strings
    |             &String
    |
-help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+   = note: string concatenation requires an owned `String` on the left
+help: create an owned `String` from a string reference
    |
 LL |     let _ = e.to_owned() + &d;
-   |             ~~~~~~~~~~~~
+   |              +++++++++++
 
 error[E0369]: cannot add `&&str` to `&&str`
   --> $DIR/issue-39018.rs:34:16
@@ -169,10 +176,11 @@ LL |     let _ = c + &d;
    |             | `+` cannot be used to concatenate two `&str` strings
    |             &str
    |
-help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+   = note: string concatenation requires an owned `String` on the left
+help: create an owned `String` from a string reference
    |
 LL |     let _ = c.to_owned() + &d;
-   |             ~~~~~~~~~~~~
+   |              +++++++++++
 
 error[E0369]: cannot add `&str` to `&str`
   --> $DIR/issue-39018.rs:37:15
@@ -183,10 +191,11 @@ LL |     let _ = c + d;
    |             | `+` cannot be used to concatenate two `&str` strings
    |             &str
    |
-help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+   = note: string concatenation requires an owned `String` on the left
+help: create an owned `String` from a string reference
    |
 LL |     let _ = c.to_owned() + d;
-   |             ~~~~~~~~~~~~
+   |              +++++++++++
 
 error: aborting due to 14 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 ad51707070f..1a7eb82c95b 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[HASH]::Id::This) }, Ty((I,))), [])`
+error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[54ea]::Id::This) }, Ty((I,))), [])`
   --> $DIR/repeated_projection_type.rs:19:1
    |
 LL | / impl<I, V: Id<This = (I,)>> X for V {
diff --git a/src/test/ui/str/str-concat-on-double-ref.stderr b/src/test/ui/str/str-concat-on-double-ref.stderr
index dee28897f4d..bd354679f78 100644
--- a/src/test/ui/str/str-concat-on-double-ref.stderr
+++ b/src/test/ui/str/str-concat-on-double-ref.stderr
@@ -7,10 +7,11 @@ LL |     let c = a + b;
    |             | `+` cannot be used to concatenate two `&str` strings
    |             &String
    |
-help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+   = note: string concatenation requires an owned `String` on the left
+help: create an owned `String` from a string reference
    |
 LL |     let c = a.to_owned() + b;
-   |             ~~~~~~~~~~~~
+   |              +++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/suggestions/args-instead-of-tuple-errors.rs b/src/test/ui/suggestions/args-instead-of-tuple-errors.rs
new file mode 100644
index 00000000000..2c3ee5fcb80
--- /dev/null
+++ b/src/test/ui/suggestions/args-instead-of-tuple-errors.rs
@@ -0,0 +1,16 @@
+// Ensure we don't suggest tuple-wrapping when we'd end up with a type error
+
+fn main() {
+    // we shouldn't suggest to fix these - `2` isn't a `bool`
+
+    let _: Option<(i32, bool)> = Some(1, 2);
+    //~^ ERROR this enum variant takes 1 argument but 2 arguments were supplied
+    int_bool(1, 2);
+    //~^ ERROR this function takes 1 argument but 2 arguments were supplied
+
+    let _: Option<(i8,)> = Some();
+    //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied
+}
+
+fn int_bool(_: (i32, bool)) {
+}
diff --git a/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr
new file mode 100644
index 00000000000..a2ad602dbd4
--- /dev/null
+++ b/src/test/ui/suggestions/args-instead-of-tuple-errors.stderr
@@ -0,0 +1,33 @@
+error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied
+  --> $DIR/args-instead-of-tuple-errors.rs:6:34
+   |
+LL |     let _: Option<(i32, bool)> = Some(1, 2);
+   |                                  ^^^^ -  - supplied 2 arguments
+   |                                  |
+   |                                  expected 1 argument
+
+error[E0061]: this function takes 1 argument but 2 arguments were supplied
+  --> $DIR/args-instead-of-tuple-errors.rs:8:5
+   |
+LL |     int_bool(1, 2);
+   |     ^^^^^^^^ -  - supplied 2 arguments
+   |     |
+   |     expected 1 argument
+   |
+note: function defined here
+  --> $DIR/args-instead-of-tuple-errors.rs:15:4
+   |
+LL | fn int_bool(_: (i32, bool)) {
+   |    ^^^^^^^^ --------------
+
+error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied
+  --> $DIR/args-instead-of-tuple-errors.rs:11:28
+   |
+LL |     let _: Option<(i8,)> = Some();
+   |                            ^^^^-- supplied 0 arguments
+   |                            |
+   |                            expected 1 argument
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0061`.
diff --git a/src/test/ui/suggestions/args-instead-of-tuple.fixed b/src/test/ui/suggestions/args-instead-of-tuple.fixed
new file mode 100644
index 00000000000..c9b8a41d469
--- /dev/null
+++ b/src/test/ui/suggestions/args-instead-of-tuple.fixed
@@ -0,0 +1,27 @@
+// Test suggesting tuples where bare arguments may have been passed
+// See issue #86481 for details.
+
+// run-rustfix
+
+fn main() {
+    let _: Result<(i32, i8), ()> = Ok((1, 2));
+    //~^ ERROR this enum variant takes 1 argument but 2 arguments were supplied
+    let _: Option<(i32, i8, &'static str)> = Some((1, 2, "hi"));
+    //~^ ERROR this enum variant takes 1 argument but 3 arguments were supplied
+    let _: Option<()> = Some(());
+    //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied
+
+    two_ints((1, 2)); //~ ERROR this function takes 1 argument
+
+    with_generic((3, 4)); //~ ERROR this function takes 1 argument
+}
+
+fn two_ints(_: (i32, i32)) {
+}
+
+fn with_generic<T: Copy + Send>((a, b): (i32, T)) {
+    if false {
+        // test generics/bound handling
+        with_generic((a, b)); //~ ERROR this function takes 1 argument
+    }
+}
diff --git a/src/test/ui/suggestions/args-instead-of-tuple.rs b/src/test/ui/suggestions/args-instead-of-tuple.rs
new file mode 100644
index 00000000000..d4cc3024dd0
--- /dev/null
+++ b/src/test/ui/suggestions/args-instead-of-tuple.rs
@@ -0,0 +1,27 @@
+// Test suggesting tuples where bare arguments may have been passed
+// See issue #86481 for details.
+
+// run-rustfix
+
+fn main() {
+    let _: Result<(i32, i8), ()> = Ok(1, 2);
+    //~^ ERROR this enum variant takes 1 argument but 2 arguments were supplied
+    let _: Option<(i32, i8, &'static str)> = Some(1, 2, "hi");
+    //~^ ERROR this enum variant takes 1 argument but 3 arguments were supplied
+    let _: Option<()> = Some();
+    //~^ ERROR this enum variant takes 1 argument but 0 arguments were supplied
+
+    two_ints(1, 2); //~ ERROR this function takes 1 argument
+
+    with_generic(3, 4); //~ ERROR this function takes 1 argument
+}
+
+fn two_ints(_: (i32, i32)) {
+}
+
+fn with_generic<T: Copy + Send>((a, b): (i32, T)) {
+    if false {
+        // test generics/bound handling
+        with_generic(a, b); //~ ERROR this function takes 1 argument
+    }
+}
diff --git a/src/test/ui/suggestions/args-instead-of-tuple.stderr b/src/test/ui/suggestions/args-instead-of-tuple.stderr
new file mode 100644
index 00000000000..172db7ee3df
--- /dev/null
+++ b/src/test/ui/suggestions/args-instead-of-tuple.stderr
@@ -0,0 +1,84 @@
+error[E0061]: this enum variant takes 1 argument but 2 arguments were supplied
+  --> $DIR/args-instead-of-tuple.rs:7:36
+   |
+LL |     let _: Result<(i32, i8), ()> = Ok(1, 2);
+   |                                    ^^ -  - supplied 2 arguments
+   |
+help: use parentheses to construct a tuple
+   |
+LL |     let _: Result<(i32, i8), ()> = Ok((1, 2));
+   |                                       +    +
+
+error[E0061]: this enum variant takes 1 argument but 3 arguments were supplied
+  --> $DIR/args-instead-of-tuple.rs:9:46
+   |
+LL |     let _: Option<(i32, i8, &'static str)> = Some(1, 2, "hi");
+   |                                              ^^^^ -  -  ---- supplied 3 arguments
+   |
+help: use parentheses to construct a tuple
+   |
+LL |     let _: Option<(i32, i8, &'static str)> = Some((1, 2, "hi"));
+   |                                                   +          +
+
+error[E0061]: this enum variant takes 1 argument but 0 arguments were supplied
+  --> $DIR/args-instead-of-tuple.rs:11:25
+   |
+LL |     let _: Option<()> = Some();
+   |                         ^^^^-- supplied 0 arguments
+   |
+help: expected the unit value `()`; create it with empty parentheses
+   |
+LL |     let _: Option<()> = Some(());
+   |                              ++
+
+error[E0061]: this function takes 1 argument but 2 arguments were supplied
+  --> $DIR/args-instead-of-tuple.rs:14:5
+   |
+LL |     two_ints(1, 2);
+   |     ^^^^^^^^ -  - supplied 2 arguments
+   |
+note: function defined here
+  --> $DIR/args-instead-of-tuple.rs:19:4
+   |
+LL | fn two_ints(_: (i32, i32)) {
+   |    ^^^^^^^^ -------------
+help: use parentheses to construct a tuple
+   |
+LL |     two_ints((1, 2));
+   |              +    +
+
+error[E0061]: this function takes 1 argument but 2 arguments were supplied
+  --> $DIR/args-instead-of-tuple.rs:16:5
+   |
+LL |     with_generic(3, 4);
+   |     ^^^^^^^^^^^^ -  - supplied 2 arguments
+   |
+note: function defined here
+  --> $DIR/args-instead-of-tuple.rs:22:4
+   |
+LL | fn with_generic<T: Copy + Send>((a, b): (i32, T)) {
+   |    ^^^^^^^^^^^^                 ----------------
+help: use parentheses to construct a tuple
+   |
+LL |     with_generic((3, 4));
+   |                  +    +
+
+error[E0061]: this function takes 1 argument but 2 arguments were supplied
+  --> $DIR/args-instead-of-tuple.rs:25:9
+   |
+LL |         with_generic(a, b);
+   |         ^^^^^^^^^^^^ -  - supplied 2 arguments
+   |
+note: function defined here
+  --> $DIR/args-instead-of-tuple.rs:22:4
+   |
+LL | fn with_generic<T: Copy + Send>((a, b): (i32, T)) {
+   |    ^^^^^^^^^^^^                 ----------------
+help: use parentheses to construct a tuple
+   |
+LL |         with_generic((a, b));
+   |                      +    +
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0061`.
diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr
index 63d291ed7cd..b125eacfb6c 100644
--- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr
+++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr
@@ -38,4 +38,5 @@ LL |     impl MyTrait for Box<dyn ObjectTrait<Assoc = i32> + '_> {
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0515`.
+Some errors have detailed explanations: E0515, E0772.
+For more information about an error, try `rustc --explain E0515`.
diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr
index 55a1bbf18ab..ed094c1365c 100644
--- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr
+++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr
@@ -131,4 +131,5 @@ LL |     impl MyTrait for Box<dyn ObjectTrait + '_> {
 
 error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0759`.
+Some errors have detailed explanations: E0759, E0772.
+For more information about an error, try `rustc --explain E0759`.
diff --git a/src/test/ui/suggestions/private-field.rs b/src/test/ui/suggestions/private-field.rs
new file mode 100644
index 00000000000..1cc4d2a4d06
--- /dev/null
+++ b/src/test/ui/suggestions/private-field.rs
@@ -0,0 +1,19 @@
+// compile-flags: --crate-type lib
+pub struct S {
+    pub val: string::MyString,
+}
+
+pub fn test(s: S) {
+    dbg!(s.cap) //~ ERROR: no field `cap` on type `S` [E0609]
+}
+
+pub(crate) mod string {
+
+    pub struct MyString {
+        buf: MyVec,
+    }
+
+    struct MyVec {
+        cap: usize,
+    }
+}
diff --git a/src/test/ui/suggestions/private-field.stderr b/src/test/ui/suggestions/private-field.stderr
new file mode 100644
index 00000000000..c38c795e07a
--- /dev/null
+++ b/src/test/ui/suggestions/private-field.stderr
@@ -0,0 +1,11 @@
+error[E0609]: no field `cap` on type `S`
+  --> $DIR/private-field.rs:7:12
+   |
+LL |     dbg!(s.cap)
+   |            ^^^ unknown field
+   |
+   = note: available fields are: `val`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0609`.
diff --git a/src/test/ui/symbol-names/basic.legacy.stderr b/src/test/ui/symbol-names/basic.legacy.stderr
index e0e798dac40..5b343b637c3 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(_ZN5basic4main17h<SYMBOL_HASH>)
+error: symbol-name(_ZN5basic4main17h7c2c715a9b77648bE)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(basic::main::h<SYMBOL_HASH>)
+error: demangling(basic::main::h7c2c715a9b77648b)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/basic.v0.stderr b/src/test/ui/symbol-names/basic.v0.stderr
index 27308fc5ec3..1f02781364e 100644
--- a/src/test/ui/symbol-names/basic.v0.stderr
+++ b/src/test/ui/symbol-names/basic.v0.stderr
@@ -4,7 +4,7 @@ error: symbol-name(_RNvCsCRATE_HASH_5basic4main)
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(basic[HASH]::main)
+error: demangling(basic[b751b4a00e2291d9]::main)
   --> $DIR/basic.rs:8:1
    |
 LL | #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/foreign-types.stderr b/src/test/ui/symbol-names/foreign-types.stderr
index fcffdd2a8ec..d6ee388ddf8 100644
--- a/src/test/ui/symbol-names/foreign-types.stderr
+++ b/src/test/ui/symbol-names/foreign-types.stderr
@@ -4,7 +4,7 @@ error: symbol-name(_RMCsCRATE_HASH_13foreign_typesINtB<REF>_5CheckNvB<REF>_11For
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<foreign_types[HASH]::Check<foreign_types[HASH]::ForeignType>>)
+error: demangling(<foreign_types[49eeeb51f120b431]::Check<foreign_types[49eeeb51f120b431]::ForeignType>>)
   --> $DIR/foreign-types.rs:13:1
    |
 LL | #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/impl1.legacy.stderr b/src/test/ui/symbol-names/impl1.legacy.stderr
index b17a073ee49..b6012e41594 100644
--- a/src/test/ui/symbol-names/impl1.legacy.stderr
+++ b/src/test/ui/symbol-names/impl1.legacy.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN5impl13foo3Foo3bar17h<SYMBOL_HASH>)
+error: symbol-name(_ZN5impl13foo3Foo3bar17<SYMBOL_HASH>)
   --> $DIR/impl1.rs:14:9
    |
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(impl1::foo::Foo::bar::h<SYMBOL_HASH>)
+error: demangling(impl1::foo::Foo::bar::<SYMBOL_HASH>)
   --> $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(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h<SYMBOL_HASH>)
+error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17<SYMBOL_HASH>)
   --> $DIR/impl1.rs:32:9
    |
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(impl1::bar::<impl impl1::foo::Foo>::baz::h<SYMBOL_HASH>)
+error: demangling(impl1::bar::<impl impl1::foo::Foo>::baz::<SYMBOL_HASH>)
   --> $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(_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$6method17h<SYMBOL_HASH>)
+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$6method17<SYMBOL_HASH>)
   --> $DIR/impl1.rs:62:13
    |
 LL |             #[rustc_symbol_name]
    |             ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method::h<SYMBOL_HASH>)
+error: demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method::<SYMBOL_HASH>)
   --> $DIR/impl1.rs:62:13
    |
 LL |             #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/impl1.v0.stderr b/src/test/ui/symbol-names/impl1.v0.stderr
index 06778e57fb1..48f7473b6a0 100644
--- a/src/test/ui/symbol-names/impl1.v0.stderr
+++ b/src/test/ui/symbol-names/impl1.v0.stderr
@@ -4,7 +4,7 @@ error: symbol-name(_RNvMNtCsCRATE_HASH_5impl13fooNtB<REF>_3Foo3bar)
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<impl1[HASH]::foo::Foo>::bar)
+error: demangling(<impl1[2c09c4f1c7c8e90c]::foo::Foo>::bar)
   --> $DIR/impl1.rs:14:9
    |
 LL |         #[rustc_symbol_name]
@@ -28,7 +28,7 @@ error: symbol-name(_RNvMNtCsCRATE_HASH_5impl13barNtNtB<REF>_3foo3Foo3baz)
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<impl1[HASH]::foo::Foo>::baz)
+error: demangling(<impl1[2c09c4f1c7c8e90c]::foo::Foo>::baz)
   --> $DIR/impl1.rs:32:9
    |
 LL |         #[rustc_symbol_name]
@@ -52,7 +52,7 @@ error: symbol-name(_RNvXNCNvCsCRATE_HASH_5impl14mains_0ARDNtB<REF>_3Foop5AssocFG
 LL |             #[rustc_symbol_name]
    |             ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<[&dyn impl1[HASH]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[HASH]::AutoTrait; 3usize] as impl1[HASH]::main::{closure#1}::Bar>::method)
+error: demangling(<[&dyn impl1[2c09c4f1c7c8e90c]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[2c09c4f1c7c8e90c]::AutoTrait; 3usize] as impl1[2c09c4f1c7c8e90c]::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 46cb84e57bf..dbeab457194 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$3foo17h<SYMBOL_HASH>)
+error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h419983d0842a72aeE)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h<SYMBOL_HASH>)
+error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h419983d0842a72ae)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/issue-60925.v0.stderr b/src/test/ui/symbol-names/issue-60925.v0.stderr
index 1cddba92085..408c957c6a1 100644
--- a/src/test/ui/symbol-names/issue-60925.v0.stderr
+++ b/src/test/ui/symbol-names/issue-60925.v0.stderr
@@ -4,7 +4,7 @@ error: symbol-name(_RNvMNtCsCRATE_HASH_11issue_609253fooINtB<REF>_3FooNtNtB<REF>
 LL |         #[rustc_symbol_name]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<issue_60925[HASH]::foo::Foo<issue_60925[HASH]::llvm::Foo>>::foo)
+error: demangling(<issue_60925[775bc577f14ef671]::foo::Foo<issue_60925[775bc577f14ef671]::llvm::Foo>>::foo)
   --> $DIR/issue-60925.rs:21:9
    |
 LL |         #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/issue-75326.legacy.stderr b/src/test/ui/symbol-names/issue-75326.legacy.stderr
index 74e481badb0..aadc0cf43a2 100644
--- a/src/test/ui/symbol-names/issue-75326.legacy.stderr
+++ b/src/test/ui/symbol-names/issue-75326.legacy.stderr
@@ -1,10 +1,10 @@
-error: symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next17h<SYMBOL_HASH>)
+error: symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next17SYMBOL_HASH)
   --> $DIR/issue-75326.rs:41:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next::h<SYMBOL_HASH>)
+error: demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next::SYMBOL_HASH)
   --> $DIR/issue-75326.rs:41:5
    |
 LL |     #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/issue-75326.v0.stderr b/src/test/ui/symbol-names/issue-75326.v0.stderr
index 446fb8d6cf6..3d7803a0c3b 100644
--- a/src/test/ui/symbol-names/issue-75326.v0.stderr
+++ b/src/test/ui/symbol-names/issue-75326.v0.stderr
@@ -4,7 +4,7 @@ error: symbol-name(_RNvXINICsCRATE_HASH_11issue_75326s_0pppEINtB<REF>_3FooppENtB
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<issue_75326[HASH]::Foo<_, _> as issue_75326[HASH]::Iterator2>::next)
+error: demangling(<issue_75326[e8e253d78520f2a2]::Foo<_, _> as issue_75326[e8e253d78520f2a2]::Iterator2>::next)
   --> $DIR/issue-75326.rs:41:5
    |
 LL |     #[rustc_symbol_name]
diff --git a/src/test/ui/symbol-names/trait-objects.v0.stderr b/src/test/ui/symbol-names/trait-objects.v0.stderr
index 6c5e55ed2ae..47192ce5b83 100644
--- a/src/test/ui/symbol-names/trait-objects.v0.stderr
+++ b/src/test/ui/symbol-names/trait-objects.v0.stderr
@@ -4,7 +4,7 @@ error: symbol-name(_RNvXCsCRATE_HASH_13trait_objectsRDG_INtNtNtCsCRATE_HASH_4cor
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects[HASH]::Bar>::method)
+error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects[7260a56bea9f357b]::Bar>::method)
   --> $DIR/trait-objects.rs:15:5
    |
 LL |     #[rustc_symbol_name]
@@ -22,7 +22,7 @@ error: symbol-name(_RNvXs_CsCRATE_HASH_13trait_objectsRDG_INtNtNtCsCRATE_HASH_4c
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[HASH]::Foo>::method)
+error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[7260a56bea9f357b]::Foo>::method)
   --> $DIR/trait-objects.rs:27:5
    |
 LL |     #[rustc_symbol_name]
@@ -40,7 +40,7 @@ error: symbol-name(_RNvXs0_CsCRATE_HASH_13trait_objectsRDG_INtNtNtCsCRATE_HASH_4
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
-error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[HASH]::Baz>::method)
+error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[7260a56bea9f357b]::Baz>::method)
   --> $DIR/trait-objects.rs:39:5
    |
 LL |     #[rustc_symbol_name]
diff --git a/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.stderr b/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.stderr
index 480f442fedd..bf277362dba 100644
--- a/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.stderr
+++ b/src/test/ui/terminal-width/non-1-width-unicode-multiline-label.stderr
@@ -7,10 +7,11 @@ LL | ...ཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔ
    |                                                  |              `+` cannot be used to concatenate two `&str` strings
    |                                                  &str
    |
-help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left
+   = note: string concatenation requires an owned `String` on the left
+help: create an owned `String` from a string reference
    |
 LL |     let _ = "ༀ༁༂༃༄༅༆༇༈༉༊་༌།༎༏༐༑༒༓༔༕༖༗༘༙༚༛༜༝༞༟༠༡༢༣༤༥༦༧༨༩༪༫༬༭༮༯༰༱༲༳༴༵༶༷༸༹༺༻༼༽༾༿ཀཁགགྷངཅཆཇ཈ཉཊཋཌཌྷཎཏཐདདྷནཔཕབབྷམཙཚཛཛྷཝཞཟའཡརལཤཥསཧཨཀྵཪཫཬ཭཮཯཰ཱཱཱིིུུྲྀཷླྀཹེཻོཽཾཿ྄ཱྀྀྂྃ྅྆྇ྈྉྊྋྌྍྎྏྐྑྒྒྷྔྕྖྗ྘ྙྚྛྜྜྷྞྟྠྡྡྷྣྤྥྦྦྷྨྩྪྫྫྷྭྮྯྰྱྲླྴྵྶྷྸྐྵྺྻྼ྽྾྿࿀࿁࿂࿃࿄࿅࿆࿇࿈࿉࿊࿋࿌࿍࿎࿏࿐࿑࿒࿓࿔࿕࿖࿗࿘࿙࿚"; let _a = unicode_is_fun.to_owned() + " really fun!";
-   |                                                                                                                                                                           ~~~~~~~~~~~~~~~~~~~~~~~~~
+   |                                                                                                                                                                                         +++++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/thir-tree.stdout b/src/test/ui/thir-tree.stdout
index a732eb68a2b..3c84be8e8f8 100644
--- a/src/test/ui/thir-tree.stdout
+++ b/src/test/ui/thir-tree.stdout
@@ -1,4 +1,4 @@
-DefId(0:3 ~ thir_tree[HASH]::main):
+DefId(0:3 ~ thir_tree[8f1d]::main):
 Thir {
     arms: [],
     exprs: [
@@ -30,7 +30,7 @@ Thir {
                 region_scope: Node(2),
                 lint_level: Explicit(
                     HirId {
-                        owner: DefId(0:3 ~ thir_tree[HASH]::main),
+                        owner: DefId(0:3 ~ thir_tree[8f1d]::main),
                         local_id: 2,
                     },
                 ),
diff --git a/src/test/ui/traits/issue-91594.rs b/src/test/ui/traits/issue-91594.rs
new file mode 100644
index 00000000000..930f7f0c6ad
--- /dev/null
+++ b/src/test/ui/traits/issue-91594.rs
@@ -0,0 +1,17 @@
+// #91594: This used to ICE.
+
+trait Component<M> {
+    type Interface;
+}
+trait HasComponent<I> {}
+
+struct Foo;
+
+impl HasComponent<<Foo as Component<Foo>>::Interface> for Foo {}
+//~^ ERROR the trait bound `Foo: HasComponent<()>` is not satisfied
+
+impl<M: HasComponent<()>> Component<M> for Foo {
+    type Interface = u8;
+}
+
+fn main() {}
diff --git a/src/test/ui/traits/issue-91594.stderr b/src/test/ui/traits/issue-91594.stderr
new file mode 100644
index 00000000000..10298a0c703
--- /dev/null
+++ b/src/test/ui/traits/issue-91594.stderr
@@ -0,0 +1,17 @@
+error[E0277]: the trait bound `Foo: HasComponent<()>` is not satisfied
+  --> $DIR/issue-91594.rs:10:6
+   |
+LL | impl HasComponent<<Foo as Component<Foo>>::Interface> for Foo {}
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `HasComponent<()>` is not implemented for `Foo`
+   |
+   = help: the following implementations were found:
+             <Foo as HasComponent<<Foo as Component<Foo>>::Interface>>
+note: required because of the requirements on the impl of `Component<Foo>` for `Foo`
+  --> $DIR/issue-91594.rs:13:27
+   |
+LL | impl<M: HasComponent<()>> Component<M> for Foo {
+   |                           ^^^^^^^^^^^^     ^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/tuple/array-diagnostics.rs b/src/test/ui/tuple/array-diagnostics.rs
new file mode 100644
index 00000000000..1929dab0731
--- /dev/null
+++ b/src/test/ui/tuple/array-diagnostics.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let _tmp = [
+        ("C200B40A82", 3),
+        ("C200B40A83", 4) //~ ERROR: expected function, found `(&'static str, {integer})` [E0618]
+        ("C200B40A8537", 5),
+    ];
+}
diff --git a/src/test/ui/tuple/array-diagnostics.stderr b/src/test/ui/tuple/array-diagnostics.stderr
new file mode 100644
index 00000000000..a10d7af470c
--- /dev/null
+++ b/src/test/ui/tuple/array-diagnostics.stderr
@@ -0,0 +1,9 @@
+error[E0618]: expected function, found `(&'static str, {integer})`
+  --> $DIR/array-diagnostics.rs:4:9
+   |
+LL |         ("C200B40A83", 4)
+   |         ^^^^^^^^^^^^^^^^^- help: consider separating array elements with a comma: `,`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0618`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-60662.stdout b/src/test/ui/type-alias-impl-trait/issue-60662.stdout
index 14a49f20e6b..a46047d9174 100644
--- a/src/test/ui/type-alias-impl-trait/issue-60662.stdout
+++ b/src/test/ui/type-alias-impl-trait/issue-60662.stdout
@@ -10,5 +10,5 @@ extern crate std;
 trait Animal { }
 
 fn main() {
-              pub type ServeFut = /*impl Trait*/;
-          }
+        pub type ServeFut = /*impl Trait*/;
+    }
diff --git a/src/test/ui/variance/variance-contravariant-arg-object.nll.stderr b/src/test/ui/variance/variance-contravariant-arg-object.nll.stderr
index 91d4fd2e971..3315eaaf1c0 100644
--- a/src/test/ui/variance/variance-contravariant-arg-object.nll.stderr
+++ b/src/test/ui/variance/variance-contravariant-arg-object.nll.stderr
@@ -7,7 +7,7 @@ LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
    |                     lifetime `'min` defined here
 ...
 LL |     v
-   |     ^ returning this value requires that `'min` must outlive `'max`
+   |     ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
    |
    = help: consider adding the following bound: `'min: 'max`
 
@@ -20,7 +20,7 @@ LL | fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>)
    |                     lifetime `'min` defined here
 ...
 LL |     v
-   |     ^ returning this value requires that `'min` must outlive `'max`
+   |     ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
    |
    = help: consider adding the following bound: `'min: 'max`
 
diff --git a/src/test/ui/variance/variance-covariant-arg-object.nll.stderr b/src/test/ui/variance/variance-covariant-arg-object.nll.stderr
index 37fdea960be..b116b8e263f 100644
--- a/src/test/ui/variance/variance-covariant-arg-object.nll.stderr
+++ b/src/test/ui/variance/variance-covariant-arg-object.nll.stderr
@@ -7,7 +7,7 @@ LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
    |                     lifetime `'min` defined here
 ...
 LL |     v
-   |     ^ returning this value requires that `'min` must outlive `'max`
+   |     ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
    |
    = help: consider adding the following bound: `'min: 'max`
 
@@ -20,7 +20,7 @@ LL | fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>)
    |                     lifetime `'min` defined here
 ...
 LL |     v
-   |     ^ returning this value requires that `'min` must outlive `'max`
+   |     ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
    |
    = help: consider adding the following bound: `'min: 'max`
 
diff --git a/src/test/ui/variance/variance-invariant-arg-object.nll.stderr b/src/test/ui/variance/variance-invariant-arg-object.nll.stderr
index f6265980af7..303c7f3388a 100644
--- a/src/test/ui/variance/variance-invariant-arg-object.nll.stderr
+++ b/src/test/ui/variance/variance-invariant-arg-object.nll.stderr
@@ -7,7 +7,7 @@ LL | fn get_min_from_max<'min, 'max>(v: Box<dyn Get<&'max i32>>)
    |                     lifetime `'min` defined here
 ...
 LL |     v
-   |     ^ returning this value requires that `'min` must outlive `'max`
+   |     ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
    |
    = help: consider adding the following bound: `'min: 'max`
 
@@ -20,7 +20,7 @@ LL | fn get_max_from_min<'min, 'max, G>(v: Box<dyn Get<&'min i32>>)
    |                     lifetime `'min` defined here
 ...
 LL |     v
-   |     ^ returning this value requires that `'min` must outlive `'max`
+   |     ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
    |
    = help: consider adding the following bound: `'min: 'max`
 
diff --git a/src/test/ui/variance/variance-use-contravariant-struct-1.nll.stderr b/src/test/ui/variance/variance-use-contravariant-struct-1.nll.stderr
index eddd4b217c0..837c70ca313 100644
--- a/src/test/ui/variance/variance-use-contravariant-struct-1.nll.stderr
+++ b/src/test/ui/variance/variance-use-contravariant-struct-1.nll.stderr
@@ -7,7 +7,7 @@ LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>)
    |        lifetime `'min` defined here
 ...
 LL |     v
-   |     ^ returning this value requires that `'min` must outlive `'max`
+   |     ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
    |
    = help: consider adding the following bound: `'min: 'max`
 
diff --git a/src/test/ui/variance/variance-use-covariant-struct-1.nll.stderr b/src/test/ui/variance/variance-use-covariant-struct-1.nll.stderr
index a86c1b93a73..bab858c5acb 100644
--- a/src/test/ui/variance/variance-use-covariant-struct-1.nll.stderr
+++ b/src/test/ui/variance/variance-use-covariant-struct-1.nll.stderr
@@ -7,7 +7,7 @@ LL | fn foo<'min,'max>(v: SomeStruct<&'min ()>)
    |        lifetime `'min` defined here
 ...
 LL |     v
-   |     ^ returning this value requires that `'min` must outlive `'max`
+   |     ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
    |
    = help: consider adding the following bound: `'min: 'max`
 
diff --git a/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr b/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr
index 6890cb115c3..f1df2a88b6b 100644
--- a/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr
+++ b/src/test/ui/variance/variance-use-invariant-struct-1.nll.stderr
@@ -7,7 +7,7 @@ LL | fn foo<'min,'max>(v: SomeStruct<&'max ()>)
    |        lifetime `'min` defined here
 ...
 LL |     v
-   |     ^ returning this value requires that `'min` must outlive `'max`
+   |     ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
    |
    = help: consider adding the following bound: `'min: 'max`
    = note: requirement occurs because of the type SomeStruct<&()>, which makes the generic argument &() invariant
@@ -23,7 +23,7 @@ LL | fn bar<'min,'max>(v: SomeStruct<&'min ()>)
    |        lifetime `'min` defined here
 ...
 LL |     v
-   |     ^ returning this value requires that `'min` must outlive `'max`
+   |     ^ function was supposed to return data with lifetime `'max` but it is returning data with lifetime `'min`
    |
    = help: consider adding the following bound: `'min: 'max`
    = note: requirement occurs because of the type SomeStruct<&()>, which makes the generic argument &() invariant
diff --git a/src/test/ui/wf/wf-static-method.nll.stderr b/src/test/ui/wf/wf-static-method.nll.stderr
index 9c066a7bdb0..26504311195 100644
--- a/src/test/ui/wf/wf-static-method.nll.stderr
+++ b/src/test/ui/wf/wf-static-method.nll.stderr
@@ -7,7 +7,7 @@ LL | impl<'a, 'b> Foo<'a, 'b, Evil<'a, 'b>> for () {
    |      lifetime `'a` defined here
 ...
 LL |         u
-   |         ^ returning this value requires that `'b` must outlive `'a`
+   |         ^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'a`
 
@@ -33,7 +33,7 @@ LL | impl<'a, 'b> Evil<'a, 'b> {
    |      lifetime `'a` defined here
 LL |     fn inherent_evil(u: &'b u32) -> &'a u32 {
 LL |         u
-   |         ^ returning this value requires that `'b` must outlive `'a`
+   |         ^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'a`
 
@@ -45,7 +45,7 @@ LL | fn evil<'a, 'b>(b: &'b u32) -> &'a u32 {
    |         |
    |         lifetime `'a` defined here
 LL |     <()>::static_evil(b)
-   |     ^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a`
+   |     ^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'a`
 
@@ -57,7 +57,7 @@ LL | fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
    |                  |
    |                  lifetime `'a` defined here
 LL |     <IndirectEvil>::static_evil(b)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'a`
 
@@ -69,7 +69,7 @@ LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 {
    |                  |
    |                  lifetime `'a` defined here
 LL |     <Evil>::inherent_evil(b)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`
    |
    = help: consider adding the following bound: `'b: 'a`
 
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 95bb3c92bf516017e812e7f1c14c2dea3845b30
+Subproject 1c034752de0df744fcd7788fcbca158830b8bf8
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 258a8256f53..d66e6cf7fb6 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -981,7 +981,7 @@ Released 2021-03-25
   [#6532](https://github.com/rust-lang/rust-clippy/pull/6532)
 * [`single_match`] Suggest `if` over `if let` when possible
   [#6574](https://github.com/rust-lang/rust-clippy/pull/6574)
-* [`ref_in_deref`] Use parentheses correctly in suggestion
+* `ref_in_deref` Use parentheses correctly in suggestion
   [#6609](https://github.com/rust-lang/rust-clippy/pull/6609)
 * [`stable_sort_primitive`] Clarify error message
   [#6611](https://github.com/rust-lang/rust-clippy/pull/6611)
@@ -3227,7 +3227,6 @@ Released 2018-09-13
 [`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
 [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
diff --git a/src/tools/clippy/clippy_dev/src/bless.rs b/src/tools/clippy/clippy_dev/src/bless.rs
index daf0fcc993b..dcc2502e4c5 100644
--- a/src/tools/clippy/clippy_dev/src/bless.rs
+++ b/src/tools/clippy/clippy_dev/src/bless.rs
@@ -9,9 +9,14 @@ use walkdir::WalkDir;
 
 use crate::clippy_project_root;
 
+#[cfg(not(windows))]
+static CARGO_CLIPPY_EXE: &str = "cargo-clippy";
+#[cfg(windows)]
+static CARGO_CLIPPY_EXE: &str = "cargo-clippy.exe";
+
 static CLIPPY_BUILD_TIME: SyncLazy<Option<std::time::SystemTime>> = SyncLazy::new(|| {
     let mut path = std::env::current_exe().unwrap();
-    path.set_file_name("cargo-clippy");
+    path.set_file_name(CARGO_CLIPPY_EXE);
     fs::metadata(path).ok()?.modified().ok()
 });
 
diff --git a/src/tools/clippy/clippy_dev/src/lint.rs b/src/tools/clippy/clippy_dev/src/lint.rs
index dfd16f71054..b8287980a4b 100644
--- a/src/tools/clippy/clippy_dev/src/lint.rs
+++ b/src/tools/clippy/clippy_dev/src/lint.rs
@@ -7,7 +7,6 @@ pub fn run(filename: &str) {
         .args(["-Z", "no-codegen"])
         .args(["--edition", "2021"])
         .arg(filename)
-        .env("__CLIPPY_INTERNAL_TESTS", "true")
         .status()
         .expect("failed to run cargo")
         .code();
diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs
index 5061c9d1eaf..e109ee0009e 100644
--- a/src/tools/clippy/clippy_lints/src/approx_const.rs
+++ b/src/tools/clippy/clippy_lints/src/approx_const.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::{meets_msrv, msrvs};
 use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
 use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_lint::{LateContext, LateLintPass};
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol;
diff --git a/src/tools/clippy/clippy_lints/src/as_conversions.rs b/src/tools/clippy/clippy_lints/src/as_conversions.rs
index 53704da1046..88b91d58907 100644
--- a/src/tools/clippy/clippy_lints/src/as_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/as_conversions.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use rustc_ast::ast::{Expr, ExprKind};
-use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
@@ -48,7 +48,7 @@ declare_lint_pass!(AsConversions => [AS_CONVERSIONS]);
 
 impl EarlyLintPass for AsConversions {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if in_external_macro(cx.sess, expr.span) {
+        if in_external_macro(cx.sess(), expr.span) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs b/src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs
index b8f5217af2b..9f8eb488c29 100644
--- a/src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/borrow_as_ptr.rs
@@ -94,4 +94,6 @@ impl<'tcx> LateLintPass<'tcx> for BorrowAsPtr {
             }
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index 1915d990c12..470c8c7ea26 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -23,15 +23,14 @@ pub(super) fn check(
 
         if_chain! {
             if let LitKind::Int(n, _) = lit.node;
-            if let Some(src) = snippet_opt(cx, lit.span);
+            if let Some(src) = snippet_opt(cx, cast_expr.span);
             if cast_to.is_floating_point();
             if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node);
             let from_nbits = 128 - n.leading_zeros();
             let to_nbits = fp_ty_mantissa_nbits(cast_to);
             if from_nbits != 0 && to_nbits != 0 && from_nbits <= to_nbits && num_lit.is_decimal();
             then {
-                let literal_str = if is_unary_neg(cast_expr) { format!("-{}", num_lit.integer) } else { num_lit.integer.into() };
-                lint_unnecessary_cast(cx, expr, &literal_str, cast_from, cast_to);
+                lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to);
                 return true
             }
         }
@@ -48,7 +47,7 @@ pub(super) fn check(
             | LitKind::Float(_, LitFloatType::Suffixed(_))
                 if cast_from.kind() == cast_to.kind() =>
             {
-                if let Some(src) = snippet_opt(cx, lit.span) {
+                if let Some(src) = snippet_opt(cx, cast_expr.span) {
                     if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) {
                         lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to);
                     }
@@ -113,7 +112,3 @@ fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 {
         _ => 0,
     }
 }
-
-fn is_unary_neg(expr: &Expr<'_>) -> bool {
-    matches!(expr.kind, ExprKind::Unary(UnOp::Neg, _))
-}
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index feb5f100de5..c0adab790f0 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
+use clippy_utils::sugg::has_enclosing_paren;
 use clippy_utils::ty::peel_mid_ty_refs;
 use clippy_utils::{get_parent_expr, get_parent_node, is_lint_allowed, path_to_local};
 use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
@@ -10,11 +11,10 @@ use rustc_hir::{
     Pat, PatKind, UnOp,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::{self, Ty, TyCtxt, TyS, TypeckResults};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{symbol::sym, Span};
-use std::iter;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -131,8 +131,6 @@ pub struct Dereferencing {
 struct StateData {
     /// Span of the top level expression
     span: Span,
-    /// The required mutability
-    target_mut: Mutability,
 }
 
 enum State {
@@ -141,9 +139,13 @@ enum State {
         // The number of calls in a sequence which changed the referenced type
         ty_changed_count: usize,
         is_final_ufcs: bool,
+        /// The required mutability
+        target_mut: Mutability,
     },
     DerefedBorrow {
-        count: u32,
+        count: usize,
+        required_precedence: i8,
+        msg: &'static str,
     },
 }
 
@@ -214,59 +216,98 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
                                     1
                                 },
                                 is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
-                            },
-                            StateData {
-                                span: expr.span,
                                 target_mut,
                             },
+                            StateData { span: expr.span },
                         ));
                     },
                     RefOp::AddrOf => {
                         // Find the number of times the borrow is auto-derefed.
                         let mut iter = find_adjustments(cx.tcx, typeck, expr).iter();
-                        if let Some((i, adjust)) = iter.by_ref().enumerate().find_map(|(i, adjust)| {
-                            if !matches!(adjust.kind, Adjust::Deref(_)) {
-                                Some((i, adjust))
-                            } else if !adjust.target.is_ref() {
-                                // Add one to the number of references found.
-                                Some((i + 1, adjust))
+                        let mut deref_count = 0usize;
+                        let next_adjust = loop {
+                            match iter.next() {
+                                Some(adjust) => {
+                                    if !matches!(adjust.kind, Adjust::Deref(_)) {
+                                        break Some(adjust);
+                                    } else if !adjust.target.is_ref() {
+                                        deref_count += 1;
+                                        break iter.next();
+                                    }
+                                    deref_count += 1;
+                                },
+                                None => break None,
+                            };
+                        };
+
+                        // Determine the required number of references before any can be removed. In all cases the
+                        // reference made by the current expression will be removed. After that there are four cases to
+                        // handle.
+                        //
+                        // 1. Auto-borrow will trigger in the current position, so no further references are required.
+                        // 2. Auto-deref ends at a reference, or the underlying type, so one extra needs to be left to
+                        //    handle the automatically inserted re-borrow.
+                        // 3. Auto-deref hits a user-defined `Deref` impl, so at least one reference needs to exist to
+                        //    start auto-deref.
+                        // 4. If the chain of non-user-defined derefs ends with a mutable re-borrow, and re-borrow
+                        //    adjustments will not be inserted automatically, then leave one further reference to avoid
+                        //    moving a mutable borrow.
+                        //    e.g.
+                        //        fn foo<T>(x: &mut Option<&mut T>, y: &mut T) {
+                        //            let x = match x {
+                        //                // Removing the borrow will cause `x` to be moved
+                        //                Some(x) => &mut *x,
+                        //                None => y
+                        //            };
+                        //        }
+                        let deref_msg =
+                            "this expression creates a reference which is immediately dereferenced by the compiler";
+                        let borrow_msg = "this expression borrows a value the compiler would automatically borrow";
+
+                        let (required_refs, required_precedence, msg) = if is_auto_borrow_position(parent, expr.hir_id)
+                        {
+                            (1, PREC_POSTFIX, if deref_count == 1 { borrow_msg } else { deref_msg })
+                        } else if let Some(&Adjust::Borrow(AutoBorrow::Ref(_, mutability))) =
+                            next_adjust.map(|a| &a.kind)
+                        {
+                            if matches!(mutability, AutoBorrowMutability::Mut { .. })
+                                && !is_auto_reborrow_position(parent)
+                            {
+                                (3, 0, deref_msg)
                             } else {
-                                None
-                            }
-                        }) {
-                            // Found two consecutive derefs. At least one can be removed.
-                            if i > 1 {
-                                let target_mut = iter::once(adjust)
-                                    .chain(iter)
-                                    .find_map(|adjust| match adjust.kind {
-                                        Adjust::Borrow(AutoBorrow::Ref(_, m)) => Some(m.into()),
-                                        _ => None,
-                                    })
-                                    // This default should never happen. Auto-deref always reborrows.
-                                    .unwrap_or(Mutability::Not);
-                                self.state = Some((
-                                    // Subtract one for the current borrow expression, and one to cover the last
-                                    // reference which can't be removed (it's either reborrowed, or needed for
-                                    // auto-deref to happen).
-                                    State::DerefedBorrow {
-                                        count:
-                                            // Truncation here would require more than a `u32::MAX` level reference. The compiler
-                                            // does not support this.
-                                            #[allow(clippy::cast_possible_truncation)]
-                                            { i as u32 - 2 }
-                                    },
-                                    StateData {
-                                        span: expr.span,
-                                        target_mut,
-                                    },
-                                ));
+                                (2, 0, deref_msg)
                             }
+                        } else {
+                            (2, 0, deref_msg)
+                        };
+
+                        if deref_count >= required_refs {
+                            self.state = Some((
+                                State::DerefedBorrow {
+                                    // One of the required refs is for the current borrow expression, the remaining ones
+                                    // can't be removed without breaking the code. See earlier comment.
+                                    count: deref_count - required_refs,
+                                    required_precedence,
+                                    msg,
+                                },
+                                StateData { span: expr.span },
+                            ));
                         }
                     },
                     _ => (),
                 }
             },
-            (Some((State::DerefMethod { ty_changed_count, .. }, data)), RefOp::Method(_)) => {
+            (
+                Some((
+                    State::DerefMethod {
+                        target_mut,
+                        ty_changed_count,
+                        ..
+                    },
+                    data,
+                )),
+                RefOp::Method(_),
+            ) => {
                 self.state = Some((
                     State::DerefMethod {
                         ty_changed_count: if deref_method_same_type(typeck.expr_ty(expr), typeck.expr_ty(sub_expr)) {
@@ -275,12 +316,30 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
                             ty_changed_count + 1
                         },
                         is_final_ufcs: matches!(expr.kind, ExprKind::Call(..)),
+                        target_mut,
                     },
                     data,
                 ));
             },
-            (Some((State::DerefedBorrow { count }, data)), RefOp::AddrOf) if count != 0 => {
-                self.state = Some((State::DerefedBorrow { count: count - 1 }, data));
+            (
+                Some((
+                    State::DerefedBorrow {
+                        count,
+                        required_precedence,
+                        msg,
+                    },
+                    data,
+                )),
+                RefOp::AddrOf,
+            ) if count != 0 => {
+                self.state = Some((
+                    State::DerefedBorrow {
+                        count: count - 1,
+                        required_precedence,
+                        msg,
+                    },
+                    data,
+                ));
             },
 
             (Some((state, data)), _) => report(cx, expr, state, data),
@@ -455,6 +514,30 @@ fn is_linted_explicit_deref_position(parent: Option<Node<'_>>, child_id: HirId,
     }
 }
 
+/// Checks if the given expression is in a position which can be auto-reborrowed.
+/// Note: This is only correct assuming auto-deref is already occurring.
+fn is_auto_reborrow_position(parent: Option<Node<'_>>) -> bool {
+    match parent {
+        Some(Node::Expr(parent)) => matches!(parent.kind, ExprKind::MethodCall(..) | ExprKind::Call(..)),
+        Some(Node::Local(_)) => true,
+        _ => false,
+    }
+}
+
+/// Checks if the given expression is a position which can auto-borrow.
+fn is_auto_borrow_position(parent: Option<Node<'_>>, child_id: HirId) -> bool {
+    if let Some(Node::Expr(parent)) = parent {
+        match parent.kind {
+            ExprKind::MethodCall(_, [self_arg, ..], _) => self_arg.hir_id == child_id,
+            ExprKind::Field(..) => true,
+            ExprKind::Call(f, _) => f.hir_id == child_id,
+            _ => false,
+        }
+    } else {
+        false
+    }
+}
+
 /// Adjustments are sometimes made in the parent block rather than the expression itself.
 fn find_adjustments<'tcx>(
     tcx: TyCtxt<'tcx>,
@@ -503,6 +586,7 @@ fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData)
         State::DerefMethod {
             ty_changed_count,
             is_final_ufcs,
+            target_mut,
         } => {
             let mut app = Applicability::MachineApplicable;
             let (expr_str, expr_is_macro_call) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
@@ -517,12 +601,12 @@ fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData)
             };
             let addr_of_str = if ty_changed_count < ref_count {
                 // Check if a reborrow from &mut T -> &T is required.
-                if data.target_mut == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
+                if target_mut == Mutability::Not && matches!(ty.kind(), ty::Ref(_, _, Mutability::Mut)) {
                     "&*"
                 } else {
                     ""
                 }
-            } else if data.target_mut == Mutability::Mut {
+            } else if target_mut == Mutability::Mut {
                 "&mut "
             } else {
                 "&"
@@ -538,7 +622,7 @@ fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData)
                 cx,
                 EXPLICIT_DEREF_METHODS,
                 data.span,
-                match data.target_mut {
+                match target_mut {
                     Mutability::Not => "explicit `deref` method call",
                     Mutability::Mut => "explicit `deref_mut` method call",
                 },
@@ -547,19 +631,24 @@ fn report(cx: &LateContext<'_>, expr: &Expr<'_>, state: State, data: StateData)
                 app,
             );
         },
-        State::DerefedBorrow { .. } => {
+        State::DerefedBorrow {
+            required_precedence,
+            msg,
+            ..
+        } => {
             let mut app = Applicability::MachineApplicable;
             let snip = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app).0;
             span_lint_and_sugg(
                 cx,
                 NEEDLESS_BORROW,
                 data.span,
-                &format!(
-                    "this expression borrows a reference (`{}`) that is immediately dereferenced by the compiler",
-                    cx.typeck_results().expr_ty(expr),
-                ),
+                msg,
                 "change this to",
-                snip.into(),
+                if required_precedence > expr.precedence().order() && !has_enclosing_paren(&snip) {
+                    format!("({})", snip)
+                } else {
+                    snip.into()
+                },
                 app,
             );
         },
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
index 3c3f3631849..0c27c3f9255 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint;
 use rustc_ast::ast;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_lint::{EarlyContext, EarlyLintPass, Level};
+use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use unicode_script::{Script, UnicodeScript};
 
@@ -72,7 +72,7 @@ impl EarlyLintPass for DisallowedScriptIdents {
             return;
         }
 
-        let symbols = cx.sess.parse_sess.symbol_gallery.symbols.lock();
+        let symbols = cx.sess().parse_sess.symbol_gallery.symbols.lock();
         // Sort by `Span` so that error messages make sense with respect to the
         // order of identifier locations in the code.
         let mut symbols: Vec<_> = symbols.iter().collect();
diff --git a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
index 92c56c762aa..0b9f54231c5 100644
--- a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
+++ b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
@@ -2,7 +2,7 @@
 
 use clippy_utils::diagnostics::span_lint_and_help;
 use rustc_ast::ast::{Expr, ExprKind};
-use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
@@ -50,7 +50,7 @@ declare_lint_pass!(ElseIfWithoutElse => [ELSE_IF_WITHOUT_ELSE]);
 
 impl EarlyLintPass for ElseIfWithoutElse {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, mut item: &Expr) {
-        if in_external_macro(cx.sess, item.span) {
+        if in_external_macro(cx.sess(), item.span) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs
index 4f89e567430..1f4353fa4f7 100644
--- a/src/tools/clippy/clippy_lints/src/enum_variants.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs
@@ -172,6 +172,9 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n
         let name = var.ident.name.as_str();
 
         let variant_split = camel_case_split(name);
+        if variant_split.len() == 1 {
+            return;
+        }
 
         pre = pre
             .iter()
diff --git a/src/tools/clippy/clippy_lints/src/eq_op.rs b/src/tools/clippy/clippy_lints/src/eq_op.rs
index df75b815436..24d7613e6f8 100644
--- a/src/tools/clippy/clippy_lints/src/eq_op.rs
+++ b/src/tools/clippy/clippy_lints/src/eq_op.rs
@@ -1,12 +1,16 @@
 use clippy_utils::diagnostics::{multispan_sugg, span_lint, span_lint_and_then};
+use clippy_utils::get_enclosing_block;
 use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace};
 use clippy_utils::source::snippet;
 use clippy_utils::ty::{implements_trait, is_copy};
 use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, is_in_test_function};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, BorrowKind, Expr, ExprKind};
+use rustc_hir::{
+    def::Res, def_id::DefId, BinOpKind, BorrowKind, Expr, ExprKind, GenericArg, ItemKind, QPath, Ty, TyKind,
+};
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::{self, TyS};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
@@ -146,6 +150,13 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
                         let rty = cx.typeck_results().expr_ty(r);
                         let lcpy = is_copy(cx, lty);
                         let rcpy = is_copy(cx, rty);
+                        if let Some((self_ty, other_ty)) = in_impl(cx, e, trait_id) {
+                            if (are_equal(cx, rty, self_ty) && are_equal(cx, lty, other_ty))
+                                || (are_equal(cx, rty, other_ty) && are_equal(cx, lty, self_ty))
+                            {
+                                return; // Don't lint
+                            }
+                        }
                         // either operator autorefs or both args are copyable
                         if (requires_ref || (lcpy && rcpy)) && implements_trait(cx, lty, trait_id, &[rty.into()]) {
                             span_lint_and_then(
@@ -206,6 +217,14 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
                     // &foo == bar
                     (&ExprKind::AddrOf(BorrowKind::Ref, _, l), _) => {
                         let lty = cx.typeck_results().expr_ty(l);
+                        if let Some((self_ty, other_ty)) = in_impl(cx, e, trait_id) {
+                            let rty = cx.typeck_results().expr_ty(right);
+                            if (are_equal(cx, rty, self_ty) && are_equal(cx, lty, other_ty))
+                                || (are_equal(cx, rty, other_ty) && are_equal(cx, lty, self_ty))
+                            {
+                                return; // Don't lint
+                            }
+                        }
                         let lcpy = is_copy(cx, lty);
                         if (requires_ref || lcpy)
                             && implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()])
@@ -230,6 +249,14 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
                     // foo == &bar
                     (_, &ExprKind::AddrOf(BorrowKind::Ref, _, r)) => {
                         let rty = cx.typeck_results().expr_ty(r);
+                        if let Some((self_ty, other_ty)) = in_impl(cx, e, trait_id) {
+                            let lty = cx.typeck_results().expr_ty(left);
+                            if (are_equal(cx, rty, self_ty) && are_equal(cx, lty, other_ty))
+                                || (are_equal(cx, rty, other_ty) && are_equal(cx, lty, self_ty))
+                            {
+                                return; // Don't lint
+                            }
+                        }
                         let rcpy = is_copy(cx, rty);
                         if (requires_ref || rcpy)
                             && implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()])
@@ -251,3 +278,43 @@ impl<'tcx> LateLintPass<'tcx> for EqOp {
         }
     }
 }
+
+fn in_impl<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, bin_op: DefId) -> Option<(&'tcx Ty<'tcx>, &'tcx Ty<'tcx>)> {
+    if_chain! {
+        if let Some(block) = get_enclosing_block(cx, e.hir_id);
+        if let Some(impl_def_id) = cx.tcx.impl_of_method(block.hir_id.owner.to_def_id());
+        let item = cx.tcx.hir().expect_item(impl_def_id.expect_local());
+        if let ItemKind::Impl(item) = &item.kind;
+        if let Some(of_trait) = &item.of_trait;
+        if let Some(seg) = of_trait.path.segments.last();
+        if let Some(Res::Def(_, trait_id)) = seg.res;
+        if trait_id == bin_op;
+        if let Some(generic_args) = seg.args;
+        if let Some(GenericArg::Type(other_ty)) = generic_args.args.last();
+
+        then {
+            Some((item.self_ty, other_ty))
+        }
+        else {
+            None
+        }
+    }
+}
+
+fn are_equal<'tcx>(cx: &LateContext<'tcx>, middle_ty: &TyS<'_>, hir_ty: &Ty<'_>) -> bool {
+    if_chain! {
+        if let ty::Adt(adt_def, _) = middle_ty.kind();
+        if let Some(local_did) = adt_def.did.as_local();
+        let item = cx.tcx.hir().expect_item(local_did);
+        let middle_ty_id = item.def_id.to_def_id();
+        if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind;
+        if let Res::Def(_, hir_ty_id) = path.res;
+
+        then {
+            hir_ty_id == middle_ty_id
+        }
+        else {
+            false
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs
index 3e85c8a9c80..ae18f8081bc 100644
--- a/src/tools/clippy/clippy_lints/src/formatting.rs
+++ b/src/tools/clippy/clippy_lints/src/formatting.rs
@@ -3,7 +3,7 @@ use clippy_utils::differing_macro_contexts;
 use clippy_utils::source::snippet_opt;
 use if_chain::if_chain;
 use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
-use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
@@ -207,7 +207,7 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
         if let ExprKind::If(_, then, Some(else_)) = &expr.kind;
         if is_block(else_) || is_if(else_);
         if !differing_macro_contexts(then.span, else_.span);
-        if !then.span.from_expansion() && !in_external_macro(cx.sess, expr.span);
+        if !then.span.from_expansion() && !in_external_macro(cx.sess(), expr.span);
 
         // workaround for rust-lang/rust#43081
         if expr.span.lo().0 != 0 && expr.span.hi().0 != 0;
@@ -259,7 +259,7 @@ fn has_unary_equivalent(bin_op: BinOpKind) -> bool {
 }
 
 fn indentation(cx: &EarlyContext<'_>, span: Span) -> usize {
-    cx.sess.source_map().lookup_char_pos(span.lo()).col.0
+    cx.sess().source_map().lookup_char_pos(span.lo()).col.0
 }
 
 /// Implementation of the `POSSIBLE_MISSING_COMMA` lint for array
diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs
index 5ece2cc5ac4..c2f52605151 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::{meets_msrv, msrvs};
 use if_chain::if_chain;
 use rustc_hir as hir;
-use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_lint::{LateContext, LateLintPass};
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::sym;
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index 104de0ff62f..eed25e9bc0e 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -179,7 +179,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
                             )
                             .and_then(|snip| {
                                 let i = snip.find("fn")?;
-                                Some(item.span.lo() + BytePos((i + (&snip[i..]).find('(')?) as u32))
+                                Some(item.span.lo() + BytePos((i + snip[i..].find('(')?) as u32))
                             })
                             .expect("failed to create span for type parameters");
                             Span::new(pos, pos, item.span.ctxt(), item.span.parent())
diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
index 4615122bbf9..2a4bcd773c6 100644
--- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
@@ -4,11 +4,11 @@ use clippy_utils::higher::IfLet;
 use clippy_utils::ty::is_copy;
 use clippy_utils::{is_expn_of, is_lint_allowed, meets_msrv, msrvs, path_to_local};
 use if_chain::if_chain;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty;
 use rustc_semver::RustcVersion;
@@ -92,9 +92,9 @@ impl<'tcx> LateLintPass<'tcx> for IndexRefutableSlice {
     extract_msrv_attr!(LateContext);
 }
 
-fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxHashMap<hir::HirId, SliceLintInformation> {
+fn find_slice_values(cx: &LateContext<'_>, pat: &hir::Pat<'_>) -> FxIndexMap<hir::HirId, SliceLintInformation> {
     let mut removed_pat: FxHashSet<hir::HirId> = FxHashSet::default();
-    let mut slices: FxHashMap<hir::HirId, SliceLintInformation> = FxHashMap::default();
+    let mut slices: FxIndexMap<hir::HirId, SliceLintInformation> = FxIndexMap::default();
     pat.walk_always(|pat| {
         if let hir::PatKind::Binding(binding, value_hir_id, ident, sub_pat) = pat.kind {
             // We'll just ignore mut and ref mut for simplicity sake right now
@@ -208,10 +208,10 @@ impl SliceLintInformation {
 
 fn filter_lintable_slices<'a, 'tcx>(
     cx: &'a LateContext<'tcx>,
-    slice_lint_info: FxHashMap<hir::HirId, SliceLintInformation>,
+    slice_lint_info: FxIndexMap<hir::HirId, SliceLintInformation>,
     max_suggested_slice: u64,
     scope: &'tcx hir::Expr<'tcx>,
-) -> FxHashMap<hir::HirId, SliceLintInformation> {
+) -> FxIndexMap<hir::HirId, SliceLintInformation> {
     let mut visitor = SliceIndexLintingVisitor {
         cx,
         slice_lint_info,
@@ -225,7 +225,7 @@ fn filter_lintable_slices<'a, 'tcx>(
 
 struct SliceIndexLintingVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
-    slice_lint_info: FxHashMap<hir::HirId, SliceLintInformation>,
+    slice_lint_info: FxIndexMap<hir::HirId, SliceLintInformation>,
     max_suggested_slice: u64,
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/items_after_statements.rs b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
index b118d3c8b87..cdefe627efd 100644
--- a/src/tools/clippy/clippy_lints/src/items_after_statements.rs
+++ b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
@@ -2,7 +2,7 @@
 
 use clippy_utils::diagnostics::span_lint;
 use rustc_ast::ast::{Block, ItemKind, StmtKind};
-use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
@@ -55,7 +55,7 @@ declare_lint_pass!(ItemsAfterStatements => [ITEMS_AFTER_STATEMENTS]);
 
 impl EarlyLintPass for ItemsAfterStatements {
     fn check_block(&mut self, cx: &EarlyContext<'_>, item: &Block) {
-        if in_external_macro(cx.sess, item.span) {
+        if in_external_macro(cx.sess(), item.span) {
             return;
         }
 
@@ -69,7 +69,7 @@ impl EarlyLintPass for ItemsAfterStatements {
         // lint on all further items
         for stmt in stmts {
             if let StmtKind::Item(ref it) = *stmt {
-                if in_external_macro(cx.sess, it.span) {
+                if in_external_macro(cx.sess(), it.span) {
                     return;
                 }
                 if let ItemKind::MacroDef(..) = it.kind {
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_all.rs b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
index 87fd7f99748..4721b7f2b47 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_all.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
@@ -247,7 +247,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(redundant_slicing::REDUNDANT_SLICING),
     LintId::of(redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES),
     LintId::of(reference::DEREF_ADDROF),
-    LintId::of(reference::REF_IN_DEREF),
     LintId::of(regex::INVALID_REGEX),
     LintId::of(repeat_once::REPEAT_ONCE),
     LintId::of(returns::LET_AND_RETURN),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs b/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs
index a21ddf73a11..bd5ff613447 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_complexity.rs
@@ -71,7 +71,6 @@ store.register_group(true, "clippy::complexity", Some("clippy_complexity"), vec!
     LintId::of(redundant_closure_call::REDUNDANT_CLOSURE_CALL),
     LintId::of(redundant_slicing::REDUNDANT_SLICING),
     LintId::of(reference::DEREF_ADDROF),
-    LintId::of(reference::REF_IN_DEREF),
     LintId::of(repeat_once::REPEAT_ONCE),
     LintId::of(strings::STRING_FROM_UTF8_AS_BYTES),
     LintId::of(strlen_on_c_strings::STRLEN_ON_C_STRINGS),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
index 56146a0fd3a..2d2693832e9 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
@@ -423,7 +423,6 @@ store.register_lints(&[
     redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES,
     ref_option_ref::REF_OPTION_REF,
     reference::DEREF_ADDROF,
-    reference::REF_IN_DEREF,
     regex::INVALID_REGEX,
     regex::TRIVIAL_REGEX,
     repeat_once::REPEAT_ONCE,
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 79e9882fef4..f2a7e925dd3 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -581,6 +581,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || Box::new(needless_question_mark::NeedlessQuestionMark));
     store.register_late_pass(move || Box::new(casts::Casts::new(msrv)));
     store.register_early_pass(move || Box::new(unnested_or_patterns::UnnestedOrPatterns::new(msrv)));
+    store.register_late_pass(move || Box::new(map_clone::MapClone::new(msrv)));
 
     store.register_late_pass(|| Box::new(size_of_in_element_count::SizeOfInElementCount));
     store.register_late_pass(|| Box::new(same_name_method::SameNameMethod));
@@ -591,7 +592,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
             msrv,
         ))
     });
-    store.register_late_pass(|| Box::new(map_clone::MapClone));
     store.register_late_pass(|| Box::new(map_err_ignore::MapErrIgnore));
     store.register_late_pass(|| Box::new(shadow::Shadow::default()));
     store.register_late_pass(|| Box::new(unit_types::UnitTypes));
@@ -703,7 +703,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(mut_key::MutableKeyType));
     store.register_late_pass(|| Box::new(modulo_arithmetic::ModuloArithmetic));
     store.register_early_pass(|| Box::new(reference::DerefAddrOf));
-    store.register_early_pass(|| Box::new(reference::RefInDeref));
     store.register_early_pass(|| Box::new(double_parens::DoubleParens));
     store.register_late_pass(|| Box::new(to_string_in_display::ToStringInDisplay::new()));
     store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval));
@@ -935,6 +934,7 @@ pub fn register_renamed(ls: &mut rustc_lint::LintStore) {
     ls.register_renamed("clippy::if_let_some_result", "clippy::match_result_ok");
     ls.register_renamed("clippy::disallowed_type", "clippy::disallowed_types");
     ls.register_renamed("clippy::disallowed_method", "clippy::disallowed_methods");
+    ls.register_renamed("clippy::ref_in_deref", "clippy::needless_borrow");
 
     // uplifted lints
     ls.register_renamed("clippy::invalid_ref", "invalid_value");
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 56505714045..b09c23f31e9 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -13,7 +13,7 @@ use rustc_hir::{
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
-use rustc_span::symbol::{kw, Symbol};
+use rustc_span::symbol::{kw, Ident, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -83,7 +83,7 @@ declare_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]);
 impl<'tcx> LateLintPass<'tcx> for Lifetimes {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if let ItemKind::Fn(ref sig, ref generics, id) = item.kind {
-            check_fn_inner(cx, sig.decl, Some(id), generics, item.span, true);
+            check_fn_inner(cx, sig.decl, Some(id), None, generics, item.span, true);
         }
     }
 
@@ -94,6 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
                 cx,
                 sig.decl,
                 Some(id),
+                None,
                 &item.generics,
                 item.span,
                 report_extra_lifetimes,
@@ -103,11 +104,11 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
         if let TraitItemKind::Fn(ref sig, ref body) = item.kind {
-            let body = match *body {
-                TraitFn::Required(_) => None,
-                TraitFn::Provided(id) => Some(id),
+            let (body, trait_sig) = match *body {
+                TraitFn::Required(sig) => (None, Some(sig)),
+                TraitFn::Provided(id) => (Some(id), None),
             };
-            check_fn_inner(cx, sig.decl, body, &item.generics, item.span, true);
+            check_fn_inner(cx, sig.decl, body, trait_sig, &item.generics, item.span, true);
         }
     }
 }
@@ -124,6 +125,7 @@ fn check_fn_inner<'tcx>(
     cx: &LateContext<'tcx>,
     decl: &'tcx FnDecl<'_>,
     body: Option<BodyId>,
+    trait_sig: Option<&[Ident]>,
     generics: &'tcx Generics<'_>,
     span: Span,
     report_extra_lifetimes: bool,
@@ -165,7 +167,7 @@ fn check_fn_inner<'tcx>(
             }
         }
     }
-    if could_use_elision(cx, decl, body, generics.params) {
+    if could_use_elision(cx, decl, body, trait_sig, generics.params) {
         span_lint(
             cx,
             NEEDLESS_LIFETIMES,
@@ -179,10 +181,31 @@ fn check_fn_inner<'tcx>(
     }
 }
 
+// elision doesn't work for explicit self types, see rust-lang/rust#69064
+fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option<Ident>) -> bool {
+    if_chain! {
+        if let Some(ident) = ident;
+        if ident.name == kw::SelfLower;
+        if !func.implicit_self.has_implicit_self();
+
+        if let Some(self_ty) = func.inputs.first();
+        then {
+            let mut visitor = RefVisitor::new(cx);
+            visitor.visit_ty(self_ty);
+
+            !visitor.all_lts().is_empty()
+        }
+        else {
+            false
+        }
+    }
+}
+
 fn could_use_elision<'tcx>(
     cx: &LateContext<'tcx>,
     func: &'tcx FnDecl<'_>,
     body: Option<BodyId>,
+    trait_sig: Option<&[Ident]>,
     named_generics: &'tcx [GenericParam<'_>],
 ) -> bool {
     // There are two scenarios where elision works:
@@ -233,11 +256,24 @@ fn could_use_elision<'tcx>(
     let input_lts = input_visitor.lts;
     let output_lts = output_visitor.lts;
 
+    if let Some(trait_sig) = trait_sig {
+        if explicit_self_type(cx, func, trait_sig.first().copied()) {
+            return false;
+        }
+    }
+
     if let Some(body_id) = body {
+        let body = cx.tcx.hir().body(body_id);
+
+        let first_ident = body.params.first().and_then(|param| param.pat.simple_ident());
+        if explicit_self_type(cx, func, first_ident) {
+            return false;
+        }
+
         let mut checker = BodyLifetimeChecker {
             lifetimes_used_in_body: false,
         };
-        checker.visit_expr(&cx.tcx.hir().body(body_id).value);
+        checker.visit_expr(&body.value);
         if checker.lifetimes_used_in_body {
             return false;
         }
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index 130543bbbee..b7430f49229 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -7,7 +7,7 @@ use clippy_utils::source::snippet_opt;
 use if_chain::if_chain;
 use rustc_ast::ast::{Expr, ExprKind, Lit, LitKind};
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use std::iter;
@@ -225,7 +225,7 @@ impl_lint_pass!(LiteralDigitGrouping => [
 
 impl EarlyLintPass for LiteralDigitGrouping {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if in_external_macro(cx.sess, expr.span) {
+        if in_external_macro(cx.sess(), expr.span) {
             return;
         }
 
@@ -418,7 +418,7 @@ impl_lint_pass!(DecimalLiteralRepresentation => [DECIMAL_LITERAL_REPRESENTATION]
 
 impl EarlyLintPass for DecimalLiteralRepresentation {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if in_external_macro(cx.sess, expr.span) {
+        if in_external_macro(cx.sess(), expr.span) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index 2af3555e370..babc6fab3c0 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -6,8 +6,8 @@ use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
-    Term, AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId,
-    IsAsync, ItemKind, LifetimeName, TraitRef, Ty, TyKind, TypeBindingKind,
+    AsyncGeneratorKind, Block, Body, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound, HirId,
+    IsAsync, ItemKind, LifetimeName, Term, TraitRef, Ty, TyKind, TypeBindingKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs
index 50bf2527e39..809aa168a7a 100644
--- a/src/tools/clippy/clippy_lints/src/manual_bits.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs
@@ -72,6 +72,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualBits {
             }
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
 
 fn get_one_size_of_ty<'tcx>(
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index 63a72d4fdde..33d1bb2985f 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -5,7 +5,7 @@ use clippy_utils::{meets_msrv, msrvs};
 use if_chain::if_chain;
 use rustc_ast::ast::{FieldDef, Item, ItemKind, Variant, VariantData, VisibilityKind};
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{sym, Span};
@@ -116,7 +116,7 @@ fn check_manual_non_exhaustive_enum(cx: &EarlyContext<'_>, item: &Item, variants
                 |diag| {
                     if_chain! {
                         if !item.attrs.iter().any(|attr| attr.has_name(sym::non_exhaustive));
-                        let header_span = cx.sess.source_map().span_until_char(item.span, '{');
+                        let header_span = cx.sess().source_map().span_until_char(item.span, '{');
                         if let Some(snippet) = snippet_opt(cx, header_span);
                         then {
                             diag.span_suggestion(
@@ -149,7 +149,7 @@ fn check_manual_non_exhaustive_struct(cx: &EarlyContext<'_>, item: &Item, data:
             VariantData::Unit(_) => unreachable!("`VariantData::Unit` is already handled above"),
         };
 
-        cx.sess.source_map().span_until_char(item.span, delimiter)
+        cx.sess().source_map().span_until_char(item.span, delimiter)
     }
 
     let fields = data.fields();
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index c814e013c63..aacabf303a7 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -9,7 +9,7 @@ use rustc_hir::def::Res;
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::BinOpKind;
 use rustc_hir::{BorrowKind, Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
diff --git a/src/tools/clippy/clippy_lints/src/map_clone.rs b/src/tools/clippy/clippy_lints/src/map_clone.rs
index 22a2552b283..3f8eeb736fb 100644
--- a/src/tools/clippy/clippy_lints/src/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/map_clone.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
-use clippy_utils::{is_trait_method, peel_blocks};
+use clippy_utils::{is_trait_method, meets_msrv, msrvs, peel_blocks};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
@@ -9,7 +9,8 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty;
 use rustc_middle::ty::adjustment::Adjust;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_semver::RustcVersion;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::Ident;
 use rustc_span::{sym, Span};
 
@@ -42,7 +43,17 @@ declare_clippy_lint! {
     "using `iterator.map(|x| x.clone())`, or dereferencing closures for `Copy` types"
 }
 
-declare_lint_pass!(MapClone => [MAP_CLONE]);
+pub struct MapClone {
+    msrv: Option<RustcVersion>,
+}
+
+impl_lint_pass!(MapClone => [MAP_CLONE]);
+
+impl MapClone {
+    pub fn new(msrv: Option<RustcVersion>) -> Self {
+        Self { msrv }
+    }
+}
 
 impl<'tcx> LateLintPass<'tcx> for MapClone {
     fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
@@ -65,7 +76,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
                         hir::BindingAnnotation::Unannotated, .., name, None
                     ) = inner.kind {
                         if ident_eq(name, closure_expr) {
-                            lint(cx, e.span, args[0].span, true);
+                            self.lint_explicit_closure(cx, e.span, args[0].span, true);
                         }
                     },
                     hir::PatKind::Binding(hir::BindingAnnotation::Unannotated, .., name, None) => {
@@ -73,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
                             hir::ExprKind::Unary(hir::UnOp::Deref, inner) => {
                                 if ident_eq(name, inner) {
                                     if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() {
-                                        lint(cx, e.span, args[0].span, true);
+                                        self.lint_explicit_closure(cx, e.span, args[0].span, true);
                                     }
                                 }
                             },
@@ -90,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
                                     if let ty::Ref(_, ty, mutability) = obj_ty.kind() {
                                         if matches!(mutability, Mutability::Not) {
                                             let copy = is_copy(cx, ty);
-                                            lint(cx, e.span, args[0].span, copy);
+                                            self.lint_explicit_closure(cx, e.span, args[0].span, copy);
                                         }
                                     } else {
                                         lint_needless_cloning(cx, e.span, args[0].span);
@@ -105,6 +116,8 @@ impl<'tcx> LateLintPass<'tcx> for MapClone {
             }
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
 
 fn ident_eq(name: Ident, path: &hir::Expr<'_>) -> bool {
@@ -127,31 +140,30 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) {
     );
 }
 
-fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) {
-    let mut applicability = Applicability::MachineApplicable;
-    if copied {
-        span_lint_and_sugg(
-            cx,
-            MAP_CLONE,
-            replace,
-            "you are using an explicit closure for copying elements",
-            "consider calling the dedicated `copied` method",
-            format!(
-                "{}.copied()",
-                snippet_with_applicability(cx, root, "..", &mut applicability)
-            ),
-            applicability,
-        );
-    } else {
+impl MapClone {
+    fn lint_explicit_closure(&self, cx: &LateContext<'_>, replace: Span, root: Span, is_copy: bool) {
+        let mut applicability = Applicability::MachineApplicable;
+        let message = if is_copy {
+            "you are using an explicit closure for copying elements"
+        } else {
+            "you are using an explicit closure for cloning elements"
+        };
+        let sugg_method = if is_copy && meets_msrv(self.msrv.as_ref(), &msrvs::ITERATOR_COPIED) {
+            "copied"
+        } else {
+            "cloned"
+        };
+
         span_lint_and_sugg(
             cx,
             MAP_CLONE,
             replace,
-            "you are using an explicit closure for cloning elements",
-            "consider calling the dedicated `cloned` method",
+            message,
+            &format!("consider calling the dedicated `{}` method", sugg_method),
             format!(
-                "{}.cloned()",
-                snippet_with_applicability(cx, root, "..", &mut applicability)
+                "{}.{}()",
+                snippet_with_applicability(cx, root, "..", &mut applicability),
+                sugg_method,
             ),
             applicability,
         );
diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs
index 411a797b6cb..2579404fb18 100644
--- a/src/tools/clippy/clippy_lints/src/matches.rs
+++ b/src/tools/clippy/clippy_lints/src/matches.rs
@@ -25,12 +25,12 @@ use rustc_hir::{
     Mutability, Node, Pat, PatKind, PathSegment, QPath, RangeEnd, TyKind,
 };
 use rustc_hir::{HirIdMap, HirIdSet};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Ty, TyS, VariantDef};
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::{Span, Spanned};
-use rustc_span::sym;
+use rustc_span::{sym, symbol::kw};
 use std::cmp::Ordering;
 use std::collections::hash_map::Entry;
 
@@ -961,13 +961,13 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm
                 let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false));
                 if path_str == "Err" {
                     let mut matching_wild = inner.iter().any(is_wild);
-                    let mut ident_bind_name = String::from("_");
+                    let mut ident_bind_name = kw::Underscore;
                     if !matching_wild {
                         // Looking for unused bindings (i.e.: `_e`)
                         for pat in inner.iter() {
                             if let PatKind::Binding(_, id, ident, None) = pat.kind {
                                 if ident.as_str().starts_with('_') && !is_local_used(cx, arm.body, id) {
-                                    ident_bind_name = ident.name.as_str().to_string();
+                                    ident_bind_name = ident.name;
                                     matching_wild = true;
                                 }
                             }
@@ -982,7 +982,7 @@ fn check_wild_err_arm<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm
                             span_lint_and_note(cx,
                                 MATCH_WILD_ERR_ARM,
                                 arm.pat.span,
-                                &format!("`Err({})` matches all errors", &ident_bind_name),
+                                &format!("`Err({})` matches all errors", ident_bind_name),
                                 None,
                                 "match each error separately or use the error output, or use `.except(msg)` if the error case is unreachable",
                             );
diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs
index 7fc39f17232..a184806d021 100644
--- a/src/tools/clippy/clippy_lints/src/mem_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs
@@ -6,7 +6,7 @@ use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::OptionNone;
 use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, QPath};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
index e7d2d550a30..d813edab687 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
@@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(
                 hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, expr) => expr,
                 hir::ExprKind::MethodCall(method_name, call_args, _) => {
                     if call_args.len() == 1
-                        && (method_name.ident.name == sym::as_str || method_name.ident.name == sym!(as_ref))
+                        && (method_name.ident.name == sym::as_str || method_name.ident.name == sym::as_ref)
                         && {
                             let arg_type = cx.typeck_results().expr_ty(&call_args[0]);
                             let base_type = arg_type.peel_refs();
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 137c9628eb4..4b43448bf7b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -2180,8 +2180,8 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                 for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) {
                     if let ty::PredicateKind::Projection(projection_predicate) = predicate.kind().skip_binder() {
                         let assoc_ty = match projection_predicate.term {
-                          ty::Term::Ty(ty) => ty,
-                          ty::Term::Const(_c) => continue,
+                            ty::Term::Ty(ty) => ty,
+                            ty::Term::Const(_c) => continue,
                         };
                         // walk the associated type and check for Self
                         if let Some(self_adt) = self_ty.ty_adt_def() {
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 6e09e25109f..d955fad7d41 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
@@ -12,7 +12,7 @@ use clippy_utils::source::snippet_opt;
 use rustc_ast::ast::{Expr, ExprKind, Generics, Lit, LitFloatType, LitIntType, LitKind, NodeId, Pat, PatKind};
 use rustc_ast::visit::FnKind;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
@@ -342,7 +342,7 @@ impl EarlyLintPass for MiscEarlyLints {
     }
 
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if in_external_macro(cx.sess, expr.span) {
+        if in_external_macro(cx.sess(), expr.span) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index 77849e1800f..bad9e0be82e 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -5,7 +5,7 @@ use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, msr
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, Constness, FnDecl, GenericParamKind, HirId};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
diff --git a/src/tools/clippy/clippy_lints/src/module_style.rs b/src/tools/clippy/clippy_lints/src/module_style.rs
index 3b65f80cba2..b8dfe996880 100644
--- a/src/tools/clippy/clippy_lints/src/module_style.rs
+++ b/src/tools/clippy/clippy_lints/src/module_style.rs
@@ -80,9 +80,9 @@ impl EarlyLintPass for ModStyle {
             return;
         }
 
-        let files = cx.sess.source_map().files();
+        let files = cx.sess().source_map().files();
 
-        let trim_to_src = if let RealFileName::LocalPath(p) = &cx.sess.opts.working_dir {
+        let trim_to_src = if let RealFileName::LocalPath(p) = &cx.sess().opts.working_dir {
             p.to_string_lossy()
         } else {
             return;
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 0e7ae43ce2d..d4c823d1c1a 100644
--- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
@@ -4,7 +4,7 @@ use clippy_utils::source::snippet;
 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_hir::{AsyncGeneratorKind, Block, Body, Expr, ExprKind, GeneratorKind, LangItem, MatchSource, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::TyS;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -88,7 +88,26 @@ impl LateLintPass<'_> for NeedlessQuestionMark {
     }
 
     fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
-        check(cx, body.value.peel_blocks());
+        if let Some(GeneratorKind::Async(AsyncGeneratorKind::Fn)) = body.generator_kind {
+            if let ExprKind::Block(
+                Block {
+                    expr:
+                        Some(Expr {
+                            kind: ExprKind::DropTemps(async_body),
+                            ..
+                        }),
+                    ..
+                },
+                _,
+            ) = body.value.kind
+            {
+                if let ExprKind::Block(Block { expr: Some(expr), .. }, ..) = async_body.kind {
+                    check(cx, expr);
+                }
+            }
+        } else {
+            check(cx, body.value.peel_blocks());
+        }
     }
 }
 
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 39a37e3e378..0d0c88b02c7 100644
--- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
+++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
@@ -3,7 +3,7 @@ use rustc_ast::ast::{
     self, Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, Pat, PatKind,
 };
 use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor};
-use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
@@ -356,7 +356,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SimilarNamesLocalVisitor<'a, 'tcx> {
 
 impl EarlyLintPass for NonExpressiveNames {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
-        if in_external_macro(cx.sess, item.span) {
+        if in_external_macro(cx.sess(), item.span) {
             return;
         }
 
@@ -371,7 +371,7 @@ impl EarlyLintPass for NonExpressiveNames {
     }
 
     fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &AssocItem) {
-        if in_external_macro(cx.sess, item.span) {
+        if in_external_macro(cx.sess(), item.span) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/octal_escapes.rs b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
index e0da12f77fc..c19cea66104 100644
--- a/src/tools/clippy/clippy_lints/src/octal_escapes.rs
+++ b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use rustc_ast::ast::{Expr, ExprKind};
 use rustc_ast::token::{Lit, LitKind};
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
@@ -51,7 +51,7 @@ declare_lint_pass!(OctalEscapes => [OCTAL_ESCAPES]);
 
 impl EarlyLintPass for OctalEscapes {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if in_external_macro(cx.sess, expr.span) {
+        if in_external_macro(cx.sess(), expr.span) {
             return;
         }
 
@@ -101,7 +101,7 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) {
         // construct a replacement escape
         // the maximum value is \077, or \x3f, so u8 is sufficient here
         if let Ok(n) = u8::from_str_radix(&contents[from + 1..to], 8) {
-            write!(&mut suggest_1, "\\x{:02x}", n).unwrap();
+            write!(suggest_1, "\\x{:02x}", n).unwrap();
         }
 
         // append the null byte as \x00 and the following digits literally
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 63de117a6f1..b5d65542de0 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -1,30 +1,36 @@
 //! Checks for usage of  `&Vec[_]` and `&String`.
 
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::ptr::get_spans;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::walk_ptrs_hir_ty;
-use clippy_utils::{expr_path_res, is_lint_allowed, match_any_diagnostic_items, paths};
+use clippy_utils::ty::expr_sig;
+use clippy_utils::{
+    expr_path_res, get_expr_use_or_unification_node, is_lint_allowed, match_any_diagnostic_items, path_to_local, paths,
+};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::def::Res;
+use rustc_hir::def_id::DefId;
+use rustc_hir::hir_id::HirIdMap;
+use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{
-    BinOpKind, BodyId, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, Impl, ImplItem, ImplItemKind, Item, ItemKind,
-    Lifetime, MutTy, Mutability, Node, PathSegment, QPath, TraitFn, TraitItem, TraitItemKind, Ty, TyKind,
+    self as hir, AnonConst, BinOpKind, BindingAnnotation, Body, Expr, ExprKind, FnDecl, FnRetTy, GenericArg,
+    ImplItemKind, ItemKind, Lifetime, LifetimeName, Mutability, Node, Param, ParamName, PatKind, QPath, TraitFn,
+    TraitItem, TraitItemKind, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::nested_filter;
+use rustc_middle::ty::{self, AssocItems, AssocKind, Ty};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::source_map::Span;
 use rustc_span::symbol::Symbol;
 use rustc_span::{sym, MultiSpan};
-use std::borrow::Cow;
+use std::fmt;
+use std::iter;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// This lint checks for function arguments of type `&String`
-    /// or `&Vec` unless the references are mutable. It will also suggest you
-    /// replace `.clone()` calls with the appropriate `.to_owned()`/`to_string()`
-    /// calls.
+    /// This lint checks for function arguments of type `&String`, `&Vec`,
+    /// `&PathBuf`, and `Cow<_>`. It will also suggest you replace `.clone()` calls
+    /// with the appropriate `.to_owned()`/`to_string()` calls.
     ///
     /// ### Why is this bad?
     /// Requiring the argument to be of the specific size
@@ -32,28 +38,7 @@ declare_clippy_lint! {
     /// or `&str` usually suffice and can be obtained from other types, too.
     ///
     /// ### Known problems
-    /// The lint does not follow data. So if you have an
-    /// argument `x` and write `let y = x; y.clone()` the lint will not suggest
-    /// changing that `.clone()` to `.to_owned()`.
-    ///
-    /// Other functions called from this function taking a `&String` or `&Vec`
-    /// argument may also fail to compile if you change the argument. Applying
-    /// this lint on them will fix the problem, but they may be in other crates.
-    ///
-    /// One notable example of a function that may cause issues, and which cannot
-    /// easily be changed due to being in the standard library is `Vec::contains`.
-    /// when called on a `Vec<Vec<T>>`. If a `&Vec` is passed to that method then
-    /// it will compile, but if a `&[T]` is passed then it will not compile.
-    ///
-    /// ```ignore
-    /// fn cannot_take_a_slice(v: &Vec<u8>) -> bool {
-    ///     let vec_of_vecs: Vec<Vec<u8>> = some_other_fn();
-    ///
-    ///     vec_of_vecs.contains(v)
-    /// }
-    /// ```
-    ///
-    /// Also there may be `fn(&Vec)`-typed references pointing to your function.
+    /// There may be `fn(&Vec)`-typed references pointing to your function.
     /// If you have them, you will get a compiler error after applying this lint's
     /// suggestions. You then have the choice to undo your changes or change the
     /// type of the reference.
@@ -155,32 +140,86 @@ declare_clippy_lint! {
 declare_lint_pass!(Ptr => [PTR_ARG, CMP_NULL, MUT_FROM_REF, INVALID_NULL_PTR_USAGE]);
 
 impl<'tcx> LateLintPass<'tcx> for Ptr {
-    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if let ItemKind::Fn(ref sig, _, body_id) = item.kind {
-            check_fn(cx, sig.decl, Some(body_id));
-        }
-    }
+    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
+        if let TraitItemKind::Fn(sig, trait_method) = &item.kind {
+            if matches!(trait_method, TraitFn::Provided(_)) {
+                // Handled by check body.
+                return;
+            }
 
-    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
-        if let ImplItemKind::Fn(ref sig, body_id) = item.kind {
-            let parent_item = cx.tcx.hir().get_parent_item(item.hir_id());
-            if let Some(Node::Item(it)) = cx.tcx.hir().find_by_def_id(parent_item) {
-                if let ItemKind::Impl(Impl { of_trait: Some(_), .. }) = it.kind {
-                    return; // ignore trait impls
-                }
+            check_mut_from_ref(cx, sig.decl);
+            for arg in check_fn_args(
+                cx,
+                cx.tcx.fn_sig(item.def_id).skip_binder().inputs(),
+                sig.decl.inputs,
+                &[],
+            ) {
+                span_lint_and_sugg(
+                    cx,
+                    PTR_ARG,
+                    arg.span,
+                    &arg.build_msg(),
+                    "change this to",
+                    format!("{}{}", arg.ref_prefix, arg.deref_ty.display(cx)),
+                    Applicability::Unspecified,
+                );
             }
-            check_fn(cx, sig.decl, Some(body_id));
         }
     }
 
-    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
-        if let TraitItemKind::Fn(ref sig, ref trait_method) = item.kind {
-            let body_id = if let TraitFn::Provided(b) = *trait_method {
-                Some(b)
-            } else {
-                None
-            };
-            check_fn(cx, sig.decl, body_id);
+    fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
+        let hir = cx.tcx.hir();
+        let mut parents = hir.parent_iter(body.value.hir_id);
+        let (item_id, decl) = match parents.next() {
+            Some((_, Node::Item(i))) => {
+                if let ItemKind::Fn(sig, ..) = &i.kind {
+                    (i.def_id, sig.decl)
+                } else {
+                    return;
+                }
+            },
+            Some((_, Node::ImplItem(i))) => {
+                if !matches!(parents.next(),
+                    Some((_, Node::Item(i))) if matches!(&i.kind, ItemKind::Impl(i) if i.of_trait.is_none())
+                ) {
+                    return;
+                }
+                if let ImplItemKind::Fn(sig, _) = &i.kind {
+                    (i.def_id, sig.decl)
+                } else {
+                    return;
+                }
+            },
+            Some((_, Node::TraitItem(i))) => {
+                if let TraitItemKind::Fn(sig, _) = &i.kind {
+                    (i.def_id, sig.decl)
+                } else {
+                    return;
+                }
+            },
+            _ => return,
+        };
+
+        check_mut_from_ref(cx, decl);
+        let sig = cx.tcx.fn_sig(item_id).skip_binder();
+        let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, body.params).collect();
+        let results = check_ptr_arg_usage(cx, body, &lint_args);
+
+        for (result, args) in results.iter().zip(lint_args.iter()).filter(|(r, _)| !r.skip) {
+            span_lint_and_then(cx, PTR_ARG, args.span, &args.build_msg(), |diag| {
+                diag.multipart_suggestion(
+                    "change this to",
+                    iter::once((args.span, format!("{}{}", args.ref_prefix, args.deref_ty.display(cx))))
+                        .chain(result.replacements.iter().map(|r| {
+                            (
+                                r.expr_span,
+                                format!("{}{}", snippet_opt(cx, r.self_span).unwrap(), r.replacement),
+                            )
+                        }))
+                        .collect(),
+                    Applicability::Unspecified,
+                );
+            });
         }
     }
 
@@ -247,154 +286,206 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
     }
 }
 
-#[allow(clippy::too_many_lines)]
-fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, opt_body_id: Option<BodyId>) {
-    let body = opt_body_id.map(|id| cx.tcx.hir().body(id));
-
-    for (idx, arg) in decl.inputs.iter().enumerate() {
-        // Honor the allow attribute on parameters. See issue 5644.
-        if let Some(body) = &body {
-            if is_lint_allowed(cx, PTR_ARG, body.params[idx].hir_id) {
-                continue;
-            }
-        }
+#[derive(Default)]
+struct PtrArgResult {
+    skip: bool,
+    replacements: Vec<PtrArgReplacement>,
+}
 
-        let (item_name, path) = if_chain! {
-            if let TyKind::Rptr(_, MutTy { ty, mutbl: Mutability::Not }) = arg.kind;
-            if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
-            if let Res::Def(_, did) = path.res;
-            if let Some(item_name) = cx.tcx.get_diagnostic_name(did);
-            then {
-                (item_name, path)
-            } else {
-                continue
-            }
-        };
+struct PtrArgReplacement {
+    expr_span: Span,
+    self_span: Span,
+    replacement: &'static str,
+}
 
-        match item_name {
-            sym::Vec => {
-                if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_owned()")]) {
-                    span_lint_and_then(
-                        cx,
-                        PTR_ARG,
-                        arg.span,
-                        "writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used \
-                         with non-Vec-based slices",
-                        |diag| {
-                            if let Some(ref snippet) = get_only_generic_arg_snippet(cx, arg) {
-                                diag.span_suggestion(
-                                    arg.span,
-                                    "change this to",
-                                    format!("&[{}]", snippet),
-                                    Applicability::Unspecified,
-                                );
-                            }
-                            for (clonespan, suggestion) in spans {
-                                diag.span_suggestion(
-                                    clonespan,
-                                    &snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
-                                        Cow::Owned(format!("change `{}` to", x))
-                                    }),
-                                    suggestion.into(),
-                                    Applicability::Unspecified,
-                                );
-                            }
-                        },
-                    );
-                }
+struct PtrArg<'tcx> {
+    idx: usize,
+    span: Span,
+    ty_did: DefId,
+    ty_name: Symbol,
+    method_renames: &'static [(&'static str, &'static str)],
+    ref_prefix: RefPrefix,
+    deref_ty: DerefTy<'tcx>,
+    deref_assoc_items: Option<(DefId, &'tcx AssocItems<'tcx>)>,
+}
+impl PtrArg<'_> {
+    fn build_msg(&self) -> String {
+        format!(
+            "writing `&{}{}` instead of `&{}{}` involves a new object where a slice will do",
+            self.ref_prefix.mutability.prefix_str(),
+            self.ty_name,
+            self.ref_prefix.mutability.prefix_str(),
+            self.deref_ty.argless_str(),
+        )
+    }
+}
+
+struct RefPrefix {
+    lt: LifetimeName,
+    mutability: Mutability,
+}
+impl fmt::Display for RefPrefix {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        use fmt::Write;
+        f.write_char('&')?;
+        match self.lt {
+            LifetimeName::Param(ParamName::Plain(name)) => {
+                name.fmt(f)?;
+                f.write_char(' ')?;
             },
-            sym::String => {
-                if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_string()"), ("as_str", "")]) {
-                    span_lint_and_then(
-                        cx,
-                        PTR_ARG,
-                        arg.span,
-                        "writing `&String` instead of `&str` involves a new object where a slice will do",
-                        |diag| {
-                            diag.span_suggestion(arg.span, "change this to", "&str".into(), Applicability::Unspecified);
-                            for (clonespan, suggestion) in spans {
-                                diag.span_suggestion_short(
-                                    clonespan,
-                                    &snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
-                                        Cow::Owned(format!("change `{}` to", x))
-                                    }),
-                                    suggestion.into(),
-                                    Applicability::Unspecified,
-                                );
-                            }
-                        },
-                    );
+            LifetimeName::Underscore => f.write_str("'_ ")?,
+            LifetimeName::Static => f.write_str("'static ")?,
+            _ => (),
+        }
+        f.write_str(self.mutability.prefix_str())
+    }
+}
+
+struct DerefTyDisplay<'a, 'tcx>(&'a LateContext<'tcx>, &'a DerefTy<'tcx>);
+impl fmt::Display for DerefTyDisplay<'_, '_> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        use std::fmt::Write;
+        match self.1 {
+            DerefTy::Str => f.write_str("str"),
+            DerefTy::Path => f.write_str("Path"),
+            DerefTy::Slice(hir_ty, ty) => {
+                f.write_char('[')?;
+                match hir_ty.and_then(|s| snippet_opt(self.0, s)) {
+                    Some(s) => f.write_str(&s)?,
+                    None => ty.fmt(f)?,
                 }
+                f.write_char(']')
             },
-            sym::PathBuf => {
-                if let Some(spans) = get_spans(cx, opt_body_id, idx, &[("clone", ".to_path_buf()"), ("as_path", "")]) {
-                    span_lint_and_then(
-                        cx,
-                        PTR_ARG,
-                        arg.span,
-                        "writing `&PathBuf` instead of `&Path` involves a new object where a slice will do",
-                        |diag| {
-                            diag.span_suggestion(
-                                arg.span,
+        }
+    }
+}
+
+enum DerefTy<'tcx> {
+    Str,
+    Path,
+    Slice(Option<Span>, Ty<'tcx>),
+}
+impl<'tcx> DerefTy<'tcx> {
+    fn argless_str(&self) -> &'static str {
+        match *self {
+            Self::Str => "str",
+            Self::Path => "Path",
+            Self::Slice(..) => "[_]",
+        }
+    }
+
+    fn display<'a>(&'a self, cx: &'a LateContext<'tcx>) -> DerefTyDisplay<'a, 'tcx> {
+        DerefTyDisplay(cx, self)
+    }
+}
+
+fn check_fn_args<'cx, 'tcx: 'cx>(
+    cx: &'cx LateContext<'tcx>,
+    tys: &'tcx [Ty<'_>],
+    hir_tys: &'tcx [hir::Ty<'_>],
+    params: &'tcx [Param<'_>],
+) -> impl Iterator<Item = PtrArg<'tcx>> + 'cx {
+    tys.iter()
+        .zip(hir_tys.iter())
+        .enumerate()
+        .filter_map(|(i, (ty, hir_ty))| {
+            if_chain! {
+                if let ty::Ref(_, ty, mutability) = *ty.kind();
+                if let ty::Adt(adt, substs) = *ty.kind();
+
+                if let TyKind::Rptr(lt, ref ty) = hir_ty.kind;
+                if let TyKind::Path(QPath::Resolved(None, path)) = ty.ty.kind;
+
+                // Check that the name as typed matches the actual name of the type.
+                // e.g. `fn foo(_: &Foo)` shouldn't trigger the lint when `Foo` is an alias for `Vec`
+                if let [.., name] = path.segments;
+                if cx.tcx.item_name(adt.did) == name.ident.name;
+
+                if !is_lint_allowed(cx, PTR_ARG, hir_ty.hir_id);
+                if params.get(i).map_or(true, |p| !is_lint_allowed(cx, PTR_ARG, p.hir_id));
+
+                then {
+                    let (method_renames, deref_ty, deref_impl_id) = match cx.tcx.get_diagnostic_name(adt.did) {
+                        Some(sym::Vec) => (
+                            [("clone", ".to_owned()")].as_slice(),
+                            DerefTy::Slice(
+                                name.args
+                                    .and_then(|args| args.args.first())
+                                    .and_then(|arg| if let GenericArg::Type(ty) = arg {
+                                        Some(ty.span)
+                                    } else {
+                                        None
+                                    }),
+                                substs.type_at(0),
+                            ),
+                            cx.tcx.lang_items().slice_impl()
+                        ),
+                        Some(sym::String) => (
+                            [("clone", ".to_owned()"), ("as_str", "")].as_slice(),
+                            DerefTy::Str,
+                            cx.tcx.lang_items().str_impl()
+                        ),
+                        Some(sym::PathBuf) => (
+                            [("clone", ".to_path_buf()"), ("as_path", "")].as_slice(),
+                            DerefTy::Path,
+                            None,
+                        ),
+                        Some(sym::Cow) => {
+                            let ty_name = name.args
+                                .and_then(|args| {
+                                    args.args.iter().find_map(|a| match a {
+                                        GenericArg::Type(x) => Some(x),
+                                        _ => None,
+                                    })
+                                })
+                                .and_then(|arg| snippet_opt(cx, arg.span))
+                                .unwrap_or_else(|| substs.type_at(1).to_string());
+                            span_lint_and_sugg(
+                                cx,
+                                PTR_ARG,
+                                hir_ty.span,
+                                "using a reference to `Cow` is not recommended",
                                 "change this to",
-                                "&Path".into(),
+                                format!("&{}{}", mutability.prefix_str(), ty_name),
                                 Applicability::Unspecified,
                             );
-                            for (clonespan, suggestion) in spans {
-                                diag.span_suggestion_short(
-                                    clonespan,
-                                    &snippet_opt(cx, clonespan).map_or("change the call to".into(), |x| {
-                                        Cow::Owned(format!("change `{}` to", x))
-                                    }),
-                                    suggestion.into(),
-                                    Applicability::Unspecified,
-                                );
-                            }
+                            return None;
                         },
-                    );
-                }
-            },
-            sym::Cow => {
-                if_chain! {
-                    if let [ref bx] = *path.segments;
-                    if let Some(params) = bx.args;
-                    if !params.parenthesized;
-                    if let Some(inner) = params.args.iter().find_map(|arg| match arg {
-                        GenericArg::Type(ty) => Some(ty),
-                        _ => None,
+                        _ => return None,
+                    };
+                    return Some(PtrArg {
+                        idx: i,
+                        span: hir_ty.span,
+                        ty_did: adt.did,
+                        ty_name: name.ident.name,
+                        method_renames,
+                        ref_prefix: RefPrefix {
+                            lt: lt.name,
+                            mutability,
+                        },
+                        deref_ty,
+                        deref_assoc_items: deref_impl_id.map(|id| (id, cx.tcx.associated_items(id))),
                     });
-                    let replacement = snippet_opt(cx, inner.span);
-                    if let Some(r) = replacement;
-                    then {
-                        span_lint_and_sugg(
-                            cx,
-                            PTR_ARG,
-                            arg.span,
-                            "using a reference to `Cow` is not recommended",
-                            "change this to",
-                            "&".to_owned() + &r,
-                            Applicability::Unspecified,
-                        );
-                    }
                 }
-            },
-            _ => {},
-        }
-    }
+            }
+            None
+        })
+}
 
+fn check_mut_from_ref(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
     if let FnRetTy::Return(ty) = decl.output {
         if let Some((out, Mutability::Mut, _)) = get_rptr_lm(ty) {
             let mut immutables = vec![];
-            for (_, ref mutbl, ref argspan) in decl
+            for (_, mutbl, argspan) in decl
                 .inputs
                 .iter()
                 .filter_map(get_rptr_lm)
                 .filter(|&(lt, _, _)| lt.name == out.name)
             {
-                if *mutbl == Mutability::Mut {
+                if mutbl == Mutability::Mut {
                     return;
                 }
-                immutables.push(*argspan);
+                immutables.push(argspan);
             }
             if immutables.is_empty() {
                 return;
@@ -413,24 +504,158 @@ fn check_fn(cx: &LateContext<'_>, decl: &FnDecl<'_>, opt_body_id: Option<BodyId>
     }
 }
 
-fn get_only_generic_arg_snippet(cx: &LateContext<'_>, arg: &Ty<'_>) -> Option<String> {
-    if_chain! {
-        if let TyKind::Path(QPath::Resolved(_, path)) = walk_ptrs_hir_ty(arg).kind;
-        if let Some(&PathSegment{args: Some(parameters), ..}) = path.segments.last();
-        let types: Vec<_> = parameters.args.iter().filter_map(|arg| match arg {
-            GenericArg::Type(ty) => Some(ty),
-            _ => None,
-        }).collect();
-        if types.len() == 1;
-        then {
-            snippet_opt(cx, types[0].span)
-        } else {
-            None
+#[allow(clippy::too_many_lines)]
+fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: &[PtrArg<'tcx>]) -> Vec<PtrArgResult> {
+    struct V<'cx, 'tcx> {
+        cx: &'cx LateContext<'tcx>,
+        /// Map from a local id to which argument it came from (index into `Self::args` and
+        /// `Self::results`)
+        bindings: HirIdMap<usize>,
+        /// The arguments being checked.
+        args: &'cx [PtrArg<'tcx>],
+        /// The results for each argument (len should match args.len)
+        results: Vec<PtrArgResult>,
+        /// The number of arguments which can't be linted. Used to return early.
+        skip_count: usize,
+    }
+    impl<'tcx> Visitor<'tcx> for V<'_, 'tcx> {
+        type NestedFilter = nested_filter::OnlyBodies;
+        fn nested_visit_map(&mut self) -> Self::Map {
+            self.cx.tcx.hir()
+        }
+
+        fn visit_anon_const(&mut self, _: &'tcx AnonConst) {}
+
+        fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
+            if self.skip_count == self.args.len() {
+                return;
+            }
+
+            // Check if this is local we care about
+            let args_idx = match path_to_local(e).and_then(|id| self.bindings.get(&id)) {
+                Some(&i) => i,
+                None => return walk_expr(self, e),
+            };
+            let args = &self.args[args_idx];
+            let result = &mut self.results[args_idx];
+
+            // Helper function to handle early returns.
+            let mut set_skip_flag = || {
+                if result.skip {
+                    self.skip_count += 1;
+                }
+                result.skip = true;
+            };
+
+            match get_expr_use_or_unification_node(self.cx.tcx, e) {
+                Some((Node::Stmt(_), _)) => (),
+                Some((Node::Local(l), _)) => {
+                    // Only trace simple bindings. e.g `let x = y;`
+                    if let PatKind::Binding(BindingAnnotation::Unannotated, id, _, None) = l.pat.kind {
+                        self.bindings.insert(id, args_idx);
+                    } else {
+                        set_skip_flag();
+                    }
+                },
+                Some((Node::Expr(e), child_id)) => match e.kind {
+                    ExprKind::Call(f, expr_args) => {
+                        let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0);
+                        if expr_sig(self.cx, f)
+                            .map(|sig| sig.input(i).skip_binder().peel_refs())
+                            .map_or(true, |ty| match *ty.kind() {
+                                ty::Param(_) => true,
+                                ty::Adt(def, _) => def.did == args.ty_did,
+                                _ => false,
+                            })
+                        {
+                            // Passed to a function taking the non-dereferenced type.
+                            set_skip_flag();
+                        }
+                    },
+                    ExprKind::MethodCall(name, expr_args @ [self_arg, ..], _) => {
+                        let i = expr_args.iter().position(|arg| arg.hir_id == child_id).unwrap_or(0);
+                        if i == 0 {
+                            // Check if the method can be renamed.
+                            let name = name.ident.as_str();
+                            if let Some((_, replacement)) = args.method_renames.iter().find(|&&(x, _)| x == name) {
+                                result.replacements.push(PtrArgReplacement {
+                                    expr_span: e.span,
+                                    self_span: self_arg.span,
+                                    replacement,
+                                });
+                                return;
+                            }
+                        }
+
+                        let id = if let Some(x) = self.cx.typeck_results().type_dependent_def_id(e.hir_id) {
+                            x
+                        } else {
+                            set_skip_flag();
+                            return;
+                        };
+
+                        match *self.cx.tcx.fn_sig(id).skip_binder().inputs()[i].peel_refs().kind() {
+                            ty::Param(_) => {
+                                set_skip_flag();
+                            },
+                            // If the types match check for methods which exist on both types. e.g. `Vec::len` and
+                            // `slice::len`
+                            ty::Adt(def, _)
+                                if def.did == args.ty_did
+                                    && (i != 0
+                                        || self.cx.tcx.trait_of_item(id).is_some()
+                                        || !args.deref_assoc_items.map_or(false, |(id, items)| {
+                                            items
+                                                .find_by_name_and_kind(self.cx.tcx, name.ident, AssocKind::Fn, id)
+                                                .is_some()
+                                        })) =>
+                            {
+                                set_skip_flag();
+                            },
+                            _ => (),
+                        }
+                    },
+                    // Indexing is fine for currently supported types.
+                    ExprKind::Index(e, _) if e.hir_id == child_id => (),
+                    _ => set_skip_flag(),
+                },
+                _ => set_skip_flag(),
+            }
         }
     }
+
+    let mut skip_count = 0;
+    let mut results = args.iter().map(|_| PtrArgResult::default()).collect::<Vec<_>>();
+    let mut v = V {
+        cx,
+        bindings: args
+            .iter()
+            .enumerate()
+            .filter_map(|(i, arg)| {
+                let param = &body.params[arg.idx];
+                match param.pat.kind {
+                    PatKind::Binding(BindingAnnotation::Unannotated, id, _, None)
+                        if !is_lint_allowed(cx, PTR_ARG, param.hir_id) =>
+                    {
+                        Some((id, i))
+                    },
+                    _ => {
+                        skip_count += 1;
+                        results[arg.idx].skip = true;
+                        None
+                    },
+                }
+            })
+            .collect(),
+        args,
+        results,
+        skip_count,
+    };
+    v.visit_expr(&body.value);
+    v.results
 }
 
-fn get_rptr_lm<'tcx>(ty: &'tcx Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
+fn get_rptr_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
     if let TyKind::Rptr(ref lt, ref m) = ty.kind {
         Some((lt, m.mutbl, ty.span))
     } else {
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index 52d47e6d978..027ab70014f 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -8,7 +8,7 @@ use if_chain::if_chain;
 use rustc_ast::ast::RangeLimits;
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, QPath};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
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 0c77cf5e77d..5a25008e95e 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -8,7 +8,7 @@ use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::intravisit as hir_visit;
 use rustc_hir::intravisit::Visitor as HirVisitor;
-use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -62,7 +62,7 @@ impl<'ast> ast_visit::Visitor<'ast> for ReturnVisitor {
 
 impl EarlyLintPass for RedundantClosureCall {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
-        if in_external_macro(cx.sess, expr.span) {
+        if in_external_macro(cx.sess(), expr.span) {
             return;
         }
         if_chain! {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_else.rs b/src/tools/clippy/clippy_lints/src/redundant_else.rs
index 93dbe936d58..73088ce1a87 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_else.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_else.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use rustc_ast::ast::{Block, Expr, ExprKind, Stmt, StmtKind};
 use rustc_ast::visit::{walk_expr, Visitor};
-use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
@@ -46,7 +46,7 @@ declare_lint_pass!(RedundantElse => [REDUNDANT_ELSE]);
 
 impl EarlyLintPass for RedundantElse {
     fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &Stmt) {
-        if in_external_macro(cx.sess, stmt.span) {
+        if in_external_macro(cx.sess(), stmt.span) {
             return;
         }
         // Only look at expressions that are a whole statement
diff --git a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
index 0dea4a784b2..40a62fd6d20 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::{meets_msrv, msrvs};
 use rustc_ast::ast::{Expr, ExprKind};
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
@@ -55,7 +55,7 @@ impl EarlyLintPass for RedundantFieldNames {
             return;
         }
 
-        if in_external_macro(cx.sess, expr.span) {
+        if in_external_macro(cx.sess(), expr.span) {
             return;
         }
         if let ExprKind::Struct(ref se) = expr.kind {
diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs
index b2448372370..811a7bb9c15 100644
--- a/src/tools/clippy/clippy_lints/src/reference.rs
+++ b/src/tools/clippy/clippy_lints/src/reference.rs
@@ -1,6 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::{snippet_opt, snippet_with_applicability};
-use clippy_utils::sugg::Sugg;
 use if_chain::if_chain;
 use rustc_ast::ast::{Expr, ExprKind, Mutability, UnOp};
 use rustc_errors::Applicability;
@@ -104,59 +103,3 @@ impl EarlyLintPass for DerefAddrOf {
         }
     }
 }
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for references in expressions that use
-    /// auto dereference.
-    ///
-    /// ### Why is this bad?
-    /// The reference is a no-op and is automatically
-    /// dereferenced by the compiler and makes the code less clear.
-    ///
-    /// ### Example
-    /// ```rust
-    /// struct Point(u32, u32);
-    /// let point = Point(30, 20);
-    /// let x = (&point).0;
-    /// ```
-    /// Use instead:
-    /// ```rust
-    /// # struct Point(u32, u32);
-    /// # let point = Point(30, 20);
-    /// let x = point.0;
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub REF_IN_DEREF,
-    complexity,
-    "Use of reference in auto dereference expression."
-}
-
-declare_lint_pass!(RefInDeref => [REF_IN_DEREF]);
-
-impl EarlyLintPass for RefInDeref {
-    fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
-        if_chain! {
-            if let ExprKind::Field(ref object, _) = e.kind;
-            if let ExprKind::Paren(ref parened) = object.kind;
-            if let ExprKind::AddrOf(_, _, ref inner) = parened.kind;
-            then {
-                let applicability = if inner.span.from_expansion() {
-                    Applicability::MaybeIncorrect
-                } else {
-                    Applicability::MachineApplicable
-                };
-                let sugg = Sugg::ast(cx, inner, "_").maybe_par();
-                span_lint_and_sugg(
-                    cx,
-                    REF_IN_DEREF,
-                    object.span,
-                    "creating a reference that is immediately dereferenced",
-                    "try this",
-                    sugg.to_string(),
-                    applicability,
-                );
-            }
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs
index 1bbaa104e60..22b45896955 100644
--- a/src/tools/clippy/clippy_lints/src/same_name_method.rs
+++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs
@@ -87,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
                                         .filter(|assoc_item| {
                                             matches!(assoc_item.kind, AssocKind::Fn)
                                         })
-                                        .map(|assoc_item| assoc_item.ident.name)
+                                        .map(|assoc_item| assoc_item.name)
                                         .collect()
                                 }else{
                                     BTreeSet::new()
diff --git a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
index ee82666b5af..aa306a630c4 100644
--- a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
+++ b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use rustc_ast::ast::{GenericParam, GenericParamKind};
-use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
@@ -43,7 +43,7 @@ declare_lint_pass!(SingleCharLifetimeNames => [SINGLE_CHAR_LIFETIME_NAMES]);
 
 impl EarlyLintPass for SingleCharLifetimeNames {
     fn check_generic_param(&mut self, ctx: &EarlyContext<'_>, param: &GenericParam) {
-        if in_external_macro(ctx.sess, param.ident.span) {
+        if in_external_macro(ctx.sess(), param.ident.span) {
             return;
         }
 
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 28d32203da9..961cdb317e7 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
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
 use rustc_ast::{ptr::P, Crate, Item, ItemKind, MacroDef, ModKind, UseTreeKind, VisibilityKind};
 use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::{edition::Edition, symbol::kw, Span, Symbol};
 
@@ -37,7 +37,7 @@ declare_lint_pass!(SingleComponentPathImports => [SINGLE_COMPONENT_PATH_IMPORTS]
 
 impl EarlyLintPass for SingleComponentPathImports {
     fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
-        if cx.sess.opts.edition < Edition::Edition2018 {
+        if cx.sess().opts.edition < Edition::Edition2018 {
             return;
         }
         check_mod(cx, &krate.items);
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index 6369aafe3f9..5257f5302cd 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability};
 use clippy_utils::{SpanlessEq, SpanlessHash};
 use core::hash::{Hash, Hasher};
 use if_chain::if_chain;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::unhash::UnhashMap;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -91,7 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) {
         let Generics { where_clause, .. } = &item.generics;
-        let mut self_bounds_set = FxHashSet::default();
+        let mut self_bounds_map = FxHashMap::default();
 
         for predicate in where_clause.predicates {
             if_chain! {
@@ -108,27 +108,29 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
                         )
                     ) = cx.tcx.hir().get_if_local(*def_id);
                 then {
-                    if self_bounds_set.is_empty() {
+                    if self_bounds_map.is_empty() {
                         for bound in self_bounds.iter() {
-                            let Some((self_res, _)) = get_trait_res_span_from_bound(bound) else { continue };
-                            self_bounds_set.insert(self_res);
+                            let Some((self_res, self_segments, _)) = get_trait_info_from_bound(bound) else { continue };
+                            self_bounds_map.insert(self_res, self_segments);
                         }
                     }
 
                     bound_predicate
                         .bounds
                         .iter()
-                        .filter_map(get_trait_res_span_from_bound)
-                        .for_each(|(trait_item_res, span)| {
-                            if self_bounds_set.get(&trait_item_res).is_some() {
-                                span_lint_and_help(
-                                    cx,
-                                    TRAIT_DUPLICATION_IN_BOUNDS,
-                                    span,
-                                    "this trait bound is already specified in trait declaration",
-                                    None,
-                                    "consider removing this trait bound",
-                                );
+                        .filter_map(get_trait_info_from_bound)
+                        .for_each(|(trait_item_res, trait_item_segments, span)| {
+                            if let Some(self_segments) = self_bounds_map.get(&trait_item_res) {
+                                if SpanlessEq::new(cx).eq_path_segments(self_segments, trait_item_segments) {
+                                    span_lint_and_help(
+                                        cx,
+                                        TRAIT_DUPLICATION_IN_BOUNDS,
+                                        span,
+                                        "this trait bound is already specified in trait declaration",
+                                        None,
+                                        "consider removing this trait bound",
+                                    );
+                                }
                             }
                         });
                 }
@@ -137,14 +139,6 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
     }
 }
 
-fn get_trait_res_span_from_bound(bound: &GenericBound<'_>) -> Option<(Res, Span)> {
-    if let GenericBound::Trait(t, _) = bound {
-        Some((t.trait_ref.path.res, t.span))
-    } else {
-        None
-    }
-}
-
 impl TraitBounds {
     fn check_type_repetition<'tcx>(self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) {
         struct SpanlessTy<'cx, 'tcx> {
@@ -231,7 +225,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
             let res = param
                 .bounds
                 .iter()
-                .filter_map(get_trait_res_span_from_bound)
+                .filter_map(get_trait_info_from_bound)
                 .collect::<Vec<_>>();
             map.insert(*ident, res);
         }
@@ -245,10 +239,10 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
             if let Some(segment) = segments.first();
             if let Some(trait_resolutions_direct) = map.get(&segment.ident);
             then {
-                for (res_where, _) in bound_predicate.bounds.iter().filter_map(get_trait_res_span_from_bound) {
-                    if let Some((_, span_direct)) = trait_resolutions_direct
+                for (res_where, _,  _) in bound_predicate.bounds.iter().filter_map(get_trait_info_from_bound) {
+                    if let Some((_, _, span_direct)) = trait_resolutions_direct
                                                 .iter()
-                                                .find(|(res_direct, _)| *res_direct == res_where) {
+                                                .find(|(res_direct, _, _)| *res_direct == res_where) {
                         span_lint_and_help(
                             cx,
                             TRAIT_DUPLICATION_IN_BOUNDS,
@@ -263,3 +257,11 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
         }
     }
 }
+
+fn get_trait_info_from_bound<'a>(bound: &'a GenericBound<'_>) -> Option<(Res, &'a [PathSegment<'a>], Span)> {
+    if let GenericBound::Trait(t, _) = bound {
+        Some((t.trait_ref.path.res, t.trait_ref.path.segments, t.span))
+    } else {
+        None
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index 141f2604872..eee1229e1ef 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -98,10 +98,11 @@ fn get_args_to_check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Ve
                         if trait_pred.self_ty() == inp;
                         if let Some(return_ty_pred) = get_projection_pred(cx, generics, *trait_pred);
                         then {
-                            if ord_preds.iter().any(|ord| Some(ord.self_ty()) ==
-                            return_ty_pred.term.ty()) {
+                            if ord_preds.iter().any(|ord| Some(ord.self_ty()) == return_ty_pred.term.ty()) {
                                 args_to_check.push((i, "Ord".to_string()));
-                            } else if partial_ord_preds.iter().any(|pord| pord.self_ty() == return_ty_pred.term.ty().unwrap()) {
+                            } else if partial_ord_preds.iter().any(|pord| {
+                                pord.self_ty() == return_ty_pred.term.ty().unwrap()
+                            }) {
                                 args_to_check.push((i, "PartialOrd".to_string()));
                             }
                         }
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index 0bd151fed91..1d4fe9cfd3c 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -291,7 +291,7 @@ fn transform_with_focus_on_idx(alternatives: &mut Vec<P<Pat>>, focus_idx: usize)
 fn extend_with_struct_pat(
     qself1: &Option<ast::QSelf>,
     path1: &ast::Path,
-    fps1: &mut Vec<ast::PatField>,
+    fps1: &mut [ast::PatField],
     rest1: bool,
     start: usize,
     alternatives: &mut Vec<P<Pat>>,
@@ -332,7 +332,7 @@ fn extend_with_struct_pat(
 /// while also requiring `ps1[..n] ~ ps2[..n]` (pre) and `ps1[n + 1..] ~ ps2[n + 1..]` (post),
 /// where `~` denotes semantic equality.
 fn extend_with_matching_product(
-    targets: &mut Vec<P<Pat>>,
+    targets: &mut [P<Pat>],
     start: usize,
     alternatives: &mut Vec<P<Pat>>,
     predicate: impl Fn(&PatKind, &[P<Pat>], usize) -> bool,
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index 6c5a5fe1434..be20282b3b8 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -11,7 +11,7 @@ use rustc_hir::{
     intravisit::{walk_inf, walk_ty, Visitor},
     Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Path, QPath, TyKind,
 };
-use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_lint::{LateContext, LateLintPass};
 use rustc_semver::RustcVersion;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::Span;
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index d6deb50cc90..c9d99617c1e 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -156,7 +156,7 @@ define_Conf! {
     ///
     /// Suppress lints whenever the suggested change would cause breakage for other crates.
     (avoid_breaking_exported_api: bool = true),
-    /// Lint: MANUAL_SPLIT_ONCE, 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, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE.
+    /// Lint: MANUAL_SPLIT_ONCE, 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, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS.
     ///
     /// The minimum rust version that the project supports
     (msrv: Option<String> = None),
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 ec1b5a499d4..f170ff69154 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
@@ -23,6 +23,7 @@ use rustc_hir::{
     UnOp,
 };
 use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
+use rustc_middle::hir::nested_filter;
 use rustc_middle::mir::interpret::ConstValue;
 use rustc_middle::ty;
 use rustc_semver::RustcVersion;
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 5ee3146eaab..3547f0b4e0a 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
@@ -19,7 +19,9 @@ use rustc_hir::{
     self as hir, def::DefKind, intravisit, intravisit::Visitor, ExprKind, Item, ItemKind, Mutability, QPath,
 };
 use rustc_lint::{CheckLintNameResult, LateContext, LateLintPass, LintContext, LintId};
+use rustc_middle::hir::nested_filter;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::symbol::Ident;
 use rustc_span::{sym, Loc, Span, Symbol};
 use serde::{ser::SerializeStruct, Serialize, Serializer};
 use std::collections::BinaryHeap;
@@ -578,9 +580,11 @@ fn get_lint_group_and_level_or_lint(
     lint_name: &str,
     item: &Item<'_>,
 ) -> Option<(String, &'static str)> {
-    let result = cx
-        .lint_store
-        .check_lint_name(cx.sess(), lint_name, Some(sym::clippy), &[]);
+    let result = cx.lint_store.check_lint_name(
+        lint_name,
+        Some(sym::clippy),
+        &[Ident::with_dummy_span(sym::clippy)].into_iter().collect(),
+    );
     if let CheckLintNameResult::Tool(Ok(lint_lst)) = result {
         if let Some(group) = get_lint_group(cx, lint_lst[0]) {
             if EXCLUDED_LINT_GROUPS.contains(&group.as_str()) {
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index f9add927b49..b0044695ea8 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -9,7 +9,7 @@ use rustc_ast::token::{self, LitKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_errors::Applicability;
 use rustc_lexer::unescape::{self, EscapeError};
-use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_parse::parser;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::symbol::{kw, Symbol};
@@ -290,7 +290,7 @@ impl EarlyLintPass for Write {
     fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &MacCall) {
         fn is_build_script(cx: &EarlyContext<'_>) -> bool {
             // Cargo sets the crate name for build scripts to `build_script_build`
-            cx.sess
+            cx.sess()
                 .opts
                 .crate_name
                 .as_ref()
@@ -529,7 +529,7 @@ impl Write {
     /// ```
     #[allow(clippy::too_many_lines)]
     fn check_tts<'a>(&self, cx: &EarlyContext<'a>, tts: TokenStream, is_write: bool) -> (Option<StrLit>, Option<Expr>) {
-        let mut parser = parser::Parser::new(&cx.sess.parse_sess, tts, false, None);
+        let mut parser = parser::Parser::new(&cx.sess().parse_sess, tts, false, None);
         let expr = if is_write {
             match parser
                 .parse_expr()
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 604c95d2bc8..3f4043ad052 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -646,11 +646,11 @@ pub fn eq_generic_bound(l: &GenericBound, r: &GenericBound) -> bool {
 }
 
 fn eq_term(l: &Term, r: &Term) -> bool {
-  match (l, r) {
-    (Term::Ty(l), Term::Ty(r)) => eq_ty(l,r),
-    (Term::Const(l), Term::Const(r)) => eq_anon_const(l,r),
-    _ => false,
-  }
+    match (l, r) {
+        (Term::Ty(l), Term::Ty(r)) => eq_ty(l, r),
+        (Term::Const(l), Term::Const(r)) => eq_anon_const(l, r),
+        _ => false,
+    }
 }
 
 pub fn eq_assoc_constraint(l: &AssocConstraint, r: &AssocConstraint) -> bool {
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 8386aaeaf44..a2f1f469651 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -117,25 +117,15 @@ pub fn meets_msrv(msrv: Option<&RustcVersion>, lint_msrv: &RustcVersion) -> bool
 
 #[macro_export]
 macro_rules! extract_msrv_attr {
-    (LateContext) => {
-        extract_msrv_attr!(@LateContext, ());
-    };
-    (EarlyContext) => {
-        extract_msrv_attr!(@EarlyContext);
-    };
-    (@$context:ident$(, $call:tt)?) => {
+    ($context:ident) => {
         fn enter_lint_attrs(&mut self, cx: &rustc_lint::$context<'_>, attrs: &[rustc_ast::ast::Attribute]) {
-            use $crate::get_unique_inner_attr;
-            match get_unique_inner_attr(cx.sess$($call)?, attrs, "msrv") {
+            let sess = rustc_lint::LintContext::sess(cx);
+            match $crate::get_unique_inner_attr(sess, attrs, "msrv") {
                 Some(msrv_attr) => {
                     if let Some(msrv) = msrv_attr.value_str() {
-                        self.msrv = $crate::parse_msrv(
-                            &msrv.to_string(),
-                            Some(cx.sess$($call)?),
-                            Some(msrv_attr.span),
-                        );
+                        self.msrv = $crate::parse_msrv(&msrv.to_string(), Some(sess), Some(msrv_attr.span));
                     } else {
-                        cx.sess$($call)?.span_err(msrv_attr.span, "bad clippy attribute");
+                        sess.span_err(msrv_attr.span, "bad clippy attribute");
                     }
                 },
                 _ => (),
@@ -1837,7 +1827,8 @@ pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool
 }
 
 /// Gets the node where an expression is either used, or it's type is unified with another branch.
-pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<Node<'tcx>> {
+/// Returns both the node and the `HirId` of the closest child node.
+pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<(Node<'tcx>, HirId)> {
     let mut child_id = expr.hir_id;
     let mut iter = tcx.hir().parent_iter(child_id);
     loop {
@@ -1849,9 +1840,9 @@ pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>
                 ExprKind::Match(_, [arm], _) if arm.hir_id == child_id => child_id = expr.hir_id,
                 ExprKind::Block(..) | ExprKind::DropTemps(_) => child_id = expr.hir_id,
                 ExprKind::If(_, then_expr, None) if then_expr.hir_id == child_id => break None,
-                _ => break Some(Node::Expr(expr)),
+                _ => break Some((Node::Expr(expr), child_id)),
             },
-            Some((_, node)) => break Some(node),
+            Some((_, node)) => break Some((node, child_id)),
         }
     }
 }
@@ -1860,18 +1851,21 @@ pub fn get_expr_use_or_unification_node<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>
 pub fn is_expr_used_or_unified(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> bool {
     !matches!(
         get_expr_use_or_unification_node(tcx, expr),
-        None | Some(Node::Stmt(Stmt {
-            kind: StmtKind::Expr(_)
-                | StmtKind::Semi(_)
-                | StmtKind::Local(Local {
-                    pat: Pat {
-                        kind: PatKind::Wild,
+        None | Some((
+            Node::Stmt(Stmt {
+                kind: StmtKind::Expr(_)
+                    | StmtKind::Semi(_)
+                    | StmtKind::Local(Local {
+                        pat: Pat {
+                            kind: PatKind::Wild,
+                            ..
+                        },
                         ..
-                    },
-                    ..
-                }),
-            ..
-        }))
+                    }),
+                ..
+            }),
+            _
+        ))
     )
 }
 
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index b7a242cf90a..a75f6b86a9b 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -339,15 +339,13 @@ impl<'tcx> FormatArgsExpn<'tcx> {
         expr_visitor_no_bodies(|e| {
             // if we're still inside of the macro definition...
             if e.span.ctxt() == expr.span.ctxt() {
-                // ArgumnetV1::new(<value>, <format_trait>::fmt)
+                // ArgumnetV1::new_<format_trait>(<value>)
                 if_chain! {
-                    if let ExprKind::Call(callee, [val, fmt_path]) = e.kind;
+                    if let ExprKind::Call(callee, [val]) = e.kind;
                     if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = callee.kind;
-                    if seg.ident.name == sym::new;
                     if let hir::TyKind::Path(QPath::Resolved(_, path)) = ty.kind;
                     if path.segments.last().unwrap().ident.name == sym::ArgumentV1;
-                    if let ExprKind::Path(QPath::Resolved(_, path)) = fmt_path.kind;
-                    if let [.., fmt_trait, _fmt] = path.segments;
+                    if seg.ident.name.as_str().starts_with("new_");
                     then {
                         let val_idx = if_chain! {
                             if val.span.ctxt() == expr.span.ctxt();
@@ -361,7 +359,19 @@ impl<'tcx> FormatArgsExpn<'tcx> {
                                 formatters.len()
                             }
                         };
-                        formatters.push((val_idx, fmt_trait.ident.name));
+                        let fmt_trait = match seg.ident.name.as_str() {
+                            "new_display" => "Display",
+                            "new_debug" => "Debug",
+                            "new_lower_exp" => "LowerExp",
+                            "new_upper_exp" => "UpperExp",
+                            "new_octal" => "Octal",
+                            "new_pointer" => "Pointer",
+                            "new_binary" => "Binary",
+                            "new_lower_hex" => "LowerHex",
+                            "new_upper_hex" => "UpperHex",
+                            _ => unreachable!(),
+                        };
+                        formatters.push((val_idx, Symbol::intern(fmt_trait)));
                     }
                 }
                 if let ExprKind::Struct(QPath::Resolved(_, path), ..) = e.kind {
diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
index 68dd1b29845..908ff822712 100644
--- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs
+++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
@@ -51,7 +51,14 @@ 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 unsigned_src = src.strip_prefix('-').map_or(src, |s| s);
+        if lit_kind.is_numeric()
+            && unsigned_src
+                .trim_start()
+                .chars()
+                .next()
+                .map_or(false, |c| c.is_digit(10))
+        {
             let (unsuffixed, suffix) = split_suffix(src, lit_kind);
             let float = matches!(lit_kind, LitKind::Float(..));
             Some(NumericLiteral::new(unsuffixed, suffix, float))
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 48525f9a572..fa63ddff253 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -386,7 +386,7 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String {
 }
 
 /// Return `true` if `sugg` is enclosed in parenthesis.
-fn has_enclosing_paren(sugg: impl AsRef<str>) -> bool {
+pub fn has_enclosing_paren(sugg: impl AsRef<str>) -> bool {
     let mut chars = sugg.as_ref().chars();
     if chars.next() == Some('(') {
         let mut depth = 1;
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index f109b7845b4..d057da73302 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -5,19 +5,22 @@
 use rustc_ast::ast::Mutability;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir as hir;
+use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::{TyKind, Unsafety};
+use rustc_hir::{Expr, TyKind, Unsafety};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
-use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
-use rustc_middle::ty::{self, AdtDef, IntTy, Predicate, Ty, TyCtxt, TypeFoldable, UintTy};
+use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
+use rustc_middle::ty::{
+    self, AdtDef, Binder, FnSig, IntTy, Predicate, PredicateKind, Ty, TyCtxt, TypeFoldable, UintTy,
+};
 use rustc_span::symbol::Ident;
 use rustc_span::{sym, Span, Symbol, DUMMY_SP};
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::query::normalize::AtExt;
 use std::iter;
 
-use crate::{match_def_path, must_use_attr};
+use crate::{expr_path_res, match_def_path, must_use_attr};
 
 // Checks if the given type implements copy.
 pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
@@ -410,3 +413,105 @@ pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator<Item = &(P
     })
     .flatten()
 }
+
+/// A signature for a function like type.
+#[derive(Clone, Copy)]
+pub enum ExprFnSig<'tcx> {
+    Sig(Binder<'tcx, FnSig<'tcx>>),
+    Closure(Binder<'tcx, FnSig<'tcx>>),
+    Trait(Binder<'tcx, Ty<'tcx>>, Option<Binder<'tcx, Ty<'tcx>>>),
+}
+impl<'tcx> ExprFnSig<'tcx> {
+    /// Gets the argument type at the given offset.
+    pub fn input(self, i: usize) -> Binder<'tcx, Ty<'tcx>> {
+        match self {
+            Self::Sig(sig) => sig.input(i),
+            Self::Closure(sig) => sig.input(0).map_bound(|ty| ty.tuple_element_ty(i).unwrap()),
+            Self::Trait(inputs, _) => inputs.map_bound(|ty| ty.tuple_element_ty(i).unwrap()),
+        }
+    }
+
+    /// Gets the result type, if one could be found. Note that the result type of a trait may not be
+    /// specified.
+    pub fn output(self) -> Option<Binder<'tcx, Ty<'tcx>>> {
+        match self {
+            Self::Sig(sig) | Self::Closure(sig) => Some(sig.output()),
+            Self::Trait(_, output) => output,
+        }
+    }
+}
+
+/// If the expression is function like, get the signature for it.
+pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnSig<'tcx>> {
+    if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) = expr_path_res(cx, expr) {
+        Some(ExprFnSig::Sig(cx.tcx.fn_sig(id)))
+    } else {
+        let ty = cx.typeck_results().expr_ty_adjusted(expr).peel_refs();
+        match *ty.kind() {
+            ty::Closure(_, subs) => Some(ExprFnSig::Closure(subs.as_closure().sig())),
+            ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).subst(cx.tcx, subs))),
+            ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig)),
+            ty::Dynamic(bounds, _) => {
+                let lang_items = cx.tcx.lang_items();
+                match bounds.principal() {
+                    Some(bound)
+                        if Some(bound.def_id()) == lang_items.fn_trait()
+                            || Some(bound.def_id()) == lang_items.fn_once_trait()
+                            || Some(bound.def_id()) == lang_items.fn_mut_trait() =>
+                    {
+                        let output = bounds
+                            .projection_bounds()
+                            .find(|p| lang_items.fn_once_output().map_or(false, |id| id == p.item_def_id()))
+                            .map(|p| p.map_bound(|p| p.term.ty().expect("return type was a const")));
+                        Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output))
+                    },
+                    _ => None,
+                }
+            },
+            ty::Param(_) | ty::Projection(..) => {
+                let mut inputs = None;
+                let mut output = None;
+                let lang_items = cx.tcx.lang_items();
+
+                for (pred, _) in all_predicates_of(cx.tcx, cx.typeck_results().hir_owner.to_def_id()) {
+                    let mut is_input = false;
+                    if let Some(ty) = pred
+                        .kind()
+                        .map_bound(|pred| match pred {
+                            PredicateKind::Trait(p)
+                                if (lang_items.fn_trait() == Some(p.def_id())
+                                    || lang_items.fn_mut_trait() == Some(p.def_id())
+                                    || lang_items.fn_once_trait() == Some(p.def_id()))
+                                    && p.self_ty() == ty =>
+                            {
+                                is_input = true;
+                                Some(p.trait_ref.substs.type_at(1))
+                            },
+                            PredicateKind::Projection(p)
+                                if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output()
+                                    && p.projection_ty.self_ty() == ty =>
+                            {
+                                is_input = false;
+                                p.term.ty()
+                            },
+                            _ => None,
+                        })
+                        .transpose()
+                    {
+                        if is_input && inputs.is_none() {
+                            inputs = Some(ty);
+                        } else if !is_input && output.is_none() {
+                            output = Some(ty);
+                        } else {
+                            // Multiple different fn trait impls. Is this even allowed?
+                            return None;
+                        }
+                    }
+                }
+
+                inputs.map(|ty| ExprFnSig::Trait(ty, output))
+            },
+            _ => None,
+        }
+    }
+}
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index e6a58e92072..e23dc73ab08 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-01-13"
+channel = "nightly-2022-01-27"
 components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index a8aa3a76abc..8f8f1140a3d 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -331,11 +331,10 @@ pub fn main() {
         // - IF Clippy is run on the main crate, not on deps (`!cap_lints_allow`) THEN
         //    - IF `--no-deps` is not set (`!no_deps`) OR
         //    - IF `--no-deps` is set and Clippy is run on the specified primary package
-        let clippy_tests_set = env::var("__CLIPPY_INTERNAL_TESTS").map_or(false, |val| val == "true");
         let cap_lints_allow = arg_value(&orig_args, "--cap-lints", |val| val == "allow").is_some();
         let in_primary_package = env::var("CARGO_PRIMARY_PACKAGE").is_ok();
 
-        let clippy_enabled = clippy_tests_set || (!cap_lints_allow && (!no_deps || in_primary_package));
+        let clippy_enabled = !cap_lints_allow && (!no_deps || in_primary_package);
         if clippy_enabled {
             args.extend(clippy_args);
         }
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index 531890c863f..6505028db9f 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -328,15 +328,9 @@ fn run_ui_cargo(config: &mut compiletest::Config) {
     }
 }
 
-fn prepare_env() {
-    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
-    set_var("__CLIPPY_INTERNAL_TESTS", "true");
-    //set_var("RUST_BACKTRACE", "0");
-}
-
 #[test]
 fn compile_test() {
-    prepare_env();
+    set_var("CLIPPY_DISABLE_DOCS_LINKS", "true");
     let mut config = default_config();
     run_ui(&mut config);
     run_ui_test(&mut config);
diff --git a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs
index 8e104926524..1e3ec123a3c 100644
--- a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs
+++ b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.rs
@@ -1,6 +1,7 @@
-#![allow(clippy::redundant_clone)]
-#![warn(clippy::manual_non_exhaustive)]
+#![allow(clippy::redundant_clone, clippy::unnecessary_operation)]
+#![warn(clippy::manual_non_exhaustive, clippy::borrow_as_ptr, clippy::manual_bits)]
 
+use std::mem::{size_of, size_of_val};
 use std::ops::Deref;
 
 mod enums {
@@ -68,6 +69,24 @@ fn check_index_refutable_slice() {
     }
 }
 
+fn map_clone_suggest_copied() {
+    // This should still trigger the lint but suggest `cloned()` instead of `copied()`
+    let _: Option<u64> = Some(&16).map(|b| *b);
+}
+
+fn borrow_as_ptr() {
+    let val = 1;
+    let _p = &val as *const i32;
+
+    let mut val_mut = 1;
+    let _p_mut = &mut val_mut as *mut i32;
+}
+
+fn manual_bits() {
+    size_of::<i8>() * 8;
+    size_of_val(&0u32) * 8;
+}
+
 fn main() {
     option_as_ref_deref();
     match_like_matches();
@@ -75,4 +94,5 @@ fn main() {
     match_same_arms2();
     manual_strip_msrv();
     check_index_refutable_slice();
+    borrow_as_ptr();
 }
diff --git a/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.stderr b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.stderr
new file mode 100644
index 00000000000..a1e7361c0cb
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/min_rust_version/min_rust_version.stderr
@@ -0,0 +1,10 @@
+error: you are using an explicit closure for copying elements
+  --> $DIR/min_rust_version.rs:74:26
+   |
+LL |     let _: Option<u64> = Some(&16).map(|b| *b);
+   |                          ^^^^^^^^^^^^^^^^^^^^^ help: consider calling the dedicated `cloned` method: `Some(&16).cloned()`
+   |
+   = note: `-D clippy::map-clone` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
index 4327f12c37c..eefeb1decb6 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.rs
@@ -1,9 +1,5 @@
 #![warn(clippy::borrow_interior_mutable_const)]
-#![allow(
-    clippy::declare_interior_mutable_const,
-    clippy::ref_in_deref,
-    clippy::needless_borrow
-)]
+#![allow(clippy::declare_interior_mutable_const, clippy::needless_borrow)]
 #![allow(const_item_mutation)]
 
 use std::borrow::Cow;
diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
index f146b97cf61..9a908cf30e9 100644
--- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
+++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/others.stderr
@@ -1,5 +1,5 @@
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:58:5
+  --> $DIR/others.rs:54:5
    |
 LL |     ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
    |     ^^^^^^
@@ -8,7 +8,7 @@ LL |     ATOMIC.store(1, Ordering::SeqCst); //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:59:16
+  --> $DIR/others.rs:55:16
    |
 LL |     assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutability
    |                ^^^^^^
@@ -16,7 +16,7 @@ LL |     assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ ERROR interior mutabi
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:62:22
+  --> $DIR/others.rs:58:22
    |
 LL |     let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
    |                      ^^^^^^^^^
@@ -24,7 +24,7 @@ LL |     let _once_ref = &ONCE_INIT; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:63:25
+  --> $DIR/others.rs:59:25
    |
 LL |     let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
    |                         ^^^^^^^^^
@@ -32,7 +32,7 @@ LL |     let _once_ref_2 = &&ONCE_INIT; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:64:27
+  --> $DIR/others.rs:60:27
    |
 LL |     let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
    |                           ^^^^^^^^^
@@ -40,7 +40,7 @@ LL |     let _once_ref_4 = &&&&ONCE_INIT; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:65:26
+  --> $DIR/others.rs:61:26
    |
 LL |     let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
    |                          ^^^^^^^^^
@@ -48,7 +48,7 @@ LL |     let _once_mut = &mut ONCE_INIT; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:76:14
+  --> $DIR/others.rs:72:14
    |
 LL |     let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
    |              ^^^^^^^^^^^^
@@ -56,7 +56,7 @@ LL |     let _ = &ATOMIC_TUPLE; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:77:14
+  --> $DIR/others.rs:73:14
    |
 LL |     let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
    |              ^^^^^^^^^^^^
@@ -64,7 +64,7 @@ LL |     let _ = &ATOMIC_TUPLE.0; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:78:19
+  --> $DIR/others.rs:74:19
    |
 LL |     let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
    |                   ^^^^^^^^^^^^
@@ -72,7 +72,7 @@ LL |     let _ = &(&&&&ATOMIC_TUPLE).0; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:79:14
+  --> $DIR/others.rs:75:14
    |
 LL |     let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
    |              ^^^^^^^^^^^^
@@ -80,7 +80,7 @@ LL |     let _ = &ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:80:13
+  --> $DIR/others.rs:76:13
    |
 LL |     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mutability
    |             ^^^^^^^^^^^^
@@ -88,7 +88,7 @@ LL |     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ ERROR interior mu
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:86:13
+  --> $DIR/others.rs:82:13
    |
 LL |     let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
    |             ^^^^^^^^^^^^
@@ -96,7 +96,7 @@ LL |     let _ = ATOMIC_TUPLE.0[0]; //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:91:5
+  --> $DIR/others.rs:87:5
    |
 LL |     CELL.set(2); //~ ERROR interior mutability
    |     ^^^^
@@ -104,7 +104,7 @@ LL |     CELL.set(2); //~ ERROR interior mutability
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> $DIR/others.rs:92:16
+  --> $DIR/others.rs:88:16
    |
 LL |     assert_eq!(CELL.get(), 6); //~ ERROR interior mutability
    |                ^^^^
diff --git a/src/tools/clippy/tests/ui/bytecount.rs b/src/tools/clippy/tests/ui/bytecount.rs
index c724ee21be3..d3ad26921bf 100644
--- a/src/tools/clippy/tests/ui/bytecount.rs
+++ b/src/tools/clippy/tests/ui/bytecount.rs
@@ -1,3 +1,5 @@
+#![allow(clippy::needless_borrow)]
+
 #[deny(clippy::naive_bytecount)]
 fn main() {
     let x = vec![0_u8; 16];
diff --git a/src/tools/clippy/tests/ui/bytecount.stderr b/src/tools/clippy/tests/ui/bytecount.stderr
index 1dc37fc8b25..68d838c1f82 100644
--- a/src/tools/clippy/tests/ui/bytecount.stderr
+++ b/src/tools/clippy/tests/ui/bytecount.stderr
@@ -1,23 +1,23 @@
 error: you appear to be counting bytes the naive way
-  --> $DIR/bytecount.rs:5:13
+  --> $DIR/bytecount.rs:7:13
    |
 LL |     let _ = x.iter().filter(|&&a| a == 0).count(); // naive byte count
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the bytecount crate: `bytecount::count(x, 0)`
    |
 note: the lint level is defined here
-  --> $DIR/bytecount.rs:1:8
+  --> $DIR/bytecount.rs:3:8
    |
 LL | #[deny(clippy::naive_bytecount)]
    |        ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: you appear to be counting bytes the naive way
-  --> $DIR/bytecount.rs:7:13
+  --> $DIR/bytecount.rs:9:13
    |
 LL |     let _ = (&x[..]).iter().filter(|&a| *a == 0).count(); // naive byte count
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the bytecount crate: `bytecount::count((&x[..]), 0)`
 
 error: you appear to be counting bytes the naive way
-  --> $DIR/bytecount.rs:19:13
+  --> $DIR/bytecount.rs:21:13
    |
 LL |     let _ = x.iter().filter(|a| b + 1 == **a).count(); // naive byte count
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the bytecount crate: `bytecount::count(x, b + 1)`
diff --git a/src/tools/clippy/tests/ui/clone_on_copy.fixed b/src/tools/clippy/tests/ui/clone_on_copy.fixed
index 8d43f64768d..dc062762604 100644
--- a/src/tools/clippy/tests/ui/clone_on_copy.fixed
+++ b/src/tools/clippy/tests/ui/clone_on_copy.fixed
@@ -7,7 +7,8 @@
     clippy::no_effect,
     clippy::unnecessary_operation,
     clippy::vec_init_then_push,
-    clippy::toplevel_ref_arg
+    clippy::toplevel_ref_arg,
+    clippy::needless_borrow
 )]
 
 use std::cell::RefCell;
diff --git a/src/tools/clippy/tests/ui/clone_on_copy.rs b/src/tools/clippy/tests/ui/clone_on_copy.rs
index f15501f7184..8c39d0d55dd 100644
--- a/src/tools/clippy/tests/ui/clone_on_copy.rs
+++ b/src/tools/clippy/tests/ui/clone_on_copy.rs
@@ -7,7 +7,8 @@
     clippy::no_effect,
     clippy::unnecessary_operation,
     clippy::vec_init_then_push,
-    clippy::toplevel_ref_arg
+    clippy::toplevel_ref_arg,
+    clippy::needless_borrow
 )]
 
 use std::cell::RefCell;
diff --git a/src/tools/clippy/tests/ui/clone_on_copy.stderr b/src/tools/clippy/tests/ui/clone_on_copy.stderr
index e7d28b4320b..861543d0aa9 100644
--- a/src/tools/clippy/tests/ui/clone_on_copy.stderr
+++ b/src/tools/clippy/tests/ui/clone_on_copy.stderr
@@ -1,5 +1,5 @@
 error: using `clone` on type `i32` which implements the `Copy` trait
-  --> $DIR/clone_on_copy.rs:24:5
+  --> $DIR/clone_on_copy.rs:25:5
    |
 LL |     42.clone();
    |     ^^^^^^^^^^ help: try removing the `clone` call: `42`
@@ -7,43 +7,43 @@ LL |     42.clone();
    = note: `-D clippy::clone-on-copy` implied by `-D warnings`
 
 error: using `clone` on type `i32` which implements the `Copy` trait
-  --> $DIR/clone_on_copy.rs:28:5
+  --> $DIR/clone_on_copy.rs:29:5
    |
 LL |     (&42).clone();
    |     ^^^^^^^^^^^^^ help: try dereferencing it: `*(&42)`
 
 error: using `clone` on type `i32` which implements the `Copy` trait
-  --> $DIR/clone_on_copy.rs:31:5
+  --> $DIR/clone_on_copy.rs:32:5
    |
 LL |     rc.borrow().clone();
    |     ^^^^^^^^^^^^^^^^^^^ help: try dereferencing it: `*rc.borrow()`
 
 error: using `clone` on type `u32` which implements the `Copy` trait
-  --> $DIR/clone_on_copy.rs:34:5
+  --> $DIR/clone_on_copy.rs:35:5
    |
 LL |     x.clone().rotate_left(1);
    |     ^^^^^^^^^ help: try removing the `clone` call: `x`
 
 error: using `clone` on type `i32` which implements the `Copy` trait
-  --> $DIR/clone_on_copy.rs:48:5
+  --> $DIR/clone_on_copy.rs:49:5
    |
 LL |     m!(42).clone();
    |     ^^^^^^^^^^^^^^ help: try removing the `clone` call: `m!(42)`
 
 error: using `clone` on type `[u32; 2]` which implements the `Copy` trait
-  --> $DIR/clone_on_copy.rs:58:5
+  --> $DIR/clone_on_copy.rs:59:5
    |
 LL |     x.clone()[0];
    |     ^^^^^^^^^ help: try dereferencing it: `(*x)`
 
 error: using `clone` on type `char` which implements the `Copy` trait
-  --> $DIR/clone_on_copy.rs:68:14
+  --> $DIR/clone_on_copy.rs:69:14
    |
 LL |     is_ascii('z'.clone());
    |              ^^^^^^^^^^^ help: try removing the `clone` call: `'z'`
 
 error: using `clone` on type `i32` which implements the `Copy` trait
-  --> $DIR/clone_on_copy.rs:72:14
+  --> $DIR/clone_on_copy.rs:73:14
    |
 LL |     vec.push(42.clone());
    |              ^^^^^^^^^^ help: try removing the `clone` call: `42`
diff --git a/src/tools/clippy/tests/ui/duration_subsec.fixed b/src/tools/clippy/tests/ui/duration_subsec.fixed
index ee5c7863eff..d92b8998e88 100644
--- a/src/tools/clippy/tests/ui/duration_subsec.fixed
+++ b/src/tools/clippy/tests/ui/duration_subsec.fixed
@@ -1,5 +1,5 @@
 // run-rustfix
-#![allow(dead_code)]
+#![allow(dead_code, clippy::needless_borrow)]
 #![warn(clippy::duration_subsec)]
 
 use std::time::Duration;
diff --git a/src/tools/clippy/tests/ui/duration_subsec.rs b/src/tools/clippy/tests/ui/duration_subsec.rs
index 3c9d2a28621..08da804996d 100644
--- a/src/tools/clippy/tests/ui/duration_subsec.rs
+++ b/src/tools/clippy/tests/ui/duration_subsec.rs
@@ -1,5 +1,5 @@
 // run-rustfix
-#![allow(dead_code)]
+#![allow(dead_code, clippy::needless_borrow)]
 #![warn(clippy::duration_subsec)]
 
 use std::time::Duration;
diff --git a/src/tools/clippy/tests/ui/enum_variants.rs b/src/tools/clippy/tests/ui/enum_variants.rs
index d3662a0a213..b2bf7c4e360 100644
--- a/src/tools/clippy/tests/ui/enum_variants.rs
+++ b/src/tools/clippy/tests/ui/enum_variants.rs
@@ -151,4 +151,11 @@ enum North {
     NoRight,
 }
 
+// #8324
+enum Phase {
+    PreLookup,
+    Lookup,
+    PostLookup,
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed
index f938f710688..618f80cdcf8 100644
--- a/src/tools/clippy/tests/ui/eta.fixed
+++ b/src/tools/clippy/tests/ui/eta.fixed
@@ -5,13 +5,10 @@
     clippy::no_effect,
     clippy::redundant_closure_call,
     clippy::needless_pass_by_value,
-    clippy::option_map_unit_fn
-)]
-#![warn(
-    clippy::redundant_closure,
-    clippy::redundant_closure_for_method_calls,
+    clippy::option_map_unit_fn,
     clippy::needless_borrow
 )]
+#![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)]
 
 use std::path::{Path, PathBuf};
 
@@ -34,7 +31,7 @@ fn main() {
     Some(1).map(closure_mac!()); // don't lint closure in macro expansion
     let _: Option<Vec<u8>> = true.then(std::vec::Vec::new); // special case vec!
     let d = Some(1u8).map(|a| foo(foo2(a))); //is adjusted?
-    all(&[1, 2, 3], &2, below); //is adjusted
+    all(&[1, 2, 3], &&2, below); //is adjusted
     unsafe {
         Some(1u8).map(|a| unsafe_fn(a)); // unsafe fn
     }
diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs
index 075bbc74922..a759e6eb514 100644
--- a/src/tools/clippy/tests/ui/eta.rs
+++ b/src/tools/clippy/tests/ui/eta.rs
@@ -5,13 +5,10 @@
     clippy::no_effect,
     clippy::redundant_closure_call,
     clippy::needless_pass_by_value,
-    clippy::option_map_unit_fn
-)]
-#![warn(
-    clippy::redundant_closure,
-    clippy::redundant_closure_for_method_calls,
+    clippy::option_map_unit_fn,
     clippy::needless_borrow
 )]
+#![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)]
 
 use std::path::{Path, PathBuf};
 
diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr
index 8092f04c3fc..cda84982c9b 100644
--- a/src/tools/clippy/tests/ui/eta.stderr
+++ b/src/tools/clippy/tests/ui/eta.stderr
@@ -1,5 +1,5 @@
 error: redundant closure
-  --> $DIR/eta.rs:31:27
+  --> $DIR/eta.rs:28:27
    |
 LL |     let a = Some(1u8).map(|a| foo(a));
    |                           ^^^^^^^^^^ help: replace the closure with the function itself: `foo`
@@ -7,45 +7,37 @@ LL |     let a = Some(1u8).map(|a| foo(a));
    = note: `-D clippy::redundant-closure` implied by `-D warnings`
 
 error: redundant closure
-  --> $DIR/eta.rs:35:40
+  --> $DIR/eta.rs:32:40
    |
 LL |     let _: Option<Vec<u8>> = true.then(|| vec![]); // special case vec!
    |                                        ^^^^^^^^^ help: replace the closure with `Vec::new`: `std::vec::Vec::new`
 
 error: redundant closure
-  --> $DIR/eta.rs:36:35
+  --> $DIR/eta.rs:33:35
    |
 LL |     let d = Some(1u8).map(|a| foo((|b| foo2(b))(a))); //is adjusted?
    |                                   ^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo2`
 
-error: this expression borrows a reference (`&u8`) that is immediately dereferenced by the compiler
-  --> $DIR/eta.rs:37:21
-   |
-LL |     all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted
-   |                     ^^^ help: change this to: `&2`
-   |
-   = note: `-D clippy::needless-borrow` implied by `-D warnings`
-
 error: redundant closure
-  --> $DIR/eta.rs:37:26
+  --> $DIR/eta.rs:34:26
    |
 LL |     all(&[1, 2, 3], &&2, |x, y| below(x, y)); //is adjusted
    |                          ^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `below`
 
 error: redundant closure
-  --> $DIR/eta.rs:43:27
+  --> $DIR/eta.rs:40:27
    |
 LL |     let e = Some(1u8).map(|a| divergent(a));
    |                           ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `divergent`
 
 error: redundant closure
-  --> $DIR/eta.rs:44:27
+  --> $DIR/eta.rs:41:27
    |
 LL |     let e = Some(1u8).map(|a| generic(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic`
 
 error: redundant closure
-  --> $DIR/eta.rs:90:51
+  --> $DIR/eta.rs:87:51
    |
 LL |     let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo());
    |                                                   ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo`
@@ -53,82 +45,82 @@ 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:88: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:93:42
+  --> $DIR/eta.rs:90: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:97:29
+  --> $DIR/eta.rs:94: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:98:27
+  --> $DIR/eta.rs:95: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:100:65
+  --> $DIR/eta.rs:97: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:163:22
+  --> $DIR/eta.rs:160:22
    |
 LL |     requires_fn_once(|| x());
    |                      ^^^^^^ help: replace the closure with the function itself: `x`
 
 error: redundant closure
-  --> $DIR/eta.rs:170:27
+  --> $DIR/eta.rs:167: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:175:27
+  --> $DIR/eta.rs:172:27
    |
 LL |     let a = Some(1u8).map(|a| closure(a));
    |                           ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure`
 
 error: redundant closure
-  --> $DIR/eta.rs:207:28
+  --> $DIR/eta.rs:204:28
    |
 LL |     x.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
 
 error: redundant closure
-  --> $DIR/eta.rs:208:28
+  --> $DIR/eta.rs:205:28
    |
 LL |     y.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut add_to_res`
 
 error: redundant closure
-  --> $DIR/eta.rs:209:28
+  --> $DIR/eta.rs:206:28
    |
 LL |     z.into_iter().for_each(|x| add_to_res(x));
    |                            ^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `add_to_res`
 
 error: redundant closure
-  --> $DIR/eta.rs:216:21
+  --> $DIR/eta.rs:213:21
    |
 LL |         Some(1).map(|n| closure(n));
    |                     ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut closure`
 
 error: redundant closure
-  --> $DIR/eta.rs:235:21
+  --> $DIR/eta.rs:232:21
    |
 LL |     map_str_to_path(|s| s.as_ref());
    |                     ^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::convert::AsRef::as_ref`
 
-error: aborting due to 21 previous errors
+error: aborting due to 20 previous errors
 
diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.fixed b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed
index 48e2aae75d0..3de2a51ffa5 100644
--- a/src/tools/clippy/tests/ui/explicit_deref_methods.fixed
+++ b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![allow(unused_variables, clippy::clone_double_ref)]
+#![allow(unused_variables, clippy::clone_double_ref, clippy::needless_borrow)]
 #![warn(clippy::explicit_deref_methods)]
 
 use std::ops::{Deref, DerefMut};
diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.rs b/src/tools/clippy/tests/ui/explicit_deref_methods.rs
index d8c8c0c5ca3..a08d7596422 100644
--- a/src/tools/clippy/tests/ui/explicit_deref_methods.rs
+++ b/src/tools/clippy/tests/ui/explicit_deref_methods.rs
@@ -1,6 +1,6 @@
 // run-rustfix
 
-#![allow(unused_variables, clippy::clone_double_ref)]
+#![allow(unused_variables, clippy::clone_double_ref, clippy::needless_borrow)]
 #![warn(clippy::explicit_deref_methods)]
 
 use std::ops::{Deref, DerefMut};
diff --git a/src/tools/clippy/tests/ui/for_loop_fixable.fixed b/src/tools/clippy/tests/ui/for_loop_fixable.fixed
index f373e905d05..aa69781d15a 100644
--- a/src/tools/clippy/tests/ui/for_loop_fixable.fixed
+++ b/src/tools/clippy/tests/ui/for_loop_fixable.fixed
@@ -23,7 +23,12 @@ impl Unrelated {
     clippy::iter_next_loop,
     clippy::for_kv_map
 )]
-#[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)]
+#[allow(
+    clippy::linkedlist,
+    clippy::unnecessary_mut_passed,
+    clippy::similar_names,
+    clippy::needless_borrow
+)]
 #[allow(unused_variables)]
 fn main() {
     let mut vec = vec![1, 2, 3, 4];
diff --git a/src/tools/clippy/tests/ui/for_loop_fixable.rs b/src/tools/clippy/tests/ui/for_loop_fixable.rs
index 3814583bb6e..7c063d99511 100644
--- a/src/tools/clippy/tests/ui/for_loop_fixable.rs
+++ b/src/tools/clippy/tests/ui/for_loop_fixable.rs
@@ -23,7 +23,12 @@ impl Unrelated {
     clippy::iter_next_loop,
     clippy::for_kv_map
 )]
-#[allow(clippy::linkedlist, clippy::unnecessary_mut_passed, clippy::similar_names)]
+#[allow(
+    clippy::linkedlist,
+    clippy::unnecessary_mut_passed,
+    clippy::similar_names,
+    clippy::needless_borrow
+)]
 #[allow(unused_variables)]
 fn main() {
     let mut vec = vec![1, 2, 3, 4];
diff --git a/src/tools/clippy/tests/ui/for_loop_fixable.stderr b/src/tools/clippy/tests/ui/for_loop_fixable.stderr
index 009dbe1a0bf..ddfe66d675f 100644
--- a/src/tools/clippy/tests/ui/for_loop_fixable.stderr
+++ b/src/tools/clippy/tests/ui/for_loop_fixable.stderr
@@ -1,5 +1,5 @@
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/for_loop_fixable.rs:38:15
+  --> $DIR/for_loop_fixable.rs:43:15
    |
 LL |     for _v in vec.iter() {}
    |               ^^^^^^^^^^ help: to write this more concisely, try: `&vec`
@@ -7,13 +7,13 @@ LL |     for _v in vec.iter() {}
    = note: `-D clippy::explicit-iter-loop` implied by `-D warnings`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/for_loop_fixable.rs:40:15
+  --> $DIR/for_loop_fixable.rs:45:15
    |
 LL |     for _v in vec.iter_mut() {}
    |               ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&mut vec`
 
 error: it is more concise to loop over containers instead of using explicit iteration methods
-  --> $DIR/for_loop_fixable.rs:43:15
+  --> $DIR/for_loop_fixable.rs:48:15
    |
 LL |     for _v in out_vec.into_iter() {}
    |               ^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `out_vec`
@@ -21,73 +21,73 @@ LL |     for _v in out_vec.into_iter() {}
    = note: `-D clippy::explicit-into-iter-loop` implied by `-D warnings`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/for_loop_fixable.rs:48:15
+  --> $DIR/for_loop_fixable.rs:53:15
    |
 LL |     for _v in [1, 2, 3].iter() {}
    |               ^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[1, 2, 3]`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/for_loop_fixable.rs:52:15
+  --> $DIR/for_loop_fixable.rs:57:15
    |
 LL |     for _v in [0; 32].iter() {}
    |               ^^^^^^^^^^^^^^ help: to write this more concisely, try: `&[0; 32]`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/for_loop_fixable.rs:57:15
+  --> $DIR/for_loop_fixable.rs:62:15
    |
 LL |     for _v in ll.iter() {}
    |               ^^^^^^^^^ help: to write this more concisely, try: `&ll`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/for_loop_fixable.rs:60:15
+  --> $DIR/for_loop_fixable.rs:65:15
    |
 LL |     for _v in vd.iter() {}
    |               ^^^^^^^^^ help: to write this more concisely, try: `&vd`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/for_loop_fixable.rs:63:15
+  --> $DIR/for_loop_fixable.rs:68:15
    |
 LL |     for _v in bh.iter() {}
    |               ^^^^^^^^^ help: to write this more concisely, try: `&bh`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/for_loop_fixable.rs:66:15
+  --> $DIR/for_loop_fixable.rs:71:15
    |
 LL |     for _v in hm.iter() {}
    |               ^^^^^^^^^ help: to write this more concisely, try: `&hm`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/for_loop_fixable.rs:69:15
+  --> $DIR/for_loop_fixable.rs:74:15
    |
 LL |     for _v in bt.iter() {}
    |               ^^^^^^^^^ help: to write this more concisely, try: `&bt`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/for_loop_fixable.rs:72:15
+  --> $DIR/for_loop_fixable.rs:77:15
    |
 LL |     for _v in hs.iter() {}
    |               ^^^^^^^^^ help: to write this more concisely, try: `&hs`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/for_loop_fixable.rs:75:15
+  --> $DIR/for_loop_fixable.rs:80:15
    |
 LL |     for _v in bs.iter() {}
    |               ^^^^^^^^^ help: to write this more concisely, try: `&bs`
 
 error: it is more concise to loop over containers instead of using explicit iteration methods
-  --> $DIR/for_loop_fixable.rs:250:18
+  --> $DIR/for_loop_fixable.rs:255:18
    |
 LL |         for i in iterator.into_iter() {
    |                  ^^^^^^^^^^^^^^^^^^^^ help: to write this more concisely, try: `iterator`
 
 error: it is more concise to loop over references to containers instead of using explicit iteration methods
-  --> $DIR/for_loop_fixable.rs:270:18
+  --> $DIR/for_loop_fixable.rs:275:18
    |
 LL |         for _ in t.into_iter() {}
    |                  ^^^^^^^^^^^^^ help: to write this more concisely, try: `&t`
 
 error: it is more concise to loop over containers instead of using explicit iteration methods
-  --> $DIR/for_loop_fixable.rs:272:18
+  --> $DIR/for_loop_fixable.rs:277:18
    |
 LL |         for _ in r.into_iter() {}
    |                  ^^^^^^^^^^^^^ help: to write this more concisely, try: `r`
diff --git a/src/tools/clippy/tests/ui/format.fixed b/src/tools/clippy/tests/ui/format.fixed
index 78d2bfd474e..d08f8f52495 100644
--- a/src/tools/clippy/tests/ui/format.fixed
+++ b/src/tools/clippy/tests/ui/format.fixed
@@ -1,6 +1,11 @@
 // run-rustfix
 
-#![allow(clippy::print_literal, clippy::redundant_clone, clippy::to_string_in_format_args)]
+#![allow(
+    clippy::print_literal,
+    clippy::redundant_clone,
+    clippy::to_string_in_format_args,
+    clippy::needless_borrow
+)]
 #![warn(clippy::useless_format)]
 
 struct Foo(pub String);
diff --git a/src/tools/clippy/tests/ui/format.rs b/src/tools/clippy/tests/ui/format.rs
index 009c1aa216f..4a10b580d26 100644
--- a/src/tools/clippy/tests/ui/format.rs
+++ b/src/tools/clippy/tests/ui/format.rs
@@ -1,6 +1,11 @@
 // run-rustfix
 
-#![allow(clippy::print_literal, clippy::redundant_clone, clippy::to_string_in_format_args)]
+#![allow(
+    clippy::print_literal,
+    clippy::redundant_clone,
+    clippy::to_string_in_format_args,
+    clippy::needless_borrow
+)]
 #![warn(clippy::useless_format)]
 
 struct Foo(pub String);
diff --git a/src/tools/clippy/tests/ui/format.stderr b/src/tools/clippy/tests/ui/format.stderr
index 660be57585e..f25c7fb1ff1 100644
--- a/src/tools/clippy/tests/ui/format.stderr
+++ b/src/tools/clippy/tests/ui/format.stderr
@@ -1,5 +1,5 @@
 error: useless use of `format!`
-  --> $DIR/format.rs:13:5
+  --> $DIR/format.rs:18:5
    |
 LL |     format!("foo");
    |     ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
@@ -7,19 +7,19 @@ LL |     format!("foo");
    = note: `-D clippy::useless-format` implied by `-D warnings`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:14:5
+  --> $DIR/format.rs:19:5
    |
 LL |     format!("{{}}");
    |     ^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{}".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:15:5
+  --> $DIR/format.rs:20:5
    |
 LL |     format!("{{}} abc {{}}");
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"{} abc {}".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:16:5
+  --> $DIR/format.rs:21:5
    |
 LL | /     format!(
 LL | |         r##"foo {{}}
@@ -34,79 +34,79 @@ LL ~ " bar"##.to_string();
    |
 
 error: useless use of `format!`
-  --> $DIR/format.rs:21:13
+  --> $DIR/format.rs:26:13
    |
 LL |     let _ = format!("");
    |             ^^^^^^^^^^^ help: consider using `String::new()`: `String::new()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:23:5
+  --> $DIR/format.rs:28:5
    |
 LL |     format!("{}", "foo");
    |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:27:5
+  --> $DIR/format.rs:32:5
    |
 LL |     format!("{:+}", "foo"); // Warn when the format makes no difference.
    |     ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:28:5
+  --> $DIR/format.rs:33:5
    |
 LL |     format!("{:<}", "foo"); // Warn when the format makes no difference.
    |     ^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `"foo".to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:33:5
+  --> $DIR/format.rs:38:5
    |
 LL |     format!("{}", arg);
    |     ^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:37:5
+  --> $DIR/format.rs:42:5
    |
 LL |     format!("{:+}", arg); // Warn when the format makes no difference.
    |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:38:5
+  --> $DIR/format.rs:43:5
    |
 LL |     format!("{:<}", arg); // Warn when the format makes no difference.
    |     ^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `arg.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:65:5
+  --> $DIR/format.rs:70:5
    |
 LL |     format!("{}", 42.to_string());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `42.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:67:5
+  --> $DIR/format.rs:72:5
    |
 LL |     format!("{}", x.display().to_string());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.display().to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:71:18
+  --> $DIR/format.rs:76:18
    |
 LL |     let _ = Some(format!("{}", a + "bar"));
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `a + "bar"`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:75:22
+  --> $DIR/format.rs:80:22
    |
 LL |     let _s: String = format!("{}", &*v.join("/n"));
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `(&*v.join("/n")).to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:81:13
+  --> $DIR/format.rs:86:13
    |
 LL |     let _ = format!("{x}");
    |             ^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
 
 error: useless use of `format!`
-  --> $DIR/format.rs:83:13
+  --> $DIR/format.rs:88:13
    |
 LL |     let _ = format!("{y}", y = x);
    |             ^^^^^^^^^^^^^^^^^^^^^ help: consider using `.to_string()`: `x.to_string()`
diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed
index 9e37fb92559..b856f1375d3 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.fixed
+++ b/src/tools/clippy/tests/ui/needless_borrow.fixed
@@ -45,6 +45,33 @@ fn main() {
         let b = &mut b;
         x(b);
     }
+
+    // Issue #8191
+    let mut x = 5;
+    let mut x = &mut x;
+
+    mut_ref(x);
+    mut_ref(x);
+    let y: &mut i32 = x;
+    let y: &mut i32 = x;
+
+    let y = match 0 {
+        // Don't lint. Removing the borrow would move 'x'
+        0 => &mut x,
+        _ => &mut *x,
+    };
+
+    *x = 5;
+
+    let s = String::new();
+    let _ = s.len();
+    let _ = s.capacity();
+    let _ = s.capacity();
+
+    let x = (1, 2);
+    let _ = x.0;
+    let x = &x as *const (i32, i32);
+    let _ = unsafe { (*x).0 };
 }
 
 #[allow(clippy::needless_borrowed_reference)]
diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs
index 093277784be..0bfe222a3dc 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.rs
+++ b/src/tools/clippy/tests/ui/needless_borrow.rs
@@ -45,6 +45,33 @@ fn main() {
         let b = &mut b;
         x(&b);
     }
+
+    // Issue #8191
+    let mut x = 5;
+    let mut x = &mut x;
+
+    mut_ref(&mut x);
+    mut_ref(&mut &mut x);
+    let y: &mut i32 = &mut x;
+    let y: &mut i32 = &mut &mut x;
+
+    let y = match 0 {
+        // Don't lint. Removing the borrow would move 'x'
+        0 => &mut x,
+        _ => &mut *x,
+    };
+
+    *x = 5;
+
+    let s = String::new();
+    let _ = (&s).len();
+    let _ = (&s).capacity();
+    let _ = (&&s).capacity();
+
+    let x = (1, 2);
+    let _ = (&x).0;
+    let x = &x as *const (i32, i32);
+    let _ = unsafe { (&*x).0 };
 }
 
 #[allow(clippy::needless_borrowed_reference)]
diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr
index 03a5b3d260e..b90e8448db0 100644
--- a/src/tools/clippy/tests/ui/needless_borrow.stderr
+++ b/src/tools/clippy/tests/ui/needless_borrow.stderr
@@ -1,4 +1,4 @@
-error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
+error: this expression creates a reference which is immediately dereferenced by the compiler
   --> $DIR/needless_borrow.rs:9:15
    |
 LL |     let _ = x(&&a); // warn
@@ -6,59 +6,113 @@ LL |     let _ = x(&&a); // warn
    |
    = note: `-D clippy::needless-borrow` implied by `-D warnings`
 
-error: this expression borrows a reference (`&mut i32`) that is immediately dereferenced by the compiler
+error: this expression creates a reference which is immediately dereferenced by the compiler
   --> $DIR/needless_borrow.rs:13:13
    |
 LL |     mut_ref(&mut &mut b); // warn
    |             ^^^^^^^^^^^ help: change this to: `&mut b`
 
-error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
+error: this expression creates a reference which is immediately dereferenced by the compiler
   --> $DIR/needless_borrow.rs:25:13
    |
 LL |             &&a
    |             ^^^ help: change this to: `&a`
 
-error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
+error: this expression creates a reference which is immediately dereferenced by the compiler
   --> $DIR/needless_borrow.rs:27:15
    |
 LL |         46 => &&a,
    |               ^^^ help: change this to: `&a`
 
-error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
+error: this expression creates a reference which is immediately dereferenced by the compiler
   --> $DIR/needless_borrow.rs:33:27
    |
 LL |                     break &ref_a;
    |                           ^^^^^^ help: change this to: `ref_a`
 
-error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
+error: this expression creates a reference which is immediately dereferenced by the compiler
   --> $DIR/needless_borrow.rs:40:15
    |
 LL |     let _ = x(&&&a);
    |               ^^^^ help: change this to: `&a`
 
-error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
+error: this expression creates a reference which is immediately dereferenced by the compiler
   --> $DIR/needless_borrow.rs:41:15
    |
 LL |     let _ = x(&mut &&a);
    |               ^^^^^^^^ help: change this to: `&a`
 
-error: this expression borrows a reference (`&mut i32`) that is immediately dereferenced by the compiler
+error: this expression creates a reference which is immediately dereferenced by the compiler
   --> $DIR/needless_borrow.rs:42:15
    |
 LL |     let _ = x(&&&mut b);
    |               ^^^^^^^^ help: change this to: `&mut b`
 
-error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler
+error: this expression creates a reference which is immediately dereferenced by the compiler
   --> $DIR/needless_borrow.rs:43:15
    |
 LL |     let _ = x(&&ref_a);
    |               ^^^^^^^ help: change this to: `ref_a`
 
-error: this expression borrows a reference (`&mut i32`) that is immediately dereferenced by the compiler
+error: this expression creates a reference which is immediately dereferenced by the compiler
   --> $DIR/needless_borrow.rs:46:11
    |
 LL |         x(&b);
    |           ^^ help: change this to: `b`
 
-error: aborting due to 10 previous errors
+error: this expression creates a reference which is immediately dereferenced by the compiler
+  --> $DIR/needless_borrow.rs:53:13
+   |
+LL |     mut_ref(&mut x);
+   |             ^^^^^^ help: change this to: `x`
+
+error: this expression creates a reference which is immediately dereferenced by the compiler
+  --> $DIR/needless_borrow.rs:54:13
+   |
+LL |     mut_ref(&mut &mut x);
+   |             ^^^^^^^^^^^ help: change this to: `x`
+
+error: this expression creates a reference which is immediately dereferenced by the compiler
+  --> $DIR/needless_borrow.rs:55:23
+   |
+LL |     let y: &mut i32 = &mut x;
+   |                       ^^^^^^ help: change this to: `x`
+
+error: this expression creates a reference which is immediately dereferenced by the compiler
+  --> $DIR/needless_borrow.rs:56:23
+   |
+LL |     let y: &mut i32 = &mut &mut x;
+   |                       ^^^^^^^^^^^ help: change this to: `x`
+
+error: this expression borrows a value the compiler would automatically borrow
+  --> $DIR/needless_borrow.rs:67:13
+   |
+LL |     let _ = (&s).len();
+   |             ^^^^ help: change this to: `s`
+
+error: this expression borrows a value the compiler would automatically borrow
+  --> $DIR/needless_borrow.rs:68:13
+   |
+LL |     let _ = (&s).capacity();
+   |             ^^^^ help: change this to: `s`
+
+error: this expression creates a reference which is immediately dereferenced by the compiler
+  --> $DIR/needless_borrow.rs:69:13
+   |
+LL |     let _ = (&&s).capacity();
+   |             ^^^^^ help: change this to: `s`
+
+error: this expression borrows a value the compiler would automatically borrow
+  --> $DIR/needless_borrow.rs:72:13
+   |
+LL |     let _ = (&x).0;
+   |             ^^^^ help: change this to: `x`
+
+error: this expression borrows a value the compiler would automatically borrow
+  --> $DIR/needless_borrow.rs:74:22
+   |
+LL |     let _ = unsafe { (&*x).0 };
+   |                      ^^^^^ help: change this to: `(*x)`
+
+error: aborting due to 19 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs
index b07c4a23810..f3eafe8e927 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.rs
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs
@@ -1,5 +1,11 @@
 #![warn(clippy::needless_lifetimes)]
-#![allow(dead_code, clippy::needless_pass_by_value, clippy::unnecessary_wraps, dyn_drop)]
+#![allow(
+    dead_code,
+    clippy::boxed_local,
+    clippy::needless_pass_by_value,
+    clippy::unnecessary_wraps,
+    dyn_drop
+)]
 
 fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
 
@@ -369,4 +375,47 @@ mod issue6159 {
     }
 }
 
+mod issue7296 {
+    use std::rc::Rc;
+    use std::sync::Arc;
+
+    struct Foo;
+    impl Foo {
+        fn implicit<'a>(&'a self) -> &'a () {
+            &()
+        }
+        fn implicit_mut<'a>(&'a mut self) -> &'a () {
+            &()
+        }
+
+        fn explicit<'a>(self: &'a Arc<Self>) -> &'a () {
+            &()
+        }
+        fn explicit_mut<'a>(self: &'a mut Rc<Self>) -> &'a () {
+            &()
+        }
+
+        fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
+            &()
+        }
+    }
+
+    trait Bar {
+        fn implicit<'a>(&'a self) -> &'a ();
+        fn implicit_provided<'a>(&'a self) -> &'a () {
+            &()
+        }
+
+        fn explicit<'a>(self: &'a Arc<Self>) -> &'a ();
+        fn explicit_provided<'a>(self: &'a Arc<Self>) -> &'a () {
+            &()
+        }
+
+        fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a ();
+        fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
+            &()
+        }
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.stderr b/src/tools/clippy/tests/ui/needless_lifetimes.stderr
index 4114e6f1832..ffa152427a9 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.stderr
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.stderr
@@ -1,5 +1,5 @@
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:4:1
+  --> $DIR/needless_lifetimes.rs:10:1
    |
 LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -7,148 +7,190 @@ LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
    = note: `-D clippy::needless-lifetimes` implied by `-D warnings`
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:6:1
+  --> $DIR/needless_lifetimes.rs:12:1
    |
 LL | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:16:1
+  --> $DIR/needless_lifetimes.rs:22:1
    |
 LL | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:50:1
+  --> $DIR/needless_lifetimes.rs:56:1
    |
 LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:55:1
+  --> $DIR/needless_lifetimes.rs:61:1
    |
 LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:67:1
+  --> $DIR/needless_lifetimes.rs:73:1
    |
 LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:91:1
+  --> $DIR/needless_lifetimes.rs:97:1
    |
 LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:121:5
+  --> $DIR/needless_lifetimes.rs:127:5
    |
 LL |     fn self_and_out<'s>(&'s self) -> &'s u8 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:130:5
+  --> $DIR/needless_lifetimes.rs:136:5
    |
 LL |     fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:149:1
+  --> $DIR/needless_lifetimes.rs:155:1
    |
 LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:179:1
+  --> $DIR/needless_lifetimes.rs:185:1
    |
 LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:185:1
+  --> $DIR/needless_lifetimes.rs:191:1
    |
 LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:204:1
+  --> $DIR/needless_lifetimes.rs:210:1
    |
 LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:212:1
+  --> $DIR/needless_lifetimes.rs:218:1
    |
 LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:248:1
+  --> $DIR/needless_lifetimes.rs:254:1
    |
 LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:255:9
+  --> $DIR/needless_lifetimes.rs:261:9
    |
 LL |         fn needless_lt<'a>(x: &'a u8) {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:259:9
+  --> $DIR/needless_lifetimes.rs:265:9
    |
 LL |         fn needless_lt<'a>(_x: &'a u8) {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:272:9
+  --> $DIR/needless_lifetimes.rs:278:9
    |
 LL |         fn baz<'a>(&'a self) -> impl Foo + 'a {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:301:5
+  --> $DIR/needless_lifetimes.rs:307:5
    |
 LL |     fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:304:5
+  --> $DIR/needless_lifetimes.rs:310:5
    |
 LL |     fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:313:5
+  --> $DIR/needless_lifetimes.rs:319:5
    |
 LL |     fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:325:5
+  --> $DIR/needless_lifetimes.rs:331:5
    |
 LL |     fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:340:5
+  --> $DIR/needless_lifetimes.rs:346:5
    |
 LL |     fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:353:5
+  --> $DIR/needless_lifetimes.rs:359:5
    |
 LL |     fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
-  --> $DIR/needless_lifetimes.rs:356:5
+  --> $DIR/needless_lifetimes.rs:362:5
    |
 LL |     fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 25 previous errors
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:384:9
+   |
+LL |         fn implicit<'a>(&'a self) -> &'a () {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:387:9
+   |
+LL |         fn implicit_mut<'a>(&'a mut self) -> &'a () {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:398:9
+   |
+LL |         fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:404:9
+   |
+LL |         fn implicit<'a>(&'a self) -> &'a ();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:405:9
+   |
+LL |         fn implicit_provided<'a>(&'a self) -> &'a () {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:414:9
+   |
+LL |         fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a ();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration)
+  --> $DIR/needless_lifetimes.rs:415:9
+   |
+LL |         fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 32 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_question_mark.fixed b/src/tools/clippy/tests/ui/needless_question_mark.fixed
index f1fc81aa12b..ba9d15e59d0 100644
--- a/src/tools/clippy/tests/ui/needless_question_mark.fixed
+++ b/src/tools/clippy/tests/ui/needless_question_mark.fixed
@@ -125,3 +125,16 @@ pub fn test2() {
     let x = Some(3);
     let _x = some_and_qmark_in_macro!(x?);
 }
+
+async fn async_option_bad(to: TO) -> Option<usize> {
+    let _ = Some(3);
+    to.magic
+}
+
+async fn async_deref_ref(s: Option<&String>) -> Option<&str> {
+    Some(s?)
+}
+
+async fn async_result_bad(s: TR) -> Result<usize, bool> {
+    s.magic
+}
diff --git a/src/tools/clippy/tests/ui/needless_question_mark.rs b/src/tools/clippy/tests/ui/needless_question_mark.rs
index 44a0c5f61b5..3a6523e8fe8 100644
--- a/src/tools/clippy/tests/ui/needless_question_mark.rs
+++ b/src/tools/clippy/tests/ui/needless_question_mark.rs
@@ -125,3 +125,16 @@ pub fn test2() {
     let x = Some(3);
     let _x = some_and_qmark_in_macro!(x?);
 }
+
+async fn async_option_bad(to: TO) -> Option<usize> {
+    let _ = Some(3);
+    Some(to.magic?)
+}
+
+async fn async_deref_ref(s: Option<&String>) -> Option<&str> {
+    Some(s?)
+}
+
+async fn async_result_bad(s: TR) -> Result<usize, bool> {
+    Ok(s.magic?)
+}
diff --git a/src/tools/clippy/tests/ui/needless_question_mark.stderr b/src/tools/clippy/tests/ui/needless_question_mark.stderr
index 57c3d48c761..f8308e24e77 100644
--- a/src/tools/clippy/tests/ui/needless_question_mark.stderr
+++ b/src/tools/clippy/tests/ui/needless_question_mark.stderr
@@ -77,5 +77,17 @@ LL |     let _x = some_and_qmark_in_macro!(x?);
    |
    = note: this error originates in the macro `some_and_qmark_in_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 12 previous errors
+error: question mark operator is useless here
+  --> $DIR/needless_question_mark.rs:131:5
+   |
+LL |     Some(to.magic?)
+   |     ^^^^^^^^^^^^^^^ help: try removing question mark and `Some()`: `to.magic`
+
+error: question mark operator is useless here
+  --> $DIR/needless_question_mark.rs:139:5
+   |
+LL |     Ok(s.magic?)
+   |     ^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `s.magic`
+
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/op_ref.rs b/src/tools/clippy/tests/ui/op_ref.rs
index ab9c4d34c88..d8bf66603d9 100644
--- a/src/tools/clippy/tests/ui/op_ref.rs
+++ b/src/tools/clippy/tests/ui/op_ref.rs
@@ -1,7 +1,7 @@
 #![allow(unused_variables, clippy::blacklisted_name)]
 #![warn(clippy::op_ref)]
 use std::collections::HashSet;
-use std::ops::BitAnd;
+use std::ops::{BitAnd, Mul};
 
 fn main() {
     let tracked_fds: HashSet<i32> = HashSet::new();
@@ -55,3 +55,40 @@ fn main() {
     let y = Y(2);
     let z = x & &y;
 }
+
+#[derive(Clone, Copy)]
+struct A(i32);
+#[derive(Clone, Copy)]
+struct B(i32);
+
+impl Mul<&A> for B {
+    type Output = i32;
+    fn mul(self, rhs: &A) -> Self::Output {
+        self.0 * rhs.0
+    }
+}
+impl Mul<A> for B {
+    type Output = i32;
+    fn mul(self, rhs: A) -> Self::Output {
+        // Should not lint because removing the reference would lead to unconditional recursion
+        self * &rhs
+    }
+}
+impl Mul<&A> for A {
+    type Output = i32;
+    fn mul(self, rhs: &A) -> Self::Output {
+        self.0 * rhs.0
+    }
+}
+impl Mul<A> for A {
+    type Output = i32;
+    fn mul(self, rhs: A) -> Self::Output {
+        let one = B(1);
+        let two = 2;
+        let three = 3;
+        let _ = one * &self;
+        let _ = two + &three;
+        // Removing the reference would lead to unconditional recursion
+        self * &rhs
+    }
+}
diff --git a/src/tools/clippy/tests/ui/op_ref.stderr b/src/tools/clippy/tests/ui/op_ref.stderr
index 992417084bd..fe36c01166f 100644
--- a/src/tools/clippy/tests/ui/op_ref.stderr
+++ b/src/tools/clippy/tests/ui/op_ref.stderr
@@ -18,5 +18,21 @@ LL |     let z = x & &y;
    |                 |
    |                 help: use the right value directly: `y`
 
-error: aborting due to 2 previous errors
+error: taken reference of right operand
+  --> $DIR/op_ref.rs:89:17
+   |
+LL |         let _ = one * &self;
+   |                 ^^^^^^-----
+   |                       |
+   |                       help: use the right value directly: `self`
+
+error: taken reference of right operand
+  --> $DIR/op_ref.rs:90:17
+   |
+LL |         let _ = two + &three;
+   |                 ^^^^^^------
+   |                       |
+   |                       help: use the right value directly: `three`
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs
index 67bfef06a05..ed724237808 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.rs
+++ b/src/tools/clippy/tests/ui/ptr_arg.rs
@@ -9,7 +9,6 @@ fn do_vec(x: &Vec<i64>) {
 }
 
 fn do_vec_mut(x: &mut Vec<i64>) {
-    // no error here
     //Nothing here
 }
 
@@ -18,7 +17,6 @@ fn do_str(x: &String) {
 }
 
 fn do_str_mut(x: &mut String) {
-    // no error here
     //Nothing here either
 }
 
@@ -27,7 +25,6 @@ fn do_path(x: &PathBuf) {
 }
 
 fn do_path_mut(x: &mut PathBuf) {
-    // no error here
     //Nothing here either
 }
 
@@ -52,7 +49,7 @@ fn cloned(x: &Vec<u8>) -> Vec<u8> {
     let e = x.clone();
     let f = e.clone(); // OK
     let g = x;
-    let h = g.clone(); // Alas, we cannot reliably detect this without following data.
+    let h = g.clone();
     let i = (e).clone();
     x.clone()
 }
@@ -156,6 +153,30 @@ mod issue6509 {
     }
 }
 
+fn mut_vec_slice_methods(v: &mut Vec<u32>) {
+    v.copy_within(1..5, 10);
+}
+
+fn mut_vec_vec_methods(v: &mut Vec<u32>) {
+    v.clear();
+}
+
+fn vec_contains(v: &Vec<u32>) -> bool {
+    [vec![], vec![0]].as_slice().contains(v)
+}
+
+fn fn_requires_vec(v: &Vec<u32>) -> bool {
+    vec_contains(v)
+}
+
+fn impl_fn_requires_vec(v: &Vec<u32>, f: impl Fn(&Vec<u32>)) {
+    f(v);
+}
+
+fn dyn_fn_requires_vec(v: &Vec<u32>, f: &dyn Fn(&Vec<u32>)) {
+    f(v);
+}
+
 // No error for types behind an alias (#7699)
 type A = Vec<u8>;
 fn aliased(a: &A) {}
diff --git a/src/tools/clippy/tests/ui/ptr_arg.stderr b/src/tools/clippy/tests/ui/ptr_arg.stderr
index 64594eb870c..a9613daadde 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.stderr
+++ b/src/tools/clippy/tests/ui/ptr_arg.stderr
@@ -1,4 +1,4 @@
-error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
+error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
   --> $DIR/ptr_arg.rs:7:14
    |
 LL | fn do_vec(x: &Vec<i64>) {
@@ -6,170 +6,154 @@ LL | fn do_vec(x: &Vec<i64>) {
    |
    = note: `-D clippy::ptr-arg` implied by `-D warnings`
 
+error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do
+  --> $DIR/ptr_arg.rs:11:18
+   |
+LL | fn do_vec_mut(x: &mut Vec<i64>) {
+   |                  ^^^^^^^^^^^^^ help: change this to: `&mut [i64]`
+
 error: writing `&String` instead of `&str` involves a new object where a slice will do
-  --> $DIR/ptr_arg.rs:16:14
+  --> $DIR/ptr_arg.rs:15:14
    |
 LL | fn do_str(x: &String) {
    |              ^^^^^^^ help: change this to: `&str`
 
+error: writing `&mut String` instead of `&mut str` involves a new object where a slice will do
+  --> $DIR/ptr_arg.rs:19:18
+   |
+LL | fn do_str_mut(x: &mut String) {
+   |                  ^^^^^^^^^^^ help: change this to: `&mut str`
+
 error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
-  --> $DIR/ptr_arg.rs:25:15
+  --> $DIR/ptr_arg.rs:23:15
    |
 LL | fn do_path(x: &PathBuf) {
    |               ^^^^^^^^ help: change this to: `&Path`
 
-error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
-  --> $DIR/ptr_arg.rs:38:18
+error: writing `&mut PathBuf` instead of `&mut Path` involves a new object where a slice will do
+  --> $DIR/ptr_arg.rs:27:19
+   |
+LL | fn do_path_mut(x: &mut PathBuf) {
+   |                   ^^^^^^^^^^^^ help: change this to: `&mut Path`
+
+error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
+  --> $DIR/ptr_arg.rs:35:18
    |
 LL |     fn do_vec(x: &Vec<i64>);
    |                  ^^^^^^^^^ help: change this to: `&[i64]`
 
-error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
-  --> $DIR/ptr_arg.rs:51:14
+error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
+  --> $DIR/ptr_arg.rs:48:14
    |
 LL | fn cloned(x: &Vec<u8>) -> Vec<u8> {
    |              ^^^^^^^^
    |
 help: change this to
    |
-LL | fn cloned(x: &[u8]) -> Vec<u8> {
-   |              ~~~~~
-help: change `x.clone()` to
-   |
-LL |     let e = x.to_owned();
-   |             ~~~~~~~~~~~~
-help: change `x.clone()` to
-   |
-LL |     x.to_owned()
-   |
+LL ~ fn cloned(x: &[u8]) -> Vec<u8> {
+LL ~     let e = x.to_owned();
+LL |     let f = e.clone(); // OK
+LL |     let g = x;
+LL ~     let h = g.to_owned();
+LL |     let i = (e).clone();
+ ...
 
 error: writing `&String` instead of `&str` involves a new object where a slice will do
-  --> $DIR/ptr_arg.rs:60:18
+  --> $DIR/ptr_arg.rs:57:18
    |
 LL | fn str_cloned(x: &String) -> String {
    |                  ^^^^^^^
    |
 help: change this to
    |
-LL | fn str_cloned(x: &str) -> String {
-   |                  ~~~~
-help: change `x.clone()` to
-   |
-LL |     let a = x.to_string();
-   |             ~~~~~~~~~~~~~
-help: change `x.clone()` to
-   |
-LL |     let b = x.to_string();
-   |             ~~~~~~~~~~~~~
-help: change `x.clone()` to
-   |
-LL |     x.to_string()
+LL ~ fn str_cloned(x: &str) -> String {
+LL ~     let a = x.to_owned();
+LL ~     let b = x.to_owned();
+LL |     let c = b.clone();
+LL |     let d = a.clone().clone().clone();
+LL ~     x.to_owned()
    |
 
 error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
-  --> $DIR/ptr_arg.rs:68:19
+  --> $DIR/ptr_arg.rs:65:19
    |
 LL | fn path_cloned(x: &PathBuf) -> PathBuf {
    |                   ^^^^^^^^
    |
 help: change this to
    |
-LL | fn path_cloned(x: &Path) -> PathBuf {
-   |                   ~~~~~
-help: change `x.clone()` to
-   |
-LL |     let a = x.to_path_buf();
-   |             ~~~~~~~~~~~~~~~
-help: change `x.clone()` to
-   |
-LL |     let b = x.to_path_buf();
-   |             ~~~~~~~~~~~~~~~
-help: change `x.clone()` to
-   |
-LL |     x.to_path_buf()
+LL ~ fn path_cloned(x: &Path) -> PathBuf {
+LL ~     let a = x.to_path_buf();
+LL ~     let b = x.to_path_buf();
+LL |     let c = b.clone();
+LL |     let d = a.clone().clone().clone();
+LL ~     x.to_path_buf()
    |
 
 error: writing `&String` instead of `&str` involves a new object where a slice will do
-  --> $DIR/ptr_arg.rs:76:44
+  --> $DIR/ptr_arg.rs:73:44
    |
 LL | fn false_positive_capacity(x: &Vec<u8>, y: &String) {
    |                                            ^^^^^^^
    |
 help: change this to
    |
-LL | fn false_positive_capacity(x: &Vec<u8>, y: &str) {
-   |                                            ~~~~
-help: change `y.clone()` to
+LL ~ fn false_positive_capacity(x: &Vec<u8>, y: &str) {
+LL |     let a = x.capacity();
+LL ~     let b = y.to_owned();
+LL ~     let c = y;
    |
-LL |     let b = y.to_string();
-   |             ~~~~~~~~~~~~~
-help: change `y.as_str()` to
-   |
-LL |     let c = y;
-   |             ~
 
 error: using a reference to `Cow` is not recommended
-  --> $DIR/ptr_arg.rs:90:25
+  --> $DIR/ptr_arg.rs:87:25
    |
 LL | fn test_cow_with_ref(c: &Cow<[i32]>) {}
    |                         ^^^^^^^^^^^ help: change this to: `&[i32]`
 
-error: writing `&Vec<_>` instead of `&[_]` involves one more reference and cannot be used with non-Vec-based slices
-  --> $DIR/ptr_arg.rs:143:21
+error: writing `&Vec` instead of `&[_]` involves a new object where a slice will do
+  --> $DIR/ptr_arg.rs:140:21
    |
 LL |     fn foo_vec(vec: &Vec<u8>) {
    |                     ^^^^^^^^
    |
 help: change this to
    |
-LL |     fn foo_vec(vec: &[u8]) {
-   |                     ~~~~~
-help: change `vec.clone()` to
-   |
-LL |         let _ = vec.to_owned().pop();
-   |                 ~~~~~~~~~~~~~~
-help: change `vec.clone()` to
+LL ~     fn foo_vec(vec: &[u8]) {
+LL ~         let _ = vec.to_owned().pop();
+LL ~         let _ = vec.to_owned().clone();
    |
-LL |         let _ = vec.to_owned().clone();
-   |                 ~~~~~~~~~~~~~~
 
 error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
-  --> $DIR/ptr_arg.rs:148:23
+  --> $DIR/ptr_arg.rs:145:23
    |
 LL |     fn foo_path(path: &PathBuf) {
    |                       ^^^^^^^^
    |
 help: change this to
    |
-LL |     fn foo_path(path: &Path) {
-   |                       ~~~~~
-help: change `path.clone()` to
+LL ~     fn foo_path(path: &Path) {
+LL ~         let _ = path.to_path_buf().pop();
+LL ~         let _ = path.to_path_buf().clone();
    |
-LL |         let _ = path.to_path_buf().pop();
-   |                 ~~~~~~~~~~~~~~~~~~
-help: change `path.clone()` to
-   |
-LL |         let _ = path.to_path_buf().clone();
-   |                 ~~~~~~~~~~~~~~~~~~
 
 error: writing `&PathBuf` instead of `&Path` involves a new object where a slice will do
-  --> $DIR/ptr_arg.rs:153:21
+  --> $DIR/ptr_arg.rs:150:21
    |
 LL |     fn foo_str(str: &PathBuf) {
    |                     ^^^^^^^^
    |
 help: change this to
    |
-LL |     fn foo_str(str: &Path) {
-   |                     ~~~~~
-help: change `str.clone()` to
+LL ~     fn foo_str(str: &Path) {
+LL ~         let _ = str.to_path_buf().pop();
+LL ~         let _ = str.to_path_buf().clone();
    |
-LL |         let _ = str.to_path_buf().pop();
-   |                 ~~~~~~~~~~~~~~~~~
-help: change `str.clone()` to
+
+error: writing `&mut Vec` instead of `&mut [_]` involves a new object where a slice will do
+  --> $DIR/ptr_arg.rs:156:29
    |
-LL |         let _ = str.to_path_buf().clone();
-   |                 ~~~~~~~~~~~~~~~~~
+LL | fn mut_vec_slice_methods(v: &mut Vec<u32>) {
+   |                             ^^^^^^^^^^^^^ help: change this to: `&mut [u32]`
 
-error: aborting due to 12 previous errors
+error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
index cc93859269c..a89845c1dd3 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
@@ -81,7 +81,7 @@ const fn issue6067() {
     None::<()>.is_none();
 }
 
-#[allow(clippy::deref_addrof, dead_code)]
+#[allow(clippy::deref_addrof, dead_code, clippy::needless_borrow)]
 fn issue7921() {
     if (&None::<()>).is_none() {}
     if (&None::<()>).is_none() {}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
index 280dca40c01..d6f44403487 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
@@ -96,7 +96,7 @@ const fn issue6067() {
     };
 }
 
-#[allow(clippy::deref_addrof, dead_code)]
+#[allow(clippy::deref_addrof, dead_code, clippy::needless_borrow)]
 fn issue7921() {
     if let None = *(&None::<()>) {}
     if let None = *&None::<()> {}
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index b9425733a8b..8bddec576ed 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -54,6 +54,7 @@
 #![warn(clippy::match_result_ok)]
 #![warn(clippy::disallowed_types)]
 #![warn(clippy::disallowed_methods)]
+#![warn(clippy::needless_borrow)]
 // uplifted lints
 #![warn(invalid_value)]
 #![warn(array_into_iter)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index 341c003b9df..d2010d71d2c 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -54,6 +54,7 @@
 #![warn(clippy::if_let_some_result)]
 #![warn(clippy::disallowed_type)]
 #![warn(clippy::disallowed_method)]
+#![warn(clippy::ref_in_deref)]
 // uplifted lints
 #![warn(clippy::invalid_ref)]
 #![warn(clippy::into_iter_on_array)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index cdec2808f1d..45cb8b786f5 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -138,59 +138,65 @@ error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
+error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
+  --> $DIR/rename.rs:57:9
+   |
+LL | #![warn(clippy::ref_in_deref)]
+   |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
+
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> $DIR/rename.rs:58:9
+  --> $DIR/rename.rs:59:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:59:9
+  --> $DIR/rename.rs:60:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> $DIR/rename.rs:60:9
+  --> $DIR/rename.rs:61:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> $DIR/rename.rs:61:9
+  --> $DIR/rename.rs:62:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> $DIR/rename.rs:62:9
+  --> $DIR/rename.rs:63:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> $DIR/rename.rs:63:9
+  --> $DIR/rename.rs:64:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/rename.rs:64:9
+  --> $DIR/rename.rs:65:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> $DIR/rename.rs:65:9
+  --> $DIR/rename.rs:66:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:66:9
+  --> $DIR/rename.rs:67:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
-error: aborting due to 32 previous errors
+error: aborting due to 33 previous errors
 
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs b/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs
index 778f4f6fa25..767518ab0c0 100644
--- a/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs
@@ -189,7 +189,7 @@ mod issue7392 {
         let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none();
     }
 
-    fn test_string_1(s: &String) -> bool {
+    fn test_string_1(s: &str) -> bool {
         s.is_empty()
     }
 
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr
index 7c5e5eb589c..933ce5cf42d 100644
--- a/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr
@@ -251,14 +251,6 @@ error: called `is_none()` after searching an `Iterator` with `find`
 LL |         let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)`
 
-error: writing `&String` instead of `&str` involves a new object where a slice will do
-  --> $DIR/search_is_some_fixable_none.rs:192:25
-   |
-LL |     fn test_string_1(s: &String) -> bool {
-   |                         ^^^^^^^ help: change this to: `&str`
-   |
-   = note: `-D clippy::ptr-arg` implied by `-D warnings`
-
 error: called `is_none()` after searching an `Iterator` with `find`
   --> $DIR/search_is_some_fixable_none.rs:208:17
    |
@@ -289,5 +281,5 @@ error: called `is_none()` after searching an `Iterator` with `find`
 LL |         let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none();
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `!_.any()` instead: `!v.iter().any(|fp| test_u32_2(*fp.field))`
 
-error: aborting due to 44 previous errors
+error: aborting due to 43 previous errors
 
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs b/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs
index 241641fceae..77fd52e4ce7 100644
--- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs
@@ -188,7 +188,7 @@ mod issue7392 {
         let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some();
     }
 
-    fn test_string_1(s: &String) -> bool {
+    fn test_string_1(s: &str) -> bool {
         s.is_empty()
     }
 
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr
index 9212c6e71ff..8b424f18ef5 100644
--- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr
@@ -234,14 +234,6 @@ error: called `is_some()` after searching an `Iterator` with `find`
 LL |         let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some();
    |                                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|(&x, y)| x == *y)`
 
-error: writing `&String` instead of `&str` involves a new object where a slice will do
-  --> $DIR/search_is_some_fixable_some.rs:191:25
-   |
-LL |     fn test_string_1(s: &String) -> bool {
-   |                         ^^^^^^^ help: change this to: `&str`
-   |
-   = note: `-D clippy::ptr-arg` implied by `-D warnings`
-
 error: called `is_some()` after searching an `Iterator` with `find`
   --> $DIR/search_is_some_fixable_some.rs:207:26
    |
@@ -272,5 +264,5 @@ error: called `is_some()` after searching an `Iterator` with `find`
 LL |         let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_some();
    |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `any()` instead: `any(|fp| test_u32_2(*fp.field))`
 
-error: aborting due to 44 previous errors
+error: aborting due to 43 previous errors
 
diff --git a/src/tools/clippy/tests/ui/slow_vector_initialization.rs b/src/tools/clippy/tests/ui/slow_vector_initialization.rs
index c5ae3ff769b..7e3d357ae50 100644
--- a/src/tools/clippy/tests/ui/slow_vector_initialization.rs
+++ b/src/tools/clippy/tests/ui/slow_vector_initialization.rs
@@ -53,7 +53,7 @@ fn resize_vector() {
     vec1.resize(10, 0);
 }
 
-fn do_stuff(vec: &mut Vec<u8>) {}
+fn do_stuff(vec: &mut [u8]) {}
 
 fn extend_vector_with_manipulations_between() {
     let len = 300;
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs
index 2edb202892a..21de19a2601 100644
--- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs
+++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs
@@ -1,5 +1,6 @@
 #![deny(clippy::trait_duplication_in_bounds)]
 
+use std::collections::BTreeMap;
 use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
 
 fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
@@ -73,4 +74,25 @@ impl U for Life {
     fn f() {}
 }
 
+// should not warn
+trait Iter: Iterator {
+    fn into_group_btreemap<K, V>(self) -> BTreeMap<K, Vec<V>>
+    where
+        Self: Iterator<Item = (K, V)> + Sized,
+        K: Ord + Eq,
+    {
+        unimplemented!();
+    }
+}
+
+struct Foo {}
+
+trait FooIter: Iterator<Item = Foo> {
+    fn bar()
+    where
+        Self: Iterator<Item = Foo>,
+    {
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr
index e0c7a7ec618..6f8c8e47dfb 100644
--- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr
+++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr
@@ -1,5 +1,5 @@
 error: this trait bound is already specified in the where clause
-  --> $DIR/trait_duplication_in_bounds.rs:5:15
+  --> $DIR/trait_duplication_in_bounds.rs:6:15
    |
 LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
    |               ^^^^^
@@ -12,7 +12,7 @@ LL | #![deny(clippy::trait_duplication_in_bounds)]
    = help: consider removing this trait bound
 
 error: this trait bound is already specified in the where clause
-  --> $DIR/trait_duplication_in_bounds.rs:5:23
+  --> $DIR/trait_duplication_in_bounds.rs:6:23
    |
 LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
    |                       ^^^^^^^
@@ -20,7 +20,7 @@ LL | fn bad_foo<T: Clone + Default, Z: Copy>(arg0: T, arg1: Z)
    = help: consider removing this trait bound
 
 error: this trait bound is already specified in trait declaration
-  --> $DIR/trait_duplication_in_bounds.rs:34:15
+  --> $DIR/trait_duplication_in_bounds.rs:35:15
    |
 LL |         Self: Default;
    |               ^^^^^^^
@@ -28,7 +28,7 @@ LL |         Self: Default;
    = help: consider removing this trait bound
 
 error: this trait bound is already specified in trait declaration
-  --> $DIR/trait_duplication_in_bounds.rs:48:15
+  --> $DIR/trait_duplication_in_bounds.rs:49:15
    |
 LL |         Self: Default + Clone;
    |               ^^^^^^^
@@ -36,7 +36,7 @@ LL |         Self: Default + Clone;
    = help: consider removing this trait bound
 
 error: this trait bound is already specified in trait declaration
-  --> $DIR/trait_duplication_in_bounds.rs:54:15
+  --> $DIR/trait_duplication_in_bounds.rs:55:15
    |
 LL |         Self: Default + Clone;
    |               ^^^^^^^
@@ -44,7 +44,7 @@ LL |         Self: Default + Clone;
    = help: consider removing this trait bound
 
 error: this trait bound is already specified in trait declaration
-  --> $DIR/trait_duplication_in_bounds.rs:54:25
+  --> $DIR/trait_duplication_in_bounds.rs:55:25
    |
 LL |         Self: Default + Clone;
    |                         ^^^^^
@@ -52,12 +52,20 @@ LL |         Self: Default + Clone;
    = help: consider removing this trait bound
 
 error: this trait bound is already specified in trait declaration
-  --> $DIR/trait_duplication_in_bounds.rs:57:15
+  --> $DIR/trait_duplication_in_bounds.rs:58:15
    |
 LL |         Self: Default;
    |               ^^^^^^^
    |
    = help: consider removing this trait bound
 
-error: aborting due to 7 previous errors
+error: this trait bound is already specified in trait declaration
+  --> $DIR/trait_duplication_in_bounds.rs:93:15
+   |
+LL |         Self: Iterator<Item = Foo>,
+   |               ^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: consider removing this trait bound
+
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.rs b/src/tools/clippy/tests/ui/unnecessary_cast.rs
index e8f2fb46665..b77c19f2ba5 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.rs
@@ -1,6 +1,7 @@
 #![warn(clippy::unnecessary_cast)]
 #![allow(clippy::no_effect)]
 
+#[rustfmt::skip]
 fn main() {
     // Test cast_unnecessary
     1i32 as i32;
@@ -8,6 +9,12 @@ fn main() {
     false as bool;
     &1i32 as &i32;
 
+    -1_i32 as i32;
+    - 1_i32 as i32;
+    -1f32 as f32;
+    1_i32 as i32;
+    1_f32 as f32;
+
     // macro version
     macro_rules! foo {
         ($a:ident, $b:ident) => {
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.stderr b/src/tools/clippy/tests/ui/unnecessary_cast.stderr
index 70aa448af68..a5a93c6110c 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_cast.stderr
@@ -1,5 +1,5 @@
 error: casting integer literal to `i32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:6:5
+  --> $DIR/unnecessary_cast.rs:7:5
    |
 LL |     1i32 as i32;
    |     ^^^^^^^^^^^ help: try: `1_i32`
@@ -7,16 +7,46 @@ LL |     1i32 as i32;
    = note: `-D clippy::unnecessary-cast` implied by `-D warnings`
 
 error: casting float literal to `f32` is unnecessary
-  --> $DIR/unnecessary_cast.rs:7:5
+  --> $DIR/unnecessary_cast.rs:8:5
    |
 LL |     1f32 as f32;
    |     ^^^^^^^^^^^ help: try: `1_f32`
 
 error: casting to the same type is unnecessary (`bool` -> `bool`)
-  --> $DIR/unnecessary_cast.rs:8:5
+  --> $DIR/unnecessary_cast.rs:9:5
    |
 LL |     false as bool;
    |     ^^^^^^^^^^^^^ help: try: `false`
 
-error: aborting due to 3 previous errors
+error: casting integer literal to `i32` is unnecessary
+  --> $DIR/unnecessary_cast.rs:12:5
+   |
+LL |     -1_i32 as i32;
+   |     ^^^^^^^^^^^^^ help: try: `-1_i32`
+
+error: casting integer literal to `i32` is unnecessary
+  --> $DIR/unnecessary_cast.rs:13:5
+   |
+LL |     - 1_i32 as i32;
+   |     ^^^^^^^^^^^^^^ help: try: `- 1_i32`
+
+error: casting float literal to `f32` is unnecessary
+  --> $DIR/unnecessary_cast.rs:14:5
+   |
+LL |     -1f32 as f32;
+   |     ^^^^^^^^^^^^ help: try: `-1_f32`
+
+error: casting integer literal to `i32` is unnecessary
+  --> $DIR/unnecessary_cast.rs:15:5
+   |
+LL |     1_i32 as i32;
+   |     ^^^^^^^^^^^^ help: try: `1_i32`
+
+error: casting float literal to `f32` is unnecessary
+  --> $DIR/unnecessary_cast.rs:16:5
+   |
+LL |     1_f32 as f32;
+   |     ^^^^^^^^^^^^ help: try: `1_f32`
+
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_ref.fixed b/src/tools/clippy/tests/ui/unnecessary_ref.fixed
deleted file mode 100644
index d927bae976f..00000000000
--- a/src/tools/clippy/tests/ui/unnecessary_ref.fixed
+++ /dev/null
@@ -1,23 +0,0 @@
-// run-rustfix
-
-#![feature(stmt_expr_attributes)]
-#![allow(unused_variables, dead_code)]
-
-struct Outer {
-    inner: u32,
-}
-
-#[deny(clippy::ref_in_deref)]
-fn main() {
-    let outer = Outer { inner: 0 };
-    let inner = outer.inner;
-}
-
-struct Apple;
-impl Apple {
-    fn hello(&self) {}
-}
-struct Package(pub *const Apple);
-fn foobar(package: *const Package) {
-    unsafe { &*(*package).0 }.hello();
-}
diff --git a/src/tools/clippy/tests/ui/unnecessary_ref.rs b/src/tools/clippy/tests/ui/unnecessary_ref.rs
deleted file mode 100644
index 86bfb76ec26..00000000000
--- a/src/tools/clippy/tests/ui/unnecessary_ref.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-// run-rustfix
-
-#![feature(stmt_expr_attributes)]
-#![allow(unused_variables, dead_code)]
-
-struct Outer {
-    inner: u32,
-}
-
-#[deny(clippy::ref_in_deref)]
-fn main() {
-    let outer = Outer { inner: 0 };
-    let inner = (&outer).inner;
-}
-
-struct Apple;
-impl Apple {
-    fn hello(&self) {}
-}
-struct Package(pub *const Apple);
-fn foobar(package: *const Package) {
-    unsafe { &*(&*package).0 }.hello();
-}
diff --git a/src/tools/clippy/tests/ui/unnecessary_ref.stderr b/src/tools/clippy/tests/ui/unnecessary_ref.stderr
deleted file mode 100644
index 436f4bcf738..00000000000
--- a/src/tools/clippy/tests/ui/unnecessary_ref.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error: creating a reference that is immediately dereferenced
-  --> $DIR/unnecessary_ref.rs:13:17
-   |
-LL |     let inner = (&outer).inner;
-   |                 ^^^^^^^^ help: try this: `outer`
-   |
-note: the lint level is defined here
-  --> $DIR/unnecessary_ref.rs:10:8
-   |
-LL | #[deny(clippy::ref_in_deref)]
-   |        ^^^^^^^^^^^^^^^^^^^^
-
-error: creating a reference that is immediately dereferenced
-  --> $DIR/unnecessary_ref.rs:22:16
-   |
-LL |     unsafe { &*(&*package).0 }.hello();
-   |                ^^^^^^^^^^^ help: try this: `(*package)`
-   |
-   = note: `-D clippy::ref-in-deref` implied by `-D warnings`
-
-error: aborting due to 2 previous errors
-
diff --git a/src/tools/clippy/tests/ui/useless_asref.fixed b/src/tools/clippy/tests/ui/useless_asref.fixed
index e356f13d087..e431661d180 100644
--- a/src/tools/clippy/tests/ui/useless_asref.fixed
+++ b/src/tools/clippy/tests/ui/useless_asref.fixed
@@ -67,7 +67,7 @@ fn not_ok() {
         foo_rslice(mrrrrrslice);
         foo_rslice(mrrrrrslice);
     }
-    #[allow(unused_parens, clippy::double_parens)]
+    #[allow(unused_parens, clippy::double_parens, clippy::needless_borrow)]
     foo_rrrrmr((&&&&MoreRef));
 
     generic_not_ok(mrslice);
diff --git a/src/tools/clippy/tests/ui/useless_asref.rs b/src/tools/clippy/tests/ui/useless_asref.rs
index 2a80291f5d8..6ae931d7aa4 100644
--- a/src/tools/clippy/tests/ui/useless_asref.rs
+++ b/src/tools/clippy/tests/ui/useless_asref.rs
@@ -67,7 +67,7 @@ fn not_ok() {
         foo_rslice(mrrrrrslice.as_ref());
         foo_rslice(mrrrrrslice);
     }
-    #[allow(unused_parens, clippy::double_parens)]
+    #[allow(unused_parens, clippy::double_parens, clippy::needless_borrow)]
     foo_rrrrmr((&&&&MoreRef).as_ref());
 
     generic_not_ok(mrslice);
diff --git a/src/tools/clippy/tests/ui/write_literal.rs b/src/tools/clippy/tests/ui/write_literal.rs
index 0a127858def..44669174411 100644
--- a/src/tools/clippy/tests/ui/write_literal.rs
+++ b/src/tools/clippy/tests/ui/write_literal.rs
@@ -7,37 +7,37 @@ fn main() {
     let mut v = Vec::new();
 
     // these should be fine
-    write!(&mut v, "Hello");
-    writeln!(&mut v, "Hello");
+    write!(v, "Hello");
+    writeln!(v, "Hello");
     let world = "world";
-    writeln!(&mut v, "Hello {}", world);
-    writeln!(&mut v, "Hello {world}", world = world);
-    writeln!(&mut v, "3 in hex is {:X}", 3);
-    writeln!(&mut v, "2 + 1 = {:.4}", 3);
-    writeln!(&mut v, "2 + 1 = {:5.4}", 3);
-    writeln!(&mut v, "Debug test {:?}", "hello, world");
-    writeln!(&mut v, "{0:8} {1:>8}", "hello", "world");
-    writeln!(&mut v, "{1:8} {0:>8}", "hello", "world");
-    writeln!(&mut v, "{foo:8} {bar:>8}", foo = "hello", bar = "world");
-    writeln!(&mut v, "{bar:8} {foo:>8}", foo = "hello", bar = "world");
-    writeln!(&mut v, "{number:>width$}", number = 1, width = 6);
-    writeln!(&mut v, "{number:>0width$}", number = 1, width = 6);
-    writeln!(&mut v, "{} of {:b} people know binary, the other half doesn't", 1, 2);
-    writeln!(&mut v, "10 / 4 is {}", 2.5);
-    writeln!(&mut v, "2 + 1 = {}", 3);
+    writeln!(v, "Hello {}", world);
+    writeln!(v, "Hello {world}", world = world);
+    writeln!(v, "3 in hex is {:X}", 3);
+    writeln!(v, "2 + 1 = {:.4}", 3);
+    writeln!(v, "2 + 1 = {:5.4}", 3);
+    writeln!(v, "Debug test {:?}", "hello, world");
+    writeln!(v, "{0:8} {1:>8}", "hello", "world");
+    writeln!(v, "{1:8} {0:>8}", "hello", "world");
+    writeln!(v, "{foo:8} {bar:>8}", foo = "hello", bar = "world");
+    writeln!(v, "{bar:8} {foo:>8}", foo = "hello", bar = "world");
+    writeln!(v, "{number:>width$}", number = 1, width = 6);
+    writeln!(v, "{number:>0width$}", number = 1, width = 6);
+    writeln!(v, "{} of {:b} people know binary, the other half doesn't", 1, 2);
+    writeln!(v, "10 / 4 is {}", 2.5);
+    writeln!(v, "2 + 1 = {}", 3);
 
     // these should throw warnings
-    write!(&mut v, "Hello {}", "world");
-    writeln!(&mut v, "Hello {} {}", world, "world");
-    writeln!(&mut v, "Hello {}", "world");
+    write!(v, "Hello {}", "world");
+    writeln!(v, "Hello {} {}", world, "world");
+    writeln!(v, "Hello {}", "world");
 
     // positional args don't change the fact
     // that we're using a literal -- this should
     // throw a warning
-    writeln!(&mut v, "{0} {1}", "hello", "world");
-    writeln!(&mut v, "{1} {0}", "hello", "world");
+    writeln!(v, "{0} {1}", "hello", "world");
+    writeln!(v, "{1} {0}", "hello", "world");
 
     // named args shouldn't change anything either
-    writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world");
-    writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world");
+    writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
+    writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
 }
diff --git a/src/tools/clippy/tests/ui/write_literal.stderr b/src/tools/clippy/tests/ui/write_literal.stderr
index e0297c00231..593e9493ec5 100644
--- a/src/tools/clippy/tests/ui/write_literal.stderr
+++ b/src/tools/clippy/tests/ui/write_literal.stderr
@@ -1,134 +1,134 @@
 error: literal with an empty format string
-  --> $DIR/write_literal.rs:30:32
+  --> $DIR/write_literal.rs:30:27
    |
-LL |     write!(&mut v, "Hello {}", "world");
-   |                                ^^^^^^^
+LL |     write!(v, "Hello {}", "world");
+   |                           ^^^^^^^
    |
    = note: `-D clippy::write-literal` implied by `-D warnings`
 help: try this
    |
-LL -     write!(&mut v, "Hello {}", "world");
-LL +     write!(&mut v, "Hello world");
+LL -     write!(v, "Hello {}", "world");
+LL +     write!(v, "Hello world");
    | 
 
 error: literal with an empty format string
-  --> $DIR/write_literal.rs:31:44
+  --> $DIR/write_literal.rs:31:39
    |
-LL |     writeln!(&mut v, "Hello {} {}", world, "world");
-   |                                            ^^^^^^^
+LL |     writeln!(v, "Hello {} {}", world, "world");
+   |                                       ^^^^^^^
    |
 help: try this
    |
-LL -     writeln!(&mut v, "Hello {} {}", world, "world");
-LL +     writeln!(&mut v, "Hello {} world", world);
+LL -     writeln!(v, "Hello {} {}", world, "world");
+LL +     writeln!(v, "Hello {} world", world);
    | 
 
 error: literal with an empty format string
-  --> $DIR/write_literal.rs:32:34
+  --> $DIR/write_literal.rs:32:29
    |
-LL |     writeln!(&mut v, "Hello {}", "world");
-   |                                  ^^^^^^^
+LL |     writeln!(v, "Hello {}", "world");
+   |                             ^^^^^^^
    |
 help: try this
    |
-LL -     writeln!(&mut v, "Hello {}", "world");
-LL +     writeln!(&mut v, "Hello world");
+LL -     writeln!(v, "Hello {}", "world");
+LL +     writeln!(v, "Hello world");
    | 
 
 error: literal with an empty format string
-  --> $DIR/write_literal.rs:37:33
+  --> $DIR/write_literal.rs:37:28
    |
-LL |     writeln!(&mut v, "{0} {1}", "hello", "world");
-   |                                 ^^^^^^^
+LL |     writeln!(v, "{0} {1}", "hello", "world");
+   |                            ^^^^^^^
    |
 help: try this
    |
-LL -     writeln!(&mut v, "{0} {1}", "hello", "world");
-LL +     writeln!(&mut v, "hello {1}", "world");
+LL -     writeln!(v, "{0} {1}", "hello", "world");
+LL +     writeln!(v, "hello {1}", "world");
    | 
 
 error: literal with an empty format string
-  --> $DIR/write_literal.rs:37:42
+  --> $DIR/write_literal.rs:37:37
    |
-LL |     writeln!(&mut v, "{0} {1}", "hello", "world");
-   |                                          ^^^^^^^
+LL |     writeln!(v, "{0} {1}", "hello", "world");
+   |                                     ^^^^^^^
    |
 help: try this
    |
-LL -     writeln!(&mut v, "{0} {1}", "hello", "world");
-LL +     writeln!(&mut v, "{0} world", "hello");
+LL -     writeln!(v, "{0} {1}", "hello", "world");
+LL +     writeln!(v, "{0} world", "hello");
    | 
 
 error: literal with an empty format string
-  --> $DIR/write_literal.rs:38:33
+  --> $DIR/write_literal.rs:38:28
    |
-LL |     writeln!(&mut v, "{1} {0}", "hello", "world");
-   |                                 ^^^^^^^
+LL |     writeln!(v, "{1} {0}", "hello", "world");
+   |                            ^^^^^^^
    |
 help: try this
    |
-LL -     writeln!(&mut v, "{1} {0}", "hello", "world");
-LL +     writeln!(&mut v, "{1} hello", "world");
+LL -     writeln!(v, "{1} {0}", "hello", "world");
+LL +     writeln!(v, "{1} hello", "world");
    | 
 
 error: literal with an empty format string
-  --> $DIR/write_literal.rs:38:42
+  --> $DIR/write_literal.rs:38:37
    |
-LL |     writeln!(&mut v, "{1} {0}", "hello", "world");
-   |                                          ^^^^^^^
+LL |     writeln!(v, "{1} {0}", "hello", "world");
+   |                                     ^^^^^^^
    |
 help: try this
    |
-LL -     writeln!(&mut v, "{1} {0}", "hello", "world");
-LL +     writeln!(&mut v, "world {0}", "hello");
+LL -     writeln!(v, "{1} {0}", "hello", "world");
+LL +     writeln!(v, "world {0}", "hello");
    | 
 
 error: literal with an empty format string
-  --> $DIR/write_literal.rs:41:37
+  --> $DIR/write_literal.rs:41:32
    |
-LL |     writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world");
-   |                                     ^^^^^^^^^^^^^
+LL |     writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
+   |                                ^^^^^^^^^^^^^
    |
 help: try this
    |
-LL -     writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world");
-LL +     writeln!(&mut v, "hello {bar}", bar = "world");
+LL -     writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
+LL +     writeln!(v, "hello {bar}", bar = "world");
    | 
 
 error: literal with an empty format string
-  --> $DIR/write_literal.rs:41:52
+  --> $DIR/write_literal.rs:41:47
    |
-LL |     writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world");
-   |                                                    ^^^^^^^^^^^^^
+LL |     writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
+   |                                               ^^^^^^^^^^^^^
    |
 help: try this
    |
-LL -     writeln!(&mut v, "{foo} {bar}", foo = "hello", bar = "world");
-LL +     writeln!(&mut v, "{foo} world", foo = "hello");
+LL -     writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
+LL +     writeln!(v, "{foo} world", foo = "hello");
    | 
 
 error: literal with an empty format string
-  --> $DIR/write_literal.rs:42:37
+  --> $DIR/write_literal.rs:42:32
    |
-LL |     writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world");
-   |                                     ^^^^^^^^^^^^^
+LL |     writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
+   |                                ^^^^^^^^^^^^^
    |
 help: try this
    |
-LL -     writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world");
-LL +     writeln!(&mut v, "{bar} hello", bar = "world");
+LL -     writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
+LL +     writeln!(v, "{bar} hello", bar = "world");
    | 
 
 error: literal with an empty format string
-  --> $DIR/write_literal.rs:42:52
+  --> $DIR/write_literal.rs:42:47
    |
-LL |     writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world");
-   |                                                    ^^^^^^^^^^^^^
+LL |     writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
+   |                                               ^^^^^^^^^^^^^
    |
 help: try this
    |
-LL -     writeln!(&mut v, "{bar} {foo}", foo = "hello", bar = "world");
-LL +     writeln!(&mut v, "world {foo}", foo = "hello");
+LL -     writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
+LL +     writeln!(v, "world {foo}", foo = "hello");
    | 
 
 error: aborting due to 11 previous errors
diff --git a/src/tools/clippy/tests/ui/write_literal_2.rs b/src/tools/clippy/tests/ui/write_literal_2.rs
index f341e8215e1..ba0d7be5eaa 100644
--- a/src/tools/clippy/tests/ui/write_literal_2.rs
+++ b/src/tools/clippy/tests/ui/write_literal_2.rs
@@ -6,20 +6,20 @@ use std::io::Write;
 fn main() {
     let mut v = Vec::new();
 
-    writeln!(&mut v, "{}", "{hello}");
-    writeln!(&mut v, r"{}", r"{hello}");
-    writeln!(&mut v, "{}", '\'');
-    writeln!(&mut v, "{}", '"');
-    writeln!(&mut v, r"{}", '"'); // don't lint
-    writeln!(&mut v, r"{}", '\'');
+    writeln!(v, "{}", "{hello}");
+    writeln!(v, r"{}", r"{hello}");
+    writeln!(v, "{}", '\'');
+    writeln!(v, "{}", '"');
+    writeln!(v, r"{}", '"'); // don't lint
+    writeln!(v, r"{}", '\'');
     writeln!(
-        &mut v,
+        v,
         "some {}",
         "hello \
         world!"
     );
     writeln!(
-        &mut v,
+        v,
         "some {}\
         {} \\ {}",
         "1", "2", "3",
diff --git a/src/tools/clippy/tests/ui/write_literal_2.stderr b/src/tools/clippy/tests/ui/write_literal_2.stderr
index 73c6b885813..fc40fbfa9e2 100644
--- a/src/tools/clippy/tests/ui/write_literal_2.stderr
+++ b/src/tools/clippy/tests/ui/write_literal_2.stderr
@@ -1,62 +1,62 @@
 error: literal with an empty format string
-  --> $DIR/write_literal_2.rs:9:28
+  --> $DIR/write_literal_2.rs:9:23
    |
-LL |     writeln!(&mut v, "{}", "{hello}");
-   |                            ^^^^^^^^^
+LL |     writeln!(v, "{}", "{hello}");
+   |                       ^^^^^^^^^
    |
    = note: `-D clippy::write-literal` implied by `-D warnings`
 help: try this
    |
-LL -     writeln!(&mut v, "{}", "{hello}");
-LL +     writeln!(&mut v, "{{hello}}");
+LL -     writeln!(v, "{}", "{hello}");
+LL +     writeln!(v, "{{hello}}");
    | 
 
 error: literal with an empty format string
-  --> $DIR/write_literal_2.rs:10:29
+  --> $DIR/write_literal_2.rs:10:24
    |
-LL |     writeln!(&mut v, r"{}", r"{hello}");
-   |                             ^^^^^^^^^^
+LL |     writeln!(v, r"{}", r"{hello}");
+   |                        ^^^^^^^^^^
    |
 help: try this
    |
-LL -     writeln!(&mut v, r"{}", r"{hello}");
-LL +     writeln!(&mut v, r"{{hello}}");
+LL -     writeln!(v, r"{}", r"{hello}");
+LL +     writeln!(v, r"{{hello}}");
    | 
 
 error: literal with an empty format string
-  --> $DIR/write_literal_2.rs:11:28
+  --> $DIR/write_literal_2.rs:11:23
    |
-LL |     writeln!(&mut v, "{}", '/'');
-   |                            ^^^^
+LL |     writeln!(v, "{}", '/'');
+   |                       ^^^^
    |
 help: try this
    |
-LL -     writeln!(&mut v, "{}", '/'');
-LL +     writeln!(&mut v, "'");
+LL -     writeln!(v, "{}", '/'');
+LL +     writeln!(v, "'");
    | 
 
 error: literal with an empty format string
-  --> $DIR/write_literal_2.rs:12:28
+  --> $DIR/write_literal_2.rs:12:23
    |
-LL |     writeln!(&mut v, "{}", '"');
-   |                            ^^^
+LL |     writeln!(v, "{}", '"');
+   |                       ^^^
    |
 help: try this
    |
-LL -     writeln!(&mut v, "{}", '"');
-LL +     writeln!(&mut v, "/"");
+LL -     writeln!(v, "{}", '"');
+LL +     writeln!(v, "/"");
    | 
 
 error: literal with an empty format string
-  --> $DIR/write_literal_2.rs:14:29
+  --> $DIR/write_literal_2.rs:14:24
    |
-LL |     writeln!(&mut v, r"{}", '/'');
-   |                             ^^^^
+LL |     writeln!(v, r"{}", '/'');
+   |                        ^^^^
    |
 help: try this
    |
-LL -     writeln!(&mut v, r"{}", '/'');
-LL +     writeln!(&mut v, r"'");
+LL -     writeln!(v, r"{}", '/'');
+LL +     writeln!(v, r"'");
    | 
 
 error: literal with an empty format string
diff --git a/src/tools/clippy/tests/ui/write_with_newline.rs b/src/tools/clippy/tests/ui/write_with_newline.rs
index 1c1b1b58402..446d6914d34 100644
--- a/src/tools/clippy/tests/ui/write_with_newline.rs
+++ b/src/tools/clippy/tests/ui/write_with_newline.rs
@@ -10,50 +10,50 @@ fn main() {
     let mut v = Vec::new();
 
     // These should fail
-    write!(&mut v, "Hello\n");
-    write!(&mut v, "Hello {}\n", "world");
-    write!(&mut v, "Hello {} {}\n", "world", "#2");
-    write!(&mut v, "{}\n", 1265);
-    write!(&mut v, "\n");
+    write!(v, "Hello\n");
+    write!(v, "Hello {}\n", "world");
+    write!(v, "Hello {} {}\n", "world", "#2");
+    write!(v, "{}\n", 1265);
+    write!(v, "\n");
 
     // These should be fine
-    write!(&mut v, "");
-    write!(&mut v, "Hello");
-    writeln!(&mut v, "Hello");
-    writeln!(&mut v, "Hello\n");
-    writeln!(&mut v, "Hello {}\n", "world");
-    write!(&mut v, "Issue\n{}", 1265);
-    write!(&mut v, "{}", 1265);
-    write!(&mut v, "\n{}", 1275);
-    write!(&mut v, "\n\n");
-    write!(&mut v, "like eof\n\n");
-    write!(&mut v, "Hello {} {}\n\n", "world", "#2");
-    writeln!(&mut v, "\ndon't\nwarn\nfor\nmultiple\nnewlines\n"); // #3126
-    writeln!(&mut v, "\nbla\n\n"); // #3126
+    write!(v, "");
+    write!(v, "Hello");
+    writeln!(v, "Hello");
+    writeln!(v, "Hello\n");
+    writeln!(v, "Hello {}\n", "world");
+    write!(v, "Issue\n{}", 1265);
+    write!(v, "{}", 1265);
+    write!(v, "\n{}", 1275);
+    write!(v, "\n\n");
+    write!(v, "like eof\n\n");
+    write!(v, "Hello {} {}\n\n", "world", "#2");
+    writeln!(v, "\ndon't\nwarn\nfor\nmultiple\nnewlines\n"); // #3126
+    writeln!(v, "\nbla\n\n"); // #3126
 
     // Escaping
-    write!(&mut v, "\\n"); // #3514
-    write!(&mut v, "\\\n"); // should fail
-    write!(&mut v, "\\\\n");
+    write!(v, "\\n"); // #3514
+    write!(v, "\\\n"); // should fail
+    write!(v, "\\\\n");
 
     // Raw strings
-    write!(&mut v, r"\n"); // #3778
+    write!(v, r"\n"); // #3778
 
     // Literal newlines should also fail
     write!(
-        &mut v,
+        v,
         "
 "
     );
     write!(
-        &mut v,
+        v,
         r"
 "
     );
 
     // Don't warn on CRLF (#4208)
-    write!(&mut v, "\r\n");
-    write!(&mut v, "foo\r\n");
-    write!(&mut v, "\\r\n"); //~ ERROR
-    write!(&mut v, "foo\rbar\n");
+    write!(v, "\r\n");
+    write!(v, "foo\r\n");
+    write!(v, "\\r\n"); //~ ERROR
+    write!(v, "foo\rbar\n");
 }
diff --git a/src/tools/clippy/tests/ui/write_with_newline.stderr b/src/tools/clippy/tests/ui/write_with_newline.stderr
index 186459e50b6..3314a2a6e24 100644
--- a/src/tools/clippy/tests/ui/write_with_newline.stderr
+++ b/src/tools/clippy/tests/ui/write_with_newline.stderr
@@ -1,81 +1,81 @@
 error: using `write!()` with a format string that ends in a single newline
   --> $DIR/write_with_newline.rs:13:5
    |
-LL |     write!(&mut v, "Hello/n");
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     write!(v, "Hello/n");
+   |     ^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::write-with-newline` implied by `-D warnings`
 help: use `writeln!()` instead
    |
-LL -     write!(&mut v, "Hello/n");
-LL +     writeln!(&mut v, "Hello");
+LL -     write!(v, "Hello/n");
+LL +     writeln!(v, "Hello");
    | 
 
 error: using `write!()` with a format string that ends in a single newline
   --> $DIR/write_with_newline.rs:14:5
    |
-LL |     write!(&mut v, "Hello {}/n", "world");
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     write!(v, "Hello {}/n", "world");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: use `writeln!()` instead
    |
-LL -     write!(&mut v, "Hello {}/n", "world");
-LL +     writeln!(&mut v, "Hello {}", "world");
+LL -     write!(v, "Hello {}/n", "world");
+LL +     writeln!(v, "Hello {}", "world");
    | 
 
 error: using `write!()` with a format string that ends in a single newline
   --> $DIR/write_with_newline.rs:15:5
    |
-LL |     write!(&mut v, "Hello {} {}/n", "world", "#2");
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     write!(v, "Hello {} {}/n", "world", "#2");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: use `writeln!()` instead
    |
-LL -     write!(&mut v, "Hello {} {}/n", "world", "#2");
-LL +     writeln!(&mut v, "Hello {} {}", "world", "#2");
+LL -     write!(v, "Hello {} {}/n", "world", "#2");
+LL +     writeln!(v, "Hello {} {}", "world", "#2");
    | 
 
 error: using `write!()` with a format string that ends in a single newline
   --> $DIR/write_with_newline.rs:16:5
    |
-LL |     write!(&mut v, "{}/n", 1265);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     write!(v, "{}/n", 1265);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: use `writeln!()` instead
    |
-LL -     write!(&mut v, "{}/n", 1265);
-LL +     writeln!(&mut v, "{}", 1265);
+LL -     write!(v, "{}/n", 1265);
+LL +     writeln!(v, "{}", 1265);
    | 
 
 error: using `write!()` with a format string that ends in a single newline
   --> $DIR/write_with_newline.rs:17:5
    |
-LL |     write!(&mut v, "/n");
-   |     ^^^^^^^^^^^^^^^^^^^^
+LL |     write!(v, "/n");
+   |     ^^^^^^^^^^^^^^^
    |
 help: use `writeln!()` instead
    |
-LL -     write!(&mut v, "/n");
-LL +     writeln!(&mut v);
+LL -     write!(v, "/n");
+LL +     writeln!(v);
    | 
 
 error: using `write!()` with a format string that ends in a single newline
   --> $DIR/write_with_newline.rs:36:5
    |
-LL |     write!(&mut v, "//n"); // should fail
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+LL |     write!(v, "//n"); // should fail
+   |     ^^^^^^^^^^^^^^^^^
    |
 help: use `writeln!()` instead
    |
-LL -     write!(&mut v, "//n"); // should fail
-LL +     writeln!(&mut v, "/"); // should fail
+LL -     write!(v, "//n"); // should fail
+LL +     writeln!(v, "/"); // should fail
    | 
 
 error: using `write!()` with a format string that ends in a single newline
   --> $DIR/write_with_newline.rs:43:5
    |
 LL | /     write!(
-LL | |         &mut v,
+LL | |         v,
 LL | |         "
 LL | | "
 LL | |     );
@@ -84,7 +84,7 @@ LL | |     );
 help: use `writeln!()` instead
    |
 LL ~     writeln!(
-LL |         &mut v,
+LL |         v,
 LL ~         ""
    |
 
@@ -92,7 +92,7 @@ error: using `write!()` with a format string that ends in a single newline
   --> $DIR/write_with_newline.rs:48:5
    |
 LL | /     write!(
-LL | |         &mut v,
+LL | |         v,
 LL | |         r"
 LL | | "
 LL | |     );
@@ -101,32 +101,32 @@ LL | |     );
 help: use `writeln!()` instead
    |
 LL ~     writeln!(
-LL |         &mut v,
+LL |         v,
 LL ~         r""
    |
 
 error: using `write!()` with a format string that ends in a single newline
   --> $DIR/write_with_newline.rs:57:5
    |
-LL |     write!(&mut v, "/r/n"); //~ ERROR
-   |     ^^^^^^^^^^^^^^^^^^^^^^^
+LL |     write!(v, "/r/n"); //~ ERROR
+   |     ^^^^^^^^^^^^^^^^^^
    |
 help: use `writeln!()` instead
    |
-LL -     write!(&mut v, "/r/n"); //~ ERROR
-LL +     writeln!(&mut v, "/r"); //~ ERROR
+LL -     write!(v, "/r/n"); //~ ERROR
+LL +     writeln!(v, "/r"); //~ ERROR
    | 
 
 error: using `write!()` with a format string that ends in a single newline
   --> $DIR/write_with_newline.rs:58:5
    |
-LL |     write!(&mut v, "foo/rbar/n");
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     write!(v, "foo/rbar/n");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: use `writeln!()` instead
    |
-LL -     write!(&mut v, "foo/rbar/n");
-LL +     writeln!(&mut v, "foo/rbar");
+LL -     write!(v, "foo/rbar/n");
+LL +     writeln!(v, "foo/rbar");
    | 
 
 error: aborting due to 10 previous errors
diff --git a/src/tools/clippy/tests/ui/writeln_empty_string.fixed b/src/tools/clippy/tests/ui/writeln_empty_string.fixed
index c3ac15b0375..e7d94acd130 100644
--- a/src/tools/clippy/tests/ui/writeln_empty_string.fixed
+++ b/src/tools/clippy/tests/ui/writeln_empty_string.fixed
@@ -8,13 +8,13 @@ fn main() {
     let mut v = Vec::new();
 
     // These should fail
-    writeln!(&mut v);
+    writeln!(v);
 
     let mut suggestion = Vec::new();
-    writeln!(&mut suggestion);
+    writeln!(suggestion);
 
     // These should be fine
-    writeln!(&mut v);
-    writeln!(&mut v, " ");
-    write!(&mut v, "");
+    writeln!(v);
+    writeln!(v, " ");
+    write!(v, "");
 }
diff --git a/src/tools/clippy/tests/ui/writeln_empty_string.rs b/src/tools/clippy/tests/ui/writeln_empty_string.rs
index 9a8894b6c0d..662c62f0211 100644
--- a/src/tools/clippy/tests/ui/writeln_empty_string.rs
+++ b/src/tools/clippy/tests/ui/writeln_empty_string.rs
@@ -8,13 +8,13 @@ fn main() {
     let mut v = Vec::new();
 
     // These should fail
-    writeln!(&mut v, "");
+    writeln!(v, "");
 
     let mut suggestion = Vec::new();
-    writeln!(&mut suggestion, "");
+    writeln!(suggestion, "");
 
     // These should be fine
-    writeln!(&mut v);
-    writeln!(&mut v, " ");
-    write!(&mut v, "");
+    writeln!(v);
+    writeln!(v, " ");
+    write!(v, "");
 }
diff --git a/src/tools/clippy/tests/ui/writeln_empty_string.stderr b/src/tools/clippy/tests/ui/writeln_empty_string.stderr
index 99635229b3e..ac65aadfc0e 100644
--- a/src/tools/clippy/tests/ui/writeln_empty_string.stderr
+++ b/src/tools/clippy/tests/ui/writeln_empty_string.stderr
@@ -1,16 +1,16 @@
-error: using `writeln!(&mut v, "")`
+error: using `writeln!(v, "")`
   --> $DIR/writeln_empty_string.rs:11:5
    |
-LL |     writeln!(&mut v, "");
-   |     ^^^^^^^^^^^^^^^^^^^^ help: replace it with: `writeln!(&mut v)`
+LL |     writeln!(v, "");
+   |     ^^^^^^^^^^^^^^^ help: replace it with: `writeln!(v)`
    |
    = note: `-D clippy::writeln-empty-string` implied by `-D warnings`
 
-error: using `writeln!(&mut suggestion, "")`
+error: using `writeln!(suggestion, "")`
   --> $DIR/writeln_empty_string.rs:14:5
    |
-LL |     writeln!(&mut suggestion, "");
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `writeln!(&mut suggestion)`
+LL |     writeln!(suggestion, "");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `writeln!(suggestion)`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/util/gh-pages/index.html b/src/tools/clippy/util/gh-pages/index.html
index 5b7e61a349d..83a200ca3c4 100644
--- a/src/tools/clippy/util/gh-pages/index.html
+++ b/src/tools/clippy/util/gh-pages/index.html
@@ -522,6 +522,11 @@ Otherwise, have a great day =^.^=
                 }
 
                 scrollToLintByURL($scope);
+
+                setTimeout(function () {
+                    var el = document.getElementById('filter-input');
+                    if (el) { el.focus() }
+                }, 0);
             })
             .error(function (data) {
                 $scope.error = data;
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 22785013085..00221b07f74 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -3498,10 +3498,12 @@ impl<'test> TestCx<'test> {
         // with placeholders as we do not want tests needing updated when compiler source code
         // changes.
         // eg. $SRC_DIR/libcore/mem.rs:323:14 becomes $SRC_DIR/libcore/mem.rs:LL:COL
-        normalized = Regex::new("SRC_DIR(.+):\\d+:\\d+(: \\d+:\\d+)?")
-            .unwrap()
-            .replace_all(&normalized, "SRC_DIR$1:LL:COL")
-            .into_owned();
+        lazy_static! {
+            static ref SRC_DIR_RE: Regex =
+                Regex::new("SRC_DIR(.+):\\d+:\\d+(: \\d+:\\d+)?").unwrap();
+        }
+
+        normalized = SRC_DIR_RE.replace_all(&normalized, "SRC_DIR$1:LL:COL").into_owned();
 
         normalized = Self::normalize_platform_differences(&normalized);
         normalized = normalized.replace("\t", "\\t"); // makes tabs visible
@@ -3510,73 +3512,38 @@ impl<'test> TestCx<'test> {
         // since they duplicate actual errors and make the output hard to read.
         // This mirrors the regex in src/tools/tidy/src/style.rs, please update
         // both if either are changed.
-        normalized =
-            Regex::new("\\s*//(\\[.*\\])?~.*").unwrap().replace_all(&normalized, "").into_owned();
+        lazy_static! {
+            static ref ANNOTATION_RE: Regex = Regex::new("\\s*//(\\[.*\\])?~.*").unwrap();
+        }
+
+        normalized = ANNOTATION_RE.replace_all(&normalized, "").into_owned();
+
+        // This code normalizes various hashes in v0 symbol mangling that is
+        // emitted in the ui and mir-opt tests.
+        lazy_static! {
+            static ref V0_CRATE_HASH_PREFIX_RE: Regex =
+                Regex::new(r"_R.*?Cs[0-9a-zA-Z]+_").unwrap();
+            static ref V0_CRATE_HASH_RE: Regex = Regex::new(r"Cs[0-9a-zA-Z]+_").unwrap();
+        }
 
-        // This code normalizes various hashes in both
-        // v0 and legacy symbol names that are emitted in
-        // the ui and mir-opt tests.
-        //
-        // Some tests still require normalization with headers.
-        const DEFID_HASH_REGEX: &str = r"\[[0-9a-z]{4}\]";
-        const DEFID_HASH_PLACEHOLDER: &str = r"[HASH]";
-        const V0_DEMANGLING_HASH_REGEX: &str = r"\[[0-9a-z]+\]";
-        const V0_DEMANGLING_HASH_PLACEHOLDER: &str = r"[HASH]";
-        const V0_CRATE_HASH_PREFIX_REGEX: &str = r"_R.*?Cs[0-9a-zA-Z]+_";
-        const V0_CRATE_HASH_REGEX: &str = r"Cs[0-9a-zA-Z]+_";
         const V0_CRATE_HASH_PLACEHOLDER: &str = r"CsCRATE_HASH_";
-        const V0_BACK_REF_PREFIX_REGEX: &str = r"\(_R.*?B[0-9a-zA-Z]_";
-        const V0_BACK_REF_REGEX: &str = r"B[0-9a-zA-Z]_";
-        const V0_BACK_REF_PLACEHOLDER: &str = r"B<REF>_";
-        const LEGACY_SYMBOL_HASH_REGEX: &str = r"h[\w]{16}E?\)";
-        const LEGACY_SYMBOL_HASH_PLACEHOLDER: &str = r"h<SYMBOL_HASH>)";
-        let test_name = self
-            .output_testname_unique()
-            .into_os_string()
-            .into_string()
-            .unwrap()
-            .split('.')
-            .next()
-            .unwrap()
-            .replace("-", "_");
-        // Normalize `DefId` hashes
-        let defid_regex = format!("{}{}", test_name, DEFID_HASH_REGEX);
-        let defid_placeholder = format!("{}{}", test_name, DEFID_HASH_PLACEHOLDER);
-        normalized = Regex::new(&defid_regex)
-            .unwrap()
-            .replace_all(&normalized, defid_placeholder)
-            .into_owned();
-        // Normalize v0 demangling hashes
-        let demangling_regex = format!("{}{}", test_name, V0_DEMANGLING_HASH_REGEX);
-        let demangling_placeholder = format!("{}{}", test_name, V0_DEMANGLING_HASH_PLACEHOLDER);
-        normalized = Regex::new(&demangling_regex)
-            .unwrap()
-            .replace_all(&normalized, demangling_placeholder)
-            .into_owned();
-        // Normalize v0 crate hashes (see RFC 2603)
-        let symbol_mangle_prefix_re = Regex::new(V0_CRATE_HASH_PREFIX_REGEX).unwrap();
-        if symbol_mangle_prefix_re.is_match(&normalized) {
+        if V0_CRATE_HASH_PREFIX_RE.is_match(&normalized) {
             // Normalize crate hash
-            normalized = Regex::new(V0_CRATE_HASH_REGEX)
-                .unwrap()
-                .replace_all(&normalized, V0_CRATE_HASH_PLACEHOLDER)
-                .into_owned();
+            normalized =
+                V0_CRATE_HASH_RE.replace_all(&normalized, V0_CRATE_HASH_PLACEHOLDER).into_owned();
+        }
+
+        lazy_static! {
+            static ref V0_BACK_REF_PREFIX_RE: Regex = Regex::new(r"\(_R.*?B[0-9a-zA-Z]_").unwrap();
+            static ref V0_BACK_REF_RE: Regex = Regex::new(r"B[0-9a-zA-Z]_").unwrap();
         }
-        let back_ref_prefix_re = Regex::new(V0_BACK_REF_PREFIX_REGEX).unwrap();
-        if back_ref_prefix_re.is_match(&normalized) {
+
+        const V0_BACK_REF_PLACEHOLDER: &str = r"B<REF>_";
+        if V0_BACK_REF_PREFIX_RE.is_match(&normalized) {
             // Normalize back references (see RFC 2603)
-            let back_ref_regex = format!("{}", V0_BACK_REF_REGEX);
-            let back_ref_placeholder = format!("{}", V0_BACK_REF_PLACEHOLDER);
-            normalized = Regex::new(&back_ref_regex)
-                .unwrap()
-                .replace_all(&normalized, back_ref_placeholder)
-                .into_owned();
+            normalized =
+                V0_BACK_REF_RE.replace_all(&normalized, V0_BACK_REF_PLACEHOLDER).into_owned();
         }
-        // Normalize legacy mangled symbols
-        normalized = Regex::new(LEGACY_SYMBOL_HASH_REGEX)
-            .unwrap()
-            .replace_all(&normalized, LEGACY_SYMBOL_HASH_PLACEHOLDER)
-            .into_owned();
 
         // Custom normalization rules
         for rule in custom_rules {