about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml12
-rw-r--r--.gitmodules2
-rw-r--r--Cargo.lock19
-rw-r--r--compiler/rustc_arena/src/lib.rs1
-rw-r--r--compiler/rustc_ast/src/ast.rs50
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs5
-rw-r--r--compiler/rustc_ast/src/util/parser.rs4
-rw-r--r--compiler/rustc_ast/src/visit.rs37
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs10
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs4
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs15
-rw-r--r--compiler/rustc_ast_lowering/src/lifetime_collector.rs9
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs24
-rw-r--r--compiler/rustc_ast_passes/src/node_count.rs14
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs14
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/item.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs9
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs38
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs12
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs13
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs21
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.lock4
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs28
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs10
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs12
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs9
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs11
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs4
-rw-r--r--compiler/rustc_driver/src/lib.rs11
-rw-r--r--compiler/rustc_errors/src/lib.rs1
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs8
-rw-r--r--compiler/rustc_hir/src/hir.rs24
-rw-r--r--compiler/rustc_hir/src/intravisit.rs51
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs2
-rw-r--r--compiler/rustc_lint/src/early.rs6
-rw-r--r--compiler/rustc_lint/src/late.rs19
-rw-r--r--compiler/rustc_lint/src/levels.rs9
-rw-r--r--compiler/rustc_lint/src/passes.rs3
-rw-r--r--compiler/rustc_lint/src/unused.rs91
-rw-r--r--compiler/rustc_llvm/build.rs7
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs26
-rw-r--r--compiler/rustc_middle/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/thir.rs8
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs23
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs7
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs12
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_box_derefs.rs8
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs10
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs8
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs56
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs12
-rw-r--r--compiler/rustc_passes/src/check_attr.rs9
-rw-r--r--compiler/rustc_passes/src/dead.rs9
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs314
-rw-r--r--compiler/rustc_passes/src/stability.rs10
-rw-r--r--compiler/rustc_privacy/src/lib.rs9
-rw-r--r--compiler/rustc_resolve/src/late.rs7
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs6
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs2
-rw-r--r--compiler/rustc_target/src/abi/call/nvptx.rs33
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_darwin.rs8
-rw-r--r--compiler/rustc_target/src/spec/android_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs53
-rw-r--r--compiler/rustc_target/src/spec/apple_sdk_base.rs44
-rw-r--r--compiler/rustc_target/src/spec/fuchsia_base.rs5
-rw-r--r--compiler/rustc_target/src/spec/i686_apple_darwin.rs3
-rw-r--r--compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs4
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_darwin.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs9
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs35
-rw-r--r--compiler/rustc_typeck/src/astconv/mod.rs169
-rw-r--r--compiler/rustc_typeck/src/check/cast.rs23
-rw-r--r--compiler/rustc_typeck/src/check/check.rs4
-rw-r--r--compiler/rustc_typeck/src/check/coercion.rs8
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs7
-rw-r--r--compiler/rustc_typeck/src/check/demand.rs16
-rw-r--r--compiler/rustc_typeck/src/check/expr.rs83
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/checks.rs2
-rw-r--r--compiler/rustc_typeck/src/check/fn_ctxt/mod.rs11
-rw-r--r--compiler/rustc_typeck/src/check/method/suggest.rs21
-rw-r--r--compiler/rustc_typeck/src/check/mod.rs9
-rw-r--r--compiler/rustc_typeck/src/check/op.rs2
-rw-r--r--compiler/rustc_typeck/src/collect.rs22
-rw-r--r--library/core/benches/num/int_log/mod.rs6
-rw-r--r--library/core/src/alloc/global.rs2
-rw-r--r--library/core/src/alloc/layout.rs43
-rw-r--r--library/core/src/array/equality.rs7
-rw-r--r--library/core/src/char/methods.rs3
-rw-r--r--library/core/src/ffi/c_str.rs1
-rw-r--r--library/core/src/intrinsics.rs3
-rw-r--r--library/core/src/mem/valid_align.rs7
-rw-r--r--library/core/src/num/bignum.rs2
-rw-r--r--library/core/src/num/int_macros.rs38
-rw-r--r--library/core/src/num/nonzero.rs20
-rw-r--r--library/core/src/num/uint_macros.rs40
-rw-r--r--library/core/src/ptr/const_ptr.rs21
-rw-r--r--library/core/src/ptr/mut_ptr.rs23
-rw-r--r--library/core/src/slice/iter.rs4
-rw-r--r--library/core/src/time.rs6
-rw-r--r--library/core/tests/alloc.rs44
-rw-r--r--library/core/tests/const_ptr.rs6
-rw-r--r--library/core/tests/lib.rs2
-rw-r--r--library/core/tests/num/int_log.rs156
-rw-r--r--library/core/tests/slice.rs3
-rw-r--r--library/std/src/backtrace.rs21
-rw-r--r--library/std/src/error.rs1
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/sys/sgx/abi/usercalls/alloc.rs2
-rw-r--r--library/std/src/sys/unix/fs.rs6
-rw-r--r--library/std/src/sys/unix/locks/pthread_condvar.rs2
-rw-r--r--library/std/src/sys/unix/mod.rs6
-rw-r--r--library/std/src/sys/unix/rand.rs18
-rw-r--r--library/std/src/sys/unix/thread.rs12
-rw-r--r--library/std/src/sys/unsupported/alloc.rs7
-rw-r--r--library/std/src/sys/unsupported/process.rs3
-rw-r--r--library/std/src/thread/mod.rs59
-rw-r--r--library/unwind/build.rs7
-rw-r--r--library/unwind/src/lib.rs20
-rw-r--r--src/bootstrap/lib.rs10
-rw-r--r--src/bootstrap/mk/Makefile.in11
-rw-r--r--src/bootstrap/native.rs3
-rw-r--r--src/bootstrap/test.rs5
-rw-r--r--src/ci/docker/host-x86_64/arm-android/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/dist-android/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/dist-x86_64-netbsd/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/i686-gnu/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile3
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-12/Dockerfile18
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile1
-rw-r--r--src/ci/github-actions/ci.yml30
-rw-r--r--src/doc/rustc/src/linker-plugin-lto.md4
-rw-r--r--src/librustdoc/clean/blanket_impl.rs2
-rw-r--r--src/librustdoc/clean/inline.rs15
-rw-r--r--src/librustdoc/clean/mod.rs730
-rw-r--r--src/librustdoc/clean/types.rs19
-rw-r--r--src/librustdoc/clean/utils.rs8
-rw-r--r--src/librustdoc/doctest.rs9
-rw-r--r--src/librustdoc/html/format.rs2
-rw-r--r--src/librustdoc/html/highlight.rs88
-rw-r--r--src/librustdoc/html/highlight/tests.rs11
-rw-r--r--src/librustdoc/html/markdown.rs26
-rw-r--r--src/librustdoc/html/render/mod.rs3
-rw-r--r--src/librustdoc/html/render/print_item.rs12
-rw-r--r--src/librustdoc/html/render/write_shared.rs79
-rw-r--r--src/librustdoc/html/sources.rs17
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css61
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css27
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css26
-rw-r--r--src/librustdoc/html/static/css/themes/light.css21
-rw-r--r--src/librustdoc/html/static/images/down-arrow.svg2
-rw-r--r--src/librustdoc/html/static/js/main.js60
-rw-r--r--src/librustdoc/html/static/js/search.js31
-rw-r--r--src/librustdoc/html/static/js/source-script.js20
-rw-r--r--src/librustdoc/json/conversions.rs30
-rw-r--r--src/librustdoc/passes/strip_hidden.rs8
-rw-r--r--src/librustdoc/passes/strip_private.rs10
-rw-r--r--src/librustdoc/passes/stripper.rs53
m---------src/llvm-project0
-rw-r--r--src/rustdoc-json-types/lib.rs7
-rw-r--r--src/test/codegen/layout-size-checks.rs31
-rw-r--r--src/test/mir-opt/README.md12
-rw-r--r--src/test/mir-opt/bool_compare.rs2
-rw-r--r--src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff77
-rw-r--r--src/test/mir-opt/combine_array_len.norm2.InstCombine.diff (renamed from src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff)0
-rw-r--r--src/test/mir-opt/combine_array_len.rs2
-rw-r--r--src/test/mir-opt/const_goto.rs2
-rw-r--r--src/test/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff2
-rw-r--r--src/test/mir-opt/const_goto_storage.rs2
-rw-r--r--src/test/mir-opt/const_prop/boxes.main.ConstProp.diff2
-rw-r--r--src/test/mir-opt/deaggregator_test.rs2
-rw-r--r--src/test/mir-opt/deaggregator_test_enum.rs2
-rw-r--r--src/test/mir-opt/deaggregator_test_enum_2.rs1
-rw-r--r--src/test/mir-opt/deaggregator_test_multiple.rs1
-rw-r--r--src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff89
-rw-r--r--src/test/mir-opt/deduplicate_blocks.rs2
-rw-r--r--src/test/mir-opt/derefer_complex_case.main.Derefer.diff8
-rw-r--r--src/test/mir-opt/derefer_complex_case.rs1
-rw-r--r--src/test/mir-opt/derefer_inline_test.main.Derefer.diff4
-rw-r--r--src/test/mir-opt/derefer_inline_test.rs1
-rw-r--r--src/test/mir-opt/derefer_terminator_test.main.Derefer.diff4
-rw-r--r--src/test/mir-opt/derefer_terminator_test.rs1
-rw-r--r--src/test/mir-opt/derefer_test.rs1
-rw-r--r--src/test/mir-opt/derefer_test_multiple.rs1
-rw-r--r--src/test/mir-opt/equal_true.rs2
-rw-r--r--src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff23
-rw-r--r--src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff23
-rw-r--r--src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff2
-rw-r--r--src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff12
-rw-r--r--src/test/mir-opt/instrument_coverage.rs1
-rw-r--r--src/test/mir-opt/not_equal_false.rs1
-rw-r--r--src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff50
-rw-r--r--src/test/mir-opt/remove_storage_markers.rs2
-rw-r--r--src/test/mir-opt/remove_zsts_dont_touch_unions.rs2
-rw-r--r--src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir4
-rw-r--r--src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir8
-rw-r--r--src/test/mir-opt/retag.rs1
-rw-r--r--src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir4
-rw-r--r--src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir4
-rw-r--r--src/test/mir-opt/simplify-locals-removes-unused-consts.rs1
-rw-r--r--src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff54
-rw-r--r--src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs1
-rw-r--r--src/test/run-make/coverage-llvmir/filecheck.testprog.txt2
-rw-r--r--src/test/rustdoc-gui/label-next-to-symbol.goml8
-rw-r--r--src/test/rustdoc-gui/pocket-menu.goml2
-rw-r--r--src/test/rustdoc-gui/search-filter.goml18
-rw-r--r--src/test/rustdoc-gui/search-result-display.goml24
-rw-r--r--src/test/rustdoc-gui/sidebar-mobile-scroll.goml31
-rw-r--r--src/test/rustdoc-gui/sidebar-source-code-display.goml11
-rw-r--r--src/test/rustdoc-json/primitive.rs10
-rw-r--r--src/test/rustdoc-ui/z-help.stdout1
-rw-r--r--src/test/rustdoc/empty-impl-block-private-with-doc.rs44
-rw-r--r--src/test/rustdoc/empty-impl-block-private.rs40
-rw-r--r--src/test/rustdoc/intra-doc/assoc-reexport-super.rs20
-rw-r--r--src/test/ui-fulldeps/pprust-expr-roundtrip.rs4
-rw-r--r--src/test/ui/associated-types/issue-22560.stderr46
-rw-r--r--src/test/ui/associated-types/issue-59324.rs2
-rw-r--r--src/test/ui/associated-types/issue-59324.stderr9
-rw-r--r--src/test/ui/backtrace-apple-no-dsymutil.rs2
-rw-r--r--src/test/ui/cfg/cfg-method-receiver.rs12
-rw-r--r--src/test/ui/cfg/cfg-method-receiver.stderr34
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-100217.rs42
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-73298.rs23
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-82268.rs73
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-83972.rs38
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-84669.rs30
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-86710.rs73
-rw-r--r--src/test/ui/const-generics/issues/issue-100313.rs21
-rw-r--r--src/test/ui/const-generics/issues/issue-100313.stderr15
-rw-r--r--src/test/ui/consts/const_in_pattern/incomplete-slice.rs15
-rw-r--r--src/test/ui/consts/const_in_pattern/incomplete-slice.stderr26
-rw-r--r--src/test/ui/consts/extra-const-ub/detect-extra-ub.rs45
-rw-r--r--src/test/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr71
-rw-r--r--src/test/ui/copy-a-resource.stderr4
-rw-r--r--src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs1
-rw-r--r--src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr21
-rw-r--r--src/test/ui/fn/implied-bounds-unnorm-associated-type-2.rs3
-rw-r--r--src/test/ui/fn/implied-bounds-unnorm-associated-type-2.stderr17
-rw-r--r--src/test/ui/fn/implied-bounds-unnorm-associated-type-3.rs5
-rw-r--r--src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr14
-rw-r--r--src/test/ui/fn/implied-bounds-unnorm-associated-type-4.rs24
-rw-r--r--src/test/ui/fn/implied-bounds-unnorm-associated-type-4.stderr14
-rw-r--r--src/test/ui/fn/implied-bounds-unnorm-associated-type-5.rs23
-rw-r--r--src/test/ui/fn/implied-bounds-unnorm-associated-type-5.stderr19
-rw-r--r--src/test/ui/fn/implied-bounds-unnorm-associated-type.rs6
-rw-r--r--src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr20
-rw-r--r--src/test/ui/generic-associated-types/bugs/issue-87748.stderr20
-rw-r--r--src/test/ui/generic-associated-types/issue-87748.rs (renamed from src/test/ui/generic-associated-types/bugs/issue-87748.rs)10
-rw-r--r--src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs1
-rw-r--r--src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr13
-rw-r--r--src/test/ui/hrtb/issue-30786.stderr8
-rw-r--r--src/test/ui/impl-trait/issue-100187.rs12
-rw-r--r--src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.rs27
-rw-r--r--src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.stderr15
-rw-r--r--src/test/ui/issues/issue-21950.stderr18
-rw-r--r--src/test/ui/issues/issue-2823.stderr4
-rw-r--r--src/test/ui/json-multiple.stderr1
-rw-r--r--src/test/ui/json-options.stderr1
-rw-r--r--src/test/ui/json/json-and-color.rs (renamed from src/test/ui/json-and-color.rs)0
-rw-r--r--src/test/ui/json/json-and-color.stderr (renamed from src/test/ui/json-and-color.stderr)0
-rw-r--r--src/test/ui/json/json-and-error-format.rs (renamed from src/test/ui/json-and-error-format.rs)0
-rw-r--r--src/test/ui/json/json-and-error-format.stderr (renamed from src/test/ui/json-and-error-format.stderr)0
-rw-r--r--src/test/ui/json/json-bom-plus-crlf-multifile-aux.rs (renamed from src/test/ui/json-bom-plus-crlf-multifile-aux.rs)0
-rw-r--r--src/test/ui/json/json-bom-plus-crlf-multifile.rs (renamed from src/test/ui/json-bom-plus-crlf-multifile.rs)0
-rw-r--r--src/test/ui/json/json-bom-plus-crlf-multifile.stderr (renamed from src/test/ui/json-bom-plus-crlf-multifile.stderr)0
-rw-r--r--src/test/ui/json/json-bom-plus-crlf.rs (renamed from src/test/ui/json-bom-plus-crlf.rs)0
-rw-r--r--src/test/ui/json/json-bom-plus-crlf.stderr (renamed from src/test/ui/json-bom-plus-crlf.stderr)0
-rw-r--r--src/test/ui/json/json-invalid.rs (renamed from src/test/ui/json-invalid.rs)0
-rw-r--r--src/test/ui/json/json-invalid.stderr (renamed from src/test/ui/json-invalid.stderr)0
-rw-r--r--src/test/ui/json/json-multiple.polonius.stderr (renamed from src/test/ui/json-multiple.polonius.stderr)0
-rw-r--r--src/test/ui/json/json-multiple.rs (renamed from src/test/ui/json-multiple.rs)0
-rw-r--r--src/test/ui/json/json-multiple.stderr1
-rw-r--r--src/test/ui/json/json-options.polonius.stderr (renamed from src/test/ui/json-options.polonius.stderr)0
-rw-r--r--src/test/ui/json/json-options.rs (renamed from src/test/ui/json-options.rs)0
-rw-r--r--src/test/ui/json/json-options.stderr1
-rw-r--r--src/test/ui/json/json-short.rs (renamed from src/test/ui/json-short.rs)0
-rw-r--r--src/test/ui/json/json-short.stderr (renamed from src/test/ui/json-short.stderr)0
-rw-r--r--src/test/ui/lint/unused_parens_multibyte_recovery.rs11
-rw-r--r--src/test/ui/lint/unused_parens_multibyte_recovery.stderr43
-rw-r--r--src/test/ui/lowering/issue-96847.rs14
-rw-r--r--src/test/ui/macros/stringify.rs5
-rw-r--r--src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs1
-rw-r--r--src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr11
-rw-r--r--src/test/ui/noncopyable-class.stderr8
-rw-r--r--src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs8
-rw-r--r--src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr10
-rw-r--r--src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed11
-rw-r--r--src/test/ui/parser/suggest-suggest-semicolon-before-array.rs11
-rw-r--r--src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr13
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.rs8
-rw-r--r--src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.stderr11
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs18
-rw-r--r--src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr23
-rw-r--r--src/test/ui/stats/hir-stats.rs41
-rw-r--r--src/test/ui/stats/hir-stats.stderr151
-rw-r--r--src/test/ui/std-backtrace.rs2
-rw-r--r--src/test/ui/suggestions/as-ref.rs7
-rw-r--r--src/test/ui/suggestions/as-ref.stderr62
-rw-r--r--src/test/ui/suggestions/field-access-considering-privacy.rs35
-rw-r--r--src/test/ui/suggestions/field-access-considering-privacy.stderr14
-rw-r--r--src/test/ui/traits/alias/generic-default-in-dyn.rs10
-rw-r--r--src/test/ui/traits/alias/generic-default-in-dyn.stderr39
-rw-r--r--src/test/ui/traits/alias/self-in-generics.rs8
-rw-r--r--src/test/ui/traits/alias/self-in-generics.stderr11
-rw-r--r--src/test/ui/traits/unspecified-self-in-trait-ref.rs (renamed from src/test/ui/unspecified-self-in-trait-ref.rs)0
-rw-r--r--src/test/ui/traits/unspecified-self-in-trait-ref.stderr (renamed from src/test/ui/unspecified-self-in-trait-ref.stderr)0
-rw-r--r--src/test/ui/typeck/issue-100246.rs30
-rw-r--r--src/test/ui/typeck/issue-100246.stderr13
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/CHANGELOG.md8
-rw-r--r--src/tools/clippy/CONTRIBUTING.md6
-rw-r--r--src/tools/clippy/Cargo.toml2
-rw-r--r--src/tools/clippy/README.md2
-rw-r--r--src/tools/clippy/book/src/configuration.md2
-rw-r--r--src/tools/clippy/clippy_dev/src/new_lint.rs2
-rw-r--r--src/tools/clippy/clippy_dev/src/update_lints.rs6
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/checked_conversions.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/create_dir.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/default.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs334
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_names.rs (renamed from src/tools/clippy/clippy_lints/src/blacklisted_name.rs)26
-rw-r--r--src/tools/clippy/clippy_lints/src/double_parens.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/formatting.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/from_str_radix_10.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_all.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_correctness.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_lints.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_nursery.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_style.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_instant_elapsed.rs69
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_ok_or.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/map_err_ignore.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/try_err.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/mem_replace.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_used.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/option_env_unwrap.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/partialeq_to_none.rs104
-rw-r--r--src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/precedence.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/ranges.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_closure_call.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/renamed_lints.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_rounding.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_unit.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs49
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/verbose_file_reads.rs6
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs329
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/numeric_literal.rs10
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/source.rs18
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs54
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr4
-rw-r--r--src/tools/clippy/tests/ui-toml/bad_toml_type/clippy.toml2
-rw-r--r--src/tools/clippy/tests/ui-toml/bad_toml_type/conf_bad_type.stderr2
-rw-r--r--src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr16
-rw-r--r--src/tools/clippy/tests/ui-toml/blacklisted_names_append/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr10
-rw-r--r--src/tools/clippy/tests/ui-toml/blacklisted_names_replace/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/conf_deprecated_key/clippy.toml5
-rw-r--r--src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs10
-rw-r--r--src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr15
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_names_append/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.rs (renamed from src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.rs)4
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr16
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_names_replace/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.rs (renamed from src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.rs)4
-rw-r--r--src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr10
-rw-r--r--src/tools/clippy/tests/ui-toml/duplicated_keys/clippy.toml5
-rw-r--r--src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.rs1
-rw-r--r--src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.stderr8
-rw-r--r--src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr2
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_blacklist/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr46
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallow/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs (renamed from src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs)2
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr46
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr1
-rw-r--r--src/tools/clippy/tests/ui/assertions_on_result_states.fixed8
-rw-r--r--src/tools/clippy/tests/ui/assertions_on_result_states.rs8
-rw-r--r--src/tools/clippy/tests/ui/assertions_on_result_states.stderr10
-rw-r--r--src/tools/clippy/tests/ui/blacklisted_name.stderr88
-rw-r--r--src/tools/clippy/tests/ui/borrow_box.rs2
-rw-r--r--src/tools/clippy/tests/ui/box_collection.rs2
-rw-r--r--src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed2
-rw-r--r--src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs2
-rw-r--r--src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr8
-rw-r--r--src/tools/clippy/tests/ui/clone_on_copy.fixed7
-rw-r--r--src/tools/clippy/tests/ui/clone_on_copy.rs7
-rw-r--r--src/tools/clippy/tests/ui/clone_on_copy.stderr8
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2760.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-3462.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/regressions.rs2
-rw-r--r--src/tools/clippy/tests/ui/def_id_nocore.rs1
-rw-r--r--src/tools/clippy/tests/ui/def_id_nocore.stderr2
-rw-r--r--src/tools/clippy/tests/ui/default_trait_access.fixed6
-rw-r--r--src/tools/clippy/tests/ui/default_trait_access.rs6
-rw-r--r--src/tools/clippy/tests/ui/default_trait_access.stderr18
-rw-r--r--src/tools/clippy/tests/ui/disallowed_names.rs (renamed from src/tools/clippy/tests/ui/blacklisted_name.rs)4
-rw-r--r--src/tools/clippy/tests/ui/disallowed_names.stderr88
-rw-r--r--src/tools/clippy/tests/ui/diverging_sub_expression.rs2
-rw-r--r--src/tools/clippy/tests/ui/empty_loop_no_std.rs1
-rw-r--r--src/tools/clippy/tests/ui/empty_loop_no_std.stderr4
-rw-r--r--src/tools/clippy/tests/ui/expect.stderr2
-rw-r--r--src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs4
-rw-r--r--src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr4
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.fixed51
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.rs51
-rw-r--r--src/tools/clippy/tests/ui/explicit_auto_deref.stderr144
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else.rs2
-rw-r--r--src/tools/clippy/tests/ui/if_same_then_else2.rs2
-rw-r--r--src/tools/clippy/tests/ui/ifs_same_cond.rs4
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_next.fixed2
-rw-r--r--src/tools/clippy/tests/ui/iter_skip_next.rs2
-rw-r--r--src/tools/clippy/tests/ui/let_if_seq.rs2
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2018.fixed2
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2021.fixed2
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.fixed2
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.rs2
-rw-r--r--src/tools/clippy/tests/ui/manual_instant_elapsed.fixed27
-rw-r--r--src/tools/clippy/tests/ui/manual_instant_elapsed.rs27
-rw-r--r--src/tools/clippy/tests/ui/manual_instant_elapsed.stderr16
-rw-r--r--src/tools/clippy/tests/ui/manual_ok_or.fixed2
-rw-r--r--src/tools/clippy/tests/ui/manual_ok_or.rs2
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms2.rs2
-rw-r--r--src/tools/clippy/tests/ui/methods.rs2
-rw-r--r--src/tools/clippy/tests/ui/mismatching_type_param_order.rs2
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs9
-rw-r--r--src/tools/clippy/tests/ui/missing_doc.rs (renamed from src/tools/clippy/tests/ui/missing-doc.rs)13
-rw-r--r--src/tools/clippy/tests/ui/missing_doc.stderr (renamed from src/tools/clippy/tests/ui/missing-doc.stderr)48
-rw-r--r--src/tools/clippy/tests/ui/missing_doc_crate.rs (renamed from src/tools/clippy/tests/ui/missing-doc-crate.rs)0
-rw-r--r--src/tools/clippy/tests/ui/missing_doc_crate_missing.rs (renamed from src/tools/clippy/tests/ui/missing-doc-crate-missing.rs)0
-rw-r--r--src/tools/clippy/tests/ui/missing_doc_crate_missing.stderr (renamed from src/tools/clippy/tests/ui/missing-doc-crate-missing.stderr)2
-rw-r--r--src/tools/clippy/tests/ui/missing_doc_impl.rs (renamed from src/tools/clippy/tests/ui/missing-doc-impl.rs)15
-rw-r--r--src/tools/clippy/tests/ui/missing_doc_impl.stderr (renamed from src/tools/clippy/tests/ui/missing-doc-impl.stderr)30
-rw-r--r--src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed6
-rw-r--r--src/tools/clippy/tests/ui/mistyped_literal_suffix.rs6
-rw-r--r--src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr32
-rw-r--r--src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs2
-rw-r--r--src/tools/clippy/tests/ui/op_ref.rs2
-rw-r--r--src/tools/clippy/tests/ui/overly_complex_bool_expr.rs (renamed from src/tools/clippy/tests/ui/logic_bug.rs)4
-rw-r--r--src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr (renamed from src/tools/clippy/tests/ui/logic_bug.stderr)22
-rw-r--r--src/tools/clippy/tests/ui/partialeq_to_none.fixed62
-rw-r--r--src/tools/clippy/tests/ui/partialeq_to_none.rs62
-rw-r--r--src/tools/clippy/tests/ui/partialeq_to_none.stderr110
-rw-r--r--src/tools/clippy/tests/ui/rc_mutex.rs2
-rw-r--r--src/tools/clippy/tests/ui/redundant_allocation.rs12
-rw-r--r--src/tools/clippy/tests/ui/redundant_allocation.stderr40
-rw-r--r--src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed2
-rw-r--r--src/tools/clippy/tests/ui/redundant_allocation_fixable.rs2
-rw-r--r--src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed20
-rw-r--r--src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs20
-rw-r--r--src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr50
-rw-r--r--src/tools/clippy/tests/ui/rename.fixed4
-rw-r--r--src/tools/clippy/tests/ui/rename.rs4
-rw-r--r--src/tools/clippy/tests/ui/rename.stderr88
-rw-r--r--src/tools/clippy/tests/ui/same_functions_in_if_condition.rs4
-rw-r--r--src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr8
-rw-r--r--src/tools/clippy/tests/ui/skip_while_next.rs2
-rw-r--r--src/tools/clippy/tests/ui/swap.fixed2
-rw-r--r--src/tools/clippy/tests/ui/swap.rs2
-rw-r--r--src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs2
-rw-r--r--src/tools/clippy/tests/ui/unit_arg.rs12
-rw-r--r--src/tools/clippy/tests/ui/unit_arg.stderr20
-rw-r--r--src/tools/clippy/tests/ui/unwrap_expect_used.rs10
-rw-r--r--src/tools/clippy/tests/ui/unwrap_expect_used.stderr36
-rw-r--r--src/tools/clippy/tests/ui/used_underscore_binding.rs2
-rw-r--r--src/tools/compiletest/Cargo.toml1
-rw-r--r--src/tools/compiletest/src/common.rs129
-rw-r--r--src/tools/compiletest/src/header.rs31
-rw-r--r--src/tools/compiletest/src/header/tests.rs193
-rw-r--r--src/tools/compiletest/src/main.rs5
-rw-r--r--src/tools/compiletest/src/runtest.rs5
-rw-r--r--src/tools/compiletest/src/util.rs152
-rw-r--r--src/tools/compiletest/src/util/tests.rs37
m---------src/tools/miri16
-rw-r--r--src/tools/rustdoc-gui/tester.js16
-rw-r--r--src/tools/rustfmt/src/chains.rs10
-rw-r--r--src/tools/tidy/src/bins.rs8
-rwxr-xr-xx.ps128
-rwxr-xr-xx.py30
-rwxr-xr-xx.sh33
525 files changed, 6752 insertions, 3062 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 5410613548c..ceda348025e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -389,26 +389,26 @@ jobs:
             os: windows-latest-xl
           - name: i686-mingw-1
             env:
-              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
+              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --set llvm.allow-old-toolchain"
               SCRIPT: make ci-mingw-subset-1
               CUSTOM_MINGW: 1
             os: windows-latest-xl
           - name: i686-mingw-2
             env:
-              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu"
+              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --set llvm.allow-old-toolchain"
               SCRIPT: make ci-mingw-subset-2
               CUSTOM_MINGW: 1
             os: windows-latest-xl
           - name: x86_64-mingw-1
             env:
               SCRIPT: make ci-mingw-subset-1
-              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler --set llvm.allow-old-toolchain"
               CUSTOM_MINGW: 1
             os: windows-latest-xl
           - name: x86_64-mingw-2
             env:
               SCRIPT: make ci-mingw-subset-2
-              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler --set llvm.allow-old-toolchain"
               CUSTOM_MINGW: 1
             os: windows-latest-xl
           - name: dist-x86_64-msvc
@@ -432,7 +432,7 @@ jobs:
             os: windows-latest-xl
           - name: dist-i686-mingw
             env:
-              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler"
+              RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain"
               SCRIPT: python x.py dist
               CUSTOM_MINGW: 1
               DIST_REQUIRE_ALL_TOOLS: 1
@@ -440,7 +440,7 @@ jobs:
           - name: dist-x86_64-mingw
             env:
               SCRIPT: python x.py dist
-              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler"
+              RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain"
               CUSTOM_MINGW: 1
               DIST_REQUIRE_ALL_TOOLS: 1
             os: windows-latest-xl
diff --git a/.gitmodules b/.gitmodules
index cca60e337d2..9a664b65098 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -34,7 +34,7 @@
 [submodule "src/llvm-project"]
 	path = src/llvm-project
 	url = https://github.com/rust-lang/llvm-project.git
-	branch = rustc/14.0-2022-06-20
+	branch = rustc/15.0-2022-08-09
 [submodule "src/doc/embedded-book"]
 	path = src/doc/embedded-book
 	url = https://github.com/rust-embedded/book.git
diff --git a/Cargo.lock b/Cargo.lock
index ededa7c2ecf..10ebff84887 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -333,7 +333,6 @@ dependencies = [
  "cargo-util",
  "clap",
  "crates-io",
- "crossbeam-utils",
  "curl",
  "curl-sys",
  "env_logger 0.9.0",
@@ -357,7 +356,6 @@ dependencies = [
  "libgit2-sys",
  "log",
  "memchr",
- "num_cpus",
  "opener",
  "openssl",
  "os_info",
@@ -417,6 +415,7 @@ dependencies = [
 name = "cargo-miri"
 version = "0.1.0"
 dependencies = [
+ "cargo_metadata 0.15.0",
  "directories",
  "rustc-workspace-hack",
  "rustc_version",
@@ -465,6 +464,7 @@ dependencies = [
  "termcolor",
  "toml_edit",
  "url 2.2.2",
+ "winapi",
 ]
 
 [[package]]
@@ -659,7 +659,7 @@ dependencies = [
 
 [[package]]
 name = "clippy"
-version = "0.1.64"
+version = "0.1.65"
 dependencies = [
  "clippy_lints",
  "clippy_utils",
@@ -702,7 +702,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_lints"
-version = "0.1.64"
+version = "0.1.65"
 dependencies = [
  "cargo_metadata 0.14.0",
  "clippy_utils",
@@ -724,7 +724,7 @@ dependencies = [
 
 [[package]]
 name = "clippy_utils"
-version = "0.1.64"
+version = "0.1.65"
 dependencies = [
  "arrayvec",
  "if_chain",
@@ -816,6 +816,7 @@ dependencies = [
  "getopts",
  "glob",
  "lazy_static",
+ "lazycell",
  "libc",
  "miow",
  "regex",
@@ -2139,9 +2140,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
 
 [[package]]
 name = "libc"
-version = "0.2.126"
+version = "0.2.129"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
+checksum = "64de3cc433455c14174d42e554d4027ee631c4d046d43e3ecc6efc4636cdc7a7"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -2655,9 +2656,9 @@ checksum = "dd20eec3dbe4376829cb7d80ae6ac45e0a766831dca50202ff2d40db46a8a024"
 
 [[package]]
 name = "os_info"
-version = "3.4.0"
+version = "3.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0eca3ecae1481e12c3d9379ec541b238a16f0b75c9a409942daa8ec20dbfdb62"
+checksum = "5209b2162b2c140df493a93689e04f8deab3a67634f5bc7a553c0a98e5b8d399"
 dependencies = [
  "log",
  "serde",
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index a5f1cbc96da..6529f11100d 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -19,7 +19,6 @@
 #![feature(rustc_attrs)]
 #![cfg_attr(test, feature(test))]
 #![feature(strict_provenance)]
-#![feature(ptr_const_cast)]
 
 use smallvec::SmallVec;
 
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 870a7c0be33..3f71fce0e3b 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1338,14 +1338,13 @@ pub enum ExprKind {
     ///
     /// The `PathSegment` represents the method name and its generic arguments
     /// (within the angle brackets).
-    /// The first element of the vector of an `Expr` is the expression that evaluates
-    /// to the object on which the method is being called on (the receiver),
-    /// and the remaining elements are the rest of the arguments.
-    /// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
-    /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`.
+    /// The standalone `Expr` is the receiver expression.
+    /// The vector of `Expr` is the arguments.
+    /// `x.foo::<Bar, Baz>(a, b, c, d)` is represented as
+    /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, x, [a, b, c, d])`.
     /// This `Span` is the span of the function, without the dot and receiver
     /// (e.g. `foo(a, b)` in `x.foo(a, b)`
-    MethodCall(PathSegment, Vec<P<Expr>>, Span),
+    MethodCall(PathSegment, P<Expr>, Vec<P<Expr>>, Span),
     /// A tuple (e.g., `(a, b, c, d)`).
     Tup(Vec<P<Expr>>),
     /// A binary operation (e.g., `a + b`, `a * b`).
@@ -2602,7 +2601,7 @@ pub struct Visibility {
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub enum VisibilityKind {
     Public,
-    Restricted { path: P<Path>, id: NodeId },
+    Restricted { path: P<Path>, id: NodeId, shorthand: bool },
     Inherited,
 }
 
@@ -3030,22 +3029,25 @@ pub type ForeignItem = Item<ForeignItemKind>;
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
+    use rustc_data_structures::static_assert_size;
     // These are in alphabetical order, which is easy to maintain.
-    rustc_data_structures::static_assert_size!(AssocItemKind, 72);
-    rustc_data_structures::static_assert_size!(Attribute, 152);
-    rustc_data_structures::static_assert_size!(Block, 48);
-    rustc_data_structures::static_assert_size!(Expr, 104);
-    rustc_data_structures::static_assert_size!(Fn, 192);
-    rustc_data_structures::static_assert_size!(ForeignItemKind, 72);
-    rustc_data_structures::static_assert_size!(GenericBound, 88);
-    rustc_data_structures::static_assert_size!(Generics, 72);
-    rustc_data_structures::static_assert_size!(Impl, 200);
-    rustc_data_structures::static_assert_size!(Item, 200);
-    rustc_data_structures::static_assert_size!(ItemKind, 112);
-    rustc_data_structures::static_assert_size!(Lit, 48);
-    rustc_data_structures::static_assert_size!(Pat, 120);
-    rustc_data_structures::static_assert_size!(Path, 40);
-    rustc_data_structures::static_assert_size!(PathSegment, 24);
-    rustc_data_structures::static_assert_size!(Stmt, 32);
-    rustc_data_structures::static_assert_size!(Ty, 96);
+    static_assert_size!(AssocItem, 160);
+    static_assert_size!(AssocItemKind, 72);
+    static_assert_size!(Attribute, 152);
+    static_assert_size!(Block, 48);
+    static_assert_size!(Expr, 104);
+    static_assert_size!(Fn, 192);
+    static_assert_size!(ForeignItem, 160);
+    static_assert_size!(ForeignItemKind, 72);
+    static_assert_size!(GenericBound, 88);
+    static_assert_size!(Generics, 72);
+    static_assert_size!(Impl, 200);
+    static_assert_size!(Item, 200);
+    static_assert_size!(ItemKind, 112);
+    static_assert_size!(Lit, 48);
+    static_assert_size!(Pat, 120);
+    static_assert_size!(Path, 40);
+    static_assert_size!(PathSegment, 24);
+    static_assert_size!(Stmt, 32);
+    static_assert_size!(Ty, 96);
 }
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 01bd498b377..40c05f43f68 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -1302,10 +1302,11 @@ pub fn noop_visit_expr<T: MutVisitor>(
             vis.visit_expr(f);
             visit_exprs(args, vis);
         }
-        ExprKind::MethodCall(PathSegment { ident, id, args }, exprs, span) => {
+        ExprKind::MethodCall(PathSegment { ident, id, args }, receiver, exprs, span) => {
             vis.visit_ident(ident);
             vis.visit_id(id);
             visit_opt(args, |args| vis.visit_generic_args(args));
+            vis.visit_expr(receiver);
             visit_exprs(exprs, vis);
             vis.visit_span(span);
         }
@@ -1486,7 +1487,7 @@ pub fn noop_flat_map_stmt_kind<T: MutVisitor>(
 pub fn noop_visit_vis<T: MutVisitor>(visibility: &mut Visibility, vis: &mut T) {
     match &mut visibility.kind {
         VisibilityKind::Public | VisibilityKind::Inherited => {}
-        VisibilityKind::Restricted { path, id } => {
+        VisibilityKind::Restricted { path, id, shorthand: _ } => {
             vis.visit_path(path);
             vis.visit_id(id);
         }
diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs
index 74b7fe9e249..5edeb54be5f 100644
--- a/compiler/rustc_ast/src/util/parser.rs
+++ b/compiler/rustc_ast/src/util/parser.rs
@@ -396,9 +396,9 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
             contains_exterior_struct_lit(&x)
         }
 
-        ast::ExprKind::MethodCall(.., ref exprs, _) => {
+        ast::ExprKind::MethodCall(_, ref receiver, _, _) => {
             // X { y: 1 }.bar(...)
-            contains_exterior_struct_lit(&exprs[0])
+            contains_exterior_struct_lit(&receiver)
         }
 
         _ => false,
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index d9594b323dd..4b485b547f4 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -168,8 +168,8 @@ pub trait Visitor<'ast>: Sized {
     fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) {
         walk_param_bound(self, bounds)
     }
-    fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
-        walk_poly_trait_ref(self, t, m)
+    fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) {
+        walk_poly_trait_ref(self, t)
     }
     fn visit_variant_data(&mut self, s: &'ast VariantData) {
         walk_struct_def(self, s)
@@ -177,14 +177,8 @@ pub trait Visitor<'ast>: Sized {
     fn visit_field_def(&mut self, s: &'ast FieldDef) {
         walk_field_def(self, s)
     }
-    fn visit_enum_def(
-        &mut self,
-        enum_definition: &'ast EnumDef,
-        generics: &'ast Generics,
-        item_id: NodeId,
-        _: Span,
-    ) {
-        walk_enum_def(self, enum_definition, generics, item_id)
+    fn visit_enum_def(&mut self, enum_definition: &'ast EnumDef) {
+        walk_enum_def(self, enum_definition)
     }
     fn visit_variant(&mut self, v: &'ast Variant) {
         walk_variant(self, v)
@@ -287,11 +281,8 @@ pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime
     visitor.visit_ident(lifetime.ident);
 }
 
-pub fn walk_poly_trait_ref<'a, V>(
-    visitor: &mut V,
-    trait_ref: &'a PolyTraitRef,
-    _: &TraitBoundModifier,
-) where
+pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, trait_ref: &'a PolyTraitRef)
+where
     V: Visitor<'a>,
 {
     walk_list!(visitor, visit_generic_param, &trait_ref.bound_generic_params);
@@ -334,7 +325,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
         }
         ItemKind::Enum(ref enum_definition, ref generics) => {
             visitor.visit_generics(generics);
-            visitor.visit_enum_def(enum_definition, generics, item.id, item.span)
+            visitor.visit_enum_def(enum_definition)
         }
         ItemKind::Impl(box Impl {
             defaultness: _,
@@ -377,12 +368,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
     walk_list!(visitor, visit_attribute, &item.attrs);
 }
 
-pub fn walk_enum_def<'a, V: Visitor<'a>>(
-    visitor: &mut V,
-    enum_definition: &'a EnumDef,
-    _: &'a Generics,
-    _: NodeId,
-) {
+pub fn walk_enum_def<'a, V: Visitor<'a>>(visitor: &mut V, enum_definition: &'a EnumDef) {
     walk_list!(visitor, visit_variant, &enum_definition.variants);
 }
 
@@ -598,7 +584,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI
 
 pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericBound) {
     match *bound {
-        GenericBound::Trait(ref typ, ref modifier) => visitor.visit_poly_trait_ref(typ, modifier),
+        GenericBound::Trait(ref typ, ref _modifier) => visitor.visit_poly_trait_ref(typ),
         GenericBound::Outlives(ref lifetime) => {
             visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound)
         }
@@ -813,8 +799,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
             visitor.visit_expr(callee_expression);
             walk_list!(visitor, visit_expr, arguments);
         }
-        ExprKind::MethodCall(ref segment, ref arguments, _span) => {
+        ExprKind::MethodCall(ref segment, ref receiver, ref arguments, _span) => {
             visitor.visit_path_segment(expression.span, segment);
+            visitor.visit_expr(receiver);
             walk_list!(visitor, visit_expr, arguments);
         }
         ExprKind::Binary(_, ref left_expression, ref right_expression) => {
@@ -935,7 +922,7 @@ pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) {
 }
 
 pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) {
-    if let VisibilityKind::Restricted { ref path, id } = vis.kind {
+    if let VisibilityKind::Restricted { ref path, id, shorthand: _ } = vis.kind {
         visitor.visit_path(path, id);
     }
 }
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index fb6715ff17e..92e6bc6013d 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -62,7 +62,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         hir::ExprKind::Call(f, self.lower_exprs(args))
                     }
                 }
-                ExprKind::MethodCall(ref seg, ref args, span) => {
+                ExprKind::MethodCall(ref seg, ref receiver, ref args, span) => {
                     let hir_seg = self.arena.alloc(self.lower_path_segment(
                         e.span,
                         seg,
@@ -70,7 +70,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         ParenthesizedGenericArgs::Err,
                         ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                     ));
-                    let args = self.lower_exprs(args);
+                    let args = self.arena.alloc_from_iter(
+                        [&*receiver].into_iter().chain(args.iter()).map(|x| self.lower_expr_mut(x)),
+                    );
                     hir::ExprKind::MethodCall(hir_seg, args, self.lower_span(span))
                 }
                 ExprKind::Binary(binop, ref lhs, ref rhs) => {
@@ -1534,15 +1536,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
             hir::MatchSource::ForLoopDesugar,
         ));
 
-        let attrs: Vec<_> = e.attrs.iter().map(|a| self.lower_attr(a)).collect();
-
         // This is effectively `{ let _result = ...; _result }`.
         // The construct was introduced in #21984 and is necessary to make sure that
         // temporaries in the `head` expression are dropped and do not leak to the
         // surrounding scope of the `match` since the `match` is not a terminating scope.
         //
         // Also, add the attributes to the outer returned expr node.
-        self.expr_drop_temps_mut(for_span, match_expr, attrs.into())
+        self.expr_drop_temps_mut(for_span, match_expr, e.attrs.clone())
     }
 
     /// Desugar `ExprKind::Try` from: `<expr>?` into:
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index d5af74d47fd..e08c1d063c1 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -295,14 +295,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
         self.insert(lifetime.span, lifetime.hir_id, Node::Lifetime(lifetime));
     }
 
-    fn visit_variant(&mut self, v: &'hir Variant<'hir>, g: &'hir Generics<'hir>, item_id: HirId) {
+    fn visit_variant(&mut self, v: &'hir Variant<'hir>) {
         self.insert(v.span, v.id, Node::Variant(v));
         self.with_parent(v.id, |this| {
             // Register the constructor of this variant.
             if let Some(ctor_hir_id) = v.data.ctor_hir_id() {
                 this.insert(v.span, ctor_hir_id, Node::Ctor(&v.data));
             }
-            intravisit::walk_variant(this, v, g, item_id);
+            intravisit::walk_variant(this, v);
         });
     }
 
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 0562f7b88a3..38d30d0ffde 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -220,7 +220,20 @@ impl ResolverAstLoweringExt for ResolverAstLowering {
     }
 
     fn get_remapped_def_id(&self, mut local_def_id: LocalDefId) -> LocalDefId {
-        for map in &self.generics_def_id_map {
+        // `generics_def_id_map` is a stack of mappings. As we go deeper in impl traits nesting we
+        // push new mappings so we need to try first the latest mappings, hence `iter().rev()`.
+        //
+        // Consider:
+        //
+        // `fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}`
+        //
+        // We would end with a generics_def_id_map like:
+        //
+        // `[[fn#'b -> impl_trait#'b], [fn#'b -> impl_sized#'b]]`
+        //
+        // for the opaque type generated on `impl Sized + 'b`, We want the result to be:
+        // impl_sized#'b, so iterating forward is the wrong thing to do.
+        for map in self.generics_def_id_map.iter().rev() {
             if let Some(r) = map.get(&local_def_id) {
                 debug!("def_id_remapper: remapping from `{local_def_id:?}` to `{r:?}`");
                 local_def_id = *r;
diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs
index 81006e00fd4..8c67cebae55 100644
--- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs
+++ b/compiler/rustc_ast_lowering/src/lifetime_collector.rs
@@ -1,9 +1,6 @@
 use super::ResolverAstLoweringExt;
 use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor};
-use rustc_ast::{
-    FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, TraitBoundModifier, Ty,
-    TyKind,
-};
+use rustc_ast::{FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind};
 use rustc_hir::def::LifetimeRes;
 use rustc_middle::span_bug;
 use rustc_middle::ty::ResolverAstLowering;
@@ -71,10 +68,10 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
         visit::walk_path_segment(self, path_span, path_segment);
     }
 
-    fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) {
+    fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) {
         self.current_binders.push(t.trait_ref.ref_id);
 
-        visit::walk_poly_trait_ref(self, t, m);
+        visit::walk_poly_trait_ref(self, t);
 
         self.current_binders.pop();
     }
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 60560b1c00e..e61dfef7bd3 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -13,9 +13,7 @@ use rustc_ast::walk_list;
 use rustc_ast::*;
 use rustc_ast_pretty::pprust::{self, State};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{
-    error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed,
-};
+use rustc_errors::{error_code, pluralize, struct_span_err, Applicability, Diagnostic};
 use rustc_parse::validate_attr;
 use rustc_session::lint::builtin::{
     DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY,
@@ -477,7 +475,7 @@ impl<'a> AstValidator<'a> {
         ctx: &str,
         msg: &str,
         sugg: &str,
-        help: impl FnOnce(&mut DiagnosticBuilder<'_, ErrorGuaranteed>),
+        help: impl FnOnce(&mut Diagnostic),
     ) {
         let source_map = self.session.source_map();
         let end = source_map.end_point(sp);
@@ -1196,7 +1194,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     let msg = "free function without a body";
                     let ext = sig.header.ext;
 
-                    let f = |e: &mut DiagnosticBuilder<'_, _>| {
+                    let f = |e: &mut Diagnostic| {
                         if let Extern::Implicit(start_span) | Extern::Explicit(_, start_span) = &ext
                         {
                             let start_suggestion = if let Extern::Explicit(abi, _) = ext {
@@ -1538,25 +1536,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         visit::walk_param_bound(self, bound)
     }
 
-    fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) {
+    fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef) {
         self.check_late_bound_lifetime_defs(&t.bound_generic_params);
-        visit::walk_poly_trait_ref(self, t, m);
+        visit::walk_poly_trait_ref(self, t);
     }
 
     fn visit_variant_data(&mut self, s: &'a VariantData) {
         self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s))
     }
 
-    fn visit_enum_def(
-        &mut self,
-        enum_definition: &'a EnumDef,
-        generics: &'a Generics,
-        item_id: NodeId,
-        _: Span,
-    ) {
-        self.with_banned_assoc_ty_bound(|this| {
-            visit::walk_enum_def(this, enum_definition, generics, item_id)
-        })
+    fn visit_enum_def(&mut self, enum_definition: &'a EnumDef) {
+        self.with_banned_assoc_ty_bound(|this| visit::walk_enum_def(this, enum_definition))
     }
 
     fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs
index 9c7369c83e2..be3e46661bf 100644
--- a/compiler/rustc_ast_passes/src/node_count.rs
+++ b/compiler/rustc_ast_passes/src/node_count.rs
@@ -79,9 +79,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
         self.count += 1;
         walk_param_bound(self, bounds)
     }
-    fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef, m: &TraitBoundModifier) {
+    fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef) {
         self.count += 1;
-        walk_poly_trait_ref(self, t, m)
+        walk_poly_trait_ref(self, t)
     }
     fn visit_variant_data(&mut self, s: &VariantData) {
         self.count += 1;
@@ -91,15 +91,9 @@ impl<'ast> Visitor<'ast> for NodeCounter {
         self.count += 1;
         walk_field_def(self, s)
     }
-    fn visit_enum_def(
-        &mut self,
-        enum_definition: &EnumDef,
-        generics: &Generics,
-        item_id: NodeId,
-        _: Span,
-    ) {
+    fn visit_enum_def(&mut self, enum_definition: &EnumDef) {
         self.count += 1;
-        walk_enum_def(self, enum_definition, generics, item_id)
+        walk_enum_def(self, enum_definition)
     }
     fn visit_variant(&mut self, v: &Variant) {
         self.count += 1;
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index ead38caee28..bcefa8ce0b9 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -193,9 +193,13 @@ impl<'a> State<'a> {
         self.print_call_post(args)
     }
 
-    fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) {
-        let base_args = &args[1..];
-        self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX);
+    fn print_expr_method_call(
+        &mut self,
+        segment: &ast::PathSegment,
+        receiver: &ast::Expr,
+        base_args: &[P<ast::Expr>],
+    ) {
+        self.print_expr_maybe_paren(receiver, parser::PREC_POSTFIX);
         self.word(".");
         self.print_ident(segment.ident);
         if let Some(ref args) = segment.args {
@@ -303,8 +307,8 @@ impl<'a> State<'a> {
             ast::ExprKind::Call(ref func, ref args) => {
                 self.print_expr_call(func, &args);
             }
-            ast::ExprKind::MethodCall(ref segment, ref args, _) => {
-                self.print_expr_method_call(segment, &args);
+            ast::ExprKind::MethodCall(ref segment, ref receiver, ref args, _) => {
+                self.print_expr_method_call(segment, &receiver, &args);
             }
             ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
                 self.print_expr_binary(op, lhs, rhs);
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index f1caf22f364..bd87987010e 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -412,9 +412,9 @@ impl<'a> State<'a> {
     pub(crate) fn print_visibility(&mut self, vis: &ast::Visibility) {
         match vis.kind {
             ast::VisibilityKind::Public => self.word_nbsp("pub"),
-            ast::VisibilityKind::Restricted { ref path, .. } => {
+            ast::VisibilityKind::Restricted { ref path, id: _, shorthand } => {
                 let path = Self::to_string(|s| s.print_path(path, false, 0));
-                if path == "crate" || path == "self" || path == "super" {
+                if shorthand && (path == "crate" || path == "self" || path == "super") {
                     self.word_nbsp(format!("pub({})", path))
                 } else {
                     self.word_nbsp(format!("pub(in {})", path))
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 8bc8964bbd7..84a0d4ba7ba 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -451,7 +451,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
     fn suggest_borrow_fn_like(
         &self,
-        err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+        err: &mut Diagnostic,
         ty: Ty<'tcx>,
         move_sites: &[MoveSite],
         value_name: &str,
@@ -526,12 +526,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
         true
     }
 
-    fn suggest_adding_copy_bounds(
-        &self,
-        err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
-        ty: Ty<'tcx>,
-        span: Span,
-    ) {
+    fn suggest_adding_copy_bounds(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) {
         let tcx = self.infcx.tcx;
         let generics = tcx.generics_of(self.mir_def_id());
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 176090c3b7a..bd3a2a3d694 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -783,7 +783,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
 
     fn maybe_suggest_constrain_dyn_trait_impl(
         &self,
-        diag: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+        diag: &mut Diagnostic,
         f: Region<'tcx>,
         o: Region<'tcx>,
         category: &ConstraintCategory<'tcx>,
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index 16796091830..9fab7ad914a 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -6,7 +6,7 @@ use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
 use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::subst::GenericArgKind;
-use rustc_middle::ty::TypeVisitable;
+use rustc_middle::ty::TypeFoldable;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::{Span, DUMMY_SP};
 
@@ -109,23 +109,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
                 self.add_outlives(r1_vid, r2_vid);
             }
 
-            GenericArgKind::Type(mut t1) => {
+            GenericArgKind::Type(t1) => {
                 // we don't actually use this for anything, but
                 // the `TypeOutlives` code needs an origin.
                 let origin = infer::RelateParamBound(DUMMY_SP, t1, None);
 
-                // Placeholder regions need to be converted now because it may
-                // create new region variables, which can't be done later when
-                // verifying these bounds.
-                if t1.has_placeholders() {
-                    t1 = tcx.fold_regions(t1, |r, _| match *r {
-                        ty::RePlaceholder(placeholder) => {
-                            self.constraints.placeholder_region(self.infcx, placeholder)
-                        }
-                        _ => r,
-                    });
-                }
-
                 TypeOutlives::new(
                     &mut *self,
                     tcx,
@@ -143,6 +131,25 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
         }
     }
 
+    /// Placeholder regions need to be converted eagerly because it may
+    /// create new region variables, which we must not do when verifying
+    /// our region bounds.
+    ///
+    /// FIXME: This should get removed once higher ranked region obligations
+    /// are dealt with during trait solving.
+    fn replace_placeholders_with_nll<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T {
+        if value.has_placeholders() {
+            self.tcx.fold_regions(value, |r, _| match *r {
+                ty::RePlaceholder(placeholder) => {
+                    self.constraints.placeholder_region(self.infcx, placeholder)
+                }
+                _ => r,
+            })
+        } else {
+            value
+        }
+    }
+
     fn verify_to_type_test(
         &mut self,
         generic_kind: GenericKind<'tcx>,
@@ -150,7 +157,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
         verify_bound: VerifyBound<'tcx>,
     ) -> TypeTest<'tcx> {
         let lower_bound = self.to_region_vid(region);
-
         TypeTest { generic_kind, lower_bound, locations: self.locations, verify_bound }
     }
 
@@ -198,6 +204,8 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<'
         a: ty::Region<'tcx>,
         bound: VerifyBound<'tcx>,
     ) {
+        let kind = self.replace_placeholders_with_nll(kind);
+        let bound = self.replace_placeholders_with_nll(bound);
         let type_test = self.verify_to_type_test(kind, a, bound);
         self.add_type_test(type_test);
     }
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index cc0318ede54..74655369faf 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -242,10 +242,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
         let constraint_sets: Vec<_> = unnormalized_input_output_tys
             .flat_map(|ty| {
                 debug!("build: input_or_output={:?}", ty);
-                // We only add implied bounds for the normalized type as the unnormalized
-                // type may not actually get checked by the caller.
-                //
-                // Can otherwise be unsound, see #91068.
+                // We add implied bounds from both the unnormalized and normalized ty.
+                // See issue #87748
+                let constraints_implied1 = self.add_implied_bounds(ty);
                 let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self
                     .param_env
                     .and(type_op::normalize::Normalize::new(ty))
@@ -273,9 +272,10 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
                 // }
                 // ```
                 // Both &Self::Bar and &() are WF
-                let constraints_implied = self.add_implied_bounds(norm_ty);
+                let constraints_implied2 =
+                    if ty != norm_ty { self.add_implied_bounds(norm_ty) } else { None };
                 normalized_inputs_and_output.push(norm_ty);
-                constraints1.into_iter().chain(constraints_implied)
+                constraints1.into_iter().chain(constraints_implied1).chain(constraints_implied2)
             })
             .collect();
 
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index d32b1edcd8f..7bf7f7357bf 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1448,9 +1448,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     ))
                 });
                 debug!(?sig);
-                let sig = self.normalize(sig, term_location);
-                self.check_call_dest(body, term, &sig, *destination, target, term_location);
-
+                // IMPORTANT: We have to prove well formed for the function signature before
+                // we normalize it, as otherwise types like `<&'a &'b () as Trait>::Assoc`
+                // get normalized away, causing us to ignore the `'b: 'a` bound used by the function.
+                //
+                // Normalization results in a well formed type if the input is well formed, so we
+                // don't have to check it twice.
+                //
+                // See #91068 for an example.
                 self.prove_predicates(
                     sig.inputs_and_output
                         .iter()
@@ -1458,6 +1463,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     term_location.to_locations(),
                     ConstraintCategory::Boring,
                 );
+                let sig = self.normalize(sig, term_location);
+                self.check_call_dest(body, term, &sig, *destination, target, term_location);
 
                 // The ordinary liveness rules will ensure that all
                 // regions in the type of the callee are live here. We
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index dcea883a5a3..c04d04020cc 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -240,8 +240,8 @@ impl<'cx, 'a> Context<'cx, 'a> {
                 self.manage_cond_expr(prefix);
                 self.manage_cond_expr(suffix);
             }
-            ExprKind::MethodCall(_, ref mut local_exprs, _) => {
-                for local_expr in local_exprs.iter_mut().skip(1) {
+            ExprKind::MethodCall(_, _,ref mut local_exprs, _) => {
+                for local_expr in local_exprs.iter_mut() {
                     self.manage_cond_expr(local_expr);
                 }
             }
@@ -377,14 +377,12 @@ impl<'cx, 'a> Context<'cx, 'a> {
                     id: DUMMY_NODE_ID,
                     ident: Ident::new(sym::try_capture, self.span),
                 },
-                vec![
-                    expr_paren(self.cx, self.span, self.cx.expr_addr_of(self.span, wrapper)),
-                    expr_addr_of_mut(
-                        self.cx,
-                        self.span,
-                        self.cx.expr_path(Path::from_ident(capture)),
-                    ),
-                ],
+                expr_paren(self.cx, self.span, self.cx.expr_addr_of(self.span, wrapper)),
+                vec![expr_addr_of_mut(
+                    self.cx,
+                    self.span,
+                    self.cx.expr_path(Path::from_ident(capture)),
+                )],
                 self.span,
             ))
             .add_trailing_semicolon();
@@ -442,10 +440,11 @@ fn expr_addr_of_mut(cx: &ExtCtxt<'_>, sp: Span, e: P<Expr>) -> P<Expr> {
 fn expr_method_call(
     cx: &ExtCtxt<'_>,
     path: PathSegment,
+    receiver: P<Expr>,
     args: Vec<P<Expr>>,
     span: Span,
 ) -> P<Expr> {
-    cx.expr(span, ExprKind::MethodCall(path, args, span))
+    cx.expr(span, ExprKind::MethodCall(path, receiver, args, span))
 }
 
 fn expr_paren(cx: &ExtCtxt<'_>, sp: Span, e: P<Expr>) -> P<Expr> {
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 735017aa5a8..ef64f52d40b 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -383,16 +383,12 @@ fn find_type_parameters(
         }
 
         // Place bound generic params on a stack, to extract them when a type is encountered.
-        fn visit_poly_trait_ref(
-            &mut self,
-            trait_ref: &'a ast::PolyTraitRef,
-            modifier: &'a ast::TraitBoundModifier,
-        ) {
+        fn visit_poly_trait_ref(&mut self, trait_ref: &'a ast::PolyTraitRef) {
             let stack_len = self.bound_generic_params_stack.len();
             self.bound_generic_params_stack
                 .extend(trait_ref.bound_generic_params.clone().into_iter());
 
-            visit::walk_poly_trait_ref(self, trait_ref, modifier);
+            visit::walk_poly_trait_ref(self, trait_ref);
 
             self.bound_generic_params_stack.truncate(stack_len);
         }
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index 532049c858d..402fbb16f97 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -15,9 +15,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.56"
+version = "1.0.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
+checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142"
 
 [[package]]
 name = "ar"
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index a0a640473eb..96d238eda59 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -440,6 +440,8 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
             .features
             .split(',')
             .filter(|v| !v.is_empty() && backend_feature_name(v).is_some())
+            // Drop +atomics-32 feature introduced in LLVM 15.
+            .filter(|v| *v != "+atomics-32" || get_version() >= (15, 0, 0))
             .map(String::from),
     );
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 63207803e32..953761a7820 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1583,12 +1583,21 @@ fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool {
 fn add_pre_link_objects(
     cmd: &mut dyn Linker,
     sess: &Session,
+    flavor: LinkerFlavor,
     link_output_kind: LinkOutputKind,
     self_contained: bool,
 ) {
+    // FIXME: we are currently missing some infra here (per-linker-flavor CRT objects),
+    // so Fuchsia has to be special-cased.
     let opts = &sess.target;
-    let objects =
-        if self_contained { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects };
+    let empty = Default::default();
+    let objects = if self_contained {
+        &opts.pre_link_objects_fallback
+    } else if !(sess.target.os == "fuchsia" && flavor == LinkerFlavor::Gcc) {
+        &opts.pre_link_objects
+    } else {
+        &empty
+    };
     for obj in objects.get(&link_output_kind).iter().copied().flatten() {
         cmd.add_object(&get_object_file_path(sess, obj, self_contained));
     }
@@ -1914,7 +1923,7 @@ fn linker_with_args<'a>(
     // ------------ Object code and libraries, order-dependent ------------
 
     // Pre-link CRT objects.
-    add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
+    add_pre_link_objects(cmd, sess, flavor, link_output_kind, crt_objects_fallback);
 
     add_linked_symbol_object(
         cmd,
@@ -2070,7 +2079,10 @@ fn add_order_independent_options(
 
     add_link_script(cmd, sess, tmpdir, crate_type);
 
-    if sess.target.os == "fuchsia" && crate_type == CrateType::Executable {
+    if sess.target.os == "fuchsia"
+        && crate_type == CrateType::Executable
+        && flavor != LinkerFlavor::Gcc
+    {
         let prefix = if sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
             "asan/"
         } else {
@@ -2674,11 +2686,16 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
     let os = &sess.target.os;
     let llvm_target = &sess.target.llvm_target;
     if sess.target.vendor != "apple"
-        || !matches!(os.as_ref(), "ios" | "tvos" | "watchos")
+        || !matches!(os.as_ref(), "ios" | "tvos" | "watchos" | "macos")
         || (flavor != LinkerFlavor::Gcc && flavor != LinkerFlavor::Lld(LldFlavor::Ld64))
     {
         return;
     }
+
+    if os == "macos" && flavor != LinkerFlavor::Lld(LldFlavor::Ld64) {
+        return;
+    }
+
     let sdk_name = match (arch.as_ref(), os.as_ref()) {
         ("aarch64", "tvos") => "appletvos",
         ("x86_64", "tvos") => "appletvsimulator",
@@ -2694,6 +2711,7 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
         ("aarch64", "watchos") if llvm_target.ends_with("-simulator") => "watchsimulator",
         ("aarch64", "watchos") => "watchos",
         ("arm", "watchos") => "watchos",
+        (_, "macos") => "macosx",
         _ => {
             sess.err(&format!("unsupported arch `{}` for os `{}`", arch, os));
             return;
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index fc2e6652a3d..684877cae76 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -236,6 +236,16 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
 
     const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error
 
+    #[inline(always)]
+    fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+        ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks
+    }
+
+    #[inline(always)]
+    fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+        ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks
+    }
+
     fn load_mir(
         ecx: &InterpCx<'mir, 'tcx, Self>,
         instance: ty::InstanceDef<'tcx>,
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 71ccd1799fa..9b9919fcc2a 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -437,24 +437,12 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
     type FrameExtra = ();
 
     #[inline(always)]
-    fn enforce_alignment(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
-        // We do not check for alignment to avoid having to carry an `Align`
-        // in `ConstValue::ByRef`.
-        false
-    }
-
-    #[inline(always)]
     fn force_int_for_alignment_check(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
         // We do not support `force_int`.
         false
     }
 
     #[inline(always)]
-    fn enforce_validity(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
-        false // for now, we don't enforce validity
-    }
-
-    #[inline(always)]
     fn enforce_number_init(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool {
         true
     }
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 94ba62c160c..fe80a55dfd2 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -823,9 +823,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
+    use rustc_data_structures::static_assert_size;
     // These are in alphabetical order, which is easy to maintain.
-    rustc_data_structures::static_assert_size!(Immediate, 56);
-    rustc_data_structures::static_assert_size!(ImmTy<'_>, 72);
-    rustc_data_structures::static_assert_size!(Operand, 64);
-    rustc_data_structures::static_assert_size!(OpTy<'_>, 88);
+    static_assert_size!(Immediate, 56);
+    static_assert_size!(ImmTy<'_>, 72);
+    static_assert_size!(Operand, 64);
+    static_assert_size!(OpTy<'_>, 88);
 }
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index f4571a1ca3d..97fe23cb5bc 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -891,10 +891,11 @@ where
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
+    use rustc_data_structures::static_assert_size;
     // These are in alphabetical order, which is easy to maintain.
-    rustc_data_structures::static_assert_size!(MemPlaceMeta, 24);
-    rustc_data_structures::static_assert_size!(MemPlace, 40);
-    rustc_data_structures::static_assert_size!(MPlaceTy<'_>, 64);
-    rustc_data_structures::static_assert_size!(Place, 48);
-    rustc_data_structures::static_assert_size!(PlaceTy<'_>, 72);
+    static_assert_size!(MemPlaceMeta, 24);
+    static_assert_size!(MemPlace, 40);
+    static_assert_size!(MPlaceTy<'_>, 64);
+    static_assert_size!(Place, 48);
+    static_assert_size!(PlaceTy<'_>, 72);
 }
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 6f6717721fb..f1b1855c3ec 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -1005,6 +1005,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// It will error if the bits at the destination do not match the ones described by the layout.
     #[inline(always)]
     pub fn validate_operand(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
+        // Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's
+        // still correct to not use `ctfe_mode`: that mode is for validation of the final constant
+        // value, it rules out things like `UnsafeCell` in awkward places. It also can make checking
+        // recurse through references which, for now, we don't want here, either.
         self.validate_operand_internal(op, vec![], None, None)
     }
 }
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 53ae913f94f..94639bf8e1e 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -1148,6 +1148,17 @@ static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send +
     LazyLock::new(|| {
         let hook = panic::take_hook();
         panic::set_hook(Box::new(|info| {
+            // If the error was caused by a broken pipe then this is not a bug.
+            // Write the error and return immediately. See #98700.
+            #[cfg(windows)]
+            if let Some(msg) = info.payload().downcast_ref::<String>() {
+                if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)")
+                {
+                    early_error_no_abort(ErrorOutputType::default(), &msg);
+                    return;
+                }
+            };
+
             // Invoke the default handler, which prints the actual panic message and optionally a backtrace
             (*DEFAULT_HOOK)(info);
 
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 2d3155a70ed..15c1858023d 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -4,7 +4,6 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(drain_filter)]
-#![feature(backtrace)]
 #![feature(if_let_guard)]
 #![cfg_attr(bootstrap, feature(let_chains))]
 #![feature(let_else)]
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index f7e1575afbf..e009e4f7c68 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -14,7 +14,7 @@ use rustc_ast::{NodeId, DUMMY_NODE_ID};
 use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, TransparencyError};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder};
 use rustc_feature::Features;
 use rustc_lint_defs::builtin::{
     RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
@@ -608,11 +608,7 @@ enum ExplainDocComment {
     },
 }
 
-fn annotate_doc_comment(
-    err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
-    sm: &SourceMap,
-    span: Span,
-) {
+fn annotate_doc_comment(err: &mut Diagnostic, sm: &SourceMap, span: Span) {
     if let Ok(src) = sm.span_to_snippet(span) {
         if src.starts_with("///") || src.starts_with("/**") {
             err.subdiagnostic(ExplainDocComment::Outer { span });
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 617433a9803..7a87a3e4882 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -3491,16 +3491,16 @@ impl<'hir> Node<'hir> {
 mod size_asserts {
     use super::*;
     // These are in alphabetical order, which is easy to maintain.
-    rustc_data_structures::static_assert_size!(Block<'static>, 48);
-    rustc_data_structures::static_assert_size!(Expr<'static>, 56);
-    rustc_data_structures::static_assert_size!(ForeignItem<'static>, 72);
-    rustc_data_structures::static_assert_size!(GenericBound<'_>, 48);
-    rustc_data_structures::static_assert_size!(Generics<'static>, 56);
-    rustc_data_structures::static_assert_size!(ImplItem<'static>, 88);
-    rustc_data_structures::static_assert_size!(Impl<'static>, 80);
-    rustc_data_structures::static_assert_size!(Item<'static>, 80);
-    rustc_data_structures::static_assert_size!(Pat<'static>, 88);
-    rustc_data_structures::static_assert_size!(QPath<'static>, 24);
-    rustc_data_structures::static_assert_size!(TraitItem<'static>, 96);
-    rustc_data_structures::static_assert_size!(Ty<'static>, 72);
+    static_assert_size!(Block<'static>, 48);
+    static_assert_size!(Expr<'static>, 56);
+    static_assert_size!(ForeignItem<'static>, 72);
+    static_assert_size!(GenericBound<'_>, 48);
+    static_assert_size!(Generics<'static>, 56);
+    static_assert_size!(ImplItem<'static>, 88);
+    static_assert_size!(Impl<'static>, 80);
+    static_assert_size!(Item<'static>, 80);
+    static_assert_size!(Pat<'static>, 88);
+    static_assert_size!(QPath<'static>, 24);
+    static_assert_size!(TraitItem<'static>, 96);
+    static_assert_size!(Ty<'static>, 72);
 }
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index e676acebe35..51b1bfad8a0 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -385,30 +385,17 @@ pub trait Visitor<'v>: Sized {
     fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef<'v>, m: TraitBoundModifier) {
         walk_poly_trait_ref(self, t, m)
     }
-    fn visit_variant_data(
-        &mut self,
-        s: &'v VariantData<'v>,
-        _: Symbol,
-        _: &'v Generics<'v>,
-        _parent_id: HirId,
-        _: Span,
-    ) {
+    fn visit_variant_data(&mut self, s: &'v VariantData<'v>) {
         walk_struct_def(self, s)
     }
     fn visit_field_def(&mut self, s: &'v FieldDef<'v>) {
         walk_field_def(self, s)
     }
-    fn visit_enum_def(
-        &mut self,
-        enum_definition: &'v EnumDef<'v>,
-        generics: &'v Generics<'v>,
-        item_id: HirId,
-        _: Span,
-    ) {
-        walk_enum_def(self, enum_definition, generics, item_id)
+    fn visit_enum_def(&mut self, enum_definition: &'v EnumDef<'v>, item_id: HirId) {
+        walk_enum_def(self, enum_definition, item_id)
     }
-    fn visit_variant(&mut self, v: &'v Variant<'v>, g: &'v Generics<'v>, item_id: HirId) {
-        walk_variant(self, v, g, item_id)
+    fn visit_variant(&mut self, v: &'v Variant<'v>) {
+        walk_variant(self, v)
     }
     fn visit_label(&mut self, label: &'v Label) {
         walk_label(self, label)
@@ -572,7 +559,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
         ItemKind::Enum(ref enum_definition, ref generics) => {
             visitor.visit_generics(generics);
             // `visit_enum_def()` takes care of visiting the `Item`'s `HirId`.
-            visitor.visit_enum_def(enum_definition, generics, item.hir_id(), item.span)
+            visitor.visit_enum_def(enum_definition, item.hir_id())
         }
         ItemKind::Impl(Impl {
             unsafety: _,
@@ -595,13 +582,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) {
         | ItemKind::Union(ref struct_definition, ref generics) => {
             visitor.visit_generics(generics);
             visitor.visit_id(item.hir_id());
-            visitor.visit_variant_data(
-                struct_definition,
-                item.ident.name,
-                generics,
-                item.hir_id(),
-                item.span,
-            );
+            visitor.visit_variant_data(struct_definition);
         }
         ItemKind::Trait(.., ref generics, bounds, trait_item_refs) => {
             visitor.visit_id(item.hir_id());
@@ -649,28 +630,16 @@ pub fn walk_use<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path<'v>, hir_id:
 pub fn walk_enum_def<'v, V: Visitor<'v>>(
     visitor: &mut V,
     enum_definition: &'v EnumDef<'v>,
-    generics: &'v Generics<'v>,
     item_id: HirId,
 ) {
     visitor.visit_id(item_id);
-    walk_list!(visitor, visit_variant, enum_definition.variants, generics, item_id);
+    walk_list!(visitor, visit_variant, enum_definition.variants);
 }
 
-pub fn walk_variant<'v, V: Visitor<'v>>(
-    visitor: &mut V,
-    variant: &'v Variant<'v>,
-    generics: &'v Generics<'v>,
-    parent_item_id: HirId,
-) {
+pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant<'v>) {
     visitor.visit_ident(variant.ident);
     visitor.visit_id(variant.id);
-    visitor.visit_variant_data(
-        &variant.data,
-        variant.ident.name,
-        generics,
-        parent_item_id,
-        variant.span,
-    );
+    visitor.visit_variant_data(&variant.data);
     walk_list!(visitor, visit_anon_const, &variant.disr_expr);
 }
 
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 0d4472a1cfd..780e6ead10e 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -187,7 +187,7 @@ pub enum GenericKind<'tcx> {
 /// }
 /// ```
 /// This is described with an `AnyRegion('a, 'b)` node.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, TypeFoldable, TypeVisitable)]
 pub enum VerifyBound<'tcx> {
     /// See [`VerifyIfEq`] docs
     IfEq(ty::Binder<'tcx, VerifyIfEq<'tcx>>),
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index d13711c3ab5..cbf1a677555 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -233,9 +233,9 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T>
         ast_visit::walk_where_predicate(self, p);
     }
 
-    fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef, m: &'a ast::TraitBoundModifier) {
-        run_early_pass!(self, check_poly_trait_ref, t, m);
-        ast_visit::walk_poly_trait_ref(self, t, m);
+    fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef) {
+        run_early_pass!(self, check_poly_trait_ref, t);
+        ast_visit::walk_poly_trait_ref(self, t);
     }
 
     fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index a329b37519d..5188ac633d3 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -24,7 +24,6 @@ use rustc_hir::intravisit::Visitor;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint::LintPass;
-use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 
 use std::any::Any;
@@ -194,14 +193,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
         self.context.cached_typeck_results.set(old_cached_typeck_results);
     }
 
-    fn visit_variant_data(
-        &mut self,
-        s: &'tcx hir::VariantData<'tcx>,
-        _: Symbol,
-        _: &'tcx hir::Generics<'tcx>,
-        _: hir::HirId,
-        _: Span,
-    ) {
+    fn visit_variant_data(&mut self, s: &'tcx hir::VariantData<'tcx>) {
         lint_callback!(self, check_struct_def, s);
         hir_visit::walk_struct_def(self, s);
     }
@@ -213,15 +205,10 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
         })
     }
 
-    fn visit_variant(
-        &mut self,
-        v: &'tcx hir::Variant<'tcx>,
-        g: &'tcx hir::Generics<'tcx>,
-        item_id: hir::HirId,
-    ) {
+    fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
         self.with_lint_attrs(v.id, |cx| {
             lint_callback!(cx, check_variant, v);
-            hir_visit::walk_variant(cx, v, g, item_id);
+            hir_visit::walk_variant(cx, v);
         })
     }
 
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 00e96f20d1a..7ab9302d835 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -772,14 +772,9 @@ impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> {
         })
     }
 
-    fn visit_variant(
-        &mut self,
-        v: &'tcx hir::Variant<'tcx>,
-        g: &'tcx hir::Generics<'tcx>,
-        item_id: hir::HirId,
-    ) {
+    fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
         self.with_lint_attrs(v.id, |builder| {
-            intravisit::walk_variant(builder, v, g, item_id);
+            intravisit::walk_variant(builder, v);
         })
     }
 
diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs
index cb7bd407ed4..413f06a97a2 100644
--- a/compiler/rustc_lint/src/passes.rs
+++ b/compiler/rustc_lint/src/passes.rs
@@ -156,8 +156,7 @@ macro_rules! early_lint_methods {
             fn check_generic_arg(a: &ast::GenericArg);
             fn check_generic_param(a: &ast::GenericParam);
             fn check_generics(a: &ast::Generics);
-            fn check_poly_trait_ref(a: &ast::PolyTraitRef,
-                                    b: &ast::TraitBoundModifier);
+            fn check_poly_trait_ref(a: &ast::PolyTraitRef);
             fn check_fn(a: rustc_ast::visit::FnKind<'_>, c: Span, d_: ast::NodeId);
             fn check_trait_item(a: &ast::AssocItem);
             fn check_impl_item(a: &ast::AssocItem);
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index b6cf182916c..58b2f0a4416 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -11,7 +11,7 @@ use rustc_middle::ty::adjustment;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::symbol::Symbol;
 use rustc_span::symbol::{kw, sym};
-use rustc_span::{BytePos, Span, DUMMY_SP};
+use rustc_span::{BytePos, Span};
 
 declare_lint! {
     /// The `unused_must_use` lint detects unused result of a type flagged as
@@ -504,23 +504,23 @@ trait UnusedDelimLint {
             ast::ExprKind::Block(ref block, None) if block.stmts.len() > 0 => {
                 let start = block.stmts[0].span;
                 let end = block.stmts[block.stmts.len() - 1].span;
-                if value.span.from_expansion() || start.from_expansion() || end.from_expansion() {
-                    (
-                        value.span.with_hi(value.span.lo() + BytePos(1)),
-                        value.span.with_lo(value.span.hi() - BytePos(1)),
-                    )
+                if let Some(start) = start.find_ancestor_inside(value.span)
+                    && let Some(end) = end.find_ancestor_inside(value.span)
+                {
+                    Some((
+                        value.span.with_hi(start.lo()),
+                        value.span.with_lo(end.hi()),
+                    ))
                 } else {
-                    (value.span.with_hi(start.lo()), value.span.with_lo(end.hi()))
+                    None
                 }
             }
             ast::ExprKind::Paren(ref expr) => {
-                if value.span.from_expansion() || expr.span.from_expansion() {
-                    (
-                        value.span.with_hi(value.span.lo() + BytePos(1)),
-                        value.span.with_lo(value.span.hi() - BytePos(1)),
-                    )
+                let expr_span = expr.span.find_ancestor_inside(value.span);
+                if let Some(expr_span) = expr_span {
+                    Some((value.span.with_hi(expr_span.lo()), value.span.with_lo(expr_span.hi())))
                 } else {
-                    (value.span.with_hi(expr.span.lo()), value.span.with_lo(expr.span.hi()))
+                    None
                 }
             }
             _ => return,
@@ -529,36 +529,38 @@ trait UnusedDelimLint {
             left_pos.map_or(false, |s| s >= value.span.lo()),
             right_pos.map_or(false, |s| s <= value.span.hi()),
         );
-        self.emit_unused_delims(cx, spans, ctx.into(), keep_space);
+        self.emit_unused_delims(cx, value.span, spans, ctx.into(), keep_space);
     }
 
     fn emit_unused_delims(
         &self,
         cx: &EarlyContext<'_>,
-        spans: (Span, Span),
+        value_span: Span,
+        spans: Option<(Span, Span)>,
         msg: &str,
         keep_space: (bool, bool),
     ) {
-        // FIXME(flip1995): Quick and dirty fix for #70814. This should be fixed in rustdoc
-        // properly.
-        if spans.0 == DUMMY_SP || spans.1 == DUMMY_SP {
-            return;
-        }
-
-        cx.struct_span_lint(self.lint(), MultiSpan::from(vec![spans.0, spans.1]), |lint| {
-            let replacement = vec![
-                (spans.0, if keep_space.0 { " ".into() } else { "".into() }),
-                (spans.1, if keep_space.1 { " ".into() } else { "".into() }),
-            ];
-            lint.build(fluent::lint::unused_delim)
-                .set_arg("delim", Self::DELIM_STR)
-                .set_arg("item", msg)
-                .multipart_suggestion(
+        let primary_span = if let Some((lo, hi)) = spans {
+            MultiSpan::from(vec![lo, hi])
+        } else {
+            MultiSpan::from(value_span)
+        };
+        cx.struct_span_lint(self.lint(), primary_span, |lint| {
+            let mut db = lint.build(fluent::lint::unused_delim);
+            db.set_arg("delim", Self::DELIM_STR);
+            db.set_arg("item", msg);
+            if let Some((lo, hi)) = spans {
+                let replacement = vec![
+                    (lo, if keep_space.0 { " ".into() } else { "".into() }),
+                    (hi, if keep_space.1 { " ".into() } else { "".into() }),
+                ];
+                db.multipart_suggestion(
                     fluent::lint::suggestion,
                     replacement,
                     Applicability::MachineApplicable,
-                )
-                .emit();
+                );
+            }
+            db.emit();
         });
     }
 
@@ -606,8 +608,7 @@ trait UnusedDelimLint {
             ref call_or_other => {
                 let (args_to_check, ctx) = match *call_or_other {
                     Call(_, ref args) => (&args[..], UnusedDelimsCtx::FunctionArg),
-                    // first "argument" is self (which sometimes needs delims)
-                    MethodCall(_, ref args, _) => (&args[1..], UnusedDelimsCtx::MethodArg),
+                    MethodCall(_, _, ref args, _) => (&args[..], UnusedDelimsCtx::MethodArg),
                     // actual catch-all arm
                     _ => {
                         return;
@@ -766,15 +767,12 @@ impl UnusedParens {
                 // Otherwise proceed with linting.
                 _ => {}
             }
-            let spans = if value.span.from_expansion() || inner.span.from_expansion() {
-                (
-                    value.span.with_hi(value.span.lo() + BytePos(1)),
-                    value.span.with_lo(value.span.hi() - BytePos(1)),
-                )
+            let spans = if let Some(inner) = inner.span.find_ancestor_inside(value.span) {
+                Some((value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi())))
             } else {
-                (value.span.with_hi(inner.span.lo()), value.span.with_lo(inner.span.hi()))
+                None
             };
-            self.emit_unused_delims(cx, spans, "pattern", (false, false));
+            self.emit_unused_delims(cx, value.span, spans, "pattern", (false, false));
         }
     }
 }
@@ -879,15 +877,12 @@ impl EarlyLintPass for UnusedParens {
                     );
                 }
                 _ => {
-                    let spans = if ty.span.from_expansion() || r.span.from_expansion() {
-                        (
-                            ty.span.with_hi(ty.span.lo() + BytePos(1)),
-                            ty.span.with_lo(ty.span.hi() - BytePos(1)),
-                        )
+                    let spans = if let Some(r) = r.span.find_ancestor_inside(ty.span) {
+                        Some((ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())))
                     } else {
-                        (ty.span.with_hi(r.span.lo()), ty.span.with_lo(r.span.hi()))
+                        None
                     };
-                    self.emit_unused_delims(cx, spans, "type", (false, false));
+                    self.emit_unused_delims(cx, ty.span, spans, "type", (false, false));
                 }
             }
         }
diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs
index 62ef5804dce..abb68f3afe5 100644
--- a/compiler/rustc_llvm/build.rs
+++ b/compiler/rustc_llvm/build.rs
@@ -242,6 +242,13 @@ fn main() {
         println!("cargo:rustc-link-lib=uuid");
     } else if target.contains("netbsd") || target.contains("haiku") || target.contains("darwin") {
         println!("cargo:rustc-link-lib=z");
+    } else if target.starts_with("arm")
+        || target.starts_with("mips-")
+        || target.starts_with("mipsel-")
+        || target.starts_with("powerpc-")
+    {
+        // 32-bit targets need to link libatomic.
+        println!("cargo:rustc-link-lib=atomic");
     }
     cmd.args(&components);
 
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 9f6079ecba4..c5e39507d7e 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -328,7 +328,31 @@ impl<'tcx> Collector<'tcx> {
                         .map(|child_item| self.build_dll_import(abi, child_item))
                         .collect()
                 }
-                _ => Vec::new(),
+                _ => {
+                    for child_item in foreign_mod_items {
+                        if self.tcx.def_kind(child_item.id.def_id).has_codegen_attrs()
+                            && self
+                                .tcx
+                                .codegen_fn_attrs(child_item.id.def_id)
+                                .link_ordinal
+                                .is_some()
+                        {
+                            let link_ordinal_attr = self
+                                .tcx
+                                .hir()
+                                .attrs(self.tcx.hir().local_def_id_to_hir_id(child_item.id.def_id))
+                                .iter()
+                                .find(|a| a.has_name(sym::link_ordinal))
+                                .unwrap();
+                            sess.span_err(
+                                link_ordinal_attr.span,
+                                "`#[link_ordinal]` is only supported if link kind is `raw-dylib`",
+                            );
+                        }
+                    }
+
+                    Vec::new()
+                }
             };
             self.libs.push(NativeLib {
                 name: name.map(|(name, _)| name),
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 45c6468bc24..4e1254efd17 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -26,7 +26,6 @@
 #![feature(allocator_api)]
 #![feature(array_windows)]
 #![feature(assert_matches)]
-#![feature(backtrace)]
 #![feature(box_patterns)]
 #![feature(core_intrinsics)]
 #![feature(discriminant_kind)]
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index b856af1d8f8..5e26a52900e 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -814,8 +814,8 @@ impl<'tcx> fmt::Display for Pat<'tcx> {
 mod size_asserts {
     use super::*;
     // These are in alphabetical order, which is easy to maintain.
-    rustc_data_structures::static_assert_size!(Block, 56);
-    rustc_data_structures::static_assert_size!(Expr<'_>, 104);
-    rustc_data_structures::static_assert_size!(Pat<'_>, 24);
-    rustc_data_structures::static_assert_size!(Stmt<'_>, 120);
+    static_assert_size!(Block, 56);
+    static_assert_size!(Expr<'_>, 104);
+    static_assert_size!(Pat<'_>, 24);
+    static_assert_size!(Stmt<'_>, 120);
 }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 79309097e78..a7833ab6431 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -594,6 +594,29 @@ impl<'tcx> Predicate<'tcx> {
         }
         self
     }
+
+    /// Whether this projection can be soundly normalized.
+    ///
+    /// Wf predicates must not be normalized, as normalization
+    /// can remove required bounds which would cause us to
+    /// unsoundly accept some programs. See #91068.
+    #[inline]
+    pub fn allow_normalization(self) -> bool {
+        match self.kind().skip_binder() {
+            PredicateKind::WellFormed(_) => false,
+            PredicateKind::Trait(_)
+            | PredicateKind::RegionOutlives(_)
+            | PredicateKind::TypeOutlives(_)
+            | PredicateKind::Projection(_)
+            | PredicateKind::ObjectSafe(_)
+            | PredicateKind::ClosureKind(_, _, _)
+            | PredicateKind::Subtype(_)
+            | PredicateKind::Coerce(_)
+            | PredicateKind::ConstEvaluatable(_)
+            | PredicateKind::ConstEquate(_, _)
+            | PredicateKind::TypeWellFormedFromEnv(_) => true,
+        }
+    }
 }
 
 impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 7f2e81a71a9..cc55b7e8611 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1513,6 +1513,10 @@ pub trait PrettyPrinter<'tcx>:
                 }
                 return Ok(self);
             }
+            (ty::ValTree::Leaf(leaf), ty::Ref(_, inner_ty, _)) => {
+                p!(write("&"));
+                return self.pretty_print_const_scalar_int(leaf, *inner_ty, print_ty);
+            }
             (ty::ValTree::Leaf(leaf), _) => {
                 return self.pretty_print_const_scalar_int(leaf, ty, print_ty);
             }
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index cefb5f36b6a..ce38283724d 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -170,7 +170,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
         let mut arm_candidates = self.create_match_candidates(scrutinee_place.clone(), &arms);
 
-        let match_has_guard = arms.iter().copied().any(|arm| self.thir[arm].guard.is_some());
+        let match_has_guard = arm_candidates.iter().any(|(_, candidate)| candidate.has_guard);
         let mut candidates =
             arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::<Vec<_>>();
 
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index d6dd0f01794..f2045ac19ca 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -168,7 +168,12 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
         // once indirect_structural_match is a full fledged error, this
         // level of indirection can be eliminated
 
-        let inlined_const_as_pat = self.recur(cv, mir_structural_match_violation).unwrap();
+        let inlined_const_as_pat =
+            self.recur(cv, mir_structural_match_violation).unwrap_or_else(|_| Pat {
+                span: self.span,
+                ty: cv.ty(),
+                kind: Box::new(PatKind::Constant { value: cv }),
+            });
 
         if self.include_lint_checks && !self.saw_const_match_error.get() {
             // If we were able to successfully convert the const to some pat,
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 98016659a05..1c087b93b49 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -183,6 +183,18 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx>
 
     type MemoryKind = !;
 
+    #[inline(always)]
+    fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+        // We do not check for alignment to avoid having to carry an `Align`
+        // in `ConstValue::ByRef`.
+        false
+    }
+
+    #[inline(always)]
+    fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool {
+        false // for now, we don't enforce validity
+    }
+
     fn load_mir(
         _ecx: &InterpCx<'mir, 'tcx, Self>,
         _instance: ty::InstanceDef<'tcx>,
diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
index 76b4cdd2ecd..76522233689 100644
--- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
@@ -70,7 +70,6 @@ impl<'tcx, 'a> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'tcx, 'a> {
                 build_ptr_tys(tcx, base_ty.boxed_ty(), self.unique_did, self.nonnull_did);
 
             let ptr_local = self.patch.new_temp(ptr_ty, source_info.span);
-            self.local_decls.push(LocalDecl::new(ptr_ty, source_info.span));
 
             self.patch.add_statement(location, StatementKind::StorageLive(ptr_local));
 
@@ -125,13 +124,6 @@ impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs {
                     index += 1;
                 }
 
-                if let Some(terminator) = terminator
-                && !matches!(terminator.kind, TerminatorKind::Yield{..})
-                {
-                    let location = Location { block, statement_index: index };
-                    visitor.visit_terminator(terminator, location);
-                }
-
                 let location = Location { block, statement_index: index };
                 match terminator {
                     // yielding into a box is handled when lowering generators
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 40dc9fe9a05..2a51af582f5 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -29,7 +29,6 @@ use rustc_middle::mir::visit::Visitor as _;
 use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPass, MirPhase, Promoted};
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
-use rustc_span::{Span, Symbol};
 
 #[macro_use]
 mod pass_manager;
@@ -159,14 +158,7 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> {
         set: &'a mut FxIndexSet<LocalDefId>,
     }
     impl<'tcx> Visitor<'tcx> for GatherCtors<'_, 'tcx> {
-        fn visit_variant_data(
-            &mut self,
-            v: &'tcx hir::VariantData<'tcx>,
-            _: Symbol,
-            _: &'tcx hir::Generics<'tcx>,
-            _: hir::HirId,
-            _: Span,
-        ) {
+        fn visit_variant_data(&mut self, v: &'tcx hir::VariantData<'tcx>) {
             if let hir::VariantData::Tuple(_, hir_id) = *v {
                 self.set.insert(self.tcx.hir().local_def_id(hir_id));
             }
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index a2155ac1d1a..f4c6b33a529 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -19,7 +19,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{
     fluent, Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult,
 };
-use rustc_errors::{pluralize, struct_span_err, Diagnostic, EmissionGuarantee, ErrorGuaranteed};
+use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed};
 use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic};
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{kw, Ident};
@@ -228,13 +228,13 @@ struct MultiSugg {
 }
 
 impl MultiSugg {
-    fn emit<G: EmissionGuarantee>(self, err: &mut DiagnosticBuilder<'_, G>) {
+    fn emit(self, err: &mut Diagnostic) {
         err.multipart_suggestion(&self.msg, self.patches, self.applicability);
     }
 
     /// Overrides individual messages and applicabilities.
-    fn emit_many<G: EmissionGuarantee>(
-        err: &mut DiagnosticBuilder<'_, G>,
+    fn emit_many(
+        err: &mut Diagnostic,
         msg: &str,
         applicability: Applicability,
         suggestions: impl Iterator<Item = Self>,
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index e473f4d30cf..2880ef78c8d 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -850,7 +850,7 @@ impl<'a> Parser<'a> {
                     ExprKind::Index(_, _) => "indexing",
                     ExprKind::Try(_) => "`?`",
                     ExprKind::Field(_, _) => "a field access",
-                    ExprKind::MethodCall(_, _, _) => "a method call",
+                    ExprKind::MethodCall(_, _, _, _) => "a method call",
                     ExprKind::Call(_, _) => "a function call",
                     ExprKind::Await(_) => "`.await`",
                     ExprKind::Err => return Ok(with_postfix),
@@ -859,7 +859,7 @@ impl<'a> Parser<'a> {
             );
             let mut err = self.struct_span_err(span, &msg);
 
-            let suggest_parens = |err: &mut DiagnosticBuilder<'_, _>| {
+            let suggest_parens = |err: &mut Diagnostic| {
                 let suggestions = vec![
                     (span.shrink_to_lo(), "(".to_string()),
                     (span.shrink_to_hi(), ")".to_string()),
@@ -1258,8 +1258,11 @@ impl<'a> Parser<'a> {
 
     /// Parse an indexing expression `expr[...]`.
     fn parse_index_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
+        let prev_span = self.prev_token.span;
+        let open_delim_span = self.token.span;
         self.bump(); // `[`
         let index = self.parse_expr()?;
+        self.suggest_missing_semicolon_before_array(prev_span, open_delim_span)?;
         self.expect(&token::CloseDelim(Delimiter::Bracket))?;
         Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_index(base, index), AttrVec::new()))
     }
@@ -1277,12 +1280,14 @@ impl<'a> Parser<'a> {
 
         if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
             // Method call `expr.f()`
-            let mut args = self.parse_paren_expr_seq()?;
-            args.insert(0, self_arg);
-
+            let args = self.parse_paren_expr_seq()?;
             let fn_span = fn_span_lo.to(self.prev_token.span);
             let span = lo.to(self.prev_token.span);
-            Ok(self.mk_expr(span, ExprKind::MethodCall(segment, args, fn_span), AttrVec::new()))
+            Ok(self.mk_expr(
+                span,
+                ExprKind::MethodCall(segment, self_arg, args, fn_span),
+                AttrVec::new(),
+            ))
         } else {
             // Field access `expr.f`
             if let Some(args) = segment.args {
@@ -2056,6 +2061,45 @@ impl<'a> Parser<'a> {
         }
     }
 
+    fn suggest_missing_semicolon_before_array(
+        &self,
+        prev_span: Span,
+        open_delim_span: Span,
+    ) -> PResult<'a, ()> {
+        if self.token.kind == token::Comma {
+            let mut snapshot = self.create_snapshot_for_diagnostic();
+            snapshot.bump();
+            match snapshot.parse_seq_to_before_end(
+                &token::CloseDelim(Delimiter::Bracket),
+                SeqSep::trailing_allowed(token::Comma),
+                |p| p.parse_expr(),
+            ) {
+                Ok(_)
+                    // When the close delim is `)`, `token.kind` is expected to be `token::CloseDelim(Delimiter::Parenthesis)`,
+                    // but the actual `token.kind` is `token::CloseDelim(Delimiter::Bracket)`.
+                    // This is because the `token.kind` of the close delim is treated as the same as
+                    // that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different.
+                    // Therefore, `token.kind` should not be compared here.
+                    if snapshot
+                        .span_to_snippet(snapshot.token.span)
+                        .map_or(false, |snippet| snippet == "]") =>
+                {
+                    let mut err = self.struct_span_err(open_delim_span, "expected `;`, found `[`");
+                    err.span_suggestion_verbose(
+                        prev_span.shrink_to_hi(),
+                        "consider adding `;` here",
+                        ';',
+                        Applicability::MaybeIncorrect,
+                    );
+                    return Err(err);
+                }
+                Ok(_) => (),
+                Err(err) => err.cancel(),
+            }
+        }
+        Ok(())
+    }
+
     /// Parses a block or unsafe block.
     pub(super) fn parse_block_expr(
         &mut self,
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 0c523ad22c2..c088b6e1e0e 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -1295,7 +1295,11 @@ impl<'a> Parser<'a> {
                 self.bump(); // `in`
                 let path = self.parse_path(PathStyle::Mod)?; // `path`
                 self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
-                let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID };
+                let vis = VisibilityKind::Restricted {
+                    path: P(path),
+                    id: ast::DUMMY_NODE_ID,
+                    shorthand: false,
+                };
                 return Ok(Visibility {
                     span: lo.to(self.prev_token.span),
                     kind: vis,
@@ -1308,7 +1312,11 @@ impl<'a> Parser<'a> {
                 self.bump(); // `(`
                 let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self`
                 self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
-                let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID };
+                let vis = VisibilityKind::Restricted {
+                    path: P(path),
+                    id: ast::DUMMY_NODE_ID,
+                    shorthand: true,
+                };
                 return Ok(Visibility {
                     span: lo.to(self.prev_token.span),
                     kind: vis,
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 6fea68ce8b3..f75fffb6871 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -2066,14 +2066,9 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
         intravisit::walk_expr(self, expr)
     }
 
-    fn visit_variant(
-        &mut self,
-        variant: &'tcx hir::Variant<'tcx>,
-        generics: &'tcx hir::Generics<'tcx>,
-        item_id: HirId,
-    ) {
+    fn visit_variant(&mut self, variant: &'tcx hir::Variant<'tcx>) {
         self.check_attributes(variant.id, variant.span, Target::Variant, None);
-        intravisit::walk_variant(self, variant, generics, item_id)
+        intravisit::walk_variant(self, variant)
     }
 
     fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 1e2fbeb384c..625c854ea77 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -368,14 +368,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
         self.maybe_typeck_results = old_maybe_typeck_results;
     }
 
-    fn visit_variant_data(
-        &mut self,
-        def: &'tcx hir::VariantData<'tcx>,
-        _: Symbol,
-        _: &hir::Generics<'_>,
-        _: hir::HirId,
-        _: rustc_span::Span,
-    ) {
+    fn visit_variant_data(&mut self, def: &'tcx hir::VariantData<'tcx>) {
         let tcx = self.tcx;
         let has_repr_c = self.repr_has_repr_c;
         let has_repr_simd = self.repr_has_repr_simd;
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index a3be827a7cc..399d00b403a 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -21,21 +21,55 @@ enum Id {
     None,
 }
 
-struct NodeData {
+struct NodeStats {
     count: usize,
     size: usize,
 }
 
+impl NodeStats {
+    fn new() -> NodeStats {
+        NodeStats { count: 0, size: 0 }
+    }
+}
+
+struct Node {
+    stats: NodeStats,
+    subnodes: FxHashMap<&'static str, NodeStats>,
+}
+
+impl Node {
+    fn new() -> Node {
+        Node { stats: NodeStats::new(), subnodes: FxHashMap::default() }
+    }
+}
+
+/// This type measures the size of AST and HIR nodes, by implementing the AST
+/// and HIR `Visitor` traits. But we don't measure every visited type because
+/// that could cause double counting.
+///
+/// For example, `ast::Visitor` has `visit_ident`, but `Ident`s are always
+/// stored inline within other AST nodes, so we don't implement `visit_ident`
+/// here. In constrast, we do implement `visit_expr` because `ast::Expr` is
+/// always stored as `P<ast::Expr>`, and every such expression should be
+/// measured separately.
+///
+/// In general, a `visit_foo` method should be implemented here if the
+/// corresponding `Foo` type is always stored on its own, e.g.: `P<Foo>`,
+/// `Box<Foo>`, `Vec<Foo>`, `Box<[Foo]>`.
+///
+/// There are some types in the AST and HIR tree that the visitors do not have
+/// a `visit_*` method for, and so we cannot measure these, which is
+/// unfortunate.
 struct StatCollector<'k> {
     krate: Option<Map<'k>>,
-    data: FxHashMap<&'static str, NodeData>,
+    nodes: FxHashMap<&'static str, Node>,
     seen: FxHashSet<Id>,
 }
 
 pub fn print_hir_stats(tcx: TyCtxt<'_>) {
     let mut collector = StatCollector {
         krate: Some(tcx.hir()),
-        data: FxHashMap::default(),
+        nodes: FxHashMap::default(),
         seen: FxHashSet::default(),
     };
     tcx.hir().walk_toplevel_module(&mut collector);
@@ -44,49 +78,88 @@ pub fn print_hir_stats(tcx: TyCtxt<'_>) {
 }
 
 pub fn print_ast_stats(krate: &ast::Crate, title: &str) {
+    use rustc_ast::visit::Visitor;
+
     let mut collector =
-        StatCollector { krate: None, data: FxHashMap::default(), seen: FxHashSet::default() };
-    ast_visit::walk_crate(&mut collector, krate);
+        StatCollector { krate: None, nodes: FxHashMap::default(), seen: FxHashSet::default() };
+    collector.visit_crate(krate);
     collector.print(title);
 }
 
 impl<'k> StatCollector<'k> {
-    fn record<T>(&mut self, label: &'static str, id: Id, node: &T) {
+    // Record a top-level node.
+    fn record<T>(&mut self, label: &'static str, id: Id, val: &T) {
+        self.record_inner(label, None, id, val);
+    }
+
+    // Record a two-level entry, with a top-level enum type and a variant.
+    fn record_variant<T>(&mut self, label1: &'static str, label2: &'static str, id: Id, val: &T) {
+        self.record_inner(label1, Some(label2), id, val);
+    }
+
+    fn record_inner<T>(
+        &mut self,
+        label1: &'static str,
+        label2: Option<&'static str>,
+        id: Id,
+        val: &T,
+    ) {
         if id != Id::None && !self.seen.insert(id) {
             return;
         }
 
-        let entry = self.data.entry(label).or_insert(NodeData { count: 0, size: 0 });
+        let node = self.nodes.entry(label1).or_insert(Node::new());
+        node.stats.count += 1;
+        node.stats.size = std::mem::size_of_val(val);
 
-        entry.count += 1;
-        entry.size = std::mem::size_of_val(node);
+        if let Some(label2) = label2 {
+            let subnode = node.subnodes.entry(label2).or_insert(NodeStats::new());
+            subnode.count += 1;
+            subnode.size = std::mem::size_of_val(val);
+        }
     }
 
     fn print(&self, title: &str) {
-        let mut stats: Vec<_> = self.data.iter().collect();
+        let mut nodes: Vec<_> = self.nodes.iter().collect();
+        nodes.sort_by_key(|&(_, ref node)| node.stats.count * node.stats.size);
 
-        stats.sort_by_key(|&(_, ref d)| d.count * d.size);
-
-        let mut total_size = 0;
+        let total_size = nodes.iter().map(|(_, node)| node.stats.count * node.stats.size).sum();
 
         eprintln!("\n{}\n", title);
 
         eprintln!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size");
         eprintln!("----------------------------------------------------------------");
 
-        for (label, data) in stats {
+        let percent = |m, n| (m * 100) as f64 / n as f64;
+
+        for (label, node) in nodes {
+            let size = node.stats.count * node.stats.size;
             eprintln!(
-                "{:<18}{:>18}{:>14}{:>14}",
+                "{:<18}{:>10} ({:4.1}%){:>14}{:>14}",
                 label,
-                to_readable_str(data.count * data.size),
-                to_readable_str(data.count),
-                to_readable_str(data.size)
+                to_readable_str(size),
+                percent(size, total_size),
+                to_readable_str(node.stats.count),
+                to_readable_str(node.stats.size)
             );
-
-            total_size += data.count * data.size;
+            if !node.subnodes.is_empty() {
+                let mut subnodes: Vec<_> = node.subnodes.iter().collect();
+                subnodes.sort_by_key(|&(_, ref subnode)| subnode.count * subnode.size);
+
+                for (label, subnode) in subnodes {
+                    let size = subnode.count * subnode.size;
+                    eprintln!(
+                        "- {:<18}{:>10} ({:4.1}%){:>14}",
+                        label,
+                        to_readable_str(size),
+                        percent(size, total_size),
+                        to_readable_str(subnode.count),
+                    );
+                }
+            }
         }
         eprintln!("----------------------------------------------------------------");
-        eprintln!("{:<18}{:>18}\n", "Total", to_readable_str(total_size));
+        eprintln!("{:<18}{:>10}\n", "Total", to_readable_str(total_size));
     }
 }
 
@@ -203,14 +276,9 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
         hir_visit::walk_field_def(self, s)
     }
 
-    fn visit_variant(
-        &mut self,
-        v: &'v hir::Variant<'v>,
-        g: &'v hir::Generics<'v>,
-        item_id: hir::HirId,
-    ) {
+    fn visit_variant(&mut self, v: &'v hir::Variant<'v>) {
         self.record("Variant", Id::None, v);
-        hir_visit::walk_variant(self, v, g, item_id)
+        hir_visit::walk_variant(self, v)
     }
 
     fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) {
@@ -228,6 +296,10 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
         hir_visit::walk_path(self, path)
     }
 
+    // `PathSegment` has one inline use (in `ast::ExprKind::MethodCall`) and
+    // one non-inline use (in `Path::segments`). The latter case is more common
+    // than the former case, so we implement this visitor and tolerate the
+    // double counting in the former case.
     fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v hir::PathSegment<'v>) {
         self.record("PathSegment", Id::None, path_segment);
         hir_visit::walk_path_segment(self, path_span, path_segment)
@@ -243,14 +315,54 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
     }
 }
 
+// Used to avoid boilerplate for types with many variants.
+macro_rules! record_variants {
+    (
+        ($self:ident, $val:expr, $kind:expr, $ty:ty, $tykind:ident), // mandatory pieces
+        [$($variant:ident),*]
+    ) => {
+        match $kind {
+            $(
+                ast::$tykind::$variant { .. } => {
+                    $self.record_variant(stringify!($ty), stringify!($variant), Id::None, $val)
+                }
+            )*
+        }
+    };
+}
+
 impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
     fn visit_foreign_item(&mut self, i: &'v ast::ForeignItem) {
-        self.record("ForeignItem", Id::None, i);
+        record_variants!(
+            (self, i, i.kind, ForeignItem, ForeignItemKind),
+            [Static, Fn, TyAlias, MacCall]
+        );
         ast_visit::walk_foreign_item(self, i)
     }
 
     fn visit_item(&mut self, i: &'v ast::Item) {
-        self.record("Item", Id::None, i);
+        record_variants!(
+            (self, i, i.kind, Item, ItemKind),
+            [
+                ExternCrate,
+                Use,
+                Static,
+                Const,
+                Fn,
+                Mod,
+                ForeignMod,
+                GlobalAsm,
+                TyAlias,
+                Enum,
+                Struct,
+                Union,
+                Trait,
+                TraitAlias,
+                Impl,
+                MacCall,
+                MacroDef
+            ]
+        );
         ast_visit::walk_item(self, i)
     }
 
@@ -265,47 +377,116 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
     }
 
     fn visit_stmt(&mut self, s: &'v ast::Stmt) {
-        self.record("Stmt", Id::None, s);
+        record_variants!(
+            (self, s, s.kind, Stmt, StmtKind),
+            [Local, Item, Expr, Semi, Empty, MacCall]
+        );
         ast_visit::walk_stmt(self, s)
     }
 
+    fn visit_param(&mut self, p: &'v ast::Param) {
+        self.record("Param", Id::None, p);
+        ast_visit::walk_param(self, p)
+    }
+
     fn visit_arm(&mut self, a: &'v ast::Arm) {
         self.record("Arm", Id::None, a);
         ast_visit::walk_arm(self, a)
     }
 
     fn visit_pat(&mut self, p: &'v ast::Pat) {
-        self.record("Pat", Id::None, p);
+        record_variants!(
+            (self, p, p.kind, Pat, PatKind),
+            [
+                Wild,
+                Ident,
+                Struct,
+                TupleStruct,
+                Or,
+                Path,
+                Tuple,
+                Box,
+                Ref,
+                Lit,
+                Range,
+                Slice,
+                Rest,
+                Paren,
+                MacCall
+            ]
+        );
         ast_visit::walk_pat(self, p)
     }
 
-    fn visit_expr(&mut self, ex: &'v ast::Expr) {
-        self.record("Expr", Id::None, ex);
-        ast_visit::walk_expr(self, ex)
+    fn visit_expr(&mut self, e: &'v ast::Expr) {
+        record_variants!(
+            (self, e, e.kind, Expr, ExprKind),
+            [
+                Box, Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let,
+                If, While, ForLoop, Loop, Match, Closure, Block, Async, Await, TryBlock, Assign,
+                AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret,
+                InlineAsm, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, Err
+            ]
+        );
+        ast_visit::walk_expr(self, e)
     }
 
     fn visit_ty(&mut self, t: &'v ast::Ty) {
-        self.record("Ty", Id::None, t);
+        record_variants!(
+            (self, t, t.kind, Ty, TyKind),
+            [
+                Slice,
+                Array,
+                Ptr,
+                Rptr,
+                BareFn,
+                Never,
+                Tup,
+                Path,
+                TraitObject,
+                ImplTrait,
+                Paren,
+                Typeof,
+                Infer,
+                ImplicitSelf,
+                MacCall,
+                Err,
+                CVarArgs
+            ]
+        );
+
         ast_visit::walk_ty(self, t)
     }
 
+    fn visit_generic_param(&mut self, g: &'v ast::GenericParam) {
+        self.record("GenericParam", Id::None, g);
+        ast_visit::walk_generic_param(self, g)
+    }
+
+    fn visit_where_predicate(&mut self, p: &'v ast::WherePredicate) {
+        record_variants!(
+            (self, p, p, WherePredicate, WherePredicate),
+            [BoundPredicate, RegionPredicate, EqPredicate]
+        );
+        ast_visit::walk_where_predicate(self, p)
+    }
+
     fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, s: Span, _: NodeId) {
         self.record("FnDecl", Id::None, fk.decl());
         ast_visit::walk_fn(self, fk, s)
     }
 
-    fn visit_assoc_item(&mut self, item: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
-        let label = match ctxt {
-            ast_visit::AssocCtxt::Trait => "TraitItem",
-            ast_visit::AssocCtxt::Impl => "ImplItem",
-        };
-        self.record(label, Id::None, item);
-        ast_visit::walk_assoc_item(self, item, ctxt);
+    fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
+        record_variants!(
+            (self, i, i.kind, AssocItem, AssocItemKind),
+            [Const, Fn, TyAlias, MacCall]
+        );
+        ast_visit::walk_assoc_item(self, i, ctxt);
     }
 
-    fn visit_param_bound(&mut self, bounds: &'v ast::GenericBound, _ctxt: BoundKind) {
-        self.record("GenericBound", Id::None, bounds);
-        ast_visit::walk_param_bound(self, bounds)
+    fn visit_param_bound(&mut self, b: &'v ast::GenericBound, _ctxt: BoundKind) {
+        record_variants!((self, b, b, GenericBound, GenericBound), [Trait, Outlives]);
+        ast_visit::walk_param_bound(self, b)
     }
 
     fn visit_field_def(&mut self, s: &'v ast::FieldDef) {
@@ -318,27 +499,42 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
         ast_visit::walk_variant(self, v)
     }
 
-    fn visit_lifetime(&mut self, lifetime: &'v ast::Lifetime, _: ast_visit::LifetimeCtxt) {
-        self.record("Lifetime", Id::None, lifetime);
-        ast_visit::walk_lifetime(self, lifetime)
-    }
-
-    fn visit_mac_call(&mut self, mac: &'v ast::MacCall) {
-        self.record("MacCall", Id::None, mac);
-        ast_visit::walk_mac(self, mac)
-    }
+    // `UseTree` has one inline use (in `ast::ItemKind::Use`) and one
+    // non-inline use (in `ast::UseTreeKind::Nested). The former case is more
+    // common, so we don't implement `visit_use_tree` and tolerate the missed
+    // coverage in the latter case.
 
     fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v ast::PathSegment) {
         self.record("PathSegment", Id::None, path_segment);
         ast_visit::walk_path_segment(self, path_span, path_segment)
     }
 
-    fn visit_assoc_constraint(&mut self, constraint: &'v ast::AssocConstraint) {
-        self.record("AssocConstraint", Id::None, constraint);
-        ast_visit::walk_assoc_constraint(self, constraint)
+    // `GenericArgs` has one inline use (in `ast::AssocConstraint::gen_args`) and one
+    // non-inline use (in `ast::PathSegment::args`). The latter case is more
+    // common, so we implement `visit_generic_args` and tolerate the double
+    // counting in the former case.
+    fn visit_generic_args(&mut self, sp: Span, g: &'v ast::GenericArgs) {
+        record_variants!((self, g, g, GenericArgs, GenericArgs), [AngleBracketed, Parenthesized]);
+        ast_visit::walk_generic_args(self, sp, g)
     }
 
     fn visit_attribute(&mut self, attr: &'v ast::Attribute) {
-        self.record("Attribute", Id::None, attr);
+        record_variants!((self, attr, attr.kind, Attribute, AttrKind), [Normal, DocComment]);
+        ast_visit::walk_attribute(self, attr)
+    }
+
+    fn visit_expr_field(&mut self, f: &'v ast::ExprField) {
+        self.record("ExprField", Id::None, f);
+        ast_visit::walk_expr_field(self, f)
+    }
+
+    fn visit_crate(&mut self, krate: &'v ast::Crate) {
+        self.record("Crate", Id::None, krate);
+        ast_visit::walk_crate(self, krate)
+    }
+
+    fn visit_inline_asm(&mut self, asm: &'v ast::InlineAsm) {
+        self.record("InlineAsm", Id::None, asm);
+        ast_visit::walk_inline_asm(self, asm)
     }
 }
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index be920601ee4..574e8073d8e 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -11,7 +11,7 @@ use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_hir::hir_id::CRATE_HIR_ID;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{FieldDef, Generics, HirId, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
+use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::privacy::AccessLevels;
 use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index};
@@ -442,7 +442,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
         );
     }
 
-    fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) {
+    fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
         self.annotate(
             self.tcx.hir().local_def_id(var.id),
             var.span,
@@ -465,7 +465,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> {
                     );
                 }
 
-                intravisit::walk_variant(v, var, g, item_id)
+                intravisit::walk_variant(v, var)
             },
         )
     }
@@ -598,9 +598,9 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> {
         intravisit::walk_impl_item(self, ii);
     }
 
-    fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) {
+    fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) {
         self.check_missing_stability(self.tcx.hir().local_def_id(var.id), var.span);
-        intravisit::walk_variant(self, var, g, item_id);
+        intravisit::walk_variant(self, var);
     }
 
     fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) {
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index c28d0569d4c..f7c28eff55b 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1625,15 +1625,10 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
         intravisit::walk_ty(self, t)
     }
 
-    fn visit_variant(
-        &mut self,
-        v: &'tcx hir::Variant<'tcx>,
-        g: &'tcx hir::Generics<'tcx>,
-        item_id: hir::HirId,
-    ) {
+    fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
         if self.access_levels.is_reachable(self.tcx.hir().local_def_id(v.id)) {
             self.in_variant = true;
-            intravisit::walk_variant(self, v, g, item_id);
+            intravisit::walk_variant(self, v);
             self.in_variant = false;
         }
     }
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index ac8d26fb072..58a4cff55db 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -723,7 +723,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
         self.diagnostic_metadata.current_trait_object = prev;
         self.diagnostic_metadata.current_type_path = prev_ty;
     }
-    fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, _: &'ast TraitBoundModifier) {
+    fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef) {
         let span = tref.span.shrink_to_lo().to(tref.trait_ref.path.span.shrink_to_lo());
         self.with_generic_param_rib(
             &tref.bound_generic_params,
@@ -3796,9 +3796,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             ExprKind::Field(ref subexpression, _) => {
                 self.resolve_expr(subexpression, Some(expr));
             }
-            ExprKind::MethodCall(ref segment, ref arguments, _) => {
-                let mut arguments = arguments.iter();
-                self.resolve_expr(arguments.next().unwrap(), Some(expr));
+            ExprKind::MethodCall(ref segment, ref receiver, ref arguments, _) => {
+                self.resolve_expr(receiver, Some(expr));
                 for argument in arguments {
                     self.resolve_expr(argument, None);
                 }
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 2b1f2b88ec4..cb133841bca 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -2021,9 +2021,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
 
     fn suggest_introducing_lifetime(
         &self,
-        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        err: &mut Diagnostic,
         name: Option<&str>,
-        suggest: impl Fn(&mut DiagnosticBuilder<'_, ErrorGuaranteed>, bool, Span, &str, String) -> bool,
+        suggest: impl Fn(&mut Diagnostic, bool, Span, &str, String) -> bool,
     ) {
         let mut suggest_note = true;
         for rib in self.lifetime_ribs.iter().rev() {
@@ -2149,7 +2149,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> {
 
     pub(crate) fn add_missing_lifetime_specifiers_label(
         &mut self,
-        err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+        err: &mut Diagnostic,
         lifetime_refs: Vec<MissingLifetime>,
         function_param_lifetimes: Option<(Vec<MissingLifetime>, Vec<ElisionFnParameter>)>,
     ) {
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 1827f1c208d..0032dd7d113 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1310,6 +1310,8 @@ options! {
         "emit the bc module with thin LTO info (default: yes)"),
     export_executable_symbols: bool = (false, parse_bool, [TRACKED],
         "export symbols from executables, as if they were dynamic libraries"),
+    extra_const_ub_checks: bool = (false, parse_bool, [TRACKED],
+        "turns on more checks to detect const UB, which can be slow (default: no)"),
     #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::fewer_names` instead of this field"))]
     fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 577126a95cc..639ce64a9f5 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -14,7 +14,6 @@ mod m68k;
 mod mips;
 mod mips64;
 mod msp430;
-mod nvptx;
 mod nvptx64;
 mod powerpc;
 mod powerpc64;
@@ -702,7 +701,6 @@ impl<'a, Ty> FnAbi<'a, Ty> {
             "msp430" => msp430::compute_abi_info(self),
             "sparc" => sparc::compute_abi_info(cx, self),
             "sparc64" => sparc64::compute_abi_info(cx, self),
-            "nvptx" => nvptx::compute_abi_info(self),
             "nvptx64" => {
                 if cx.target_spec().adjust_abi(abi) == spec::abi::Abi::PtxKernel {
                     nvptx64::compute_ptx_kernel_abi_info(cx, self)
diff --git a/compiler/rustc_target/src/abi/call/nvptx.rs b/compiler/rustc_target/src/abi/call/nvptx.rs
deleted file mode 100644
index 428dd95bbcd..00000000000
--- a/compiler/rustc_target/src/abi/call/nvptx.rs
+++ /dev/null
@@ -1,33 +0,0 @@
-// Reference: PTX Writer's Guide to Interoperability
-// https://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
-
-use crate::abi::call::{ArgAbi, FnAbi};
-
-fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
-    if ret.layout.is_aggregate() && ret.layout.size.bits() > 32 {
-        ret.make_indirect();
-    } else {
-        ret.extend_integer_width_to(32);
-    }
-}
-
-fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
-    if arg.layout.is_aggregate() && arg.layout.size.bits() > 32 {
-        arg.make_indirect();
-    } else {
-        arg.extend_integer_width_to(32);
-    }
-}
-
-pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
-    if !fn_abi.ret.is_ignore() {
-        classify_ret(&mut fn_abi.ret);
-    }
-
-    for arg in &mut fn_abi.args {
-        if arg.is_ignore() {
-            continue;
-        }
-        classify_arg(arg);
-    }
-}
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
index 9d36e37d7b8..6d919a4c2ad 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
@@ -1,20 +1,20 @@
-use crate::spec::{FramePointer, LinkerFlavor, SanitizerSet, Target, TargetOptions};
+use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::apple_base::opts("macos");
+    let arch = "arm64";
+    let mut base = super::apple_base::opts("macos", arch, "");
     base.cpu = "apple-a14".into();
     base.max_atomic_width = Some(128);
 
     // FIXME: The leak sanitizer currently fails the tests, see #88132.
     base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD;
 
-    base.add_pre_link_args(LinkerFlavor::Gcc, &["-arch", "arm64"]);
     base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove());
 
     // Clang automatically chooses a more specific target based on
     // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
     // correctly, we do too.
-    let llvm_target = super::apple_base::macos_llvm_target("arm64");
+    let llvm_target = super::apple_base::macos_llvm_target(arch);
 
     Target {
         llvm_target: llvm_target.into(),
diff --git a/compiler/rustc_target/src/spec/android_base.rs b/compiler/rustc_target/src/spec/android_base.rs
index dc06597db6f..2bf83a8782a 100644
--- a/compiler/rustc_target/src/spec/android_base.rs
+++ b/compiler/rustc_target/src/spec/android_base.rs
@@ -10,6 +10,6 @@ pub fn opts() -> TargetOptions {
     // for context. (At that time, there was no `-C force-unwind-tables`, so the only solution
     // was to always emit `uwtable`).
     base.default_uwtable = true;
-    base.crt_static_respected = false;
+    base.crt_static_respected = true;
     base
 }
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index 15e4fb9be63..db38ff50c78 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -1,8 +1,45 @@
 use std::{borrow::Cow, env};
 
-use crate::spec::{cvs, FramePointer, LldFlavor, SplitDebuginfo, TargetOptions};
+use crate::spec::{cvs, FramePointer, SplitDebuginfo, TargetOptions};
+use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor};
+
+fn pre_link_args(os: &'static str, arch: &'static str, abi: &'static str) -> LinkArgs {
+    let mut args = LinkArgs::new();
+
+    let platform_name = match abi {
+        "sim" => format!("{}-simulator", os),
+        "macabi" => "mac-catalyst".to_string(),
+        _ => os.to_string(),
+    };
+
+    let platform_version = match os.as_ref() {
+        "ios" => ios_lld_platform_version(),
+        "tvos" => tvos_lld_platform_version(),
+        "watchos" => watchos_lld_platform_version(),
+        "macos" => macos_lld_platform_version(arch),
+        _ => unreachable!(),
+    };
+
+    if abi != "macabi" {
+        args.insert(LinkerFlavor::Gcc, vec!["-arch".into(), arch.into()]);
+    }
+
+    args.insert(
+        LinkerFlavor::Lld(LldFlavor::Ld64),
+        vec![
+            "-arch".into(),
+            arch.into(),
+            "-platform_version".into(),
+            platform_name.into(),
+            platform_version.clone().into(),
+            platform_version.into(),
+        ],
+    );
+
+    args
+}
 
-pub fn opts(os: &'static str) -> TargetOptions {
+pub fn opts(os: &'static str, arch: &'static str, abi: &'static str) -> TargetOptions {
     // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6
     // either the linker will complain if it is used or the binary will end up
     // segfaulting at runtime when run on 10.6. Rust by default supports macOS
@@ -24,6 +61,7 @@ pub fn opts(os: &'static str) -> TargetOptions {
         // macOS has -dead_strip, which doesn't rely on function_sections
         function_sections: false,
         dynamic_linking: true,
+        pre_link_args: pre_link_args(os, arch, abi),
         linker_is_gnu: false,
         families: cvs!["unix"],
         is_like_osx: true,
@@ -73,6 +111,11 @@ fn macos_deployment_target(arch: &str) -> (u32, u32) {
         .unwrap_or_else(|| macos_default_deployment_target(arch))
 }
 
+fn macos_lld_platform_version(arch: &str) -> String {
+    let (major, minor) = macos_deployment_target(arch);
+    format!("{}.{}", major, minor)
+}
+
 pub fn macos_llvm_target(arch: &str) -> String {
     let (major, minor) = macos_deployment_target(arch);
     format!("{}-apple-macosx{}.{}.0", arch, major, minor)
@@ -109,7 +152,7 @@ pub fn ios_llvm_target(arch: &str) -> String {
     format!("{}-apple-ios{}.{}.0", arch, major, minor)
 }
 
-pub fn ios_lld_platform_version() -> String {
+fn ios_lld_platform_version() -> String {
     let (major, minor) = ios_deployment_target();
     format!("{}.{}", major, minor)
 }
@@ -123,7 +166,7 @@ fn tvos_deployment_target() -> (u32, u32) {
     deployment_target("TVOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
 }
 
-pub fn tvos_lld_platform_version() -> String {
+fn tvos_lld_platform_version() -> String {
     let (major, minor) = tvos_deployment_target();
     format!("{}.{}", major, minor)
 }
@@ -132,7 +175,7 @@ fn watchos_deployment_target() -> (u32, u32) {
     deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0))
 }
 
-pub fn watchos_lld_platform_version() -> String {
+fn watchos_lld_platform_version() -> String {
     let (major, minor) = watchos_deployment_target();
     format!("{}.{}", major, minor)
 }
diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs
index d77558f0f84..bf3ebaa2840 100644
--- a/compiler/rustc_target/src/spec/apple_sdk_base.rs
+++ b/compiler/rustc_target/src/spec/apple_sdk_base.rs
@@ -1,4 +1,4 @@
-use crate::spec::{cvs, LinkArgs, LinkerFlavor, LldFlavor, TargetOptions};
+use crate::spec::{cvs, TargetOptions};
 use std::borrow::Cow;
 
 use Arch::*;
@@ -61,53 +61,13 @@ fn link_env_remove(arch: Arch) -> Cow<'static, [Cow<'static, str>]> {
     }
 }
 
-fn pre_link_args(os: &'static str, arch: Arch) -> LinkArgs {
-    let mut args = LinkArgs::new();
-
-    let target_abi = target_abi(arch);
-
-    let platform_name = match target_abi {
-        "sim" => format!("{}-simulator", os),
-        "macabi" => "mac-catalyst".to_string(),
-        _ => os.to_string(),
-    };
-
-    let platform_version = match os.as_ref() {
-        "ios" => super::apple_base::ios_lld_platform_version(),
-        "tvos" => super::apple_base::tvos_lld_platform_version(),
-        "watchos" => super::apple_base::watchos_lld_platform_version(),
-        _ => unreachable!(),
-    };
-
-    let arch_str = target_arch_name(arch);
-
-    if target_abi != "macabi" {
-        args.insert(LinkerFlavor::Gcc, vec!["-arch".into(), arch_str.into()]);
-    }
-
-    args.insert(
-        LinkerFlavor::Lld(LldFlavor::Ld64),
-        vec![
-            "-arch".into(),
-            arch_str.into(),
-            "-platform_version".into(),
-            platform_name.into(),
-            platform_version.clone().into(),
-            platform_version.into(),
-        ],
-    );
-
-    args
-}
-
 pub fn opts(os: &'static str, arch: Arch) -> TargetOptions {
     TargetOptions {
         abi: target_abi(arch).into(),
         cpu: target_cpu(arch).into(),
         dynamic_linking: false,
-        pre_link_args: pre_link_args(os, arch),
         link_env_remove: link_env_remove(arch),
         has_thread_local: false,
-        ..super::apple_base::opts(os)
+        ..super::apple_base::opts(os, target_arch_name(arch), target_abi(arch))
     }
 }
diff --git a/compiler/rustc_target/src/spec/fuchsia_base.rs b/compiler/rustc_target/src/spec/fuchsia_base.rs
index df1e3275f73..962ad0c66d9 100644
--- a/compiler/rustc_target/src/spec/fuchsia_base.rs
+++ b/compiler/rustc_target/src/spec/fuchsia_base.rs
@@ -1,6 +1,11 @@
 use crate::spec::{crt_objects, cvs, LinkOutputKind, LinkerFlavor, LldFlavor, TargetOptions};
 
 pub fn opts() -> TargetOptions {
+    // This mirrors the linker options provided by clang. We presume lld for
+    // now. When using clang as the linker it will supply these options for us,
+    // so we only list them for ld/lld.
+    //
+    // https://github.com/llvm/llvm-project/blob/db9322b2066c55254e7691efeab863f43bfcc084/clang/lib/Driver/ToolChains/Fuchsia.cpp#L31
     let pre_link_args = TargetOptions::link_args(
         LinkerFlavor::Ld,
         &[
diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
index 1718bd77b86..5e9ceb844f7 100644
--- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs
@@ -1,7 +1,8 @@
 use crate::spec::{FramePointer, LinkerFlavor, StackProbeType, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let mut base = super::apple_base::opts("macos");
+    // ld64 only understand i386 and not i686
+    let mut base = super::apple_base::opts("macos", "i386", "");
     base.cpu = "yonah".into();
     base.max_atomic_width = Some(64);
     base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]);
diff --git a/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs
index 2546ab9b7e6..c9bb0112f0e 100644
--- a/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs
@@ -13,7 +13,9 @@ pub fn target() -> Target {
             abi: "eabi".into(),
             // The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them
             // with +strict-align.
-            features: "+strict-align".into(),
+            // Also force-enable 32-bit atomics, which allows the use of atomic load/store only.
+            // The resulting atomics are ABI incompatible with atomics backed by libatomic.
+            features: "+strict-align,+atomics-32".into(),
             // There are no atomic CAS instructions available in the instruction set of the ARMv6-M
             // architecture
             atomic_cas: false,
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
index dbd26899c18..176c9dd6b76 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs
@@ -2,11 +2,12 @@ use crate::spec::TargetOptions;
 use crate::spec::{FramePointer, LinkerFlavor, SanitizerSet, StackProbeType, Target};
 
 pub fn target() -> Target {
-    let mut base = super::apple_base::opts("macos");
+    let arch = "x86_64";
+    let mut base = super::apple_base::opts("macos", arch, "");
     base.cpu = "core2".into();
     base.max_atomic_width = Some(128); // core2 support cmpxchg16b
     base.frame_pointer = FramePointer::Always;
-    base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64", "-arch", "x86_64"]);
+    base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]);
     base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove());
     // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved
     base.stack_probes = StackProbeType::Call;
@@ -16,7 +17,6 @@ pub fn target() -> Target {
     // Clang automatically chooses a more specific target based on
     // MACOSX_DEPLOYMENT_TARGET.  To enable cross-language LTO to work
     // correctly, we do too.
-    let arch = "x86_64";
     let llvm_target = super::apple_base::macos_llvm_target(&arch);
 
     Target {
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index adf47ece69d..74625cc7bb7 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -619,6 +619,15 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> {
             constant.eval(self.selcx.tcx(), self.param_env)
         }
     }
+
+    #[inline]
+    fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> {
+        if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) {
+            p.super_fold_with(self)
+        } else {
+            p
+        }
+    }
 }
 
 pub struct BoundVarReplacer<'me, 'tcx> {
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 449d7a7b47b..61c556b726d 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -266,7 +266,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                 debug!("QueryNormalizer: result = {:#?}", result);
                 debug!("QueryNormalizer: obligations = {:#?}", obligations);
                 self.obligations.extend(obligations);
-                Ok(result.normalized_ty)
+
+                let res = result.normalized_ty;
+                // `tcx.normalize_projection_ty` may normalize to a type that still has
+                // unevaluated consts, so keep normalizing here if that's the case.
+                if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
+                    Ok(res.try_super_fold_with(self)?)
+                } else {
+                    Ok(res)
+                }
             }
 
             ty::Projection(data) => {
@@ -305,18 +313,27 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
                 debug!("QueryNormalizer: result = {:#?}", result);
                 debug!("QueryNormalizer: obligations = {:#?}", obligations);
                 self.obligations.extend(obligations);
-                Ok(crate::traits::project::PlaceholderReplacer::replace_placeholders(
+
+                let res = crate::traits::project::PlaceholderReplacer::replace_placeholders(
                     infcx,
                     mapped_regions,
                     mapped_types,
                     mapped_consts,
                     &self.universes,
                     result.normalized_ty,
-                ))
+                );
+                // `tcx.normalize_projection_ty` may normalize to a type that still has
+                // unevaluated consts, so keep normalizing here if that's the case.
+                if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) {
+                    Ok(res.try_super_fold_with(self)?)
+                } else {
+                    Ok(res)
+                }
             }
 
             _ => ty.try_super_fold_with(self),
         })()?;
+
         self.cache.insert(ty, res);
         Ok(res)
     }
@@ -351,4 +368,16 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> {
             mir::ConstantKind::Val(_, _) => constant.try_super_fold_with(self)?,
         })
     }
+
+    #[inline]
+    fn try_fold_predicate(
+        &mut self,
+        p: ty::Predicate<'tcx>,
+    ) -> Result<ty::Predicate<'tcx>, Self::Error> {
+        if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) {
+            p.try_super_fold_with(self)
+        } else {
+            Ok(p)
+        }
+    }
 }
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 8a5c7fee697..1e6cb53f3ee 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -16,7 +16,8 @@ use crate::require_c_abi_if_c_variadic;
 use rustc_ast::TraitObjectSyntax;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{
-    struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, MultiSpan,
+    struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError,
+    MultiSpan,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
@@ -43,7 +44,7 @@ use rustc_trait_selection::traits::error_reporting::{
 };
 use rustc_trait_selection::traits::wf::object_region_bounds;
 
-use smallvec::SmallVec;
+use smallvec::{smallvec, SmallVec};
 use std::collections::BTreeSet;
 use std::slice;
 
@@ -367,36 +368,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             return (tcx.intern_substs(&[]), arg_count);
         }
 
-        let is_object = self_ty.map_or(false, |ty| ty == self.tcx().types.trait_object_dummy_self);
-
         struct SubstsForAstPathCtxt<'a, 'tcx> {
             astconv: &'a (dyn AstConv<'tcx> + 'a),
             def_id: DefId,
             generic_args: &'a GenericArgs<'a>,
             span: Span,
-            missing_type_params: Vec<Symbol>,
             inferred_params: Vec<Span>,
             infer_args: bool,
-            is_object: bool,
-        }
-
-        impl<'tcx, 'a> SubstsForAstPathCtxt<'tcx, 'a> {
-            fn default_needs_object_self(&mut self, param: &ty::GenericParamDef) -> bool {
-                let tcx = self.astconv.tcx();
-                if let GenericParamDefKind::Type { has_default, .. } = param.kind {
-                    if self.is_object && has_default {
-                        let default_ty = tcx.at(self.span).type_of(param.def_id);
-                        let self_param = tcx.types.self_param;
-                        if default_ty.walk().any(|arg| arg == self_param.into()) {
-                            // There is no suitable inference default for a type parameter
-                            // that references self, in an object type.
-                            return true;
-                        }
-                    }
-                }
-
-                false
-            }
         }
 
         impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> {
@@ -499,41 +477,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     GenericParamDefKind::Type { has_default, .. } => {
                         if !infer_args && has_default {
                             // No type parameter provided, but a default exists.
-
-                            // If we are converting an object type, then the
-                            // `Self` parameter is unknown. However, some of the
-                            // other type parameters may reference `Self` in their
-                            // defaults. This will lead to an ICE if we are not
-                            // careful!
-                            if self.default_needs_object_self(param) {
-                                self.missing_type_params.push(param.name);
-                                tcx.ty_error().into()
-                            } else {
-                                // This is a default type parameter.
-                                let substs = substs.unwrap();
-                                if substs.iter().any(|arg| match arg.unpack() {
-                                    GenericArgKind::Type(ty) => ty.references_error(),
-                                    _ => false,
-                                }) {
-                                    // Avoid ICE #86756 when type error recovery goes awry.
-                                    return tcx.ty_error().into();
-                                }
-                                self.astconv
-                                    .normalize_ty(
-                                        self.span,
-                                        EarlyBinder(tcx.at(self.span).type_of(param.def_id))
-                                            .subst(tcx, substs),
-                                    )
-                                    .into()
+                            let substs = substs.unwrap();
+                            if substs.iter().any(|arg| match arg.unpack() {
+                                GenericArgKind::Type(ty) => ty.references_error(),
+                                _ => false,
+                            }) {
+                                // Avoid ICE #86756 when type error recovery goes awry.
+                                return tcx.ty_error().into();
                             }
+                            self.astconv
+                                .normalize_ty(
+                                    self.span,
+                                    EarlyBinder(tcx.at(self.span).type_of(param.def_id))
+                                        .subst(tcx, substs),
+                                )
+                                .into()
                         } else if infer_args {
-                            // No type parameters were provided, we can infer all.
-                            let param = if !self.default_needs_object_self(param) {
-                                Some(param)
-                            } else {
-                                None
-                            };
-                            self.astconv.ty_infer(param, self.span).into()
+                            self.astconv.ty_infer(Some(param), self.span).into()
                         } else {
                             // We've already errored above about the mismatch.
                             tcx.ty_error().into()
@@ -563,10 +523,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             def_id,
             span,
             generic_args,
-            missing_type_params: vec![],
             inferred_params: vec![],
             infer_args,
-            is_object,
         };
         let substs = Self::create_substs_for_generic_args(
             tcx,
@@ -578,13 +536,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             &mut substs_ctx,
         );
 
-        self.complain_about_missing_type_params(
-            substs_ctx.missing_type_params,
-            def_id,
-            span,
-            generic_args.args.is_empty(),
-        );
-
         debug!(
             "create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}",
             generics, self_ty, substs
@@ -1489,23 +1440,71 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         // Erase the `dummy_self` (`trait_object_dummy_self`) used above.
         let existential_trait_refs = regular_traits.iter().map(|i| {
             i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| {
-                if trait_ref.self_ty() != dummy_self {
-                    // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`,
-                    // which picks up non-supertraits where clauses - but also, the object safety
-                    // completely ignores trait aliases, which could be object safety hazards. We
-                    // `delay_span_bug` here to avoid an ICE in stable even when the feature is
-                    // disabled. (#66420)
-                    tcx.sess.delay_span_bug(
-                        DUMMY_SP,
-                        &format!(
-                            "trait_ref_to_existential called on {:?} with non-dummy Self",
-                            trait_ref,
-                        ),
+                assert_eq!(trait_ref.self_ty(), dummy_self);
+
+                // Verify that `dummy_self` did not leak inside default type parameters.  This
+                // could not be done at path creation, since we need to see through trait aliases.
+                let mut missing_type_params = vec![];
+                let mut references_self = false;
+                let generics = tcx.generics_of(trait_ref.def_id);
+                let substs: Vec<_> = trait_ref
+                    .substs
+                    .iter()
+                    .enumerate()
+                    .skip(1) // Remove `Self` for `ExistentialPredicate`.
+                    .map(|(index, arg)| {
+                        if let ty::GenericArgKind::Type(ty) = arg.unpack() {
+                            debug!(?ty);
+                            if ty == dummy_self {
+                                let param = &generics.params[index];
+                                missing_type_params.push(param.name);
+                                tcx.ty_error().into()
+                            } else if ty.walk().any(|arg| arg == dummy_self.into()) {
+                                references_self = true;
+                                tcx.ty_error().into()
+                            } else {
+                                arg
+                            }
+                        } else {
+                            arg
+                        }
+                    })
+                    .collect();
+                let substs = tcx.intern_substs(&substs[..]);
+
+                let span = i.bottom().1;
+                let empty_generic_args = trait_bounds.iter().any(|hir_bound| {
+                    hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id)
+                        && hir_bound.span.contains(span)
+                });
+                self.complain_about_missing_type_params(
+                    missing_type_params,
+                    trait_ref.def_id,
+                    span,
+                    empty_generic_args,
+                );
+
+                if references_self {
+                    let def_id = i.bottom().0.def_id();
+                    let mut err = struct_span_err!(
+                        tcx.sess,
+                        i.bottom().1,
+                        E0038,
+                        "the {} `{}` cannot be made into an object",
+                        tcx.def_kind(def_id).descr(def_id),
+                        tcx.item_name(def_id),
+                    );
+                    err.note(
+                        rustc_middle::traits::ObjectSafetyViolation::SupertraitSelf(smallvec![])
+                            .error_msg(),
                     );
+                    err.emit();
                 }
-                ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref)
+
+                ty::ExistentialTraitRef { def_id: trait_ref.def_id, substs }
             })
         });
+
         let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| {
             bound.map_bound(|b| {
                 if b.projection_ty.self_ty() != dummy_self {
@@ -2106,7 +2105,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     pub fn prohibit_generics<'a>(
         &self,
         segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone,
-        extend: impl Fn(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>),
+        extend: impl Fn(&mut Diagnostic),
     ) -> bool {
         let args = segments.clone().flat_map(|segment| segment.args().args);
 
@@ -2984,11 +2983,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
     }
 
     /// Make sure that we are in the condition to suggest the blanket implementation.
-    fn maybe_lint_blanket_trait_impl<T: rustc_errors::EmissionGuarantee>(
-        &self,
-        self_ty: &hir::Ty<'_>,
-        diag: &mut DiagnosticBuilder<'_, T>,
-    ) {
+    fn maybe_lint_blanket_trait_impl(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) {
         let tcx = self.tcx();
         let parent_id = tcx.hir().get_parent_item(self_ty.hir_id);
         if let hir::Node::Item(hir::Item {
@@ -3081,7 +3076,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                             sugg,
                             Applicability::MachineApplicable,
                         );
-                        self.maybe_lint_blanket_trait_impl::<()>(&self_ty, &mut diag);
+                        self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
                         diag.emit();
                     },
                 );
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 7aaddc2bd7a..6c7b2a2889f 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -32,6 +32,7 @@ use super::FnCtxt;
 
 use crate::hir::def_id::DefId;
 use crate::type_error_struct;
+use hir::def_id::LOCAL_CRATE;
 use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
@@ -40,7 +41,7 @@ use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::cast::{CastKind, CastTy};
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable};
+use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef};
 use rustc_session::lint;
 use rustc_session::Session;
 use rustc_span::symbol::sym;
@@ -173,6 +174,7 @@ pub enum CastError {
     /// or "a length". If this argument is None, then the metadata is unknown, for example,
     /// when we're typechecking a type parameter with a ?Sized bound.
     IntToFatCast(Option<&'static str>),
+    ForeignNonExhaustiveAdt,
 }
 
 impl From<ErrorGuaranteed> for CastError {
@@ -591,6 +593,17 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 }
                 err.emit();
             }
+            CastError::ForeignNonExhaustiveAdt => {
+                make_invalid_casting_error(
+                    fcx.tcx.sess,
+                    self.span,
+                    self.expr_ty,
+                    self.cast_ty,
+                    fcx,
+                )
+                .note("cannot cast an enum with a non-exhaustive variant when it's defined in another crate")
+                .emit();
+            }
         }
     }
 
@@ -789,6 +802,14 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             _ => return Err(CastError::NonScalar),
         };
 
+        if let ty::Adt(adt_def, _) = *self.expr_ty.kind() {
+            if adt_def.did().krate != LOCAL_CRATE {
+                if adt_def.variants().iter().any(VariantDef::is_field_list_non_exhaustive) {
+                    return Err(CastError::ForeignNonExhaustiveAdt);
+                }
+            }
+        }
+
         match (t_from, t_cast) {
             // These types have invariants! can't cast into them.
             (_, Int(CEnum) | FnPtr) => Err(CastError::NonScalar),
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 6e3ef15f884..5cdb2acd9f3 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -1525,9 +1525,7 @@ fn detect_discriminant_duplicate<'tcx>(
 ) {
     // Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate.
     // Here `idx` refers to the order of which the discriminant appears, and its index in `vs`
-    let report = |dis: Discr<'tcx>,
-                  idx: usize,
-                  err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>| {
+    let report = |dis: Discr<'tcx>, idx: usize, err: &mut Diagnostic| {
         let var = &vs[idx]; // HIR for the duplicate discriminant
         let (span, display_discr) = match var.disr_expr {
             Some(ref expr) => {
diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs
index 540a8c3a83d..6c6bbfa22e3 100644
--- a/compiler/rustc_typeck/src/check/coercion.rs
+++ b/compiler/rustc_typeck/src/check/coercion.rs
@@ -1479,6 +1479,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                 }
             }
             Err(coercion_error) => {
+                // Mark that we've failed to coerce the types here to suppress
+                // any superfluous errors we might encounter while trying to
+                // emit or provide suggestions on how to fix the initial error.
+                fcx.set_tainted_by_errors();
                 let (expected, found) = if label_expression_as_expected {
                     // In the case where this is a "forced unit", like
                     // `break`, we want to call the `()` "expected"
@@ -1581,9 +1585,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
             }
         }
     }
-    fn note_unreachable_loop_return<'a>(
+    fn note_unreachable_loop_return(
         &self,
-        err: &mut DiagnosticBuilder<'a, ErrorGuaranteed>,
+        err: &mut Diagnostic,
         expr: &hir::Expr<'tcx>,
         ret_exprs: &Vec<&'tcx hir::Expr<'tcx>>,
     ) {
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index 666498403c4..15a995ae59a 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -264,8 +264,13 @@ fn compare_predicate_entailment<'tcx>(
 
         let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs);
         let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig);
+        // Next, add all inputs and output as well-formed tys. Importantly,
+        // we have to do this before normalization, since the normalized ty may
+        // not contain the input parameters. See issue #87748.
+        wf_tys.extend(trait_sig.inputs_and_output.iter());
         let trait_sig = ocx.normalize(norm_cause, param_env, trait_sig);
-        // Add the resulting inputs and output as well-formed.
+        // We also have to add the normalized trait signature
+        // as we don't normalize during implied bounds computation.
         wf_tys.extend(trait_sig.inputs_and_output.iter());
         let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig));
 
diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs
index 0595b9a73be..bac0be44aa9 100644
--- a/compiler/rustc_typeck/src/check/demand.rs
+++ b/compiler/rustc_typeck/src/check/demand.rs
@@ -598,13 +598,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         let self_ty = self.typeck_results.borrow().expr_ty(&method_expr[0]);
-        let self_ty = format!("{:?}", self_ty);
         let name = method_path.ident.name;
-        let is_as_ref_able = (self_ty.starts_with("&std::option::Option")
-            || self_ty.starts_with("&std::result::Result")
-            || self_ty.starts_with("std::option::Option")
-            || self_ty.starts_with("std::result::Result"))
-            && (name == sym::map || name == sym::and_then);
+        let is_as_ref_able = match self_ty.peel_refs().kind() {
+            ty::Adt(def, _) => {
+                (self.tcx.is_diagnostic_item(sym::Option, def.did())
+                    || self.tcx.is_diagnostic_item(sym::Result, def.did()))
+                    && (name == sym::map || name == sym::and_then)
+            }
+            _ => false,
+        };
         match (is_as_ref_able, self.sess().source_map().span_to_snippet(method_path.ident.span)) {
             (true, Ok(src)) => {
                 let suggestion = format!("as_ref().{}", src);
@@ -792,7 +794,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             _ if is_range_literal(expr) => true,
                             _ => false,
                         };
-                        let sugg_expr = if needs_parens { format!("({src})") } else { src };
 
                         if let Some(sugg) = self.can_use_as_ref(expr) {
                             return Some((
@@ -820,6 +821,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             }
                         }
 
+                        let sugg_expr = if needs_parens { format!("({src})") } else { src };
                         return Some(match mutability {
                             hir::Mutability::Mut => (
                                 sp,
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index fb78632069e..6a6c03a8cba 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -28,7 +28,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{
     pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId,
-    EmissionGuarantee, ErrorGuaranteed,
+    ErrorGuaranteed,
 };
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
@@ -879,7 +879,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         lhs: &'tcx hir::Expr<'tcx>,
         err_code: &'static str,
         op_span: Span,
-        adjust_err: impl FnOnce(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>),
+        adjust_err: impl FnOnce(&mut Diagnostic),
     ) {
         if lhs.is_syntactic_place_expr() {
             return;
@@ -1089,8 +1089,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
 
-        let suggest_deref_binop = |err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
-                                   rhs_ty: Ty<'tcx>| {
+        let suggest_deref_binop = |err: &mut Diagnostic, rhs_ty: Ty<'tcx>| {
             if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) {
                 // Can only assign if the type is sized, so if `DerefMut` yields a type that is
                 // unsized, do not suggest dereferencing it.
@@ -2205,9 +2204,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.tcx().ty_error()
     }
 
-    fn check_call_constructor<G: EmissionGuarantee>(
+    fn check_call_constructor(
         &self,
-        err: &mut DiagnosticBuilder<'_, G>,
+        err: &mut Diagnostic,
         base: &'tcx hir::Expr<'tcx>,
         def_id: DefId,
     ) {
@@ -2526,15 +2525,18 @@ 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() {
+        let mod_id = self.tcx.parent_module(id).to_def_id();
+        if let Some((fields, substs)) =
+            self.get_field_candidates_considering_privacy(span, expr_t, mod_id)
+        {
+            for candidate_field in fields {
                 if let Some(mut field_path) = self.check_for_nested_field_satisfying(
                     span,
                     &|candidate_field, _| candidate_field.ident(self.tcx()) == field,
                     candidate_field,
                     substs,
                     vec![],
-                    self.tcx.parent_module(id).to_def_id(),
+                    mod_id,
                 ) {
                     // field_path includes `field` that we're looking for, so pop it.
                     field_path.pop();
@@ -2558,22 +2560,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err
     }
 
-    pub(crate) fn get_field_candidates(
+    pub(crate) fn get_field_candidates_considering_privacy(
         &self,
         span: Span,
-        base_t: Ty<'tcx>,
-    ) -> Option<(&[ty::FieldDef], SubstsRef<'tcx>)> {
-        debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_t);
+        base_ty: Ty<'tcx>,
+        mod_id: DefId,
+    ) -> Option<(impl Iterator<Item = &'tcx ty::FieldDef> + 'tcx, SubstsRef<'tcx>)> {
+        debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty);
 
-        for (base_t, _) in self.autoderef(span, base_t) {
+        for (base_t, _) in self.autoderef(span, base_ty) {
             match base_t.kind() {
                 ty::Adt(base_def, substs) if !base_def.is_enum() => {
+                    let tcx = self.tcx;
                     let fields = &base_def.non_enum_variant().fields;
-                    // For compile-time reasons put a limit on number of fields we search
-                    if fields.len() > 100 {
-                        return None;
+                    // Some struct, e.g. some that impl `Deref`, have all private fields
+                    // because you're expected to deref them to access the _real_ fields.
+                    // This, for example, will help us suggest accessing a field through a `Box<T>`.
+                    if fields.iter().all(|field| !field.vis.is_accessible_from(mod_id, tcx)) {
+                        continue;
                     }
-                    return Some((fields, substs));
+                    return Some((
+                        fields
+                            .iter()
+                            .filter(move |field| field.vis.is_accessible_from(mod_id, tcx))
+                            // For compile-time reasons put a limit on number of fields we search
+                            .take(100),
+                        substs,
+                    ));
                 }
                 _ => {}
             }
@@ -2590,7 +2603,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         candidate_field: &ty::FieldDef,
         subst: SubstsRef<'tcx>,
         mut field_path: Vec<Ident>,
-        id: DefId,
+        mod_id: DefId,
     ) -> Option<Vec<Ident>> {
         debug!(
             "check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}",
@@ -2602,24 +2615,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // up to a depth of three
             None
         } else {
-            // recursively search fields of `candidate_field` if it's a ty::Adt
             field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0());
             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() {
-                    if field.vis.is_accessible_from(id, self.tcx) {
-                        if matches(candidate_field, field_ty) {
-                            return Some(field_path);
-                        } else if let Some(field_path) = self.check_for_nested_field_satisfying(
-                            span,
-                            matches,
-                            field,
-                            subst,
-                            field_path.clone(),
-                            id,
-                        ) {
-                            return Some(field_path);
-                        }
+            if matches(candidate_field, field_ty) {
+                return Some(field_path);
+            } else if let Some((nested_fields, subst)) =
+                self.get_field_candidates_considering_privacy(span, field_ty, mod_id)
+            {
+                // recursively search fields of `candidate_field` if it's a ty::Adt
+                for field in nested_fields {
+                    if let Some(field_path) = self.check_for_nested_field_satisfying(
+                        span,
+                        matches,
+                        field,
+                        subst,
+                        field_path.clone(),
+                        mod_id,
+                    ) {
+                        return Some(field_path);
                     }
                 }
             }
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
index 660e7e4e399..1d1f755947f 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs
@@ -1778,7 +1778,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     fn label_fn_like(
         &self,
-        err: &mut rustc_errors::DiagnosticBuilder<'tcx, rustc_errors::ErrorGuaranteed>,
+        err: &mut Diagnostic,
         callable_def_id: Option<DefId>,
         callee_ty: Option<Ty<'tcx>>,
     ) {
diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
index 05bcc710e16..e008d50aa51 100644
--- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
+++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs
@@ -26,6 +26,17 @@ use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
 use std::cell::{Cell, RefCell};
 use std::ops::Deref;
 
+/// The `FnCtxt` stores type-checking context needed to type-check bodies of
+/// functions, closures, and `const`s, including performing type inference
+/// with [`InferCtxt`].
+///
+/// This is in contrast to [`ItemCtxt`], which is used to type-check item *signatures*
+/// and thus does not perform type inference.
+///
+/// See [`ItemCtxt`]'s docs for more.
+///
+/// [`ItemCtxt`]: crate::collect::ItemCtxt
+/// [`InferCtxt`]: infer::InferCtxt
 pub struct FnCtxt<'a, 'tcx> {
     pub(super) body_id: hir::HirId,
 
diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs
index c92b93cbc22..44c7c148c75 100644
--- a/compiler/rustc_typeck/src/check/method/suggest.rs
+++ b/compiler/rustc_typeck/src/check/method/suggest.rs
@@ -904,7 +904,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 }
 
-                let label_span_not_found = |err: &mut DiagnosticBuilder<'_, _>| {
+                let label_span_not_found = |err: &mut Diagnostic| {
                     if unsatisfied_predicates.is_empty() {
                         err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
                         let is_string_or_ref_str = match actual.kind() {
@@ -1000,7 +1000,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     label_span_not_found(&mut err);
                 }
 
-                self.check_for_field_method(&mut err, source, span, actual, item_name);
+                // Don't suggest (for example) `expr.field.method()` if `expr.method()`
+                // doesn't exist due to unsatisfied predicates.
+                if unsatisfied_predicates.is_empty() {
+                    self.check_for_field_method(&mut err, source, span, actual, item_name);
+                }
 
                 self.check_for_unwrap_self(&mut err, source, span, actual, item_name);
 
@@ -1150,7 +1154,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         rcvr_ty: Ty<'tcx>,
         expr: &hir::Expr<'_>,
         item_name: Ident,
-        err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+        err: &mut Diagnostic,
     ) -> bool {
         let tcx = self.tcx;
         let field_receiver = self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() {
@@ -1327,17 +1331,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     fn check_for_field_method(
         &self,
-        err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+        err: &mut Diagnostic,
         source: SelfSource<'tcx>,
         span: Span,
         actual: Ty<'tcx>,
         item_name: Ident,
     ) {
         if let SelfSource::MethodCall(expr) = source
-            && let Some((fields, substs)) = self.get_field_candidates(span, actual)
+            && let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id()
+            && let Some((fields, substs)) = self.get_field_candidates_considering_privacy(span, actual, mod_id)
         {
             let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id));
-            for candidate_field in fields.iter() {
+            for candidate_field in fields {
                 if let Some(field_path) = self.check_for_nested_field_satisfying(
                     span,
                     &|_, field_ty| {
@@ -1353,7 +1358,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     candidate_field,
                     substs,
                     vec![],
-                    self.tcx.parent_module(expr.hir_id).to_def_id(),
+                    mod_id,
                 ) {
                     let field_path_str = field_path
                         .iter()
@@ -1375,7 +1380,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     fn check_for_unwrap_self(
         &self,
-        err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>,
+        err: &mut Diagnostic,
         source: SelfSource<'tcx>,
         span: Span,
         actual: Ty<'tcx>,
diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs
index b73d9a9eb75..1b50209ee64 100644
--- a/compiler/rustc_typeck/src/check/mod.rs
+++ b/compiler/rustc_typeck/src/check/mod.rs
@@ -104,7 +104,7 @@ use crate::astconv::AstConv;
 use crate::check::gather_locals::GatherLocalsVisitor;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::{
-    pluralize, struct_span_err, Applicability, DiagnosticBuilder, EmissionGuarantee, MultiSpan,
+    pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan,
 };
 use rustc_hir as hir;
 use rustc_hir::def::Res;
@@ -973,12 +973,7 @@ fn has_expected_num_generic_args<'tcx>(
 /// * `span` - The span of the snippet
 /// * `params` - The number of parameters the constructor accepts
 /// * `err` - A mutable diagnostic builder to add the suggestion to
-fn suggest_call_constructor<G: EmissionGuarantee>(
-    span: Span,
-    kind: CtorOf,
-    params: usize,
-    err: &mut DiagnosticBuilder<'_, G>,
-) {
+fn suggest_call_constructor(span: Span, kind: CtorOf, params: usize, err: &mut Diagnostic) {
     // Note: tuple-structs don't have named fields, so just use placeholders
     let args = vec!["_"; params].join(", ");
     let applicable = if params > 0 {
diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs
index 920b3e68808..eb0c51bb2f9 100644
--- a/compiler/rustc_typeck/src/check/op.rs
+++ b/compiler/rustc_typeck/src/check/op.rs
@@ -59,7 +59,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 {
                     // Suppress this error, since we already emitted
                     // a deref suggestion in check_overloaded_binop
-                    err.delay_as_bug();
+                    err.downgrade_to_delayed_bug();
                 }
             }
         });
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index 99996e80c9c..e7c5ecc60ec 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -94,7 +94,27 @@ pub fn provide(providers: &mut Providers) {
 ///////////////////////////////////////////////////////////////////////////
 
 /// Context specific to some particular item. This is what implements
-/// `AstConv`. It has information about the predicates that are defined
+/// [`AstConv`].
+///
+/// # `ItemCtxt` vs `FnCtxt`
+///
+/// `ItemCtxt` is primarily used to type-check item signatures and lower them
+/// from HIR to their [`ty::Ty`] representation, which is exposed using [`AstConv`].
+/// It's also used for the bodies of items like structs where the body (the fields)
+/// are just signatures.
+///
+/// This is in contrast to [`FnCtxt`], which is used to type-check bodies of
+/// functions, closures, and `const`s -- anywhere that expressions and statements show up.
+///
+/// An important thing to note is that `ItemCtxt` does no inference -- it has no [`InferCtxt`] --
+/// while `FnCtxt` does do inference.
+///
+/// [`FnCtxt`]: crate::check::FnCtxt
+/// [`InferCtxt`]: rustc_infer::infer::InferCtxt
+///
+/// # Trait predicates
+///
+/// `ItemCtxt` has information about the predicates that are defined
 /// on the trait. Unfortunately, this predicate information is
 /// available in various different forms at various points in the
 /// process. So we can't just store a pointer to e.g., the AST or the
diff --git a/library/core/benches/num/int_log/mod.rs b/library/core/benches/num/int_log/mod.rs
index 19864d2d467..3c01e2998cd 100644
--- a/library/core/benches/num/int_log/mod.rs
+++ b/library/core/benches/num/int_log/mod.rs
@@ -9,7 +9,7 @@ macro_rules! int_log_bench {
                 for n in 0..(<$t>::BITS / 8) {
                     for i in 1..=(100 as $t) {
                         let x = black_box(i << (n * 8));
-                        black_box(x.log10());
+                        black_box(x.ilog10());
                     }
                 }
             });
@@ -27,7 +27,7 @@ macro_rules! int_log_bench {
                 .collect();
             bench.iter(|| {
                 for x in &numbers {
-                    black_box(black_box(x).log10());
+                    black_box(black_box(x).ilog10());
                 }
             });
         }
@@ -44,7 +44,7 @@ macro_rules! int_log_bench {
                 .collect();
             bench.iter(|| {
                 for x in &numbers {
-                    black_box(black_box(x).log10());
+                    black_box(black_box(x).ilog10());
                 }
             });
         }
diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs
index 887246c6001..6756eecd0e0 100644
--- a/library/core/src/alloc/global.rs
+++ b/library/core/src/alloc/global.rs
@@ -74,7 +74,7 @@ use crate::ptr;
 ///         {
 ///             return null_mut();
 ///         };
-///         (self.arena.get() as *mut u8).add(allocated)
+///         self.arena.get().cast::<u8>().add(allocated)
 ///     }
 ///     unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
 /// }
diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs
index 59ebe5fbe02..3473ac09e95 100644
--- a/library/core/src/alloc/layout.rs
+++ b/library/core/src/alloc/layout.rs
@@ -72,9 +72,8 @@ impl Layout {
         Layout::from_size_valid_align(size, unsafe { ValidAlign::new_unchecked(align) })
     }
 
-    /// Internal helper constructor to skip revalidating alignment validity.
-    #[inline]
-    const fn from_size_valid_align(size: usize, align: ValidAlign) -> Result<Self, LayoutError> {
+    #[inline(always)]
+    const fn max_size_for_align(align: ValidAlign) -> usize {
         // (power-of-two implies align != 0.)
 
         // Rounded up size is:
@@ -89,7 +88,13 @@ impl Layout {
         //
         // Above implies that checking for summation overflow is both
         // necessary and sufficient.
-        if size > isize::MAX as usize - (align.as_nonzero().get() - 1) {
+        isize::MAX as usize - (align.as_usize() - 1)
+    }
+
+    /// Internal helper constructor to skip revalidating alignment validity.
+    #[inline]
+    const fn from_size_valid_align(size: usize, align: ValidAlign) -> Result<Self, LayoutError> {
+        if size > Self::max_size_for_align(align) {
             return Err(LayoutError);
         }
 
@@ -128,7 +133,7 @@ impl Layout {
                   without modifying the layout"]
     #[inline]
     pub const fn align(&self) -> usize {
-        self.align.as_nonzero().get()
+        self.align.as_usize()
     }
 
     /// Constructs a `Layout` suitable for holding a value of type `T`.
@@ -410,13 +415,33 @@ impl Layout {
 
     /// Creates a layout describing the record for a `[T; n]`.
     ///
-    /// On arithmetic overflow, returns `LayoutError`.
+    /// On arithmetic overflow or when the total size would exceed
+    /// `isize::MAX`, returns `LayoutError`.
     #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
     #[inline]
     pub fn array<T>(n: usize) -> Result<Self, LayoutError> {
-        let array_size = mem::size_of::<T>().checked_mul(n).ok_or(LayoutError)?;
-        // The safe constructor is called here to enforce the isize size limit.
-        Layout::from_size_valid_align(array_size, ValidAlign::of::<T>())
+        // Reduce the amount of code we need to monomorphize per `T`.
+        return inner(mem::size_of::<T>(), ValidAlign::of::<T>(), n);
+
+        #[inline]
+        fn inner(element_size: usize, align: ValidAlign, n: usize) -> Result<Layout, LayoutError> {
+            // We need to check two things about the size:
+            //  - That the total size won't overflow a `usize`, and
+            //  - That the total size still fits in an `isize`.
+            // By using division we can check them both with a single threshold.
+            // That'd usually be a bad idea, but thankfully here the element size
+            // and alignment are constants, so the compiler will fold all of it.
+            if element_size != 0 && n > Layout::max_size_for_align(align) / element_size {
+                return Err(LayoutError);
+            }
+
+            let array_size = element_size * n;
+
+            // SAFETY: We just checked above that the `array_size` will not
+            // exceed `isize::MAX` even when rounded up to the alignment.
+            // And `ValidAlign` guarantees it's a power of two.
+            unsafe { Ok(Layout::from_size_align_unchecked(array_size, align.as_usize())) }
+        }
     }
 }
 
diff --git a/library/core/src/array/equality.rs b/library/core/src/array/equality.rs
index 33f7f494e9d..b2c895f882c 100644
--- a/library/core/src/array/equality.rs
+++ b/library/core/src/array/equality.rs
@@ -173,13 +173,14 @@ macro_rules! is_raw_eq_comparable {
     )+};
 }
 
-// SAFETY: All the ordinary integer types allow all bit patterns as distinct values
+// SAFETY: All the ordinary integer types have no padding, and are not pointers.
 is_raw_eq_comparable!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize);
 
-// SAFETY: bool and char have *niches*, but no *padding*, so this is sound
+// SAFETY: bool and char have *niches*, but no *padding* (and these are not pointer types), so this
+// is sound
 is_raw_eq_comparable!(bool, char);
 
-// SAFETY: Similarly, the non-zero types have a niche, but no undef,
+// SAFETY: Similarly, the non-zero types have a niche, but no undef and no pointers,
 // and they compare like their underlying numeric type.
 is_raw_eq_comparable!(
     NonZeroU8,
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index eae567cad00..2433139a592 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -892,8 +892,7 @@ impl char {
     ///
     /// The general categories for numbers (`Nd` for decimal digits, `Nl` for letter-like numeric
     /// characters, and `No` for other numeric characters) are specified in the [Unicode Character
-    /// Database][ucd] [`UnicodeData.txt`]. Note that this means ideographic numbers like '三'
-    /// are considered alphabetic, not numeric. Please consider to use `is_ascii_digit` or `is_digit`.
+    /// Database][ucd] [`UnicodeData.txt`].
     ///
     /// This method doesn't cover everything that could be considered a number, e.g. ideographic numbers like '三'.
     /// If you want everything including characters with overlapping purposes then you might want to use
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 82e63a7fe1d..d8b8ac4d871 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -387,6 +387,7 @@ impl CStr {
     #[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")]
     #[rustc_allow_const_fn_unstable(const_eval_select)]
     pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+        #[inline]
         fn rt_impl(bytes: &[u8]) -> &CStr {
             // Chance at catching some UB at runtime with debug builds.
             debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0);
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index cabc5017f1d..2d44feb15f8 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -2282,7 +2282,8 @@ extern "rust-intrinsic" {
     ///
     /// # Safety
     ///
-    /// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized.
+    /// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized or carry a
+    /// pointer value.
     /// Note that this is a stricter criterion than just the *values* being
     /// fully-initialized: if `T` has padding, it's UB to call this intrinsic.
     ///
diff --git a/library/core/src/mem/valid_align.rs b/library/core/src/mem/valid_align.rs
index 4ce6d13cf90..b9ccc0b4c79 100644
--- a/library/core/src/mem/valid_align.rs
+++ b/library/core/src/mem/valid_align.rs
@@ -36,9 +36,14 @@ impl ValidAlign {
     }
 
     #[inline]
+    pub(crate) const fn as_usize(self) -> usize {
+        self.0 as usize
+    }
+
+    #[inline]
     pub(crate) const fn as_nonzero(self) -> NonZeroUsize {
         // SAFETY: All the discriminants are non-zero.
-        unsafe { NonZeroUsize::new_unchecked(self.0 as usize) }
+        unsafe { NonZeroUsize::new_unchecked(self.as_usize()) }
     }
 
     /// Returns the base 2 logarithm of the alignment.
diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs
index de85fdd6ed2..d2a21b6b382 100644
--- a/library/core/src/num/bignum.rs
+++ b/library/core/src/num/bignum.rs
@@ -137,7 +137,7 @@ macro_rules! define_bignum {
                 // Find the most significant non-zero digit.
                 let msd = digits.iter().rposition(|&x| x != 0);
                 match msd {
-                    Some(msd) => msd * digitbits + digits[msd].log2() as usize + 1,
+                    Some(msd) => msd * digitbits + digits[msd].ilog2() as usize + 1,
                     // There are no non-zero digits, i.e., the number is zero.
                     _ => 0,
                 }
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index a66de19bad0..92b12ed3352 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -2204,7 +2204,7 @@ macro_rules! int_impl {
         /// rounded down.
         ///
         /// This method might not be optimized owing to implementation details;
-        /// `log2` can produce results more efficiently for base 2, and `log10`
+        /// `ilog2` can produce results more efficiently for base 2, and `ilog10`
         /// can produce results more efficiently for base 10.
         ///
         /// # Panics
@@ -2217,7 +2217,7 @@ macro_rules! int_impl {
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".log(5), 1);")]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
@@ -2226,8 +2226,8 @@ macro_rules! int_impl {
         #[track_caller]
         #[rustc_inherit_overflow_checks]
         #[allow(arithmetic_overflow)]
-        pub const fn log(self, base: Self) -> u32 {
-            match self.checked_log(base) {
+        pub const fn ilog(self, base: Self) -> u32 {
+            match self.checked_ilog(base) {
                 Some(n) => n,
                 None => {
                     // In debug builds, trigger a panic on None.
@@ -2250,7 +2250,7 @@ macro_rules! int_impl {
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".log2(), 1);")]
+        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
@@ -2259,8 +2259,8 @@ macro_rules! int_impl {
         #[track_caller]
         #[rustc_inherit_overflow_checks]
         #[allow(arithmetic_overflow)]
-        pub const fn log2(self) -> u32 {
-            match self.checked_log2() {
+        pub const fn ilog2(self) -> u32 {
+            match self.checked_ilog2() {
                 Some(n) => n,
                 None => {
                     // In debug builds, trigger a panic on None.
@@ -2283,7 +2283,7 @@ macro_rules! int_impl {
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".log10(), 1);")]
+        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
@@ -2292,8 +2292,8 @@ macro_rules! int_impl {
         #[track_caller]
         #[rustc_inherit_overflow_checks]
         #[allow(arithmetic_overflow)]
-        pub const fn log10(self) -> u32 {
-            match self.checked_log10() {
+        pub const fn ilog10(self) -> u32 {
+            match self.checked_ilog10() {
                 Some(n) => n,
                 None => {
                     // In debug builds, trigger a panic on None.
@@ -2311,20 +2311,20 @@ macro_rules! int_impl {
         /// Returns `None` if the number is negative or zero, or if the base is not at least 2.
         ///
         /// This method might not be optimized owing to implementation details;
-        /// `checked_log2` can produce results more efficiently for base 2, and
-        /// `checked_log10` can produce results more efficiently for base 10.
+        /// `checked_ilog2` can produce results more efficiently for base 2, and
+        /// `checked_ilog10` can produce results more efficiently for base 10.
         ///
         /// # Examples
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_log(5), Some(1));")]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        pub const fn checked_log(self, base: Self) -> Option<u32> {
+        pub const fn checked_ilog(self, base: Self) -> Option<u32> {
             if self <= 0 || base <= 1 {
                 None
             } else {
@@ -2333,7 +2333,7 @@ macro_rules! int_impl {
 
                 // Optimization for 128 bit wide integers.
                 if Self::BITS == 128 {
-                    let b = Self::log2(self) / (Self::log2(base) + 1);
+                    let b = Self::ilog2(self) / (Self::ilog2(base) + 1);
                     n += b;
                     r /= base.pow(b as u32);
                 }
@@ -2354,13 +2354,13 @@ macro_rules! int_impl {
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_log2(), Some(1));")]
+        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        pub const fn checked_log2(self) -> Option<u32> {
+        pub const fn checked_ilog2(self) -> Option<u32> {
             if self <= 0 {
                 None
             } else {
@@ -2378,13 +2378,13 @@ macro_rules! int_impl {
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_log10(), Some(1));")]
+        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        pub const fn checked_log10(self) -> Option<u32> {
+        pub const fn checked_ilog10(self) -> Option<u32> {
             if self > 0 {
                 Some(int_log10::$ActualT(self as $ActualT))
             } else {
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 4de0a0cf564..6196c4da4e3 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -450,7 +450,7 @@ macro_rules! nonzero_unsigned_operations {
                 /// Returns the base 2 logarithm of the number, rounded down.
                 ///
                 /// This is the same operation as
-                #[doc = concat!("[`", stringify!($Int), "::log2`],")]
+                #[doc = concat!("[`", stringify!($Int), "::ilog2`],")]
                 /// except that it has no failure cases to worry about
                 /// since this value can never be zero.
                 ///
@@ -460,22 +460,22 @@ macro_rules! nonzero_unsigned_operations {
                 /// #![feature(int_log)]
                 #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
                 ///
-                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().log2(), 2);")]
-                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().log2(), 3);")]
-                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().log2(), 3);")]
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().ilog2(), 2);")]
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().ilog2(), 3);")]
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().ilog2(), 3);")]
                 /// ```
                 #[unstable(feature = "int_log", issue = "70887")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
-                pub const fn log2(self) -> u32 {
+                pub const fn ilog2(self) -> u32 {
                     Self::BITS - 1 - self.leading_zeros()
                 }
 
                 /// Returns the base 10 logarithm of the number, rounded down.
                 ///
                 /// This is the same operation as
-                #[doc = concat!("[`", stringify!($Int), "::log10`],")]
+                #[doc = concat!("[`", stringify!($Int), "::ilog10`],")]
                 /// except that it has no failure cases to worry about
                 /// since this value can never be zero.
                 ///
@@ -485,15 +485,15 @@ macro_rules! nonzero_unsigned_operations {
                 /// #![feature(int_log)]
                 #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
                 ///
-                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().log10(), 1);")]
-                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().log10(), 2);")]
-                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().log10(), 2);")]
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().ilog10(), 1);")]
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().ilog10(), 2);")]
+                #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().ilog10(), 2);")]
                 /// ```
                 #[unstable(feature = "int_log", issue = "70887")]
                 #[must_use = "this returns the result of the operation, \
                               without modifying the original"]
                 #[inline]
-                pub const fn log10(self) -> u32 {
+                pub const fn ilog10(self) -> u32 {
                     super::int_log10::$Int(self.0)
                 }
             }
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 73365544233..aa3e8b9974e 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -700,7 +700,7 @@ macro_rules! uint_impl {
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".log(5), 1);")]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
@@ -709,8 +709,8 @@ macro_rules! uint_impl {
         #[track_caller]
         #[rustc_inherit_overflow_checks]
         #[allow(arithmetic_overflow)]
-        pub const fn log(self, base: Self) -> u32 {
-            match self.checked_log(base) {
+        pub const fn ilog(self, base: Self) -> u32 {
+            match self.checked_ilog(base) {
                 Some(n) => n,
                 None => {
                     // In debug builds, trigger a panic on None.
@@ -733,7 +733,7 @@ macro_rules! uint_impl {
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".log2(), 1);")]
+        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
@@ -742,8 +742,8 @@ macro_rules! uint_impl {
         #[track_caller]
         #[rustc_inherit_overflow_checks]
         #[allow(arithmetic_overflow)]
-        pub const fn log2(self) -> u32 {
-            match self.checked_log2() {
+        pub const fn ilog2(self) -> u32 {
+            match self.checked_ilog2() {
                 Some(n) => n,
                 None => {
                     // In debug builds, trigger a panic on None.
@@ -766,7 +766,7 @@ macro_rules! uint_impl {
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".log10(), 1);")]
+        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
@@ -775,8 +775,8 @@ macro_rules! uint_impl {
         #[track_caller]
         #[rustc_inherit_overflow_checks]
         #[allow(arithmetic_overflow)]
-        pub const fn log10(self) -> u32 {
-            match self.checked_log10() {
+        pub const fn ilog10(self) -> u32 {
+            match self.checked_ilog10() {
                 Some(n) => n,
                 None => {
                     // In debug builds, trigger a panic on None.
@@ -794,20 +794,20 @@ macro_rules! uint_impl {
         /// Returns `None` if the number is zero, or if the base is not at least 2.
         ///
         /// This method might not be optimized owing to implementation details;
-        /// `checked_log2` can produce results more efficiently for base 2, and
-        /// `checked_log10` can produce results more efficiently for base 10.
+        /// `checked_ilog2` can produce results more efficiently for base 2, and
+        /// `checked_ilog10` can produce results more efficiently for base 10.
         ///
         /// # Examples
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_log(5), Some(1));")]
+        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        pub const fn checked_log(self, base: Self) -> Option<u32> {
+        pub const fn checked_ilog(self, base: Self) -> Option<u32> {
             if self <= 0 || base <= 1 {
                 None
             } else {
@@ -816,7 +816,7 @@ macro_rules! uint_impl {
 
                 // Optimization for 128 bit wide integers.
                 if Self::BITS == 128 {
-                    let b = Self::log2(self) / (Self::log2(base) + 1);
+                    let b = Self::ilog2(self) / (Self::ilog2(base) + 1);
                     n += b;
                     r /= base.pow(b as u32);
                 }
@@ -837,15 +837,15 @@ macro_rules! uint_impl {
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_log2(), Some(1));")]
+        #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        pub const fn checked_log2(self) -> Option<u32> {
+        pub const fn checked_ilog2(self) -> Option<u32> {
             if let Some(x) = <$NonZeroT>::new(self) {
-                Some(x.log2())
+                Some(x.ilog2())
             } else {
                 None
             }
@@ -859,15 +859,15 @@ macro_rules! uint_impl {
         ///
         /// ```
         /// #![feature(int_log)]
-        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_log10(), Some(1));")]
+        #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")]
         /// ```
         #[unstable(feature = "int_log", issue = "70887")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        pub const fn checked_log10(self) -> Option<u32> {
+        pub const fn checked_ilog10(self) -> Option<u32> {
             if let Some(x) = <$NonZeroT>::new(self) {
-                Some(x.log10())
+                Some(x.ilog10())
             } else {
                 None
             }
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 2cd6e23c71a..c25b159c533 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -95,8 +95,8 @@ impl<T: ?Sized> *const T {
     ///
     /// This is a bit safer than `as` because it wouldn't silently change the type if the code is
     /// refactored.
-    #[unstable(feature = "ptr_const_cast", issue = "92675")]
-    #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")]
+    #[stable(feature = "ptr_const_cast", since = "1.65.0")]
+    #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
     pub const fn cast_mut(self) -> *mut T {
         self as _
     }
@@ -1267,20 +1267,21 @@ impl<T: ?Sized> *const T {
     /// Accessing adjacent `u8` as `u16`
     ///
     /// ```
-    /// # fn foo(n: usize) {
-    /// # use std::mem::align_of;
+    /// use std::mem::align_of;
+    ///
     /// # unsafe {
-    /// let x = [5u8, 6u8, 7u8, 8u8, 9u8];
-    /// let ptr = x.as_ptr().add(n) as *const u8;
+    /// let x = [5_u8, 6, 7, 8, 9];
+    /// let ptr = x.as_ptr();
     /// let offset = ptr.align_offset(align_of::<u16>());
-    /// if offset < x.len() - n - 1 {
-    ///     let u16_ptr = ptr.add(offset) as *const u16;
-    ///     assert_ne!(*u16_ptr, 500);
+    ///
+    /// if offset < x.len() - 1 {
+    ///     let u16_ptr = ptr.add(offset).cast::<u16>();
+    ///     assert!(*u16_ptr == u16::from_ne_bytes([5, 6]) || *u16_ptr == u16::from_ne_bytes([6, 7]));
     /// } else {
     ///     // while the pointer can be aligned via `offset`, it would point
     ///     // outside the allocation
     /// }
-    /// # } }
+    /// # }
     /// ```
     #[stable(feature = "align_offset", since = "1.36.0")]
     #[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 56ad5f7658e..fff06b458c7 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -100,8 +100,8 @@ impl<T: ?Sized> *mut T {
     /// coercion.
     ///
     /// [`cast_mut`]: #method.cast_mut
-    #[unstable(feature = "ptr_const_cast", issue = "92675")]
-    #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")]
+    #[stable(feature = "ptr_const_cast", since = "1.65.0")]
+    #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")]
     pub const fn cast_const(self) -> *const T {
         self as _
     }
@@ -1545,20 +1545,23 @@ impl<T: ?Sized> *mut T {
     /// Accessing adjacent `u8` as `u16`
     ///
     /// ```
-    /// # fn foo(n: usize) {
-    /// # use std::mem::align_of;
+    /// use std::mem::align_of;
+    ///
     /// # unsafe {
-    /// let x = [5u8, 6u8, 7u8, 8u8, 9u8];
-    /// let ptr = x.as_ptr().add(n) as *const u8;
+    /// let mut x = [5_u8, 6, 7, 8, 9];
+    /// let ptr = x.as_mut_ptr();
     /// let offset = ptr.align_offset(align_of::<u16>());
-    /// if offset < x.len() - n - 1 {
-    ///     let u16_ptr = ptr.add(offset) as *const u16;
-    ///     assert_ne!(*u16_ptr, 500);
+    ///
+    /// if offset < x.len() - 1 {
+    ///     let u16_ptr = ptr.add(offset).cast::<u16>();
+    ///     *u16_ptr = 0;
+    ///
+    ///     assert!(x == [0, 0, 7, 8, 9] || x == [5, 0, 0, 8, 9]);
     /// } else {
     ///     // while the pointer can be aligned via `offset`, it would point
     ///     // outside the allocation
     /// }
-    /// # } }
+    /// # }
     /// ```
     #[stable(feature = "align_offset", since = "1.36.0")]
     #[rustc_const_unstable(feature = "const_align_offset", issue = "90962")]
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index f1e65930967..f43b780ec9a 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -92,7 +92,7 @@ impl<'a, T> Iter<'a, T> {
             assume(!ptr.is_null());
 
             let end = if mem::size_of::<T>() == 0 {
-                (ptr as *const u8).wrapping_add(slice.len()) as *const T
+                ptr.wrapping_byte_add(slice.len())
             } else {
                 ptr.add(slice.len())
             };
@@ -228,7 +228,7 @@ impl<'a, T> IterMut<'a, T> {
             assume(!ptr.is_null());
 
             let end = if mem::size_of::<T>() == 0 {
-                (ptr as *mut u8).wrapping_add(slice.len()) as *mut T
+                ptr.wrapping_byte_add(slice.len())
             } else {
                 ptr.add(slice.len())
             };
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index 48353756741..153dc4dbb08 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -321,8 +321,8 @@ impl Duration {
     /// To determine the total number of seconds represented by the `Duration`
     /// including the fractional part, use [`as_secs_f64`] or [`as_secs_f32`]
     ///
-    /// [`as_secs_f32`]: Duration::as_secs_f64
-    /// [`as_secs_f64`]: Duration::as_secs_f32
+    /// [`as_secs_f64`]: Duration::as_secs_f64
+    /// [`as_secs_f32`]: Duration::as_secs_f32
     /// [`subsec_nanos`]: Duration::subsec_nanos
     #[stable(feature = "duration", since = "1.3.0")]
     #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
@@ -1135,7 +1135,7 @@ impl fmt::Debug for Duration {
                     // 2. The postfix: can be "µs" so we have to count UTF8 characters.
                     let mut actual_w = prefix.len() + postfix.chars().count();
                     // 3. The integer part:
-                    if let Some(log) = integer_part.checked_log10() {
+                    if let Some(log) = integer_part.checked_ilog10() {
                         // integer_part is > 0, so has length log10(x)+1
                         actual_w += 1 + log as usize;
                     } else {
diff --git a/library/core/tests/alloc.rs b/library/core/tests/alloc.rs
index 8a5a06b3440..3ceaeadcec6 100644
--- a/library/core/tests/alloc.rs
+++ b/library/core/tests/alloc.rs
@@ -1,4 +1,5 @@
 use core::alloc::Layout;
+use core::mem::size_of;
 use core::ptr::{self, NonNull};
 
 #[test]
@@ -13,6 +14,49 @@ fn const_unchecked_layout() {
 }
 
 #[test]
+fn layout_round_up_to_align_edge_cases() {
+    const MAX_SIZE: usize = isize::MAX as usize;
+
+    for shift in 0..usize::BITS {
+        let align = 1_usize << shift;
+        let edge = (MAX_SIZE + 1) - align;
+        let low = edge.saturating_sub(10);
+        let high = edge.saturating_add(10);
+        assert!(Layout::from_size_align(low, align).is_ok());
+        assert!(Layout::from_size_align(high, align).is_err());
+        for size in low..=high {
+            assert_eq!(
+                Layout::from_size_align(size, align).is_ok(),
+                size.next_multiple_of(align) <= MAX_SIZE,
+            );
+        }
+    }
+}
+
+#[test]
+fn layout_array_edge_cases() {
+    for_type::<i64>();
+    for_type::<[i32; 0b10101]>();
+    for_type::<[u8; 0b1010101]>();
+
+    // Make sure ZSTs don't lead to divide-by-zero
+    assert_eq!(Layout::array::<()>(usize::MAX).unwrap(), Layout::from_size_align(0, 1).unwrap());
+
+    fn for_type<T>() {
+        const MAX_SIZE: usize = isize::MAX as usize;
+
+        let edge = (MAX_SIZE + 1) / size_of::<T>();
+        let low = edge.saturating_sub(10);
+        let high = edge.saturating_add(10);
+        assert!(Layout::array::<T>(low).is_ok());
+        assert!(Layout::array::<T>(high).is_err());
+        for n in low..=high {
+            assert_eq!(Layout::array::<T>(n).is_ok(), n * size_of::<T>() <= MAX_SIZE);
+        }
+    }
+}
+
+#[test]
 fn layout_debug_shows_log2_of_alignment() {
     // `Debug` is not stable, but here's what it does right now
     let layout = Layout::from_size_align(24576, 8192).unwrap();
diff --git a/library/core/tests/const_ptr.rs b/library/core/tests/const_ptr.rs
index 152fed803ec..d874f08317f 100644
--- a/library/core/tests/const_ptr.rs
+++ b/library/core/tests/const_ptr.rs
@@ -3,7 +3,7 @@ const DATA: [u16; 2] = [u16::from_ne_bytes([0x01, 0x23]), u16::from_ne_bytes([0x
 
 const fn unaligned_ptr() -> *const u16 {
     // Since DATA.as_ptr() is aligned to two bytes, adding 1 byte to that produces an unaligned *const u16
-    unsafe { (DATA.as_ptr() as *const u8).add(1) as *const u16 }
+    unsafe { DATA.as_ptr().byte_add(1) }
 }
 
 #[test]
@@ -67,7 +67,7 @@ fn write() {
     const fn write_unaligned() -> [u16; 2] {
         let mut two_aligned = [0u16; 2];
         unsafe {
-            let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16;
+            let unaligned_ptr = two_aligned.as_mut_ptr().byte_add(1);
             ptr::write_unaligned(unaligned_ptr, u16::from_ne_bytes([0x23, 0x45]));
         }
         two_aligned
@@ -91,7 +91,7 @@ fn mut_ptr_write() {
     const fn write_unaligned() -> [u16; 2] {
         let mut two_aligned = [0u16; 2];
         unsafe {
-            let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16;
+            let unaligned_ptr = two_aligned.as_mut_ptr().byte_add(1);
             unaligned_ptr.write_unaligned(u16::from_ne_bytes([0x23, 0x45]));
         }
         two_aligned
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index db94368f6e0..df9b1073a09 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -14,6 +14,7 @@
 #![feature(const_maybe_uninit_assume_init_read)]
 #![feature(const_nonnull_new)]
 #![feature(const_num_from_num)]
+#![feature(const_pointer_byte_offsets)]
 #![feature(const_ptr_as_ref)]
 #![feature(const_ptr_read)]
 #![feature(const_ptr_write)]
@@ -74,6 +75,7 @@
 #![feature(never_type)]
 #![feature(unwrap_infallible)]
 #![feature(result_into_ok_or_err)]
+#![feature(pointer_byte_offsets)]
 #![feature(portable_simd)]
 #![feature(ptr_metadata)]
 #![feature(once_cell)]
diff --git a/library/core/tests/num/int_log.rs b/library/core/tests/num/int_log.rs
index dc3092e1486..be203fb5c04 100644
--- a/library/core/tests/num/int_log.rs
+++ b/library/core/tests/num/int_log.rs
@@ -1,166 +1,166 @@
-//! This tests the `Integer::{log,log2,log10}` methods. These tests are in a
+//! This tests the `Integer::{ilog,log2,log10}` methods. These tests are in a
 //! separate file because there's both a large number of them, and not all tests
-//! can be run on Android. This is because in Android `log2` uses an imprecise
+//! can be run on Android. This is because in Android `ilog2` uses an imprecise
 //! approximation:https://github.com/rust-lang/rust/blob/4825e12fc9c79954aa0fe18f5521efa6c19c7539/src/libstd/sys/unix/android.rs#L27-L53
 
 #[test]
-fn checked_log() {
-    assert_eq!(999u32.checked_log(10), Some(2));
-    assert_eq!(1000u32.checked_log(10), Some(3));
-    assert_eq!(555u32.checked_log(13), Some(2));
-    assert_eq!(63u32.checked_log(4), Some(2));
-    assert_eq!(64u32.checked_log(4), Some(3));
-    assert_eq!(10460353203u64.checked_log(3), Some(21));
-    assert_eq!(10460353202u64.checked_log(3), Some(20));
-    assert_eq!(147808829414345923316083210206383297601u128.checked_log(3), Some(80));
-    assert_eq!(147808829414345923316083210206383297600u128.checked_log(3), Some(79));
-    assert_eq!(22528399544939174411840147874772641u128.checked_log(19683), Some(8));
-    assert_eq!(22528399544939174411840147874772631i128.checked_log(19683), Some(7));
-
-    assert_eq!(0u8.checked_log(4), None);
-    assert_eq!(0u16.checked_log(4), None);
-    assert_eq!(0i8.checked_log(4), None);
-    assert_eq!(0i16.checked_log(4), None);
+fn checked_ilog() {
+    assert_eq!(999u32.checked_ilog(10), Some(2));
+    assert_eq!(1000u32.checked_ilog(10), Some(3));
+    assert_eq!(555u32.checked_ilog(13), Some(2));
+    assert_eq!(63u32.checked_ilog(4), Some(2));
+    assert_eq!(64u32.checked_ilog(4), Some(3));
+    assert_eq!(10460353203u64.checked_ilog(3), Some(21));
+    assert_eq!(10460353202u64.checked_ilog(3), Some(20));
+    assert_eq!(147808829414345923316083210206383297601u128.checked_ilog(3), Some(80));
+    assert_eq!(147808829414345923316083210206383297600u128.checked_ilog(3), Some(79));
+    assert_eq!(22528399544939174411840147874772641u128.checked_ilog(19683), Some(8));
+    assert_eq!(22528399544939174411840147874772631i128.checked_ilog(19683), Some(7));
+
+    assert_eq!(0u8.checked_ilog(4), None);
+    assert_eq!(0u16.checked_ilog(4), None);
+    assert_eq!(0i8.checked_ilog(4), None);
+    assert_eq!(0i16.checked_ilog(4), None);
 
     #[cfg(not(miri))] // Miri is too slow
     for i in i16::MIN..=0 {
-        assert_eq!(i.checked_log(4), None);
+        assert_eq!(i.checked_ilog(4), None);
     }
     #[cfg(not(miri))] // Miri is too slow
     for i in 1..=i16::MAX {
-        assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32));
+        assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32));
     }
     #[cfg(not(miri))] // Miri is too slow
     for i in 1..=u16::MAX {
-        assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32));
+        assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32));
     }
 }
 
 #[test]
-fn checked_log2() {
-    assert_eq!(5u32.checked_log2(), Some(2));
-    assert_eq!(0u64.checked_log2(), None);
-    assert_eq!(128i32.checked_log2(), Some(7));
-    assert_eq!((-55i16).checked_log2(), None);
+fn checked_ilog2() {
+    assert_eq!(5u32.checked_ilog2(), Some(2));
+    assert_eq!(0u64.checked_ilog2(), None);
+    assert_eq!(128i32.checked_ilog2(), Some(7));
+    assert_eq!((-55i16).checked_ilog2(), None);
 
-    assert_eq!(0u8.checked_log2(), None);
-    assert_eq!(0u16.checked_log2(), None);
-    assert_eq!(0i8.checked_log2(), None);
-    assert_eq!(0i16.checked_log2(), None);
+    assert_eq!(0u8.checked_ilog2(), None);
+    assert_eq!(0u16.checked_ilog2(), None);
+    assert_eq!(0i8.checked_ilog2(), None);
+    assert_eq!(0i16.checked_ilog2(), None);
 
     for i in 1..=u8::MAX {
-        assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32));
+        assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32));
     }
     #[cfg(not(miri))] // Miri is too slow
     for i in 1..=u16::MAX {
-        // Guard against Android's imprecise f32::log2 implementation.
+        // Guard against Android's imprecise f32::ilog2 implementation.
         if i != 8192 && i != 32768 {
-            assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32));
+            assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32));
         }
     }
     for i in i8::MIN..=0 {
-        assert_eq!(i.checked_log2(), None);
+        assert_eq!(i.checked_ilog2(), None);
     }
     for i in 1..=i8::MAX {
-        assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32));
+        assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32));
     }
     #[cfg(not(miri))] // Miri is too slow
     for i in i16::MIN..=0 {
-        assert_eq!(i.checked_log2(), None);
+        assert_eq!(i.checked_ilog2(), None);
     }
     #[cfg(not(miri))] // Miri is too slow
     for i in 1..=i16::MAX {
-        // Guard against Android's imprecise f32::log2 implementation.
+        // Guard against Android's imprecise f32::ilog2 implementation.
         if i != 8192 {
-            assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32));
+            assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32));
         }
     }
 }
 
-// Validate cases that fail on Android's imprecise float log2 implementation.
+// Validate cases that fail on Android's imprecise float ilog2 implementation.
 #[test]
 #[cfg(not(target_os = "android"))]
-fn checked_log2_not_android() {
-    assert_eq!(8192u16.checked_log2(), Some((8192f32).log2() as u32));
-    assert_eq!(32768u16.checked_log2(), Some((32768f32).log2() as u32));
-    assert_eq!(8192i16.checked_log2(), Some((8192f32).log2() as u32));
+fn checked_ilog2_not_android() {
+    assert_eq!(8192u16.checked_ilog2(), Some((8192f32).log2() as u32));
+    assert_eq!(32768u16.checked_ilog2(), Some((32768f32).log2() as u32));
+    assert_eq!(8192i16.checked_ilog2(), Some((8192f32).log2() as u32));
 }
 
 #[test]
-fn checked_log10() {
-    assert_eq!(0u8.checked_log10(), None);
-    assert_eq!(0u16.checked_log10(), None);
-    assert_eq!(0i8.checked_log10(), None);
-    assert_eq!(0i16.checked_log10(), None);
+fn checked_ilog10() {
+    assert_eq!(0u8.checked_ilog10(), None);
+    assert_eq!(0u16.checked_ilog10(), None);
+    assert_eq!(0i8.checked_ilog10(), None);
+    assert_eq!(0i16.checked_ilog10(), None);
 
     #[cfg(not(miri))] // Miri is too slow
     for i in i16::MIN..=0 {
-        assert_eq!(i.checked_log10(), None);
+        assert_eq!(i.checked_ilog10(), None);
     }
     #[cfg(not(miri))] // Miri is too slow
     for i in 1..=i16::MAX {
-        assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32));
+        assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32));
     }
     #[cfg(not(miri))] // Miri is too slow
     for i in 1..=u16::MAX {
-        assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32));
+        assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32));
     }
     #[cfg(not(miri))] // Miri is too slow
     for i in 1..=100_000u32 {
-        assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32));
+        assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32));
     }
 }
 
-macro_rules! log10_loop {
-    ($T:ty, $log10_max:expr) => {
-        assert_eq!(<$T>::MAX.log10(), $log10_max);
-        for i in 0..=$log10_max {
+macro_rules! ilog10_loop {
+    ($T:ty, $ilog10_max:expr) => {
+        assert_eq!(<$T>::MAX.ilog10(), $ilog10_max);
+        for i in 0..=$ilog10_max {
             let p = (10 as $T).pow(i as u32);
             if p >= 10 {
-                assert_eq!((p - 9).log10(), i - 1);
-                assert_eq!((p - 1).log10(), i - 1);
+                assert_eq!((p - 9).ilog10(), i - 1);
+                assert_eq!((p - 1).ilog10(), i - 1);
             }
-            assert_eq!(p.log10(), i);
-            assert_eq!((p + 1).log10(), i);
+            assert_eq!(p.ilog10(), i);
+            assert_eq!((p + 1).ilog10(), i);
             if p >= 10 {
-                assert_eq!((p + 9).log10(), i);
+                assert_eq!((p + 9).ilog10(), i);
             }
 
-            // also check `x.log(10)`
+            // also check `x.ilog(10)`
             if p >= 10 {
-                assert_eq!((p - 9).log(10), i - 1);
-                assert_eq!((p - 1).log(10), i - 1);
+                assert_eq!((p - 9).ilog(10), i - 1);
+                assert_eq!((p - 1).ilog(10), i - 1);
             }
-            assert_eq!(p.log(10), i);
-            assert_eq!((p + 1).log(10), i);
+            assert_eq!(p.ilog(10), i);
+            assert_eq!((p + 1).ilog(10), i);
             if p >= 10 {
-                assert_eq!((p + 9).log(10), i);
+                assert_eq!((p + 9).ilog(10), i);
             }
         }
     };
 }
 
 #[test]
-fn log10_u8() {
-    log10_loop! { u8, 2 }
+fn ilog10_u8() {
+    ilog10_loop! { u8, 2 }
 }
 
 #[test]
-fn log10_u16() {
-    log10_loop! { u16, 4 }
+fn ilog10_u16() {
+    ilog10_loop! { u16, 4 }
 }
 
 #[test]
-fn log10_u32() {
-    log10_loop! { u32, 9 }
+fn ilog10_u32() {
+    ilog10_loop! { u32, 9 }
 }
 
 #[test]
-fn log10_u64() {
-    log10_loop! { u64, 19 }
+fn ilog10_u64() {
+    ilog10_loop! { u64, 19 }
 }
 
 #[test]
-fn log10_u128() {
-    log10_loop! { u128, 38 }
+fn ilog10_u128() {
+    ilog10_loop! { u128, 38 }
 }
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
index 0656109e9db..b8f6fe6961a 100644
--- a/library/core/tests/slice.rs
+++ b/library/core/tests/slice.rs
@@ -1197,7 +1197,6 @@ fn chunks_mut_are_send_and_sync() {
     use std::slice::{ChunksExactMut, ChunksMut, RChunksExactMut, RChunksMut};
     use std::sync::MutexGuard;
 
-    #[allow(unused)]
     fn assert_send_and_sync()
     where
         ChunksMut<'static, Cell<i32>>: Send,
@@ -1210,6 +1209,8 @@ fn chunks_mut_are_send_and_sync() {
         RChunksExactMut<'static, MutexGuard<'static, u32>>: Sync,
     {
     }
+
+    assert_send_and_sync();
 }
 
 #[test]
diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs
index 05e9b2eb6bc..5cf6ec81789 100644
--- a/library/std/src/backtrace.rs
+++ b/library/std/src/backtrace.rs
@@ -9,12 +9,6 @@
 //! implementing `std::error::Error`) to get a causal chain of where an error
 //! was generated.
 //!
-//! > **Note**: this module is unstable and is designed in [RFC 2504], and you
-//! > can learn more about its status in the [tracking issue].
-//!
-//! [RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md
-//! [tracking issue]: https://github.com/rust-lang/rust/issues/53487
-//!
 //! ## Accuracy
 //!
 //! Backtraces are attempted to be as accurate as possible, but no guarantees
@@ -64,7 +58,7 @@
 //! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime might not actually change
 //! how backtraces are captured.
 
-#![unstable(feature = "backtrace", issue = "53487")]
+#![stable(feature = "backtrace", since = "1.65.0")]
 
 #[cfg(test)]
 mod tests;
@@ -110,6 +104,7 @@ use crate::vec::Vec;
 /// previous point in time. In some instances the `Backtrace` type may
 /// internally be empty due to configuration. For more information see
 /// `Backtrace::capture`.
+#[stable(feature = "backtrace", since = "1.65.0")]
 #[must_use]
 pub struct Backtrace {
     inner: Inner,
@@ -117,17 +112,21 @@ pub struct Backtrace {
 
 /// The current status of a backtrace, indicating whether it was captured or
 /// whether it is empty for some other reason.
+#[stable(feature = "backtrace", since = "1.65.0")]
 #[non_exhaustive]
 #[derive(Debug, PartialEq, Eq)]
 pub enum BacktraceStatus {
     /// Capturing a backtrace is not supported, likely because it's not
     /// implemented for the current platform.
+    #[stable(feature = "backtrace", since = "1.65.0")]
     Unsupported,
     /// Capturing a backtrace has been disabled through either the
     /// `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` environment variables.
+    #[stable(feature = "backtrace", since = "1.65.0")]
     Disabled,
     /// A backtrace has been captured and the `Backtrace` should print
     /// reasonable information when rendered.
+    #[stable(feature = "backtrace", since = "1.65.0")]
     Captured,
 }
 
@@ -174,6 +173,7 @@ enum BytesOrWide {
     Wide(Vec<u16>),
 }
 
+#[stable(feature = "backtrace", since = "1.65.0")]
 impl fmt::Debug for Backtrace {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         let capture = match &self.inner {
@@ -200,6 +200,7 @@ impl fmt::Debug for Backtrace {
     }
 }
 
+#[unstable(feature = "backtrace_frames", issue = "79676")]
 impl fmt::Debug for BacktraceFrame {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         let mut dbg = fmt.debug_list();
@@ -288,6 +289,7 @@ impl Backtrace {
     ///
     /// To forcibly capture a backtrace regardless of environment variables, use
     /// the `Backtrace::force_capture` function.
+    #[stable(feature = "backtrace", since = "1.65.0")]
     #[inline(never)] // want to make sure there's a frame here to remove
     pub fn capture() -> Backtrace {
         if !Backtrace::enabled() {
@@ -306,6 +308,7 @@ impl Backtrace {
     /// Note that capturing a backtrace can be an expensive operation on some
     /// platforms, so this should be used with caution in performance-sensitive
     /// parts of code.
+    #[stable(feature = "backtrace", since = "1.65.0")]
     #[inline(never)] // want to make sure there's a frame here to remove
     pub fn force_capture() -> Backtrace {
         Backtrace::create(Backtrace::force_capture as usize)
@@ -313,6 +316,8 @@ impl Backtrace {
 
     /// Forcibly captures a disabled backtrace, regardless of environment
     /// variable configuration.
+    #[stable(feature = "backtrace", since = "1.65.0")]
+    #[rustc_const_stable(feature = "backtrace", since = "1.65.0")]
     pub const fn disabled() -> Backtrace {
         Backtrace { inner: Inner::Disabled }
     }
@@ -356,6 +361,7 @@ impl Backtrace {
     /// Returns the status of this backtrace, indicating whether this backtrace
     /// request was unsupported, disabled, or a stack trace was actually
     /// captured.
+    #[stable(feature = "backtrace", since = "1.65.0")]
     #[must_use]
     pub fn status(&self) -> BacktraceStatus {
         match self.inner {
@@ -375,6 +381,7 @@ impl<'a> Backtrace {
     }
 }
 
+#[stable(feature = "backtrace", since = "1.65.0")]
 impl fmt::Display for Backtrace {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
         let capture = match &self.inner {
diff --git a/library/std/src/error.rs b/library/std/src/error.rs
index 722df119d22..df7a49d2582 100644
--- a/library/std/src/error.rs
+++ b/library/std/src/error.rs
@@ -1454,7 +1454,6 @@ impl<E> Report<E> {
     ///
     /// ```rust
     /// #![feature(error_reporter)]
-    /// #![feature(backtrace)]
     /// #![feature(provide_any)]
     /// #![feature(error_generic_member_access)]
     /// # use std::error::Error;
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 6b0c0ad7c21..ebe0ccbdc0b 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -246,6 +246,7 @@
 #![cfg_attr(bootstrap, feature(let_chains))]
 #![feature(let_else)]
 #![feature(linkage)]
+#![feature(link_cfg)]
 #![feature(min_specialization)]
 #![feature(must_not_suspend)]
 #![feature(needs_panic_runtime)]
diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs
index ea24fedd0eb..66fa1efbf10 100644
--- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs
+++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs
@@ -115,7 +115,7 @@ pub unsafe trait UserSafe {
     /// * the pointer is null.
     /// * the pointed-to range is not in user memory.
     unsafe fn check_ptr(ptr: *const Self) {
-        let is_aligned = |p| -> bool { 0 == (p as usize) & (Self::align_of() - 1) };
+        let is_aligned = |p: *const u8| -> bool { 0 == p.addr() & (Self::align_of() - 1) };
 
         assert!(is_aligned(ptr as *const u8));
         assert!(is_user_range(ptr as _, mem::size_of_val(unsafe { &*ptr })));
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index b5cc8038ca4..1f2f9d97bdd 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -687,7 +687,11 @@ impl Iterator for ReadDir {
 impl Drop for Dir {
     fn drop(&mut self) {
         let r = unsafe { libc::closedir(self.0) };
-        debug_assert_eq!(r, 0);
+        assert!(
+            r == 0 || crate::io::Error::last_os_error().kind() == crate::io::ErrorKind::Interrupted,
+            "unexpected error during closedir: {:?}",
+            crate::io::Error::last_os_error()
+        );
     }
 }
 
diff --git a/library/std/src/sys/unix/locks/pthread_condvar.rs b/library/std/src/sys/unix/locks/pthread_condvar.rs
index abf27e7db78..4741c0c6736 100644
--- a/library/std/src/sys/unix/locks/pthread_condvar.rs
+++ b/library/std/src/sys/unix/locks/pthread_condvar.rs
@@ -172,7 +172,7 @@ impl Condvar {
         let mut sys_now = libc::timeval { tv_sec: 0, tv_usec: 0 };
         let stable_now = Instant::now();
         let r = libc::gettimeofday(&mut sys_now, ptr::null_mut());
-        debug_assert_eq!(r, 0);
+        assert_eq!(r, 0, "unexpected error: {:?}", crate::io::Error::last_os_error());
 
         let nsec = dur.subsec_nanos() as libc::c_long + (sys_now.tv_usec * 1000) as libc::c_long;
         let extra = (nsec / 1_000_000_000) as libc::time_t;
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index 3d0d91460f7..3a375093099 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -295,8 +295,10 @@ pub fn abort_internal() -> ! {
 
 cfg_if::cfg_if! {
     if #[cfg(target_os = "android")] {
-        #[link(name = "dl")]
-        #[link(name = "log")]
+        #[link(name = "dl", kind = "static", modifiers = "-bundle",
+            cfg(target_feature = "crt-static"))]
+        #[link(name = "dl", cfg(not(target_feature = "crt-static")))]
+        #[link(name = "log", cfg(not(target_feature = "crt-static")))]
         extern "C" {}
     } else if #[cfg(target_os = "freebsd")] {
         #[link(name = "execinfo")]
diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs
index bf49204881d..a6fe07873d7 100644
--- a/library/std/src/sys/unix/rand.rs
+++ b/library/std/src/sys/unix/rand.rs
@@ -1,13 +1,13 @@
-use crate::mem;
-use crate::slice;
-
 pub fn hashmap_random_keys() -> (u64, u64) {
-    let mut v = (0, 0);
-    unsafe {
-        let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8, mem::size_of_val(&v));
-        imp::fill_bytes(view);
-    }
-    v
+    const KEY_LEN: usize = core::mem::size_of::<u64>();
+
+    let mut v = [0u8; KEY_LEN * 2];
+    imp::fill_bytes(&mut v);
+
+    let key1 = v[0..KEY_LEN].try_into().unwrap();
+    let key2 = v[KEY_LEN..].try_into().unwrap();
+
+    (u64::from_ne_bytes(key1), u64::from_ne_bytes(key2))
 }
 
 #[cfg(all(
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 36a3fa6023b..7db3065dee0 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -116,11 +116,9 @@ impl Thread {
         debug_assert_eq!(ret, 0);
     }
 
-    #[cfg(any(target_os = "linux", target_os = "android"))]
+    #[cfg(target_os = "android")]
     pub fn set_name(name: &CStr) {
         const PR_SET_NAME: libc::c_int = 15;
-        // pthread wrapper only appeared in glibc 2.12, so we use syscall
-        // directly.
         unsafe {
             libc::prctl(
                 PR_SET_NAME,
@@ -132,6 +130,14 @@ impl Thread {
         }
     }
 
+    #[cfg(target_os = "linux")]
+    pub fn set_name(name: &CStr) {
+        unsafe {
+            // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20.
+            libc::pthread_setname_np(libc::pthread_self(), name.as_ptr());
+        }
+    }
+
     #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
     pub fn set_name(name: &CStr) {
         unsafe {
diff --git a/library/std/src/sys/unsupported/alloc.rs b/library/std/src/sys/unsupported/alloc.rs
index 8d5d0a2f5cc..d715ae45401 100644
--- a/library/std/src/sys/unsupported/alloc.rs
+++ b/library/std/src/sys/unsupported/alloc.rs
@@ -1,15 +1,16 @@
 use crate::alloc::{GlobalAlloc, Layout, System};
+use crate::ptr::null_mut;
 
 #[stable(feature = "alloc_system_type", since = "1.28.0")]
 unsafe impl GlobalAlloc for System {
     #[inline]
     unsafe fn alloc(&self, _layout: Layout) -> *mut u8 {
-        0 as *mut u8
+        null_mut()
     }
 
     #[inline]
     unsafe fn alloc_zeroed(&self, _layout: Layout) -> *mut u8 {
-        0 as *mut u8
+        null_mut()
     }
 
     #[inline]
@@ -17,6 +18,6 @@ unsafe impl GlobalAlloc for System {
 
     #[inline]
     unsafe fn realloc(&self, _ptr: *mut u8, _layout: Layout, _new_size: usize) -> *mut u8 {
-        0 as *mut u8
+        null_mut()
     }
 }
diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs
index 42a1ff730e3..633f17c054b 100644
--- a/library/std/src/sys/unsupported/process.rs
+++ b/library/std/src/sys/unsupported/process.rs
@@ -200,6 +200,9 @@ impl<'a> Iterator for CommandArgs<'a> {
     fn next(&mut self) -> Option<&'a OsStr> {
         None
     }
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (0, Some(0))
+    }
 }
 
 impl<'a> ExactSizeIterator for CommandArgs<'a> {}
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 44c8a50fd86..479669647c1 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -170,7 +170,6 @@ use crate::ptr::addr_of_mut;
 use crate::str;
 use crate::sync::Arc;
 use crate::sys::thread as imp;
-use crate::sys_common::mutex;
 use crate::sys_common::thread;
 use crate::sys_common::thread_info;
 use crate::sys_common::thread_parker::Parker;
@@ -1033,24 +1032,48 @@ pub struct ThreadId(NonZeroU64);
 impl ThreadId {
     // Generate a new unique thread ID.
     fn new() -> ThreadId {
-        // It is UB to attempt to acquire this mutex reentrantly!
-        static GUARD: mutex::StaticMutex = mutex::StaticMutex::new();
-        static mut COUNTER: u64 = 1;
-
-        unsafe {
-            let guard = GUARD.lock();
-
-            // If we somehow use up all our bits, panic so that we're not
-            // covering up subtle bugs of IDs being reused.
-            if COUNTER == u64::MAX {
-                drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire.
-                panic!("failed to generate unique thread ID: bitspace exhausted");
-            }
-
-            let id = COUNTER;
-            COUNTER += 1;
+        #[cold]
+        fn exhausted() -> ! {
+            panic!("failed to generate unique thread ID: bitspace exhausted")
+        }
 
-            ThreadId(NonZeroU64::new(id).unwrap())
+        cfg_if::cfg_if! {
+            if #[cfg(target_has_atomic = "64")] {
+                use crate::sync::atomic::{AtomicU64, Ordering::Relaxed};
+
+                static COUNTER: AtomicU64 = AtomicU64::new(0);
+
+                let mut last = COUNTER.load(Relaxed);
+                loop {
+                    let Some(id) = last.checked_add(1) else {
+                        exhausted();
+                    };
+
+                    match COUNTER.compare_exchange_weak(last, id, Relaxed, Relaxed) {
+                        Ok(_) => return ThreadId(NonZeroU64::new(id).unwrap()),
+                        Err(id) => last = id,
+                    }
+                }
+            } else {
+                use crate::sys_common::mutex::StaticMutex;
+
+                // It is UB to attempt to acquire this mutex reentrantly!
+                static GUARD: StaticMutex = StaticMutex::new();
+                static mut COUNTER: u64 = 0;
+
+                unsafe {
+                    let guard = GUARD.lock();
+
+                    let Some(id) = COUNTER.checked_add(1) else {
+                        drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire.
+                        exhausted();
+                    };
+
+                    COUNTER = id;
+                    drop(guard);
+                    ThreadId(NonZeroU64::new(id).unwrap())
+                }
+            }
         }
     }
 
diff --git a/library/unwind/build.rs b/library/unwind/build.rs
index f88e6a924b5..126e41d1e20 100644
--- a/library/unwind/build.rs
+++ b/library/unwind/build.rs
@@ -13,13 +13,8 @@ fn main() {
         let has_unwind = build.is_flag_supported("-lunwind").expect("Unable to invoke compiler");
 
         if has_unwind {
-            println!("cargo:rustc-link-lib=unwind");
-        } else {
-            println!("cargo:rustc-link-lib=gcc");
+            println!("cargo:rustc-cfg=feature=\"system-llvm-libunwind\"");
         }
-
-        // Android's unwinding library depends on dl_iterate_phdr in `libdl`.
-        println!("cargo:rustc-link-lib=dl");
     } else if target.contains("freebsd") {
         println!("cargo:rustc-link-lib=gcc_s");
     } else if target.contains("netbsd") {
diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs
index 4a6ba6e10c3..46fe50cb945 100644
--- a/library/unwind/src/lib.rs
+++ b/library/unwind/src/lib.rs
@@ -55,6 +55,26 @@ cfg_if::cfg_if! {
     }
 }
 
+#[cfg(target_os = "android")]
+cfg_if::cfg_if! {
+    if #[cfg(feature = "llvm-libunwind")] {
+        compile_error!("`llvm-libunwind` is not supported for Android targets");
+    } else if #[cfg(feature = "system-llvm-libunwind")] {
+        #[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
+        #[link(name = "unwind", cfg(not(target_feature = "crt-static")))]
+        extern "C" {}
+    } else {
+        #[link(name = "gcc", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
+        #[link(name = "gcc", cfg(not(target_feature = "crt-static")))]
+        extern "C" {}
+    }
+}
+// Android's unwinding library depends on dl_iterate_phdr in `libdl`.
+#[cfg(target_os = "android")]
+#[link(name = "dl", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))]
+#[link(name = "dl", cfg(not(target_feature = "crt-static")))]
+extern "C" {}
+
 // When building with crt-static, we get `gcc_eh` from the `libc` crate, since
 // glibc needs it, and needs it listed later on the linker command line. We
 // don't want to duplicate it here.
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index f84de73297a..a242243aaaf 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -1631,14 +1631,12 @@ fn chmod(_path: &Path, _perms: u32) {}
 /// If code is not 0 (successful exit status), exit status is 101 (rust's default error code.)
 /// If the test is running and code is an error code, it will cause a panic.
 fn detail_exit(code: i32) -> ! {
-    // Successful exit
-    if code == 0 {
-        std::process::exit(0);
-    }
-    if cfg!(test) {
+    // if in test and code is an error code, panic with staus code provided
+    if cfg!(test) && code != 0 {
         panic!("status code: {}", code);
     } else {
-        std::panic::resume_unwind(Box::new(code));
+        //otherwise,exit with provided status code
+        std::process::exit(code);
     }
 }
 
diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in
index 5a1f2e70413..1e0f7e9acf4 100644
--- a/src/bootstrap/mk/Makefile.in
+++ b/src/bootstrap/mk/Makefile.in
@@ -66,16 +66,21 @@ TESTS_IN_2 := \
 	src/test/ui \
 	src/tools/linkchecker
 
+## MSVC native builders
+
+# these intentionally don't use `$(BOOTSTRAP)` so we can test the shebang on Windows
 ci-subset-1:
-	$(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_2:%=--exclude %)
+	$(Q)$(CFG_SRC_DIR)/x.py test --stage 2 $(TESTS_IN_2:%=--exclude %)
 ci-subset-2:
-	$(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_2)
+	$(Q)$(CFG_SRC_DIR)/x.ps1 test --stage 2 $(TESTS_IN_2)
+
+## MingW native builders
 
 TESTS_IN_MINGW_2 := \
 	src/test/ui
 
 ci-mingw-subset-1:
-	$(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_MINGW_2:%=--exclude %)
+	$(Q)$(CFG_SRC_DIR)/x.sh test --stage 2 $(TESTS_IN_MINGW_2:%=--exclude %)
 ci-mingw-subset-2:
 	$(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_MINGW_2)
 
diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs
index 4d548dbb638..8b50d5dc52b 100644
--- a/src/bootstrap/native.rs
+++ b/src/bootstrap/native.rs
@@ -325,6 +325,9 @@ impl Step for Llvm {
             cfg.define("LLVM_PROFDATA_FILE", &path);
         }
 
+        // Disable zstd to avoid a dependency on libzstd.so.
+        cfg.define("LLVM_ENABLE_ZSTD", "OFF");
+
         if target != "aarch64-apple-darwin" && !target.contains("windows") {
             cfg.define("LLVM_ENABLE_ZLIB", "ON");
         } else {
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index ed1d883d0dc..baad0c75295 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -924,6 +924,11 @@ fn compare_browser_ui_test_version(installed_version: &str, src: &Path) {
                      one used in the CI (`{}`)",
                     installed_version, v
                 );
+                eprintln!(
+                    "You can install this version using `npm update browser-ui-test` or by using \
+                     `npm install browser-ui-test@{}`",
+                    v,
+                );
             }
         }
         Err(e) => eprintln!("Couldn't find the CI browser-ui-test version: {:?}", e),
diff --git a/src/ci/docker/host-x86_64/arm-android/Dockerfile b/src/ci/docker/host-x86_64/arm-android/Dockerfile
index 43cdbbe92e3..a2335687ab3 100644
--- a/src/ci/docker/host-x86_64/arm-android/Dockerfile
+++ b/src/ci/docker/host-x86_64/arm-android/Dockerfile
@@ -29,7 +29,8 @@ ENV PATH=$PATH:/android/sdk/platform-tools
 
 ENV TARGETS=arm-linux-androideabi
 
-ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/arm-14
+ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/arm-14 \
+    --set llvm.allow-old-toolchain
 
 ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target $TARGETS
 
diff --git a/src/ci/docker/host-x86_64/dist-android/Dockerfile b/src/ci/docker/host-x86_64/dist-android/Dockerfile
index 2f0496d7dd4..c98fa496d48 100644
--- a/src/ci/docker/host-x86_64/dist-android/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-android/Dockerfile
@@ -32,7 +32,8 @@ ENV RUST_CONFIGURE_ARGS \
       --i686-linux-android-ndk=/android/ndk/x86-14 \
       --aarch64-linux-android-ndk=/android/ndk/arm64-21 \
       --x86_64-linux-android-ndk=/android/ndk/x86_64-21 \
-      --disable-docs
+      --disable-docs \
+      --set llvm.allow-old-toolchain
 
 ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS
 
diff --git a/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile
index c98fc7dcfff..b0d65428ec6 100644
--- a/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile
@@ -36,7 +36,8 @@ RUN /scripts/cmake.sh
 ENV RUST_CONFIGURE_ARGS \
       --musl-root-i586=/musl-i586 \
       --musl-root-i686=/musl-i686 \
-      --disable-docs
+      --disable-docs \
+      --set llvm.allow-old-toolchain
 
 # Newer binutils broke things on some vms/distros (i.e., linking against
 # unknown relocs disabled by the following flag), so we need to go out of our
diff --git a/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile
index b0f06569a9c..948fa40dd4b 100644
--- a/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile
@@ -26,5 +26,6 @@ RUN /scripts/cmake.sh
 
 ENV HOSTS=mips-unknown-linux-gnu
 
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \
+    --set llvm.allow-old-toolchain
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile
index 245c28e1fa3..fd15dbd22c6 100644
--- a/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile
@@ -25,5 +25,6 @@ RUN /scripts/cmake.sh
 
 ENV HOSTS=mips64-unknown-linux-gnuabi64
 
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \
+    --set llvm.allow-old-toolchain
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile
index 03998c8880a..376bdfb4a2f 100644
--- a/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile
@@ -26,5 +26,6 @@ RUN /scripts/cmake.sh
 
 ENV HOSTS=mips64el-unknown-linux-gnuabi64
 
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \
+    --set llvm.allow-old-toolchain
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile
index 58617270621..70c8b2a96c8 100644
--- a/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile
@@ -25,5 +25,6 @@ RUN /scripts/cmake.sh
 
 ENV HOSTS=mipsel-unknown-linux-gnu
 
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \
+    --set llvm.allow-old-toolchain
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-netbsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-netbsd/Dockerfile
index 92bdc9811fd..fed4be4c30a 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-netbsd/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-netbsd/Dockerfile
@@ -21,5 +21,6 @@ ENV \
 
 ENV HOSTS=x86_64-unknown-netbsd
 
-ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \
+    --set llvm.allow-old-toolchain
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
index 0182ebb8b59..1f8d0a64ea4 100644
--- a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
+++ b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
@@ -27,6 +27,7 @@ RUN mkdir -p /config
 RUN echo "[rust]" > /config/nopt-std-config.toml
 RUN echo "optimize = false" >> /config/nopt-std-config.toml
 
-ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests
+ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests \
+    --set llvm.allow-old-toolchain
 ENV SCRIPT python3 ../x.py test --stage 0 --config /config/nopt-std-config.toml library/std \
   && python3 ../x.py --stage 2 test
diff --git a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile
index feaab819bdd..7bca0398dea 100644
--- a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile
+++ b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile
@@ -23,7 +23,8 @@ RUN sh /scripts/sccache.sh
 COPY scripts/cmake.sh /scripts/
 RUN /scripts/cmake.sh
 
-ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu
+ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu \
+    --set llvm.allow-old-toolchain
 # Exclude some tests that are unlikely to be platform specific, to speed up
 # this slow job.
 ENV SCRIPT python3 ../x.py --stage 2 test \
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile
index ee3cd092f4c..bfc6975c19d 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile
@@ -26,5 +26,6 @@ RUN sh /scripts/sccache.sh
 COPY scripts/cmake.sh /scripts/
 RUN /scripts/cmake.sh
 
-ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
+ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu \
+    --set llvm.allow-old-toolchain
 ENV RUST_CHECK_TARGET check-aux
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile
index 09d9cda02bd..4bb4042cd7e 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile
@@ -22,6 +22,7 @@ RUN sh /scripts/sccache.sh
 COPY scripts/cmake.sh /scripts/
 RUN /scripts/cmake.sh
 
-ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --set rust.ignore-git=false
+ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --set rust.ignore-git=false \
+    --set llvm.allow-old-toolchain
 ENV SCRIPT python3 ../x.py --stage 2 test distcheck
 ENV DIST_SRC 1
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-12/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-12/Dockerfile
index df1fbc29cf5..8de9045c3ba 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-12/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-12/Dockerfile
@@ -1,6 +1,8 @@
 FROM ubuntu:20.04
 
 ARG DEBIAN_FRONTEND=noninteractive
+
+# NOTE: intentionally installs both python2 and python3 so we can test support for both.
 RUN apt-get update && apt-get install -y --no-install-recommends \
   g++ \
   gcc-multilib \
@@ -10,6 +12,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   curl \
   ca-certificates \
   python2.7 \
+  python3.9 \
   git \
   cmake \
   sudo \
@@ -23,6 +26,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   xz-utils \
   nodejs
 
+# Install powershell so we can test x.ps1 on Linux
+RUN apt-get update && \
+    apt-get install -y apt-transport-https software-properties-common && \
+    curl -s "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb" > packages-microsoft-prod.deb && \
+    dpkg -i packages-microsoft-prod.deb && \
+    apt-get update && \
+    apt-get install -y powershell
+
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
@@ -33,21 +44,22 @@ ENV RUST_CONFIGURE_ARGS \
       --enable-llvm-link-shared \
       --set rust.thin-lto-import-instr-limit=10
 
-ENV SCRIPT python2.7 ../x.py --stage 2 test --exclude src/tools/tidy && \
+# NOTE: intentionally uses all of `x.py`, `x.sh`, and `x.ps1` to make sure they all work on Linux.
+ENV SCRIPT ../x.py --stage 2 test --exclude src/tools/tidy && \
            # Run the `mir-opt` tests again but this time for a 32-bit target.
            # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have
            # both 32-bit and 64-bit outputs updated by the PR author, before
            # the PR is approved and tested for merging.
            # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`,
            # despite having different output on 32-bit vs 64-bit targets.
-           python2.7 ../x.py --stage 2 test src/test/mir-opt \
+           ../x.sh --stage 2 test src/test/mir-opt \
                              --host='' --target=i686-unknown-linux-gnu && \
            # Run the UI test suite again, but in `--pass=check` mode
            #
            # This is intended to make sure that both `--pass=check` continues to
            # work.
            #
-           python2.7 ../x.py --stage 2 test src/test/ui --pass=check \
+           ../x.ps1 --stage 2 test src/test/ui --pass=check \
                              --host='' --target=i686-unknown-linux-gnu && \
            # Run tidy at the very end, after all the other tests.
            python2.7 ../x.py --stage 2 test src/tools/tidy
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 2358091a6df..f442a477a7b 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
@@ -81,6 +81,7 @@ COPY host-x86_64/x86_64-gnu-tools/browser-ui-test.version /tmp/
 RUN npm install -g browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true
 
 ENV RUST_CONFIGURE_ARGS \
+  --set llvm.allow-old-toolchain \
   --build=x86_64-unknown-linux-gnu \
   --save-toolstates=/tmp/toolstate/toolstates.json
 
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 3ad4e3f97a3..a21400cc472 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -596,14 +596,18 @@ jobs:
 
           - name: i686-mingw-1
             env:
-              RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
+              RUST_CONFIGURE_ARGS: >-
+                --build=i686-pc-windows-gnu
+                --set llvm.allow-old-toolchain
               SCRIPT: make ci-mingw-subset-1
               CUSTOM_MINGW: 1
             <<: *job-windows-xl
 
           - name: i686-mingw-2
             env:
-              RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu
+              RUST_CONFIGURE_ARGS: >-
+                --build=i686-pc-windows-gnu
+                --set llvm.allow-old-toolchain
               SCRIPT: make ci-mingw-subset-2
               CUSTOM_MINGW: 1
             <<: *job-windows-xl
@@ -611,14 +615,20 @@ jobs:
           - name: x86_64-mingw-1
             env:
               SCRIPT: make ci-mingw-subset-1
-              RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-profiler
+              RUST_CONFIGURE_ARGS: >-
+                --build=x86_64-pc-windows-gnu
+                --enable-profiler
+                --set llvm.allow-old-toolchain
               CUSTOM_MINGW: 1
             <<: *job-windows-xl
 
           - name: x86_64-mingw-2
             env:
               SCRIPT: make ci-mingw-subset-2
-              RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-profiler
+              RUST_CONFIGURE_ARGS: >-
+                --build=x86_64-pc-windows-gnu
+                --enable-profiler
+                --set llvm.allow-old-toolchain
               CUSTOM_MINGW: 1
             <<: *job-windows-xl
 
@@ -663,7 +673,11 @@ jobs:
 
           - name: dist-i686-mingw
             env:
-              RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler
+              RUST_CONFIGURE_ARGS: >-
+                --build=i686-pc-windows-gnu
+                --enable-full-tools
+                --enable-profiler
+                --set llvm.allow-old-toolchain
               SCRIPT: python x.py dist
               CUSTOM_MINGW: 1
               DIST_REQUIRE_ALL_TOOLS: 1
@@ -672,7 +686,11 @@ jobs:
           - name: dist-x86_64-mingw
             env:
               SCRIPT: python x.py dist
-              RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler
+              RUST_CONFIGURE_ARGS: >-
+                --build=x86_64-pc-windows-gnu
+                --enable-full-tools
+                --enable-profiler
+                --set llvm.allow-old-toolchain
               CUSTOM_MINGW: 1
               DIST_REQUIRE_ALL_TOOLS: 1
             <<: *job-windows-xl
diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md
index 9c644dd404d..b1854b22a7c 100644
--- a/src/doc/rustc/src/linker-plugin-lto.md
+++ b/src/doc/rustc/src/linker-plugin-lto.md
@@ -30,7 +30,7 @@ Using `rustc` directly:
 # Compile the Rust staticlib
 rustc --crate-type=staticlib -Clinker-plugin-lto -Copt-level=2 ./lib.rs
 # Compile the C code with `-flto=thin`
-clang -c -O2 -flto=thin -o main.o ./main.c
+clang -c -O2 -flto=thin -o cmain.o ./cmain.c
 # Link everything, making sure that we use an appropriate linker
 clang -flto=thin -fuse-ld=lld -L . -l"name-of-your-rust-lib" -o main -O2 ./cmain.o
 ```
@@ -41,7 +41,7 @@ Using `cargo`:
 # Compile the Rust staticlib
 RUSTFLAGS="-Clinker-plugin-lto" cargo build --release
 # Compile the C code with `-flto=thin`
-clang -c -O2 -flto=thin -o main.o ./main.c
+clang -c -O2 -flto=thin -o cmain.o ./cmain.c
 # Link everything, making sure that we use an appropriate linker
 clang -flto=thin -fuse-ld=lld -L . -l"name-of-your-rust-lib" -o main -O2 ./cmain.o
 ```
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 01dd95e6e40..da15c3c2b1f 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -120,7 +120,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                             items: cx.tcx
                                 .associated_items(impl_def_id)
                                 .in_definition_order()
-                                .map(|x| x.clean(cx))
+                                .map(|x| clean_middle_assoc_item(x, cx))
                                 .collect::<Vec<_>>(),
                             polarity: ty::ImplPolarity::Positive,
                             kind: ImplKind::Blanket(Box::new(clean_middle_ty(trait_ref.0.self_ty(), cx, None))),
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 58d0aedb023..e56a715e857 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -16,9 +16,10 @@ use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Symbol};
 
 use crate::clean::{
-    self, clean_fn_decl_from_did_and_sig, clean_middle_field, clean_middle_ty,
-    clean_trait_ref_with_bindings, clean_ty, clean_ty_generics, clean_variant_def,
-    clean_visibility, utils, Attributes, AttributesExt, Clean, ImplKind, ItemId, Type, Visibility,
+    self, clean_fn_decl_from_did_and_sig, clean_generics, clean_impl_item, clean_middle_assoc_item,
+    clean_middle_field, clean_middle_ty, clean_trait_ref_with_bindings, clean_ty,
+    clean_ty_generics, clean_variant_def, clean_visibility, utils, Attributes, AttributesExt,
+    ImplKind, ItemId, Type, Visibility,
 };
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
@@ -217,7 +218,7 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean
             // which causes methods to have a `pub` prefix, which is invalid since items in traits
             // can not have a visibility prefix. Thus we override the visibility here manually.
             // See https://github.com/rust-lang/rust/issues/81274
-            clean::Item { visibility: Visibility::Inherited, ..item.clean(cx) }
+            clean::Item { visibility: Visibility::Inherited, ..clean_middle_assoc_item(item, cx) }
         })
         .collect();
 
@@ -426,9 +427,9 @@ pub(crate) fn build_impl(
                         true
                     }
                 })
-                .map(|item| item.clean(cx))
+                .map(|item| clean_impl_item(item, cx))
                 .collect::<Vec<_>>(),
-            impl_.generics.clean(cx),
+            clean_generics(impl_.generics, cx),
         ),
         None => (
             tcx.associated_items(did)
@@ -452,7 +453,7 @@ pub(crate) fn build_impl(
                         item.visibility(tcx).is_public()
                     }
                 })
-                .map(|item| item.clean(cx))
+                .map(|item| clean_middle_assoc_item(item, cx))
                 .collect::<Vec<_>>(),
             clean::enter_impl_trait(cx, |cx| {
                 clean_ty_generics(cx, tcx.generics_of(did), predicates)
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 78b93725537..6e246385489 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -48,75 +48,68 @@ pub(crate) trait Clean<'tcx, T> {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> T;
 }
 
-impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
-        let mut items: Vec<Item> = vec![];
-        let mut inserted = FxHashSet::default();
-        items.extend(self.foreigns.iter().map(|(item, renamed)| {
-            let item = clean_maybe_renamed_foreign_item(cx, item, *renamed);
+pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
+    let mut items: Vec<Item> = vec![];
+    let mut inserted = FxHashSet::default();
+    items.extend(doc.foreigns.iter().map(|(item, renamed)| {
+        let item = clean_maybe_renamed_foreign_item(cx, item, *renamed);
+        if let Some(name) = item.name {
+            inserted.insert((item.type_(), name));
+        }
+        item
+    }));
+    items.extend(doc.mods.iter().map(|x| {
+        inserted.insert((ItemType::Module, x.name));
+        clean_doc_module(x, cx)
+    }));
+
+    // Split up imports from all other items.
+    //
+    // This covers the case where somebody does an import which should pull in an item,
+    // but there's already an item with the same namespace and same name. Rust gives
+    // priority to the not-imported one, so we should, too.
+    items.extend(doc.items.iter().flat_map(|(item, renamed)| {
+        // First, lower everything other than imports.
+        if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
+            return Vec::new();
+        }
+        let v = clean_maybe_renamed_item(cx, item, *renamed);
+        for item in &v {
             if let Some(name) = item.name {
                 inserted.insert((item.type_(), name));
             }
-            item
-        }));
-        items.extend(self.mods.iter().map(|x| {
-            inserted.insert((ItemType::Module, x.name));
-            x.clean(cx)
-        }));
-
-        // Split up imports from all other items.
-        //
-        // This covers the case where somebody does an import which should pull in an item,
-        // but there's already an item with the same namespace and same name. Rust gives
-        // priority to the not-imported one, so we should, too.
-        items.extend(self.items.iter().flat_map(|(item, renamed)| {
-            // First, lower everything other than imports.
-            if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
-                return Vec::new();
-            }
-            let v = clean_maybe_renamed_item(cx, item, *renamed);
-            for item in &v {
-                if let Some(name) = item.name {
-                    inserted.insert((item.type_(), name));
-                }
-            }
-            v
-        }));
-        items.extend(self.items.iter().flat_map(|(item, renamed)| {
-            // Now we actually lower the imports, skipping everything else.
-            if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind {
-                let name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
-                clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted)
-            } else {
-                // skip everything else
-                Vec::new()
-            }
-        }));
-
-        // determine if we should display the inner contents or
-        // the outer `mod` item for the source code.
-
-        let span = Span::new({
-            let where_outer = self.where_outer(cx.tcx);
-            let sm = cx.sess().source_map();
-            let outer = sm.lookup_char_pos(where_outer.lo());
-            let inner = sm.lookup_char_pos(self.where_inner.lo());
-            if outer.file.start_pos == inner.file.start_pos {
-                // mod foo { ... }
-                where_outer
-            } else {
-                // mod foo; (and a separate SourceFile for the contents)
-                self.where_inner
-            }
-        });
+        }
+        v
+    }));
+    items.extend(doc.items.iter().flat_map(|(item, renamed)| {
+        // Now we actually lower the imports, skipping everything else.
+        if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind {
+            let name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
+            clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted)
+        } else {
+            // skip everything else
+            Vec::new()
+        }
+    }));
+
+    // determine if we should display the inner contents or
+    // the outer `mod` item for the source code.
+
+    let span = Span::new({
+        let where_outer = doc.where_outer(cx.tcx);
+        let sm = cx.sess().source_map();
+        let outer = sm.lookup_char_pos(where_outer.lo());
+        let inner = sm.lookup_char_pos(doc.where_inner.lo());
+        if outer.file.start_pos == inner.file.start_pos {
+            // mod foo { ... }
+            where_outer
+        } else {
+            // mod foo; (and a separate SourceFile for the contents)
+            doc.where_inner
+        }
+    });
 
-        Item::from_hir_id_and_parts(
-            self.id,
-            Some(self.name),
-            ModuleItem(Module { items, span }),
-            cx,
-        )
-    }
+    Item::from_hir_id_and_parts(doc.id, Some(doc.name), ModuleItem(Module { items, span }), cx)
 }
 
 fn clean_generic_bound<'tcx>(
@@ -130,7 +123,7 @@ fn clean_generic_bound<'tcx>(
 
             let trait_ref = ty::TraitRef::identity(cx.tcx, def_id).skip_binder();
 
-            let generic_args = generic_args.clean(cx);
+            let generic_args = clean_generic_args(generic_args, cx);
             let GenericArgs::AngleBracketed { bindings, .. } = generic_args
             else {
                 bug!("clean: parenthesized `GenericBound::LangItemTrait`");
@@ -568,69 +561,68 @@ fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool {
     matches!(param.kind, hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided })
 }
 
-impl<'tcx> Clean<'tcx, Generics> for hir::Generics<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Generics {
-        let impl_trait_params = self
-            .params
-            .iter()
-            .filter(|param| is_impl_trait(param))
-            .map(|param| {
-                let param = clean_generic_param(cx, Some(self), param);
-                match param.kind {
-                    GenericParamDefKind::Lifetime { .. } => unreachable!(),
-                    GenericParamDefKind::Type { did, ref bounds, .. } => {
-                        cx.impl_trait_bounds.insert(did.into(), bounds.clone());
-                    }
-                    GenericParamDefKind::Const { .. } => unreachable!(),
+pub(crate) fn clean_generics<'tcx>(
+    gens: &hir::Generics<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> Generics {
+    let impl_trait_params = gens
+        .params
+        .iter()
+        .filter(|param| is_impl_trait(param))
+        .map(|param| {
+            let param = clean_generic_param(cx, Some(gens), param);
+            match param.kind {
+                GenericParamDefKind::Lifetime { .. } => unreachable!(),
+                GenericParamDefKind::Type { did, ref bounds, .. } => {
+                    cx.impl_trait_bounds.insert(did.into(), bounds.clone());
                 }
-                param
-            })
-            .collect::<Vec<_>>();
+                GenericParamDefKind::Const { .. } => unreachable!(),
+            }
+            param
+        })
+        .collect::<Vec<_>>();
 
-        let mut params = Vec::with_capacity(self.params.len());
-        for p in self.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
-            let p = clean_generic_param(cx, Some(self), p);
-            params.push(p);
-        }
-        params.extend(impl_trait_params);
+    let mut params = Vec::with_capacity(gens.params.len());
+    for p in gens.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
+        let p = clean_generic_param(cx, Some(gens), p);
+        params.push(p);
+    }
+    params.extend(impl_trait_params);
 
-        let mut generics = Generics {
-            params,
-            where_predicates: self
-                .predicates
-                .iter()
-                .filter_map(|x| clean_where_predicate(x, cx))
-                .collect(),
-        };
+    let mut generics = Generics {
+        params,
+        where_predicates: gens
+            .predicates
+            .iter()
+            .filter_map(|x| clean_where_predicate(x, cx))
+            .collect(),
+    };
 
-        // Some duplicates are generated for ?Sized bounds between type params and where
-        // predicates. The point in here is to move the bounds definitions from type params
-        // to where predicates when such cases occur.
-        for where_pred in &mut generics.where_predicates {
-            match *where_pred {
-                WherePredicate::BoundPredicate {
-                    ty: Generic(ref name), ref mut bounds, ..
-                } => {
-                    if bounds.is_empty() {
-                        for param in &mut generics.params {
-                            match param.kind {
-                                GenericParamDefKind::Lifetime { .. } => {}
-                                GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => {
-                                    if &param.name == name {
-                                        mem::swap(bounds, ty_bounds);
-                                        break;
-                                    }
+    // Some duplicates are generated for ?Sized bounds between type params and where
+    // predicates. The point in here is to move the bounds definitions from type params
+    // to where predicates when such cases occur.
+    for where_pred in &mut generics.where_predicates {
+        match *where_pred {
+            WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds, .. } => {
+                if bounds.is_empty() {
+                    for param in &mut generics.params {
+                        match param.kind {
+                            GenericParamDefKind::Lifetime { .. } => {}
+                            GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => {
+                                if &param.name == name {
+                                    mem::swap(bounds, ty_bounds);
+                                    break;
                                 }
-                                GenericParamDefKind::Const { .. } => {}
                             }
+                            GenericParamDefKind::Const { .. } => {}
                         }
                     }
                 }
-                _ => continue,
             }
+            _ => continue,
         }
-        generics
     }
+    generics
 }
 
 fn clean_ty_generics<'tcx>(
@@ -896,7 +888,7 @@ fn clean_function<'tcx>(
 ) -> Box<Function> {
     let (generics, decl) = enter_impl_trait(cx, |cx| {
         // NOTE: generics must be cleaned before args
-        let generics = generics.clean(cx);
+        let generics = clean_generics(generics, cx);
         let args = clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id);
         let decl = clean_fn_decl_with_args(cx, sig.decl, args);
         (generics, decl)
@@ -1025,7 +1017,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
             hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
                 let (generics, decl) = enter_impl_trait(cx, |cx| {
                     // NOTE: generics must be cleaned before args
-                    let generics = trait_item.generics.clean(cx);
+                    let generics = clean_generics(trait_item.generics, cx);
                     let args = clean_args_from_types_and_names(cx, sig.decl.inputs, names);
                     let decl = clean_fn_decl_with_args(cx, sig.decl, args);
                     (generics, decl)
@@ -1033,7 +1025,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
                 TyMethodItem(Box::new(Function { decl, generics }))
             }
             hir::TraitItemKind::Type(bounds, Some(default)) => {
-                let generics = enter_impl_trait(cx, |cx| trait_item.generics.clean(cx));
+                let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
                 let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
                 let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, default), cx, None);
                 AssocTypeItem(
@@ -1046,7 +1038,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
                 )
             }
             hir::TraitItemKind::Type(bounds, None) => {
-                let generics = enter_impl_trait(cx, |cx| trait_item.generics.clean(cx));
+                let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
                 let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
                 TyAssocTypeItem(Box::new(generics), bounds)
             }
@@ -1058,240 +1050,243 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
     })
 }
 
-impl<'tcx> Clean<'tcx, Item> for hir::ImplItem<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
-        let local_did = self.def_id.to_def_id();
-        cx.with_param_env(local_did, |cx| {
-            let inner = match self.kind {
-                hir::ImplItemKind::Const(ty, expr) => {
-                    let default = ConstantKind::Local { def_id: local_did, body: expr };
-                    AssocConstItem(clean_ty(ty, cx), default)
-                }
-                hir::ImplItemKind::Fn(ref sig, body) => {
-                    let m = clean_function(cx, sig, self.generics, body);
-                    let defaultness = cx.tcx.impl_defaultness(self.def_id);
-                    MethodItem(m, Some(defaultness))
-                }
-                hir::ImplItemKind::TyAlias(hir_ty) => {
-                    let type_ = clean_ty(hir_ty, cx);
-                    let generics = self.generics.clean(cx);
-                    let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
-                    AssocTypeItem(
-                        Box::new(Typedef { type_, generics, item_type: Some(item_type) }),
-                        Vec::new(),
-                    )
-                }
-            };
+pub(crate) fn clean_impl_item<'tcx>(
+    impl_: &hir::ImplItem<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> Item {
+    let local_did = impl_.def_id.to_def_id();
+    cx.with_param_env(local_did, |cx| {
+        let inner = match impl_.kind {
+            hir::ImplItemKind::Const(ty, expr) => {
+                let default = ConstantKind::Local { def_id: local_did, body: expr };
+                AssocConstItem(clean_ty(ty, cx), default)
+            }
+            hir::ImplItemKind::Fn(ref sig, body) => {
+                let m = clean_function(cx, sig, impl_.generics, body);
+                let defaultness = cx.tcx.impl_defaultness(impl_.def_id);
+                MethodItem(m, Some(defaultness))
+            }
+            hir::ImplItemKind::TyAlias(hir_ty) => {
+                let type_ = clean_ty(hir_ty, cx);
+                let generics = clean_generics(impl_.generics, cx);
+                let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
+                AssocTypeItem(
+                    Box::new(Typedef { type_, generics, item_type: Some(item_type) }),
+                    Vec::new(),
+                )
+            }
+        };
 
-            let mut what_rustc_thinks =
-                Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx);
+        let mut what_rustc_thinks =
+            Item::from_def_id_and_parts(local_did, Some(impl_.ident.name), inner, cx);
 
-            let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(self.def_id));
+        let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(impl_.def_id));
 
-            // Trait impl items always inherit the impl's visibility --
-            // we don't want to show `pub`.
-            if impl_ref.is_some() {
-                what_rustc_thinks.visibility = Inherited;
-            }
+        // Trait impl items always inherit the impl's visibility --
+        // we don't want to show `pub`.
+        if impl_ref.is_some() {
+            what_rustc_thinks.visibility = Inherited;
+        }
 
-            what_rustc_thinks
-        })
-    }
+        what_rustc_thinks
+    })
 }
 
-impl<'tcx> Clean<'tcx, Item> for ty::AssocItem {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> Item {
-        let tcx = cx.tcx;
-        let kind = match self.kind {
-            ty::AssocKind::Const => {
-                let ty = clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id));
-
-                let provided = match self.container {
-                    ty::ImplContainer => true,
-                    ty::TraitContainer => tcx.impl_defaultness(self.def_id).has_value(),
-                };
-                if provided {
-                    AssocConstItem(ty, ConstantKind::Extern { def_id: self.def_id })
-                } else {
-                    TyAssocConstItem(ty)
-                }
+pub(crate) fn clean_middle_assoc_item<'tcx>(
+    assoc_item: &ty::AssocItem,
+    cx: &mut DocContext<'tcx>,
+) -> Item {
+    let tcx = cx.tcx;
+    let kind = match assoc_item.kind {
+        ty::AssocKind::Const => {
+            let ty = clean_middle_ty(tcx.type_of(assoc_item.def_id), cx, Some(assoc_item.def_id));
+
+            let provided = match assoc_item.container {
+                ty::ImplContainer => true,
+                ty::TraitContainer => tcx.impl_defaultness(assoc_item.def_id).has_value(),
+            };
+            if provided {
+                AssocConstItem(ty, ConstantKind::Extern { def_id: assoc_item.def_id })
+            } else {
+                TyAssocConstItem(ty)
             }
-            ty::AssocKind::Fn => {
-                let generics = clean_ty_generics(
-                    cx,
-                    tcx.generics_of(self.def_id),
-                    tcx.explicit_predicates_of(self.def_id),
-                );
-                let sig = tcx.fn_sig(self.def_id);
-                let mut decl = clean_fn_decl_from_did_and_sig(cx, Some(self.def_id), sig);
-
-                if self.fn_has_self_parameter {
-                    let self_ty = match self.container {
-                        ty::ImplContainer => tcx.type_of(self.container_id(tcx)),
-                        ty::TraitContainer => tcx.types.self_param,
-                    };
-                    let self_arg_ty = sig.input(0).skip_binder();
-                    if self_arg_ty == self_ty {
-                        decl.inputs.values[0].type_ = Generic(kw::SelfUpper);
-                    } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
-                        if ty == self_ty {
-                            match decl.inputs.values[0].type_ {
-                                BorrowedRef { ref mut type_, .. } => {
-                                    **type_ = Generic(kw::SelfUpper)
-                                }
-                                _ => unreachable!(),
-                            }
+        }
+        ty::AssocKind::Fn => {
+            let generics = clean_ty_generics(
+                cx,
+                tcx.generics_of(assoc_item.def_id),
+                tcx.explicit_predicates_of(assoc_item.def_id),
+            );
+            let sig = tcx.fn_sig(assoc_item.def_id);
+            let mut decl = clean_fn_decl_from_did_and_sig(cx, Some(assoc_item.def_id), sig);
+
+            if assoc_item.fn_has_self_parameter {
+                let self_ty = match assoc_item.container {
+                    ty::ImplContainer => tcx.type_of(assoc_item.container_id(tcx)),
+                    ty::TraitContainer => tcx.types.self_param,
+                };
+                let self_arg_ty = sig.input(0).skip_binder();
+                if self_arg_ty == self_ty {
+                    decl.inputs.values[0].type_ = Generic(kw::SelfUpper);
+                } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() {
+                    if ty == self_ty {
+                        match decl.inputs.values[0].type_ {
+                            BorrowedRef { ref mut type_, .. } => **type_ = Generic(kw::SelfUpper),
+                            _ => unreachable!(),
                         }
                     }
                 }
+            }
 
-                let provided = match self.container {
-                    ty::ImplContainer => true,
-                    ty::TraitContainer => self.defaultness(tcx).has_value(),
+            let provided = match assoc_item.container {
+                ty::ImplContainer => true,
+                ty::TraitContainer => assoc_item.defaultness(tcx).has_value(),
+            };
+            if provided {
+                let defaultness = match assoc_item.container {
+                    ty::ImplContainer => Some(assoc_item.defaultness(tcx)),
+                    ty::TraitContainer => None,
                 };
-                if provided {
-                    let defaultness = match self.container {
-                        ty::ImplContainer => Some(self.defaultness(tcx)),
-                        ty::TraitContainer => None,
-                    };
-                    MethodItem(Box::new(Function { generics, decl }), defaultness)
-                } else {
-                    TyMethodItem(Box::new(Function { generics, decl }))
-                }
+                MethodItem(Box::new(Function { generics, decl }), defaultness)
+            } else {
+                TyMethodItem(Box::new(Function { generics, decl }))
             }
-            ty::AssocKind::Type => {
-                let my_name = self.name;
-
-                fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
-                    match (&param.kind, arg) {
-                        (GenericParamDefKind::Type { .. }, GenericArg::Type(Type::Generic(ty)))
-                            if *ty == param.name =>
-                        {
-                            true
-                        }
-                        (
-                            GenericParamDefKind::Lifetime { .. },
-                            GenericArg::Lifetime(Lifetime(lt)),
-                        ) if *lt == param.name => true,
-                        (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => {
-                            match &c.kind {
-                                ConstantKind::TyConst { expr } => expr == param.name.as_str(),
-                                _ => false,
-                            }
-                        }
-                        _ => false,
+        }
+        ty::AssocKind::Type => {
+            let my_name = assoc_item.name;
+
+            fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
+                match (&param.kind, arg) {
+                    (GenericParamDefKind::Type { .. }, GenericArg::Type(Type::Generic(ty)))
+                        if *ty == param.name =>
+                    {
+                        true
+                    }
+                    (GenericParamDefKind::Lifetime { .. }, GenericArg::Lifetime(Lifetime(lt)))
+                        if *lt == param.name =>
+                    {
+                        true
                     }
+                    (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => match &c.kind {
+                        ConstantKind::TyConst { expr } => expr == param.name.as_str(),
+                        _ => false,
+                    },
+                    _ => false,
                 }
+            }
 
-                if let ty::TraitContainer = self.container {
-                    let bounds = tcx.explicit_item_bounds(self.def_id);
-                    let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
-                    let mut generics =
-                        clean_ty_generics(cx, tcx.generics_of(self.def_id), predicates);
-                    // Filter out the bounds that are (likely?) directly attached to the associated type,
-                    // as opposed to being located in the where clause.
-                    let mut bounds = generics
-                        .where_predicates
-                        .drain_filter(|pred| match *pred {
-                            WherePredicate::BoundPredicate {
-                                ty: QPath { ref assoc, ref self_type, ref trait_, .. },
-                                ..
-                            } => {
-                                if assoc.name != my_name {
-                                    return false;
-                                }
-                                if trait_.def_id() != self.container_id(tcx) {
-                                    return false;
-                                }
-                                match **self_type {
-                                    Generic(ref s) if *s == kw::SelfUpper => {}
-                                    _ => return false,
-                                }
-                                match &assoc.args {
-                                    GenericArgs::AngleBracketed { args, bindings } => {
-                                        if !bindings.is_empty()
-                                            || generics
-                                                .params
-                                                .iter()
-                                                .zip(args.iter())
-                                                .any(|(param, arg)| !param_eq_arg(param, arg))
-                                        {
-                                            return false;
-                                        }
-                                    }
-                                    GenericArgs::Parenthesized { .. } => {
-                                        // The only time this happens is if we're inside the rustdoc for Fn(),
-                                        // which only has one associated type, which is not a GAT, so whatever.
+            if let ty::TraitContainer = assoc_item.container {
+                let bounds = tcx.explicit_item_bounds(assoc_item.def_id);
+                let predicates = ty::GenericPredicates { parent: None, predicates: bounds };
+                let mut generics =
+                    clean_ty_generics(cx, tcx.generics_of(assoc_item.def_id), predicates);
+                // Filter out the bounds that are (likely?) directly attached to the associated type,
+                // as opposed to being located in the where clause.
+                let mut bounds = generics
+                    .where_predicates
+                    .drain_filter(|pred| match *pred {
+                        WherePredicate::BoundPredicate {
+                            ty: QPath { ref assoc, ref self_type, ref trait_, .. },
+                            ..
+                        } => {
+                            if assoc.name != my_name {
+                                return false;
+                            }
+                            if trait_.def_id() != assoc_item.container_id(tcx) {
+                                return false;
+                            }
+                            match **self_type {
+                                Generic(ref s) if *s == kw::SelfUpper => {}
+                                _ => return false,
+                            }
+                            match &assoc.args {
+                                GenericArgs::AngleBracketed { args, bindings } => {
+                                    if !bindings.is_empty()
+                                        || generics
+                                            .params
+                                            .iter()
+                                            .zip(args.iter())
+                                            .any(|(param, arg)| !param_eq_arg(param, arg))
+                                    {
+                                        return false;
                                     }
                                 }
-                                true
-                            }
-                            _ => false,
-                        })
-                        .flat_map(|pred| {
-                            if let WherePredicate::BoundPredicate { bounds, .. } = pred {
-                                bounds
-                            } else {
-                                unreachable!()
+                                GenericArgs::Parenthesized { .. } => {
+                                    // The only time this happens is if we're inside the rustdoc for Fn(),
+                                    // which only has one associated type, which is not a GAT, so whatever.
+                                }
                             }
-                        })
-                        .collect::<Vec<_>>();
-                    // Our Sized/?Sized bound didn't get handled when creating the generics
-                    // because we didn't actually get our whole set of bounds until just now
-                    // (some of them may have come from the trait). If we do have a sized
-                    // bound, we remove it, and if we don't then we add the `?Sized` bound
-                    // at the end.
-                    match bounds.iter().position(|b| b.is_sized_bound(cx)) {
-                        Some(i) => {
-                            bounds.remove(i);
+                            true
+                        }
+                        _ => false,
+                    })
+                    .flat_map(|pred| {
+                        if let WherePredicate::BoundPredicate { bounds, .. } = pred {
+                            bounds
+                        } else {
+                            unreachable!()
                         }
-                        None => bounds.push(GenericBound::maybe_sized(cx)),
+                    })
+                    .collect::<Vec<_>>();
+                // Our Sized/?Sized bound didn't get handled when creating the generics
+                // because we didn't actually get our whole set of bounds until just now
+                // (some of them may have come from the trait). If we do have a sized
+                // bound, we remove it, and if we don't then we add the `?Sized` bound
+                // at the end.
+                match bounds.iter().position(|b| b.is_sized_bound(cx)) {
+                    Some(i) => {
+                        bounds.remove(i);
                     }
+                    None => bounds.push(GenericBound::maybe_sized(cx)),
+                }
 
-                    if tcx.impl_defaultness(self.def_id).has_value() {
-                        AssocTypeItem(
-                            Box::new(Typedef {
-                                type_: clean_middle_ty(
-                                    tcx.type_of(self.def_id),
-                                    cx,
-                                    Some(self.def_id),
-                                ),
-                                generics,
-                                // FIXME: should we obtain the Type from HIR and pass it on here?
-                                item_type: None,
-                            }),
-                            bounds,
-                        )
-                    } else {
-                        TyAssocTypeItem(Box::new(generics), bounds)
-                    }
-                } else {
-                    // FIXME: when could this happen? Associated items in inherent impls?
+                if tcx.impl_defaultness(assoc_item.def_id).has_value() {
                     AssocTypeItem(
                         Box::new(Typedef {
-                            type_: clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id)),
-                            generics: Generics { params: Vec::new(), where_predicates: Vec::new() },
+                            type_: clean_middle_ty(
+                                tcx.type_of(assoc_item.def_id),
+                                cx,
+                                Some(assoc_item.def_id),
+                            ),
+                            generics,
+                            // FIXME: should we obtain the Type from HIR and pass it on here?
                             item_type: None,
                         }),
-                        Vec::new(),
+                        bounds,
                     )
+                } else {
+                    TyAssocTypeItem(Box::new(generics), bounds)
                 }
+            } else {
+                // FIXME: when could this happen? Associated items in inherent impls?
+                AssocTypeItem(
+                    Box::new(Typedef {
+                        type_: clean_middle_ty(
+                            tcx.type_of(assoc_item.def_id),
+                            cx,
+                            Some(assoc_item.def_id),
+                        ),
+                        generics: Generics { params: Vec::new(), where_predicates: Vec::new() },
+                        item_type: None,
+                    }),
+                    Vec::new(),
+                )
             }
-        };
+        }
+    };
 
-        let mut what_rustc_thinks =
-            Item::from_def_id_and_parts(self.def_id, Some(self.name), kind, cx);
+    let mut what_rustc_thinks =
+        Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx);
 
-        let impl_ref = tcx.impl_trait_ref(tcx.parent(self.def_id));
+    let impl_ref = tcx.impl_trait_ref(tcx.parent(assoc_item.def_id));
 
-        // Trait impl items always inherit the impl's visibility --
-        // we don't want to show `pub`.
-        if impl_ref.is_some() {
-            what_rustc_thinks.visibility = Visibility::Inherited;
-        }
-
-        what_rustc_thinks
+    // Trait impl items always inherit the impl's visibility --
+    // we don't want to show `pub`.
+    if impl_ref.is_some() {
+        what_rustc_thinks.visibility = Visibility::Inherited;
     }
+
+    what_rustc_thinks
 }
 
 fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
@@ -1831,39 +1826,44 @@ fn clean_path<'tcx>(path: &hir::Path<'tcx>, cx: &mut DocContext<'tcx>) -> Path {
     Path { res: path.res, segments: path.segments.iter().map(|x| x.clean(cx)).collect() }
 }
 
-impl<'tcx> Clean<'tcx, GenericArgs> for hir::GenericArgs<'tcx> {
-    fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericArgs {
-        if self.parenthesized {
-            let output = clean_ty(self.bindings[0].ty(), cx);
-            let output =
-                if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None };
-            let inputs = self.inputs().iter().map(|x| clean_ty(x, cx)).collect::<Vec<_>>().into();
-            GenericArgs::Parenthesized { inputs, output }
-        } else {
-            let args = self
-                .args
-                .iter()
-                .map(|arg| match arg {
-                    hir::GenericArg::Lifetime(lt) if !lt.is_elided() => {
-                        GenericArg::Lifetime(clean_lifetime(*lt, cx))
-                    }
-                    hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
-                    hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)),
-                    hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))),
-                    hir::GenericArg::Infer(_inf) => GenericArg::Infer,
-                })
-                .collect::<Vec<_>>()
-                .into();
-            let bindings =
-                self.bindings.iter().map(|x| clean_type_binding(x, cx)).collect::<Vec<_>>().into();
-            GenericArgs::AngleBracketed { args, bindings }
-        }
+fn clean_generic_args<'tcx>(
+    generic_args: &hir::GenericArgs<'tcx>,
+    cx: &mut DocContext<'tcx>,
+) -> GenericArgs {
+    if generic_args.parenthesized {
+        let output = clean_ty(generic_args.bindings[0].ty(), cx);
+        let output = if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None };
+        let inputs =
+            generic_args.inputs().iter().map(|x| clean_ty(x, cx)).collect::<Vec<_>>().into();
+        GenericArgs::Parenthesized { inputs, output }
+    } else {
+        let args = generic_args
+            .args
+            .iter()
+            .map(|arg| match arg {
+                hir::GenericArg::Lifetime(lt) if !lt.is_elided() => {
+                    GenericArg::Lifetime(clean_lifetime(*lt, cx))
+                }
+                hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
+                hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)),
+                hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))),
+                hir::GenericArg::Infer(_inf) => GenericArg::Infer,
+            })
+            .collect::<Vec<_>>()
+            .into();
+        let bindings = generic_args
+            .bindings
+            .iter()
+            .map(|x| clean_type_binding(x, cx))
+            .collect::<Vec<_>>()
+            .into();
+        GenericArgs::AngleBracketed { args, bindings }
     }
 }
 
 impl<'tcx> Clean<'tcx, PathSegment> for hir::PathSegment<'tcx> {
     fn clean(&self, cx: &mut DocContext<'tcx>) -> PathSegment {
-        PathSegment { name: self.ident.name, args: self.args().clean(cx) }
+        PathSegment { name: self.ident.name, args: clean_generic_args(self.args(), cx) }
     }
 }
 
@@ -1905,32 +1905,32 @@ fn clean_maybe_renamed_item<'tcx>(
             }),
             ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy {
                 bounds: ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
-                generics: ty.generics.clean(cx),
+                generics: clean_generics(ty.generics, cx),
             }),
             ItemKind::TyAlias(hir_ty, generics) => {
                 let rustdoc_ty = clean_ty(hir_ty, cx);
                 let ty = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None);
                 TypedefItem(Box::new(Typedef {
                     type_: rustdoc_ty,
-                    generics: generics.clean(cx),
+                    generics: clean_generics(generics, cx),
                     item_type: Some(ty),
                 }))
             }
             ItemKind::Enum(ref def, generics) => EnumItem(Enum {
                 variants: def.variants.iter().map(|v| v.clean(cx)).collect(),
-                generics: generics.clean(cx),
+                generics: clean_generics(generics, cx),
             }),
             ItemKind::TraitAlias(generics, bounds) => TraitAliasItem(TraitAlias {
-                generics: generics.clean(cx),
+                generics: clean_generics(generics, cx),
                 bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
             }),
             ItemKind::Union(ref variant_data, generics) => UnionItem(Union {
-                generics: generics.clean(cx),
+                generics: clean_generics(generics, cx),
                 fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
             }),
             ItemKind::Struct(ref variant_data, generics) => StructItem(Struct {
                 struct_type: CtorKind::from_hir(variant_data),
-                generics: generics.clean(cx),
+                generics: clean_generics(generics, cx),
                 fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
             }),
             ItemKind::Impl(impl_) => return clean_impl(impl_, item.hir_id(), cx),
@@ -1953,7 +1953,7 @@ fn clean_maybe_renamed_item<'tcx>(
                 TraitItem(Trait {
                     def_id,
                     items,
-                    generics: generics.clean(cx),
+                    generics: clean_generics(generics, cx),
                     bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(),
                 })
             }
@@ -1988,8 +1988,11 @@ fn clean_impl<'tcx>(
     let tcx = cx.tcx;
     let mut ret = Vec::new();
     let trait_ = impl_.of_trait.as_ref().map(|t| clean_trait_ref(t, cx));
-    let items =
-        impl_.items.iter().map(|ii| tcx.hir().impl_item(ii.id).clean(cx)).collect::<Vec<_>>();
+    let items = impl_
+        .items
+        .iter()
+        .map(|ii| clean_impl_item(tcx.hir().impl_item(ii.id), cx))
+        .collect::<Vec<_>>();
     let def_id = tcx.hir().local_def_id(hir_id);
 
     // If this impl block is an implementation of the Deref trait, then we
@@ -2006,7 +2009,7 @@ fn clean_impl<'tcx>(
     let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| {
         let kind = ImplItem(Box::new(Impl {
             unsafety: impl_.unsafety,
-            generics: impl_.generics.clean(cx),
+            generics: clean_generics(impl_.generics, cx),
             trait_,
             for_,
             items,
@@ -2203,7 +2206,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
             hir::ForeignItemKind::Fn(decl, names, generics) => {
                 let (generics, decl) = enter_impl_trait(cx, |cx| {
                     // NOTE: generics must be cleaned before args
-                    let generics = generics.clean(cx);
+                    let generics = clean_generics(generics, cx);
                     let args = clean_args_from_types_and_names(cx, decl.inputs, names);
                     let decl = clean_fn_decl_with_args(cx, decl, args);
                     (generics, decl)
@@ -2230,7 +2233,10 @@ fn clean_type_binding<'tcx>(
     cx: &mut DocContext<'tcx>,
 ) -> TypeBinding {
     TypeBinding {
-        assoc: PathSegment { name: type_binding.ident.name, args: type_binding.gen_args.clean(cx) },
+        assoc: PathSegment {
+            name: type_binding.ident.name,
+            args: clean_generic_args(type_binding.gen_args, cx),
+        },
         kind: match type_binding.kind {
             hir::TypeBindingKind::Equality { ref term } => {
                 TypeBindingKind::Equality { term: clean_hir_term(term, cx) }
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 0e6de842cc2..91d5758077c 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -2495,14 +2495,15 @@ impl SubstParam {
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
 mod size_asserts {
     use super::*;
+    use rustc_data_structures::static_assert_size;
     // These are in alphabetical order, which is easy to maintain.
-    rustc_data_structures::static_assert_size!(Crate, 72); // frequently moved by-value
-    rustc_data_structures::static_assert_size!(DocFragment, 32);
-    rustc_data_structures::static_assert_size!(GenericArg, 80);
-    rustc_data_structures::static_assert_size!(GenericArgs, 32);
-    rustc_data_structures::static_assert_size!(GenericParamDef, 56);
-    rustc_data_structures::static_assert_size!(Item, 56);
-    rustc_data_structures::static_assert_size!(ItemKind, 112);
-    rustc_data_structures::static_assert_size!(PathSegment, 40);
-    rustc_data_structures::static_assert_size!(Type, 72);
+    static_assert_size!(Crate, 72); // frequently moved by-value
+    static_assert_size!(DocFragment, 32);
+    static_assert_size!(GenericArg, 80);
+    static_assert_size!(GenericArgs, 32);
+    static_assert_size!(GenericParamDef, 56);
+    static_assert_size!(Item, 56);
+    static_assert_size!(ItemKind, 112);
+    static_assert_size!(PathSegment, 40);
+    static_assert_size!(Type, 72);
 }
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 43e71e90a6f..718cbbd2b83 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -2,9 +2,9 @@ use crate::clean::auto_trait::AutoTraitFinder;
 use crate::clean::blanket_impl::BlanketImplFinder;
 use crate::clean::render_macro_matchers::render_macro_matcher;
 use crate::clean::{
-    clean_middle_const, clean_middle_region, clean_middle_ty, inline, Clean, Crate, ExternalCrate,
-    Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime, Path, PathSegment,
-    Primitive, PrimitiveType, Type, TypeBinding, Visibility,
+    clean_doc_module, clean_middle_const, clean_middle_region, clean_middle_ty, inline, Crate,
+    ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime, Path,
+    PathSegment, Primitive, PrimitiveType, Type, TypeBinding, Visibility,
 };
 use crate::core::DocContext;
 use crate::formats::item_type::ItemType;
@@ -37,7 +37,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
 
     // Clean the crate, translating the entire librustc_ast AST to one that is
     // understood by rustdoc.
-    let mut module = module.clean(cx);
+    let mut module = clean_doc_module(&module, cx);
 
     match *module.kind {
         ItemKind::ModuleItem(ref module) => {
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 35964e3ba38..20ae102bc27 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -1289,14 +1289,9 @@ impl<'a, 'hir, 'tcx> intravisit::Visitor<'hir> for HirCollector<'a, 'hir, 'tcx>
         });
     }
 
-    fn visit_variant(
-        &mut self,
-        v: &'hir hir::Variant<'_>,
-        g: &'hir hir::Generics<'_>,
-        item_id: hir::HirId,
-    ) {
+    fn visit_variant(&mut self, v: &'hir hir::Variant<'_>) {
         self.visit_testable(v.ident.to_string(), v.id, v.span, |this| {
-            intravisit::walk_variant(this, v, g, item_id);
+            intravisit::walk_variant(this, v);
         });
     }
 
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 36a47b05cb9..3dee4d1acc8 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -152,7 +152,7 @@ impl Buffer {
     }
 }
 
-fn comma_sep<T: fmt::Display>(
+pub(crate) fn comma_sep<T: fmt::Display>(
     items: impl Iterator<Item = T>,
     space_after_comma: bool,
 ) -> impl fmt::Display {
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 05547ea1515..5a6720a8dd9 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -33,27 +33,39 @@ pub(crate) struct HrefContext<'a, 'b, 'c> {
 
 /// Decorations are represented as a map from CSS class to vector of character ranges.
 /// Each range will be wrapped in a span with that class.
+#[derive(Default)]
 pub(crate) struct DecorationInfo(pub(crate) FxHashMap<&'static str, Vec<(u32, u32)>>);
 
-/// Highlights `src`, returning the HTML output.
-pub(crate) fn render_with_highlighting(
+#[derive(Eq, PartialEq, Clone, Copy)]
+pub(crate) enum Tooltip {
+    Ignore,
+    CompileFail,
+    ShouldPanic,
+    Edition(Edition),
+    None,
+}
+
+/// Highlights `src` as an inline example, returning the HTML output.
+pub(crate) fn render_example_with_highlighting(
     src: &str,
     out: &mut Buffer,
-    class: Option<&str>,
+    tooltip: Tooltip,
     playground_button: Option<&str>,
-    tooltip: Option<(Option<Edition>, &str)>,
-    edition: Edition,
-    extra_content: Option<Buffer>,
-    href_context: Option<HrefContext<'_, '_, '_>>,
-    decoration_info: Option<DecorationInfo>,
 ) {
-    debug!("highlighting: ================\n{}\n==============", src);
-    if let Some((edition_info, class)) = tooltip {
+    let class = match tooltip {
+        Tooltip::Ignore => " ignore",
+        Tooltip::CompileFail => " compile_fail",
+        Tooltip::ShouldPanic => " should_panic",
+        Tooltip::Edition(_) => " edition",
+        Tooltip::None => "",
+    };
+
+    if tooltip != Tooltip::None {
         write!(
             out,
-            "<div class='information'><div class='tooltip {}'{}>ⓘ</div></div>",
+            "<div class='information'><div class='tooltip{}'{}>ⓘ</div></div>",
             class,
-            if let Some(edition_info) = edition_info {
+            if let Tooltip::Edition(edition_info) = tooltip {
                 format!(" data-edition=\"{}\"", edition_info)
             } else {
                 String::new()
@@ -61,20 +73,40 @@ pub(crate) fn render_with_highlighting(
         );
     }
 
-    write_header(out, class, extra_content);
-    write_code(out, src, edition, href_context, decoration_info);
+    write_header(out, &format!("rust-example-rendered{}", class), None);
+    write_code(out, src, None, None);
     write_footer(out, playground_button);
 }
 
-fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buffer>) {
+/// Highlights `src` as a macro, returning the HTML output.
+pub(crate) fn render_macro_with_highlighting(src: &str, out: &mut Buffer) {
+    write_header(out, "macro", None);
+    write_code(out, src, None, None);
+    write_footer(out, None);
+}
+
+/// Highlights `src` as a source code page, returning the HTML output.
+pub(crate) fn render_source_with_highlighting(
+    src: &str,
+    out: &mut Buffer,
+    line_numbers: Buffer,
+    href_context: HrefContext<'_, '_, '_>,
+    decoration_info: DecorationInfo,
+) {
+    write_header(out, "", Some(line_numbers));
+    write_code(out, src, Some(href_context), Some(decoration_info));
+    write_footer(out, None);
+}
+
+fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>) {
     write!(out, "<div class=\"example-wrap\">");
     if let Some(extra) = extra_content {
         out.push_buffer(extra);
     }
-    if let Some(class) = class {
-        write!(out, "<pre class=\"rust {}\">", class);
-    } else {
+    if class.is_empty() {
         write!(out, "<pre class=\"rust\">");
+    } else {
+        write!(out, "<pre class=\"rust {}\">", class);
     }
     write!(out, "<code>");
 }
@@ -93,7 +125,6 @@ fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buf
 fn write_code(
     out: &mut Buffer,
     src: &str,
-    edition: Edition,
     href_context: Option<HrefContext<'_, '_, '_>>,
     decoration_info: Option<DecorationInfo>,
 ) {
@@ -102,7 +133,6 @@ fn write_code(
     let mut closing_tags: Vec<&'static str> = Vec::new();
     Classifier::new(
         &src,
-        edition,
         href_context.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP),
         decoration_info,
     )
@@ -220,7 +250,7 @@ impl<'a> Iterator for TokenIter<'a> {
 }
 
 /// Classifies into identifier class; returns `None` if this is a non-keyword identifier.
-fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool) -> Option<Class> {
+fn get_real_ident_class(text: &str, allow_path_keywords: bool) -> Option<Class> {
     let ignore: &[&str] =
         if allow_path_keywords { &["self", "Self", "super", "crate"] } else { &["self", "Self"] };
     if ignore.iter().any(|k| *k == text) {
@@ -229,7 +259,7 @@ fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool)
     Some(match text {
         "ref" | "mut" => Class::RefKeyWord,
         "false" | "true" => Class::Bool,
-        _ if Symbol::intern(text).is_reserved(|| edition) => Class::KeyWord,
+        _ if Symbol::intern(text).is_reserved(|| Edition::Edition2021) => Class::KeyWord,
         _ => return None,
     })
 }
@@ -311,7 +341,6 @@ struct Classifier<'a> {
     in_attribute: bool,
     in_macro: bool,
     in_macro_nonterminal: bool,
-    edition: Edition,
     byte_pos: u32,
     file_span: Span,
     src: &'a str,
@@ -321,12 +350,7 @@ struct Classifier<'a> {
 impl<'a> Classifier<'a> {
     /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code
     /// file span which will be used later on by the `span_correspondance_map`.
-    fn new(
-        src: &str,
-        edition: Edition,
-        file_span: Span,
-        decoration_info: Option<DecorationInfo>,
-    ) -> Classifier<'_> {
+    fn new(src: &str, file_span: Span, decoration_info: Option<DecorationInfo>) -> Classifier<'_> {
         let tokens = PeekIter::new(TokenIter { src });
         let decorations = decoration_info.map(Decorations::new);
         Classifier {
@@ -334,7 +358,6 @@ impl<'a> Classifier<'a> {
             in_attribute: false,
             in_macro: false,
             in_macro_nonterminal: false,
-            edition,
             byte_pos: 0,
             file_span,
             src,
@@ -354,7 +377,6 @@ impl<'a> Classifier<'a> {
         let start = self.byte_pos as usize;
         let mut pos = start;
         let mut has_ident = false;
-        let edition = self.edition;
 
         loop {
             let mut nb = 0;
@@ -376,7 +398,7 @@ impl<'a> Classifier<'a> {
 
             if let Some((None, text)) = self.tokens.peek().map(|(token, text)| {
                 if *token == TokenKind::Ident {
-                    let class = get_real_ident_class(text, edition, true);
+                    let class = get_real_ident_class(text, true);
                     (class, text)
                 } else {
                     // Doesn't matter which Class we put in here...
@@ -634,7 +656,7 @@ impl<'a> Classifier<'a> {
                 sink(Highlight::Token { text, class: None });
                 return;
             }
-            TokenKind::Ident => match get_real_ident_class(text, self.edition, false) {
+            TokenKind::Ident => match get_real_ident_class(text, false) {
                 None => match text {
                     "Option" | "Result" => Class::PreludeTy,
                     "Some" | "None" | "Ok" | "Err" => Class::PreludeVal,
diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs
index 1fea7e983b4..4861a8ad32d 100644
--- a/src/librustdoc/html/highlight/tests.rs
+++ b/src/librustdoc/html/highlight/tests.rs
@@ -3,7 +3,6 @@ use crate::html::format::Buffer;
 use expect_test::expect_file;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_span::create_default_session_globals_then;
-use rustc_span::edition::Edition;
 
 const STYLE: &str = r#"
 <style>
@@ -23,7 +22,7 @@ fn test_html_highlighting() {
         let src = include_str!("fixtures/sample.rs");
         let html = {
             let mut out = Buffer::new();
-            write_code(&mut out, src, Edition::Edition2018, None, None);
+            write_code(&mut out, src, None, None);
             format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner())
         };
         expect_file!["fixtures/sample.html"].assert_eq(&html);
@@ -37,7 +36,7 @@ fn test_dos_backline() {
     println!(\"foo\");\r\n\
 }\r\n";
         let mut html = Buffer::new();
-        write_code(&mut html, src, Edition::Edition2018, None, None);
+        write_code(&mut html, src, None, None);
         expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner());
     });
 }
@@ -51,7 +50,7 @@ let x = super::b::foo;
 let y = Self::whatever;";
 
         let mut html = Buffer::new();
-        write_code(&mut html, src, Edition::Edition2018, None, None);
+        write_code(&mut html, src, None, None);
         expect_file!["fixtures/highlight.html"].assert_eq(&html.into_inner());
     });
 }
@@ -61,7 +60,7 @@ fn test_union_highlighting() {
     create_default_session_globals_then(|| {
         let src = include_str!("fixtures/union.rs");
         let mut html = Buffer::new();
-        write_code(&mut html, src, Edition::Edition2018, None, None);
+        write_code(&mut html, src, None, None);
         expect_file!["fixtures/union.html"].assert_eq(&html.into_inner());
     });
 }
@@ -75,7 +74,7 @@ let y = 2;";
         decorations.insert("example", vec![(0, 10)]);
 
         let mut html = Buffer::new();
-        write_code(&mut html, src, Edition::Edition2018, None, Some(DecorationInfo(decorations)));
+        write_code(&mut html, src, None, Some(DecorationInfo(decorations)));
         expect_file!["fixtures/decorations.html"].assert_eq(&html.into_inner());
     });
 }
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 52a2effca0f..ec2e129c364 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -330,34 +330,27 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
         });
 
         let tooltip = if ignore != Ignore::None {
-            Some((None, "ignore"))
+            highlight::Tooltip::Ignore
         } else if compile_fail {
-            Some((None, "compile_fail"))
+            highlight::Tooltip::CompileFail
         } else if should_panic {
-            Some((None, "should_panic"))
+            highlight::Tooltip::ShouldPanic
         } else if explicit_edition {
-            Some((Some(edition), "edition"))
+            highlight::Tooltip::Edition(edition)
         } else {
-            None
+            highlight::Tooltip::None
         };
 
         // insert newline to clearly separate it from the
         // previous block so we can shorten the html output
         let mut s = Buffer::new();
         s.push_str("\n");
-        highlight::render_with_highlighting(
+
+        highlight::render_example_with_highlighting(
             &text,
             &mut s,
-            Some(&format!(
-                "rust-example-rendered{}",
-                if let Some((_, class)) = tooltip { format!(" {}", class) } else { String::new() }
-            )),
-            playground_button.as_deref(),
             tooltip,
-            edition,
-            None,
-            None,
-            None,
+            playground_button.as_deref(),
         );
         Some(Event::Html(s.into_inner().into()))
     }
@@ -1446,6 +1439,8 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
     map.insert("not-displayed".into(), 1);
     map.insert("alternative-display".into(), 1);
     map.insert("search".into(), 1);
+    map.insert("crate-search".into(), 1);
+    map.insert("crate-search-div".into(), 1);
     // This is the list of IDs used in HTML generated in Rust (including the ones
     // used in tera template files).
     map.insert("mainThemeStyle".into(), 1);
@@ -1453,7 +1448,6 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
     map.insert("settings-menu".into(), 1);
     map.insert("help-button".into(), 1);
     map.insert("main-content".into(), 1);
-    map.insert("crate-search".into(), 1);
     map.insert("toggle-all-docs".into(), 1);
     map.insert("all-types".into(), 1);
     map.insert("default-settings".into(), 1);
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index ae7d8c108d3..09c54969ef1 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -2773,11 +2773,10 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite
         sources::print_src(
             w,
             contents_subset,
-            call_data.edition,
             file_span,
             cx,
             &root_path,
-            Some(highlight::DecorationInfo(decoration_info)),
+            highlight::DecorationInfo(decoration_info),
             sources::SourceContext::Embedded { offset: line_min },
         );
         write!(w, "</div></div>");
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 99cf4291927..6d0a825fec8 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1322,17 +1322,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
 
 fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Macro) {
     wrap_into_docblock(w, |w| {
-        highlight::render_with_highlighting(
-            &t.source,
-            w,
-            Some("macro"),
-            None,
-            None,
-            it.span(cx.tcx()).inner().edition(),
-            None,
-            None,
-            None,
-        );
+        highlight::render_macro_with_highlighting(&t.source, w);
     });
     document(w, cx, it, None, HeadingOffset::H2)
 }
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index 6fb41ff3279..f9abb46207d 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -1,5 +1,4 @@
 use std::ffi::OsStr;
-use std::fmt::Write;
 use std::fs::{self, File};
 use std::io::prelude::*;
 use std::io::{self, BufReader};
@@ -10,7 +9,8 @@ use std::sync::LazyLock as Lazy;
 use itertools::Itertools;
 use rustc_data_structures::flock;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use serde::Serialize;
+use serde::ser::SerializeSeq;
+use serde::{Serialize, Serializer};
 
 use super::{collect_paths_for_type, ensure_trailing_slash, Context, BASIC_KEYWORDS};
 use crate::clean::Crate;
@@ -284,25 +284,43 @@ pub(super) fn write_shared(
         cx.write_shared(SharedResource::Unversioned { name }, contents, &options.emit)?;
     }
 
-    fn collect(path: &Path, krate: &str, key: &str) -> io::Result<(Vec<String>, Vec<String>)> {
+    /// Read a file and return all lines that match the `"{crate}":{data},` format,
+    /// and return a tuple `(Vec<DataString>, Vec<CrateNameString>)`.
+    ///
+    /// This forms the payload of files that look like this:
+    ///
+    /// ```javascript
+    /// var data = {
+    /// "{crate1}":{data},
+    /// "{crate2}":{data}
+    /// };
+    /// use_data(data);
+    /// ```
+    ///
+    /// The file needs to be formatted so that *only crate data lines start with `"`*.
+    fn collect(path: &Path, krate: &str) -> io::Result<(Vec<String>, Vec<String>)> {
         let mut ret = Vec::new();
         let mut krates = Vec::new();
 
         if path.exists() {
-            let prefix = format!(r#"{}["{}"]"#, key, krate);
+            let prefix = format!("\"{}\"", krate);
             for line in BufReader::new(File::open(path)?).lines() {
                 let line = line?;
-                if !line.starts_with(key) {
+                if !line.starts_with('"') {
                     continue;
                 }
                 if line.starts_with(&prefix) {
                     continue;
                 }
-                ret.push(line.to_string());
+                if line.ends_with(",") {
+                    ret.push(line[..line.len() - 1].to_string());
+                } else {
+                    // No comma (it's the case for the last added crate line)
+                    ret.push(line.to_string());
+                }
                 krates.push(
-                    line[key.len() + 2..]
-                        .split('"')
-                        .next()
+                    line.split('"')
+                        .find(|s| !s.is_empty())
                         .map(|s| s.to_owned())
                         .unwrap_or_else(String::new),
                 );
@@ -311,6 +329,20 @@ pub(super) fn write_shared(
         Ok((ret, krates))
     }
 
+    /// Read a file and return all lines that match the <code>"{crate}":{data},\</code> format,
+    /// and return a tuple `(Vec<DataString>, Vec<CrateNameString>)`.
+    ///
+    /// This forms the payload of files that look like this:
+    ///
+    /// ```javascript
+    /// var data = JSON.parse('{\
+    /// "{crate1}":{data},\
+    /// "{crate2}":{data}\
+    /// }');
+    /// use_data(data);
+    /// ```
+    ///
+    /// The file needs to be formatted so that *only crate data lines start with `"`*.
     fn collect_json(path: &Path, krate: &str) -> io::Result<(Vec<String>, Vec<String>)> {
         let mut ret = Vec::new();
         let mut krates = Vec::new();
@@ -526,13 +558,27 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex};
             },
         };
 
-        #[derive(Serialize)]
         struct Implementor {
             text: String,
             synthetic: bool,
             types: Vec<String>,
         }
 
+        impl Serialize for Implementor {
+            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+            where
+                S: Serializer,
+            {
+                let mut seq = serializer.serialize_seq(None)?;
+                seq.serialize_element(&self.text)?;
+                if self.synthetic {
+                    seq.serialize_element(&1)?;
+                    seq.serialize_element(&self.types)?;
+                }
+                seq.end()
+            }
+        }
+
         let implementors = imps
             .iter()
             .filter_map(|imp| {
@@ -563,9 +609,9 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex};
         }
 
         let implementors = format!(
-            r#"implementors["{}"] = {};"#,
+            r#""{}":{}"#,
             krate.name(cx.tcx()),
-            serde_json::to_string(&implementors).unwrap()
+            serde_json::to_string(&implementors).expect("failed serde conversion"),
         );
 
         let mut mydst = dst.clone();
@@ -576,16 +622,15 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex};
         mydst.push(&format!("{}.{}.js", remote_item_type, remote_path[remote_path.len() - 1]));
 
         let (mut all_implementors, _) =
-            try_err!(collect(&mydst, krate.name(cx.tcx()).as_str(), "implementors"), &mydst);
+            try_err!(collect(&mydst, krate.name(cx.tcx()).as_str()), &mydst);
         all_implementors.push(implementors);
         // Sort the implementors by crate so the file will be generated
         // identically even with rustdoc running in parallel.
         all_implementors.sort();
 
-        let mut v = String::from("(function() {var implementors = {};\n");
-        for implementor in &all_implementors {
-            writeln!(v, "{}", *implementor).unwrap();
-        }
+        let mut v = String::from("(function() {var implementors = {\n");
+        v.push_str(&all_implementors.join(",\n"));
+        v.push_str("\n};");
         v.push_str(
             "if (window.register_implementors) {\
                  window.register_implementors(implementors);\
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index d0fd637ba88..f508808a8b6 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -11,7 +11,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
-use rustc_span::edition::Edition;
 use rustc_span::source_map::FileName;
 
 use std::ffi::OsStr;
@@ -213,11 +212,10 @@ impl SourceCollector<'_, '_> {
                 print_src(
                     buf,
                     contents,
-                    cx.shared.edition(),
                     file_span,
                     cx,
                     &root_path,
-                    None,
+                    highlight::DecorationInfo::default(),
                     SourceContext::Standalone,
                 )
             },
@@ -266,11 +264,10 @@ pub(crate) enum SourceContext {
 pub(crate) fn print_src(
     buf: &mut Buffer,
     s: &str,
-    edition: Edition,
     file_span: rustc_span::Span,
     context: &Context<'_>,
     root_path: &str,
-    decoration_info: Option<highlight::DecorationInfo>,
+    decoration_info: highlight::DecorationInfo,
     source_context: SourceContext,
 ) {
     let lines = s.lines().count();
@@ -289,15 +286,11 @@ pub(crate) fn print_src(
         }
     }
     line_numbers.write_str("</pre>");
-    highlight::render_with_highlighting(
+    highlight::render_source_with_highlighting(
         s,
         buf,
-        None,
-        None,
-        None,
-        edition,
-        Some(line_numbers),
-        Some(highlight::HrefContext { context, file_span, root_path }),
+        line_numbers,
+        highlight::HrefContext { context, file_span, root_path },
         decoration_info,
     );
 }
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 83fe14550cc..710ca3ee7c7 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -947,18 +947,33 @@ table,
 	height: 100%;
 }
 .search-results-title {
-	display: inline;
+	margin-top: 0;
+	white-space: nowrap;
+	/* flex layout allows shrinking the <select> appropriately if it becomes too large */
+	display: inline-flex;
+	max-width: 100%;
+	/* make things look like in a line, despite the fact that we're using a layout
+	with boxes (i.e. from the flex layout) */
+	align-items: baseline;
 }
-#search-settings {
-	font-size: 1.5rem;
-	font-weight: 500;
-	margin-bottom: 20px;
+#crate-search-div {
+	display: inline-block;
+	/* ensures that 100% in properties of #crate-search-div:after
+	are relative to the size of this div */
+	position: relative;
+	/* allows this div (and with it the <select>-element "#crate-search") to be shrunk */
+	min-width: 5em;
 }
 #crate-search {
 	min-width: 115px;
-	margin-top: 5px;
-	padding-left: 0.15em;
+	padding: 0;
+	/* keep these two in sync with "@-moz-document url-prefix()" below */
+	padding-left: 4px;
 	padding-right: 23px;
+	/* prevents the <select> from overflowing the containing div in case it's shrunk */
+	max-width: 100%;
+	/* contents can overflow because of max-width limit, then show ellipsis */
+	text-overflow: ellipsis;
 	border: 1px solid;
 	border-radius: 4px;
 	outline: none;
@@ -966,13 +981,37 @@ table,
 	-moz-appearance: none;
 	-webkit-appearance: none;
 	/* Removes default arrow from firefox */
+	text-indent: 0.01px;
+	background-color: var(--main-background-color);
+}
+/* cancel stylistic differences in padding in firefox
+for "appearance: none"-style (or equivalent) <select>s */
+@-moz-document url-prefix() {
+	#crate-search {
+		padding-left: 0px; /* == 4px - 4px */
+		padding-right: 19px; /* == 23px - 4px */
+	}
+}
+/* pseudo-element for holding the dropdown-arrow image; needs to be a separate thing
+so that we can apply CSS-filters to change the arrow color in themes */
+#crate-search-div::after {
+	/* lets clicks through! */
+	pointer-events: none;
+	/* completely covers the underlying div */
+	width: 100%;
+	height: 100%;
+	position: absolute;
+	top: 0;
+	left: 0;
+	content: "";
 	background-repeat: no-repeat;
-	background-color: transparent;
 	background-size: 20px;
-	background-position: calc(100% - 1px) 56%;
+	background-position: calc(100% - 2px) 56%;
+	/* image is black color, themes should apply a "filter" property to change the color */
 	background-image: /* AUTOREPLACE: */url("down-arrow.svg");
-	max-width: 100%;
-	text-overflow: ellipsis;
+}
+#crate-search > option {
+	font-size: 1rem;
 }
 .search-container {
 	margin-top: 4px;
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index c42cac59bd6..39a4dae3348 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -182,7 +182,7 @@ details.rustdoc-toggle > summary::before {
 	filter: invert(100%);
 }
 
-#crate-search, .search-input {
+.search-input {
 	background-color: #141920;
 	border-color: #424c57;
 }
@@ -191,7 +191,17 @@ details.rustdoc-toggle > summary::before {
 	/* Without the `!important`, the border-color is ignored for `<select>`...
 	   It cannot be in the group above because `.search-input` has a different border color on
 	   hover. */
-	border-color: #424c57 !important;
+	border-color: #5c6773 !important;
+}
+#crate-search-div::after {
+	/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+	filter: invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg) brightness(94%) contrast(94%);
+}
+#crate-search:hover, #crate-search:focus {
+	border-color: #e0e0e0 !important;
+}
+#crate-search-div:hover::after, #crate-search-div:focus-within::after {
+	filter: invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg) brightness(113%) contrast(76%);
 }
 
 .search-input {
@@ -203,20 +213,9 @@ details.rustdoc-toggle > summary::before {
 	color: #000;
 }
 
-/* Created this empty rule to satisfy the theme checks. */
-.stab.empty-impl {}
-.stab.must_implement {}
-
-.stab.unstable,
-.stab.deprecated,
-.stab.portability,
-.stab.empty-impl,
-.stab.must_implement {
+.stab {
 	color: #c5c5c5;
 	background: #314559 !important;
-	border-style: none !important;
-	border-radius: 4px;
-	padding: 3px 6px 3px 6px;
 }
 
 .stab.portability > code {
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index a550eb1c130..6188e0ac0a9 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -152,7 +152,7 @@ details.rustdoc-toggle > summary::before {
 	filter: invert(100%);
 }
 
-#crate-search, .search-input {
+.search-input {
 	color: #111;
 	background-color: #f0f0f0;
 	border-color: #f0f0f0;
@@ -162,7 +162,17 @@ details.rustdoc-toggle > summary::before {
 	/* Without the `!important`, the border-color is ignored for `<select>`...
 	   It cannot be in the group above because `.search-input` has a different border color on
 	   hover. */
-	border-color: #f0f0f0 !important;
+	border-color: #d2d2d2 !important;
+}
+#crate-search-div::after {
+	/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+	filter: invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) brightness(90%) contrast(90%);
+}
+#crate-search:hover, #crate-search:focus {
+	border-color: #2196f3 !important;
+}
+#crate-search-div:hover::after, #crate-search-div:focus-within::after {
+	filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%);
 }
 
 .search-input {
@@ -173,12 +183,12 @@ details.rustdoc-toggle > summary::before {
 	border-color: #008dfd;
 }
 
-.stab.empty-impl { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; }
-.stab.unstable { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; }
-.stab.deprecated { background: #ffc4c4; border-color: #db7b7b; color: #2f2f2f; }
-.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; }
-.stab.portability { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; }
-.stab.portability > code { background: none; }
+.stab { background: #314559; }
+
+.stab.portability > code {
+	color: #e6e1cf;
+	background: none;
+}
 
 .rightside,
 .out-of-band {
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index b751acff152..fba790b6193 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -144,27 +144,32 @@ details.rustdoc-toggle > summary::before {
 	color: #999;
 }
 
-#crate-search, .search-input {
+.search-input {
 	background-color: white;
 	border-color: #e0e0e0;
 }
-
 #crate-search {
 	/* Without the `!important`, the border-color is ignored for `<select>`...
 	   It cannot be in the group above because `.search-input` has a different border color on
 	   hover. */
 	border-color: #e0e0e0 !important;
 }
+#crate-search-div::after {
+	/* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */
+	filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) brightness(114%) contrast(76%);
+}
+#crate-search:hover, #crate-search:focus {
+	border-color: #717171 !important;
+}
+#crate-search-div:hover::after, #crate-search-div:focus-within::after {
+	filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%);
+}
 
 .search-input:focus {
 	border-color: #66afe9;
 }
 
-.stab.empty-impl { background: #FFF5D6; border-color: #FFC600; }
-.stab.unstable { background: #FFF5D6; border-color: #FFC600; }
-.stab.deprecated { background: #ffc4c4; border-color: #db7b7b; }
-.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; }
-.stab.portability { background: #F3DFFF; border-color: #b07bdb; }
+.stab { background: #FFF5D6; border-color: #FFC600; }
 .stab.portability > code { background: none; }
 
 .rightside,
@@ -321,7 +326,7 @@ kbd {
 
 .popover, .popover::before,
 #help-button span.top, #help-button span.bottom {
-	border-color: #DDDDDD;
+	border-color: #e0e0e0;
 }
 
 #copy-path {
diff --git a/src/librustdoc/html/static/images/down-arrow.svg b/src/librustdoc/html/static/images/down-arrow.svg
index 35437e77a71..5d76a64e92c 100644
--- a/src/librustdoc/html/static/images/down-arrow.svg
+++ b/src/librustdoc/html/static/images/down-arrow.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" width="128" height="128" enable-background="new 0 0 128 128" version="1.1" viewBox="-30 -20 176 176" xml:space="preserve"><g><line x1="111" x2="64" y1="40.5" y2="87.499" fill="none" stroke="#2F3435" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/><line x1="64" x2="17" y1="87.499" y2="40.5" fill="none" stroke="#2F3435" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/></g></svg>
\ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" width="128" height="128" enable-background="new 0 0 128 128" version="1.1" viewBox="-30 -20 176 176" xml:space="preserve"><g><line x1="111" x2="64" y1="40.5" y2="87.499" fill="none" stroke="#000000" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/><line x1="64" x2="17" y1="87.499" y2="40.5" fill="none" stroke="#000000" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/></g></svg>
\ No newline at end of file
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 0702b2b0b7c..5dec610b30c 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -348,8 +348,7 @@ function loadCss(cssFileName) {
 
     function onHashChange(ev) {
         // If we're in mobile mode, we should hide the sidebar in any case.
-        const sidebar = document.getElementsByClassName("sidebar")[0];
-        removeClass(sidebar, "shown");
+        hideSidebar();
         handleHashes(ev);
     }
 
@@ -501,6 +500,10 @@ function loadCss(cssFileName) {
         const synthetic_implementors = document.getElementById("synthetic-implementors-list");
         const inlined_types = new Set();
 
+        const TEXT_IDX = 0;
+        const SYNTHETIC_IDX = 1;
+        const TYPES_IDX = 2;
+
         if (synthetic_implementors) {
             // This `inlined_types` variable is used to avoid having the same implementation
             // showing up twice. For example "String" in the "Sync" doc page.
@@ -536,10 +539,12 @@ function loadCss(cssFileName) {
 
             struct_loop:
             for (const struct of structs) {
-                const list = struct.synthetic ? synthetic_implementors : implementors;
+                const list = struct[SYNTHETIC_IDX] ? synthetic_implementors : implementors;
 
-                if (struct.synthetic) {
-                    for (const struct_type of struct.types) {
+                // The types list is only used for synthetic impls.
+                // If this changes, `main.js` and `write_shared.rs` both need changed.
+                if (struct[SYNTHETIC_IDX]) {
+                    for (const struct_type of struct[TYPES_IDX]) {
                         if (inlined_types.has(struct_type)) {
                             continue struct_loop;
                         }
@@ -548,7 +553,7 @@ function loadCss(cssFileName) {
                 }
 
                 const code = document.createElement("h3");
-                code.innerHTML = struct.text;
+                code.innerHTML = struct[TEXT_IDX];
                 addClass(code, "code-header");
                 addClass(code, "in-band");
 
@@ -728,11 +733,50 @@ function loadCss(cssFileName) {
         });
     }());
 
+    let oldSidebarScrollPosition = null;
+
+    function showSidebar() {
+        if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
+            // This is to keep the scroll position on mobile.
+            oldSidebarScrollPosition = window.scrollY;
+            document.body.style.width = `${document.body.offsetWidth}px`;
+            document.body.style.position = "fixed";
+            document.body.style.top = `-${oldSidebarScrollPosition}px`;
+            document.querySelector(".mobile-topbar").style.top = `${oldSidebarScrollPosition}px`;
+            document.querySelector(".mobile-topbar").style.position = "relative";
+        } else {
+            oldSidebarScrollPosition = null;
+        }
+        const sidebar = document.getElementsByClassName("sidebar")[0];
+        addClass(sidebar, "shown");
+    }
+
     function hideSidebar() {
+        if (oldSidebarScrollPosition !== null) {
+            // This is to keep the scroll position on mobile.
+            document.body.style.width = "";
+            document.body.style.position = "";
+            document.body.style.top = "";
+            document.querySelector(".mobile-topbar").style.top = "";
+            document.querySelector(".mobile-topbar").style.position = "";
+            // The scroll position is lost when resetting the style, hence why we store it in
+            // `oldSidebarScrollPosition`.
+            window.scrollTo(0, oldSidebarScrollPosition);
+            oldSidebarScrollPosition = null;
+        }
         const sidebar = document.getElementsByClassName("sidebar")[0];
         removeClass(sidebar, "shown");
     }
 
+    window.addEventListener("resize", () => {
+        if (window.innerWidth >= window.RUSTDOC_MOBILE_BREAKPOINT &&
+            oldSidebarScrollPosition !== null) {
+            // If the user opens the sidebar in "mobile" mode, and then grows the browser window,
+            // we need to switch away from mobile mode and make the main content area scrollable.
+            hideSidebar();
+        }
+    });
+
     function handleClick(id, f) {
         const elem = document.getElementById(id);
         if (elem) {
@@ -775,9 +819,9 @@ function loadCss(cssFileName) {
         sidebar_menu_toggle.addEventListener("click", () => {
             const sidebar = document.getElementsByClassName("sidebar")[0];
             if (!hasClass(sidebar, "shown")) {
-                addClass(sidebar, "shown");
+                showSidebar();
             } else {
-                removeClass(sidebar, "shown");
+                hideSidebar();
             }
         });
     }
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 75c7bd45a29..d04ec357c40 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -429,9 +429,9 @@ function initSearch(rawSearchIndex) {
             }
             const posBefore = parserState.pos;
             getNextElem(query, parserState, elems, endChar === ">");
-            // This case can be encountered if `getNextElem` encounted a "stop character" right from
-            // the start. For example if you have `,,` or `<>`. In this case, we simply move up the
-            // current position to continue the parsing.
+            // This case can be encountered if `getNextElem` encountered a "stop character" right
+            // from the start. For example if you have `,,` or `<>`. In this case, we simply move up
+            // the current position to continue the parsing.
             if (posBefore === parserState.pos) {
                 parserState.pos += 1;
             }
@@ -581,7 +581,7 @@ function initSearch(rawSearchIndex) {
         const elem = document.getElementById("crate-search");
 
         if (elem &&
-            elem.value !== "All crates" &&
+            elem.value !== "all crates" &&
             hasOwnPropertyRustdoc(rawSearchIndex, elem.value)
         ) {
             return elem.value;
@@ -1551,12 +1551,6 @@ function initSearch(rawSearchIndex) {
         return [displayPath, href];
     }
 
-    function escape(content) {
-        const h1 = document.createElement("h1");
-        h1.textContent = content;
-        return h1.innerHTML;
-    }
-
     function pathSplitter(path) {
         const tmp = "<span>" + path.replace(/::/g, "::</span><span>");
         if (tmp.endsWith("<span>")) {
@@ -1710,22 +1704,15 @@ function initSearch(rawSearchIndex) {
         let crates = "";
         const crates_list = Object.keys(rawSearchIndex);
         if (crates_list.length > 1) {
-            crates = " in <select id=\"crate-search\"><option value=\"All crates\">" +
-                "All crates</option>";
+            crates = " in&nbsp;<div id=\"crate-search-div\"><select id=\"crate-search\">" +
+                "<option value=\"all crates\">all crates</option>";
             for (const c of crates_list) {
                 crates += `<option value="${c}" ${c === filterCrates && "selected"}>${c}</option>`;
             }
-            crates += "</select>";
-        }
-
-        let typeFilter = "";
-        if (results.query.typeFilter !== NO_TYPE_FILTER) {
-            typeFilter = " (type: " + escape(itemTypes[results.query.typeFilter]) + ")";
+            crates += "</select></div>";
         }
 
-        let output = "<div id=\"search-settings\">" +
-            `<h1 class="search-results-title">Results for ${escape(results.query.userQuery)}` +
-            `${typeFilter}</h1>${crates}</div>`;
+        let output = `<h1 class="search-results-title">Results${crates}</h1>`;
         if (results.query.error !== null) {
             output += `<h3>Query parser error: "${results.query.error}".</h3>`;
             output += "<div id=\"titles\">" +
@@ -2245,7 +2232,7 @@ function initSearch(rawSearchIndex) {
     }
 
     function updateCrate(ev) {
-        if (ev.target.value === "All crates") {
+        if (ev.target.value === "all crates") {
             // If we don't remove it from the URL, it'll be picked up again by the search.
             const params = searchState.getQueryStringParams();
             const query = searchState.input.value.trim();
diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js
index c45d614293a..06d15d9e5ff 100644
--- a/src/librustdoc/html/static/js/source-script.js
+++ b/src/librustdoc/html/static/js/source-script.js
@@ -10,7 +10,7 @@
 (function() {
 
 const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-path"].value;
-let oldScrollPosition = 0;
+let oldScrollPosition = null;
 
 const NAME_OFFSET = 0;
 const DIRS_OFFSET = 1;
@@ -75,18 +75,21 @@ function toggleSidebar() {
             oldScrollPosition = window.scrollY;
             document.body.style.position = "fixed";
             document.body.style.top = `-${oldScrollPosition}px`;
+        } else {
+            oldScrollPosition = null;
         }
         addClass(document.documentElement, "source-sidebar-expanded");
         child.innerText = "<";
         updateLocalStorage("source-sidebar-show", "true");
     } else {
-        if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
+        if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT && oldScrollPosition !== null) {
             // This is to keep the scroll position on mobile.
             document.body.style.position = "";
             document.body.style.top = "";
             // The scroll position is lost when resetting the style, hence why we store it in
-            // `oldScroll`.
+            // `oldScrollPosition`.
             window.scrollTo(0, oldScrollPosition);
+            oldScrollPosition = null;
         }
         removeClass(document.documentElement, "source-sidebar-expanded");
         child.innerText = ">";
@@ -94,6 +97,17 @@ function toggleSidebar() {
     }
 }
 
+window.addEventListener("resize", () => {
+    if (window.innerWidth >= window.RUSTDOC_MOBILE_BREAKPOINT && oldScrollPosition !== null) {
+        // If the user opens the sidebar in "mobile" mode, and then grows the browser window,
+        // we need to switch away from mobile mode and make the main content area scrollable.
+        document.body.style.position = "";
+        document.body.style.top = "";
+        window.scrollTo(0, oldScrollPosition);
+        oldScrollPosition = null;
+    }
+});
+
 function createSidebarToggle() {
     const sidebarToggle = document.createElement("div");
     sidebarToggle.id = "sidebar-toggle";
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 8caba8cb902..4c21fd55328 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -685,24 +685,18 @@ impl FromWithTcx<clean::Variant> for Variant {
 impl FromWithTcx<clean::Import> for Import {
     fn from_tcx(import: clean::Import, tcx: TyCtxt<'_>) -> Self {
         use clean::ImportKind::*;
-        match import.kind {
-            Simple(s) => Import {
-                source: import.source.path.whole_name(),
-                name: s.to_string(),
-                id: import.source.did.map(ItemId::from).map(|i| from_item_id(i, tcx)),
-                glob: false,
-            },
-            Glob => Import {
-                source: import.source.path.whole_name(),
-                name: import
-                    .source
-                    .path
-                    .last_opt()
-                    .unwrap_or_else(|| Symbol::intern("*"))
-                    .to_string(),
-                id: import.source.did.map(ItemId::from).map(|i| from_item_id(i, tcx)),
-                glob: true,
-            },
+        let (name, glob) = match import.kind {
+            Simple(s) => (s.to_string(), false),
+            Glob => (
+                import.source.path.last_opt().unwrap_or_else(|| Symbol::intern("*")).to_string(),
+                true,
+            ),
+        };
+        Import {
+            source: import.source.path.whole_name(),
+            name,
+            id: import.source.did.map(ItemId::from).map(|i| from_item_id(i, tcx)),
+            glob,
         }
     }
 }
diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs
index 533e2ce46dd..9914edf3036 100644
--- a/src/librustdoc/passes/strip_hidden.rs
+++ b/src/librustdoc/passes/strip_hidden.rs
@@ -17,6 +17,7 @@ pub(crate) const STRIP_HIDDEN: Pass = Pass {
 /// Strip items marked `#[doc(hidden)]`
 pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
     let mut retained = ItemIdSet::default();
+    let is_json_output = cx.output_format.is_json() && !cx.show_coverage;
 
     // strip all #[doc(hidden)] items
     let krate = {
@@ -25,7 +26,12 @@ pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clea
     };
 
     // strip all impls referencing stripped items
-    let mut stripper = ImplStripper { retained: &retained, cache: &cx.cache };
+    let mut stripper = ImplStripper {
+        retained: &retained,
+        cache: &cx.cache,
+        is_json_output,
+        document_private: cx.render_options.document_private,
+    };
     stripper.fold_crate(krate)
 }
 
diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs
index 9ba841a31cf..f3aa3c7ce24 100644
--- a/src/librustdoc/passes/strip_private.rs
+++ b/src/librustdoc/passes/strip_private.rs
@@ -17,6 +17,7 @@ pub(crate) const STRIP_PRIVATE: Pass = Pass {
 pub(crate) fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
     // This stripper collects all *retained* nodes.
     let mut retained = ItemIdSet::default();
+    let is_json_output = cx.output_format.is_json() && !cx.show_coverage;
 
     // strip all private items
     {
@@ -24,12 +25,17 @@ pub(crate) fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) ->
             retained: &mut retained,
             access_levels: &cx.cache.access_levels,
             update_retained: true,
-            is_json_output: cx.output_format.is_json() && !cx.show_coverage,
+            is_json_output,
         };
         krate = ImportStripper.fold_crate(stripper.fold_crate(krate));
     }
 
     // strip all impls referencing private items
-    let mut stripper = ImplStripper { retained: &retained, cache: &cx.cache };
+    let mut stripper = ImplStripper {
+        retained: &retained,
+        cache: &cx.cache,
+        is_json_output,
+        document_private: cx.render_options.document_private,
+    };
     stripper.fold_crate(krate)
 }
diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs
index 0d419042a10..3f069e8393f 100644
--- a/src/librustdoc/passes/stripper.rs
+++ b/src/librustdoc/passes/stripper.rs
@@ -14,17 +14,19 @@ pub(crate) struct Stripper<'a> {
     pub(crate) is_json_output: bool,
 }
 
-impl<'a> Stripper<'a> {
-    // We need to handle this differently for the JSON output because some non exported items could
-    // be used in public API. And so, we need these items as well. `is_exported` only checks if they
-    // are in the public API, which is not enough.
-    #[inline]
-    fn is_item_reachable(&self, item_id: ItemId) -> bool {
-        if self.is_json_output {
-            self.access_levels.is_reachable(item_id.expect_def_id())
-        } else {
-            self.access_levels.is_exported(item_id.expect_def_id())
-        }
+// We need to handle this differently for the JSON output because some non exported items could
+// be used in public API. And so, we need these items as well. `is_exported` only checks if they
+// are in the public API, which is not enough.
+#[inline]
+fn is_item_reachable(
+    is_json_output: bool,
+    access_levels: &AccessLevels<DefId>,
+    item_id: ItemId,
+) -> bool {
+    if is_json_output {
+        access_levels.is_reachable(item_id.expect_def_id())
+    } else {
+        access_levels.is_exported(item_id.expect_def_id())
     }
 }
 
@@ -61,7 +63,9 @@ impl<'a> DocFolder for Stripper<'a> {
             | clean::MacroItem(..)
             | clean::ForeignTypeItem => {
                 let item_id = i.item_id;
-                if item_id.is_local() && !self.is_item_reachable(item_id) {
+                if item_id.is_local()
+                    && !is_item_reachable(self.is_json_output, self.access_levels, item_id)
+                {
                     debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name);
                     return None;
                 }
@@ -133,6 +137,8 @@ impl<'a> DocFolder for Stripper<'a> {
 pub(crate) struct ImplStripper<'a> {
     pub(crate) retained: &'a ItemIdSet,
     pub(crate) cache: &'a Cache,
+    pub(crate) is_json_output: bool,
+    pub(crate) document_private: bool,
 }
 
 impl<'a> DocFolder for ImplStripper<'a> {
@@ -140,8 +146,27 @@ impl<'a> DocFolder for ImplStripper<'a> {
         if let clean::ImplItem(ref imp) = *i.kind {
             // Impl blocks can be skipped if they are: empty; not a trait impl; and have no
             // documentation.
-            if imp.trait_.is_none() && imp.items.is_empty() && i.doc_value().is_none() {
-                return None;
+            //
+            // There is one special case: if the impl block contains only private items.
+            if imp.trait_.is_none() {
+                // If the only items present are private ones and we're not rendering private items,
+                // we don't document it.
+                if !imp.items.is_empty()
+                    && !self.document_private
+                    && imp.items.iter().all(|i| {
+                        let item_id = i.item_id;
+                        item_id.is_local()
+                            && !is_item_reachable(
+                                self.is_json_output,
+                                &self.cache.access_levels,
+                                item_id,
+                            )
+                    })
+                {
+                    return None;
+                } else if imp.items.is_empty() && i.doc_value().is_none() {
+                    return None;
+                }
             }
             if let Some(did) = imp.for_.def_id(self.cache) {
                 if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into())
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 8b6b5014fdad3a750f7242a6bfdcad83619498d
+Subproject e3be3f64ecac101d14ceda759ba078ad0aaf374
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index bd4ea98441d..ecdecadd2ef 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -591,8 +591,11 @@ pub struct Import {
     /// May be different from the last segment of `source` when renaming imports:
     /// `use source as name;`
     pub name: String,
-    /// The ID of the item being imported.
-    pub id: Option<Id>, // FIXME is this actually ever None?
+    /// The ID of the item being imported. Will be `None` in case of re-exports of primitives:
+    /// ```rust
+    /// pub use i32 as my_i32;
+    /// ```
+    pub id: Option<Id>,
     /// Whether this import uses a glob: `use source::*;`
     pub glob: bool,
 }
diff --git a/src/test/codegen/layout-size-checks.rs b/src/test/codegen/layout-size-checks.rs
new file mode 100644
index 00000000000..d067cc10a94
--- /dev/null
+++ b/src/test/codegen/layout-size-checks.rs
@@ -0,0 +1,31 @@
+// compile-flags: -O
+// only-x86_64
+// ignore-debug: the debug assertions get in the way
+
+#![crate_type = "lib"]
+
+use std::alloc::Layout;
+
+type RGB48 = [u16; 3];
+
+// CHECK-LABEL: @layout_array_rgb48
+#[no_mangle]
+pub fn layout_array_rgb48(n: usize) -> Layout {
+    // CHECK-NOT: llvm.umul.with.overflow.i64
+    // CHECK: icmp ugt i64 %n, 1537228672809129301
+    // CHECK-NOT: llvm.umul.with.overflow.i64
+    // CHECK: mul nuw nsw i64 %n, 6
+    // CHECK-NOT: llvm.umul.with.overflow.i64
+    Layout::array::<RGB48>(n).unwrap()
+}
+
+// CHECK-LABEL: @layout_array_i32
+#[no_mangle]
+pub fn layout_array_i32(n: usize) -> Layout {
+    // CHECK-NOT: llvm.umul.with.overflow.i64
+    // CHECK: icmp ugt i64 %n, 2305843009213693951
+    // CHECK-NOT: llvm.umul.with.overflow.i64
+    // CHECK: shl nuw nsw i64 %n, 2
+    // CHECK-NOT: llvm.umul.with.overflow.i64
+    Layout::array::<i32>(n).unwrap()
+}
diff --git a/src/test/mir-opt/README.md b/src/test/mir-opt/README.md
index a0550466cf0..0721d9f7019 100644
--- a/src/test/mir-opt/README.md
+++ b/src/test/mir-opt/README.md
@@ -14,6 +14,18 @@ presence of pointers in constants or other bit width dependent things. In that c
 
 to your test, causing separate files to be generated for 32bit and 64bit systems.
 
+## Unit testing
+
+If you are only testing the behavior of a particular mir-opt pass on some specific input (as is
+usually the case), you should add
+
+```
+// unit-test: PassName
+```
+
+to the top of the file. This makes sure that other passes don't run which means you'll get the input
+you expected and your test won't break when other code changes.
+
 ## Emit a diff of the mir for a specific optimization
 
 This is what you want most often when you want to see how an optimization changes the MIR.
diff --git a/src/test/mir-opt/bool_compare.rs b/src/test/mir-opt/bool_compare.rs
index 3ff046325dc..4435bf5b0f2 100644
--- a/src/test/mir-opt/bool_compare.rs
+++ b/src/test/mir-opt/bool_compare.rs
@@ -1,3 +1,5 @@
+// unit-test: InstCombine
+
 // EMIT_MIR bool_compare.opt1.InstCombine.diff
 fn opt1(x: bool) -> u32 {
     if x != true { 0 } else { 1 }
diff --git a/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff b/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff
deleted file mode 100644
index c73150f947d..00000000000
--- a/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff
+++ /dev/null
@@ -1,77 +0,0 @@
-- // MIR for `norm2` before InstCombine
-+ // MIR for `norm2` after InstCombine
-  
-  fn norm2(_1: [f32; 2]) -> f32 {
-      debug x => _1;                       // in scope 0 at $DIR/combine_array_len.rs:+0:10: +0:11
-      let mut _0: f32;                     // return place in scope 0 at $DIR/combine_array_len.rs:+0:26: +0:29
-      let _2: f32;                         // in scope 0 at $DIR/combine_array_len.rs:+1:9: +1:10
-      let _3: usize;                       // in scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
-      let mut _4: usize;                   // in scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-      let mut _5: bool;                    // in scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-      let _7: usize;                       // in scope 0 at $DIR/combine_array_len.rs:+2:15: +2:16
-      let mut _8: usize;                   // in scope 0 at $DIR/combine_array_len.rs:+2:13: +2:17
-      let mut _9: bool;                    // in scope 0 at $DIR/combine_array_len.rs:+2:13: +2:17
-      let mut _10: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:5: +3:8
-      let mut _11: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:5: +3:6
-      let mut _12: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:7: +3:8
-      let mut _13: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:11: +3:14
-      let mut _14: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:11: +3:12
-      let mut _15: f32;                    // in scope 0 at $DIR/combine_array_len.rs:+3:13: +3:14
-      scope 1 {
-          debug a => _2;                   // in scope 1 at $DIR/combine_array_len.rs:+1:9: +1:10
-          let _6: f32;                     // in scope 1 at $DIR/combine_array_len.rs:+2:9: +2:10
-          scope 2 {
-              debug b => _6;               // in scope 2 at $DIR/combine_array_len.rs:+2:9: +2:10
-          }
-      }
-  
-      bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/combine_array_len.rs:+1:9: +1:10
-          StorageLive(_3);                 // scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
-          _3 = const 0_usize;              // scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16
--         _4 = Len(_1);                    // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-+         _4 = const 2_usize;              // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-          _5 = Lt(_3, _4);                 // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-          assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-      }
-  
-      bb1: {
-          _2 = _1[_3];                     // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17
-          StorageDead(_3);                 // scope 0 at $DIR/combine_array_len.rs:+1:17: +1:18
-          StorageLive(_6);                 // scope 1 at $DIR/combine_array_len.rs:+2:9: +2:10
-          StorageLive(_7);                 // scope 1 at $DIR/combine_array_len.rs:+2:15: +2:16
-          _7 = const 1_usize;              // scope 1 at $DIR/combine_array_len.rs:+2:15: +2:16
--         _8 = Len(_1);                    // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
-+         _8 = const 2_usize;              // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
-          _9 = Lt(_7, _8);                 // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
-          assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
-      }
-  
-      bb2: {
-          _6 = _1[_7];                     // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17
-          StorageDead(_7);                 // scope 1 at $DIR/combine_array_len.rs:+2:17: +2:18
-          StorageLive(_10);                // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:8
-          StorageLive(_11);                // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:6
-          _11 = _2;                        // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:6
-          StorageLive(_12);                // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
-          _12 = _2;                        // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
-          _10 = Mul(move _11, move _12);   // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:8
-          StorageDead(_12);                // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
-          StorageDead(_11);                // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8
-          StorageLive(_13);                // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:14
-          StorageLive(_14);                // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:12
-          _14 = _6;                        // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:12
-          StorageLive(_15);                // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
-          _15 = _6;                        // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
-          _13 = Mul(move _14, move _15);   // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:14
-          StorageDead(_15);                // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
-          StorageDead(_14);                // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
-          _0 = Add(move _10, move _13);    // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:14
-          StorageDead(_13);                // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
-          StorageDead(_10);                // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14
-          StorageDead(_6);                 // scope 1 at $DIR/combine_array_len.rs:+4:1: +4:2
-          StorageDead(_2);                 // scope 0 at $DIR/combine_array_len.rs:+4:1: +4:2
-          return;                          // scope 0 at $DIR/combine_array_len.rs:+4:2: +4:2
-      }
-  }
-  
diff --git a/src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff b/src/test/mir-opt/combine_array_len.norm2.InstCombine.diff
index c73150f947d..c73150f947d 100644
--- a/src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff
+++ b/src/test/mir-opt/combine_array_len.norm2.InstCombine.diff
diff --git a/src/test/mir-opt/combine_array_len.rs b/src/test/mir-opt/combine_array_len.rs
index 93490c14fd6..3ef3bd09afd 100644
--- a/src/test/mir-opt/combine_array_len.rs
+++ b/src/test/mir-opt/combine_array_len.rs
@@ -1,4 +1,4 @@
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
+// unit-test: InstCombine
 // EMIT_MIR combine_array_len.norm2.InstCombine.diff
 
 fn norm2(x: [f32; 2]) -> f32 {
diff --git a/src/test/mir-opt/const_goto.rs b/src/test/mir-opt/const_goto.rs
index 939902e70e9..6f84f186b31 100644
--- a/src/test/mir-opt/const_goto.rs
+++ b/src/test/mir-opt/const_goto.rs
@@ -1,3 +1,5 @@
+// unit-test: ConstGoto
+
 pub enum Foo {
     A,
     B,
diff --git a/src/test/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff b/src/test/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff
index 2b09ef78661..81c356cb1db 100644
--- a/src/test/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff
+++ b/src/test/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff
@@ -17,7 +17,7 @@
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/const_goto_storage.rs:+1:9: +1:12
 -         StorageLive(_2);                 // scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23
--         nop;                             // scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23
+-         Deinit(_2);                      // scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23
 -         StorageLive(_3);                 // scope 0 at $DIR/const_goto_storage.rs:+2:15: +6:10
 -         StorageLive(_4);                 // scope 0 at $DIR/const_goto_storage.rs:+2:18: +2:76
 -         StorageLive(_5);                 // scope 0 at $DIR/const_goto_storage.rs:+2:21: +2:52
diff --git a/src/test/mir-opt/const_goto_storage.rs b/src/test/mir-opt/const_goto_storage.rs
index 4ef68e7e1fa..459599c73eb 100644
--- a/src/test/mir-opt/const_goto_storage.rs
+++ b/src/test/mir-opt/const_goto_storage.rs
@@ -1,3 +1,5 @@
+// unit-test: ConstGoto
+
 // EMIT_MIR const_goto_storage.match_nested_if.ConstGoto.diff
 fn match_nested_if() -> bool {
     let val = match () {
diff --git a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff
index f2d4bee1bf9..73fdf140498 100644
--- a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff
@@ -12,8 +12,6 @@
       let mut _7: std::boxed::Box<i32>;    // in scope 0 at $DIR/boxes.rs:+1:14: +1:22
       let mut _8: *const i32;              // in scope 0 at $DIR/boxes.rs:+1:14: +1:22
       let mut _9: *const i32;              // in scope 0 at $DIR/boxes.rs:+1:14: +1:22
-      let mut _10: *const i32;             // in scope 0 at $DIR/boxes.rs:+1:14: +1:22
-      let mut _11: *const i32;             // in scope 0 at $DIR/boxes.rs:+1:14: +1:22
       scope 1 {
           debug x => _1;                   // in scope 1 at $DIR/boxes.rs:+1:9: +1:10
       }
diff --git a/src/test/mir-opt/deaggregator_test.rs b/src/test/mir-opt/deaggregator_test.rs
index 342e222431b..ee59402af38 100644
--- a/src/test/mir-opt/deaggregator_test.rs
+++ b/src/test/mir-opt/deaggregator_test.rs
@@ -1,3 +1,5 @@
+// unit-test: Deaggregator
+
 struct Baz {
     x: usize,
     y: f32,
diff --git a/src/test/mir-opt/deaggregator_test_enum.rs b/src/test/mir-opt/deaggregator_test_enum.rs
index 02b63a1f55d..ea402dafdec 100644
--- a/src/test/mir-opt/deaggregator_test_enum.rs
+++ b/src/test/mir-opt/deaggregator_test_enum.rs
@@ -1,3 +1,5 @@
+// unit-test: Deaggregator
+
 enum Baz {
     Empty,
     Foo { x: usize },
diff --git a/src/test/mir-opt/deaggregator_test_enum_2.rs b/src/test/mir-opt/deaggregator_test_enum_2.rs
index 489854ff0aa..955c317324a 100644
--- a/src/test/mir-opt/deaggregator_test_enum_2.rs
+++ b/src/test/mir-opt/deaggregator_test_enum_2.rs
@@ -1,3 +1,4 @@
+// unit-test: Deaggregator
 // Test that deaggregate fires in more than one basic block
 
 enum Foo {
diff --git a/src/test/mir-opt/deaggregator_test_multiple.rs b/src/test/mir-opt/deaggregator_test_multiple.rs
index 9730b9aa8e5..46305fe21d2 100644
--- a/src/test/mir-opt/deaggregator_test_multiple.rs
+++ b/src/test/mir-opt/deaggregator_test_multiple.rs
@@ -1,3 +1,4 @@
+// unit-test: Deaggregator
 // Test that deaggregate fires more than once per block
 
 enum Foo {
diff --git a/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff b/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
index 01864ba24ac..53f977de5d6 100644
--- a/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
+++ b/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
@@ -7,101 +7,94 @@
       let mut _2: &[u8];                   // in scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
       let mut _3: &str;                    // in scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
       let mut _4: usize;                   // in scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
-      let mut _5: bool;                    // in scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
-      let mut _6: usize;                   // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
-      let mut _7: bool;                    // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
-      scope 1 (inlined core::str::<impl str>::as_bytes) { // at $DIR/deduplicate_blocks.rs:3:11: 3:23
-          debug self => _3;                // in scope 1 at $SRC_DIR/core/src/str/mod.rs:LL:COL
-          let mut _8: &str;                // in scope 1 at $SRC_DIR/core/src/str/mod.rs:LL:COL
-          scope 2 {
-          }
-      }
+      let mut _5: usize;                   // in scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
+      let mut _6: bool;                    // in scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
+      let mut _7: usize;                   // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
+      let mut _8: usize;                   // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
+      let mut _9: bool;                    // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
   
       bb0: {
           StorageLive(_2);                 // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
           StorageLive(_3);                 // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
-          _3 = _1;                         // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
-          StorageLive(_8);                 // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL
-          _8 = _3;                         // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL
--         _2 = transmute::<&str, &[u8]>(move _8) -> bb14; // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL
-+         _2 = transmute::<&str, &[u8]>(move _8) -> bb12; // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL
+          _3 = &(*_1);                     // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
+          _2 = core::str::<impl str>::as_bytes(move _3) -> bb1; // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23
                                            // mir::Constant
-                                           // + span: $SRC_DIR/core/src/str/mod.rs:LL:COL
-                                           // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&str) -> &[u8] {transmute::<&str, &[u8]>}, val: Value(<ZST>) }
+                                           // + span: $DIR/deduplicate_blocks.rs:5:13: 5:21
+                                           // + literal: Const { ty: for<'r> fn(&'r str) -> &'r [u8] {core::str::<impl str>::as_bytes}, val: Value(<ZST>) }
       }
   
       bb1: {
-          switchInt((*_2)[0 of 4]) -> [47_u8: bb2, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+          StorageDead(_3);                 // scope 0 at $DIR/deduplicate_blocks.rs:+1:22: +1:23
+          _7 = Len((*_2));                 // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
+          _8 = const 4_usize;              // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
+          _9 = Ge(move _7, move _8);       // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
+          switchInt(move _9) -> [false: bb6, otherwise: bb2]; // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
       }
   
       bb2: {
-          switchInt((*_2)[1 of 4]) -> [47_u8: bb3, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+          switchInt((*_2)[0 of 4]) -> [47_u8: bb3, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
       }
   
       bb3: {
-          switchInt((*_2)[2 of 4]) -> [47_u8: bb4, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+          switchInt((*_2)[1 of 4]) -> [47_u8: bb4, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
       }
   
       bb4: {
--         switchInt((*_2)[3 of 4]) -> [47_u8: bb10, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
-+         switchInt((*_2)[3 of 4]) -> [47_u8: bb9, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+          switchInt((*_2)[2 of 4]) -> [47_u8: bb5, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
       }
   
       bb5: {
-          _4 = Len((*_2));                 // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
-          _5 = Ge(move _4, const 3_usize); // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
-          switchInt(move _5) -> [false: bb9, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
+-         switchInt((*_2)[3 of 4]) -> [47_u8: bb11, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
++         switchInt((*_2)[3 of 4]) -> [47_u8: bb10, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
       }
   
       bb6: {
-          switchInt((*_2)[0 of 3]) -> [47_u8: bb7, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+          _4 = Len((*_2));                 // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
+          _5 = const 3_usize;              // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
+          _6 = Ge(move _4, move _5);       // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
+          switchInt(move _6) -> [false: bb10, otherwise: bb7]; // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31
       }
   
       bb7: {
-          switchInt((*_2)[1 of 3]) -> [47_u8: bb8, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+          switchInt((*_2)[0 of 3]) -> [47_u8: bb8, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
       }
   
       bb8: {
--         switchInt((*_2)[2 of 3]) -> [47_u8: bb11, 33_u8: bb12, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
-+         switchInt((*_2)[2 of 3]) -> [47_u8: bb10, 33_u8: bb10, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+          switchInt((*_2)[1 of 3]) -> [47_u8: bb9, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
       }
   
       bb9: {
+-         switchInt((*_2)[2 of 3]) -> [47_u8: bb12, 33_u8: bb13, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
++         switchInt((*_2)[2 of 3]) -> [47_u8: bb11, 33_u8: bb11, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23
+      }
+  
+      bb10: {
 -         _0 = const false;                // scope 0 at $DIR/deduplicate_blocks.rs:+5:14: +5:19
--         goto -> bb13;                    // scope 0 at $DIR/deduplicate_blocks.rs:+5:14: +5:19
+-         goto -> bb14;                    // scope 0 at $DIR/deduplicate_blocks.rs:+5:14: +5:19
 -     }
 - 
--     bb10: {
+-     bb11: {
           _0 = const false;                // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46
--         goto -> bb13;                    // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46
-+         goto -> bb11;                    // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46
+-         goto -> bb14;                    // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46
++         goto -> bb12;                    // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46
       }
   
--     bb11: {
+-     bb12: {
 -         _0 = const true;                 // scope 0 at $DIR/deduplicate_blocks.rs:+3:35: +3:39
--         goto -> bb13;                    // scope 0 at $DIR/deduplicate_blocks.rs:+3:35: +3:39
+-         goto -> bb14;                    // scope 0 at $DIR/deduplicate_blocks.rs:+3:35: +3:39
 -     }
 - 
--     bb12: {
-+     bb10: {
-          _0 = const true;                 // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39
--         goto -> bb13;                    // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39
-+         goto -> bb11;                    // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39
-      }
-  
 -     bb13: {
 +     bb11: {
-          StorageDead(_2);                 // scope 0 at $DIR/deduplicate_blocks.rs:+7:1: +7:2
-          return;                          // scope 0 at $DIR/deduplicate_blocks.rs:+7:2: +7:2
+          _0 = const true;                 // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39
+-         goto -> bb14;                    // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39
++         goto -> bb12;                    // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39
       }
   
 -     bb14: {
 +     bb12: {
-          StorageDead(_8);                 // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL
-          StorageDead(_3);                 // scope 0 at $DIR/deduplicate_blocks.rs:+1:22: +1:23
-          _6 = Len((*_2));                 // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
-          _7 = Ge(move _6, const 4_usize); // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
-          switchInt(move _7) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37
+          StorageDead(_2);                 // scope 0 at $DIR/deduplicate_blocks.rs:+7:1: +7:2
+          return;                          // scope 0 at $DIR/deduplicate_blocks.rs:+7:2: +7:2
       }
   }
   
diff --git a/src/test/mir-opt/deduplicate_blocks.rs b/src/test/mir-opt/deduplicate_blocks.rs
index f8f7361dc0d..2b9eed99ecd 100644
--- a/src/test/mir-opt/deduplicate_blocks.rs
+++ b/src/test/mir-opt/deduplicate_blocks.rs
@@ -1,3 +1,5 @@
+// unit-test: DeduplicateBlocks
+
 // EMIT_MIR deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff
 pub const fn is_line_doc_comment_2(s: &str) -> bool {
     match s.as_bytes() {
diff --git a/src/test/mir-opt/derefer_complex_case.main.Derefer.diff b/src/test/mir-opt/derefer_complex_case.main.Derefer.diff
index de0c03bb70b..abd6193fed9 100644
--- a/src/test/mir-opt/derefer_complex_case.main.Derefer.diff
+++ b/src/test/mir-opt/derefer_complex_case.main.Derefer.diff
@@ -30,12 +30,12 @@
           StorageLive(_2);                 // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26
           _14 = const main::promoted[0];   // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26
                                            // mir::Constant
-                                           // + span: $DIR/derefer_complex_case.rs:5:17: 5:26
+                                           // + span: $DIR/derefer_complex_case.rs:6:17: 6:26
                                            // + literal: Const { ty: &[i32; 2], val: Unevaluated(main, [], Some(promoted[0])) }
           _2 = &(*_14);                    // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26
           _1 = <&[i32; 2] as IntoIterator>::into_iter(move _2) -> bb1; // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26
                                            // mir::Constant
-                                           // + span: $DIR/derefer_complex_case.rs:5:17: 5:26
+                                           // + span: $DIR/derefer_complex_case.rs:6:17: 6:26
                                            // + literal: Const { ty: fn(&[i32; 2]) -> <&[i32; 2] as IntoIterator>::IntoIter {<&[i32; 2] as IntoIterator>::into_iter}, val: Value(<ZST>) }
       }
   
@@ -55,7 +55,7 @@
           _8 = &mut (*_9);                 // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26
           _7 = <std::slice::Iter<i32> as Iterator>::next(move _8) -> bb3; // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26
                                            // mir::Constant
-                                           // + span: $DIR/derefer_complex_case.rs:5:17: 5:26
+                                           // + span: $DIR/derefer_complex_case.rs:6:17: 6:26
                                            // + literal: Const { ty: for<'r> fn(&'r mut std::slice::Iter<i32>) -> Option<<std::slice::Iter<i32> as Iterator>::Item> {<std::slice::Iter<i32> as Iterator>::next}, val: Value(<ZST>) }
       }
   
@@ -76,7 +76,7 @@
           _13 = _12;                       // scope 2 at $DIR/derefer_complex_case.rs:+1:34: +1:37
           _6 = std::mem::drop::<i32>(move _13) -> bb7; // scope 2 at $DIR/derefer_complex_case.rs:+1:29: +1:38
                                            // mir::Constant
-                                           // + span: $DIR/derefer_complex_case.rs:5:29: 5:33
+                                           // + span: $DIR/derefer_complex_case.rs:6:29: 6:33
                                            // + literal: Const { ty: fn(i32) {std::mem::drop::<i32>}, val: Value(<ZST>) }
       }
   
diff --git a/src/test/mir-opt/derefer_complex_case.rs b/src/test/mir-opt/derefer_complex_case.rs
index 48bec39074c..dc48cee950b 100644
--- a/src/test/mir-opt/derefer_complex_case.rs
+++ b/src/test/mir-opt/derefer_complex_case.rs
@@ -1,3 +1,4 @@
+// unit-test: Derefer
 // EMIT_MIR derefer_complex_case.main.Derefer.diff
 // ignore-wasm32
 
diff --git a/src/test/mir-opt/derefer_inline_test.main.Derefer.diff b/src/test/mir-opt/derefer_inline_test.main.Derefer.diff
index ce6ffaa5641..3540df30836 100644
--- a/src/test/mir-opt/derefer_inline_test.main.Derefer.diff
+++ b/src/test/mir-opt/derefer_inline_test.main.Derefer.diff
@@ -17,7 +17,7 @@
           _3 = AlignOf(std::boxed::Box<u32>); // scope 1 at $DIR/derefer_inline_test.rs:+1:5: +1:12
           _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 1 at $DIR/derefer_inline_test.rs:+1:5: +1:12
                                            // mir::Constant
-                                           // + span: $DIR/derefer_inline_test.rs:10:5: 10:12
+                                           // + span: $DIR/derefer_inline_test.rs:11:5: 11:12
                                            // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
       }
   
@@ -26,7 +26,7 @@
           _5 = ShallowInitBox(move _4, std::boxed::Box<u32>); // scope 0 at $DIR/derefer_inline_test.rs:+1:5: +1:12
           (*_5) = f() -> [return: bb2, unwind: bb6]; // scope 0 at $DIR/derefer_inline_test.rs:+1:9: +1:12
                                            // mir::Constant
-                                           // + span: $DIR/derefer_inline_test.rs:10:9: 10:10
+                                           // + span: $DIR/derefer_inline_test.rs:11:9: 11:10
                                            // + literal: Const { ty: fn() -> Box<u32> {f}, val: Value(<ZST>) }
       }
   
diff --git a/src/test/mir-opt/derefer_inline_test.rs b/src/test/mir-opt/derefer_inline_test.rs
index 191a8cbbef4..cc06a7dd8c4 100644
--- a/src/test/mir-opt/derefer_inline_test.rs
+++ b/src/test/mir-opt/derefer_inline_test.rs
@@ -1,3 +1,4 @@
+// unit-test: Derefer
 // EMIT_MIR derefer_inline_test.main.Derefer.diff
 // ignore-wasm32 compiled with panic=abort by default
 
diff --git a/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff b/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff
index 0a56ee5e454..ed336208325 100644
--- a/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff
+++ b/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff
@@ -32,7 +32,7 @@
           StorageLive(_1);                 // scope 0 at $DIR/derefer_terminator_test.rs:+1:9: +1:10
           _1 = foo() -> bb1;               // scope 0 at $DIR/derefer_terminator_test.rs:+1:13: +1:18
                                            // mir::Constant
-                                           // + span: $DIR/derefer_terminator_test.rs:5:13: 5:16
+                                           // + span: $DIR/derefer_terminator_test.rs:6:13: 6:16
                                            // + literal: Const { ty: fn() -> bool {foo}, val: Value(<ZST>) }
       }
   
@@ -40,7 +40,7 @@
           StorageLive(_2);                 // scope 1 at $DIR/derefer_terminator_test.rs:+2:9: +2:10
           _2 = foo() -> bb2;               // scope 1 at $DIR/derefer_terminator_test.rs:+2:13: +2:18
                                            // mir::Constant
-                                           // + span: $DIR/derefer_terminator_test.rs:6:13: 6:16
+                                           // + span: $DIR/derefer_terminator_test.rs:7:13: 7:16
                                            // + literal: Const { ty: fn() -> bool {foo}, val: Value(<ZST>) }
       }
   
diff --git a/src/test/mir-opt/derefer_terminator_test.rs b/src/test/mir-opt/derefer_terminator_test.rs
index 787b14ae735..d6750c29dd9 100644
--- a/src/test/mir-opt/derefer_terminator_test.rs
+++ b/src/test/mir-opt/derefer_terminator_test.rs
@@ -1,3 +1,4 @@
+// unit-test: Derefer
 // EMIT_MIR derefer_terminator_test.main.Derefer.diff
 // ignore-wasm32
 
diff --git a/src/test/mir-opt/derefer_test.rs b/src/test/mir-opt/derefer_test.rs
index 2ebc0d343bd..fad0fe8eb6f 100644
--- a/src/test/mir-opt/derefer_test.rs
+++ b/src/test/mir-opt/derefer_test.rs
@@ -1,3 +1,4 @@
+// unit-test: Derefer
 // EMIT_MIR derefer_test.main.Derefer.diff
 fn main() {
     let mut a = (42,43);
diff --git a/src/test/mir-opt/derefer_test_multiple.rs b/src/test/mir-opt/derefer_test_multiple.rs
index a27363447fe..0b3888b07ab 100644
--- a/src/test/mir-opt/derefer_test_multiple.rs
+++ b/src/test/mir-opt/derefer_test_multiple.rs
@@ -1,3 +1,4 @@
+// unit-test: Derefer
 // EMIT_MIR derefer_test_multiple.main.Derefer.diff
 fn main () {
     let mut a = (42, 43);
diff --git a/src/test/mir-opt/equal_true.rs b/src/test/mir-opt/equal_true.rs
index 994cd194a45..717d10c6d76 100644
--- a/src/test/mir-opt/equal_true.rs
+++ b/src/test/mir-opt/equal_true.rs
@@ -1,3 +1,5 @@
+// unit-test InstCombine
+
 // EMIT_MIR equal_true.opt.InstCombine.diff
 
 fn opt(x: bool) -> i32 {
diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff
index deaba70e082..5dfcd2d54ca 100644
--- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff
+++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff
@@ -10,15 +10,14 @@
       let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
       let mut _6: ();                      // in scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
       let mut _7: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-      let mut _8: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-+     let mut _9: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++     let mut _8: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
       scope 1 {
           debug _x => _1;                  // in scope 1 at $DIR/inline-into-box-place.rs:+1:9: +1:11
       }
       scope 2 {
       }
 +     scope 3 (inlined Vec::<u32>::new) {  // at $DIR/inline-into-box-place.rs:8:33: 8:43
-+         let mut _10: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         let mut _9: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +     }
   
       bb0: {
@@ -37,10 +36,10 @@
           StorageLive(_7);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
           _7 = (((_5.0: std::ptr::Unique<std::vec::Vec<u32>>).0: std::ptr::NonNull<std::vec::Vec<u32>>).0: *const std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
 -         (*_7) = Vec::<u32>::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         StorageLive(_9);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         _9 = &mut (*_7);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         StorageLive(_10);                // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         _10 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageLive(_8);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++         _8 = &mut (*_7);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++         StorageLive(_9);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         _9 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
                                            // mir::Constant
 -                                          // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
 -                                          // + user_ty: UserType(1)
@@ -51,11 +50,11 @@
 +                                          // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +                                          // + user_ty: UserType(0)
 +                                          // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Unevaluated(alloc::raw_vec::RawVec::<T>::NEW, [u32], None) }
-+         Deinit((*_9));                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         ((*_9).0: alloc::raw_vec::RawVec<u32>) = move _10; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         ((*_9).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         StorageDead(_10);                // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         StorageDead(_9);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++         Deinit((*_8));                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         ((*_8).0: alloc::raw_vec::RawVec<u32>) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageDead(_9);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageDead(_8);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
           StorageDead(_7);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
           _1 = move _5;                    // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
           StorageDead(_5);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
index deaba70e082..5dfcd2d54ca 100644
--- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
+++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
@@ -10,15 +10,14 @@
       let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
       let mut _6: ();                      // in scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
       let mut _7: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-      let mut _8: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-+     let mut _9: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++     let mut _8: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
       scope 1 {
           debug _x => _1;                  // in scope 1 at $DIR/inline-into-box-place.rs:+1:9: +1:11
       }
       scope 2 {
       }
 +     scope 3 (inlined Vec::<u32>::new) {  // at $DIR/inline-into-box-place.rs:8:33: 8:43
-+         let mut _10: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         let mut _9: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +     }
   
       bb0: {
@@ -37,10 +36,10 @@
           StorageLive(_7);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
           _7 = (((_5.0: std::ptr::Unique<std::vec::Vec<u32>>).0: std::ptr::NonNull<std::vec::Vec<u32>>).0: *const std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
 -         (*_7) = Vec::<u32>::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         StorageLive(_9);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         _9 = &mut (*_7);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+         StorageLive(_10);                // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         _10 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageLive(_8);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++         _8 = &mut (*_7);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++         StorageLive(_9);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         _9 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
                                            // mir::Constant
 -                                          // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
 -                                          // + user_ty: UserType(1)
@@ -51,11 +50,11 @@
 +                                          // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
 +                                          // + user_ty: UserType(0)
 +                                          // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Unevaluated(alloc::raw_vec::RawVec::<T>::NEW, [u32], None) }
-+         Deinit((*_9));                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         ((*_9).0: alloc::raw_vec::RawVec<u32>) = move _10; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         ((*_9).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         StorageDead(_10);                // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+         StorageDead(_9);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
++         Deinit((*_8));                   // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         ((*_8).0: alloc::raw_vec::RawVec<u32>) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageDead(_9);                 // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
++         StorageDead(_8);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
           StorageDead(_7);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
           _1 = move _5;                    // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
           StorageDead(_5);                 // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
diff --git a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff
index b78ef36eadd..a3cee3ecf61 100644
--- a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff
+++ b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff
@@ -5,7 +5,7 @@
       let mut _0: bool;                    // return place in scope 0 at /the/src/instrument_coverage.rs:+0:13: +0:17
   
       bb0: {
-+         Coverage::Counter(1) for /the/src/instrument_coverage.rs:19:1 - 21:2; // scope 0 at /the/src/instrument_coverage.rs:+2:2: +2:2
++         Coverage::Counter(1) for /the/src/instrument_coverage.rs:20:1 - 22:2; // scope 0 at /the/src/instrument_coverage.rs:+2:2: +2:2
           _0 = const true;                 // scope 0 at /the/src/instrument_coverage.rs:+1:5: +1:9
           return;                          // scope 0 at /the/src/instrument_coverage.rs:+2:2: +2:2
       }
diff --git a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
index 0490c0df2e6..81d5528231d 100644
--- a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
+++ b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff
@@ -8,12 +8,12 @@
       let mut _3: !;                       // in scope 0 at /the/src/instrument_coverage.rs:+2:18: +4:10
   
       bb0: {
-+         Coverage::Counter(1) for /the/src/instrument_coverage.rs:10:1 - 10:11; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
++         Coverage::Counter(1) for /the/src/instrument_coverage.rs:11:1 - 11:11; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
           goto -> bb1;                     // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
       }
   
       bb1: {
-+         Coverage::Expression(4294967295) = 1 + 2 for /the/src/instrument_coverage.rs:11:5 - 12:17; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
++         Coverage::Expression(4294967295) = 1 + 2 for /the/src/instrument_coverage.rs:12:5 - 13:17; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
           falseUnwind -> [real: bb2, cleanup: bb6]; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
       }
   
@@ -21,7 +21,7 @@
           StorageLive(_2);                 // scope 0 at /the/src/instrument_coverage.rs:+2:12: +2:17
           _2 = bar() -> [return: bb3, unwind: bb6]; // scope 0 at /the/src/instrument_coverage.rs:+2:12: +2:17
                                            // mir::Constant
-                                           // + span: /the/src/instrument_coverage.rs:12:12: 12:15
+                                           // + span: /the/src/instrument_coverage.rs:13:12: 13:15
                                            // + literal: Const { ty: fn() -> bool {bar}, val: Value(<ZST>) }
       }
   
@@ -30,15 +30,15 @@
       }
   
       bb4: {
-+         Coverage::Expression(4294967293) = 4294967294 + 0 for /the/src/instrument_coverage.rs:16:1 - 16:2; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2
-+         Coverage::Expression(4294967294) = 4294967295 - 2 for /the/src/instrument_coverage.rs:13:13 - 13:18; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2
++         Coverage::Expression(4294967293) = 4294967294 + 0 for /the/src/instrument_coverage.rs:17:1 - 17:2; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2
++         Coverage::Expression(4294967294) = 4294967295 - 2 for /the/src/instrument_coverage.rs:14:13 - 14:18; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2
           _0 = const ();                   // scope 0 at /the/src/instrument_coverage.rs:+3:13: +3:18
           StorageDead(_2);                 // scope 0 at /the/src/instrument_coverage.rs:+4:9: +4:10
           return;                          // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2
       }
   
       bb5: {
-+         Coverage::Counter(2) for /the/src/instrument_coverage.rs:14:10 - 14:11; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
++         Coverage::Counter(2) for /the/src/instrument_coverage.rs:15:10 - 15:11; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
           _1 = const ();                   // scope 0 at /the/src/instrument_coverage.rs:+4:10: +4:10
           StorageDead(_2);                 // scope 0 at /the/src/instrument_coverage.rs:+4:9: +4:10
           goto -> bb1;                     // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6
diff --git a/src/test/mir-opt/instrument_coverage.rs b/src/test/mir-opt/instrument_coverage.rs
index a748f2c5ccc..7f6a0a0eb09 100644
--- a/src/test/mir-opt/instrument_coverage.rs
+++ b/src/test/mir-opt/instrument_coverage.rs
@@ -1,6 +1,7 @@
 // Test that `-C instrument-coverage` injects Coverage statements. The Coverage Counter statements
 // are later converted into LLVM instrprof.increment intrinsics, during codegen.
 
+// unit-test: InstrumentCoverage
 // needs-profiler-support
 // ignore-windows
 // compile-flags: -C instrument-coverage --remap-path-prefix={{src-base}}=/the/src
diff --git a/src/test/mir-opt/not_equal_false.rs b/src/test/mir-opt/not_equal_false.rs
index 5fbb848dcb5..2ae03da40f8 100644
--- a/src/test/mir-opt/not_equal_false.rs
+++ b/src/test/mir-opt/not_equal_false.rs
@@ -1,3 +1,4 @@
+// unit-test: InstCombine
 // EMIT_MIR not_equal_false.opt.InstCombine.diff
 
 fn opt(x: bool) -> u32 {
diff --git a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
index 750aaa88b1c..99667aabdae 100644
--- a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
+++ b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff
@@ -23,13 +23,6 @@
               scope 3 {
                   debug i => _12;          // in scope 3 at $DIR/remove_storage_markers.rs:+2:9: +2:10
               }
-              scope 5 (inlined iter::range::<impl Iterator for std::ops::Range<i32>>::next) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
-                  debug self => _8;        // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
-                  let mut _14: &mut std::ops::Range<i32>; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
-              }
-          }
-          scope 4 (inlined <std::ops::Range<i32> as IntoIterator>::into_iter) { // at $DIR/remove_storage_markers.rs:8:14: 8:19
-              debug self => _3;            // in scope 4 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
           }
       }
   
@@ -41,29 +34,39 @@
           Deinit(_3);                      // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
           (_3.0: i32) = const 0_i32;       // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
           (_3.1: i32) = const 10_i32;      // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
-          _2 = move _3;                    // scope 4 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
+          _2 = <std::ops::Range<i32> as IntoIterator>::into_iter(move _3) -> bb1; // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
+                                           // mir::Constant
+                                           // + span: $DIR/remove_storage_markers.rs:10:14: 10:19
+                                           // + literal: Const { ty: fn(std::ops::Range<i32>) -> <std::ops::Range<i32> as IntoIterator>::IntoIter {<std::ops::Range<i32> as IntoIterator>::into_iter}, val: Value(<ZST>) }
+      }
+  
+      bb1: {
 -         StorageDead(_3);                 // scope 1 at $DIR/remove_storage_markers.rs:+2:18: +2:19
 -         StorageLive(_4);                 // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
           _4 = move _2;                    // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19
-          goto -> bb1;                     // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6
+          goto -> bb2;                     // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6
       }
   
-      bb1: {
+      bb2: {
 -         StorageLive(_6);                 // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
 -         StorageLive(_7);                 // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
 -         StorageLive(_8);                 // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
 -         StorageLive(_9);                 // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
           _9 = &mut _4;                    // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
           _8 = &mut (*_9);                 // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
--         StorageLive(_14);                // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
-          _14 = &mut (*_8);                // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
-          _7 = <std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next(move _14) -> bb4; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
+          _7 = <std::ops::Range<i32> as Iterator>::next(move _8) -> bb3; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
                                            // mir::Constant
-                                           // + span: $SRC_DIR/core/src/iter/range.rs:LL:COL
-                                           // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> Option<<std::ops::Range<i32> as iter::range::RangeIteratorImpl>::Item> {<std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next}, val: Value(<ZST>) }
+                                           // + span: $DIR/remove_storage_markers.rs:10:14: 10:19
+                                           // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> Option<<std::ops::Range<i32> as Iterator>::Item> {<std::ops::Range<i32> as Iterator>::next}, val: Value(<ZST>) }
       }
   
-      bb2: {
+      bb3: {
+-         StorageDead(_8);                 // scope 2 at $DIR/remove_storage_markers.rs:+2:18: +2:19
+          _10 = discriminant(_7);          // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
+          switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
+      }
+  
+      bb4: {
 -         StorageLive(_12);                // scope 2 at $DIR/remove_storage_markers.rs:+2:9: +2:10
           _12 = ((_7 as Some).0: i32);     // scope 2 at $DIR/remove_storage_markers.rs:+2:9: +2:10
 -         StorageLive(_13);                // scope 3 at $DIR/remove_storage_markers.rs:+3:16: +3:17
@@ -76,10 +79,14 @@
 -         StorageDead(_7);                 // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6
 -         StorageDead(_6);                 // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6
           _5 = const ();                   // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6
-          goto -> bb1;                     // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6
+          goto -> bb2;                     // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6
       }
   
-      bb3: {
+      bb5: {
+          unreachable;                     // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
+      }
+  
+      bb6: {
           _0 = const ();                   // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6
 -         StorageDead(_9);                 // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6
 -         StorageDead(_7);                 // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6
@@ -89,12 +96,5 @@
 -         StorageDead(_1);                 // scope 0 at $DIR/remove_storage_markers.rs:+5:1: +5:2
           return;                          // scope 0 at $DIR/remove_storage_markers.rs:+5:2: +5:2
       }
-  
-      bb4: {
--         StorageDead(_14);                // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL
--         StorageDead(_8);                 // scope 2 at $DIR/remove_storage_markers.rs:+2:18: +2:19
-          _10 = discriminant(_7);          // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
-          switchInt(move _10) -> [0_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19
-      }
   }
   
diff --git a/src/test/mir-opt/remove_storage_markers.rs b/src/test/mir-opt/remove_storage_markers.rs
index c144d3ff795..f00b826911c 100644
--- a/src/test/mir-opt/remove_storage_markers.rs
+++ b/src/test/mir-opt/remove_storage_markers.rs
@@ -1,3 +1,5 @@
+// unit-test: RemoveStorageMarkers
+
 // Checks that storage markers are removed at opt-level=0.
 //
 // compile-flags: -C opt-level=0 -Coverflow-checks=off
diff --git a/src/test/mir-opt/remove_zsts_dont_touch_unions.rs b/src/test/mir-opt/remove_zsts_dont_touch_unions.rs
index 7a6f86b8085..8b9de9b4d65 100644
--- a/src/test/mir-opt/remove_zsts_dont_touch_unions.rs
+++ b/src/test/mir-opt/remove_zsts_dont_touch_unions.rs
@@ -1,4 +1,4 @@
-// compile-flags: -Zmir-opt-level=3
+// unit-test: RemoveZsts
 
 // Ensure RemoveZsts doesn't remove ZST assignments to union fields,
 // which causes problems in Miri.
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 451d0fe4c02..05554174ae2 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
@@ -80,7 +80,7 @@ fn array_casts() -> () {
         _7 = _2;                         // scope 3 at $DIR/retag.rs:+3:15: +3:16
         _6 = ptr::mut_ptr::<impl *mut usize>::add(move _7, const 1_usize) -> bb1; // scope 3 at $DIR/retag.rs:+3:15: +3:23
                                          // mir::Constant
-                                         // + span: $DIR/retag.rs:60:17: 60:20
+                                         // + span: $DIR/retag.rs:61:17: 61:20
                                          // + literal: Const { ty: unsafe fn(*mut usize, usize) -> *mut usize {ptr::mut_ptr::<impl *mut usize>::add}, val: Value(<ZST>) }
     }
 
@@ -111,7 +111,7 @@ fn array_casts() -> () {
         _17 = _9;                        // scope 6 at $DIR/retag.rs:+7:26: +7:27
         _16 = ptr::const_ptr::<impl *const usize>::add(move _17, const 1_usize) -> bb2; // scope 6 at $DIR/retag.rs:+7:26: +7:34
                                          // mir::Constant
-                                         // + span: $DIR/retag.rs:64:28: 64:31
+                                         // + span: $DIR/retag.rs:65:28: 65:31
                                          // + literal: Const { ty: unsafe fn(*const usize, usize) -> *const usize {ptr::const_ptr::<impl *const usize>::add}, val: Value(<ZST>) }
     }
 
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 ae6b5cfe21e..8802f3b2958 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
@@ -73,7 +73,7 @@ fn main() -> () {
         Retag([2phase] _6);              // scope 1 at $DIR/retag.rs:+3:29: +3:35
         _3 = Test::foo(move _4, move _6) -> [return: bb1, unwind: bb8]; // scope 1 at $DIR/retag.rs:+3:17: +3:36
                                          // mir::Constant
-                                         // + span: $DIR/retag.rs:32:25: 32:28
+                                         // + span: $DIR/retag.rs:33:25: 33:28
                                          // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x mut i32) -> &'x mut i32 {Test::foo}, val: Value(<ZST>) }
     }
 
@@ -149,7 +149,7 @@ fn main() -> () {
         StorageLive(_23);                // scope 7 at $DIR/retag.rs:+18:21: +18:23
         _28 = const main::promoted[0];   // scope 7 at $DIR/retag.rs:+18:21: +18:23
                                          // mir::Constant
-                                         // + span: $DIR/retag.rs:47:21: 47:23
+                                         // + span: $DIR/retag.rs:48:21: 48:23
                                          // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) }
         Retag(_28);                      // scope 7 at $DIR/retag.rs:+18:21: +18:23
         _23 = &(*_28);                   // scope 7 at $DIR/retag.rs:+18:21: +18:23
@@ -158,7 +158,7 @@ fn main() -> () {
         Retag(_22);                      // scope 7 at $DIR/retag.rs:+18:21: +18:23
         _19 = Test::foo_shr(move _20, move _22) -> [return: bb4, unwind: bb7]; // scope 7 at $DIR/retag.rs:+18:5: +18:24
                                          // mir::Constant
-                                         // + span: $DIR/retag.rs:47:13: 47:20
+                                         // + span: $DIR/retag.rs:48:13: 48:20
                                          // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x i32) -> &'x i32 {Test::foo_shr}, val: Value(<ZST>) }
     }
 
@@ -182,7 +182,7 @@ fn main() -> () {
         StorageLive(_27);                // scope 8 at $DIR/retag.rs:+23:5: +23:18
         _27 = array_casts() -> bb6;      // scope 8 at $DIR/retag.rs:+23:5: +23:18
                                          // mir::Constant
-                                         // + span: $DIR/retag.rs:52:5: 52:16
+                                         // + span: $DIR/retag.rs:53:5: 53:16
                                          // + literal: Const { ty: fn() {array_casts}, val: Value(<ZST>) }
     }
 
diff --git a/src/test/mir-opt/retag.rs b/src/test/mir-opt/retag.rs
index 13568b822d4..86deb0e7ccd 100644
--- a/src/test/mir-opt/retag.rs
+++ b/src/test/mir-opt/retag.rs
@@ -1,3 +1,4 @@
+// unit-test: AddRetag
 // ignore-wasm32-bare compiled with panic=abort by default
 // ignore-tidy-linelength
 // compile-flags: -Z mir-emit-retag -Z mir-opt-level=0 -Z span_free_formats
diff --git a/src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir
index e395fdb274f..25d400f0c9f 100644
--- a/src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir
+++ b/src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir
@@ -1,6 +1,6 @@
-// MIR for `<impl at $DIR/retag.rs:11:1: 11:10>::foo` after SimplifyCfg-elaborate-drops
+// MIR for `<impl at $DIR/retag.rs:12:1: 12:10>::foo` after SimplifyCfg-elaborate-drops
 
-fn <impl at $DIR/retag.rs:11:1: 11:10>::foo(_1: &Test, _2: &mut i32) -> &mut i32 {
+fn <impl at $DIR/retag.rs:12:1: 12:10>::foo(_1: &Test, _2: &mut i32) -> &mut i32 {
     debug self => _1;                    // in scope 0 at $DIR/retag.rs:+0:16: +0:21
     debug x => _2;                       // in scope 0 at $DIR/retag.rs:+0:23: +0:24
     let mut _0: &mut i32;                // return place in scope 0 at $DIR/retag.rs:+0:42: +0:53
diff --git a/src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir
index e609166dec8..84ad8afc357 100644
--- a/src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir
+++ b/src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir
@@ -1,6 +1,6 @@
-// MIR for `<impl at $DIR/retag.rs:11:1: 11:10>::foo_shr` after SimplifyCfg-elaborate-drops
+// MIR for `<impl at $DIR/retag.rs:12:1: 12:10>::foo_shr` after SimplifyCfg-elaborate-drops
 
-fn <impl at $DIR/retag.rs:11:1: 11:10>::foo_shr(_1: &Test, _2: &i32) -> &i32 {
+fn <impl at $DIR/retag.rs:12:1: 12:10>::foo_shr(_1: &Test, _2: &i32) -> &i32 {
     debug self => _1;                    // in scope 0 at $DIR/retag.rs:+0:20: +0:25
     debug x => _2;                       // in scope 0 at $DIR/retag.rs:+0:27: +0:28
     let mut _0: &i32;                    // return place in scope 0 at $DIR/retag.rs:+0:42: +0:49
diff --git a/src/test/mir-opt/simplify-locals-removes-unused-consts.rs b/src/test/mir-opt/simplify-locals-removes-unused-consts.rs
index 17999454472..39b7911d4ae 100644
--- a/src/test/mir-opt/simplify-locals-removes-unused-consts.rs
+++ b/src/test/mir-opt/simplify-locals-removes-unused-consts.rs
@@ -1,3 +1,4 @@
+// unit-test: SimplifyLocals
 // compile-flags: -C overflow-checks=no
 
 fn use_zst(_: ((), ())) {}
diff --git a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff
index da2f6fc440a..b41527ba02d 100644
--- a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff
+++ b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff
@@ -16,29 +16,53 @@
 -     let mut _11: Temp;                   // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
 +     let _1: ();                          // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
 +     let mut _2: ((), ());                // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
-+     let _3: ();                          // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
++     let mut _3: ();                      // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
++     let mut _4: ();                      // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
++     let _5: ();                          // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
++     let mut _6: u8;                      // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
++     let mut _7: u8;                      // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
++     let mut _8: Temp;                    // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
       scope 1 {
       }
   
       bb0: {
 -         StorageLive(_1);                 // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28
 -         StorageLive(_2);                 // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:21: +1:23
+-         Deinit(_2);                      // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:21: +1:23
 -         StorageLive(_3);                 // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:25: +1:27
+-         Deinit(_3);                      // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:25: +1:27
+-         Deinit(_1);                      // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28
+-         (_1.0: ()) = move _2;            // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28
+-         (_1.1: ()) = move _3;            // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28
 -         StorageDead(_3);                 // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:27: +1:28
 -         StorageDead(_2);                 // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:27: +1:28
 -         StorageDead(_1);                 // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:28: +1:29
 -         StorageLive(_4);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
 -         StorageLive(_5);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
 -         StorageLive(_6);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
+-         Deinit(_6);                      // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
 -         StorageLive(_7);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
+-         Deinit(_7);                      // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
+-         Deinit(_5);                      // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
+-         (_5.0: ()) = move _6;            // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
+-         (_5.1: ()) = move _7;            // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
 -         StorageDead(_7);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21
 -         StorageDead(_6);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21
 -         _4 = use_zst(move _5) -> bb1;    // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
 +         StorageLive(_1);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
 +         StorageLive(_2);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
++         StorageLive(_3);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
++         Deinit(_3);                      // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
++         StorageLive(_4);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
++         Deinit(_4);                      // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
++         Deinit(_2);                      // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
++         (_2.0: ()) = move _3;            // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
++         (_2.1: ()) = move _4;            // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
++         StorageDead(_4);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21
++         StorageDead(_3);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21
 +         _1 = use_zst(move _2) -> bb1;    // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
                                            // mir::Constant
-                                           // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:12
+                                           // + span: $DIR/simplify-locals-removes-unused-consts.rs:15:5: 15:12
                                            // + literal: Const { ty: fn(((), ())) {use_zst}, val: Value(<ZST>) }
       }
   
@@ -49,22 +73,36 @@
 -         StorageLive(_9);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
 -         StorageLive(_10);                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
 -         StorageLive(_11);                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
+-         Deinit(_11);                     // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
+-         (_11.0: u8) = const 40_u8;       // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
+-         _10 = (_11.0: u8);               // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
+-         _9 = Add(move _10, const 2_u8);  // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
 -         StorageDead(_10);                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:33: +4:34
--         _8 = use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
+-         _8 = use_u8(move _9) -> bb2;     // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
 +         StorageDead(_2);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:21: +2:22
 +         StorageDead(_1);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:22: +2:23
-+         StorageLive(_3);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
-+         _3 = use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
++         StorageLive(_5);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
++         StorageLive(_6);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
++         StorageLive(_7);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
++         StorageLive(_8);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
++         Deinit(_8);                      // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
++         (_8.0: u8) = const 40_u8;        // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
++         _7 = (_8.0: u8);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
++         _6 = Add(move _7, const 2_u8);   // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
++         StorageDead(_7);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:33: +4:34
++         _5 = use_u8(move _6) -> bb2;     // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
                                            // mir::Constant
-                                           // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:11
+                                           // + span: $DIR/simplify-locals-removes-unused-consts.rs:17:5: 17:11
                                            // + literal: Const { ty: fn(u8) {use_u8}, val: Value(<ZST>) }
       }
   
       bb2: {
 -         StorageDead(_9);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:34: +4:35
 -         StorageDead(_11);                // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36
--         StorageDead(_8);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36
-+         StorageDead(_3);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36
++         StorageDead(_6);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:34: +4:35
+          StorageDead(_8);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36
++         StorageDead(_5);                 // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36
+          _0 = const ();                   // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+0:11: +5:2
           return;                          // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+5:2: +5:2
       }
   }
diff --git a/src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs b/src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs
index 2f740dc4fac..a2c7a31b7c3 100644
--- a/src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs
+++ b/src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs
@@ -1,6 +1,5 @@
 // run-pass
 
-#![feature(backtrace)]
 #[derive(Clone, Copy)]
 struct Foo {
     array: [u64; 10240],
diff --git a/src/test/run-make/coverage-llvmir/filecheck.testprog.txt b/src/test/run-make/coverage-llvmir/filecheck.testprog.txt
index 7a5f2192277..c943261d799 100644
--- a/src/test/run-make/coverage-llvmir/filecheck.testprog.txt
+++ b/src/test/run-make/coverage-llvmir/filecheck.testprog.txt
@@ -9,7 +9,7 @@ CHECK-SAME:   section "[[INSTR_PROF_COVFUN]]"[[COMDAT_IF_SUPPORTED]], align 8
 CHECK:        @__llvm_coverage_mapping = private constant
 CHECK-SAME:   section "[[INSTR_PROF_COVMAP]]", align 8
 
-WINDOWS:      @__llvm_profile_runtime = external global i32
+WINDOWS:      @__llvm_profile_runtime = external{{.*}}global i32
 
 CHECK:        @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global
 CHECK-SAME:   section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8
diff --git a/src/test/rustdoc-gui/label-next-to-symbol.goml b/src/test/rustdoc-gui/label-next-to-symbol.goml
index ca3994a08b2..f9081189a86 100644
--- a/src/test/rustdoc-gui/label-next-to-symbol.goml
+++ b/src/test/rustdoc-gui/label-next-to-symbol.goml
@@ -7,14 +7,14 @@ size: (1080, 600)
 assert: (".stab.deprecated")
 assert: (".stab.portability")
 
-// make sure that deprecated and portability are different colours
+// make sure that deprecated and portability have the right colors
 assert-css: (
     ".item-table .item-left .stab.deprecated",
-    { "background-color": "rgb(255, 196, 196)" },
+    { "background-color": "rgb(255, 245, 214)" },
 )
 assert-css: (
     ".item-table .item-left .stab.portability",
-    { "background-color": "rgb(243, 223, 255)" },
+    { "background-color": "rgb(255, 245, 214)" },
 )
 
 // table like view
@@ -51,7 +51,7 @@ assert-css: (".item-right.docblock-short", { "padding-left": "32px" })
 compare-elements-position-near: (
     "//*[@class='item-left module-item']//a[text()='replaced_function']",
     ".item-left .stab.deprecated",
-    {"y": 1},
+    {"y": 2},
 )
 compare-elements-position: (
     ".item-left .stab.deprecated",
diff --git a/src/test/rustdoc-gui/pocket-menu.goml b/src/test/rustdoc-gui/pocket-menu.goml
index 54f3790a765..782526e29f4 100644
--- a/src/test/rustdoc-gui/pocket-menu.goml
+++ b/src/test/rustdoc-gui/pocket-menu.goml
@@ -71,7 +71,7 @@ reload:
 click: "#help-button"
 assert-css: (
     "#help-button .popover",
-    {"display": "block", "border-color": "rgb(221, 221, 221)"},
+    {"display": "block", "border-color": "rgb(224, 224, 224)"},
 )
 compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"])
 compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"])
diff --git a/src/test/rustdoc-gui/search-filter.goml b/src/test/rustdoc-gui/search-filter.goml
index d645e237061..b12eddfd12a 100644
--- a/src/test/rustdoc-gui/search-filter.goml
+++ b/src/test/rustdoc-gui/search-filter.goml
@@ -40,7 +40,7 @@ press-key: "ArrowUp"
 press-key: "Enter"
 // Waiting for the search results to appear...
 wait-for: "#titles"
-assert-property: ("#crate-search", {"value": "All crates"})
+assert-property: ("#crate-search", {"value": "all crates"})
 
 // Checking that the URL parameter is taken into account for crate filtering.
 goto: file://|DOC_PATH|/test_docs/index.html?search=test&filter-crate=lib2
@@ -48,8 +48,8 @@ wait-for: "#crate-search"
 assert-property: ("#crate-search", {"value": "lib2"})
 assert-false: "#results .externcrate"
 
-// Checking that the text for the "title" is correct (the "All" comes from the "<select>").
-assert-text: ("#search-settings", "Results for test in All", STARTS_WITH)
+// Checking that the text for the "title" is correct (the "all crates" comes from the "<select>").
+assert-text: (".search-results-title", "Results in all crates", STARTS_WITH)
 
 // Checking the display of the crate filter.
 // We start with the light theme.
@@ -69,15 +69,15 @@ click: "#settings-menu"
 wait-for: "#settings"
 click: "#theme-dark"
 wait-for-css: ("#crate-search", {
-    "border": "1px solid rgb(240, 240, 240)",
-    "color": "rgb(17, 17, 17)",
-    "background-color": "rgb(240, 240, 240)",
+    "border": "1px solid rgb(210, 210, 210)",
+    "color": "rgb(221, 221, 221)",
+    "background-color": "rgb(53, 53, 53)",
 })
 
 // And finally we check the ayu theme.
 click: "#theme-ayu"
 wait-for-css: ("#crate-search", {
-    "border": "1px solid rgb(66, 76, 87)",
-    "color": "rgb(197, 197, 197)",
-    "background-color": "rgb(20, 25, 32)",
+    "border": "1px solid rgb(92, 103, 115)",
+    "color": "rgb(255, 255, 255)",
+    "background-color": "rgb(15, 20, 25)",
 })
diff --git a/src/test/rustdoc-gui/search-result-display.goml b/src/test/rustdoc-gui/search-result-display.goml
index 8464ba7c23c..db4907924fa 100644
--- a/src/test/rustdoc-gui/search-result-display.goml
+++ b/src/test/rustdoc-gui/search-result-display.goml
@@ -4,7 +4,7 @@ size: (900, 1000)
 write: (".search-input", "test")
 // To be SURE that the search will be run.
 press-key: 'Enter'
-wait-for: "#search-settings"
+wait-for: "#crate-search"
 // The width is returned by "getComputedStyle" which returns the exact number instead of the
 // CSS rule which is "50%"...
 assert-css: (".search-results div.desc", {"width": "295px"})
@@ -17,13 +17,9 @@ assert-css: (".search-results div.desc", {"width": "570px"})
 // To do so we need to update the length of one of its `<option>`.
 size: (900, 900)
 
-// First we check the current width and position.
-assert-css: ("#crate-search", {"width": "218px"})
-compare-elements-position-near: (
-    "#crate-search",
-    "#search-settings .search-results-title",
-    {"y": 5},
-)
+// First we check the current width, height and position.
+assert-css: ("#crate-search", {"width": "223px"})
+assert-css: (".search-results-title", {"height": "44px", "width": "336px"})
 
 // Then we update the text of one of the `<option>`.
 text: (
@@ -31,12 +27,8 @@ text: (
     "sdjfaksdjfaksjdbfkadsbfkjsadbfkdsbkfbsadkjfbkdsabfkadsfkjdsafa",
 )
 
-// Then we compare again.
-assert-css: ("#crate-search", {"width": "640px"})
-compare-elements-position-near-false: (
-    "#crate-search",
-    "#search-settings .search-results-title",
-    {"y": 5},
-)
-// And we check that the `<select>` isn't bigger than its container.
+// Then we compare again to confirm the height didn't change.
+assert-css: ("#crate-search", {"width": "527px"})
+assert-css: (".search-results-title", {"height": "44px", "width": "640px"})
+// And we check that the `<select>` isn't bigger than its container (".search-results-title").
 assert-css: ("#search", {"width": "640px"})
diff --git a/src/test/rustdoc-gui/sidebar-mobile-scroll.goml b/src/test/rustdoc-gui/sidebar-mobile-scroll.goml
new file mode 100644
index 00000000000..b3bcea25338
--- /dev/null
+++ b/src/test/rustdoc-gui/sidebar-mobile-scroll.goml
@@ -0,0 +1,31 @@
+// This test ensures that the mobile sidebar preserves scroll position.
+goto: file://|DOC_PATH|/test_docs/struct.Foo.html
+// Switching to "mobile view" by reducing the width to 600px.
+size: (600, 600)
+assert-css: (".sidebar", {"display": "block", "left": "-1000px"})
+
+// Scroll down.
+scroll-to: "//h2[@id='blanket-implementations']"
+assert-window-property: {"pageYOffset": "702"}
+
+// Open the sidebar menu.
+click: ".sidebar-menu-toggle"
+wait-for-css: (".sidebar", {"left": "0px"})
+
+// We are no longer "scrolled". It's important that the user can't
+// scroll the body at all, but these test scripts are run only in Chrome,
+// and we need to use a more complicated solution to this problem because
+// of Mobile Safari...
+assert-window-property: {"pageYOffset": "0"}
+
+// Close the sidebar menu. Make sure the scroll position gets restored.
+click: ".sidebar-menu-toggle"
+wait-for-css: (".sidebar", {"left": "-1000px"})
+assert-window-property: {"pageYOffset": "702"}
+
+// Now test that scrollability returns when the browser window is just resized.
+click: ".sidebar-menu-toggle"
+wait-for-css: (".sidebar", {"left": "0px"})
+assert-window-property: {"pageYOffset": "0"}
+size: (900, 900)
+assert-window-property: {"pageYOffset": "702"}
diff --git a/src/test/rustdoc-gui/sidebar-source-code-display.goml b/src/test/rustdoc-gui/sidebar-source-code-display.goml
index fa322574fde..e4662a10ed5 100644
--- a/src/test/rustdoc-gui/sidebar-source-code-display.goml
+++ b/src/test/rustdoc-gui/sidebar-source-code-display.goml
@@ -233,6 +233,17 @@ wait-for-css: (".sidebar", {"width": "0px"})
 // The "scrollTop" property should be the same.
 assert-window-property: {"pageYOffset": "2519"}
 
+// We now check that the scroll position is restored if the window is resized.
+size: (500, 700)
+click: "#sidebar-toggle"
+wait-for-css: ("#source-sidebar", {"visibility": "visible"})
+assert-window-property: {"pageYOffset": "0"}
+size: (900, 900)
+assert-window-property: {"pageYOffset": "2519"}
+size: (500, 700)
+click: "#sidebar-toggle"
+wait-for-css: ("#source-sidebar", {"visibility": "hidden"})
+
 // We now check that opening the sidebar and clicking a link will close it.
 // The behavior here on mobile is different than the behavior on desktop,
 // but common sense dictates that if you have a list of files that fills the entire screen, and
diff --git a/src/test/rustdoc-json/primitive.rs b/src/test/rustdoc-json/primitive.rs
index b84c2f7c6ac..8d1141b5864 100644
--- a/src/test/rustdoc-json/primitive.rs
+++ b/src/test/rustdoc-json/primitive.rs
@@ -7,8 +7,14 @@ mod usize {}
 
 // @set local_crate_id = primitive.json "$.index[*][?(@.name=='primitive')].crate_id"
 
-// @has - "$.index[*][?(@.name=='log10')]"
-// @!is - "$.index[*][?(@.name=='log10')].crate_id" $local_crate_id
+// @has - "$.index[*][?(@.name=='ilog10')]"
+// @!is - "$.index[*][?(@.name=='ilog10')].crate_id" $local_crate_id
 // @has - "$.index[*][?(@.name=='checked_add')]"
 // @!is - "$.index[*][?(@.name=='checked_add')]" $local_crate_id
 // @!has - "$.index[*][?(@.name=='is_ascii_uppercase')]"
+
+// @is - "$.index[*][?(@.kind=='import' && @.inner.name=='my_i32')].inner.id" null
+pub use i32 as my_i32;
+
+// @is - "$.index[*][?(@.kind=='import' && @.inner.name=='u32')].inner.id" null
+pub use u32;
diff --git a/src/test/rustdoc-ui/z-help.stdout b/src/test/rustdoc-ui/z-help.stdout
index 6dc41231559..236469ce979 100644
--- a/src/test/rustdoc-ui/z-help.stdout
+++ b/src/test/rustdoc-ui/z-help.stdout
@@ -38,6 +38,7 @@
     -Z                        emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
     -Z                           emit-thin-lto=val -- emit the bc module with thin LTO info (default: yes)
     -Z               export-executable-symbols=val -- export symbols from executables, as if they were dynamic libraries
+    -Z                   extra-const-ub-checks=val -- turns on more checks to detect const UB, which can be slow (default: no)
     -Z                             fewer-names=val -- reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) (default: no)
     -Z              force-unstable-if-unmarked=val -- force all crates to be `rustc_private` unstable (default: no)
     -Z                                    fuel=val -- set the optimization fuel quota for a crate
diff --git a/src/test/rustdoc/empty-impl-block-private-with-doc.rs b/src/test/rustdoc/empty-impl-block-private-with-doc.rs
new file mode 100644
index 00000000000..43971996163
--- /dev/null
+++ b/src/test/rustdoc/empty-impl-block-private-with-doc.rs
@@ -0,0 +1,44 @@
+// compile-flags: --document-private-items
+
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+#![crate_name = "foo"]
+
+// @has 'foo/struct.Foo.html'
+pub struct Foo;
+
+// There are 3 impl blocks with public item and one that should not be displayed
+// by default because it only contains private items (but not in this case because
+// we used `--document-private-items`).
+// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 4
+
+// Impl block only containing private items should not be displayed unless the
+// `--document-private-items` flag is used.
+/// Private
+impl Foo {
+    const BAR: u32 = 0;
+    type FOO = i32;
+    fn hello() {}
+}
+
+// But if any element of the impl block is public, it should be displayed.
+/// Not private
+impl Foo {
+    pub const BAR: u32 = 0;
+    type FOO = i32;
+    fn hello() {}
+}
+
+/// Not private
+impl Foo {
+    const BAR: u32 = 0;
+    pub type FOO = i32;
+    fn hello() {}
+}
+
+/// Not private
+impl Foo {
+    const BAR: u32 = 0;
+    type FOO = i32;
+    pub fn hello() {}
+}
diff --git a/src/test/rustdoc/empty-impl-block-private.rs b/src/test/rustdoc/empty-impl-block-private.rs
new file mode 100644
index 00000000000..5caf020658c
--- /dev/null
+++ b/src/test/rustdoc/empty-impl-block-private.rs
@@ -0,0 +1,40 @@
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+#![crate_name = "foo"]
+
+// @has 'foo/struct.Foo.html'
+pub struct Foo;
+
+// There are 3 impl blocks with public item and one that should not be displayed
+// because it only contains private items.
+// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 3
+
+// Impl block only containing private items should not be displayed.
+/// Private
+impl Foo {
+    const BAR: u32 = 0;
+    type FOO = i32;
+    fn hello() {}
+}
+
+// But if any element of the impl block is public, it should be displayed.
+/// Not private
+impl Foo {
+    pub const BAR: u32 = 0;
+    type FOO = i32;
+    fn hello() {}
+}
+
+/// Not private
+impl Foo {
+    const BAR: u32 = 0;
+    pub type FOO = i32;
+    fn hello() {}
+}
+
+/// Not private
+impl Foo {
+    const BAR: u32 = 0;
+    type FOO = i32;
+    pub fn hello() {}
+}
diff --git a/src/test/rustdoc/intra-doc/assoc-reexport-super.rs b/src/test/rustdoc/intra-doc/assoc-reexport-super.rs
new file mode 100644
index 00000000000..a7bc1c6a29f
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/assoc-reexport-super.rs
@@ -0,0 +1,20 @@
+// Regression test for #93205
+
+#![crate_name = "foo"]
+
+mod generated {
+    pub struct MyNewType;
+    impl MyNewType {
+        pub const FOO: Self = Self;
+    }
+}
+
+pub use generated::MyNewType;
+
+mod prelude {
+    impl super::MyNewType {
+        /// An alias for [`Self::FOO`].
+        // @has 'foo/struct.MyNewType.html' '//a[@href="struct.MyNewType.html#associatedconstant.FOO"]' 'Self::FOO'
+        pub const FOO2: Self = Self::FOO;
+    }
+}
diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
index a679b7b4e19..0d9c9350efc 100644
--- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
+++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs
@@ -74,10 +74,10 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
             2 => {
                 let seg = PathSegment::from_ident(Ident::from_str("x"));
                 iter_exprs(depth - 1, &mut |e| {
-                    g(ExprKind::MethodCall(seg.clone(), vec![e, make_x()], DUMMY_SP))
+                    g(ExprKind::MethodCall(seg.clone(), e, vec![make_x()], DUMMY_SP))
                 });
                 iter_exprs(depth - 1, &mut |e| {
-                    g(ExprKind::MethodCall(seg.clone(), vec![make_x(), e], DUMMY_SP))
+                    g(ExprKind::MethodCall(seg.clone(), make_x(), vec![e], DUMMY_SP))
                 });
             }
             3..=8 => {
diff --git a/src/test/ui/associated-types/issue-22560.stderr b/src/test/ui/associated-types/issue-22560.stderr
index 700923c1b3f..2b88cf0b441 100644
--- a/src/test/ui/associated-types/issue-22560.stderr
+++ b/src/test/ui/associated-types/issue-22560.stderr
@@ -1,25 +1,3 @@
-error[E0393]: the type parameter `Rhs` must be explicitly specified
-  --> $DIR/issue-22560.rs:9:23
-   |
-LL | trait Sub<Rhs=Self> {
-   | ------------------- type parameter `Rhs` must be specified for this
-...
-LL | type Test = dyn Add + Sub;
-   |                       ^^^ help: set the type parameter to the desired type: `Sub<Rhs>`
-   |
-   = note: because of the default `Self` reference, type parameters must be specified on object types
-
-error[E0393]: the type parameter `Rhs` must be explicitly specified
-  --> $DIR/issue-22560.rs:9:17
-   |
-LL | trait Add<Rhs=Self> {
-   | ------------------- type parameter `Rhs` must be specified for this
-...
-LL | type Test = dyn Add + Sub;
-   |                 ^^^ help: set the type parameter to the desired type: `Add<Rhs>`
-   |
-   = note: because of the default `Self` reference, type parameters must be specified on object types
-
 error[E0225]: only auto traits can be used as additional traits in a trait object
   --> $DIR/issue-22560.rs:9:23
    |
@@ -28,7 +6,7 @@ LL | type Test = dyn Add + Sub;
    |                 |
    |                 first non-auto trait
    |
-   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add<[type error]> + Sub<[type error]> {}`
+   = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add + Sub {}`
    = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits>
 
 error[E0191]: the value of the associated types `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified
@@ -50,6 +28,28 @@ help: specify the associated types
 LL | type Test = dyn Add<Output = Type> + Sub<Output = Type>;
    |                 ~~~~~~~~~~~~~~~~~~   ~~~~~~~~~~~~~~~~~~
 
+error[E0393]: the type parameter `Rhs` must be explicitly specified
+  --> $DIR/issue-22560.rs:9:17
+   |
+LL | trait Add<Rhs=Self> {
+   | ------------------- type parameter `Rhs` must be specified for this
+...
+LL | type Test = dyn Add + Sub;
+   |                 ^^^ help: set the type parameter to the desired type: `Add<Rhs>`
+   |
+   = note: because of the default `Self` reference, type parameters must be specified on object types
+
+error[E0393]: the type parameter `Rhs` must be explicitly specified
+  --> $DIR/issue-22560.rs:9:23
+   |
+LL | trait Sub<Rhs=Self> {
+   | ------------------- type parameter `Rhs` must be specified for this
+...
+LL | type Test = dyn Add + Sub;
+   |                       ^^^ help: set the type parameter to the desired type: `Sub<Rhs>`
+   |
+   = note: because of the default `Self` reference, type parameters must be specified on object types
+
 error: aborting due to 4 previous errors
 
 Some errors have detailed explanations: E0191, E0225, E0393.
diff --git a/src/test/ui/associated-types/issue-59324.rs b/src/test/ui/associated-types/issue-59324.rs
index 162f9e00edd..9e68e9e7751 100644
--- a/src/test/ui/associated-types/issue-59324.rs
+++ b/src/test/ui/associated-types/issue-59324.rs
@@ -15,9 +15,9 @@ pub trait ThriftService<Bug: NotFoo>:
 {
     fn get_service(
     //~^ ERROR the trait bound `Bug: Foo` is not satisfied
+    //~| ERROR the trait bound `Bug: Foo` is not satisfied
         &self,
     ) -> Self::AssocType;
-    //~^ the trait bound `Bug: Foo` is not satisfied
 }
 
 fn with_factory<H>(factory: dyn ThriftService<()>) {}
diff --git a/src/test/ui/associated-types/issue-59324.stderr b/src/test/ui/associated-types/issue-59324.stderr
index a84b599b52b..dd5ec7175b5 100644
--- a/src/test/ui/associated-types/issue-59324.stderr
+++ b/src/test/ui/associated-types/issue-59324.stderr
@@ -20,7 +20,7 @@ LL | |
 LL | |
 LL | |     Service<AssocType = <Bug as Foo>::OnlyFoo>
 ...  |
-LL | |
+LL | |     ) -> Self::AssocType;
 LL | | }
    | |_^ the trait `Foo` is not implemented for `Bug`
    |
@@ -34,6 +34,7 @@ error[E0277]: the trait bound `Bug: Foo` is not satisfied
    |
 LL | /     fn get_service(
 LL | |
+LL | |
 LL | |         &self,
 LL | |     ) -> Self::AssocType;
    | |_________________________^ the trait `Foo` is not implemented for `Bug`
@@ -50,10 +51,10 @@ LL | fn with_factory<H>(factory: dyn ThriftService<()>) {}
    |                             ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()`
 
 error[E0277]: the trait bound `Bug: Foo` is not satisfied
-  --> $DIR/issue-59324.rs:19:10
+  --> $DIR/issue-59324.rs:16:8
    |
-LL |     ) -> Self::AssocType;
-   |          ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
+LL |     fn get_service(
+   |        ^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug`
    |
 help: consider further restricting this bound
    |
diff --git a/src/test/ui/backtrace-apple-no-dsymutil.rs b/src/test/ui/backtrace-apple-no-dsymutil.rs
index d32ad11a122..3844ebcfd30 100644
--- a/src/test/ui/backtrace-apple-no-dsymutil.rs
+++ b/src/test/ui/backtrace-apple-no-dsymutil.rs
@@ -4,8 +4,6 @@
 // compile-flags:-g -Csplit-debuginfo=unpacked
 // only-macos
 
-#![feature(backtrace)]
-
 use std::process::Command;
 use std::str;
 
diff --git a/src/test/ui/cfg/cfg-method-receiver.rs b/src/test/ui/cfg/cfg-method-receiver.rs
new file mode 100644
index 00000000000..78a072f503f
--- /dev/null
+++ b/src/test/ui/cfg/cfg-method-receiver.rs
@@ -0,0 +1,12 @@
+macro_rules! cbor_map {
+    ($key:expr) => {
+        $key.signum();
+        //~^ ERROR can't call method `signum` on ambiguous numeric type `{integer}` [E0689]
+    };
+}
+
+fn main() {
+    cbor_map! { #[cfg(test)] 4};
+    //~^ ERROR attributes on expressions are experimental
+    //~| ERROR removing an expression is not supported in this position
+}
diff --git a/src/test/ui/cfg/cfg-method-receiver.stderr b/src/test/ui/cfg/cfg-method-receiver.stderr
new file mode 100644
index 00000000000..517fc8168e7
--- /dev/null
+++ b/src/test/ui/cfg/cfg-method-receiver.stderr
@@ -0,0 +1,34 @@
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/cfg-method-receiver.rs:9:17
+   |
+LL |     cbor_map! { #[cfg(test)] 4};
+   |                 ^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error: removing an expression is not supported in this position
+  --> $DIR/cfg-method-receiver.rs:9:17
+   |
+LL |     cbor_map! { #[cfg(test)] 4};
+   |                 ^^^^^^^^^^^^
+
+error[E0689]: can't call method `signum` on ambiguous numeric type `{integer}`
+  --> $DIR/cfg-method-receiver.rs:3:14
+   |
+LL |         $key.signum();
+   |              ^^^^^^
+...
+LL |     cbor_map! { #[cfg(test)] 4};
+   |     --------------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `cbor_map` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: you must specify a concrete type for this numeric value, like `i32`
+   |
+LL |     cbor_map! { #[cfg(test)] 4_i32};
+   |                              ~~~~~
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0658, E0689.
+For more information about an error, try `rustc --explain E0658`.
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-100217.rs b/src/test/ui/const-generics/generic_const_exprs/issue-100217.rs
new file mode 100644
index 00000000000..acdc348a385
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-100217.rs
@@ -0,0 +1,42 @@
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+trait TraitOne {
+    const MY_NUM: usize;
+    type MyErr: std::fmt::Debug;
+
+    fn do_one_stuff(arr: [u8; Self::MY_NUM]) -> Result<(), Self::MyErr>;
+}
+
+trait TraitTwo {
+    fn do_two_stuff();
+}
+
+impl<O: TraitOne> TraitTwo for O
+where
+    [(); Self::MY_NUM]:,
+{
+    fn do_two_stuff() {
+        O::do_one_stuff([5; Self::MY_NUM]).unwrap()
+    }
+}
+
+struct Blargotron;
+
+#[derive(Debug)]
+struct ErrTy<const N: usize>([(); N]);
+
+impl TraitOne for Blargotron {
+    const MY_NUM: usize = 3;
+    type MyErr = ErrTy<{ Self::MY_NUM }>;
+
+    fn do_one_stuff(_arr: [u8; Self::MY_NUM]) -> Result<(), Self::MyErr> {
+        Ok(())
+    }
+}
+
+fn main() {
+    Blargotron::do_two_stuff();
+}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-73298.rs b/src/test/ui/const-generics/generic_const_exprs/issue-73298.rs
new file mode 100644
index 00000000000..3c59e1b790a
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-73298.rs
@@ -0,0 +1,23 @@
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+use std::convert::AsMut;
+use std::default::Default;
+
+trait Foo: Sized {
+    type Baz: Default + AsMut<[u8]>;
+    fn bar() {
+        Self::Baz::default().as_mut();
+    }
+}
+
+impl Foo for () {
+    type Baz = [u8; 1 * 1];
+    //type Baz = [u8; 1];
+}
+
+fn main() {
+    <() as Foo>::bar();
+}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-82268.rs b/src/test/ui/const-generics/generic_const_exprs/issue-82268.rs
new file mode 100644
index 00000000000..d08fc5beb75
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-82268.rs
@@ -0,0 +1,73 @@
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+trait Collate<Op> {
+    type Pass;
+    type Fail;
+
+    fn collate(self) -> (Self::Pass, Self::Fail);
+}
+
+impl<Op> Collate<Op> for () {
+    type Pass = ();
+    type Fail = ();
+
+    fn collate(self) -> ((), ()) {
+        ((), ())
+    }
+}
+
+trait CollateStep<X, Prev> {
+    type Pass;
+    type Fail;
+    fn collate_step(x: X, prev: Prev) -> (Self::Pass, Self::Fail);
+}
+
+impl<X, P, F> CollateStep<X, (P, F)> for () {
+    type Pass = (X, P);
+    type Fail = F;
+
+    fn collate_step(x: X, (p, f): (P, F)) -> ((X, P), F) {
+        ((x, p), f)
+    }
+}
+
+struct CollateOpImpl<const MASK: u32>;
+trait CollateOpStep {
+    type NextOp;
+    type Apply;
+}
+
+impl<const MASK: u32> CollateOpStep for CollateOpImpl<MASK>
+where
+    CollateOpImpl<{ MASK >> 1 }>: Sized,
+{
+    type NextOp = CollateOpImpl<{ MASK >> 1 }>;
+    type Apply = ();
+}
+
+impl<H, T, Op: CollateOpStep> Collate<Op> for (H, T)
+where
+    T: Collate<Op::NextOp>,
+    Op::Apply: CollateStep<H, (T::Pass, T::Fail)>,
+{
+    type Pass = <Op::Apply as CollateStep<H, (T::Pass, T::Fail)>>::Pass;
+    type Fail = <Op::Apply as CollateStep<H, (T::Pass, T::Fail)>>::Fail;
+
+    fn collate(self) -> (Self::Pass, Self::Fail) {
+        <Op::Apply as CollateStep<H, (T::Pass, T::Fail)>>::collate_step(self.0, self.1.collate())
+    }
+}
+
+fn collate<X, const MASK: u32>(x: X) -> (X::Pass, X::Fail)
+where
+    X: Collate<CollateOpImpl<MASK>>,
+{
+    x.collate()
+}
+
+fn main() {
+    dbg!(collate::<_, 5>(("Hello", (42, ('!', ())))));
+}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-83972.rs b/src/test/ui/const-generics/generic_const_exprs/issue-83972.rs
new file mode 100644
index 00000000000..0063719b852
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-83972.rs
@@ -0,0 +1,38 @@
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+pub trait Foo {
+    fn foo(&self);
+}
+
+pub struct FooImpl<const N: usize>;
+impl<const N: usize> Foo for FooImpl<N> {
+    fn foo(&self) {}
+}
+
+pub trait Bar: 'static {
+    type Foo: Foo;
+    fn get() -> &'static Self::Foo;
+}
+
+struct BarImpl;
+impl Bar for BarImpl {
+    type Foo = FooImpl<
+        {
+            { 4 }
+        },
+    >;
+    fn get() -> &'static Self::Foo {
+        &FooImpl
+    }
+}
+
+pub fn boom<B: Bar>() {
+    B::get().foo();
+}
+
+fn main() {
+    boom::<BarImpl>();
+}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-84669.rs b/src/test/ui/const-generics/generic_const_exprs/issue-84669.rs
new file mode 100644
index 00000000000..3933ff20a49
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-84669.rs
@@ -0,0 +1,30 @@
+// build-pass
+
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+trait Foo {
+    type Output;
+
+    fn foo() -> Self::Output;
+}
+
+impl Foo for [u8; 3] {
+    type Output = [u8; 1 + 2];
+
+    fn foo() -> [u8; 3] {
+        [1u8; 3]
+    }
+}
+
+fn bug<const N: usize>()
+where
+    [u8; N]: Foo,
+    <[u8; N] as Foo>::Output: AsRef<[u8]>,
+{
+    <[u8; N]>::foo().as_ref();
+}
+
+fn main() {
+    bug::<3>();
+}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-86710.rs b/src/test/ui/const-generics/generic_const_exprs/issue-86710.rs
new file mode 100644
index 00000000000..bdd8a21b3b9
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-86710.rs
@@ -0,0 +1,73 @@
+// build-pass
+
+#![allow(incomplete_features)]
+#![feature(generic_const_exprs)]
+
+use std::marker::PhantomData;
+
+fn main() {
+    let x = FooImpl::<BarImpl<1>> { phantom: PhantomData };
+    let _ = x.foo::<BarImpl<1>>();
+}
+
+trait Foo<T>
+where
+    T: Bar,
+{
+    fn foo<U>(&self)
+    where
+        T: Operation<U>,
+        <T as Operation<U>>::Output: Bar;
+}
+
+struct FooImpl<T>
+where
+    T: Bar,
+{
+    phantom: PhantomData<T>,
+}
+
+impl<T> Foo<T> for FooImpl<T>
+where
+    T: Bar,
+{
+    fn foo<U>(&self)
+    where
+        T: Operation<U>,
+        <T as Operation<U>>::Output: Bar,
+    {
+        <<T as Operation<U>>::Output as Bar>::error_occurs_here();
+    }
+}
+
+trait Bar {
+    fn error_occurs_here();
+}
+
+struct BarImpl<const N: usize>;
+
+impl<const N: usize> Bar for BarImpl<N> {
+    fn error_occurs_here() {}
+}
+
+trait Operation<Rhs> {
+    type Output;
+}
+
+//// Part-A: This causes error.
+impl<const M: usize, const N: usize> Operation<BarImpl<M>> for BarImpl<N>
+where
+    BarImpl<{ N + M }>: Sized,
+{
+    type Output = BarImpl<{ N + M }>;
+}
+
+//// Part-B: This doesn't cause error.
+// impl<const M: usize, const N: usize> Operation<BarImpl<M>> for BarImpl<N> {
+//     type Output = BarImpl<M>;
+// }
+
+//// Part-C: This also doesn't cause error.
+// impl<const M: usize, const N: usize> Operation<BarImpl<M>> for BarImpl<N> {
+//     type Output = BarImpl<{ M }>;
+// }
diff --git a/src/test/ui/const-generics/issues/issue-100313.rs b/src/test/ui/const-generics/issues/issue-100313.rs
new file mode 100644
index 00000000000..4e9d3626aa8
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-100313.rs
@@ -0,0 +1,21 @@
+#![allow(incomplete_features)]
+#![feature(const_mut_refs)]
+#![feature(adt_const_params)]
+
+struct T<const B: &'static bool>;
+
+impl <const B: &'static bool> T<B> {
+    const fn set_false(&self) {
+        unsafe {
+            *(B as *const bool as *mut bool) = false;
+            //~^ ERROR evaluation of constant value failed [E0080]
+        }
+    }
+}
+
+const _: () = {
+    let x = T::<{&true}>;
+    x.set_false();
+};
+
+fn main() {}
diff --git a/src/test/ui/const-generics/issues/issue-100313.stderr b/src/test/ui/const-generics/issues/issue-100313.stderr
new file mode 100644
index 00000000000..f3ce357c2bb
--- /dev/null
+++ b/src/test/ui/const-generics/issues/issue-100313.stderr
@@ -0,0 +1,15 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/issue-100313.rs:10:13
+   |
+LL |             *(B as *const bool as *mut bool) = false;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |             |
+   |             writing to alloc7 which is read-only
+   |             inside `T::<&true>::set_false` at $DIR/issue-100313.rs:10:13
+...
+LL |     x.set_false();
+   |     ------------- inside `_` at $DIR/issue-100313.rs:18:5
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/src/test/ui/consts/const_in_pattern/incomplete-slice.rs b/src/test/ui/consts/const_in_pattern/incomplete-slice.rs
new file mode 100644
index 00000000000..e1ccda71d40
--- /dev/null
+++ b/src/test/ui/consts/const_in_pattern/incomplete-slice.rs
@@ -0,0 +1,15 @@
+#[derive(PartialEq)]
+enum E {
+    A,
+}
+
+const E_SL: &[E] = &[E::A];
+
+fn main() {
+    match &[][..] {
+        //~^ ERROR non-exhaustive patterns: `&_` not covered [E0004]
+        E_SL => {}
+        //~^ WARN to use a constant of type `E` in a pattern, `E` must be annotated with `#[derive(PartialEq, Eq)]`
+        //~| WARN this was previously accepted by the compiler but is being phased out
+    }
+}
diff --git a/src/test/ui/consts/const_in_pattern/incomplete-slice.stderr b/src/test/ui/consts/const_in_pattern/incomplete-slice.stderr
new file mode 100644
index 00000000000..0ff70837138
--- /dev/null
+++ b/src/test/ui/consts/const_in_pattern/incomplete-slice.stderr
@@ -0,0 +1,26 @@
+warning: to use a constant of type `E` in a pattern, `E` must be annotated with `#[derive(PartialEq, Eq)]`
+  --> $DIR/incomplete-slice.rs:11:9
+   |
+LL |         E_SL => {}
+   |         ^^^^
+   |
+   = note: `#[warn(indirect_structural_match)]` 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 #62411 <https://github.com/rust-lang/rust/issues/62411>
+
+error[E0004]: non-exhaustive patterns: `&_` not covered
+  --> $DIR/incomplete-slice.rs:9:11
+   |
+LL |     match &[][..] {
+   |           ^^^^^^^ pattern `&_` not covered
+   |
+   = note: the matched value is of type `&[E]`
+help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
+   |
+LL ~         E_SL => {}
+LL +         &_ => todo!()
+   |
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0004`.
diff --git a/src/test/ui/consts/extra-const-ub/detect-extra-ub.rs b/src/test/ui/consts/extra-const-ub/detect-extra-ub.rs
new file mode 100644
index 00000000000..97c9e150519
--- /dev/null
+++ b/src/test/ui/consts/extra-const-ub/detect-extra-ub.rs
@@ -0,0 +1,45 @@
+// revisions: no_flag with_flag
+// [no_flag] check-pass
+// [with_flag] compile-flags: -Zextra-const-ub-checks
+#![feature(const_ptr_read)]
+
+use std::mem::transmute;
+
+const INVALID_BOOL: () = unsafe {
+    let _x: bool = transmute(3u8);
+    //[with_flag]~^ ERROR: evaluation of constant value failed
+    //[with_flag]~| invalid value
+};
+
+const INVALID_PTR_IN_INT: () = unsafe {
+    let _x: usize = transmute(&3u8);
+    //[with_flag]~^ ERROR: evaluation of constant value failed
+    //[with_flag]~| invalid value
+};
+
+const INVALID_SLICE_TO_USIZE_TRANSMUTE: () = unsafe {
+    let x: &[u8] = &[0; 32];
+    let _x: (usize, usize) = transmute(x);
+    //[with_flag]~^ ERROR: evaluation of constant value failed
+    //[with_flag]~| invalid value
+};
+
+const UNALIGNED_PTR: () = unsafe {
+    let _x: &u32 = transmute(&[0u8; 4]);
+    //[with_flag]~^ ERROR: evaluation of constant value failed
+    //[with_flag]~| invalid value
+};
+
+const UNALIGNED_READ: () = {
+    INNER; //[with_flag]~ERROR any use of this value will cause an error
+    //[with_flag]~| previously accepted
+    // There is an error here but its span is in the standard library so we cannot match it...
+    // so we have this in a *nested* const, such that the *outer* const fails to use it.
+    const INNER: () = unsafe {
+        let x = &[0u8; 4];
+        let ptr = x.as_ptr().cast::<u32>();
+        ptr.read();
+    };
+};
+
+fn main() {}
diff --git a/src/test/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr b/src/test/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr
new file mode 100644
index 00000000000..1706db7ac43
--- /dev/null
+++ b/src/test/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr
@@ -0,0 +1,71 @@
+error[E0080]: evaluation of constant value failed
+  --> $DIR/detect-extra-ub.rs:9:20
+   |
+LL |     let _x: bool = transmute(3u8);
+   |                    ^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/detect-extra-ub.rs:15:21
+   |
+LL |     let _x: usize = transmute(&3u8);
+   |                     ^^^^^^^^^^^^^^^ constructing invalid value: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/detect-extra-ub.rs:22:30
+   |
+LL |     let _x: (usize, usize) = transmute(x);
+   |                              ^^^^^^^^^^^^ constructing invalid value at .0: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes
+
+error[E0080]: evaluation of constant value failed
+  --> $DIR/detect-extra-ub.rs:28:20
+   |
+LL |     let _x: &u32 = transmute(&[0u8; 4]);
+   |                    ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1)
+
+error[E0080]: evaluation of constant value failed
+  --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |
+LL |         copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         accessing memory with alignment 1, but alignment 4 is required
+   |         inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+   |
+  ::: $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+LL |         unsafe { read(self) }
+   |                  ---------- inside `ptr::const_ptr::<impl *const u32>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
+   |
+  ::: $DIR/detect-extra-ub.rs:41:9
+   |
+LL |         ptr.read();
+   |         ---------- inside `INNER` at $DIR/detect-extra-ub.rs:41:9
+
+error: any use of this value will cause an error
+  --> $DIR/detect-extra-ub.rs:34:5
+   |
+LL | const UNALIGNED_READ: () = {
+   | ------------------------
+LL |     INNER;
+   |     ^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
+Future incompatibility report: Future breakage diagnostic:
+error: any use of this value will cause an error
+  --> $DIR/detect-extra-ub.rs:34:5
+   |
+LL | const UNALIGNED_READ: () = {
+   | ------------------------
+LL |     INNER;
+   |     ^^^^^ referenced constant has errors
+   |
+   = note: `#[deny(const_err)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
+
diff --git a/src/test/ui/copy-a-resource.stderr b/src/test/ui/copy-a-resource.stderr
index 128087f1e37..b92449c6e0a 100644
--- a/src/test/ui/copy-a-resource.stderr
+++ b/src/test/ui/copy-a-resource.stderr
@@ -10,6 +10,10 @@ LL |     let _y = x.clone();
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `clone`, perhaps you need to implement it:
            candidate #1: `Clone`
+help: one of the expressions' fields has a method of the same name
+   |
+LL |     let _y = x.i.clone();
+   |                ++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs
index b2edc1a1f66..6175b7df110 100644
--- a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs
+++ b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs
@@ -3,7 +3,6 @@
 
 trait Foo<X = Box<dyn Foo>> {
     //~^ ERROR cycle detected
-    //~| ERROR cycle detected
 }
 
 fn main() { }
diff --git a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr
index d4976a0f9c9..9d715f49471 100644
--- a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr
+++ b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr
@@ -10,30 +10,11 @@ note: cycle used when collecting item types in top-level module
    |
 LL | / trait Foo<X = Box<dyn Foo>> {
 LL | |
-LL | |
-LL | | }
-LL | |
-LL | | fn main() { }
-   | |_____________^
-
-error[E0391]: cycle detected when computing type of `Foo::X`
-  --> $DIR/cycle-trait-default-type-trait.rs:4:23
-   |
-LL | trait Foo<X = Box<dyn Foo>> {
-   |                       ^^^
-   |
-   = note: ...which immediately requires computing type of `Foo::X` again
-note: cycle used when collecting item types in top-level module
-  --> $DIR/cycle-trait-default-type-trait.rs:4:1
-   |
-LL | / trait Foo<X = Box<dyn Foo>> {
-LL | |
-LL | |
 LL | | }
 LL | |
 LL | | fn main() { }
    | |_____________^
 
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.rs b/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.rs
index 5a92bcd37b6..5d924555625 100644
--- a/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.rs
+++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.rs
@@ -1,4 +1,4 @@
-// check-pass
+// check-fail
 
 trait Trait {
     type Type;
@@ -17,6 +17,7 @@ where
 
 fn g<'a, 'b>() {
     f::<'a, 'b>(());
+    //~^ ERROR lifetime may not live long enough
 }
 
 fn main() {}
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.stderr
new file mode 100644
index 00000000000..0c3df04eabc
--- /dev/null
+++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.stderr
@@ -0,0 +1,17 @@
+error: lifetime may not live long enough
+  --> $DIR/implied-bounds-unnorm-associated-type-2.rs:19:5
+   |
+LL | fn g<'a, 'b>() {
+   |      --  -- lifetime `'b` defined here
+   |      |
+   |      lifetime `'a` defined here
+LL |     f::<'a, 'b>(());
+   |     ^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a`
+   |
+   = help: consider adding the following bound: `'b: 'a`
+   = note: requirement occurs because of a function pointer to `f`
+   = note: the function `f` is invariant over the parameter `'a`
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.rs b/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.rs
index dc25ac08613..888f74cf6b3 100644
--- a/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.rs
+++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.rs
@@ -1,6 +1,4 @@
-// check-fail
-// See issue #91899. If we treat unnormalized args as WF, `Self` can also be a
-// source of unsoundness.
+// check-pass
 
 pub trait Yokeable<'a>: 'static {
     type Output: 'a;
@@ -17,7 +15,6 @@ pub trait ZeroCopyFrom<C: ?Sized>: for<'a> Yokeable<'a> {
 
 impl<T> ZeroCopyFrom<[T]> for &'static [T] {
     fn zero_copy_from<'b>(cart: &'b [T]) -> &'b [T] {
-        //~^ the parameter
         cart
     }
 }
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr
deleted file mode 100644
index 95cf4fb168f..00000000000
--- a/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr
+++ /dev/null
@@ -1,14 +0,0 @@
-error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/implied-bounds-unnorm-associated-type-3.rs:19:5
-   |
-LL |     fn zero_copy_from<'b>(cart: &'b [T]) -> &'b [T] {
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `[T]` will meet its required lifetime bounds
-   |
-help: consider adding an explicit lifetime bound...
-   |
-LL | impl<T: 'static> ZeroCopyFrom<[T]> for &'static [T] {
-   |       +++++++++
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0310`.
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-4.rs b/src/test/ui/fn/implied-bounds-unnorm-associated-type-4.rs
new file mode 100644
index 00000000000..12859252c87
--- /dev/null
+++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type-4.rs
@@ -0,0 +1,24 @@
+// A regression test for #98543
+
+trait Trait {
+    type Type;
+}
+
+impl<T> Trait for T {
+    type Type = ();
+}
+
+fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str
+where
+    &'a &'b (): Trait, // <- adding this bound is the change from #91068
+{
+    s
+}
+
+fn main() {
+    let x = String::from("Hello World!");
+    let y = f(&x, ());
+    drop(x);
+    //~^ ERROR cannot move out of `x` because it is borrowed
+    println!("{}", y);
+}
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-4.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type-4.stderr
new file mode 100644
index 00000000000..fcbaa91d19f
--- /dev/null
+++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type-4.stderr
@@ -0,0 +1,14 @@
+error[E0505]: cannot move out of `x` because it is borrowed
+  --> $DIR/implied-bounds-unnorm-associated-type-4.rs:21:10
+   |
+LL |     let y = f(&x, ());
+   |               -- borrow of `x` occurs here
+LL |     drop(x);
+   |          ^ move out of `x` occurs here
+LL |
+LL |     println!("{}", y);
+   |                    - borrow later used here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0505`.
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-5.rs b/src/test/ui/fn/implied-bounds-unnorm-associated-type-5.rs
new file mode 100644
index 00000000000..2a9a6a8cc6c
--- /dev/null
+++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type-5.rs
@@ -0,0 +1,23 @@
+trait Trait<'a>: 'a {
+    type Type;
+}
+
+// if the `T: 'a` bound gets implied we would probably get ub here again
+impl<'a, T> Trait<'a> for T {
+    //~^ ERROR the parameter type `T` may not live long enough
+    type Type = ();
+}
+
+fn f<'a, 'b>(s: &'b str, _: <&'b () as Trait<'a>>::Type) -> &'a str
+where
+    &'b (): Trait<'a>,
+{
+    s
+}
+
+fn main() {
+    let x = String::from("Hello World!");
+    let y = f(&x, ());
+    drop(x);
+    println!("{}", y);
+}
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-5.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type-5.stderr
new file mode 100644
index 00000000000..458756a3dcd
--- /dev/null
+++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type-5.stderr
@@ -0,0 +1,19 @@
+error[E0309]: the parameter type `T` may not live long enough
+  --> $DIR/implied-bounds-unnorm-associated-type-5.rs:6:13
+   |
+LL | impl<'a, T> Trait<'a> for T {
+   |             ^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/implied-bounds-unnorm-associated-type-5.rs:1:18
+   |
+LL | trait Trait<'a>: 'a {
+   |                  ^^
+help: consider adding an explicit lifetime bound...
+   |
+LL | impl<'a, T: 'a> Trait<'a> for T {
+   |           ++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0309`.
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type.rs b/src/test/ui/fn/implied-bounds-unnorm-associated-type.rs
index 04b6f4dd84e..d58d25036c5 100644
--- a/src/test/ui/fn/implied-bounds-unnorm-associated-type.rs
+++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type.rs
@@ -1,6 +1,6 @@
 // check-fail
-// See issue #91068. Types in the substs of an associated type can't be implied
-// to be WF, since they don't actually have to be constructed.
+// See issue #91068. We check that the unnormalized associated types in
+// function signatures are implied
 
 trait Trait {
     type Type;
@@ -12,12 +12,12 @@ impl<T> Trait for T {
 
 fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str {
     s
-    //~^ ERROR lifetime may not live long enough
 }
 
 fn main() {
     let x = String::from("Hello World!");
     let y = f(&x, ());
     drop(x);
+    //~^ ERROR cannot move out of `x` because it is borrowed
     println!("{}", y);
 }
diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr
index 8096f08385c..e35f46e4439 100644
--- a/src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr
+++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr
@@ -1,14 +1,14 @@
-error: lifetime may not live long enough
-  --> $DIR/implied-bounds-unnorm-associated-type.rs:14:5
+error[E0505]: cannot move out of `x` because it is borrowed
+  --> $DIR/implied-bounds-unnorm-associated-type.rs:20:10
    |
-LL | fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str {
-   |      --  -- lifetime `'b` defined here
-   |      |
-   |      lifetime `'a` defined here
-LL |     s
-   |     ^ 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`
+LL |     let y = f(&x, ());
+   |               -- borrow of `x` occurs here
+LL |     drop(x);
+   |          ^ move out of `x` occurs here
+LL |
+LL |     println!("{}", y);
+   |                    - borrow later used here
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0505`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87748.stderr b/src/test/ui/generic-associated-types/bugs/issue-87748.stderr
deleted file mode 100644
index ac197dfe6ff..00000000000
--- a/src/test/ui/generic-associated-types/bugs/issue-87748.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0478]: lifetime bound not satisfied
-  --> $DIR/issue-87748.rs:18:5
-   |
-LL |     fn do_sth(_: u32) {}
-   |     ^^^^^^^^^^^^^^^^^
-   |
-note: lifetime parameter instantiated with the anonymous lifetime as defined here
-  --> $DIR/issue-87748.rs:18:5
-   |
-LL |     fn do_sth(_: u32) {}
-   |     ^^^^^^^^^^^^^^^^^
-note: but lifetime parameter must outlive the anonymous lifetime as defined here
-  --> $DIR/issue-87748.rs:18:5
-   |
-LL |     fn do_sth(_: u32) {}
-   |     ^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0478`.
diff --git a/src/test/ui/generic-associated-types/bugs/issue-87748.rs b/src/test/ui/generic-associated-types/issue-87748.rs
index a3d00ee03b1..1a1ab9bf8a4 100644
--- a/src/test/ui/generic-associated-types/bugs/issue-87748.rs
+++ b/src/test/ui/generic-associated-types/issue-87748.rs
@@ -1,13 +1,14 @@
-// check-fail
-// known-bug: #87748
+// Checks that we properly add implied bounds from unnormalized projections in
+// inputs when typechecking functions.
 
-// This should pass, but unnormalized input args aren't treated as implied.
+// check-pass
 
 #![feature(generic_associated_types)]
 
 trait MyTrait {
     type Assoc<'a, 'b> where 'b: 'a;
     fn do_sth(arg: Self::Assoc<'_, '_>);
+    fn do_sth2(arg: Self::Assoc<'_, '_>) {}
 }
 
 struct Foo;
@@ -16,8 +17,7 @@ impl MyTrait for Foo {
     type Assoc<'a, 'b> = u32 where 'b: 'a;
 
     fn do_sth(_: u32) {}
-    // fn do_sth(_: Self::Assoc<'static, 'static>) {}
-    // fn do_sth(_: Self::Assoc<'_, '_>) {}
+    fn do_sth2(_: Self::Assoc<'static, 'static>) {}
 }
 
 fn main() {}
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs
index 172bf218c0d..de9348f5397 100644
--- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs
@@ -7,7 +7,6 @@ trait SomeTrait<'a> {
 fn give_me_ice<T>() {
     callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
     //~^ ERROR the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied [E0277]
-    //~| ERROR the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied [E0277]
 }
 
 fn callee<T: Fn<(&'static (),)>>() {
diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr
index ecca4b999e7..6a948a116e0 100644
--- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr
+++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr
@@ -9,17 +9,6 @@ help: consider restricting type parameter `T`
 LL | fn give_me_ice<T: for<'r> SomeTrait<'r>>() {
    |                 +++++++++++++++++++++++
 
-error[E0277]: the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied
-  --> $DIR/issue-85455.rs:8:14
-   |
-LL |     callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>();
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'r> SomeTrait<'r>` is not implemented for `T`
-   |
-help: consider restricting type parameter `T`
-   |
-LL | fn give_me_ice<T: for<'r> SomeTrait<'r>>() {
-   |                 +++++++++++++++++++++++
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/hrtb/issue-30786.stderr b/src/test/ui/hrtb/issue-30786.stderr
index bc7b5e914e1..ffe3d7b81f5 100644
--- a/src/test/ui/hrtb/issue-30786.stderr
+++ b/src/test/ui/hrtb/issue-30786.stderr
@@ -18,10 +18,6 @@ note: the following trait bounds were not satisfied:
    |
 LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
    |         ---------     -                          ^^^^^^ unsatisfied trait bound introduced here
-help: one of the expressions' fields has a method of the same name
-   |
-LL |     let filter = map.stream.filterx(|x: &_| true);
-   |                      +++++++
 
 error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>`, but its trait bounds were not satisfied
   --> $DIR/issue-30786.rs:130:24
@@ -43,10 +39,6 @@ note: the following trait bounds were not satisfied:
    |
 LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {}
    |         ---------     -                          ^^^^^^ unsatisfied trait bound introduced here
-help: one of the expressions' fields has a method of the same name
-   |
-LL |     let count = filter.stream.countx();
-   |                        +++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/impl-trait/issue-100187.rs b/src/test/ui/impl-trait/issue-100187.rs
new file mode 100644
index 00000000000..fc541c69629
--- /dev/null
+++ b/src/test/ui/impl-trait/issue-100187.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+trait Trait<T> {
+    type Ty;
+}
+impl Trait<&u8> for () {
+    type Ty = ();
+}
+
+fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}
+
+fn main() {}
diff --git a/src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.rs b/src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.rs
new file mode 100644
index 00000000000..33b746c5edf
--- /dev/null
+++ b/src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.rs
@@ -0,0 +1,27 @@
+// Test for a less than ideal interaction of implied bounds and normalization.
+trait Tr {
+    type Ty;
+}
+
+impl<T: 'static> Tr for T {
+    type Ty = &'static T;
+}
+
+// `<&'a u8 as Tr>::Ty` should cause an error because `&'a u8: Tr` doesn't hold for
+// all possible 'a. However, we consider normalized types for implied bounds.
+//
+// We normalize this projection to `&'static &'a u8` and add a nested `&'a u8: 'static`
+// bound. This bound is then proven using the implied bounds for `&'static &'a u8` which
+// we only get by normalizing in the first place.
+fn test<'a>(x: &'a u8, _wf: <&'a u8 as Tr>::Ty) -> &'static u8 { x }
+
+fn main() {
+    // This works as we have 'static references due to promotion.
+    let _: &'static u8 = test(&3, &&3);
+    // This causes an error because the projection requires 'a to be 'static.
+    // It would be unsound if this compiled.
+    let x: u8 = 3;
+    let _: &'static u8 = test(&x, &&3);
+    //~^ ERROR `x` does not live long enough
+
+}
diff --git a/src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.stderr b/src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.stderr
new file mode 100644
index 00000000000..d0249e74f39
--- /dev/null
+++ b/src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.stderr
@@ -0,0 +1,15 @@
+error[E0597]: `x` does not live long enough
+  --> $DIR/assoc-ty-wf-used-to-get-assoc-ty.rs:24:31
+   |
+LL |     let _: &'static u8 = test(&x, &&3);
+   |                          -----^^------
+   |                          |    |
+   |                          |    borrowed value does not live long enough
+   |                          argument requires that `x` is borrowed for `'static`
+...
+LL | }
+   | - `x` dropped here while still borrowed
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/src/test/ui/issues/issue-21950.stderr b/src/test/ui/issues/issue-21950.stderr
index 4909398bb84..731615a6bd8 100644
--- a/src/test/ui/issues/issue-21950.stderr
+++ b/src/test/ui/issues/issue-21950.stderr
@@ -1,3 +1,12 @@
+error[E0191]: the value of the associated type `Output` (from trait `Add`) must be specified
+  --> $DIR/issue-21950.rs:10:25
+   |
+LL |     type Output;
+   |     ----------- `Output` defined here
+...
+LL |     let x = &10 as &dyn Add;
+   |                         ^^^ help: specify the associated type: `Add<Output = Type>`
+
 error[E0393]: the type parameter `Rhs` must be explicitly specified
   --> $DIR/issue-21950.rs:10:25
    |
@@ -9,15 +18,6 @@ LL |     let x = &10 as &dyn Add;
    |
    = note: because of the default `Self` reference, type parameters must be specified on object types
 
-error[E0191]: the value of the associated type `Output` (from trait `Add`) must be specified
-  --> $DIR/issue-21950.rs:10:25
-   |
-LL |     type Output;
-   |     ----------- `Output` defined here
-...
-LL |     let x = &10 as &dyn Add;
-   |                         ^^^ help: specify the associated type: `Add<Output = Type>`
-
 error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0191, E0393.
diff --git a/src/test/ui/issues/issue-2823.stderr b/src/test/ui/issues/issue-2823.stderr
index b5a2b2f55a6..208b340d064 100644
--- a/src/test/ui/issues/issue-2823.stderr
+++ b/src/test/ui/issues/issue-2823.stderr
@@ -10,6 +10,10 @@ LL |     let _d = c.clone();
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `clone`, perhaps you need to implement it:
            candidate #1: `Clone`
+help: one of the expressions' fields has a method of the same name
+   |
+LL |     let _d = c.x.clone();
+   |                ++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/json-multiple.stderr b/src/test/ui/json-multiple.stderr
deleted file mode 100644
index 7ed345113cb..00000000000
--- a/src/test/ui/json-multiple.stderr
+++ /dev/null
@@ -1 +0,0 @@
-{"artifact":"$TEST_BUILD_DIR/json-multiple/libjson_multiple.rlib","emit":"link"}
diff --git a/src/test/ui/json-options.stderr b/src/test/ui/json-options.stderr
deleted file mode 100644
index 24977731d17..00000000000
--- a/src/test/ui/json-options.stderr
+++ /dev/null
@@ -1 +0,0 @@
-{"artifact":"$TEST_BUILD_DIR/json-options/libjson_options.rlib","emit":"link"}
diff --git a/src/test/ui/json-and-color.rs b/src/test/ui/json/json-and-color.rs
index 6f8326fe247..6f8326fe247 100644
--- a/src/test/ui/json-and-color.rs
+++ b/src/test/ui/json/json-and-color.rs
diff --git a/src/test/ui/json-and-color.stderr b/src/test/ui/json/json-and-color.stderr
index 1cda6af090d..1cda6af090d 100644
--- a/src/test/ui/json-and-color.stderr
+++ b/src/test/ui/json/json-and-color.stderr
diff --git a/src/test/ui/json-and-error-format.rs b/src/test/ui/json/json-and-error-format.rs
index 6e2d73c76b7..6e2d73c76b7 100644
--- a/src/test/ui/json-and-error-format.rs
+++ b/src/test/ui/json/json-and-error-format.rs
diff --git a/src/test/ui/json-and-error-format.stderr b/src/test/ui/json/json-and-error-format.stderr
index 80e0221376e..80e0221376e 100644
--- a/src/test/ui/json-and-error-format.stderr
+++ b/src/test/ui/json/json-and-error-format.stderr
diff --git a/src/test/ui/json-bom-plus-crlf-multifile-aux.rs b/src/test/ui/json/json-bom-plus-crlf-multifile-aux.rs
index 991ea1d85d2..991ea1d85d2 100644
--- a/src/test/ui/json-bom-plus-crlf-multifile-aux.rs
+++ b/src/test/ui/json/json-bom-plus-crlf-multifile-aux.rs
diff --git a/src/test/ui/json-bom-plus-crlf-multifile.rs b/src/test/ui/json/json-bom-plus-crlf-multifile.rs
index 9290e010403..9290e010403 100644
--- a/src/test/ui/json-bom-plus-crlf-multifile.rs
+++ b/src/test/ui/json/json-bom-plus-crlf-multifile.rs
diff --git a/src/test/ui/json-bom-plus-crlf-multifile.stderr b/src/test/ui/json/json-bom-plus-crlf-multifile.stderr
index 02f3bc687cb..02f3bc687cb 100644
--- a/src/test/ui/json-bom-plus-crlf-multifile.stderr
+++ b/src/test/ui/json/json-bom-plus-crlf-multifile.stderr
diff --git a/src/test/ui/json-bom-plus-crlf.rs b/src/test/ui/json/json-bom-plus-crlf.rs
index be5b7dd2a86..be5b7dd2a86 100644
--- a/src/test/ui/json-bom-plus-crlf.rs
+++ b/src/test/ui/json/json-bom-plus-crlf.rs
diff --git a/src/test/ui/json-bom-plus-crlf.stderr b/src/test/ui/json/json-bom-plus-crlf.stderr
index df6bd7286a6..df6bd7286a6 100644
--- a/src/test/ui/json-bom-plus-crlf.stderr
+++ b/src/test/ui/json/json-bom-plus-crlf.stderr
diff --git a/src/test/ui/json-invalid.rs b/src/test/ui/json/json-invalid.rs
index 54d0dd1849a..54d0dd1849a 100644
--- a/src/test/ui/json-invalid.rs
+++ b/src/test/ui/json/json-invalid.rs
diff --git a/src/test/ui/json-invalid.stderr b/src/test/ui/json/json-invalid.stderr
index 18bc76ab7eb..18bc76ab7eb 100644
--- a/src/test/ui/json-invalid.stderr
+++ b/src/test/ui/json/json-invalid.stderr
diff --git a/src/test/ui/json-multiple.polonius.stderr b/src/test/ui/json/json-multiple.polonius.stderr
index 0e4d442f299..0e4d442f299 100644
--- a/src/test/ui/json-multiple.polonius.stderr
+++ b/src/test/ui/json/json-multiple.polonius.stderr
diff --git a/src/test/ui/json-multiple.rs b/src/test/ui/json/json-multiple.rs
index fb126339dc2..fb126339dc2 100644
--- a/src/test/ui/json-multiple.rs
+++ b/src/test/ui/json/json-multiple.rs
diff --git a/src/test/ui/json/json-multiple.stderr b/src/test/ui/json/json-multiple.stderr
new file mode 100644
index 00000000000..55ccfd5fa70
--- /dev/null
+++ b/src/test/ui/json/json-multiple.stderr
@@ -0,0 +1 @@
+{"artifact":"$TEST_BUILD_DIR/json/json-multiple/libjson_multiple.rlib","emit":"link"}
diff --git a/src/test/ui/json-options.polonius.stderr b/src/test/ui/json/json-options.polonius.stderr
index e21f6f85d16..e21f6f85d16 100644
--- a/src/test/ui/json-options.polonius.stderr
+++ b/src/test/ui/json/json-options.polonius.stderr
diff --git a/src/test/ui/json-options.rs b/src/test/ui/json/json-options.rs
index 8b6ba131eb0..8b6ba131eb0 100644
--- a/src/test/ui/json-options.rs
+++ b/src/test/ui/json/json-options.rs
diff --git a/src/test/ui/json/json-options.stderr b/src/test/ui/json/json-options.stderr
new file mode 100644
index 00000000000..645a26f5ad4
--- /dev/null
+++ b/src/test/ui/json/json-options.stderr
@@ -0,0 +1 @@
+{"artifact":"$TEST_BUILD_DIR/json/json-options/libjson_options.rlib","emit":"link"}
diff --git a/src/test/ui/json-short.rs b/src/test/ui/json/json-short.rs
index 7414a55869c..7414a55869c 100644
--- a/src/test/ui/json-short.rs
+++ b/src/test/ui/json/json-short.rs
diff --git a/src/test/ui/json-short.stderr b/src/test/ui/json/json-short.stderr
index 3bd85b083d0..3bd85b083d0 100644
--- a/src/test/ui/json-short.stderr
+++ b/src/test/ui/json/json-short.stderr
diff --git a/src/test/ui/lint/unused_parens_multibyte_recovery.rs b/src/test/ui/lint/unused_parens_multibyte_recovery.rs
new file mode 100644
index 00000000000..8fcfae22a3d
--- /dev/null
+++ b/src/test/ui/lint/unused_parens_multibyte_recovery.rs
@@ -0,0 +1,11 @@
+// ignore-tidy-trailing-newlines
+//
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: format argument must be a string literal
+//
+// Verify that unused parens lint does not try to create a span
+// which points in the middle of a multibyte character.
+
+fn f(){(print!(á
\ No newline at end of file
diff --git a/src/test/ui/lint/unused_parens_multibyte_recovery.stderr b/src/test/ui/lint/unused_parens_multibyte_recovery.stderr
new file mode 100644
index 00000000000..a0302b17e25
--- /dev/null
+++ b/src/test/ui/lint/unused_parens_multibyte_recovery.stderr
@@ -0,0 +1,43 @@
+error: this file contains an unclosed delimiter
+  --> $DIR/unused_parens_multibyte_recovery.rs:11:17
+   |
+LL | fn f(){(print!(á
+   |       --      - ^
+   |       ||      |
+   |       ||      unclosed delimiter
+   |       |unclosed delimiter
+   |       unclosed delimiter
+
+error: this file contains an unclosed delimiter
+  --> $DIR/unused_parens_multibyte_recovery.rs:11:17
+   |
+LL | fn f(){(print!(á
+   |       --      - ^
+   |       ||      |
+   |       ||      unclosed delimiter
+   |       |unclosed delimiter
+   |       unclosed delimiter
+
+error: this file contains an unclosed delimiter
+  --> $DIR/unused_parens_multibyte_recovery.rs:11:17
+   |
+LL | fn f(){(print!(á
+   |       --      - ^
+   |       ||      |
+   |       ||      unclosed delimiter
+   |       |unclosed delimiter
+   |       unclosed delimiter
+
+error: format argument must be a string literal
+  --> $DIR/unused_parens_multibyte_recovery.rs:11:16
+   |
+LL | fn f(){(print!(á
+   |                ^
+   |
+help: you might be missing a string literal to format with
+   |
+LL | fn f(){(print!("{}", á
+   |                +++++
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/lowering/issue-96847.rs b/src/test/ui/lowering/issue-96847.rs
new file mode 100644
index 00000000000..2aa34c8b335
--- /dev/null
+++ b/src/test/ui/lowering/issue-96847.rs
@@ -0,0 +1,14 @@
+// run-pass
+
+// Test that this doesn't abort during AST lowering. In #96847 it did abort
+// because the attribute was being lowered twice.
+
+#![feature(stmt_expr_attributes)]
+#![feature(lang_items)]
+
+fn main() {
+    for _ in [1,2,3] {
+        #![lang="foo"]
+        println!("foo");
+    }
+}
diff --git a/src/test/ui/macros/stringify.rs b/src/test/ui/macros/stringify.rs
index f246aa26a9d..8e71ed7c112 100644
--- a/src/test/ui/macros/stringify.rs
+++ b/src/test/ui/macros/stringify.rs
@@ -865,8 +865,9 @@ fn test_vis() {
     assert_eq!(stringify_vis!(pub(crate)), "pub(crate) ");
     assert_eq!(stringify_vis!(pub(self)), "pub(self) ");
     assert_eq!(stringify_vis!(pub(super)), "pub(super) ");
-    assert_eq!(stringify_vis!(pub(in self)), "pub(self) ");
-    assert_eq!(stringify_vis!(pub(in super)), "pub(super) ");
+    assert_eq!(stringify_vis!(pub(in crate)), "pub(in crate) ");
+    assert_eq!(stringify_vis!(pub(in self)), "pub(in self) ");
+    assert_eq!(stringify_vis!(pub(in super)), "pub(in super) ");
     assert_eq!(stringify_vis!(pub(in path::to)), "pub(in path::to) ");
     assert_eq!(stringify_vis!(pub(in ::path::to)), "pub(in ::path::to) ");
     assert_eq!(stringify_vis!(pub(in self::path::to)), "pub(in self::path::to) ");
diff --git a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs
index c4db6fc97dc..05e2ea047f6 100644
--- a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs
+++ b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs
@@ -30,4 +30,5 @@ fn main() {
     let _x = <fn(&())>::make_f();
     //~^ ERROR implementation of `Y` is not general enough
     //~| ERROR implementation of `Y` is not general enough
+    //~| ERROR implementation of `Y` is not general enough
 }
diff --git a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr
index 51adfca3e79..8c47379886d 100644
--- a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr
+++ b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr
@@ -16,5 +16,14 @@ LL |     let _x = <fn(&())>::make_f();
    = note: `Y` would have to be implemented for the type `for<'r> fn(&'r ())`
    = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`
 
-error: aborting due to 2 previous errors
+error: implementation of `Y` is not general enough
+  --> $DIR/impl-fn-ignore-binder-via-bottom.rs:30:14
+   |
+LL |     let _x = <fn(&())>::make_f();
+   |              ^^^^^^^^^^^^^^^^^^^ implementation of `Y` is not general enough
+   |
+   = note: `Y` would have to be implemented for the type `for<'r> fn(&'r ())`
+   = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0`
+
+error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/noncopyable-class.stderr b/src/test/ui/noncopyable-class.stderr
index 0c696163a26..15e22e946da 100644
--- a/src/test/ui/noncopyable-class.stderr
+++ b/src/test/ui/noncopyable-class.stderr
@@ -10,6 +10,14 @@ LL |     let _y = x.clone();
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following trait defines an item `clone`, perhaps you need to implement it:
            candidate #1: `Clone`
+help: one of the expressions' fields has a method of the same name
+   |
+LL |     let _y = x.i.clone();
+   |                ++
+help: one of the expressions' fields has a method of the same name
+   |
+LL |     let _y = x.j.x.clone();
+   |                ++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs b/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs
new file mode 100644
index 00000000000..7ebf3f6b0d8
--- /dev/null
+++ b/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs
@@ -0,0 +1,8 @@
+fn foo() {}
+
+fn bar() -> [u8; 2] {
+    foo()
+    [1, 3) //~ ERROR expected one of `.`, `?`, `]`, or an operator, found `,`
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr b/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr
new file mode 100644
index 00000000000..d6e8db80329
--- /dev/null
+++ b/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr
@@ -0,0 +1,10 @@
+error: expected one of `.`, `?`, `]`, or an operator, found `,`
+  --> $DIR/do-not-suggest-suggest-semicolon-before-array.rs:5:5
+   |
+LL |     [1, 3)
+   |     ^ ^ help: `]` may belong here
+   |     |
+   |     unclosed delimiter
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed b/src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed
new file mode 100644
index 00000000000..a06b58b2740
--- /dev/null
+++ b/src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed
@@ -0,0 +1,11 @@
+// run-rustfix
+#![allow(dead_code)]
+
+fn foo() {}
+
+fn bar() -> [u8; 2] {
+    foo();
+    [1, 3] //~ ERROR expected `;`, found `[`
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.rs b/src/test/ui/parser/suggest-suggest-semicolon-before-array.rs
new file mode 100644
index 00000000000..f601ca2aef5
--- /dev/null
+++ b/src/test/ui/parser/suggest-suggest-semicolon-before-array.rs
@@ -0,0 +1,11 @@
+// run-rustfix
+#![allow(dead_code)]
+
+fn foo() {}
+
+fn bar() -> [u8; 2] {
+    foo()
+    [1, 3] //~ ERROR expected `;`, found `[`
+}
+
+fn main() {}
diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr b/src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr
new file mode 100644
index 00000000000..bf86b43554d
--- /dev/null
+++ b/src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr
@@ -0,0 +1,13 @@
+error: expected `;`, found `[`
+  --> $DIR/suggest-suggest-semicolon-before-array.rs:8:5
+   |
+LL |     [1, 3]
+   |     ^
+   |
+help: consider adding `;` here
+   |
+LL |     foo();
+   |          +
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.rs b/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.rs
index d9657bac776..5dce8180f59 100644
--- a/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.rs
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.rs
@@ -1,5 +1,4 @@
 // aux-build:enums.rs
-// run-pass
 
 extern crate enums;
 
@@ -7,11 +6,6 @@ use enums::FieldLessWithNonExhaustiveVariant;
 
 fn main() {
     let e = FieldLessWithNonExhaustiveVariant::default();
-    // FIXME: https://github.com/rust-lang/rust/issues/91161
-    // This `as` cast *should* be an error, since it would fail
-    // if the non-exhaustive variant got fields.  But today it
-    // doesn't.  The fix for that will update this test to
-    // show an error (and not be run-pass any more).
-    let d = e as u8;
+    let d = e as u8; //~ ERROR casting `FieldLessWithNonExhaustiveVariant` as `u8` is invalid [E0606]
     assert_eq!(d, 0);
 }
diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.stderr
new file mode 100644
index 00000000000..a61dcf8399f
--- /dev/null
+++ b/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.stderr
@@ -0,0 +1,11 @@
+error[E0606]: casting `FieldLessWithNonExhaustiveVariant` as `u8` is invalid
+  --> $DIR/enum-as-cast.rs:9:13
+   |
+LL |     let d = e as u8;
+   |             ^^^^^^^
+   |
+   = note: cannot cast an enum with a non-exhaustive variant when it's defined in another crate
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0606`.
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs
new file mode 100644
index 00000000000..99f317399d7
--- /dev/null
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs
@@ -0,0 +1,18 @@
+#![feature(raw_dylib)]
+//~^ WARN the feature `raw_dylib` is incomplete
+
+#[link(name = "foo")]
+extern "C" {
+    #[link_ordinal(3)]
+    //~^ ERROR `#[link_ordinal]` is only supported if link kind is `raw-dylib`
+    fn foo();
+}
+
+#[link(name = "bar", kind = "static")]
+extern "C" {
+    #[link_ordinal(3)]
+    //~^ ERROR `#[link_ordinal]` is only supported if link kind is `raw-dylib`
+    fn bar();
+}
+
+fn main() {}
diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr
new file mode 100644
index 00000000000..f1eeb22da59
--- /dev/null
+++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr
@@ -0,0 +1,23 @@
+warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/link-ordinal-unsupported-link-kind.rs:1:12
+   |
+LL | #![feature(raw_dylib)]
+   |            ^^^^^^^^^
+   |
+   = note: `#[warn(incomplete_features)]` on by default
+   = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information
+
+error: `#[link_ordinal]` is only supported if link kind is `raw-dylib`
+  --> $DIR/link-ordinal-unsupported-link-kind.rs:6:5
+   |
+LL |     #[link_ordinal(3)]
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: `#[link_ordinal]` is only supported if link kind is `raw-dylib`
+  --> $DIR/link-ordinal-unsupported-link-kind.rs:13:5
+   |
+LL |     #[link_ordinal(3)]
+   |     ^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
diff --git a/src/test/ui/stats/hir-stats.rs b/src/test/ui/stats/hir-stats.rs
new file mode 100644
index 00000000000..a24b3ada57e
--- /dev/null
+++ b/src/test/ui/stats/hir-stats.rs
@@ -0,0 +1,41 @@
+// check-pass
+// compile-flags: -Zhir-stats
+// only-x86_64
+
+// The aim here is to include at least one of every different type of top-level
+// AST/HIR node reported by `-Zhir-stats`.
+
+#![allow(dead_code)]
+
+use std::arch::asm;
+use std::fmt::Debug;
+use std::ffi::c_void;
+
+extern "C" { fn f(p: *mut c_void); }
+
+/// An enum.
+enum E<'a, T: Copy> { A { t: T }, B(&'a u32) }
+
+trait Go {
+    type G: Debug;
+    fn go(self) -> u32;
+}
+
+impl<'a, T: Copy> Go for E<'a, T> {
+    type G = bool;
+    fn go(self) -> u32 {
+        99
+    }
+}
+
+fn f2<T>(t: T) where T: Debug {}
+
+fn main() {
+    let x = E::A { t: 3 };
+    match x {
+        E::A { .. } => {}
+        _ => {}
+    }
+
+    unsafe { asm!("mov rdi, 1"); }
+}
diff --git a/src/test/ui/stats/hir-stats.stderr b/src/test/ui/stats/hir-stats.stderr
new file mode 100644
index 00000000000..f4874408c90
--- /dev/null
+++ b/src/test/ui/stats/hir-stats.stderr
@@ -0,0 +1,151 @@
+
+PRE EXPANSION AST STATS
+
+Name                Accumulated Size         Count     Item Size
+----------------------------------------------------------------
+ExprField                 48 ( 0.5%)             1            48
+GenericArgs               64 ( 0.7%)             1            64
+- AngleBracketed            64 ( 0.7%)             1
+Local                     72 ( 0.8%)             1            72
+WherePredicate            72 ( 0.8%)             1            72
+- BoundPredicate            72 ( 0.8%)             1
+Crate                     72 ( 0.8%)             1            72
+Arm                       96 ( 1.0%)             2            48
+FieldDef                 160 ( 1.7%)             2            80
+ForeignItem              160 ( 1.7%)             1           160
+- Fn                       160 ( 1.7%)             1
+Stmt                     160 ( 1.7%)             5            32
+- Local                     32 ( 0.3%)             1
+- MacCall                   32 ( 0.3%)             1
+- Expr                      96 ( 1.0%)             3
+Param                    160 ( 1.7%)             4            40
+FnDecl                   200 ( 2.2%)             5            40
+Variant                  240 ( 2.6%)             2           120
+Block                    288 ( 3.1%)             6            48
+Attribute                304 ( 3.3%)             2           152
+- Normal                   152 ( 1.7%)             1
+- DocComment               152 ( 1.7%)             1
+GenericBound             352 ( 3.8%)             4            88
+- Trait                    352 ( 3.8%)             4
+GenericParam             520 ( 5.7%)             5           104
+AssocItem                640 ( 7.0%)             4           160
+- TyAlias                  320 ( 3.5%)             2
+- Fn                       320 ( 3.5%)             2
+PathSegment              720 ( 7.9%)            30            24
+Expr                     832 ( 9.1%)             8           104
+- Path                     104 ( 1.1%)             1
+- Match                    104 ( 1.1%)             1
+- Struct                   104 ( 1.1%)             1
+- Lit                      208 ( 2.3%)             2
+- Block                    312 ( 3.4%)             3
+Pat                      840 ( 9.2%)             7           120
+- Struct                   120 ( 1.3%)             1
+- Wild                     120 ( 1.3%)             1
+- Ident                    600 ( 6.6%)             5
+Ty                     1_344 (14.7%)            14            96
+- Rptr                      96 ( 1.0%)             1
+- Ptr                       96 ( 1.0%)             1
+- ImplicitSelf             192 ( 2.1%)             2
+- Path                     960 (10.5%)            10
+Item                   1_800 (19.7%)             9           200
+- Trait                    200 ( 2.2%)             1
+- Enum                     200 ( 2.2%)             1
+- ForeignMod               200 ( 2.2%)             1
+- Impl                     200 ( 2.2%)             1
+- Fn                       400 ( 4.4%)             2
+- Use                      600 ( 6.6%)             3
+----------------------------------------------------------------
+Total                  9_144
+
+
+POST EXPANSION AST STATS
+
+Name                Accumulated Size         Count     Item Size
+----------------------------------------------------------------
+ExprField                 48 ( 0.5%)             1            48
+GenericArgs               64 ( 0.6%)             1            64
+- AngleBracketed            64 ( 0.6%)             1
+Local                     72 ( 0.7%)             1            72
+WherePredicate            72 ( 0.7%)             1            72
+- BoundPredicate            72 ( 0.7%)             1
+Crate                     72 ( 0.7%)             1            72
+Arm                       96 ( 0.9%)             2            48
+InlineAsm                120 ( 1.2%)             1           120
+FieldDef                 160 ( 1.6%)             2            80
+ForeignItem              160 ( 1.6%)             1           160
+- Fn                       160 ( 1.6%)             1
+Stmt                     160 ( 1.6%)             5            32
+- Local                     32 ( 0.3%)             1
+- Semi                      32 ( 0.3%)             1
+- Expr                      96 ( 0.9%)             3
+Param                    160 ( 1.6%)             4            40
+FnDecl                   200 ( 2.0%)             5            40
+Variant                  240 ( 2.4%)             2           120
+Block                    288 ( 2.8%)             6            48
+GenericBound             352 ( 3.5%)             4            88
+- Trait                    352 ( 3.5%)             4
+GenericParam             520 ( 5.1%)             5           104
+Attribute                608 ( 6.0%)             4           152
+- DocComment               152 ( 1.5%)             1
+- Normal                   456 ( 4.5%)             3
+AssocItem                640 ( 6.3%)             4           160
+- TyAlias                  320 ( 3.2%)             2
+- Fn                       320 ( 3.2%)             2
+PathSegment              792 ( 7.8%)            33            24
+Pat                      840 ( 8.3%)             7           120
+- Struct                   120 ( 1.2%)             1
+- Wild                     120 ( 1.2%)             1
+- Ident                    600 ( 5.9%)             5
+Expr                     936 ( 9.2%)             9           104
+- Path                     104 ( 1.0%)             1
+- Match                    104 ( 1.0%)             1
+- Struct                   104 ( 1.0%)             1
+- InlineAsm                104 ( 1.0%)             1
+- Lit                      208 ( 2.1%)             2
+- Block                    312 ( 3.1%)             3
+Ty                     1_344 (13.2%)            14            96
+- Rptr                      96 ( 0.9%)             1
+- Ptr                       96 ( 0.9%)             1
+- ImplicitSelf             192 ( 1.9%)             2
+- Path                     960 ( 9.5%)            10
+Item                   2_200 (21.7%)            11           200
+- Trait                    200 ( 2.0%)             1
+- Enum                     200 ( 2.0%)             1
+- ExternCrate              200 ( 2.0%)             1
+- ForeignMod               200 ( 2.0%)             1
+- Impl                     200 ( 2.0%)             1
+- Fn                       400 ( 3.9%)             2
+- Use                      800 ( 7.9%)             4
+----------------------------------------------------------------
+Total                 10_144
+
+
+HIR STATS
+
+Name                Accumulated Size         Count     Item Size
+----------------------------------------------------------------
+Param                     64 ( 0.7%)             2            32
+Local                     64 ( 0.7%)             1            64
+ForeignItem               72 ( 0.7%)             1            72
+FieldDef                  96 ( 1.0%)             2            48
+Arm                       96 ( 1.0%)             2            48
+Stmt                      96 ( 1.0%)             3            32
+FnDecl                   120 ( 1.2%)             3            40
+Lifetime                 128 ( 1.3%)             4            32
+Variant                  160 ( 1.6%)             2            80
+ImplItem                 176 ( 1.8%)             2            88
+GenericBound             192 ( 2.0%)             4            48
+TraitItem                192 ( 2.0%)             2            96
+WherePredicate           216 ( 2.2%)             3            72
+Block                    288 ( 3.0%)             6            48
+QPath                    408 ( 4.2%)            17            24
+Pat                      440 ( 4.5%)             5            88
+Attribute                608 ( 6.2%)             4           152
+Expr                     672 ( 6.9%)            12            56
+Item                     960 ( 9.9%)            12            80
+Ty                     1_152 (11.8%)            16            72
+Path                   1_296 (13.3%)            27            48
+PathSegment            2_240 (23.0%)            40            56
+----------------------------------------------------------------
+Total                  9_736
+
diff --git a/src/test/ui/std-backtrace.rs b/src/test/ui/std-backtrace.rs
index 07de066b558..3f8306baf8a 100644
--- a/src/test/ui/std-backtrace.rs
+++ b/src/test/ui/std-backtrace.rs
@@ -7,8 +7,6 @@
 // compile-flags:-g
 // compile-flags:-Cstrip=none
 
-#![feature(backtrace)]
-
 use std::env;
 use std::process::Command;
 use std::str;
diff --git a/src/test/ui/suggestions/as-ref.rs b/src/test/ui/suggestions/as-ref.rs
index 46d9461538c..a0535344185 100644
--- a/src/test/ui/suggestions/as-ref.rs
+++ b/src/test/ui/suggestions/as-ref.rs
@@ -17,4 +17,11 @@ fn main() {
     // note: do not suggest because of `E: usize`
     let x: &Result<usize, usize> = &Ok(3);
     let y: Result<&usize, usize> = x; //~ ERROR mismatched types [E0308]
+
+    let multiple_ref_opt = &&Some(Foo);
+    multiple_ref_opt.map(|arg| takes_ref(arg)); //~ ERROR mismatched types [E0308]
+    multiple_ref_opt.and_then(|arg| Some(takes_ref(arg))); //~ ERROR mismatched types [E0308]
+    let multiple_ref_result = &&Ok(Foo);
+    multiple_ref_result.map(|arg| takes_ref(arg)); //~ ERROR mismatched types [E0308]
+    multiple_ref_result.and_then(|arg| Ok(takes_ref(arg))); //~ ERROR mismatched types [E0308]
 }
diff --git a/src/test/ui/suggestions/as-ref.stderr b/src/test/ui/suggestions/as-ref.stderr
index 1efd1b317b7..deafa9f48d4 100644
--- a/src/test/ui/suggestions/as-ref.stderr
+++ b/src/test/ui/suggestions/as-ref.stderr
@@ -97,6 +97,66 @@ LL |     let y: Result<&usize, usize> = x;
    = note:   expected enum `Result<&usize, usize>`
            found reference `&Result<usize, usize>`
 
-error: aborting due to 7 previous errors
+error[E0308]: mismatched types
+  --> $DIR/as-ref.rs:22:42
+   |
+LL |     multiple_ref_opt.map(|arg| takes_ref(arg));
+   |                      ---       --------- ^^^ expected `&Foo`, found struct `Foo`
+   |                      |         |
+   |                      |         arguments to this function are incorrect
+   |                      help: consider using `as_ref` instead: `as_ref().map`
+   |
+note: function defined here
+  --> $DIR/as-ref.rs:3:4
+   |
+LL | fn takes_ref(_: &Foo) {}
+   |    ^^^^^^^^^ -------
+
+error[E0308]: mismatched types
+  --> $DIR/as-ref.rs:23:52
+   |
+LL |     multiple_ref_opt.and_then(|arg| Some(takes_ref(arg)));
+   |                      --------            --------- ^^^ expected `&Foo`, found struct `Foo`
+   |                      |                   |
+   |                      |                   arguments to this function are incorrect
+   |                      help: consider using `as_ref` instead: `as_ref().and_then`
+   |
+note: function defined here
+  --> $DIR/as-ref.rs:3:4
+   |
+LL | fn takes_ref(_: &Foo) {}
+   |    ^^^^^^^^^ -------
+
+error[E0308]: mismatched types
+  --> $DIR/as-ref.rs:25:45
+   |
+LL |     multiple_ref_result.map(|arg| takes_ref(arg));
+   |                         ---       --------- ^^^ expected `&Foo`, found struct `Foo`
+   |                         |         |
+   |                         |         arguments to this function are incorrect
+   |                         help: consider using `as_ref` instead: `as_ref().map`
+   |
+note: function defined here
+  --> $DIR/as-ref.rs:3:4
+   |
+LL | fn takes_ref(_: &Foo) {}
+   |    ^^^^^^^^^ -------
+
+error[E0308]: mismatched types
+  --> $DIR/as-ref.rs:26:53
+   |
+LL |     multiple_ref_result.and_then(|arg| Ok(takes_ref(arg)));
+   |                         --------          --------- ^^^ expected `&Foo`, found struct `Foo`
+   |                         |                 |
+   |                         |                 arguments to this function are incorrect
+   |                         help: consider using `as_ref` instead: `as_ref().and_then`
+   |
+note: function defined here
+  --> $DIR/as-ref.rs:3:4
+   |
+LL | fn takes_ref(_: &Foo) {}
+   |    ^^^^^^^^^ -------
+
+error: aborting due to 11 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/suggestions/field-access-considering-privacy.rs b/src/test/ui/suggestions/field-access-considering-privacy.rs
new file mode 100644
index 00000000000..3de06b21420
--- /dev/null
+++ b/src/test/ui/suggestions/field-access-considering-privacy.rs
@@ -0,0 +1,35 @@
+use a::TyCtxt;
+
+mod a {
+    use std::ops::Deref;
+    pub struct TyCtxt<'tcx> {
+        gcx: &'tcx GlobalCtxt<'tcx>,
+    }
+
+    impl<'tcx> Deref for TyCtxt<'tcx> {
+        type Target = &'tcx GlobalCtxt<'tcx>;
+
+        fn deref(&self) -> &Self::Target {
+            &self.gcx
+        }
+    }
+
+    pub struct GlobalCtxt<'tcx> {
+        pub sess: &'tcx Session,
+        _t: &'tcx (),
+    }
+
+    pub struct Session {
+        pub opts: (),
+    }
+}
+
+mod b {
+    fn foo<'tcx>(tcx: crate::TyCtxt<'tcx>) {
+        tcx.opts;
+        //~^ ERROR no field `opts` on type `TyCtxt<'tcx>`
+        //~| HELP one of the expressions' fields has a field of the same name
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/suggestions/field-access-considering-privacy.stderr b/src/test/ui/suggestions/field-access-considering-privacy.stderr
new file mode 100644
index 00000000000..cbf6f3d1002
--- /dev/null
+++ b/src/test/ui/suggestions/field-access-considering-privacy.stderr
@@ -0,0 +1,14 @@
+error[E0609]: no field `opts` on type `TyCtxt<'tcx>`
+  --> $DIR/field-access-considering-privacy.rs:29:13
+   |
+LL |         tcx.opts;
+   |             ^^^^ unknown field
+   |
+help: one of the expressions' fields has a field of the same name
+   |
+LL |         tcx.sess.opts;
+   |             +++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0609`.
diff --git a/src/test/ui/traits/alias/generic-default-in-dyn.rs b/src/test/ui/traits/alias/generic-default-in-dyn.rs
new file mode 100644
index 00000000000..d44e1c2a975
--- /dev/null
+++ b/src/test/ui/traits/alias/generic-default-in-dyn.rs
@@ -0,0 +1,10 @@
+trait SendEqAlias<T> = PartialEq;
+//~^ ERROR trait aliases are experimental
+
+struct Foo<T>(dyn SendEqAlias<T>);
+//~^ ERROR the type parameter `Rhs` must be explicitly specified [E0393]
+
+struct Bar<T>(dyn SendEqAlias<T>, T);
+//~^ ERROR the type parameter `Rhs` must be explicitly specified [E0393]
+
+fn main() {}
diff --git a/src/test/ui/traits/alias/generic-default-in-dyn.stderr b/src/test/ui/traits/alias/generic-default-in-dyn.stderr
new file mode 100644
index 00000000000..76a068e864a
--- /dev/null
+++ b/src/test/ui/traits/alias/generic-default-in-dyn.stderr
@@ -0,0 +1,39 @@
+error[E0658]: trait aliases are experimental
+  --> $DIR/generic-default-in-dyn.rs:1:1
+   |
+LL | trait SendEqAlias<T> = PartialEq;
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #41517 <https://github.com/rust-lang/rust/issues/41517> for more information
+   = help: add `#![feature(trait_alias)]` to the crate attributes to enable
+
+error[E0393]: the type parameter `Rhs` must be explicitly specified
+  --> $DIR/generic-default-in-dyn.rs:4:19
+   |
+LL | struct Foo<T>(dyn SendEqAlias<T>);
+   |                   ^^^^^^^^^^^^^^ missing reference to `Rhs`
+   |
+  ::: $SRC_DIR/core/src/cmp.rs:LL:COL
+   |
+LL | pub trait PartialEq<Rhs: ?Sized = Self> {
+   | --------------------------------------- type parameter `Rhs` must be specified for this
+   |
+   = note: because of the default `Self` reference, type parameters must be specified on object types
+
+error[E0393]: the type parameter `Rhs` must be explicitly specified
+  --> $DIR/generic-default-in-dyn.rs:7:19
+   |
+LL | struct Bar<T>(dyn SendEqAlias<T>, T);
+   |                   ^^^^^^^^^^^^^^ missing reference to `Rhs`
+   |
+  ::: $SRC_DIR/core/src/cmp.rs:LL:COL
+   |
+LL | pub trait PartialEq<Rhs: ?Sized = Self> {
+   | --------------------------------------- type parameter `Rhs` must be specified for this
+   |
+   = note: because of the default `Self` reference, type parameters must be specified on object types
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0393, E0658.
+For more information about an error, try `rustc --explain E0393`.
diff --git a/src/test/ui/traits/alias/self-in-generics.rs b/src/test/ui/traits/alias/self-in-generics.rs
new file mode 100644
index 00000000000..6b99431f5bb
--- /dev/null
+++ b/src/test/ui/traits/alias/self-in-generics.rs
@@ -0,0 +1,8 @@
+#![feature(trait_alias)]
+
+pub trait SelfInput = Fn(&mut Self);
+
+pub fn f(_f: &dyn SelfInput) {}
+//~^ ERROR the trait alias `SelfInput` cannot be made into an object [E0038]
+
+fn main() {}
diff --git a/src/test/ui/traits/alias/self-in-generics.stderr b/src/test/ui/traits/alias/self-in-generics.stderr
new file mode 100644
index 00000000000..a1056872ea6
--- /dev/null
+++ b/src/test/ui/traits/alias/self-in-generics.stderr
@@ -0,0 +1,11 @@
+error[E0038]: the trait alias `SelfInput` cannot be made into an object
+  --> $DIR/self-in-generics.rs:5:19
+   |
+LL | pub fn f(_f: &dyn SelfInput) {}
+   |                   ^^^^^^^^^
+   |
+   = note: it cannot use `Self` as a type parameter in a supertrait or `where`-clause
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/src/test/ui/unspecified-self-in-trait-ref.rs b/src/test/ui/traits/unspecified-self-in-trait-ref.rs
index 158b5a98557..158b5a98557 100644
--- a/src/test/ui/unspecified-self-in-trait-ref.rs
+++ b/src/test/ui/traits/unspecified-self-in-trait-ref.rs
diff --git a/src/test/ui/unspecified-self-in-trait-ref.stderr b/src/test/ui/traits/unspecified-self-in-trait-ref.stderr
index 7869176bb3a..7869176bb3a 100644
--- a/src/test/ui/unspecified-self-in-trait-ref.stderr
+++ b/src/test/ui/traits/unspecified-self-in-trait-ref.stderr
diff --git a/src/test/ui/typeck/issue-100246.rs b/src/test/ui/typeck/issue-100246.rs
new file mode 100644
index 00000000000..8f0b34bab0c
--- /dev/null
+++ b/src/test/ui/typeck/issue-100246.rs
@@ -0,0 +1,30 @@
+#![recursion_limit = "5"] // To reduce noise
+
+//expect incompatible type error when ambiguous traits are in scope
+//and not an overflow error on the span in the main function.
+
+struct Ratio<T>(T);
+
+pub trait Pow {
+    fn pow(self) -> Self;
+}
+
+impl<'a, T> Pow for &'a Ratio<T>
+where
+    &'a T: Pow,
+{
+    fn pow(self) -> Self {
+        self
+    }
+}
+
+fn downcast<'a, W: ?Sized>() -> std::io::Result<&'a W> {
+    todo!()
+}
+
+struct Other;
+
+fn main() -> std::io::Result<()> {
+    let other: Other = downcast()?;//~ERROR 28:24: 28:35: `?` operator has incompatible types
+    Ok(())
+}
diff --git a/src/test/ui/typeck/issue-100246.stderr b/src/test/ui/typeck/issue-100246.stderr
new file mode 100644
index 00000000000..8b77de94e89
--- /dev/null
+++ b/src/test/ui/typeck/issue-100246.stderr
@@ -0,0 +1,13 @@
+error[E0308]: `?` operator has incompatible types
+  --> $DIR/issue-100246.rs:28:24
+   |
+LL |     let other: Other = downcast()?;
+   |                        ^^^^^^^^^^^ expected struct `Other`, found reference
+   |
+   = note: `?` operator cannot convert from `&_` to `Other`
+   = note: expected struct `Other`
+           found reference `&_`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 4fd148c47e733770c537efac5220744945d572e
+Subproject efd4ca3dc0b89929dc8c5f5c023d25978d76cb6
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 2278a8dc16b..380cd451987 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -965,7 +965,7 @@ Released 2021-09-09
   [#7407](https://github.com/rust-lang/rust-clippy/pull/7407)
 * [`redundant_allocation`]: Now additionally supports the `Arc<>` type
   [#7308](https://github.com/rust-lang/rust-clippy/pull/7308)
-* [`blacklisted_name`]: Now allows blacklisted names in test code
+* [`disallowed_names`]: Now allows disallowed names in test code
   [#7379](https://github.com/rust-lang/rust-clippy/pull/7379)
 * [`redundant_closure`]: Suggests `&mut` for `FnMut`
   [#7437](https://github.com/rust-lang/rust-clippy/pull/7437)
@@ -2066,7 +2066,7 @@ Released 2020-08-27
   [#5692](https://github.com/rust-lang/rust-clippy/pull/5692)
 * [`if_same_then_else`]: Don't assume multiplication is always commutative
   [#5702](https://github.com/rust-lang/rust-clippy/pull/5702)
-* [`blacklisted_name`]: Remove `bar` from the default configuration
+* [`disallowed_names`]: Remove `bar` from the default configuration
   [#5712](https://github.com/rust-lang/rust-clippy/pull/5712)
 * [`redundant_pattern_matching`]: Avoid suggesting non-`const fn` calls in const contexts
   [#5724](https://github.com/rust-lang/rust-clippy/pull/5724)
@@ -3522,6 +3522,7 @@ Released 2018-09-13
 [`derive_partial_eq_without_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq
 [`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method
 [`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods
+[`disallowed_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names
 [`disallowed_script_idents`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents
 [`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type
 [`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types
@@ -3685,6 +3686,7 @@ Released 2018-09-13
 [`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find
 [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
 [`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten
+[`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed
 [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map
 [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy
 [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive
@@ -3816,11 +3818,13 @@ Released 2018-09-13
 [`or_then_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_then_unwrap
 [`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing
 [`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional
+[`overly_complex_bool_expr`]: https://rust-lang.github.io/rust-clippy/master/index.html#overly_complex_bool_expr
 [`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic
 [`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn
 [`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params
 [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap
 [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl
+[`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none
 [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite
 [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch
 [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md
index 6e15133d267..28b4cfd5f09 100644
--- a/src/tools/clippy/CONTRIBUTING.md
+++ b/src/tools/clippy/CONTRIBUTING.md
@@ -30,10 +30,10 @@ All contributors are expected to follow the [Rust Code of Conduct].
 ## The Clippy book
 
 If you're new to Clippy and don't know where to start the [Clippy book] includes
-a developer guide and is a good place to start your journey.
+a [developer guide] and is a good place to start your journey.
 
-<!-- FIXME: Link to the deployed book, once it is deployed through CI -->
-[Clippy book]: book/src
+[Clippy book]: https://doc.rust-lang.org/nightly/clippy/index.html
+[developer guide]: https://doc.rust-lang.org/nightly/clippy/development/index.html
 
 ## High level approach
 
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 1c875c3adcf..b7e136ce9b2 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy"
-version = "0.1.64"
+version = "0.1.65"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md
index 2c3defeaa83..1193771ff73 100644
--- a/src/tools/clippy/README.md
+++ b/src/tools/clippy/README.md
@@ -144,7 +144,7 @@ value` mapping e.g.
 
 ```toml
 avoid-breaking-exported-api = false
-blacklisted-names = ["toto", "tata", "titi"]
+disallowed-names = ["toto", "tata", "titi"]
 cognitive-complexity-threshold = 30
 ```
 
diff --git a/src/tools/clippy/book/src/configuration.md b/src/tools/clippy/book/src/configuration.md
index 6e295ac3181..77f1d2e8797 100644
--- a/src/tools/clippy/book/src/configuration.md
+++ b/src/tools/clippy/book/src/configuration.md
@@ -7,7 +7,7 @@ basic `variable = value` mapping eg.
 
 ```toml
 avoid-breaking-exported-api = false
-blacklisted-names = ["toto", "tata", "titi"]
+disallowed-names = ["toto", "tata", "titi"]
 cognitive-complexity-threshold = 30
 ```
 
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index 03d2ef3d19e..10a8f31f457 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -438,7 +438,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str>
     let mut lint_context = None;
 
     let mut iter = rustc_lexer::tokenize(&file_contents).map(|t| {
-        let range = offset..offset + t.len;
+        let range = offset..offset + t.len as usize;
         offset = range.end;
 
         LintDeclSearchResult {
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index aed38bc2817..05e79a24188 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -836,7 +836,7 @@ pub(crate) struct LintDeclSearchResult<'a> {
 fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
     let mut offset = 0usize;
     let mut iter = tokenize(contents).map(|t| {
-        let range = offset..offset + t.len;
+        let range = offset..offset + t.len as usize;
         offset = range.end;
 
         LintDeclSearchResult {
@@ -899,7 +899,7 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) {
 fn parse_deprecated_contents(contents: &str, lints: &mut Vec<DeprecatedLint>) {
     let mut offset = 0usize;
     let mut iter = tokenize(contents).map(|t| {
-        let range = offset..offset + t.len;
+        let range = offset..offset + t.len as usize;
         offset = range.end;
 
         LintDeclSearchResult {
@@ -946,7 +946,7 @@ fn parse_renamed_contents(contents: &str, lints: &mut Vec<RenamedLint>) {
     for line in contents.lines() {
         let mut offset = 0usize;
         let mut iter = tokenize(line).map(|t| {
-            let range = offset..offset + t.len;
+            let range = offset..offset + t.len as usize;
             offset = range.end;
 
             LintDeclSearchResult {
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 79a56dc405d..738562ef855 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_lints"
-version = "0.1.64"
+version = "0.1.65"
 description = "A bunch of helpful lints to avoid common pitfalls in Rust"
 repository = "https://github.com/rust-lang/rust-clippy"
 readme = "README.md"
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
index 4caab623090..6a6554f968b 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
@@ -53,13 +53,14 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
                 if result_type_with_refs != result_type {
                     return;
                 } else if let Res::Local(binding_id) = path_res(cx, recv)
-                    && local_used_after_expr(cx, binding_id, recv) {
+                    && local_used_after_expr(cx, binding_id, recv)
+                {
                     return;
                 }
             }
             let mut app = Applicability::MachineApplicable;
             match method_segment.ident.as_str() {
-                "is_ok" if has_debug_impl(cx, substs.type_at(1)) => {
+                "is_ok" if type_suitable_to_unwrap(cx, substs.type_at(1)) => {
                     span_lint_and_sugg(
                         cx,
                         ASSERTIONS_ON_RESULT_STATES,
@@ -73,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
                         app,
                     );
                 }
-                "is_err" if has_debug_impl(cx, substs.type_at(0)) => {
+                "is_err" if type_suitable_to_unwrap(cx, substs.type_at(0)) => {
                     span_lint_and_sugg(
                         cx,
                         ASSERTIONS_ON_RESULT_STATES,
@@ -99,3 +100,7 @@ fn has_debug_impl<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         .get_diagnostic_item(sym::Debug)
         .map_or(false, |debug| implements_trait(cx, ty, debug, &[]))
 }
+
+fn type_suitable_to_unwrap<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    has_debug_impl(cx, ty) && !ty.is_unit() && !ty.is_never()
+}
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index 526ee2f891a..6eb78d21e82 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -64,7 +64,7 @@ declare_clippy_lint! {
     /// if a {}
     /// ```
     #[clippy::version = "pre 1.29.0"]
-    pub LOGIC_BUG,
+    pub OVERLY_COMPLEX_BOOL_EXPR,
     correctness,
     "boolean expressions that contain terminals which can be eliminated"
 }
@@ -72,7 +72,7 @@ declare_clippy_lint! {
 // For each pairs, both orders are considered.
 const METHODS_WITH_NEGATION: [(&str, &str); 2] = [("is_some", "is_none"), ("is_err", "is_ok")];
 
-declare_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, LOGIC_BUG]);
+declare_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, OVERLY_COMPLEX_BOOL_EXPR]);
 
 impl<'tcx> LateLintPass<'tcx> for NonminimalBool {
     fn check_fn(
@@ -396,7 +396,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
                     if stats.terminals[i] != 0 && simplified_stats.terminals[i] == 0 {
                         span_lint_hir_and_then(
                             self.cx,
-                            LOGIC_BUG,
+                            OVERLY_COMPLEX_BOOL_EXPR,
                             e.hir_id,
                             e.span,
                             "this boolean expression contains a logic bug",
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
index 64ea326b75a..6426e8c25ac 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
@@ -37,7 +37,7 @@ pub(super) fn check(
             span,
             &format!("casting the result of `{cast_from}::abs()` to {cast_to}"),
             "replace with",
-            format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..")),
+            format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..").maybe_par()),
             Applicability::MachineApplicable,
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
index 17fc81951f9..37b2fdcff09 100644
--- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
@@ -270,10 +270,7 @@ fn get_types_from_cast<'a>(
     let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| {
         if_chain! {
             // `from_type::from, to_type::max_value()`
-            if let ExprKind::Call(from_func, args) = &expr.kind;
-            // `to_type::max_value()`
-            if args.len() == 1;
-            if let limit = &args[0];
+            if let ExprKind::Call(from_func, [limit]) = &expr.kind;
             // `from_type::from`
             if let ExprKind::Path(ref path) = &from_func.kind;
             if let Some(from_sym) = get_implementing_type(path, INTS, "from");
diff --git a/src/tools/clippy/clippy_lints/src/create_dir.rs b/src/tools/clippy/clippy_lints/src/create_dir.rs
index 18d34370a7b..878248a6bdc 100644
--- a/src/tools/clippy/clippy_lints/src/create_dir.rs
+++ b/src/tools/clippy/clippy_lints/src/create_dir.rs
@@ -34,7 +34,7 @@ declare_lint_pass!(CreateDir => [CREATE_DIR]);
 impl LateLintPass<'_> for CreateDir {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         if_chain! {
-            if let ExprKind::Call(func, args) = expr.kind;
+            if let ExprKind::Call(func, [arg, ..]) = expr.kind;
             if let ExprKind::Path(ref path) = func.kind;
             if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id();
             if match_def_path(cx, def_id, &paths::STD_FS_CREATE_DIR);
@@ -45,7 +45,7 @@ impl LateLintPass<'_> for CreateDir {
                     expr.span,
                     "calling `std::fs::create_dir` where there may be a better way",
                     "consider calling `std::fs::create_dir_all` instead",
-                    format!("create_dir_all({})", snippet(cx, args[0].span, "..")),
+                    format!("create_dir_all({})", snippet(cx, arg.span, "..")),
                     Applicability::MaybeIncorrect,
                 )
             }
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index d99a1aa2969..74f7df61177 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -1,7 +1,9 @@
 use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
 use clippy_utils::source::snippet_with_macro_callsite;
 use clippy_utils::ty::{has_drop, is_copy};
-use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, match_def_path, paths};
+use clippy_utils::{
+    any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro, match_def_path, paths,
+};
 use if_chain::if_chain;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
@@ -94,6 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
             if let QPath::Resolved(None, _path) = qpath;
             let expr_ty = cx.typeck_results().expr_ty(expr);
             if let ty::Adt(def, ..) = expr_ty.kind();
+            if !is_from_proc_macro(cx, expr);
             then {
                 // TODO: Work out a way to put "whatever the imported way of referencing
                 // this type in this file" rather than a fully-qualified type.
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index a90f894a7b1..5d41c63928d 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, variant_of_res};
+use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, ty_sig, variant_of_res};
 use clippy_utils::{get_parent_expr, is_lint_allowed, path_to_local, walk_to_expr_usage};
 use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX};
 use rustc_data_structures::fx::FxIndexMap;
@@ -15,9 +15,9 @@ use rustc_hir::{
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable, TypeckResults};
+use rustc_middle::ty::{self, Binder, BoundVariableKind, List, Ty, TyCtxt, TypeVisitable, TypeckResults};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{symbol::sym, Span, Symbol};
+use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
 use rustc_trait_selection::infer::InferCtxtExt;
 
 declare_clippy_lint! {
@@ -183,24 +183,24 @@ enum State {
     },
     DerefedBorrow(DerefedBorrow),
     ExplicitDeref {
-        // Span and id of the top-level deref expression if the parent expression is a borrow.
-        deref_span_id: Option<(Span, HirId)>,
+        mutability: Option<Mutability>,
     },
     ExplicitDerefField {
         name: Symbol,
     },
     Reborrow {
-        deref_span: Span,
-        deref_hir_id: HirId,
+        mutability: Mutability,
+    },
+    Borrow {
+        mutability: Mutability,
     },
-    Borrow,
 }
 
 // A reference operation considered by this lint pass
 enum RefOp {
     Method(Mutability),
     Deref,
-    AddrOf,
+    AddrOf(Mutability),
 }
 
 struct RefPat {
@@ -263,7 +263,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
                             ));
                         } else if position.is_deref_stable() {
                             self.state = Some((
-                                State::ExplicitDeref { deref_span_id: None },
+                                State::ExplicitDeref { mutability: None },
                                 StateData { span: expr.span, hir_id: expr.hir_id, position },
                             ));
                         }
@@ -289,7 +289,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
                             },
                         ));
                     },
-                    RefOp::AddrOf => {
+                    RefOp::AddrOf(mutability) => {
                         // Find the number of times the borrow is auto-derefed.
                         let mut iter = adjustments.iter();
                         let mut deref_count = 0usize;
@@ -357,9 +357,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
                                 }),
                                 StateData { span: expr.span, hir_id: expr.hir_id, position },
                             ));
-                        } else if position.is_deref_stable() {
+                        } else if position.is_deref_stable()
+                            // Auto-deref doesn't combine with other adjustments
+                            && next_adjust.map_or(true, |a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
+                            && iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_)))
+                        {
                             self.state = Some((
-                                State::Borrow,
+                                State::Borrow { mutability },
                                 StateData {
                                     span: expr.span,
                                     hir_id: expr.hir_id,
@@ -395,7 +399,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
                     data,
                 ));
             },
-            (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf) if state.count != 0 => {
+            (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(_)) if state.count != 0 => {
                 self.state = Some((
                     State::DerefedBorrow(DerefedBorrow {
                         count: state.count - 1,
@@ -404,12 +408,12 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
                     data,
                 ));
             },
-            (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf) => {
+            (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(mutability)) => {
                 let position = data.position;
                 report(cx, expr, State::DerefedBorrow(state), data);
                 if position.is_deref_stable() {
                     self.state = Some((
-                        State::Borrow,
+                        State::Borrow { mutability },
                         StateData {
                             span: expr.span,
                             hir_id: expr.hir_id,
@@ -430,43 +434,28 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing {
                     ));
                 } else if position.is_deref_stable() {
                     self.state = Some((
-                        State::ExplicitDeref { deref_span_id: None },
+                        State::ExplicitDeref { mutability: None },
                         StateData { span: expr.span, hir_id: expr.hir_id, position },
                     ));
                 }
             },
 
-            (Some((State::Borrow, data)), RefOp::Deref) => {
+            (Some((State::Borrow { mutability }, data)), RefOp::Deref) => {
                 if typeck.expr_ty(sub_expr).is_ref() {
-                    self.state = Some((
-                        State::Reborrow {
-                            deref_span: expr.span,
-                            deref_hir_id: expr.hir_id,
-                        },
-                        data,
-                    ));
+                    self.state = Some((State::Reborrow { mutability }, data));
                 } else {
                     self.state = Some((
                         State::ExplicitDeref {
-                            deref_span_id: Some((expr.span, expr.hir_id)),
+                            mutability: Some(mutability),
                         },
                         data,
                     ));
                 }
             },
-            (
-                Some((
-                    State::Reborrow {
-                        deref_span,
-                        deref_hir_id,
-                    },
-                    data,
-                )),
-                RefOp::Deref,
-            ) => {
+            (Some((State::Reborrow { mutability }, data)), RefOp::Deref) => {
                 self.state = Some((
                     State::ExplicitDeref {
-                        deref_span_id: Some((deref_span, deref_hir_id)),
+                        mutability: Some(mutability),
                     },
                     data,
                 ));
@@ -573,7 +562,7 @@ fn try_parse_ref_op<'tcx>(
         ExprKind::Unary(UnOp::Deref, sub_expr) if !typeck.expr_ty(sub_expr).is_unsafe_ptr() => {
             return Some((RefOp::Deref, sub_expr));
         },
-        ExprKind::AddrOf(BorrowKind::Ref, _, sub_expr) => return Some((RefOp::AddrOf, sub_expr)),
+        ExprKind::AddrOf(BorrowKind::Ref, mutability, sub_expr) => return Some((RefOp::AddrOf(mutability), sub_expr)),
         _ => return None,
     };
     if tcx.is_diagnostic_item(sym::deref_method, def_id) {
@@ -609,18 +598,21 @@ enum Position {
     Postfix,
     Deref,
     /// Any other location which will trigger auto-deref to a specific time.
-    DerefStable(i8),
+    /// Contains the precedence of the parent expression and whether the target type is sized.
+    DerefStable(i8, bool),
     /// Any other location which will trigger auto-reborrowing.
+    /// Contains the precedence of the parent expression.
     ReborrowStable(i8),
+    /// Contains the precedence of the parent expression.
     Other(i8),
 }
 impl Position {
     fn is_deref_stable(self) -> bool {
-        matches!(self, Self::DerefStable(_))
+        matches!(self, Self::DerefStable(..))
     }
 
     fn is_reborrow_stable(self) -> bool {
-        matches!(self, Self::DerefStable(_) | Self::ReborrowStable(_))
+        matches!(self, Self::DerefStable(..) | Self::ReborrowStable(_))
     }
 
     fn can_auto_borrow(self) -> bool {
@@ -628,7 +620,7 @@ impl Position {
     }
 
     fn lint_explicit_deref(self) -> bool {
-        matches!(self, Self::Other(_) | Self::DerefStable(_) | Self::ReborrowStable(_))
+        matches!(self, Self::Other(_) | Self::DerefStable(..) | Self::ReborrowStable(_))
     }
 
     fn precedence(self) -> i8 {
@@ -639,7 +631,7 @@ impl Position {
             | Self::FieldAccess(_)
             | Self::Postfix => PREC_POSTFIX,
             Self::Deref => PREC_PREFIX,
-            Self::DerefStable(p) | Self::ReborrowStable(p) | Self::Other(p) => p,
+            Self::DerefStable(p, _) | Self::ReborrowStable(p) | Self::Other(p) => p,
         }
     }
 }
@@ -659,7 +651,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
         }
         match parent {
             Node::Local(Local { ty: Some(ty), span, .. }) if span.ctxt() == ctxt => {
-                Some(binding_ty_auto_deref_stability(ty, precedence))
+                Some(binding_ty_auto_deref_stability(cx, ty, precedence, List::empty()))
             },
             Node::Item(&Item {
                 kind: ItemKind::Static(..) | ItemKind::Const(..),
@@ -680,11 +672,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
                 ..
             }) if span.ctxt() == ctxt => {
                 let ty = cx.tcx.type_of(def_id);
-                Some(if ty.is_ref() {
-                    Position::DerefStable(precedence)
-                } else {
-                    Position::Other(precedence)
-                })
+                Some(ty_auto_deref_stability(cx, ty, precedence).position_for_result(cx))
             },
 
             Node::Item(&Item {
@@ -705,45 +693,38 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
                 span,
                 ..
             }) if span.ctxt() == ctxt => {
-                let output = cx.tcx.fn_sig(def_id.to_def_id()).skip_binder().output();
-                Some(if !output.is_ref() {
-                    Position::Other(precedence)
-                } else if output.has_placeholders() || output.has_opaque_types() {
-                    Position::ReborrowStable(precedence)
-                } else {
-                    Position::DerefStable(precedence)
-                })
+                let output = cx
+                    .tcx
+                    .erase_late_bound_regions(cx.tcx.fn_sig(def_id.to_def_id()).output());
+                Some(ty_auto_deref_stability(cx, output, precedence).position_for_result(cx))
             },
 
             Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind {
                 ExprKind::Ret(_) => {
                     let owner_id = cx.tcx.hir().body_owner(cx.enclosing_body.unwrap());
                     Some(
-                        if let Node::Expr(Expr {
-                            kind: ExprKind::Closure(&Closure { fn_decl, .. }),
-                            ..
-                        }) = cx.tcx.hir().get(owner_id)
+                        if let Node::Expr(
+                            closure_expr @ Expr {
+                                kind: ExprKind::Closure(closure),
+                                ..
+                            },
+                        ) = cx.tcx.hir().get(owner_id)
                         {
-                            match fn_decl.output {
-                                FnRetTy::Return(ty) => binding_ty_auto_deref_stability(ty, precedence),
-                                FnRetTy::DefaultReturn(_) => Position::Other(precedence),
-                            }
+                            closure_result_position(cx, closure, cx.typeck_results().expr_ty(closure_expr), precedence)
                         } else {
                             let output = cx
                                 .tcx
-                                .fn_sig(cx.tcx.hir().local_def_id(owner_id))
-                                .skip_binder()
-                                .output();
-                            if !output.is_ref() {
-                                Position::Other(precedence)
-                            } else if output.has_placeholders() || output.has_opaque_types() {
-                                Position::ReborrowStable(precedence)
-                            } else {
-                                Position::DerefStable(precedence)
-                            }
+                                .erase_late_bound_regions(cx.tcx.fn_sig(cx.tcx.hir().local_def_id(owner_id)).output());
+                            ty_auto_deref_stability(cx, output, precedence).position_for_result(cx)
                         },
                     )
                 },
+                ExprKind::Closure(closure) => Some(closure_result_position(
+                    cx,
+                    closure,
+                    cx.typeck_results().expr_ty(parent),
+                    precedence,
+                )),
                 ExprKind::Call(func, _) if func.hir_id == child_id => {
                     (child_id == e.hir_id).then_some(Position::Callee)
                 },
@@ -755,8 +736,9 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
                     .map(|(hir_ty, ty)| match hir_ty {
                         // Type inference for closures can depend on how they're called. Only go by the explicit
                         // types here.
-                        Some(ty) => binding_ty_auto_deref_stability(ty, precedence),
-                        None => param_auto_deref_stability(ty.skip_binder(), precedence),
+                        Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()),
+                        None => ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence)
+                            .position_for_arg(),
                     }),
                 ExprKind::MethodCall(_, args, _) => {
                     let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap();
@@ -797,7 +779,12 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
                                 Position::MethodReceiver
                             }
                         } else {
-                            param_auto_deref_stability(cx.tcx.fn_sig(id).skip_binder().inputs()[i], precedence)
+                            ty_auto_deref_stability(
+                                cx,
+                                cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)),
+                                precedence,
+                            )
+                            .position_for_arg()
                         }
                     })
                 },
@@ -808,7 +795,9 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
                         .find(|f| f.expr.hir_id == child_id)
                         .zip(variant)
                         .and_then(|(field, variant)| variant.fields.iter().find(|f| f.name == field.ident.name))
-                        .map(|field| param_auto_deref_stability(cx.tcx.type_of(field.did), precedence))
+                        .map(|field| {
+                            ty_auto_deref_stability(cx, cx.tcx.type_of(field.did), precedence).position_for_arg()
+                        })
                 },
                 ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)),
                 ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref),
@@ -831,6 +820,26 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
     (position, adjustments)
 }
 
+fn closure_result_position<'tcx>(
+    cx: &LateContext<'tcx>,
+    closure: &'tcx Closure<'_>,
+    ty: Ty<'tcx>,
+    precedence: i8,
+) -> Position {
+    match closure.fn_decl.output {
+        FnRetTy::Return(hir_ty) => {
+            if let Some(sig) = ty_sig(cx, ty)
+                && let Some(output) = sig.output()
+            {
+                binding_ty_auto_deref_stability(cx, hir_ty, precedence, output.bound_vars())
+            } else {
+                Position::Other(precedence)
+            }
+        },
+        FnRetTy::DefaultReturn(_) => Position::Other(precedence),
+    }
+}
+
 // Checks the stability of auto-deref when assigned to a binding with the given explicit type.
 //
 // e.g.
@@ -840,7 +849,12 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, &
 //
 // Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when
 // switching to auto-dereferencing.
-fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position {
+fn binding_ty_auto_deref_stability<'tcx>(
+    cx: &LateContext<'tcx>,
+    ty: &'tcx hir::Ty<'_>,
+    precedence: i8,
+    binder_args: &'tcx List<BoundVariableKind>,
+) -> Position {
     let TyKind::Rptr(_, ty) = &ty.kind else {
         return Position::Other(precedence);
     };
@@ -870,21 +884,33 @@ fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position
                 {
                     Position::ReborrowStable(precedence)
                 } else {
-                    Position::DerefStable(precedence)
+                    Position::DerefStable(
+                        precedence,
+                        cx.tcx
+                            .erase_late_bound_regions(Binder::bind_with_vars(
+                                cx.typeck_results().node_type(ty.ty.hir_id),
+                                binder_args,
+                            ))
+                            .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
+                    )
                 }
             },
-            TyKind::Slice(_)
-            | TyKind::Array(..)
-            | TyKind::BareFn(_)
-            | TyKind::Never
+            TyKind::Slice(_) => Position::DerefStable(precedence, false),
+            TyKind::Array(..) | TyKind::Ptr(_) | TyKind::BareFn(_) => Position::DerefStable(precedence, true),
+            TyKind::Never
             | TyKind::Tup(_)
-            | TyKind::Ptr(_)
-            | TyKind::TraitObject(..)
-            | TyKind::Path(_) => Position::DerefStable(precedence),
-            TyKind::OpaqueDef(..)
-            | TyKind::Infer
-            | TyKind::Typeof(..)
-            | TyKind::Err => Position::ReborrowStable(precedence),
+            | TyKind::Path(_) => Position::DerefStable(
+                precedence,
+                cx.tcx
+                    .erase_late_bound_regions(Binder::bind_with_vars(
+                        cx.typeck_results().node_type(ty.ty.hir_id),
+                        binder_args,
+                    ))
+                    .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
+            ),
+            TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => {
+                Position::ReborrowStable(precedence)
+            },
         };
     }
 }
@@ -920,10 +946,39 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool {
     v.0
 }
 
+struct TyPosition<'tcx> {
+    position: Position,
+    ty: Option<Ty<'tcx>>,
+}
+impl From<Position> for TyPosition<'_> {
+    fn from(position: Position) -> Self {
+        Self { position, ty: None }
+    }
+}
+impl<'tcx> TyPosition<'tcx> {
+    fn new_deref_stable_for_result(precedence: i8, ty: Ty<'tcx>) -> Self {
+        Self {
+            position: Position::ReborrowStable(precedence),
+            ty: Some(ty),
+        }
+    }
+    fn position_for_result(self, cx: &LateContext<'tcx>) -> Position {
+        match (self.position, self.ty) {
+            (Position::ReborrowStable(precedence), Some(ty)) => {
+                Position::DerefStable(precedence, ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env))
+            },
+            (position, _) => position,
+        }
+    }
+    fn position_for_arg(self) -> Position {
+        self.position
+    }
+}
+
 // Checks whether a type is stable when switching to auto dereferencing,
-fn param_auto_deref_stability(ty: Ty<'_>, precedence: i8) -> Position {
+fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedence: i8) -> TyPosition<'tcx> {
     let ty::Ref(_, mut ty, _) = *ty.kind() else {
-        return Position::Other(precedence);
+        return Position::Other(precedence).into();
     };
 
     loop {
@@ -932,35 +987,38 @@ fn param_auto_deref_stability(ty: Ty<'_>, precedence: i8) -> Position {
                 ty = ref_ty;
                 continue;
             },
-            ty::Infer(_)
-            | ty::Error(_)
-            | ty::Param(_)
-            | ty::Bound(..)
-            | ty::Opaque(..)
-            | ty::Placeholder(_)
-            | ty::Dynamic(..) => Position::ReborrowStable(precedence),
-            ty::Adt(..) if ty.has_placeholders() || ty.has_param_types_or_consts() => {
-                Position::ReborrowStable(precedence)
+            ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty),
+            ty::Infer(_) | ty::Error(_) | ty::Bound(..) | ty::Opaque(..) | ty::Placeholder(_) | ty::Dynamic(..) => {
+                Position::ReborrowStable(precedence).into()
             },
-            ty::Adt(..)
-            | ty::Bool
+            ty::Adt(..) if ty.has_placeholders() || ty.has_opaque_types() => {
+                Position::ReborrowStable(precedence).into()
+            },
+            ty::Adt(_, substs) if substs.has_param_types_or_consts() => {
+                TyPosition::new_deref_stable_for_result(precedence, ty)
+            },
+            ty::Bool
             | ty::Char
             | ty::Int(_)
             | ty::Uint(_)
-            | ty::Float(_)
-            | ty::Foreign(_)
-            | ty::Str
             | ty::Array(..)
-            | ty::Slice(..)
+            | ty::Float(_)
             | ty::RawPtr(..)
+            | ty::FnPtr(_) => Position::DerefStable(precedence, true).into(),
+            ty::Str | ty::Slice(..) => Position::DerefStable(precedence, false).into(),
+            ty::Adt(..)
+            | ty::Foreign(_)
             | ty::FnDef(..)
-            | ty::FnPtr(_)
-            | ty::Closure(..)
             | ty::Generator(..)
             | ty::GeneratorWitness(..)
+            | ty::Closure(..)
             | ty::Never
             | ty::Tuple(_)
-            | ty::Projection(_) => Position::DerefStable(precedence),
+            | ty::Projection(_) => Position::DerefStable(
+                precedence,
+                ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
+            )
+            .into(),
         };
     }
 }
@@ -1040,34 +1098,64 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
                 diag.span_suggestion(data.span, "change this to", sugg, app);
             });
         },
-        State::ExplicitDeref { deref_span_id } => {
-            let (span, hir_id, precedence) = if let Some((span, hir_id)) = deref_span_id
+        State::ExplicitDeref { mutability } => {
+            if matches!(
+                expr.kind,
+                ExprKind::Block(..)
+                    | ExprKind::ConstBlock(_)
+                    | ExprKind::If(..)
+                    | ExprKind::Loop(..)
+                    | ExprKind::Match(..)
+            ) && matches!(data.position, Position::DerefStable(_, true))
+            {
+                // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
+                return;
+            }
+
+            let (prefix, precedence) = if let Some(mutability) = mutability
                 && !cx.typeck_results().expr_ty(expr).is_ref()
             {
-                (span, hir_id, PREC_PREFIX)
+                let prefix = match mutability {
+                    Mutability::Not => "&",
+                    Mutability::Mut => "&mut ",
+                };
+                (prefix, 0)
             } else {
-                (data.span, data.hir_id, data.position.precedence())
+                ("", data.position.precedence())
             };
             span_lint_hir_and_then(
                 cx,
                 EXPLICIT_AUTO_DEREF,
-                hir_id,
-                span,
+                data.hir_id,
+                data.span,
                 "deref which would be done by auto-deref",
                 |diag| {
                     let mut app = Applicability::MachineApplicable;
-                    let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, span.ctxt(), "..", &mut app);
+                    let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
                     let sugg =
                         if !snip_is_macro && expr.precedence().order() < precedence && !has_enclosing_paren(&snip) {
-                            format!("({})", snip)
+                            format!("{}({})", prefix, snip)
                         } else {
-                            snip.into()
+                            format!("{}{}", prefix, snip)
                         };
-                    diag.span_suggestion(span, "try this", sugg, app);
+                    diag.span_suggestion(data.span, "try this", sugg, app);
                 },
             );
         },
         State::ExplicitDerefField { .. } => {
+            if matches!(
+                expr.kind,
+                ExprKind::Block(..)
+                    | ExprKind::ConstBlock(_)
+                    | ExprKind::If(..)
+                    | ExprKind::Loop(..)
+                    | ExprKind::Match(..)
+            ) && matches!(data.position, Position::DerefStable(_, true))
+            {
+                // Rustc bug: auto deref doesn't work on block expression when targeting sized types.
+                return;
+            }
+
             span_lint_hir_and_then(
                 cx,
                 EXPLICIT_AUTO_DEREF,
@@ -1081,7 +1169,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
                 },
             );
         },
-        State::Borrow | State::Reborrow { .. } => (),
+        State::Borrow { .. } | State::Reborrow { .. } => (),
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/blacklisted_name.rs b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
index 1600fb25d89..6e6615f08ee 100644
--- a/src/tools/clippy/clippy_lints/src/blacklisted_name.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
@@ -6,7 +6,7 @@ use rustc_session::{declare_tool_lint, impl_lint_pass};
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for usage of blacklisted names for variables, such
+    /// Checks for usage of disallowed names for variables, such
     /// as `foo`.
     ///
     /// ### Why is this bad?
@@ -18,21 +18,21 @@ declare_clippy_lint! {
     /// let foo = 3.14;
     /// ```
     #[clippy::version = "pre 1.29.0"]
-    pub BLACKLISTED_NAME,
+    pub DISALLOWED_NAMES,
     style,
-    "usage of a blacklisted/placeholder name"
+    "usage of a disallowed/placeholder name"
 }
 
 #[derive(Clone, Debug)]
-pub struct BlacklistedName {
-    blacklist: FxHashSet<String>,
+pub struct DisallowedNames {
+    disallow: FxHashSet<String>,
     test_modules_deep: u32,
 }
 
-impl BlacklistedName {
-    pub fn new(blacklist: FxHashSet<String>) -> Self {
+impl DisallowedNames {
+    pub fn new(disallow: FxHashSet<String>) -> Self {
         Self {
-            blacklist,
+            disallow,
             test_modules_deep: 0,
         }
     }
@@ -42,9 +42,9 @@ impl BlacklistedName {
     }
 }
 
-impl_lint_pass!(BlacklistedName => [BLACKLISTED_NAME]);
+impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]);
 
-impl<'tcx> LateLintPass<'tcx> for BlacklistedName {
+impl<'tcx> LateLintPass<'tcx> for DisallowedNames {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
         if is_test_module_or_function(cx.tcx, item) {
             self.test_modules_deep = self.test_modules_deep.saturating_add(1);
@@ -58,12 +58,12 @@ impl<'tcx> LateLintPass<'tcx> for BlacklistedName {
         }
 
         if let PatKind::Binding(.., ident, _) = pat.kind {
-            if self.blacklist.contains(&ident.name.to_string()) {
+            if self.disallow.contains(&ident.name.to_string()) {
                 span_lint(
                     cx,
-                    BLACKLISTED_NAME,
+                    DISALLOWED_NAMES,
                     ident.span,
-                    &format!("use of a blacklisted/placeholder name `{}`", ident.name),
+                    &format!("use of a disallowed/placeholder name `{}`", ident.name),
                 );
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/double_parens.rs b/src/tools/clippy/clippy_lints/src/double_parens.rs
index a33ef5ce6e3..0f1d701865e 100644
--- a/src/tools/clippy/clippy_lints/src/double_parens.rs
+++ b/src/tools/clippy/clippy_lints/src/double_parens.rs
@@ -61,9 +61,8 @@ impl EarlyLintPass for DoubleParens {
                     }
                 }
             },
-            ExprKind::MethodCall(_, ref params, _) => {
-                if params.len() == 2 {
-                    let param = &params[1];
+            ExprKind::MethodCall(_, _, ref params, _) => {
+                if let [ref param] = params[..] {
                     if let ExprKind::Paren(_) = param.kind {
                         span_lint(cx, DOUBLE_PARENS, param.span, msg);
                     }
diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs
index db0166da57f..01cefe4af85 100644
--- a/src/tools/clippy/clippy_lints/src/formatting.rs
+++ b/src/tools/clippy/clippy_lints/src/formatting.rs
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note};
+use clippy_utils::is_span_if;
 use clippy_utils::source::snippet_opt;
 use if_chain::if_chain;
 use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
@@ -297,12 +298,11 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) {
 fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) {
     if_chain! {
         if !first.span.from_expansion() && !second.span.from_expansion();
-        if let ExprKind::If(cond_expr, ..) = &first.kind;
+        if matches!(first.kind, ExprKind::If(..));
         if is_block(second) || is_if(second);
 
         // Proc-macros can give weird spans. Make sure this is actually an `if`.
-        if let Some(if_snip) = snippet_opt(cx, first.span.until(cond_expr.span));
-        if if_snip.starts_with("if");
+        if is_span_if(cx, first.span);
 
         // If there is a line break between the two expressions, don't lint.
         // If there is a non-whitespace character, this span came from a proc-macro.
diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
index 57b07513205..74941d817be 100644
--- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
+++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
@@ -46,7 +46,7 @@ declare_lint_pass!(FromStrRadix10 => [FROM_STR_RADIX_10]);
 impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) {
         if_chain! {
-            if let ExprKind::Call(maybe_path, arguments) = &exp.kind;
+            if let ExprKind::Call(maybe_path, [src, radix]) = &exp.kind;
             if let ExprKind::Path(QPath::TypeRelative(ty, pathseg)) = &maybe_path.kind;
 
             // check if the first part of the path is some integer primitive
@@ -60,20 +60,19 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 {
             if pathseg.ident.name.as_str() == "from_str_radix";
 
             // check if the second argument is a primitive `10`
-            if arguments.len() == 2;
-            if let ExprKind::Lit(lit) = &arguments[1].kind;
+            if let ExprKind::Lit(lit) = &radix.kind;
             if let rustc_ast::ast::LitKind::Int(10, _) = lit.node;
 
             then {
-                let expr = if let ExprKind::AddrOf(_, _, expr) = &arguments[0].kind {
+                let expr = if let ExprKind::AddrOf(_, _, expr) = &src.kind {
                     let ty = cx.typeck_results().expr_ty(expr);
                     if is_ty_stringish(cx, ty) {
                         expr
                     } else {
-                        &arguments[0]
+                        &src
                     }
                 } else {
-                    &arguments[0]
+                    &src
                 };
 
                 let sugg = Sugg::hir_with_applicability(
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 0ba9b7ae7e5..01082cc8eeb 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_all.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_all.rs
@@ -15,11 +15,10 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE),
     LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK),
     LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF),
-    LintId::of(blacklisted_name::BLACKLISTED_NAME),
     LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
     LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
-    LintId::of(booleans::LOGIC_BUG),
     LintId::of(booleans::NONMINIMAL_BOOL),
+    LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR),
     LintId::of(borrow_deref_ref::BORROW_DEREF_REF),
     LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN),
     LintId::of(casts::CAST_ABS_TO_UNSIGNED),
@@ -46,6 +45,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD),
     LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
     LintId::of(disallowed_methods::DISALLOWED_METHODS),
+    LintId::of(disallowed_names::DISALLOWED_NAMES),
     LintId::of(disallowed_types::DISALLOWED_TYPES),
     LintId::of(doc::MISSING_SAFETY_DOC),
     LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
@@ -144,7 +144,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(matches::MATCH_STR_CASE_MISMATCH),
     LintId::of(matches::NEEDLESS_MATCH),
     LintId::of(matches::REDUNDANT_PATTERN_MATCHING),
-    LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE),
     LintId::of(matches::SINGLE_MATCH),
     LintId::of(matches::WILDCARD_IN_OR_PATTERNS),
     LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE),
@@ -267,6 +266,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![
     LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP),
     LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL),
     LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL),
+    LintId::of(partialeq_to_none::PARTIALEQ_TO_NONE),
     LintId::of(precedence::PRECEDENCE),
     LintId::of(ptr::CMP_NULL),
     LintId::of(ptr::INVALID_NULL_PTR_USAGE),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs b/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs
index 9975859c54f..006275d1383 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs
@@ -8,7 +8,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve
     LintId::of(attrs::DEPRECATED_SEMVER),
     LintId::of(attrs::MISMATCHED_TARGET_OS),
     LintId::of(attrs::USELESS_ATTRIBUTE),
-    LintId::of(booleans::LOGIC_BUG),
+    LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR),
     LintId::of(casts::CAST_REF_TO_MUT),
     LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES),
     LintId::of(copies::IFS_SAME_COND),
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 99bde35cf15..c540573b802 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs
@@ -55,11 +55,10 @@ store.register_lints(&[
     await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE,
     await_holding_invalid::AWAIT_HOLDING_LOCK,
     await_holding_invalid::AWAIT_HOLDING_REFCELL_REF,
-    blacklisted_name::BLACKLISTED_NAME,
     blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS,
     bool_assert_comparison::BOOL_ASSERT_COMPARISON,
-    booleans::LOGIC_BUG,
     booleans::NONMINIMAL_BOOL,
+    booleans::OVERLY_COMPLEX_BOOL_EXPR,
     borrow_as_ptr::BORROW_AS_PTR,
     borrow_deref_ref::BORROW_DEREF_REF,
     bytecount::NAIVE_BYTECOUNT,
@@ -116,6 +115,7 @@ store.register_lints(&[
     derive::EXPL_IMPL_CLONE_ON_COPY,
     derive::UNSAFE_DERIVE_DESERIALIZE,
     disallowed_methods::DISALLOWED_METHODS,
+    disallowed_names::DISALLOWED_NAMES,
     disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS,
     disallowed_types::DISALLOWED_TYPES,
     doc::DOC_MARKDOWN,
@@ -244,6 +244,7 @@ store.register_lints(&[
     manual_assert::MANUAL_ASSERT,
     manual_async_fn::MANUAL_ASYNC_FN,
     manual_bits::MANUAL_BITS,
+    manual_instant_elapsed::MANUAL_INSTANT_ELAPSED,
     manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE,
     manual_ok_or::MANUAL_OK_OR,
     manual_rem_euclid::MANUAL_REM_EUCLID,
@@ -453,6 +454,7 @@ store.register_lints(&[
     panic_unimplemented::UNIMPLEMENTED,
     panic_unimplemented::UNREACHABLE,
     partialeq_ne_impl::PARTIALEQ_NE_IMPL,
+    partialeq_to_none::PARTIALEQ_TO_NONE,
     pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE,
     pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF,
     path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE,
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs b/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs
index 642d629971d..91210b23afe 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs
@@ -13,6 +13,7 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![
     LintId::of(future_not_send::FUTURE_NOT_SEND),
     LintId::of(index_refutable_slice::INDEX_REFUTABLE_SLICE),
     LintId::of(let_if_seq::USELESS_LET_IF_SEQ),
+    LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE),
     LintId::of(methods::ITER_WITH_DRAIN),
     LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN),
     LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs b/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
index a1b54665814..bd7d1a15ab4 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs
@@ -49,6 +49,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![
     LintId::of(loops::EXPLICIT_ITER_LOOP),
     LintId::of(macro_use::MACRO_USE_IMPORTS),
     LintId::of(manual_assert::MANUAL_ASSERT),
+    LintId::of(manual_instant_elapsed::MANUAL_INSTANT_ELAPSED),
     LintId::of(manual_ok_or::MANUAL_OK_OR),
     LintId::of(matches::MATCH_BOOL),
     LintId::of(matches::MATCH_ON_VEC_ITEMS),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_style.rs b/src/tools/clippy/clippy_lints/src/lib.register_style.rs
index e95bab1d045..bfa654238f1 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_style.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_style.rs
@@ -4,7 +4,6 @@
 
 store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS),
-    LintId::of(blacklisted_name::BLACKLISTED_NAME),
     LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS),
     LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON),
     LintId::of(casts::FN_TO_NUMERIC_CAST),
@@ -17,6 +16,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(dereference::NEEDLESS_BORROW),
     LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ),
     LintId::of(disallowed_methods::DISALLOWED_METHODS),
+    LintId::of(disallowed_names::DISALLOWED_NAMES),
     LintId::of(disallowed_types::DISALLOWED_TYPES),
     LintId::of(doc::MISSING_SAFETY_DOC),
     LintId::of(doc::NEEDLESS_DOCTEST_MAIN),
@@ -100,6 +100,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![
     LintId::of(operators::ASSIGN_OP_PATTERN),
     LintId::of(operators::OP_REF),
     LintId::of(operators::PTR_EQ),
+    LintId::of(partialeq_to_none::PARTIALEQ_TO_NONE),
     LintId::of(ptr::CMP_NULL),
     LintId::of(ptr::PTR_ARG),
     LintId::of(question_mark::QUESTION_MARK),
diff --git a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs b/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
index f7558f87098..964992bd94f 100644
--- a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs
@@ -22,7 +22,6 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec!
     LintId::of(loops::EMPTY_LOOP),
     LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES),
     LintId::of(loops::MUT_RANGE_BOUND),
-    LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE),
     LintId::of(methods::NO_EFFECT_REPLACE),
     LintId::of(methods::SUSPICIOUS_MAP),
     LintId::of(mut_key::MUTABLE_KEY_TYPE),
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index eb3841272b1..2975399a8bb 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -178,7 +178,6 @@ mod assertions_on_result_states;
 mod async_yields_async;
 mod attrs;
 mod await_holding_invalid;
-mod blacklisted_name;
 mod blocks_in_if_conditions;
 mod bool_assert_comparison;
 mod booleans;
@@ -206,6 +205,7 @@ mod dereference;
 mod derivable_impls;
 mod derive;
 mod disallowed_methods;
+mod disallowed_names;
 mod disallowed_script_idents;
 mod disallowed_types;
 mod doc;
@@ -274,6 +274,7 @@ mod main_recursion;
 mod manual_assert;
 mod manual_async_fn;
 mod manual_bits;
+mod manual_instant_elapsed;
 mod manual_non_exhaustive;
 mod manual_ok_or;
 mod manual_rem_euclid;
@@ -332,6 +333,7 @@ mod overflow_check_conditional;
 mod panic_in_result_fn;
 mod panic_unimplemented;
 mod partialeq_ne_impl;
+mod partialeq_to_none;
 mod pass_by_ref_or_value;
 mod path_buf_push_overwrite;
 mod pattern_type_mismatch;
@@ -487,7 +489,7 @@ pub fn read_conf(sess: &Session) -> Conf {
         },
     };
 
-    let TryConf { conf, errors } = utils::conf::read(&file_name);
+    let TryConf { conf, errors, warnings } = utils::conf::read(&file_name);
     // all conf errors are non-fatal, we just use the default conf in case of error
     for error in errors {
         sess.err(&format!(
@@ -497,6 +499,15 @@ pub fn read_conf(sess: &Session) -> Conf {
         ));
     }
 
+    for warning in warnings {
+        sess.struct_warn(&format!(
+            "error reading Clippy's configuration file `{}`: {}",
+            file_name.display(),
+            format_error(warning)
+        ))
+        .emit();
+    }
+
     conf
 }
 
@@ -675,8 +686,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|| Box::new(swap::Swap));
     store.register_late_pass(|| Box::new(overflow_check_conditional::OverflowCheckConditional));
     store.register_late_pass(|| Box::new(new_without_default::NewWithoutDefault::default()));
-    let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>();
-    store.register_late_pass(move || Box::new(blacklisted_name::BlacklistedName::new(blacklisted_names.clone())));
+    let disallowed_names = conf.disallowed_names.iter().cloned().collect::<FxHashSet<_>>();
+    store.register_late_pass(move || Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone())));
     let too_many_arguments_threshold = conf.too_many_arguments_threshold;
     let too_many_lines_threshold = conf.too_many_lines_threshold;
     store.register_late_pass(move || {
@@ -921,6 +932,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move || Box::new(operators::Operators::new(verbose_bit_mask_threshold)));
     store.register_late_pass(|| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked));
     store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default()));
+    store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed));
+    store.register_late_pass(|| Box::new(partialeq_to_none::PartialeqToNone));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
index b31015d195b..a65df48e413 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
@@ -119,11 +119,9 @@ fn build_manual_memcpy_suggestion<'tcx>(
 
     let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| {
         if_chain! {
-            if let ExprKind::MethodCall(method, len_args, _) = end.kind;
+            if let ExprKind::MethodCall(method, [recv], _) = end.kind;
             if method.ident.name == sym::len;
-            if len_args.len() == 1;
-            if let Some(arg) = len_args.get(0);
-            if path_to_local(arg) == path_to_local(base);
+            if path_to_local(recv) == path_to_local(base);
             then {
                 if sugg.to_string() == end_str {
                     sugg::EMPTY.into()
@@ -343,10 +341,8 @@ fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Opti
 
 fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> {
     if_chain! {
-        if let ExprKind::MethodCall(method, args, _) = expr.kind;
+        if let ExprKind::MethodCall(method, [arg], _) = expr.kind;
         if method.ident.name == sym::clone;
-        if args.len() == 1;
-        if let Some(arg) = args.get(0);
         then { arg } else { expr }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index a7ef562b21f..7ca4a7c4ebf 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -188,10 +188,9 @@ pub(super) fn check<'tcx>(
 
 fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool {
     if_chain! {
-        if let ExprKind::MethodCall(method, len_args, _) = expr.kind;
-        if len_args.len() == 1;
+        if let ExprKind::MethodCall(method, [recv], _) = expr.kind;
         if method.ident.name == sym::len;
-        if let ExprKind::Path(QPath::Resolved(_, path)) = len_args[0].kind;
+        if let ExprKind::Path(QPath::Resolved(_, path)) = recv.kind;
         if path.segments.len() == 1;
         if path.segments[0].ident.name == var;
         then {
diff --git a/src/tools/clippy/clippy_lints/src/manual_instant_elapsed.rs b/src/tools/clippy/clippy_lints/src/manual_instant_elapsed.rs
new file mode 100644
index 00000000000..331cda1db89
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/manual_instant_elapsed.rs
@@ -0,0 +1,69 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::source_map::Spanned;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Lints subtraction between `Instant::now()` and another `Instant`.
+    ///
+    /// ### Why is this bad?
+    /// It is easy to accidentally write `prev_instant - Instant::now()`, which will always be 0ns
+    /// as `Instant` subtraction saturates.
+    ///
+    /// `prev_instant.elapsed()` also more clearly signals intention.
+    ///
+    /// ### Example
+    /// ```rust
+    /// use std::time::Instant;
+    /// let prev_instant = Instant::now();
+    /// let duration = Instant::now() - prev_instant;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use std::time::Instant;
+    /// let prev_instant = Instant::now();
+    /// let duration = prev_instant.elapsed();
+    /// ```
+    #[clippy::version = "1.64.0"]
+    pub MANUAL_INSTANT_ELAPSED,
+    pedantic,
+    "subtraction between `Instant::now()` and previous `Instant`"
+}
+
+declare_lint_pass!(ManualInstantElapsed => [MANUAL_INSTANT_ELAPSED]);
+
+impl LateLintPass<'_> for ManualInstantElapsed {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
+        if let ExprKind::Binary(Spanned {node: BinOpKind::Sub, ..}, lhs, rhs) = expr.kind
+            && check_instant_now_call(cx, lhs)
+            && let ty_resolved = cx.typeck_results().expr_ty(rhs)
+            && let rustc_middle::ty::Adt(def, _) = ty_resolved.kind()
+            && clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT)
+            && let Some(sugg) = clippy_utils::sugg::Sugg::hir_opt(cx, rhs)
+        {
+            span_lint_and_sugg(
+                cx,
+                MANUAL_INSTANT_ELAPSED,
+                expr.span,
+                "manual implementation of `Instant::elapsed`",
+                "try",
+                format!("{}.elapsed()", sugg.maybe_par()),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
+
+fn check_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool {
+    if let ExprKind::Call(fn_expr, []) = expr_block.kind
+        && let Some(fn_id) = clippy_utils::path_def_id(cx, fn_expr)
+        && clippy_utils::match_def_path(cx, fn_id, &clippy_utils::paths::INSTANT_NOW)
+    {
+        true
+    } else {
+        false
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/manual_ok_or.rs
index 9abf2507b92..cf5004399b8 100644
--- a/src/tools/clippy/clippy_lints/src/manual_ok_or.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_ok_or.rs
@@ -47,17 +47,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualOkOr {
         }
 
         if_chain! {
-            if let ExprKind::MethodCall(method_segment, args, _) = scrutinee.kind;
+            if let ExprKind::MethodCall(method_segment, [receiver, or_expr, map_expr], _) = scrutinee.kind;
             if method_segment.ident.name == sym!(map_or);
-            if args.len() == 3;
-            let method_receiver = &args[0];
-            let ty = cx.typeck_results().expr_ty(method_receiver);
+            let ty = cx.typeck_results().expr_ty(receiver);
             if is_type_diagnostic_item(cx, ty, sym::Option);
-            let or_expr = &args[1];
-            if is_ok_wrapping(cx, &args[2]);
+            if is_ok_wrapping(cx, map_expr);
             if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, &[ref err_arg]) = or_expr.kind;
             if is_lang_ctor(cx, err_path, ResultErr);
-            if let Some(method_receiver_snippet) = snippet_opt(cx, method_receiver.span);
+            if let Some(method_receiver_snippet) = snippet_opt(cx, receiver.span);
             if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span);
             if let Some(indent) = indent_of(cx, scrutinee.span);
             then {
diff --git a/src/tools/clippy/clippy_lints/src/map_err_ignore.rs b/src/tools/clippy/clippy_lints/src/map_err_ignore.rs
index 21d0e19eb0a..1e542447c96 100644
--- a/src/tools/clippy/clippy_lints/src/map_err_ignore.rs
+++ b/src/tools/clippy/clippy_lints/src/map_err_ignore.rs
@@ -113,10 +113,10 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore {
         }
 
         // check if this is a method call (e.g. x.foo())
-        if let ExprKind::MethodCall(method, args, _) = e.kind {
+        if let ExprKind::MethodCall(method, [_, arg], _) = e.kind {
             // only work if the method name is `map_err` and there are only 2 arguments (e.g. x.map_err(|_|[1]
             // Enum::Variant[2]))
-            if method.ident.as_str() == "map_err" && args.len() == 2 {
+            if method.ident.name == sym!(map_err) {
                 // make sure the first argument is a closure, and grab the CaptureRef, BodyId, and fn_decl_span
                 // fields
                 if let ExprKind::Closure(&Closure {
@@ -124,7 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore {
                     body,
                     fn_decl_span,
                     ..
-                }) = args[1].kind
+                }) = arg.kind
                 {
                     // check if this is by Reference (meaning there's no move statement)
                     if capture_clause == CaptureBy::Ref {
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index af9d948af00..6db852c3ffe 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -97,11 +97,7 @@ declare_clippy_lint! {
 declare_lint_pass!(MapUnit => [OPTION_MAP_UNIT_FN, RESULT_MAP_UNIT_FN]);
 
 fn is_unit_type(ty: Ty<'_>) -> bool {
-    match ty.kind() {
-        ty::Tuple(slice) => slice.is_empty(),
-        ty::Never => true,
-        _ => false,
-    }
+    ty.is_unit() || ty.is_never()
 }
 
 fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
index d914eba0171..a0efdecec67 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
@@ -72,10 +72,10 @@ fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<BindingAnnotat
         if is_lang_ctor(cx, qpath, LangItem::OptionSome);
         if let PatKind::Binding(rb, .., ident, _) = first_pat.kind;
         if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut;
-        if let ExprKind::Call(e, args) = peel_blocks(arm.body).kind;
+        if let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind;
         if let ExprKind::Path(ref some_path) = e.kind;
-        if is_lang_ctor(cx, some_path, LangItem::OptionSome) && args.len() == 1;
-        if let ExprKind::Path(QPath::Resolved(_, path2)) = args[0].kind;
+        if is_lang_ctor(cx, some_path, LangItem::OptionSome);
+        if let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind;
         if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name;
         then {
             return Some(rb)
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index e9e13aece18..e6b183fc05f 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -21,8 +21,8 @@ mod single_match;
 mod try_err;
 mod wild_in_or_pats;
 
-use clippy_utils::source::{snippet_opt, span_starts_with, walk_span_to_context};
-use clippy_utils::{higher, in_constant, meets_msrv, msrvs};
+use clippy_utils::source::{snippet_opt, walk_span_to_context};
+use clippy_utils::{higher, in_constant, is_span_match, meets_msrv, msrvs};
 use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat};
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -835,7 +835,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.60.0"]
     pub SIGNIFICANT_DROP_IN_SCRUTINEE,
-    suspicious,
+    nursery,
     "warns when a temporary of a type with a drop with a significant side-effect might have a surprising lifetime"
 }
 
@@ -949,7 +949,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
         let from_expansion = expr.span.from_expansion();
 
         if let ExprKind::Match(ex, arms, source) = expr.kind {
-            if source == MatchSource::Normal && !span_starts_with(cx, expr.span, "match") {
+            if source == MatchSource::Normal && !is_span_match(cx, expr.span) {
                 return;
             }
             if matches!(source, MatchSource::Normal | MatchSource::ForLoopDesugar) {
diff --git a/src/tools/clippy/clippy_lints/src/matches/try_err.rs b/src/tools/clippy/clippy_lints/src/matches/try_err.rs
index 0491a0679f3..663277d1136 100644
--- a/src/tools/clippy/clippy_lints/src/matches/try_err.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/try_err.rs
@@ -23,12 +23,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine
     //         val,
     // };
     if_chain! {
-        if let ExprKind::Call(match_fun, try_args) = scrutinee.kind;
+        if let ExprKind::Call(match_fun, [try_arg, ..]) = scrutinee.kind;
         if let ExprKind::Path(ref match_fun_path) = match_fun.kind;
         if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..));
-        if let Some(try_arg) = try_args.get(0);
-        if let ExprKind::Call(err_fun, err_args) = try_arg.kind;
-        if let Some(err_arg) = err_args.get(0);
+        if let ExprKind::Call(err_fun, [err_arg, ..]) = try_arg.kind;
         if let ExprKind::Path(ref err_fun_path) = err_fun.kind;
         if is_lang_ctor(cx, err_fun_path, ResultErr);
         if let Some(return_ty) = find_return_type(cx, &expr.kind);
diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs
index 41073d40f3d..cad3ea2a176 100644
--- a/src/tools/clippy/clippy_lints/src/mem_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs
@@ -163,8 +163,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<'
     }
 
     if_chain! {
-        if let ExprKind::Call(repl_func, repl_args) = src.kind;
-        if repl_args.is_empty();
+        if let ExprKind::Call(repl_func, []) = src.kind;
         if let ExprKind::Path(ref repl_func_qpath) = repl_func.kind;
         if let Some(repl_def_id) = cx.qpath_res(repl_func_qpath, repl_func.hir_id).opt_def_id();
         then {
@@ -246,11 +245,10 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
             // Check that `expr` is a call to `mem::replace()`
-            if let ExprKind::Call(func, func_args) = expr.kind;
+            if let ExprKind::Call(func, [dest, src]) = expr.kind;
             if let ExprKind::Path(ref func_qpath) = func.kind;
             if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
             if cx.tcx.is_diagnostic_item(sym::mem_replace, def_id);
-            if let [dest, src] = func_args;
             then {
                 check_replace_option_with_none(cx, src, dest, expr.span);
                 check_replace_with_uninit(cx, src, dest, expr.span);
diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
index 0b38a07204e..60e1355f9b9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
@@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context;
 use clippy_utils::sugg;
 use clippy_utils::ty::is_copy;
 use rustc_errors::Applicability;
-use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind};
+use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind, QPath};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, adjustment::Adjust};
 use rustc_span::symbol::{sym, Symbol};
@@ -86,6 +86,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol,
                 {
                     return;
                 },
+                // ? is a Call, makes sure not to rec *x?, but rather (*x)?
+                ExprKind::Call(hir_callee, _) => matches!(
+                    hir_callee.kind,
+                    ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _))
+                ),
                 ExprKind::MethodCall(_, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true,
                 ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar)
                 | ExprKind::Field(..)
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs b/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
index fbc3348f185..5ef08ca6290 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_used.rs
@@ -12,9 +12,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
     let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
 
     let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) {
-        Some((EXPECT_USED, "an Option", "None"))
+        Some((EXPECT_USED, "an Option", "None", ""))
     } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
-        Some((EXPECT_USED, "a Result", "Err"))
+        Some((EXPECT_USED, "a Result", "Err", "an "))
     } else {
         None
     };
@@ -23,14 +23,14 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
         return;
     }
 
-    if let Some((lint, kind, none_value)) = mess {
+    if let Some((lint, kind, none_value, none_prefix)) = mess {
         span_lint_and_help(
             cx,
             lint,
             expr.span,
-            &format!("used `expect()` on `{}` value", kind,),
+            &format!("used `expect()` on `{kind}` value"),
             None,
-            &format!("if this value is an `{}`, it will panic", none_value,),
+            &format!("if this value is {none_prefix}`{none_value}`, it will panic"),
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 202fbc1f7f6..5ac6b09f0aa 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -204,6 +204,17 @@ declare_clippy_lint! {
     /// option.expect("more helpful message");
     /// result.expect("more helpful message");
     /// ```
+    ///
+    /// If [expect_used](#expect_used) is enabled, instead:
+    /// ```rust,ignore
+    /// # let option = Some(1);
+    /// # let result: Result<usize, ()> = Ok(1);
+    /// option?;
+    ///
+    /// // or
+    ///
+    /// result?;
+    /// ```
     #[clippy::version = "1.45.0"]
     pub UNWRAP_USED,
     restriction,
diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
index 5c761014927..ce1a52e5480 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs
@@ -1,20 +1,20 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::is_in_test_function;
 use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{is_in_test_function, is_lint_allowed};
 use rustc_hir as hir;
 use rustc_lint::LateContext;
 use rustc_span::sym;
 
-use super::UNWRAP_USED;
+use super::{EXPECT_USED, UNWRAP_USED};
 
 /// lint use of `unwrap()` for `Option`s and `Result`s
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_unwrap_in_tests: bool) {
     let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
 
     let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) {
-        Some((UNWRAP_USED, "an Option", "None"))
+        Some((UNWRAP_USED, "an Option", "None", ""))
     } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) {
-        Some((UNWRAP_USED, "a Result", "Err"))
+        Some((UNWRAP_USED, "a Result", "Err", "an "))
     } else {
         None
     };
@@ -23,18 +23,23 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr
         return;
     }
 
-    if let Some((lint, kind, none_value)) = mess {
+    if let Some((lint, kind, none_value, none_prefix)) = mess {
+        let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) {
+            format!(
+                "if you don't want to handle the `{none_value}` case gracefully, consider \
+                using `expect()` to provide a better panic message"
+            )
+        } else {
+            format!("if this value is {none_prefix}`{none_value}`, it will panic")
+        };
+
         span_lint_and_help(
             cx,
             lint,
             expr.span,
-            &format!("used `unwrap()` on `{}` value", kind,),
+            &format!("used `unwrap()` on `{kind}` value"),
             None,
-            &format!(
-                "if you don't want to handle the `{}` case gracefully, consider \
-                using `expect()` to provide a better panic message",
-                none_value,
-            ),
+            &help,
         );
     }
 }
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 16d65966c10..bc304c081b9 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -1,7 +1,9 @@
 use clippy_utils::diagnostics::span_lint;
 use clippy_utils::qualify_min_const_fn::is_min_const_fn;
 use clippy_utils::ty::has_drop;
-use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, msrvs, trait_ref_of_method};
+use clippy_utils::{
+    fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, meets_msrv, msrvs, trait_ref_of_method,
+};
 use rustc_hir as hir;
 use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_hir::intravisit::FnKind;
@@ -86,10 +88,10 @@ impl MissingConstForFn {
 impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
     fn check_fn(
         &mut self,
-        cx: &LateContext<'_>,
-        kind: FnKind<'_>,
+        cx: &LateContext<'tcx>,
+        kind: FnKind<'tcx>,
         _: &FnDecl<'_>,
-        _: &Body<'_>,
+        body: &Body<'tcx>,
         span: Span,
         hir_id: HirId,
     ) {
@@ -124,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
             FnKind::Method(_, sig, ..) => {
                 if trait_ref_of_method(cx, def_id).is_some()
                     || already_const(sig.header)
-                    || method_accepts_dropable(cx, sig.decl.inputs)
+                    || method_accepts_droppable(cx, sig.decl.inputs)
                 {
                     return;
                 }
@@ -144,6 +146,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
             }
         }
 
+        if is_from_proc_macro(cx, &(&kind, body, hir_id, span)) {
+            return;
+        }
+
         let mir = cx.tcx.optimized_mir(def_id);
 
         if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv) {
@@ -159,7 +165,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
 
 /// Returns true if any of the method parameters is a type that implements `Drop`. The method
 /// can't be made const then, because `drop` can't be const-evaluated.
-fn method_accepts_dropable(cx: &LateContext<'_>, param_tys: &[hir::Ty<'_>]) -> bool {
+fn method_accepts_droppable(cx: &LateContext<'_>, param_tys: &[hir::Ty<'_>]) -> bool {
     // If any of the params are droppable, return true
     param_tys.iter().any(|hir_ty| {
         let ty_ty = hir_ty_to_ty(cx.tcx, hir_ty);
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index 88ba002927a..3701fdb4adb 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -7,7 +7,8 @@
 
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::span_lint;
-use rustc_ast::ast;
+use clippy_utils::is_from_proc_macro;
+use rustc_ast::ast::{self, MetaItem, MetaItemKind};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::DefIdTree;
@@ -57,6 +58,20 @@ impl MissingDoc {
         *self.doc_hidden_stack.last().expect("empty doc_hidden_stack")
     }
 
+    fn has_include(meta: Option<MetaItem>) -> bool {
+        if_chain! {
+            if let Some(meta) = meta;
+            if let MetaItemKind::List(list) = meta.kind;
+            if let Some(meta) = list.get(0);
+            if let Some(name) = meta.ident();
+            then {
+                name.name == sym::include
+            } else {
+                false
+            }
+        }
+    }
+
     fn check_missing_docs_attrs(
         &self,
         cx: &LateContext<'_>,
@@ -80,7 +95,9 @@ impl MissingDoc {
             return;
         }
 
-        let has_doc = attrs.iter().any(|a| a.doc_str().is_some());
+        let has_doc = attrs
+            .iter()
+            .any(|a| a.doc_str().is_some() || Self::has_include(a.meta()));
         if !has_doc {
             span_lint(
                 cx,
@@ -141,14 +158,18 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
         let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());
 
         let attrs = cx.tcx.hir().attrs(it.hir_id());
-        self.check_missing_docs_attrs(cx, attrs, it.span, article, desc);
+        if !is_from_proc_macro(cx, it) {
+            self.check_missing_docs_attrs(cx, attrs, it.span, article, desc);
+        }
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) {
         let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());
 
         let attrs = cx.tcx.hir().attrs(trait_item.hir_id());
-        self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc);
+        if !is_from_proc_macro(cx, trait_item) {
+            self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc);
+        }
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
@@ -163,18 +184,24 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
 
         let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
         let attrs = cx.tcx.hir().attrs(impl_item.hir_id());
-        self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc);
+        if !is_from_proc_macro(cx, impl_item) {
+            self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc);
+        }
     }
 
     fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) {
         if !sf.is_positional() {
             let attrs = cx.tcx.hir().attrs(sf.hir_id);
-            self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field");
+            if !is_from_proc_macro(cx, sf) {
+                self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field");
+            }
         }
     }
 
     fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) {
         let attrs = cx.tcx.hir().attrs(v.id);
-        self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant");
+        if !is_from_proc_macro(cx, v) {
+            self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant");
+        }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
index 3f5286ba097..d9ee031c9f9 100644
--- a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
@@ -37,9 +37,9 @@ declare_lint_pass!(OptionEnvUnwrap => [OPTION_ENV_UNWRAP]);
 impl EarlyLintPass for OptionEnvUnwrap {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
         if_chain! {
-            if let ExprKind::MethodCall(path_segment, args, _) = &expr.kind;
+            if let ExprKind::MethodCall(path_segment, receiver, _, _) = &expr.kind;
             if matches!(path_segment.ident.name, sym::expect | sym::unwrap);
-            if let ExprKind::Call(caller, _) = &args[0].kind;
+            if let ExprKind::Call(caller, _) = &receiver.kind;
             if is_direct_expn_of(caller.span, "option_env").is_some();
             then {
                 span_lint_and_help(
diff --git a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
new file mode 100644
index 00000000000..eee7642068d
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
@@ -0,0 +1,104 @@
+use clippy_utils::{
+    diagnostics::span_lint_and_sugg, is_lang_ctor, peel_hir_expr_refs, peel_ref_operators, sugg,
+    ty::is_type_diagnostic_item,
+};
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Checks for binary comparisons to a literal `Option::None`.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// A programmer checking if some `foo` is `None` via a comparison `foo == None`
+    /// is usually inspired from other programming languages (e.g. `foo is None`
+    /// in Python).
+    /// Checking if a value of type `Option<T>` is (not) equal to `None` in that
+    /// way relies on `T: PartialEq` to do the comparison, which is unneeded.
+    ///
+    /// ### Example
+    /// ```rust
+    /// fn foo(f: Option<u32>) -> &'static str {
+    ///     if f != None { "yay" } else { "nay" }
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// fn foo(f: Option<u32>) -> &'static str {
+    ///     if f.is_some() { "yay" } else { "nay" }
+    /// }
+    /// ```
+    #[clippy::version = "1.64.0"]
+    pub PARTIALEQ_TO_NONE,
+    style,
+    "Binary comparison to `Option<T>::None` relies on `T: PartialEq`, which is unneeded"
+}
+declare_lint_pass!(PartialeqToNone => [PARTIALEQ_TO_NONE]);
+
+impl<'tcx> LateLintPass<'tcx> for PartialeqToNone {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
+        // Skip expanded code, as we have no control over it anyway...
+        if e.span.from_expansion() {
+            return;
+        }
+
+        // If the expression is of type `Option`
+        let is_ty_option =
+            |expr: &Expr<'_>| is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr).peel_refs(), sym::Option);
+
+        // If the expression is a literal `Option::None`
+        let is_none_ctor = |expr: &Expr<'_>| {
+            matches!(&peel_hir_expr_refs(expr).0.kind,
+            ExprKind::Path(p) if is_lang_ctor(cx, p, LangItem::OptionNone))
+        };
+
+        let mut applicability = Applicability::MachineApplicable;
+
+        if let ExprKind::Binary(op, left_side, right_side) = e.kind {
+            // All other comparisons (e.g. `>= None`) have special meaning wrt T
+            let is_eq = match op.node {
+                BinOpKind::Eq => true,
+                BinOpKind::Ne => false,
+                _ => return,
+            };
+
+            // We are only interested in comparisons between `Option` and a literal `Option::None`
+            let scrutinee = match (
+                is_none_ctor(left_side) && is_ty_option(right_side),
+                is_none_ctor(right_side) && is_ty_option(left_side),
+            ) {
+                (true, false) => right_side,
+                (false, true) => left_side,
+                _ => return,
+            };
+
+            // Peel away refs/derefs (as long as we don't cross manual deref impls), as
+            // autoref/autoderef will take care of those
+            let sugg = format!(
+                "{}.{}",
+                sugg::Sugg::hir_with_applicability(cx, peel_ref_operators(cx, scrutinee), "..", &mut applicability)
+                    .maybe_par(),
+                if is_eq { "is_none()" } else { "is_some()" }
+            );
+
+            span_lint_and_sugg(
+                cx,
+                PARTIALEQ_TO_NONE,
+                e.span,
+                "binary comparison to literal `Option::None`",
+                if is_eq {
+                    "use `Option::is_none()` instead"
+                } else {
+                    "use `Option::is_some()` instead"
+                },
+                sugg,
+                applicability,
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs b/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs
index 3f940ce61c0..bc6a918f703 100644
--- a/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs
+++ b/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs
@@ -46,11 +46,9 @@ declare_lint_pass!(PathBufPushOverwrite => [PATH_BUF_PUSH_OVERWRITE]);
 impl<'tcx> LateLintPass<'tcx> for PathBufPushOverwrite {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
-            if let ExprKind::MethodCall(path, args, _) = expr.kind;
+            if let ExprKind::MethodCall(path, [recv, get_index_arg], _) = expr.kind;
             if path.ident.name == sym!(push);
-            if args.len() == 2;
-            if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), sym::PathBuf);
-            if let Some(get_index_arg) = args.get(1);
+            if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv).peel_refs(), sym::PathBuf);
             if let ExprKind::Lit(ref lit) = get_index_arg.kind;
             if let LitKind::Str(ref path_lit, _) = lit.node;
             if let pushed_path = Path::new(path_lit.as_str());
diff --git a/src/tools/clippy/clippy_lints/src/precedence.rs b/src/tools/clippy/clippy_lints/src/precedence.rs
index cc0533c9f5d..e6e3ad05ad7 100644
--- a/src/tools/clippy/clippy_lints/src/precedence.rs
+++ b/src/tools/clippy/clippy_lints/src/precedence.rs
@@ -109,12 +109,12 @@ impl EarlyLintPass for Precedence {
             let mut arg = operand;
 
             let mut all_odd = true;
-            while let ExprKind::MethodCall(path_segment, args, _) = &arg.kind {
+            while let ExprKind::MethodCall(path_segment, receiver, _, _) = &arg.kind {
                 let path_segment_str = path_segment.ident.name.as_str();
                 all_odd &= ALLOWED_ODD_FUNCTIONS
                     .iter()
                     .any(|odd_function| **odd_function == *path_segment_str);
-                arg = args.first().expect("A method always has a receiver.");
+                arg = receiver;
             }
 
             if_chain! {
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index fd0a53839e6..964a057f00d 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -86,8 +86,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex
     if_chain! {
         if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr);
         if !is_else_clause(cx.tcx, expr);
-        if let ExprKind::MethodCall(segment, args, _) = &cond.kind;
-        if let Some(caller) = args.get(0);
+        if let ExprKind::MethodCall(segment, [caller, ..], _) = &cond.kind;
         let caller_ty = cx.typeck_results().expr_ty(caller);
         let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else);
         if is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block);
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index 547d4da8187..fbf842c339e 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -385,24 +385,24 @@ fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args:
         if path.ident.as_str() == "zip";
         if let [iter, zip_arg] = args;
         // `.iter()` call
-        if let ExprKind::MethodCall(iter_path, iter_args, _) = iter.kind;
+        if let ExprKind::MethodCall(iter_path, [iter_caller, ..], _) = iter.kind;
         if iter_path.ident.name == sym::iter;
         // range expression in `.zip()` call: `0..x.len()`
         if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg);
         if is_integer_const(cx, start, 0);
         // `.len()` call
-        if let ExprKind::MethodCall(len_path, len_args, _) = end.kind;
-        if len_path.ident.name == sym::len && len_args.len() == 1;
+        if let ExprKind::MethodCall(len_path, [len_caller], _) = end.kind;
+        if len_path.ident.name == sym::len;
         // `.iter()` and `.len()` called on same `Path`
-        if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_args[0].kind;
-        if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_args[0].kind;
-        if SpanlessEq::new(cx).eq_path_segments(&iter_path.segments, &len_path.segments);
+        if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_caller.kind;
+        if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_caller.kind;
+        if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments);
         then {
             span_lint(cx,
                 RANGE_ZIP_WITH_LEN,
                 span,
                 &format!("it is more idiomatic to use `{}.iter().enumerate()`",
-                    snippet(cx, iter_args[0].span, "_"))
+                    snippet(cx, iter_caller.span, "_"))
             );
         }
     }
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 f5a93cebab8..74eea6de4bb 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
-use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sugg::Sugg;
 use if_chain::if_chain;
 use rustc_ast::ast;
 use rustc_ast::visit as ast_visit;
@@ -69,7 +69,7 @@ impl EarlyLintPass for RedundantClosureCall {
         if_chain! {
             if let ast::ExprKind::Call(ref paren, _) = expr.kind;
             if let ast::ExprKind::Paren(ref closure) = paren.kind;
-            if let ast::ExprKind::Closure(_, _, _, _, ref decl, ref block, _) = closure.kind;
+            if let ast::ExprKind::Closure(_, _, ref r#async, _, ref decl, ref block, _) = closure.kind;
             then {
                 let mut visitor = ReturnVisitor::new();
                 visitor.visit_expr(block);
@@ -81,10 +81,19 @@ impl EarlyLintPass for RedundantClosureCall {
                         "try not to call a closure in the expression where it is declared",
                         |diag| {
                             if decl.inputs.is_empty() {
-                                let mut app = Applicability::MachineApplicable;
-                                let hint =
-                                    snippet_with_applicability(cx, block.span, "..", &mut app).into_owned();
-                                diag.span_suggestion(expr.span, "try doing something like", hint, app);
+                                let app = Applicability::MachineApplicable;
+                                let mut hint = Sugg::ast(cx, block, "..");
+
+                                if r#async.is_async() {
+                                    // `async x` is a syntax error, so it becomes `async { x }`
+                                    if !matches!(block.kind, ast::ExprKind::Block(_, _)) {
+                                        hint = hint.blockify();
+                                    }
+
+                                    hint = hint.asyncify();
+                                }
+
+                                diag.span_suggestion(expr.span, "try doing something like", hint.to_string(), app);
                             }
                         },
                     );
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index f9a9b069193..6bcae0da8f4 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -57,21 +57,20 @@ declare_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]);
 impl<'tcx> LateLintPass<'tcx> for Regex {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if_chain! {
-            if let ExprKind::Call(fun, args) = expr.kind;
+            if let ExprKind::Call(fun, [arg]) = expr.kind;
             if let ExprKind::Path(ref qpath) = fun.kind;
-            if args.len() == 1;
             if let Some(def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
             then {
                 if match_def_path(cx, def_id, &paths::REGEX_NEW) ||
                    match_def_path(cx, def_id, &paths::REGEX_BUILDER_NEW) {
-                    check_regex(cx, &args[0], true);
+                    check_regex(cx, arg, true);
                 } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_NEW) ||
                    match_def_path(cx, def_id, &paths::REGEX_BYTES_BUILDER_NEW) {
-                    check_regex(cx, &args[0], false);
+                    check_regex(cx, arg, false);
                 } else if match_def_path(cx, def_id, &paths::REGEX_SET_NEW) {
-                    check_set(cx, &args[0], true);
+                    check_set(cx, arg, true);
                 } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_SET_NEW) {
-                    check_set(cx, &args[0], false);
+                    check_set(cx, arg, false);
                 }
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
index ba03ef93721..6bea6dc0773 100644
--- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
@@ -2,6 +2,7 @@
 
 #[rustfmt::skip]
 pub static RENAMED_LINTS: &[(&str, &str)] = &[
+    ("clippy::blacklisted_name", "clippy::disallowed_names"),
     ("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions"),
     ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions"),
     ("clippy::box_vec", "clippy::box_collection"),
@@ -14,6 +15,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles"),
     ("clippy::identity_conversion", "clippy::useless_conversion"),
     ("clippy::if_let_some_result", "clippy::match_result_ok"),
+    ("clippy::logic_bug", "clippy::overly_complex_bool_expr"),
     ("clippy::new_without_default_derive", "clippy::new_without_default"),
     ("clippy::option_and_then_some", "clippy::bind_instead_of_map"),
     ("clippy::option_expect_used", "clippy::expect_used"),
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index 2c8aa17e80d..b59a25e3a40 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -233,15 +233,10 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> {
     /// Returns `true` if give expression is `repeat(0).take(...)`
     fn is_repeat_take(&self, expr: &Expr<'_>) -> bool {
         if_chain! {
-            if let ExprKind::MethodCall(take_path, take_args, _) = expr.kind;
+            if let ExprKind::MethodCall(take_path, [recv, len_arg, ..], _) = expr.kind;
             if take_path.ident.name == sym!(take);
-
             // Check that take is applied to `repeat(0)`
-            if let Some(repeat_expr) = take_args.get(0);
-            if self.is_repeat_zero(repeat_expr);
-
-            if let Some(len_arg) = take_args.get(1);
-
+            if self.is_repeat_zero(recv);
             then {
                 // Check that len expression is equals to `with_capacity` expression
                 if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) {
diff --git a/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs b/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs
index a6c685df721..6d54935f81a 100644
--- a/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs
+++ b/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs
@@ -97,12 +97,11 @@ struct LintDetection {
 
 fn detect_stable_sort_primitive(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintDetection> {
     if_chain! {
-        if let ExprKind::MethodCall(method_name, args, _) = &expr.kind;
-        if let Some(slice) = &args.get(0);
+        if let ExprKind::MethodCall(method_name, [slice, args @ ..], _) = &expr.kind;
         if let Some(method) = SortingKind::from_stable_name(method_name.ident.name.as_str());
         if let Some(slice_type) = is_slice_of_primitives(cx, slice);
         then {
-            let args_str = args.iter().skip(1).map(|arg| Sugg::hir(cx, arg, "..").to_string()).collect::<Vec<String>>().join(", ");
+            let args_str = args.iter().map(|arg| Sugg::hir(cx, arg, "..").to_string()).collect::<Vec<String>>().join(", ");
             Some(LintDetection { slice_name: Sugg::hir(cx, slice, "..").to_string(), method, method_args: args_str, slice_type })
         } else {
             None
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
index fe885990595..5d36f0f5ff8 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
@@ -595,7 +595,7 @@ fn ident_difference_expr_with_base_location(
         | (Unary(_, _), Unary(_, _))
         | (Binary(_, _, _), Binary(_, _, _))
         | (Tup(_), Tup(_))
-        | (MethodCall(_, _, _), MethodCall(_, _, _))
+        | (MethodCall(_, _, _, _), MethodCall(_, _, _, _))
         | (Call(_, _), Call(_, _))
         | (ConstBlock(_), ConstBlock(_))
         | (Array(_), Array(_))
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
index 6aa86a57c9b..546242ebd9a 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
@@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitTypes {
         let_unit_value::check(cx, local);
     }
 
-    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         unit_cmp::check(cx, expr);
         unit_arg::check(cx, expr);
     }
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
index 97d92f10e1c..16da2f11b81 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_from_proc_macro;
 use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
@@ -7,7 +8,7 @@ use rustc_lint::LateContext;
 
 use super::{utils, UNIT_ARG};
 
-pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
     if expr.span.from_expansion() {
         return;
     }
@@ -44,7 +45,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
                     }
                 })
                 .collect::<Vec<_>>();
-            if !args_to_recover.is_empty() {
+            if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) {
                 lint_unit_args(cx, expr, &args_to_recover);
             }
         },
diff --git a/src/tools/clippy/clippy_lints/src/unused_rounding.rs b/src/tools/clippy/clippy_lints/src/unused_rounding.rs
index 306afe44148..e1ec357838d 100644
--- a/src/tools/clippy/clippy_lints/src/unused_rounding.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_rounding.rs
@@ -30,11 +30,10 @@ declare_clippy_lint! {
 declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]);
 
 fn is_useless_rounding(expr: &Expr) -> Option<(&str, String)> {
-    if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind
+    if let ExprKind::MethodCall(name_ident, receiver, _, _) = &expr.kind
         && let method_name = name_ident.ident.name.as_str()
         && (method_name == "ceil" || method_name == "round" || method_name == "floor")
-        && !args.is_empty()
-        && let ExprKind::Lit(spanned) = &args[0].kind
+        && let ExprKind::Lit(spanned) = &receiver.kind
         && let LitKind::Float(symbol, ty) = spanned.kind {
             let f = symbol.as_str().parse::<f64>().unwrap();
             let f_str = symbol.to_string() + if let LitFloatType::Suffixed(ty) = ty {
diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs
index 52585e59566..cd1d90e860b 100644
--- a/src/tools/clippy/clippy_lints/src/unused_unit.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs
@@ -89,7 +89,7 @@ impl EarlyLintPass for UnusedUnit {
         }
     }
 
-    fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef, _: &ast::TraitBoundModifier) {
+    fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef) {
         let segments = &poly.trait_ref.path.segments;
 
         if_chain! {
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index fe29bf29d0c..b6738e2891d 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -59,17 +59,17 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                     ExprKind::Ret(Some(e)) | ExprKind::Break(_, Some(e)) => e,
                     _ => return,
                 };
-                if let ExprKind::Call(_, args) = e.kind {
-                    self.try_desugar_arm.push(args[0].hir_id);
+                if let ExprKind::Call(_, [arg, ..]) = e.kind {
+                    self.try_desugar_arm.push(arg.hir_id);
                 }
             },
 
-            ExprKind::MethodCall(name, .., args, _) => {
+            ExprKind::MethodCall(name, .., [recv, ..], _) => {
                 if is_trait_method(cx, e, sym::Into) && name.ident.as_str() == "into" {
                     let a = cx.typeck_results().expr_ty(e);
-                    let b = cx.typeck_results().expr_ty(&args[0]);
+                    let b = cx.typeck_results().expr_ty(recv);
                     if same_type_and_consts(a, b) {
-                        let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string();
+                        let sugg = snippet_with_macro_callsite(cx, recv.span, "<expr>").to_string();
                         span_lint_and_sugg(
                             cx,
                             USELESS_CONVERSION,
@@ -90,9 +90,9 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                         }
                     }
                     let a = cx.typeck_results().expr_ty(e);
-                    let b = cx.typeck_results().expr_ty(&args[0]);
+                    let b = cx.typeck_results().expr_ty(recv);
                     if same_type_and_consts(a, b) {
-                        let sugg = snippet(cx, args[0].span, "<expr>").into_owned();
+                        let sugg = snippet(cx, recv.span, "<expr>").into_owned();
                         span_lint_and_sugg(
                             cx,
                             USELESS_CONVERSION,
@@ -107,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                 if_chain! {
                     if is_trait_method(cx, e, sym::TryInto) && name.ident.name == sym::try_into;
                     let a = cx.typeck_results().expr_ty(e);
-                    let b = cx.typeck_results().expr_ty(&args[0]);
+                    let b = cx.typeck_results().expr_ty(recv);
                     if is_type_diagnostic_item(cx, a, sym::Result);
                     if let ty::Adt(_, substs) = a.kind();
                     if let Some(a_type) = substs.types().next();
@@ -126,14 +126,13 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                 }
             },
 
-            ExprKind::Call(path, args) => {
+            ExprKind::Call(path, [arg]) => {
                 if_chain! {
-                    if args.len() == 1;
                     if let ExprKind::Path(ref qpath) = path.kind;
                     if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
                     then {
                         let a = cx.typeck_results().expr_ty(e);
-                        let b = cx.typeck_results().expr_ty(&args[0]);
+                        let b = cx.typeck_results().expr_ty(arg);
                         if_chain! {
                             if match_def_path(cx, def_id, &paths::TRY_FROM);
                             if is_type_diagnostic_item(cx, a, sym::Result);
@@ -159,7 +158,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                             if same_type_and_consts(a, b);
 
                             then {
-                                let sugg = Sugg::hir_with_macro_callsite(cx, &args[0], "<expr>").maybe_par();
+                                let sugg = Sugg::hir_with_macro_callsite(cx, arg, "<expr>").maybe_par();
                                 let sugg_msg =
                                     format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
                                 span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index 6e033b3be2d..3faae9ac0d2 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -30,7 +30,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[
     "MinGW",
     "CamelCase",
 ];
-const DEFAULT_BLACKLISTED_NAMES: &[&str] = &["foo", "baz", "quux"];
+const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"];
 
 /// Holds information used by `MISSING_ENFORCED_IMPORT_RENAMES` lint.
 #[derive(Clone, Debug, Deserialize)]
@@ -68,6 +68,7 @@ pub enum DisallowedType {
 pub struct TryConf {
     pub conf: Conf,
     pub errors: Vec<Box<dyn Error>>,
+    pub warnings: Vec<Box<dyn Error>>,
 }
 
 impl TryConf {
@@ -75,6 +76,7 @@ impl TryConf {
         Self {
             conf: Conf::default(),
             errors: vec![Box::new(error)],
+            warnings: vec![],
         }
     }
 }
@@ -90,14 +92,14 @@ impl fmt::Display for ConfError {
 
 impl Error for ConfError {}
 
-fn conf_error(s: String) -> Box<dyn Error> {
-    Box::new(ConfError(s))
+fn conf_error(s: impl Into<String>) -> Box<dyn Error> {
+    Box::new(ConfError(s.into()))
 }
 
 macro_rules! define_Conf {
     ($(
         $(#[doc = $doc:literal])+
-        $(#[conf_deprecated($dep:literal)])?
+        $(#[conf_deprecated($dep:literal, $new_conf:ident)])?
         ($name:ident: $ty:ty = $default:expr),
     )*) => {
         /// Clippy lint configuration
@@ -137,17 +139,29 @@ macro_rules! define_Conf {
 
             fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> where V: MapAccess<'de> {
                 let mut errors = Vec::new();
+                let mut warnings = Vec::new();
                 $(let mut $name = None;)*
                 // could get `Field` here directly, but get `str` first for diagnostics
                 while let Some(name) = map.next_key::<&str>()? {
                     match Field::deserialize(name.into_deserializer())? {
                         $(Field::$name => {
-                            $(errors.push(conf_error(format!("deprecated field `{}`. {}", name, $dep)));)?
+                            $(warnings.push(conf_error(format!("deprecated field `{}`. {}", name, $dep)));)?
                             match map.next_value() {
                                 Err(e) => errors.push(conf_error(e.to_string())),
                                 Ok(value) => match $name {
                                     Some(_) => errors.push(conf_error(format!("duplicate field `{}`", name))),
-                                    None => $name = Some(value),
+                                    None => {
+                                        $name = Some(value);
+                                        // $new_conf is the same as one of the defined `$name`s, so
+                                        // this variable is defined in line 2 of this function.
+                                        $(match $new_conf {
+                                            Some(_) => errors.push(conf_error(concat!(
+                                                "duplicate field `", stringify!($new_conf),
+                                                "` (provided as `", stringify!($name), "`)"
+                                            ))),
+                                            None => $new_conf = $name.clone(),
+                                        })?
+                                    },
                                 }
                             }
                         })*
@@ -156,7 +170,7 @@ macro_rules! define_Conf {
                     }
                 }
                 let conf = Conf { $($name: $name.unwrap_or_else(defaults::$name),)* };
-                Ok(TryConf { conf, errors })
+                Ok(TryConf { conf, errors, warnings })
             }
         }
 
@@ -203,12 +217,11 @@ define_Conf! {
     ///
     /// The minimum rust version that the project supports
     (msrv: Option<String> = None),
-    /// Lint: BLACKLISTED_NAME.
+    /// DEPRECATED LINT: BLACKLISTED_NAME.
     ///
-    /// The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses. The value
-    /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the
-    /// default configuration of Clippy. By default any configuraction will replace the default value.
-    (blacklisted_names: Vec<String> = super::DEFAULT_BLACKLISTED_NAMES.iter().map(ToString::to_string).collect()),
+    /// Use the Disallowed Names lint instead
+    #[conf_deprecated("Please use `disallowed-names` instead", disallowed_names)]
+    (blacklisted_names: Vec<String> = Vec::new()),
     /// Lint: COGNITIVE_COMPLEXITY.
     ///
     /// The maximum cognitive complexity a function can have
@@ -216,8 +229,14 @@ define_Conf! {
     /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY.
     ///
     /// Use the Cognitive Complexity lint instead.
-    #[conf_deprecated("Please use `cognitive-complexity-threshold` instead")]
-    (cyclomatic_complexity_threshold: Option<u64> = None),
+    #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)]
+    (cyclomatic_complexity_threshold: u64 = 25),
+    /// Lint: DISALLOWED_NAMES.
+    ///
+    /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value
+    /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the
+    /// default configuration of Clippy. By default any configuration will replace the default value.
+    (disallowed_names: Vec<String> = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()),
     /// Lint: DOC_MARKDOWN.
     ///
     /// The list of words this lint should not consider as identifiers needing ticks. The value
@@ -420,7 +439,7 @@ pub fn read(path: &Path) -> TryConf {
     match toml::from_str::<TryConf>(&content) {
         Ok(mut conf) => {
             extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS);
-            extend_vec_if_indicator_present(&mut conf.conf.blacklisted_names, DEFAULT_BLACKLISTED_NAMES);
+            extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES);
 
             conf
         },
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 b309653291b..5dcacd604be 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
@@ -496,12 +496,14 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
                     cx,
                 };
                 let body_id = cx.tcx.hir().body_owned_by(
-                    impl_item_refs
-                        .iter()
-                        .find(|iiref| iiref.ident.as_str() == "get_lints")
-                        .expect("LintPass needs to implement get_lints")
-                        .id
-                        .hir_id(),
+                    cx.tcx.hir().local_def_id(
+                        impl_item_refs
+                            .iter()
+                            .find(|iiref| iiref.ident.as_str() == "get_lints")
+                            .expect("LintPass needs to implement get_lints")
+                            .id
+                            .hir_id(),
+                    ),
                 );
                 collector.visit_expr(&cx.tcx.hir().body(body_id).value);
             }
@@ -569,7 +571,7 @@ fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<'
                 item.span,
                 "this item has an invalid `clippy::version` attribute",
                 None,
-                "please use a valid sematic version, see `doc/adding_lints.md`",
+                "please use a valid semantic version, see `doc/adding_lints.md`",
             );
         }
     } else {
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 92934c16d4b..92cf42c7ad4 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
@@ -619,7 +619,7 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
             if_chain! {
                 // item validation
                 if is_lint_ref_type(cx, ty);
-                // blacklist check
+                // disallow check
                 let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
                 if !BLACK_LISTED_LINTS.contains(&lint_name.as_str());
                 // metadata extraction
@@ -644,7 +644,7 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
 
             if_chain! {
                 if is_deprecated_lint(cx, ty);
-                // blacklist check
+                // disallow check
                 let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
                 if !BLACK_LISTED_LINTS.contains(&lint_name.as_str());
                 // Metadata the little we can get from a deprecated lint
diff --git a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
index 8e2ddd225fd..afd0077a658 100644
--- a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
+++ b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs
@@ -61,10 +61,10 @@ impl<'tcx> LateLintPass<'tcx> for VerboseFileReads {
 
 fn is_file_read_to_end<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
     if_chain! {
-        if let ExprKind::MethodCall(method_name, exprs, _) = expr.kind;
+        if let ExprKind::MethodCall(method_name, [recv, ..], _) = expr.kind;
         if method_name.ident.as_str() == "read_to_end";
-        if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind;
-        let ty = cx.typeck_results().expr_ty(&exprs[0]);
+        if let ExprKind::Path(QPath::Resolved(None, _)) = &recv.kind;
+        let ty = cx.typeck_results().expr_ty(recv);
         if match_type(cx, ty, &paths::FILE);
         then {
             return true
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index bb443bdc116..a688050f63a 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "clippy_utils"
-version = "0.1.64"
+version = "0.1.65"
 edition = "2021"
 publish = false
 
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index b226026323b..9f74729bdfa 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -147,7 +147,9 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
         (Array(l), Array(r)) | (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)),
         (Repeat(le, ls), Repeat(re, rs)) => eq_expr(le, re) && eq_expr(&ls.value, &rs.value),
         (Call(lc, la), Call(rc, ra)) => eq_expr(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)),
-        (MethodCall(lc, la, _), MethodCall(rc, ra, _)) => eq_path_seg(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)),
+        (MethodCall(lc, ls, la, _), MethodCall(rc, rs, ra, _)) => {
+            eq_path_seg(lc, rc) && eq_expr(ls, rs) && over(la, ra, |l, r| eq_expr(l, r))
+        },
         (Binary(lo, ll, lr), Binary(ro, rl, rr)) => lo.node == ro.node && eq_expr(ll, rl) && eq_expr(lr, rr),
         (Unary(lo, l), Unary(ro, r)) => mem::discriminant(lo) == mem::discriminant(ro) && eq_expr(l, r),
         (Lit(l), Lit(r)) => l.kind == r.kind,
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
new file mode 100644
index 00000000000..8335ffae81e
--- /dev/null
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -0,0 +1,329 @@
+//! This module handles checking if the span given is from a proc-macro or not.
+//!
+//! Proc-macros are capable of setting the span of every token they output to a few possible spans.
+//! This includes spans we can detect easily as coming from a proc-macro (e.g. the call site
+//! or the def site), and spans we can't easily detect as such (e.g. the span of any token
+//! passed into the proc macro). This capability means proc-macros are capable of generating code
+//! with a span that looks like it was written by the user, but which should not be linted by clippy
+//! as it was generated by an external macro.
+//!
+//! That brings us to this module. The current approach is to determine a small bit of text which
+//! must exist at both the start and the end of an item (e.g. an expression or a path) assuming the
+//! code was written, and check if the span contains that text. Note this will only work correctly
+//! if the span is not from a `macro_rules` based macro.
+
+use rustc_ast::ast::{IntTy, LitIntType, LitKind, StrStyle, UintTy};
+use rustc_hir::{
+    intravisit::FnKind, Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, HirId,
+    Impl, ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, Node, QPath, TraitItem,
+    TraitItemKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource,
+};
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::ty::TyCtxt;
+use rustc_session::Session;
+use rustc_span::{Span, Symbol};
+use rustc_target::spec::abi::Abi;
+
+/// The search pattern to look for. Used by `span_matches_pat`
+#[derive(Clone, Copy)]
+pub enum Pat {
+    /// A single string.
+    Str(&'static str),
+    /// Any of the given strings.
+    MultiStr(&'static [&'static str]),
+    /// The string representation of the symbol.
+    Sym(Symbol),
+    /// Any decimal or hexadecimal digit depending on the location.
+    Num,
+}
+
+/// Checks if the start and the end of the span's text matches the patterns. This will return false
+/// if the span crosses multiple files or if source is not available.
+fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) -> bool {
+    let pos = sess.source_map().lookup_byte_offset(span.lo());
+    let Some(ref src) = pos.sf.src else {
+        return false;
+    };
+    let end = span.hi() - pos.sf.start_pos;
+    src.get(pos.pos.0 as usize..end.0 as usize).map_or(false, |s| {
+        // Spans can be wrapped in a mixture or parenthesis, whitespace, and trailing commas.
+        let start_str = s.trim_start_matches(|c: char| c.is_whitespace() || c == '(');
+        let end_str = s.trim_end_matches(|c: char| c.is_whitespace() || c == ')' || c == ',');
+        (match start_pat {
+            Pat::Str(text) => start_str.starts_with(text),
+            Pat::MultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)),
+            Pat::Sym(sym) => start_str.starts_with(sym.as_str()),
+            Pat::Num => start_str.as_bytes().first().map_or(false, u8::is_ascii_digit),
+        } && match end_pat {
+            Pat::Str(text) => end_str.ends_with(text),
+            Pat::MultiStr(texts) => texts.iter().any(|s| start_str.ends_with(s)),
+            Pat::Sym(sym) => end_str.ends_with(sym.as_str()),
+            Pat::Num => end_str.as_bytes().last().map_or(false, u8::is_ascii_hexdigit),
+        })
+    })
+}
+
+/// Get the search patterns to use for the given literal
+fn lit_search_pat(lit: &LitKind) -> (Pat, Pat) {
+    match lit {
+        LitKind::Str(_, StrStyle::Cooked) => (Pat::Str("\""), Pat::Str("\"")),
+        LitKind::Str(_, StrStyle::Raw(0)) => (Pat::Str("r"), Pat::Str("\"")),
+        LitKind::Str(_, StrStyle::Raw(_)) => (Pat::Str("r#"), Pat::Str("#")),
+        LitKind::ByteStr(_) => (Pat::Str("b\""), Pat::Str("\"")),
+        LitKind::Byte(_) => (Pat::Str("b'"), Pat::Str("'")),
+        LitKind::Char(_) => (Pat::Str("'"), Pat::Str("'")),
+        LitKind::Int(_, LitIntType::Signed(IntTy::Isize)) => (Pat::Num, Pat::Str("isize")),
+        LitKind::Int(_, LitIntType::Unsigned(UintTy::Usize)) => (Pat::Num, Pat::Str("usize")),
+        LitKind::Int(..) => (Pat::Num, Pat::Num),
+        LitKind::Float(..) => (Pat::Num, Pat::Str("")),
+        LitKind::Bool(true) => (Pat::Str("true"), Pat::Str("true")),
+        LitKind::Bool(false) => (Pat::Str("false"), Pat::Str("false")),
+        _ => (Pat::Str(""), Pat::Str("")),
+    }
+}
+
+/// Get the search patterns to use for the given path
+fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) {
+    match path {
+        QPath::Resolved(ty, path) => {
+            let start = if ty.is_some() {
+                Pat::Str("<")
+            } else {
+                path.segments
+                    .first()
+                    .map_or(Pat::Str(""), |seg| Pat::Sym(seg.ident.name))
+            };
+            let end = path.segments.last().map_or(Pat::Str(""), |seg| {
+                if seg.args.is_some() {
+                    Pat::Str(">")
+                } else {
+                    Pat::Sym(seg.ident.name)
+                }
+            });
+            (start, end)
+        },
+        QPath::TypeRelative(_, name) => (Pat::Str(""), Pat::Sym(name.ident.name)),
+        QPath::LangItem(..) => (Pat::Str(""), Pat::Str("")),
+    }
+}
+
+/// Get the search patterns to use for the given expression
+fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
+    match e.kind {
+        ExprKind::Box(e) => (Pat::Str("box"), expr_search_pat(tcx, e).1),
+        ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")),
+        ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")),
+        ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1),
+        ExprKind::Unary(UnOp::Not, e) => (Pat::Str("!"), expr_search_pat(tcx, e).1),
+        ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat(tcx, e).1),
+        ExprKind::Lit(ref lit) => lit_search_pat(&lit.node),
+        ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")),
+        ExprKind::Call(e, []) | ExprKind::MethodCall(_, [e], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")),
+        ExprKind::Call(first, [.., last])
+        | ExprKind::MethodCall(_, [first, .., last], _)
+        | ExprKind::Binary(_, first, last)
+        | ExprKind::Tup([first, .., last])
+        | ExprKind::Assign(first, last, _)
+        | ExprKind::AssignOp(_, first, last) => (expr_search_pat(tcx, first).0, expr_search_pat(tcx, last).1),
+        ExprKind::Tup([e]) | ExprKind::DropTemps(e) => expr_search_pat(tcx, e),
+        ExprKind::Cast(e, _) | ExprKind::Type(e, _) => (expr_search_pat(tcx, e).0, Pat::Str("")),
+        ExprKind::Let(let_expr) => (Pat::Str("let"), expr_search_pat(tcx, let_expr.init).1),
+        ExprKind::If(..) => (Pat::Str("if"), Pat::Str("}")),
+        ExprKind::Loop(_, Some(_), _, _) | ExprKind::Block(_, Some(_)) => (Pat::Str("'"), Pat::Str("}")),
+        ExprKind::Loop(_, None, LoopSource::Loop, _) => (Pat::Str("loop"), Pat::Str("}")),
+        ExprKind::Loop(_, None, LoopSource::While, _) => (Pat::Str("while"), Pat::Str("}")),
+        ExprKind::Loop(_, None, LoopSource::ForLoop, _) | ExprKind::Match(_, _, MatchSource::ForLoopDesugar) => {
+            (Pat::Str("for"), Pat::Str("}"))
+        },
+        ExprKind::Match(_, _, MatchSource::Normal) => (Pat::Str("match"), Pat::Str("}")),
+        ExprKind::Match(e, _, MatchSource::TryDesugar) => (expr_search_pat(tcx, e).0, Pat::Str("?")),
+        ExprKind::Match(e, _, MatchSource::AwaitDesugar) | ExprKind::Yield(e, YieldSource::Await { .. }) => {
+            (expr_search_pat(tcx, e).0, Pat::Str("await"))
+        },
+        ExprKind::Closure(&Closure { body, .. }) => (Pat::Str(""), expr_search_pat(tcx, &tcx.hir().body(body).value).1),
+        ExprKind::Block(
+            Block {
+                rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided),
+                ..
+            },
+            None,
+        ) => (Pat::Str("unsafe"), Pat::Str("}")),
+        ExprKind::Block(_, None) => (Pat::Str("{"), Pat::Str("}")),
+        ExprKind::Field(e, name) => (expr_search_pat(tcx, e).0, Pat::Sym(name.name)),
+        ExprKind::Index(e, _) => (expr_search_pat(tcx, e).0, Pat::Str("]")),
+        ExprKind::Path(ref path) => qpath_search_pat(path),
+        ExprKind::AddrOf(_, _, e) => (Pat::Str("&"), expr_search_pat(tcx, e).1),
+        ExprKind::Break(Destination { label: None, .. }, None) => (Pat::Str("break"), Pat::Str("break")),
+        ExprKind::Break(Destination { label: Some(name), .. }, None) => (Pat::Str("break"), Pat::Sym(name.ident.name)),
+        ExprKind::Break(_, Some(e)) => (Pat::Str("break"), expr_search_pat(tcx, e).1),
+        ExprKind::Continue(Destination { label: None, .. }) => (Pat::Str("continue"), Pat::Str("continue")),
+        ExprKind::Continue(Destination { label: Some(name), .. }) => (Pat::Str("continue"), Pat::Sym(name.ident.name)),
+        ExprKind::Ret(None) => (Pat::Str("return"), Pat::Str("return")),
+        ExprKind::Ret(Some(e)) => (Pat::Str("return"), expr_search_pat(tcx, e).1),
+        ExprKind::Struct(path, _, _) => (qpath_search_pat(path).0, Pat::Str("}")),
+        ExprKind::Yield(e, YieldSource::Yield) => (Pat::Str("yield"), expr_search_pat(tcx, e).1),
+        _ => (Pat::Str(""), Pat::Str("")),
+    }
+}
+
+fn fn_header_search_pat(header: FnHeader) -> Pat {
+    if header.is_async() {
+        Pat::Str("async")
+    } else if header.is_const() {
+        Pat::Str("const")
+    } else if header.is_unsafe() {
+        Pat::Str("unsafe")
+    } else if header.abi != Abi::Rust {
+        Pat::Str("extern")
+    } else {
+        Pat::MultiStr(&["fn", "extern"])
+    }
+}
+
+fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) {
+    let (start_pat, end_pat) = match &item.kind {
+        ItemKind::ExternCrate(_) => (Pat::Str("extern"), Pat::Str(";")),
+        ItemKind::Static(..) => (Pat::Str("static"), Pat::Str(";")),
+        ItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")),
+        ItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")),
+        ItemKind::ForeignMod { .. } => (Pat::Str("extern"), Pat::Str("}")),
+        ItemKind::TyAlias(..) | ItemKind::OpaqueTy(_) => (Pat::Str("type"), Pat::Str(";")),
+        ItemKind::Enum(..) => (Pat::Str("enum"), Pat::Str("}")),
+        ItemKind::Struct(VariantData::Struct(..), _) => (Pat::Str("struct"), Pat::Str("}")),
+        ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")),
+        ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")),
+        ItemKind::Trait(_, Unsafety::Unsafe, ..)
+        | ItemKind::Impl(Impl {
+            unsafety: Unsafety::Unsafe,
+            ..
+        }) => (Pat::Str("unsafe"), Pat::Str("}")),
+        ItemKind::Trait(IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")),
+        ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")),
+        ItemKind::Impl(_) => (Pat::Str("impl"), Pat::Str("}")),
+        _ => return (Pat::Str(""), Pat::Str("")),
+    };
+    if item.vis_span.is_empty() {
+        (start_pat, end_pat)
+    } else {
+        (Pat::Str("pub"), end_pat)
+    }
+}
+
+fn trait_item_search_pat(item: &TraitItem<'_>) -> (Pat, Pat) {
+    match &item.kind {
+        TraitItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")),
+        TraitItemKind::Type(..) => (Pat::Str("type"), Pat::Str(";")),
+        TraitItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")),
+    }
+}
+
+fn impl_item_search_pat(item: &ImplItem<'_>) -> (Pat, Pat) {
+    let (start_pat, end_pat) = match &item.kind {
+        ImplItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")),
+        ImplItemKind::TyAlias(..) => (Pat::Str("type"), Pat::Str(";")),
+        ImplItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")),
+    };
+    if item.vis_span.is_empty() {
+        (start_pat, end_pat)
+    } else {
+        (Pat::Str("pub"), end_pat)
+    }
+}
+
+fn field_def_search_pat(def: &FieldDef<'_>) -> (Pat, Pat) {
+    if def.vis_span.is_empty() {
+        if def.is_positional() {
+            (Pat::Str(""), Pat::Str(""))
+        } else {
+            (Pat::Sym(def.ident.name), Pat::Str(""))
+        }
+    } else {
+        (Pat::Str("pub"), Pat::Str(""))
+    }
+}
+
+fn variant_search_pat(v: &Variant<'_>) -> (Pat, Pat) {
+    match v.data {
+        VariantData::Struct(..) => (Pat::Sym(v.ident.name), Pat::Str("}")),
+        VariantData::Tuple(..) => (Pat::Sym(v.ident.name), Pat::Str("")),
+        VariantData::Unit(..) => (Pat::Sym(v.ident.name), Pat::Sym(v.ident.name)),
+    }
+}
+
+fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirId) -> (Pat, Pat) {
+    let (start_pat, end_pat) = match kind {
+        FnKind::ItemFn(.., header) => (fn_header_search_pat(*header), Pat::Str("")),
+        FnKind::Method(.., sig) => (fn_header_search_pat(sig.header), Pat::Str("")),
+        FnKind::Closure => return (Pat::Str(""), expr_search_pat(tcx, &body.value).1),
+    };
+    let start_pat = match tcx.hir().get(hir_id) {
+        Node::Item(Item { vis_span, .. }) | Node::ImplItem(ImplItem { vis_span, .. }) => {
+            if vis_span.is_empty() {
+                start_pat
+            } else {
+                Pat::Str("pub")
+            }
+        },
+        Node::TraitItem(_) => start_pat,
+        _ => Pat::Str(""),
+    };
+    (start_pat, end_pat)
+}
+
+pub trait WithSearchPat {
+    type Context: LintContext;
+    fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat);
+    fn span(&self) -> Span;
+}
+macro_rules! impl_with_search_pat {
+    ($cx:ident: $ty:ident with $fn:ident $(($tcx:ident))?) => {
+        impl<'cx> WithSearchPat for $ty<'cx> {
+            type Context = $cx<'cx>;
+            #[allow(unused_variables)]
+            fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat) {
+                $(let $tcx = cx.tcx;)?
+                $fn($($tcx,)? self)
+            }
+            fn span(&self) -> Span {
+                self.span
+            }
+        }
+    };
+}
+impl_with_search_pat!(LateContext: Expr with expr_search_pat(tcx));
+impl_with_search_pat!(LateContext: Item with item_search_pat);
+impl_with_search_pat!(LateContext: TraitItem with trait_item_search_pat);
+impl_with_search_pat!(LateContext: ImplItem with impl_item_search_pat);
+impl_with_search_pat!(LateContext: FieldDef with field_def_search_pat);
+impl_with_search_pat!(LateContext: Variant with variant_search_pat);
+
+impl<'cx> WithSearchPat for (&FnKind<'cx>, &Body<'cx>, HirId, Span) {
+    type Context = LateContext<'cx>;
+
+    fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat) {
+        fn_kind_pat(cx.tcx, self.0, self.1, self.2)
+    }
+
+    fn span(&self) -> Span {
+        self.3
+    }
+}
+
+/// Checks if the item likely came from a proc-macro.
+///
+/// This should be called after `in_external_macro` and the initial pattern matching of the ast as
+/// it is significantly slower than both of those.
+pub fn is_from_proc_macro<T: WithSearchPat>(cx: &T::Context, item: &T) -> bool {
+    let (start_pat, end_pat) = item.search_pat(cx);
+    !span_matches_pat(cx.sess(), item.span(), start_pat, end_pat)
+}
+
+/// Checks if the span actually refers to a match expression
+pub fn is_span_match(cx: &impl LintContext, span: Span) -> bool {
+    span_matches_pat(cx.sess(), span, Pat::Str("match"), Pat::Str("}"))
+}
+
+/// Checks if the span actually refers to an if expression
+pub fn is_span_if(cx: &impl LintContext, span: Span) -> bool {
+    span_matches_pat(cx.sess(), span, Pat::Str("if"), Pat::Str("}"))
+}
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 7493a8685df..2616a578bb8 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -39,6 +39,7 @@ pub mod sym_helper;
 
 pub mod ast_utils;
 pub mod attrs;
+mod check_proc_macro;
 pub mod comparisons;
 pub mod consts;
 pub mod diagnostics;
@@ -59,6 +60,7 @@ pub mod usage;
 pub mod visitors;
 
 pub use self::attrs::*;
+pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match};
 pub use self::hir_utils::{
     both, count_eq, eq_expr_value, hash_expr, hash_stmt, over, HirEqInterExpr, SpanlessEq, SpanlessHash,
 };
diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
index 3fb5415ce02..80098d9766c 100644
--- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs
+++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
@@ -223,10 +223,12 @@ impl<'a> NumericLiteral<'a> {
 
 fn split_suffix<'a>(src: &'a str, lit_kind: &LitKind) -> (&'a str, Option<&'a str>) {
     debug_assert!(lit_kind.is_numeric());
-    lit_suffix_length(lit_kind).map_or((src, None), |suffix_length| {
-        let (unsuffixed, suffix) = src.split_at(src.len() - suffix_length);
-        (unsuffixed, Some(suffix))
-    })
+    lit_suffix_length(lit_kind)
+        .and_then(|suffix_length| src.len().checked_sub(suffix_length))
+        .map_or((src, None), |split_pos| {
+            let (unsuffixed, suffix) = src.split_at(split_pos);
+            (unsuffixed, Some(suffix))
+        })
 }
 
 fn lit_suffix_length(lit_kind: &LitKind) -> Option<usize> {
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 05429d05d9e..8d697a301c4 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -194,3 +194,5 @@ pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
 pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
 pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
 pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"];
+pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"];
+pub const INSTANT: [&str; 3] = ["std", "time", "Instant"];
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index 1197fe914de..d85f591fb9a 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -11,24 +11,6 @@ use rustc_span::source_map::SourceMap;
 use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext};
 use std::borrow::Cow;
 
-/// Checks if the span starts with the given text. This will return false if the span crosses
-/// multiple files or if source is not available.
-///
-/// This is used to check for proc macros giving unhelpful spans to things.
-pub fn span_starts_with<T: LintContext>(cx: &T, span: Span, text: &str) -> bool {
-    fn helper(sm: &SourceMap, span: Span, text: &str) -> bool {
-        let pos = sm.lookup_byte_offset(span.lo());
-        let Some(ref src) = pos.sf.src else {
-            return false;
-        };
-        let end = span.hi() - pos.sf.start_pos;
-        src.get(pos.pos.0 as usize..end.0 as usize)
-            // Expression spans can include wrapping parenthesis. Remove them first.
-            .map_or(false, |s| s.trim_start_matches('(').starts_with(text))
-    }
-    helper(cx.sess().source_map(), span, text)
-}
-
 /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`.
 /// Also takes an `Option<String>` which can be put inside the braces.
 pub fn expr_block<'a, T: LintContext>(
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index bad291dfc25..081c98e2f3c 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -315,6 +315,12 @@ impl<'a> Sugg<'a> {
         Sugg::NonParen(Cow::Owned(format!("{{ {} }}", self)))
     }
 
+    /// Convenience method to prefix the expression with the `async` keyword.
+    /// Can be used after `blockify` to create an async block.
+    pub fn asyncify(self) -> Sugg<'static> {
+        Sugg::NonParen(Cow::Owned(format!("async {}", self)))
+    }
+
     /// Convenience method to create the `<lhs>..<rhs>` or `<lhs>...<rhs>`
     /// suggestion.
     pub fn range(self, end: &Self, limit: ast::RangeLimits) -> Sugg<'static> {
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index a05d633d980..e7d670766a0 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -503,7 +503,7 @@ pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator<Item = &(P
 pub enum ExprFnSig<'tcx> {
     Sig(Binder<'tcx, FnSig<'tcx>>, Option<DefId>),
     Closure(Option<&'tcx FnDecl<'tcx>>, Binder<'tcx, FnSig<'tcx>>),
-    Trait(Binder<'tcx, Ty<'tcx>>, Option<Binder<'tcx, Ty<'tcx>>>),
+    Trait(Binder<'tcx, Ty<'tcx>>, Option<Binder<'tcx, Ty<'tcx>>>, Option<DefId>),
 }
 impl<'tcx> ExprFnSig<'tcx> {
     /// Gets the argument type at the given offset. This will return `None` when the index is out of
@@ -518,7 +518,7 @@ impl<'tcx> ExprFnSig<'tcx> {
                 }
             },
             Self::Closure(_, sig) => Some(sig.input(0).map_bound(|ty| ty.tuple_fields()[i])),
-            Self::Trait(inputs, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])),
+            Self::Trait(inputs, _, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])),
         }
     }
 
@@ -541,7 +541,7 @@ impl<'tcx> ExprFnSig<'tcx> {
                 decl.and_then(|decl| decl.inputs.get(i)),
                 sig.input(0).map_bound(|ty| ty.tuple_fields()[i]),
             )),
-            Self::Trait(inputs, _) => Some((None, inputs.map_bound(|ty| ty.tuple_fields()[i]))),
+            Self::Trait(inputs, _, _) => Some((None, inputs.map_bound(|ty| ty.tuple_fields()[i]))),
         }
     }
 
@@ -550,12 +550,16 @@ impl<'tcx> ExprFnSig<'tcx> {
     pub fn output(self) -> Option<Binder<'tcx, Ty<'tcx>>> {
         match self {
             Self::Sig(sig, _) | Self::Closure(_, sig) => Some(sig.output()),
-            Self::Trait(_, output) => output,
+            Self::Trait(_, output, _) => output,
         }
     }
 
     pub fn predicates_id(&self) -> Option<DefId> {
-        if let ExprFnSig::Sig(_, id) = *self { id } else { None }
+        if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self {
+            id
+        } else {
+            None
+        }
     }
 }
 
@@ -568,7 +572,8 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnS
     }
 }
 
-fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> {
+/// If the type is function like, get the signature for it.
+pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> {
     if ty.is_box() {
         return ty_sig(cx, ty.boxed_ty());
     }
@@ -580,7 +585,7 @@ fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>>
             Some(ExprFnSig::Closure(decl, subs.as_closure().sig()))
         },
         ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))),
-        ty::Opaque(id, _) => ty_sig(cx, cx.tcx.type_of(id)),
+        ty::Opaque(id, _) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(id), cx.tcx.opt_parent(id)),
         ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)),
         ty::Dynamic(bounds, _) => {
             let lang_items = cx.tcx.lang_items();
@@ -594,26 +599,31 @@ fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>>
                         .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().unwrap()));
-                    Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output))
+                    Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output, None))
                 },
                 _ => None,
             }
         },
         ty::Projection(proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) {
             Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty),
-            _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty)),
+            _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)),
         },
-        ty::Param(_) => sig_from_bounds(cx, ty),
+        ty::Param(_) => sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None),
         _ => None,
     }
 }
 
-fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> {
+fn sig_from_bounds<'tcx>(
+    cx: &LateContext<'tcx>,
+    ty: Ty<'tcx>,
+    predicates: &'tcx [Predicate<'tcx>],
+    predicates_id: Option<DefId>,
+) -> Option<ExprFnSig<'tcx>> {
     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()) {
+    for pred in predicates {
         match pred.kind().skip_binder() {
             PredicateKind::Trait(p)
                 if (lang_items.fn_trait() == Some(p.def_id())
@@ -621,11 +631,12 @@ fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnS
                     || lang_items.fn_once_trait() == Some(p.def_id()))
                     && p.self_ty() == ty =>
             {
-                if inputs.is_some() {
+                let i = pred.kind().rebind(p.trait_ref.substs.type_at(1));
+                if inputs.map_or(false, |inputs| i != inputs) {
                     // Multiple different fn trait impls. Is this even allowed?
                     return None;
                 }
-                inputs = Some(pred.kind().rebind(p.trait_ref.substs.type_at(1)));
+                inputs = Some(i);
             },
             PredicateKind::Projection(p)
                 if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output()
@@ -641,7 +652,7 @@ fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnS
         }
     }
 
-    inputs.map(|ty| ExprFnSig::Trait(ty, output))
+    inputs.map(|ty| ExprFnSig::Trait(ty, output, predicates_id))
 }
 
 fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> Option<ExprFnSig<'tcx>> {
@@ -661,14 +672,15 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O
                     || lang_items.fn_mut_trait() == Some(p.def_id())
                     || lang_items.fn_once_trait() == Some(p.def_id())) =>
             {
-                if inputs.is_some() {
+                let i = pred
+                    .map_bound(|pred| pred.kind().rebind(p.trait_ref.substs.type_at(1)))
+                    .subst(cx.tcx, ty.substs);
+
+                if inputs.map_or(false, |inputs| inputs != i) {
                     // Multiple different fn trait impls. Is this even allowed?
                     return None;
                 }
-                inputs = Some(
-                    pred.map_bound(|pred| pred.kind().rebind(p.trait_ref.substs.type_at(1)))
-                        .subst(cx.tcx, ty.substs),
-                );
+                inputs = Some(i);
             },
             PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => {
                 if output.is_some() {
@@ -684,7 +696,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O
         }
     }
 
-    inputs.map(|ty| ExprFnSig::Trait(ty, output))
+    inputs.map(|ty| ExprFnSig::Trait(ty, output, None))
 }
 
 #[derive(Clone, Copy)]
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 23ba7c71277..7e14df4feea 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2022-07-28"
+channel = "nightly-2022-08-11"
 components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr b/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr
index 5331075885c..2aa4de490bc 100644
--- a/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr
+++ b/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr
@@ -16,7 +16,7 @@ note: the lint level is defined here
 LL | #![deny(clippy::internal)]
    |         ^^^^^^^^^^^^^^^^
    = note: `#[deny(clippy::invalid_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]`
-   = help: please use a valid sematic version, see `doc/adding_lints.md`
+   = help: please use a valid semantic version, see `doc/adding_lints.md`
    = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this item has an invalid `clippy::version` attribute
@@ -31,7 +31,7 @@ LL | |     report_in_external_macro: true
 LL | | }
    | |_^
    |
-   = help: please use a valid sematic version, see `doc/adding_lints.md`
+   = help: please use a valid semantic version, see `doc/adding_lints.md`
    = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: this lint is missing the `clippy::version` attribute or version value
diff --git a/src/tools/clippy/tests/ui-toml/bad_toml_type/clippy.toml b/src/tools/clippy/tests/ui-toml/bad_toml_type/clippy.toml
index 168675394d7..d48bab08f69 100644
--- a/src/tools/clippy/tests/ui-toml/bad_toml_type/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/bad_toml_type/clippy.toml
@@ -1 +1 @@
-blacklisted-names = 42
+disallowed-names = 42
diff --git a/src/tools/clippy/tests/ui-toml/bad_toml_type/conf_bad_type.stderr b/src/tools/clippy/tests/ui-toml/bad_toml_type/conf_bad_type.stderr
index c7bc261de6c..e3ec6019204 100644
--- a/src/tools/clippy/tests/ui-toml/bad_toml_type/conf_bad_type.stderr
+++ b/src/tools/clippy/tests/ui-toml/bad_toml_type/conf_bad_type.stderr
@@ -1,4 +1,4 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: invalid type: integer `42`, expected a sequence for key `blacklisted-names`
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: invalid type: integer `42`, expected a sequence for key `disallowed-names`
 
 error: aborting due to previous error
 
diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr b/src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr
deleted file mode 100644
index 9169bb0e866..00000000000
--- a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr
+++ /dev/null
@@ -1,16 +0,0 @@
-error: use of a blacklisted/placeholder name `foo`
-  --> $DIR/blacklisted_names.rs:5:9
-   |
-LL |     let foo = "bar";
-   |         ^^^
-   |
-   = note: `-D clippy::blacklisted-name` implied by `-D warnings`
-
-error: use of a blacklisted/placeholder name `ducks`
-  --> $DIR/blacklisted_names.rs:7:9
-   |
-LL |     let ducks = ["quack", "quack"];
-   |         ^^^^^
-
-error: aborting due to 2 previous errors
-
diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/clippy.toml b/src/tools/clippy/tests/ui-toml/blacklisted_names_append/clippy.toml
deleted file mode 100644
index 0e052ef50f0..00000000000
--- a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/clippy.toml
+++ /dev/null
@@ -1 +0,0 @@
-blacklisted-names = ["ducks", ".."]
diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr b/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr
deleted file mode 100644
index ec6f7f084f2..00000000000
--- a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr
+++ /dev/null
@@ -1,10 +0,0 @@
-error: use of a blacklisted/placeholder name `ducks`
-  --> $DIR/blacklisted_names.rs:7:9
-   |
-LL |     let ducks = ["quack", "quack"];
-   |         ^^^^^
-   |
-   = note: `-D clippy::blacklisted-name` implied by `-D warnings`
-
-error: aborting due to previous error
-
diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/clippy.toml b/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/clippy.toml
deleted file mode 100644
index 4582f1c0667..00000000000
--- a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/clippy.toml
+++ /dev/null
@@ -1 +0,0 @@
-blacklisted-names = ["ducks"]
diff --git a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/clippy.toml b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/clippy.toml
index ac47b195042..d79a98d05af 100644
--- a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/clippy.toml
@@ -1,5 +1,6 @@
-# that one is an error
-cyclomatic-complexity-threshold = 42
+# Expect errors from these deprecated configs
+cyclomatic-complexity-threshold = 2
+blacklisted-names = [ "..", "wibble" ]
 
 # that one is white-listed
 [third-party]
diff --git a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs
index f328e4d9d04..b4e677ea124 100644
--- a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs
+++ b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs
@@ -1 +1,11 @@
 fn main() {}
+
+#[warn(clippy::cognitive_complexity)]
+fn cognitive_complexity() {
+    let x = vec![1, 2, 3];
+    for i in x {
+        if i == 1 {
+            println!("{}", i);
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr
index 90021a034a3..4c560299ebd 100644
--- a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr
@@ -1,4 +1,15 @@
-error: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead
+warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead
 
-error: aborting due to previous error
+warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `blacklisted-names`. Please use `disallowed-names` instead
+
+error: the function has a cognitive complexity of (3/2)
+  --> $DIR/conf_deprecated_key.rs:4:4
+   |
+LL | fn cognitive_complexity() {
+   |    ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::cognitive-complexity` implied by `-D warnings`
+   = help: you could split it up into multiple smaller functions
+
+error: aborting due to previous error; 2 warnings emitted
 
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_append/clippy.toml b/src/tools/clippy/tests/ui-toml/disallowed_names_append/clippy.toml
new file mode 100644
index 00000000000..6df96a3c214
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/disallowed_names_append/clippy.toml
@@ -0,0 +1 @@
+disallowed-names = ["ducks", ".."]
diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.rs b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.rs
index fb2395cf90b..a2e2b46c426 100644
--- a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.rs
+++ b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.rs
@@ -1,9 +1,9 @@
-#[warn(clippy::blacklisted_name)]
+#[warn(clippy::disallowed_names)]
 
 fn main() {
     // `foo` is part of the default configuration
     let foo = "bar";
-    // `ducks` was unrightfully blacklisted
+    // `ducks` was unrightfully disallowed
     let ducks = ["quack", "quack"];
     // `fox` is okay
     let fox = ["what", "does", "the", "fox", "say", "?"];
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr
new file mode 100644
index 00000000000..23c3e96a8d0
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr
@@ -0,0 +1,16 @@
+error: use of a disallowed/placeholder name `foo`
+  --> $DIR/disallowed_names.rs:5:9
+   |
+LL |     let foo = "bar";
+   |         ^^^
+   |
+   = note: `-D clippy::disallowed-names` implied by `-D warnings`
+
+error: use of a disallowed/placeholder name `ducks`
+  --> $DIR/disallowed_names.rs:7:9
+   |
+LL |     let ducks = ["quack", "quack"];
+   |         ^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_replace/clippy.toml b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/clippy.toml
new file mode 100644
index 00000000000..a1c515652d3
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/clippy.toml
@@ -0,0 +1 @@
+disallowed-names = ["ducks"]
diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.rs b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.rs
index fb2395cf90b..a2e2b46c426 100644
--- a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.rs
+++ b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.rs
@@ -1,9 +1,9 @@
-#[warn(clippy::blacklisted_name)]
+#[warn(clippy::disallowed_names)]
 
 fn main() {
     // `foo` is part of the default configuration
     let foo = "bar";
-    // `ducks` was unrightfully blacklisted
+    // `ducks` was unrightfully disallowed
     let ducks = ["quack", "quack"];
     // `fox` is okay
     let fox = ["what", "does", "the", "fox", "say", "?"];
diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr
new file mode 100644
index 00000000000..d961fa34074
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr
@@ -0,0 +1,10 @@
+error: use of a disallowed/placeholder name `ducks`
+  --> $DIR/disallowed_names.rs:7:9
+   |
+LL |     let ducks = ["quack", "quack"];
+   |         ^^^^^
+   |
+   = note: `-D clippy::disallowed-names` implied by `-D warnings`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys/clippy.toml b/src/tools/clippy/tests/ui-toml/duplicated_keys/clippy.toml
new file mode 100644
index 00000000000..63a893cc6c7
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/duplicated_keys/clippy.toml
@@ -0,0 +1,5 @@
+cognitive-complexity-threshold = 2
+# This is the deprecated name for the same key
+cyclomatic-complexity-threshold = 3
+# Check we get duplication warning regardless of order
+cognitive-complexity-threshold = 4
diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.rs b/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.stderr b/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.stderr
new file mode 100644
index 00000000000..d99490a242d
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.stderr
@@ -0,0 +1,8 @@
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: duplicate field `cognitive_complexity_threshold` (provided as `cyclomatic_complexity_threshold`)
+
+error: error reading Clippy's configuration file `$DIR/clippy.toml`: duplicate field `cognitive-complexity-threshold`
+
+warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead
+
+error: aborting due to 2 previous errors; 1 warning emitted
+
diff --git a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr
index 9cb2199ed21..c5d95cb8a14 100644
--- a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr
+++ b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr
@@ -5,7 +5,7 @@ LL |     let _ = opt.expect("");
    |             ^^^^^^^^^^^^^^
    |
    = note: `-D clippy::expect-used` implied by `-D warnings`
-   = help: if this value is an `None`, it will panic
+   = help: if this value is `None`, it will panic
 
 error: used `expect()` on `a Result` value
   --> $DIR/expect_used.rs:11:13
diff --git a/src/tools/clippy/tests/ui-toml/toml_blacklist/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_blacklist/clippy.toml
deleted file mode 100644
index 6abe5a3bbc2..00000000000
--- a/src/tools/clippy/tests/ui-toml/toml_blacklist/clippy.toml
+++ /dev/null
@@ -1 +0,0 @@
-blacklisted-names = ["toto", "tata", "titi"]
diff --git a/src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr b/src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr
deleted file mode 100644
index 84ba77851f7..00000000000
--- a/src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr
+++ /dev/null
@@ -1,46 +0,0 @@
-error: use of a blacklisted/placeholder name `toto`
-  --> $DIR/conf_french_blacklisted_name.rs:6:9
-   |
-LL | fn test(toto: ()) {}
-   |         ^^^^
-   |
-   = note: `-D clippy::blacklisted-name` implied by `-D warnings`
-
-error: use of a blacklisted/placeholder name `toto`
-  --> $DIR/conf_french_blacklisted_name.rs:9:9
-   |
-LL |     let toto = 42;
-   |         ^^^^
-
-error: use of a blacklisted/placeholder name `tata`
-  --> $DIR/conf_french_blacklisted_name.rs:10:9
-   |
-LL |     let tata = 42;
-   |         ^^^^
-
-error: use of a blacklisted/placeholder name `titi`
-  --> $DIR/conf_french_blacklisted_name.rs:11:9
-   |
-LL |     let titi = 42;
-   |         ^^^^
-
-error: use of a blacklisted/placeholder name `toto`
-  --> $DIR/conf_french_blacklisted_name.rs:17:10
-   |
-LL |         (toto, Some(tata), titi @ Some(_)) => (),
-   |          ^^^^
-
-error: use of a blacklisted/placeholder name `tata`
-  --> $DIR/conf_french_blacklisted_name.rs:17:21
-   |
-LL |         (toto, Some(tata), titi @ Some(_)) => (),
-   |                     ^^^^
-
-error: use of a blacklisted/placeholder name `titi`
-  --> $DIR/conf_french_blacklisted_name.rs:17:28
-   |
-LL |         (toto, Some(tata), titi @ Some(_)) => (),
-   |                            ^^^^
-
-error: aborting due to 7 previous errors
-
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallow/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_disallow/clippy.toml
new file mode 100644
index 00000000000..e4f0cb6df57
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_disallow/clippy.toml
@@ -0,0 +1 @@
+disallowed-names = ["toto", "tata", "titi"]
diff --git a/src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs b/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs
index cb35d0e8589..2f86b3eda4c 100644
--- a/src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs
+++ b/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs
@@ -1,7 +1,7 @@
 #![allow(dead_code)]
 #![allow(clippy::single_match)]
 #![allow(unused_variables)]
-#![warn(clippy::blacklisted_name)]
+#![warn(clippy::disallowed_names)]
 
 fn test(toto: ()) {}
 
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr b/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr
new file mode 100644
index 00000000000..9082c1c54c3
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr
@@ -0,0 +1,46 @@
+error: use of a disallowed/placeholder name `toto`
+  --> $DIR/conf_french_disallowed_name.rs:6:9
+   |
+LL | fn test(toto: ()) {}
+   |         ^^^^
+   |
+   = note: `-D clippy::disallowed-names` implied by `-D warnings`
+
+error: use of a disallowed/placeholder name `toto`
+  --> $DIR/conf_french_disallowed_name.rs:9:9
+   |
+LL |     let toto = 42;
+   |         ^^^^
+
+error: use of a disallowed/placeholder name `tata`
+  --> $DIR/conf_french_disallowed_name.rs:10:9
+   |
+LL |     let tata = 42;
+   |         ^^^^
+
+error: use of a disallowed/placeholder name `titi`
+  --> $DIR/conf_french_disallowed_name.rs:11:9
+   |
+LL |     let titi = 42;
+   |         ^^^^
+
+error: use of a disallowed/placeholder name `toto`
+  --> $DIR/conf_french_disallowed_name.rs:17:10
+   |
+LL |         (toto, Some(tata), titi @ Some(_)) => (),
+   |          ^^^^
+
+error: use of a disallowed/placeholder name `tata`
+  --> $DIR/conf_french_disallowed_name.rs:17:21
+   |
+LL |         (toto, Some(tata), titi @ Some(_)) => (),
+   |                     ^^^^
+
+error: use of a disallowed/placeholder name `titi`
+  --> $DIR/conf_french_disallowed_name.rs:17:28
+   |
+LL |         (toto, Some(tata), titi @ Some(_)) => (),
+   |                            ^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index fe5139c4768..9f8e778b3b9 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -12,6 +12,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie
            cognitive-complexity-threshold
            cyclomatic-complexity-threshold
            disallowed-methods
+           disallowed-names
            disallowed-types
            doc-valid-idents
            enable-raw-pointer-heuristic-for-send
diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.fixed b/src/tools/clippy/tests/ui/assertions_on_result_states.fixed
index 7bde72e4b6b..795f435f24c 100644
--- a/src/tools/clippy/tests/ui/assertions_on_result_states.fixed
+++ b/src/tools/clippy/tests/ui/assertions_on_result_states.fixed
@@ -27,6 +27,14 @@ fn main() {
     let r: Result<Foo, Foo> = Ok(Foo);
     assert!(r.is_ok());
 
+    // test ok with some messages
+    let r: Result<Foo, DebugFoo> = Ok(Foo);
+    assert!(r.is_ok(), "oops");
+
+    // test ok with unit error
+    let r: Result<Foo, ()> = Ok(Foo);
+    assert!(r.is_ok());
+
     // test temporary ok
     fn get_ok() -> Result<Foo, DebugFoo> {
         Ok(Foo)
diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.rs b/src/tools/clippy/tests/ui/assertions_on_result_states.rs
index 4c5af81efc2..1101aec1e1b 100644
--- a/src/tools/clippy/tests/ui/assertions_on_result_states.rs
+++ b/src/tools/clippy/tests/ui/assertions_on_result_states.rs
@@ -27,6 +27,14 @@ fn main() {
     let r: Result<Foo, Foo> = Ok(Foo);
     assert!(r.is_ok());
 
+    // test ok with some messages
+    let r: Result<Foo, DebugFoo> = Ok(Foo);
+    assert!(r.is_ok(), "oops");
+
+    // test ok with unit error
+    let r: Result<Foo, ()> = Ok(Foo);
+    assert!(r.is_ok());
+
     // test temporary ok
     fn get_ok() -> Result<Foo, DebugFoo> {
         Ok(Foo)
diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.stderr b/src/tools/clippy/tests/ui/assertions_on_result_states.stderr
index 13c2dd877a9..97a5f3dfca4 100644
--- a/src/tools/clippy/tests/ui/assertions_on_result_states.stderr
+++ b/src/tools/clippy/tests/ui/assertions_on_result_states.stderr
@@ -7,31 +7,31 @@ LL |     assert!(r.is_ok());
    = note: `-D clippy::assertions-on-result-states` implied by `-D warnings`
 
 error: called `assert!` with `Result::is_ok`
-  --> $DIR/assertions_on_result_states.rs:34:5
+  --> $DIR/assertions_on_result_states.rs:42:5
    |
 LL |     assert!(get_ok().is_ok());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok().unwrap()`
 
 error: called `assert!` with `Result::is_ok`
-  --> $DIR/assertions_on_result_states.rs:37:5
+  --> $DIR/assertions_on_result_states.rs:45:5
    |
 LL |     assert!(get_ok_macro!().is_ok());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok_macro!().unwrap()`
 
 error: called `assert!` with `Result::is_ok`
-  --> $DIR/assertions_on_result_states.rs:50:5
+  --> $DIR/assertions_on_result_states.rs:58:5
    |
 LL |     assert!(r.is_ok());
    |     ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()`
 
 error: called `assert!` with `Result::is_ok`
-  --> $DIR/assertions_on_result_states.rs:56:9
+  --> $DIR/assertions_on_result_states.rs:64:9
    |
 LL |         assert!(r.is_ok());
    |         ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()`
 
 error: called `assert!` with `Result::is_err`
-  --> $DIR/assertions_on_result_states.rs:64:5
+  --> $DIR/assertions_on_result_states.rs:72:5
    |
 LL |     assert!(r.is_err());
    |     ^^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap_err()`
diff --git a/src/tools/clippy/tests/ui/blacklisted_name.stderr b/src/tools/clippy/tests/ui/blacklisted_name.stderr
deleted file mode 100644
index 70dbdaece8b..00000000000
--- a/src/tools/clippy/tests/ui/blacklisted_name.stderr
+++ /dev/null
@@ -1,88 +0,0 @@
-error: use of a blacklisted/placeholder name `foo`
-  --> $DIR/blacklisted_name.rs:11:9
-   |
-LL | fn test(foo: ()) {}
-   |         ^^^
-   |
-   = note: `-D clippy::blacklisted-name` implied by `-D warnings`
-
-error: use of a blacklisted/placeholder name `foo`
-  --> $DIR/blacklisted_name.rs:14:9
-   |
-LL |     let foo = 42;
-   |         ^^^
-
-error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:15:9
-   |
-LL |     let baz = 42;
-   |         ^^^
-
-error: use of a blacklisted/placeholder name `quux`
-  --> $DIR/blacklisted_name.rs:16:9
-   |
-LL |     let quux = 42;
-   |         ^^^^
-
-error: use of a blacklisted/placeholder name `foo`
-  --> $DIR/blacklisted_name.rs:27:10
-   |
-LL |         (foo, Some(baz), quux @ Some(_)) => (),
-   |          ^^^
-
-error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:27:20
-   |
-LL |         (foo, Some(baz), quux @ Some(_)) => (),
-   |                    ^^^
-
-error: use of a blacklisted/placeholder name `quux`
-  --> $DIR/blacklisted_name.rs:27:26
-   |
-LL |         (foo, Some(baz), quux @ Some(_)) => (),
-   |                          ^^^^
-
-error: use of a blacklisted/placeholder name `foo`
-  --> $DIR/blacklisted_name.rs:32:19
-   |
-LL | fn issue_1647(mut foo: u8) {
-   |                   ^^^
-
-error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:33:13
-   |
-LL |     let mut baz = 0;
-   |             ^^^
-
-error: use of a blacklisted/placeholder name `quux`
-  --> $DIR/blacklisted_name.rs:34:21
-   |
-LL |     if let Some(mut quux) = Some(42) {}
-   |                     ^^^^
-
-error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:38:13
-   |
-LL |     let ref baz = 0;
-   |             ^^^
-
-error: use of a blacklisted/placeholder name `quux`
-  --> $DIR/blacklisted_name.rs:39:21
-   |
-LL |     if let Some(ref quux) = Some(42) {}
-   |                     ^^^^
-
-error: use of a blacklisted/placeholder name `baz`
-  --> $DIR/blacklisted_name.rs:43:17
-   |
-LL |     let ref mut baz = 0;
-   |                 ^^^
-
-error: use of a blacklisted/placeholder name `quux`
-  --> $DIR/blacklisted_name.rs:44:25
-   |
-LL |     if let Some(ref mut quux) = Some(42) {}
-   |                         ^^^^
-
-error: aborting due to 14 previous errors
-
diff --git a/src/tools/clippy/tests/ui/borrow_box.rs b/src/tools/clippy/tests/ui/borrow_box.rs
index b606f773cfb..35ed87b0f18 100644
--- a/src/tools/clippy/tests/ui/borrow_box.rs
+++ b/src/tools/clippy/tests/ui/borrow_box.rs
@@ -1,5 +1,5 @@
 #![deny(clippy::borrowed_box)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
 #![allow(unused_variables)]
 #![allow(dead_code)]
 
diff --git a/src/tools/clippy/tests/ui/box_collection.rs b/src/tools/clippy/tests/ui/box_collection.rs
index 1a74cdb3ff6..0780c8f0586 100644
--- a/src/tools/clippy/tests/ui/box_collection.rs
+++ b/src/tools/clippy/tests/ui/box_collection.rs
@@ -2,7 +2,7 @@
 #![allow(
     clippy::boxed_local,
     clippy::needless_pass_by_value,
-    clippy::blacklisted_name,
+    clippy::disallowed_names,
     unused
 )]
 
diff --git a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed
index a68b32b097e..7ecefd7b134 100644
--- a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed
+++ b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed
@@ -26,4 +26,6 @@ fn main() {
     let _ = a.unsigned_abs() as u32;
     let _ = a.unsigned_abs() as u64;
     let _ = a.unsigned_abs() as u128;
+
+    let _ = (x as i64 - y as i64).unsigned_abs() as u32;
 }
diff --git a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs
index 110fbc6c2df..30c603fca9a 100644
--- a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs
+++ b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs
@@ -26,4 +26,6 @@ fn main() {
     let _ = a.abs() as u32;
     let _ = a.abs() as u64;
     let _ = a.abs() as u128;
+
+    let _ = (x as i64 - y as i64).abs() as u32;
 }
diff --git a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr
index 02c24e10659..04553774526 100644
--- a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr
+++ b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr
@@ -96,5 +96,11 @@ error: casting the result of `isize::abs()` to u128
 LL |     let _ = a.abs() as u128;
    |             ^^^^^^^ help: replace with: `a.unsigned_abs()`
 
-error: aborting due to 16 previous errors
+error: casting the result of `i64::abs()` to u32
+  --> $DIR/cast_abs_to_unsigned.rs:30:13
+   |
+LL |     let _ = (x as i64 - y as i64).abs() as u32;
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `(x as i64 - y as i64).unsigned_abs()`
+
+error: aborting due to 17 previous errors
 
diff --git a/src/tools/clippy/tests/ui/clone_on_copy.fixed b/src/tools/clippy/tests/ui/clone_on_copy.fixed
index dc062762604..72b12227098 100644
--- a/src/tools/clippy/tests/ui/clone_on_copy.fixed
+++ b/src/tools/clippy/tests/ui/clone_on_copy.fixed
@@ -21,7 +21,7 @@ fn is_ascii(ch: char) -> bool {
     ch.is_ascii()
 }
 
-fn clone_on_copy() {
+fn clone_on_copy() -> Option<(i32)> {
     42;
 
     vec![1].clone(); // ok, not a Copy type
@@ -71,4 +71,9 @@ fn clone_on_copy() {
     // Issue #5436
     let mut vec = Vec::new();
     vec.push(42);
+
+    //  Issue #9277
+    let opt: &Option<i32> = &None;
+    let value = (*opt)?; // operator precedence needed (*opt)?
+    None
 }
diff --git a/src/tools/clippy/tests/ui/clone_on_copy.rs b/src/tools/clippy/tests/ui/clone_on_copy.rs
index 8c39d0d55dd..03e210ebad9 100644
--- a/src/tools/clippy/tests/ui/clone_on_copy.rs
+++ b/src/tools/clippy/tests/ui/clone_on_copy.rs
@@ -21,7 +21,7 @@ fn is_ascii(ch: char) -> bool {
     ch.is_ascii()
 }
 
-fn clone_on_copy() {
+fn clone_on_copy() -> Option<(i32)> {
     42.clone();
 
     vec![1].clone(); // ok, not a Copy type
@@ -71,4 +71,9 @@ fn clone_on_copy() {
     // Issue #5436
     let mut vec = Vec::new();
     vec.push(42.clone());
+
+    //  Issue #9277
+    let opt: &Option<i32> = &None;
+    let value = opt.clone()?; // operator precedence needed (*opt)?
+    None
 }
diff --git a/src/tools/clippy/tests/ui/clone_on_copy.stderr b/src/tools/clippy/tests/ui/clone_on_copy.stderr
index 861543d0aa9..42ae227777c 100644
--- a/src/tools/clippy/tests/ui/clone_on_copy.stderr
+++ b/src/tools/clippy/tests/ui/clone_on_copy.stderr
@@ -48,5 +48,11 @@ error: using `clone` on type `i32` which implements the `Copy` trait
 LL |     vec.push(42.clone());
    |              ^^^^^^^^^^ help: try removing the `clone` call: `42`
 
-error: aborting due to 8 previous errors
+error: using `clone` on type `std::option::Option<i32>` which implements the `Copy` trait
+  --> $DIR/clone_on_copy.rs:77:17
+   |
+LL |     let value = opt.clone()?; // operator precedence needed (*opt)?
+   |                 ^^^^^^^^^^^ help: try dereferencing it: `(*opt)`
+
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2760.rs b/src/tools/clippy/tests/ui/crashes/ice-2760.rs
index f1a229f3f4f..61ef2480498 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-2760.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-2760.rs
@@ -1,6 +1,6 @@
 #![allow(
     unused_variables,
-    clippy::blacklisted_name,
+    clippy::disallowed_names,
     clippy::needless_pass_by_value,
     dead_code
 )]
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3462.rs b/src/tools/clippy/tests/ui/crashes/ice-3462.rs
index 02c49aa0d7c..b402052882a 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-3462.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-3462.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::all)]
-#![allow(clippy::blacklisted_name, clippy::equatable_if_let)]
+#![allow(clippy::disallowed_names, clippy::equatable_if_let)]
 #![allow(unused)]
 
 /// Test for https://github.com/rust-lang/rust-clippy/issues/3462
diff --git a/src/tools/clippy/tests/ui/crashes/regressions.rs b/src/tools/clippy/tests/ui/crashes/regressions.rs
index 6f9d98bbfe7..55a8b403407 100644
--- a/src/tools/clippy/tests/ui/crashes/regressions.rs
+++ b/src/tools/clippy/tests/ui/crashes/regressions.rs
@@ -1,4 +1,4 @@
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
 
 pub fn foo(bar: *const u8) {
     println!("{:#p}", bar);
diff --git a/src/tools/clippy/tests/ui/def_id_nocore.rs b/src/tools/clippy/tests/ui/def_id_nocore.rs
index 156c88e2e45..a7da8f89aa3 100644
--- a/src/tools/clippy/tests/ui/def_id_nocore.rs
+++ b/src/tools/clippy/tests/ui/def_id_nocore.rs
@@ -1,4 +1,3 @@
-// ignore-windows
 // ignore-macos
 
 #![feature(no_core, lang_items, start)]
diff --git a/src/tools/clippy/tests/ui/def_id_nocore.stderr b/src/tools/clippy/tests/ui/def_id_nocore.stderr
index 40d355e9a2e..6210d7c6cfd 100644
--- a/src/tools/clippy/tests/ui/def_id_nocore.stderr
+++ b/src/tools/clippy/tests/ui/def_id_nocore.stderr
@@ -1,5 +1,5 @@
 error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-  --> $DIR/def_id_nocore.rs:28:19
+  --> $DIR/def_id_nocore.rs:27:19
    |
 LL |     pub fn as_ref(self) -> &'static str {
    |                   ^^^^
diff --git a/src/tools/clippy/tests/ui/default_trait_access.fixed b/src/tools/clippy/tests/ui/default_trait_access.fixed
index 264dd4efaeb..fce66eb1759 100644
--- a/src/tools/clippy/tests/ui/default_trait_access.fixed
+++ b/src/tools/clippy/tests/ui/default_trait_access.fixed
@@ -1,8 +1,12 @@
 // run-rustfix
+// aux-build: proc_macro_with_span.rs
 
 #![allow(unused_imports, dead_code)]
 #![deny(clippy::default_trait_access)]
 
+extern crate proc_macro_with_span;
+
+use proc_macro_with_span::with_span;
 use std::default;
 use std::default::Default as D2;
 use std::string;
@@ -51,6 +55,8 @@ fn main() {
         ..Default::default()
     };
 
+    let _s21: String = with_span!(s Default::default());
+
     println!(
         "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]",
         s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20,
diff --git a/src/tools/clippy/tests/ui/default_trait_access.rs b/src/tools/clippy/tests/ui/default_trait_access.rs
index a0930fab8e7..3e8e898b7bc 100644
--- a/src/tools/clippy/tests/ui/default_trait_access.rs
+++ b/src/tools/clippy/tests/ui/default_trait_access.rs
@@ -1,8 +1,12 @@
 // run-rustfix
+// aux-build: proc_macro_with_span.rs
 
 #![allow(unused_imports, dead_code)]
 #![deny(clippy::default_trait_access)]
 
+extern crate proc_macro_with_span;
+
+use proc_macro_with_span::with_span;
 use std::default;
 use std::default::Default as D2;
 use std::string;
@@ -51,6 +55,8 @@ fn main() {
         ..Default::default()
     };
 
+    let _s21: String = with_span!(s Default::default());
+
     println!(
         "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]",
         s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20,
diff --git a/src/tools/clippy/tests/ui/default_trait_access.stderr b/src/tools/clippy/tests/ui/default_trait_access.stderr
index df8a5b94ddc..3493de37a55 100644
--- a/src/tools/clippy/tests/ui/default_trait_access.stderr
+++ b/src/tools/clippy/tests/ui/default_trait_access.stderr
@@ -1,53 +1,53 @@
 error: calling `std::string::String::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:11:22
+  --> $DIR/default_trait_access.rs:15:22
    |
 LL |     let s1: String = Default::default();
    |                      ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
    |
 note: the lint level is defined here
-  --> $DIR/default_trait_access.rs:4:9
+  --> $DIR/default_trait_access.rs:5:9
    |
 LL | #![deny(clippy::default_trait_access)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: calling `std::string::String::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:15:22
+  --> $DIR/default_trait_access.rs:19:22
    |
 LL |     let s3: String = D2::default();
    |                      ^^^^^^^^^^^^^ help: try: `std::string::String::default()`
 
 error: calling `std::string::String::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:17:22
+  --> $DIR/default_trait_access.rs:21:22
    |
 LL |     let s4: String = std::default::Default::default();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
 
 error: calling `std::string::String::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:21:22
+  --> $DIR/default_trait_access.rs:25:22
    |
 LL |     let s6: String = default::Default::default();
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()`
 
 error: calling `GenericDerivedDefault::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:31:46
+  --> $DIR/default_trait_access.rs:35:46
    |
 LL |     let s11: GenericDerivedDefault<String> = Default::default();
    |                                              ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault::default()`
 
 error: calling `TupleDerivedDefault::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:37:36
+  --> $DIR/default_trait_access.rs:41:36
    |
 LL |     let s14: TupleDerivedDefault = Default::default();
    |                                    ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()`
 
 error: calling `ArrayDerivedDefault::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:39:36
+  --> $DIR/default_trait_access.rs:43:36
    |
 LL |     let s15: ArrayDerivedDefault = Default::default();
    |                                    ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()`
 
 error: calling `TupleStructDerivedDefault::default()` is more clear than this expression
-  --> $DIR/default_trait_access.rs:43:42
+  --> $DIR/default_trait_access.rs:47:42
    |
 LL |     let s17: TupleStructDerivedDefault = Default::default();
    |                                          ^^^^^^^^^^^^^^^^^^ help: try: `TupleStructDerivedDefault::default()`
diff --git a/src/tools/clippy/tests/ui/blacklisted_name.rs b/src/tools/clippy/tests/ui/disallowed_names.rs
index 27df732a088..e937c49f389 100644
--- a/src/tools/clippy/tests/ui/blacklisted_name.rs
+++ b/src/tools/clippy/tests/ui/disallowed_names.rs
@@ -6,7 +6,7 @@
     unused_mut,
     unused_variables
 )]
-#![warn(clippy::blacklisted_name)]
+#![warn(clippy::disallowed_names)]
 
 fn test(foo: ()) {}
 
@@ -46,7 +46,7 @@ fn issue_1647_ref_mut() {
 
 mod tests {
     fn issue_7305() {
-        // `blacklisted_name` lint should not be triggered inside of the test code.
+        // `disallowed_names` lint should not be triggered inside of the test code.
         let foo = 0;
 
         // Check that even in nested functions warning is still not triggered.
diff --git a/src/tools/clippy/tests/ui/disallowed_names.stderr b/src/tools/clippy/tests/ui/disallowed_names.stderr
new file mode 100644
index 00000000000..78cb55096ff
--- /dev/null
+++ b/src/tools/clippy/tests/ui/disallowed_names.stderr
@@ -0,0 +1,88 @@
+error: use of a disallowed/placeholder name `foo`
+  --> $DIR/disallowed_names.rs:11:9
+   |
+LL | fn test(foo: ()) {}
+   |         ^^^
+   |
+   = note: `-D clippy::disallowed-names` implied by `-D warnings`
+
+error: use of a disallowed/placeholder name `foo`
+  --> $DIR/disallowed_names.rs:14:9
+   |
+LL |     let foo = 42;
+   |         ^^^
+
+error: use of a disallowed/placeholder name `baz`
+  --> $DIR/disallowed_names.rs:15:9
+   |
+LL |     let baz = 42;
+   |         ^^^
+
+error: use of a disallowed/placeholder name `quux`
+  --> $DIR/disallowed_names.rs:16:9
+   |
+LL |     let quux = 42;
+   |         ^^^^
+
+error: use of a disallowed/placeholder name `foo`
+  --> $DIR/disallowed_names.rs:27:10
+   |
+LL |         (foo, Some(baz), quux @ Some(_)) => (),
+   |          ^^^
+
+error: use of a disallowed/placeholder name `baz`
+  --> $DIR/disallowed_names.rs:27:20
+   |
+LL |         (foo, Some(baz), quux @ Some(_)) => (),
+   |                    ^^^
+
+error: use of a disallowed/placeholder name `quux`
+  --> $DIR/disallowed_names.rs:27:26
+   |
+LL |         (foo, Some(baz), quux @ Some(_)) => (),
+   |                          ^^^^
+
+error: use of a disallowed/placeholder name `foo`
+  --> $DIR/disallowed_names.rs:32:19
+   |
+LL | fn issue_1647(mut foo: u8) {
+   |                   ^^^
+
+error: use of a disallowed/placeholder name `baz`
+  --> $DIR/disallowed_names.rs:33:13
+   |
+LL |     let mut baz = 0;
+   |             ^^^
+
+error: use of a disallowed/placeholder name `quux`
+  --> $DIR/disallowed_names.rs:34:21
+   |
+LL |     if let Some(mut quux) = Some(42) {}
+   |                     ^^^^
+
+error: use of a disallowed/placeholder name `baz`
+  --> $DIR/disallowed_names.rs:38:13
+   |
+LL |     let ref baz = 0;
+   |             ^^^
+
+error: use of a disallowed/placeholder name `quux`
+  --> $DIR/disallowed_names.rs:39:21
+   |
+LL |     if let Some(ref quux) = Some(42) {}
+   |                     ^^^^
+
+error: use of a disallowed/placeholder name `baz`
+  --> $DIR/disallowed_names.rs:43:17
+   |
+LL |     let ref mut baz = 0;
+   |                 ^^^
+
+error: use of a disallowed/placeholder name `quux`
+  --> $DIR/disallowed_names.rs:44:25
+   |
+LL |     if let Some(ref mut quux) = Some(42) {}
+   |                         ^^^^
+
+error: aborting due to 14 previous errors
+
diff --git a/src/tools/clippy/tests/ui/diverging_sub_expression.rs b/src/tools/clippy/tests/ui/diverging_sub_expression.rs
index e27f9fea708..e8f992e6dde 100644
--- a/src/tools/clippy/tests/ui/diverging_sub_expression.rs
+++ b/src/tools/clippy/tests/ui/diverging_sub_expression.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::diverging_sub_expression)]
-#![allow(clippy::match_same_arms, clippy::logic_bug)]
+#![allow(clippy::match_same_arms, clippy::overly_complex_bool_expr)]
 #[allow(clippy::empty_loop)]
 fn diverge() -> ! {
     loop {}
diff --git a/src/tools/clippy/tests/ui/empty_loop_no_std.rs b/src/tools/clippy/tests/ui/empty_loop_no_std.rs
index 235e0fc5179..e742b396fcd 100644
--- a/src/tools/clippy/tests/ui/empty_loop_no_std.rs
+++ b/src/tools/clippy/tests/ui/empty_loop_no_std.rs
@@ -1,6 +1,5 @@
 // compile-flags: -Clink-arg=-nostartfiles
 // ignore-macos
-// ignore-windows
 
 #![warn(clippy::empty_loop)]
 #![feature(lang_items, start, libc)]
diff --git a/src/tools/clippy/tests/ui/empty_loop_no_std.stderr b/src/tools/clippy/tests/ui/empty_loop_no_std.stderr
index 520248fcb68..5ded35a6f0d 100644
--- a/src/tools/clippy/tests/ui/empty_loop_no_std.stderr
+++ b/src/tools/clippy/tests/ui/empty_loop_no_std.stderr
@@ -1,5 +1,5 @@
 error: empty `loop {}` wastes CPU cycles
-  --> $DIR/empty_loop_no_std.rs:14:5
+  --> $DIR/empty_loop_no_std.rs:13:5
    |
 LL |     loop {}
    |     ^^^^^^^
@@ -8,7 +8,7 @@ LL |     loop {}
    = help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body
 
 error: empty `loop {}` wastes CPU cycles
-  --> $DIR/empty_loop_no_std.rs:26:5
+  --> $DIR/empty_loop_no_std.rs:25:5
    |
 LL |     loop {}
    |     ^^^^^^^
diff --git a/src/tools/clippy/tests/ui/expect.stderr b/src/tools/clippy/tests/ui/expect.stderr
index 9d3fc7df15c..ab28aac4556 100644
--- a/src/tools/clippy/tests/ui/expect.stderr
+++ b/src/tools/clippy/tests/ui/expect.stderr
@@ -5,7 +5,7 @@ LL |     let _ = opt.expect("");
    |             ^^^^^^^^^^^^^^
    |
    = note: `-D clippy::expect-used` implied by `-D warnings`
-   = help: if this value is an `None`, it will panic
+   = help: if this value is `None`, it will panic
 
 error: used `expect()` on `a Result` value
   --> $DIR/expect.rs:10:13
diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs
index 28b37f96e91..0415e33b3fa 100644
--- a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs
+++ b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs
@@ -98,7 +98,7 @@ mod clippy_ok {
         let _ = if true { 42 } else { 42 };
     }
 
-    #[expect(clippy::logic_bug)]
+    #[expect(clippy::overly_complex_bool_expr)]
     fn burger() {
         let a = false;
         let b = true;
@@ -127,7 +127,7 @@ mod clippy_warn {
         let _ = if true { 33 } else { 42 };
     }
 
-    #[expect(clippy::logic_bug)]
+    #[expect(clippy::overly_complex_bool_expr)]
     fn burger() {
         let a = false;
         let b = true;
diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr
index db29e85a821..7ce9e855b5e 100644
--- a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr
+++ b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr
@@ -33,8 +33,8 @@ LL |     #[expect(clippy::if_same_then_else)]
 error: this lint expectation is unfulfilled
   --> $DIR/expect_tool_lint_rfc_2383.rs:130:14
    |
-LL |     #[expect(clippy::logic_bug)]
-   |              ^^^^^^^^^^^^^^^^^
+LL |     #[expect(clippy::overly_complex_bool_expr)]
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
index a650fdc1f89..d1d35e5c0eb 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![feature(closure_lifetime_binder)]
 #![warn(clippy::explicit_auto_deref)]
 #![allow(
     dead_code,
@@ -67,6 +68,8 @@ fn main() {
     let s = String::new();
 
     let _: &str = &s;
+    let _: &str = &{ String::new() };
+    let _: &str = &mut { String::new() };
     let _ = &*s; // Don't lint. Inferred type would change.
     let _: &_ = &*s; // Don't lint. Inferred type would change.
 
@@ -215,4 +218,52 @@ fn main() {
     let s = &"str";
     let _ = || return *s;
     let _ = || -> &'static str { return s };
+
+    struct X;
+    struct Y(X);
+    impl core::ops::Deref for Y {
+        type Target = X;
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+    let _: &X = &*{ Y(X) };
+    let _: &X = &*match 0 {
+        #[rustfmt::skip]
+        0 => { Y(X) },
+        _ => panic!(),
+    };
+    let _: &X = &*if true { Y(X) } else { panic!() };
+
+    fn deref_to_u<U, T: core::ops::Deref<Target = U>>(x: &T) -> &U {
+        x
+    }
+
+    let _ = |x: &'static Box<dyn Iterator<Item = u32>>| -> &'static dyn Iterator<Item = u32> { &**x };
+    fn ret_any(x: &Box<dyn std::any::Any>) -> &dyn std::any::Any {
+        &**x
+    }
+
+    let x = String::new();
+    let _: *const str = &*x;
+
+    struct S7([u32; 1]);
+    impl core::ops::Deref for S7 {
+        type Target = [u32; 1];
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+    let x = S7([0]);
+    let _: &[u32] = &*x;
+
+    let c1 = |_: &Vec<&u32>| {};
+    let x = &&vec![&1u32];
+    c1(x);
+    let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> {
+        if b {
+            return x;
+        }
+        x
+    };
 }
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.rs b/src/tools/clippy/tests/ui/explicit_auto_deref.rs
index 8f4f352576a..deedafad153 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.rs
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.rs
@@ -1,5 +1,6 @@
 // run-rustfix
 
+#![feature(closure_lifetime_binder)]
 #![warn(clippy::explicit_auto_deref)]
 #![allow(
     dead_code,
@@ -67,6 +68,8 @@ fn main() {
     let s = String::new();
 
     let _: &str = &*s;
+    let _: &str = &*{ String::new() };
+    let _: &str = &mut *{ String::new() };
     let _ = &*s; // Don't lint. Inferred type would change.
     let _: &_ = &*s; // Don't lint. Inferred type would change.
 
@@ -215,4 +218,52 @@ fn main() {
     let s = &"str";
     let _ = || return *s;
     let _ = || -> &'static str { return *s };
+
+    struct X;
+    struct Y(X);
+    impl core::ops::Deref for Y {
+        type Target = X;
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+    let _: &X = &*{ Y(X) };
+    let _: &X = &*match 0 {
+        #[rustfmt::skip]
+        0 => { Y(X) },
+        _ => panic!(),
+    };
+    let _: &X = &*if true { Y(X) } else { panic!() };
+
+    fn deref_to_u<U, T: core::ops::Deref<Target = U>>(x: &T) -> &U {
+        &**x
+    }
+
+    let _ = |x: &'static Box<dyn Iterator<Item = u32>>| -> &'static dyn Iterator<Item = u32> { &**x };
+    fn ret_any(x: &Box<dyn std::any::Any>) -> &dyn std::any::Any {
+        &**x
+    }
+
+    let x = String::new();
+    let _: *const str = &*x;
+
+    struct S7([u32; 1]);
+    impl core::ops::Deref for S7 {
+        type Target = [u32; 1];
+        fn deref(&self) -> &Self::Target {
+            &self.0
+        }
+    }
+    let x = S7([0]);
+    let _: &[u32] = &*x;
+
+    let c1 = |_: &Vec<&u32>| {};
+    let x = &&vec![&1u32];
+    c1(*x);
+    let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> {
+        if b {
+            return *x;
+        }
+        *x
+    };
 }
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
index 92765307ea7..91863abcc5d 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr
@@ -1,202 +1,238 @@
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:69:20
+  --> $DIR/explicit_auto_deref.rs:70:19
    |
 LL |     let _: &str = &*s;
-   |                    ^^ help: try this: `s`
+   |                   ^^^ help: try this: `&s`
    |
    = note: `-D clippy::explicit-auto-deref` implied by `-D warnings`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:73:12
+  --> $DIR/explicit_auto_deref.rs:71:19
+   |
+LL |     let _: &str = &*{ String::new() };
+   |                   ^^^^^^^^^^^^^^^^^^^ help: try this: `&{ String::new() }`
+
+error: deref which would be done by auto-deref
+  --> $DIR/explicit_auto_deref.rs:72:19
+   |
+LL |     let _: &str = &mut *{ String::new() };
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut { String::new() }`
+
+error: deref which would be done by auto-deref
+  --> $DIR/explicit_auto_deref.rs:76:11
    |
 LL |     f_str(&*s);
-   |            ^^ help: try this: `s`
+   |           ^^^ help: try this: `&s`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:77:14
+  --> $DIR/explicit_auto_deref.rs:80:13
    |
 LL |     f_str_t(&*s, &*s); // Don't lint second param.
-   |              ^^ help: try this: `s`
+   |             ^^^ help: try this: `&s`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:80:25
+  --> $DIR/explicit_auto_deref.rs:83:24
    |
 LL |     let _: &Box<i32> = &**b;
-   |                         ^^^ help: try this: `b`
+   |                        ^^^^ help: try this: `&b`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:86:8
+  --> $DIR/explicit_auto_deref.rs:89:7
    |
 LL |     c(&*s);
-   |        ^^ help: try this: `s`
+   |       ^^^ help: try this: `&s`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:92:9
+  --> $DIR/explicit_auto_deref.rs:95:9
    |
 LL |         &**x
    |         ^^^^ help: try this: `x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:96:11
+  --> $DIR/explicit_auto_deref.rs:99:11
    |
 LL |         { &**x }
    |           ^^^^ help: try this: `x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:100:9
+  --> $DIR/explicit_auto_deref.rs:103:9
    |
 LL |         &**{ x }
    |         ^^^^^^^^ help: try this: `{ x }`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:104:9
+  --> $DIR/explicit_auto_deref.rs:107:9
    |
 LL |         &***x
    |         ^^^^^ help: try this: `x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:121:13
+  --> $DIR/explicit_auto_deref.rs:124:12
    |
 LL |         f1(&*x);
-   |             ^^ help: try this: `x`
+   |            ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:122:13
+  --> $DIR/explicit_auto_deref.rs:125:12
    |
 LL |         f2(&*x);
-   |             ^^ help: try this: `x`
+   |            ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:123:13
+  --> $DIR/explicit_auto_deref.rs:126:12
    |
 LL |         f3(&*x);
-   |             ^^ help: try this: `x`
+   |            ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:124:28
+  --> $DIR/explicit_auto_deref.rs:127:27
    |
 LL |         f4.callable_str()(&*x);
-   |                            ^^ help: try this: `x`
+   |                           ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:125:13
+  --> $DIR/explicit_auto_deref.rs:128:12
    |
 LL |         f5(&*x);
-   |             ^^ help: try this: `x`
+   |            ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:126:13
+  --> $DIR/explicit_auto_deref.rs:129:12
    |
 LL |         f6(&*x);
-   |             ^^ help: try this: `x`
+   |            ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:127:28
+  --> $DIR/explicit_auto_deref.rs:130:27
    |
 LL |         f7.callable_str()(&*x);
-   |                            ^^ help: try this: `x`
+   |                           ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:128:26
+  --> $DIR/explicit_auto_deref.rs:131:25
    |
 LL |         f8.callable_t()(&*x);
-   |                          ^^ help: try this: `x`
+   |                         ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:129:13
+  --> $DIR/explicit_auto_deref.rs:132:12
    |
 LL |         f9(&*x);
-   |             ^^ help: try this: `x`
+   |            ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:130:14
+  --> $DIR/explicit_auto_deref.rs:133:13
    |
 LL |         f10(&*x);
-   |              ^^ help: try this: `x`
+   |             ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:131:27
+  --> $DIR/explicit_auto_deref.rs:134:26
    |
 LL |         f11.callable_t()(&*x);
-   |                           ^^ help: try this: `x`
+   |                          ^^^ help: try this: `&x`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:135:17
+  --> $DIR/explicit_auto_deref.rs:138:16
    |
 LL |     let _ = S1(&*s);
-   |                 ^^ help: try this: `s`
+   |                ^^^ help: try this: `&s`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:140:22
+  --> $DIR/explicit_auto_deref.rs:143:21
    |
 LL |     let _ = S2 { s: &*s };
-   |                      ^^ help: try this: `s`
+   |                     ^^^ help: try this: `&s`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:156:30
+  --> $DIR/explicit_auto_deref.rs:159:30
    |
 LL |             let _ = Self::S1(&**s);
    |                              ^^^^ help: try this: `s`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:157:35
+  --> $DIR/explicit_auto_deref.rs:160:35
    |
 LL |             let _ = Self::S2 { s: &**s };
    |                                   ^^^^ help: try this: `s`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:160:21
+  --> $DIR/explicit_auto_deref.rs:163:20
    |
 LL |     let _ = E1::S1(&*s);
-   |                     ^^ help: try this: `s`
+   |                    ^^^ help: try this: `&s`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:161:26
+  --> $DIR/explicit_auto_deref.rs:164:25
    |
 LL |     let _ = E1::S2 { s: &*s };
-   |                          ^^ help: try this: `s`
+   |                         ^^^ help: try this: `&s`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:179:13
+  --> $DIR/explicit_auto_deref.rs:182:13
    |
 LL |     let _ = (*b).foo;
    |             ^^^^ help: try this: `b`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:180:13
+  --> $DIR/explicit_auto_deref.rs:183:13
    |
 LL |     let _ = (**b).foo;
    |             ^^^^^ help: try this: `b`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:195:19
+  --> $DIR/explicit_auto_deref.rs:198:19
    |
 LL |     let _ = f_str(*ref_str);
    |                   ^^^^^^^^ help: try this: `ref_str`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:197:19
+  --> $DIR/explicit_auto_deref.rs:200:19
    |
 LL |     let _ = f_str(**ref_ref_str);
    |                   ^^^^^^^^^^^^^ help: try this: `ref_ref_str`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:207:13
+  --> $DIR/explicit_auto_deref.rs:210:13
    |
 LL |     f_str(&&*ref_str); // `needless_borrow` will suggest removing both references
    |             ^^^^^^^^ help: try this: `ref_str`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:208:12
+  --> $DIR/explicit_auto_deref.rs:211:12
    |
 LL |     f_str(&&**ref_str); // `needless_borrow` will suggest removing only one reference
    |            ^^^^^^^^^^ help: try this: `ref_str`
 
 error: deref which would be done by auto-deref
-  --> $DIR/explicit_auto_deref.rs:217:41
+  --> $DIR/explicit_auto_deref.rs:220:41
    |
 LL |     let _ = || -> &'static str { return *s };
    |                                         ^^ help: try this: `s`
 
-error: aborting due to 33 previous errors
+error: deref which would be done by auto-deref
+  --> $DIR/explicit_auto_deref.rs:239:9
+   |
+LL |         &**x
+   |         ^^^^ help: try this: `x`
+
+error: deref which would be done by auto-deref
+  --> $DIR/explicit_auto_deref.rs:262:8
+   |
+LL |     c1(*x);
+   |        ^^ help: try this: `x`
+
+error: deref which would be done by auto-deref
+  --> $DIR/explicit_auto_deref.rs:265:20
+   |
+LL |             return *x;
+   |                    ^^ help: try this: `x`
+
+error: deref which would be done by auto-deref
+  --> $DIR/explicit_auto_deref.rs:267:9
+   |
+LL |         *x
+   |         ^^ help: try this: `x`
+
+error: aborting due to 39 previous errors
 
diff --git a/src/tools/clippy/tests/ui/if_same_then_else.rs b/src/tools/clippy/tests/ui/if_same_then_else.rs
index 2598c2ab426..07d2002eb27 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else.rs
+++ b/src/tools/clippy/tests/ui/if_same_then_else.rs
@@ -1,6 +1,6 @@
 #![warn(clippy::if_same_then_else)]
 #![allow(
-    clippy::blacklisted_name,
+    clippy::disallowed_names,
     clippy::eq_op,
     clippy::never_loop,
     clippy::no_effect,
diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.rs b/src/tools/clippy/tests/ui/if_same_then_else2.rs
index 0016009a02f..58167f4446d 100644
--- a/src/tools/clippy/tests/ui/if_same_then_else2.rs
+++ b/src/tools/clippy/tests/ui/if_same_then_else2.rs
@@ -1,6 +1,6 @@
 #![warn(clippy::if_same_then_else)]
 #![allow(
-    clippy::blacklisted_name,
+    clippy::disallowed_names,
     clippy::collapsible_else_if,
     clippy::equatable_if_let,
     clippy::collapsible_if,
diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.rs b/src/tools/clippy/tests/ui/ifs_same_cond.rs
index 80e9839ff40..9850fc0919e 100644
--- a/src/tools/clippy/tests/ui/ifs_same_cond.rs
+++ b/src/tools/clippy/tests/ui/ifs_same_cond.rs
@@ -32,9 +32,9 @@ fn ifs_same_cond() {
     };
 
     let mut v = vec![1];
-    if v.pop() == None {
+    if v.pop().is_none() {
         // ok, functions
-    } else if v.pop() == None {
+    } else if v.pop().is_none() {
     }
 
     if v.len() == 42 {
diff --git a/src/tools/clippy/tests/ui/iter_skip_next.fixed b/src/tools/clippy/tests/ui/iter_skip_next.fixed
index 2db4c2bee7f..d56d623b526 100644
--- a/src/tools/clippy/tests/ui/iter_skip_next.fixed
+++ b/src/tools/clippy/tests/ui/iter_skip_next.fixed
@@ -2,7 +2,7 @@
 // aux-build:option_helpers.rs
 
 #![warn(clippy::iter_skip_next)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
 #![allow(clippy::iter_nth)]
 #![allow(unused_mut, dead_code)]
 
diff --git a/src/tools/clippy/tests/ui/iter_skip_next.rs b/src/tools/clippy/tests/ui/iter_skip_next.rs
index 692edb9aed9..3ec5d1b8214 100644
--- a/src/tools/clippy/tests/ui/iter_skip_next.rs
+++ b/src/tools/clippy/tests/ui/iter_skip_next.rs
@@ -2,7 +2,7 @@
 // aux-build:option_helpers.rs
 
 #![warn(clippy::iter_skip_next)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
 #![allow(clippy::iter_nth)]
 #![allow(unused_mut, dead_code)]
 
diff --git a/src/tools/clippy/tests/ui/let_if_seq.rs b/src/tools/clippy/tests/ui/let_if_seq.rs
index c5cb2eb1fe1..959567f6867 100644
--- a/src/tools/clippy/tests/ui/let_if_seq.rs
+++ b/src/tools/clippy/tests/ui/let_if_seq.rs
@@ -2,7 +2,7 @@
     unused_variables,
     unused_assignments,
     clippy::similar_names,
-    clippy::blacklisted_name,
+    clippy::disallowed_names,
     clippy::branches_sharing_code,
     clippy::needless_late_init
 )]
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
index d0bc640db88..65598f1eacc 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
@@ -17,7 +17,7 @@ fn main() {
     let c = Some(2);
     if !a.is_empty()
         && a.len() == 3
-        && c != None
+        && c.is_some()
         && !a.is_empty()
         && a.len() == 3
         && !a.is_empty()
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
index d0bc640db88..65598f1eacc 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed
@@ -17,7 +17,7 @@ fn main() {
     let c = Some(2);
     if !a.is_empty()
         && a.len() == 3
-        && c != None
+        && c.is_some()
         && !a.is_empty()
         && a.len() == 3
         && !a.is_empty()
diff --git a/src/tools/clippy/tests/ui/manual_assert.fixed b/src/tools/clippy/tests/ui/manual_assert.fixed
index 6c2a25c37d8..a2393674fe6 100644
--- a/src/tools/clippy/tests/ui/manual_assert.fixed
+++ b/src/tools/clippy/tests/ui/manual_assert.fixed
@@ -11,7 +11,7 @@ fn main() {
     let c = Some(2);
     if !a.is_empty()
         && a.len() == 3
-        && c != None
+        && c.is_some()
         && !a.is_empty()
         && a.len() == 3
         && !a.is_empty()
diff --git a/src/tools/clippy/tests/ui/manual_assert.rs b/src/tools/clippy/tests/ui/manual_assert.rs
index 027747d8386..4d2706dd621 100644
--- a/src/tools/clippy/tests/ui/manual_assert.rs
+++ b/src/tools/clippy/tests/ui/manual_assert.rs
@@ -17,7 +17,7 @@ fn main() {
     let c = Some(2);
     if !a.is_empty()
         && a.len() == 3
-        && c != None
+        && c.is_some()
         && !a.is_empty()
         && a.len() == 3
         && !a.is_empty()
diff --git a/src/tools/clippy/tests/ui/manual_instant_elapsed.fixed b/src/tools/clippy/tests/ui/manual_instant_elapsed.fixed
new file mode 100644
index 00000000000..0fa776b7b2e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_instant_elapsed.fixed
@@ -0,0 +1,27 @@
+// run-rustfix
+#![warn(clippy::manual_instant_elapsed)]
+#![allow(clippy::unnecessary_operation)]
+#![allow(unused_variables)]
+#![allow(unused_must_use)]
+
+use std::time::Instant;
+
+fn main() {
+    let prev_instant = Instant::now();
+
+    {
+        // don't influence
+        let another_instant = Instant::now();
+    }
+
+    let duration = prev_instant.elapsed();
+
+    // don't catch
+    let duration = prev_instant.elapsed();
+
+    Instant::now() - duration;
+
+    let ref_to_instant = &Instant::now();
+
+    (*ref_to_instant).elapsed(); // to ensure parens are added correctly
+}
diff --git a/src/tools/clippy/tests/ui/manual_instant_elapsed.rs b/src/tools/clippy/tests/ui/manual_instant_elapsed.rs
new file mode 100644
index 00000000000..5b11b84535d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_instant_elapsed.rs
@@ -0,0 +1,27 @@
+// run-rustfix
+#![warn(clippy::manual_instant_elapsed)]
+#![allow(clippy::unnecessary_operation)]
+#![allow(unused_variables)]
+#![allow(unused_must_use)]
+
+use std::time::Instant;
+
+fn main() {
+    let prev_instant = Instant::now();
+
+    {
+        // don't influence
+        let another_instant = Instant::now();
+    }
+
+    let duration = Instant::now() - prev_instant;
+
+    // don't catch
+    let duration = prev_instant.elapsed();
+
+    Instant::now() - duration;
+
+    let ref_to_instant = &Instant::now();
+
+    Instant::now() - *ref_to_instant; // to ensure parens are added correctly
+}
diff --git a/src/tools/clippy/tests/ui/manual_instant_elapsed.stderr b/src/tools/clippy/tests/ui/manual_instant_elapsed.stderr
new file mode 100644
index 00000000000..5537f5642a2
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_instant_elapsed.stderr
@@ -0,0 +1,16 @@
+error: manual implementation of `Instant::elapsed`
+  --> $DIR/manual_instant_elapsed.rs:17:20
+   |
+LL |     let duration = Instant::now() - prev_instant;
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `prev_instant.elapsed()`
+   |
+   = note: `-D clippy::manual-instant-elapsed` implied by `-D warnings`
+
+error: manual implementation of `Instant::elapsed`
+  --> $DIR/manual_instant_elapsed.rs:26:5
+   |
+LL |     Instant::now() - *ref_to_instant; // to ensure parens are added correctly
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*ref_to_instant).elapsed()`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_ok_or.fixed b/src/tools/clippy/tests/ui/manual_ok_or.fixed
index 887a97d7a01..d864f855453 100644
--- a/src/tools/clippy/tests/ui/manual_ok_or.fixed
+++ b/src/tools/clippy/tests/ui/manual_ok_or.fixed
@@ -1,6 +1,6 @@
 // run-rustfix
 #![warn(clippy::manual_ok_or)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
 #![allow(clippy::redundant_closure)]
 #![allow(dead_code)]
 #![allow(unused_must_use)]
diff --git a/src/tools/clippy/tests/ui/manual_ok_or.rs b/src/tools/clippy/tests/ui/manual_ok_or.rs
index 3c99872f502..6264768460e 100644
--- a/src/tools/clippy/tests/ui/manual_ok_or.rs
+++ b/src/tools/clippy/tests/ui/manual_ok_or.rs
@@ -1,6 +1,6 @@
 // run-rustfix
 #![warn(clippy::manual_ok_or)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
 #![allow(clippy::redundant_closure)]
 #![allow(dead_code)]
 #![allow(unused_must_use)]
diff --git a/src/tools/clippy/tests/ui/match_same_arms2.rs b/src/tools/clippy/tests/ui/match_same_arms2.rs
index 7aba5b447d5..61793e80c98 100644
--- a/src/tools/clippy/tests/ui/match_same_arms2.rs
+++ b/src/tools/clippy/tests/ui/match_same_arms2.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::match_same_arms)]
-#![allow(clippy::blacklisted_name, clippy::diverging_sub_expression)]
+#![allow(clippy::disallowed_names, clippy::diverging_sub_expression)]
 
 fn bar<T>(_: T) {}
 fn foo() -> bool {
diff --git a/src/tools/clippy/tests/ui/methods.rs b/src/tools/clippy/tests/ui/methods.rs
index 1970c2eae53..6f22366eab2 100644
--- a/src/tools/clippy/tests/ui/methods.rs
+++ b/src/tools/clippy/tests/ui/methods.rs
@@ -2,7 +2,7 @@
 
 #![warn(clippy::all, clippy::pedantic)]
 #![allow(
-    clippy::blacklisted_name,
+    clippy::disallowed_names,
     clippy::default_trait_access,
     clippy::missing_docs_in_private_items,
     clippy::missing_safety_doc,
diff --git a/src/tools/clippy/tests/ui/mismatching_type_param_order.rs b/src/tools/clippy/tests/ui/mismatching_type_param_order.rs
index 8c0da84d8e9..40c1fcae1fd 100644
--- a/src/tools/clippy/tests/ui/mismatching_type_param_order.rs
+++ b/src/tools/clippy/tests/ui/mismatching_type_param_order.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::mismatching_type_param_order)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
 
 fn main() {
     struct Foo<A, B> {
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
index aa60d0504e5..b950248ef94 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
@@ -3,12 +3,16 @@
 //! The .stderr output of this test should be empty. Otherwise it's a bug somewhere.
 
 // aux-build:helper.rs
+// aux-build:../../auxiliary/proc_macro_with_span.rs
 
 #![warn(clippy::missing_const_for_fn)]
 #![feature(start)]
 #![feature(custom_inner_attributes)]
 
 extern crate helper;
+extern crate proc_macro_with_span;
+
+use proc_macro_with_span::with_span;
 
 struct Game;
 
@@ -119,3 +123,8 @@ mod const_fn_stabilized_after_msrv {
         byte.is_ascii_digit();
     }
 }
+
+with_span! {
+    span
+    fn dont_check_in_proc_macro() {}
+}
diff --git a/src/tools/clippy/tests/ui/missing-doc.rs b/src/tools/clippy/tests/ui/missing_doc.rs
index 6e2e710e21c..29cc026a8fd 100644
--- a/src/tools/clippy/tests/ui/missing-doc.rs
+++ b/src/tools/clippy/tests/ui/missing_doc.rs
@@ -1,3 +1,5 @@
+// aux-build: proc_macro_with_span.rs
+
 #![warn(clippy::missing_docs_in_private_items)]
 // When denying at the crate level, be sure to not get random warnings from the
 // injected intrinsics by the compiler.
@@ -5,6 +7,9 @@
 //! Some garbage docs for the crate here
 #![doc = "More garbage"]
 
+extern crate proc_macro_with_span;
+
+use proc_macro_with_span::with_span;
 use std::arch::global_asm;
 
 type Typedef = String;
@@ -100,3 +105,11 @@ fn main() {}
 
 // Ensure global asm doesn't require documentation.
 global_asm! { "" }
+
+// Don't lint proc macro output with an unexpected span.
+with_span!(span pub struct FooPm { pub field: u32});
+with_span!(span pub struct FooPm2;);
+with_span!(span pub enum FooPm3 { A, B(u32), C { field: u32 }});
+with_span!(span pub fn foo_pm() {});
+with_span!(span pub static FOO_PM: u32 = 0;);
+with_span!(span pub const FOO2_PM: u32 = 0;);
diff --git a/src/tools/clippy/tests/ui/missing-doc.stderr b/src/tools/clippy/tests/ui/missing_doc.stderr
index a876dc078eb..6c8e66f4643 100644
--- a/src/tools/clippy/tests/ui/missing-doc.stderr
+++ b/src/tools/clippy/tests/ui/missing_doc.stderr
@@ -1,5 +1,5 @@
 error: missing documentation for a type alias
-  --> $DIR/missing-doc.rs:10:1
+  --> $DIR/missing_doc.rs:15:1
    |
 LL | type Typedef = String;
    | ^^^^^^^^^^^^^^^^^^^^^^
@@ -7,37 +7,37 @@ LL | type Typedef = String;
    = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
 
 error: missing documentation for a type alias
-  --> $DIR/missing-doc.rs:11:1
+  --> $DIR/missing_doc.rs:16:1
    |
 LL | pub type PubTypedef = String;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a module
-  --> $DIR/missing-doc.rs:13:1
+  --> $DIR/missing_doc.rs:18:1
    |
 LL | mod module_no_dox {}
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a module
-  --> $DIR/missing-doc.rs:14:1
+  --> $DIR/missing_doc.rs:19:1
    |
 LL | pub mod pub_module_no_dox {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:18:1
+  --> $DIR/missing_doc.rs:23:1
    |
 LL | pub fn foo2() {}
    | ^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:19:1
+  --> $DIR/missing_doc.rs:24:1
    |
 LL | fn foo3() {}
    | ^^^^^^^^^^^^
 
 error: missing documentation for an enum
-  --> $DIR/missing-doc.rs:33:1
+  --> $DIR/missing_doc.rs:38:1
    |
 LL | / enum Baz {
 LL | |     BazA { a: isize, b: isize },
@@ -46,31 +46,31 @@ LL | | }
    | |_^
 
 error: missing documentation for a variant
-  --> $DIR/missing-doc.rs:34:5
+  --> $DIR/missing_doc.rs:39:5
    |
 LL |     BazA { a: isize, b: isize },
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc.rs:34:12
+  --> $DIR/missing_doc.rs:39:12
    |
 LL |     BazA { a: isize, b: isize },
    |            ^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc.rs:34:22
+  --> $DIR/missing_doc.rs:39:22
    |
 LL |     BazA { a: isize, b: isize },
    |                      ^^^^^^^^
 
 error: missing documentation for a variant
-  --> $DIR/missing-doc.rs:35:5
+  --> $DIR/missing_doc.rs:40:5
    |
 LL |     BarB,
    |     ^^^^
 
 error: missing documentation for an enum
-  --> $DIR/missing-doc.rs:38:1
+  --> $DIR/missing_doc.rs:43:1
    |
 LL | / pub enum PubBaz {
 LL | |     PubBazA { a: isize },
@@ -78,43 +78,43 @@ LL | | }
    | |_^
 
 error: missing documentation for a variant
-  --> $DIR/missing-doc.rs:39:5
+  --> $DIR/missing_doc.rs:44:5
    |
 LL |     PubBazA { a: isize },
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc.rs:39:15
+  --> $DIR/missing_doc.rs:44:15
    |
 LL |     PubBazA { a: isize },
    |               ^^^^^^^^
 
 error: missing documentation for a constant
-  --> $DIR/missing-doc.rs:59:1
+  --> $DIR/missing_doc.rs:64:1
    |
 LL | const FOO: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a constant
-  --> $DIR/missing-doc.rs:66:1
+  --> $DIR/missing_doc.rs:71:1
    |
 LL | pub const FOO4: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a static
-  --> $DIR/missing-doc.rs:68:1
+  --> $DIR/missing_doc.rs:73:1
    |
 LL | static BAR: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a static
-  --> $DIR/missing-doc.rs:75:1
+  --> $DIR/missing_doc.rs:80:1
    |
 LL | pub static BAR4: u32 = 0;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a module
-  --> $DIR/missing-doc.rs:77:1
+  --> $DIR/missing_doc.rs:82:1
    |
 LL | / mod internal_impl {
 LL | |     /// dox
@@ -126,31 +126,31 @@ LL | | }
    | |_^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:80:5
+  --> $DIR/missing_doc.rs:85:5
    |
 LL |     pub fn undocumented1() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:81:5
+  --> $DIR/missing_doc.rs:86:5
    |
 LL |     pub fn undocumented2() {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:82:5
+  --> $DIR/missing_doc.rs:87:5
    |
 LL |     fn undocumented3() {}
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:87:9
+  --> $DIR/missing_doc.rs:92:9
    |
 LL |         pub fn also_undocumented1() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for a function
-  --> $DIR/missing-doc.rs:88:9
+  --> $DIR/missing_doc.rs:93:9
    |
 LL |         fn also_undocumented2() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/missing-doc-crate.rs b/src/tools/clippy/tests/ui/missing_doc_crate.rs
index e00c7fbfed1..e00c7fbfed1 100644
--- a/src/tools/clippy/tests/ui/missing-doc-crate.rs
+++ b/src/tools/clippy/tests/ui/missing_doc_crate.rs
diff --git a/src/tools/clippy/tests/ui/missing-doc-crate-missing.rs b/src/tools/clippy/tests/ui/missing_doc_crate_missing.rs
index 51fd57df8df..51fd57df8df 100644
--- a/src/tools/clippy/tests/ui/missing-doc-crate-missing.rs
+++ b/src/tools/clippy/tests/ui/missing_doc_crate_missing.rs
diff --git a/src/tools/clippy/tests/ui/missing-doc-crate-missing.stderr b/src/tools/clippy/tests/ui/missing_doc_crate_missing.stderr
index d56c5cc4c3a..19516bf5fab 100644
--- a/src/tools/clippy/tests/ui/missing-doc-crate-missing.stderr
+++ b/src/tools/clippy/tests/ui/missing_doc_crate_missing.stderr
@@ -1,5 +1,5 @@
 error: missing documentation for the crate
-  --> $DIR/missing-doc-crate-missing.rs:1:1
+  --> $DIR/missing_doc_crate_missing.rs:1:1
    |
 LL | / #![warn(clippy::missing_docs_in_private_items)]
 LL | |
diff --git a/src/tools/clippy/tests/ui/missing-doc-impl.rs b/src/tools/clippy/tests/ui/missing_doc_impl.rs
index d5724bf661c..0396d1193ff 100644
--- a/src/tools/clippy/tests/ui/missing-doc-impl.rs
+++ b/src/tools/clippy/tests/ui/missing_doc_impl.rs
@@ -1,3 +1,5 @@
+// aux-build: proc_macro_with_span.rs
+
 #![warn(clippy::missing_docs_in_private_items)]
 #![allow(dead_code)]
 #![feature(associated_type_defaults)]
@@ -5,6 +7,9 @@
 //! Some garbage docs for the crate here
 #![doc = "More garbage"]
 
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
+
 struct Foo {
     a: isize,
     b: isize,
@@ -90,3 +95,13 @@ impl F for Foo {
 }
 
 fn main() {}
+
+// don't lint proc macro output
+with_span!(span
+    pub struct FooPm;
+    impl FooPm {
+        pub fn foo() {}
+        pub const fn bar() {}
+        pub const X: u32 = 0;
+    }
+);
diff --git a/src/tools/clippy/tests/ui/missing-doc-impl.stderr b/src/tools/clippy/tests/ui/missing_doc_impl.stderr
index bda63d66a17..f22fa19dbca 100644
--- a/src/tools/clippy/tests/ui/missing-doc-impl.stderr
+++ b/src/tools/clippy/tests/ui/missing_doc_impl.stderr
@@ -1,5 +1,5 @@
 error: missing documentation for a struct
-  --> $DIR/missing-doc-impl.rs:8:1
+  --> $DIR/missing_doc_impl.rs:13:1
    |
 LL | / struct Foo {
 LL | |     a: isize,
@@ -10,19 +10,19 @@ LL | | }
    = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings`
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc-impl.rs:9:5
+  --> $DIR/missing_doc_impl.rs:14:5
    |
 LL |     a: isize,
    |     ^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc-impl.rs:10:5
+  --> $DIR/missing_doc_impl.rs:15:5
    |
 LL |     b: isize,
    |     ^^^^^^^^
 
 error: missing documentation for a struct
-  --> $DIR/missing-doc-impl.rs:13:1
+  --> $DIR/missing_doc_impl.rs:18:1
    |
 LL | / pub struct PubFoo {
 LL | |     pub a: isize,
@@ -31,19 +31,19 @@ LL | | }
    | |_^
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc-impl.rs:14:5
+  --> $DIR/missing_doc_impl.rs:19:5
    |
 LL |     pub a: isize,
    |     ^^^^^^^^^^^^
 
 error: missing documentation for a struct field
-  --> $DIR/missing-doc-impl.rs:15:5
+  --> $DIR/missing_doc_impl.rs:20:5
    |
 LL |     b: isize,
    |     ^^^^^^^^
 
 error: missing documentation for a trait
-  --> $DIR/missing-doc-impl.rs:38:1
+  --> $DIR/missing_doc_impl.rs:43:1
    |
 LL | / pub trait C {
 LL | |     fn foo(&self);
@@ -52,31 +52,31 @@ LL | | }
    | |_^
 
 error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:39:5
+  --> $DIR/missing_doc_impl.rs:44:5
    |
 LL |     fn foo(&self);
    |     ^^^^^^^^^^^^^^
 
 error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:40:5
+  --> $DIR/missing_doc_impl.rs:45:5
    |
 LL |     fn foo_with_impl(&self) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for an associated type
-  --> $DIR/missing-doc-impl.rs:50:5
+  --> $DIR/missing_doc_impl.rs:55:5
    |
 LL |     type AssociatedType;
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for an associated type
-  --> $DIR/missing-doc-impl.rs:51:5
+  --> $DIR/missing_doc_impl.rs:56:5
    |
 LL |     type AssociatedTypeDef = Self;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:62:5
+  --> $DIR/missing_doc_impl.rs:67:5
    |
 LL | /     pub fn new() -> Self {
 LL | |         Foo { a: 0, b: 0 }
@@ -84,19 +84,19 @@ LL | |     }
    | |_____^
 
 error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:65:5
+  --> $DIR/missing_doc_impl.rs:70:5
    |
 LL |     fn bar() {}
    |     ^^^^^^^^^^^
 
 error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:69:5
+  --> $DIR/missing_doc_impl.rs:74:5
    |
 LL |     pub fn foo() {}
    |     ^^^^^^^^^^^^^^^
 
 error: missing documentation for an associated function
-  --> $DIR/missing-doc-impl.rs:73:5
+  --> $DIR/missing_doc_impl.rs:78:5
    |
 LL | /     fn foo2() -> u32 {
 LL | |         1
diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed
index a7b36d53cd2..becb9562a84 100644
--- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed
+++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed
@@ -1,4 +1,5 @@
 // run-rustfix
+// aux-build: proc_macro_with_span.rs
 
 #![allow(
     dead_code,
@@ -9,6 +10,9 @@
     clippy::unusual_byte_groupings
 )]
 
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
+
 fn main() {
     let fail14 = 2_i32;
     let fail15 = 4_i64;
@@ -40,4 +44,6 @@ fn main() {
     let ok38 = 124_64.0;
 
     let _ = 1.123_45E1_f32;
+
+    let _ = with_span!(1 2_u32);
 }
diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs
index c97b31965c7..ee841bcd7e4 100644
--- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs
+++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs
@@ -1,4 +1,5 @@
 // run-rustfix
+// aux-build: proc_macro_with_span.rs
 
 #![allow(
     dead_code,
@@ -9,6 +10,9 @@
     clippy::unusual_byte_groupings
 )]
 
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
+
 fn main() {
     let fail14 = 2_32;
     let fail15 = 4_64;
@@ -40,4 +44,6 @@ fn main() {
     let ok38 = 124_64.0;
 
     let _ = 1.12345E1_32;
+
+    let _ = with_span!(1 2_u32);
 }
diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr b/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr
index fb761d9bde4..ef8e6a33d28 100644
--- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr
+++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr
@@ -1,5 +1,5 @@
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:13:18
+  --> $DIR/mistyped_literal_suffix.rs:17:18
    |
 LL |     let fail14 = 2_32;
    |                  ^^^^ help: did you mean to write: `2_i32`
@@ -7,91 +7,91 @@ LL |     let fail14 = 2_32;
    = note: `#[deny(clippy::mistyped_literal_suffixes)]` on by default
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:14:18
+  --> $DIR/mistyped_literal_suffix.rs:18:18
    |
 LL |     let fail15 = 4_64;
    |                  ^^^^ help: did you mean to write: `4_i64`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:15:18
+  --> $DIR/mistyped_literal_suffix.rs:19:18
    |
 LL |     let fail16 = 7_8; //
    |                  ^^^ help: did you mean to write: `7_i8`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:16:18
+  --> $DIR/mistyped_literal_suffix.rs:20:18
    |
 LL |     let fail17 = 23_16; //
    |                  ^^^^^ help: did you mean to write: `23_i16`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:19:18
+  --> $DIR/mistyped_literal_suffix.rs:23:18
    |
 LL |     let fail20 = 2__8; //
    |                  ^^^^ help: did you mean to write: `2_i8`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:20:18
+  --> $DIR/mistyped_literal_suffix.rs:24:18
    |
 LL |     let fail21 = 4___16; //
    |                  ^^^^^^ help: did you mean to write: `4_i16`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:23:18
+  --> $DIR/mistyped_literal_suffix.rs:27:18
    |
 LL |     let fail25 = 1E2_32;
    |                  ^^^^^^ help: did you mean to write: `1E2_f32`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:24:18
+  --> $DIR/mistyped_literal_suffix.rs:28:18
    |
 LL |     let fail26 = 43E7_64;
    |                  ^^^^^^^ help: did you mean to write: `43E7_f64`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:25:18
+  --> $DIR/mistyped_literal_suffix.rs:29:18
    |
 LL |     let fail27 = 243E17_32;
    |                  ^^^^^^^^^ help: did you mean to write: `243E17_f32`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:26:18
+  --> $DIR/mistyped_literal_suffix.rs:30:18
    |
 LL |     let fail28 = 241251235E723_64;
    |                  ^^^^^^^^^^^^^^^^ help: did you mean to write: `241_251_235E723_f64`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:30:18
+  --> $DIR/mistyped_literal_suffix.rs:34:18
    |
 LL |     let fail30 = 127_8; // should be i8
    |                  ^^^^^ help: did you mean to write: `127_i8`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:31:18
+  --> $DIR/mistyped_literal_suffix.rs:35:18
    |
 LL |     let fail31 = 240_8; // should be u8
    |                  ^^^^^ help: did you mean to write: `240_u8`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:33:18
+  --> $DIR/mistyped_literal_suffix.rs:37:18
    |
 LL |     let fail33 = 0x1234_16;
    |                  ^^^^^^^^^ help: did you mean to write: `0x1234_i16`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:34:18
+  --> $DIR/mistyped_literal_suffix.rs:38:18
    |
 LL |     let fail34 = 0xABCD_16;
    |                  ^^^^^^^^^ help: did you mean to write: `0xABCD_u16`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:36:18
+  --> $DIR/mistyped_literal_suffix.rs:40:18
    |
 LL |     let fail36 = 0xFFFF_FFFF_FFFF_FFFF_64; // u64
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to write: `0xFFFF_FFFF_FFFF_FFFF_u64`
 
 error: mistyped literal suffix
-  --> $DIR/mistyped_literal_suffix.rs:42:13
+  --> $DIR/mistyped_literal_suffix.rs:46:13
    |
 LL |     let _ = 1.12345E1_32;
    |             ^^^^^^^^^^^^ help: did you mean to write: `1.123_45E1_f32`
diff --git a/src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs b/src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs
index 7640057ab6e..6efc7657ec0 100644
--- a/src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs
@@ -4,7 +4,7 @@
     unused_variables,
     clippy::no_effect,
     dead_code,
-    clippy::blacklisted_name
+    clippy::disallowed_names
 )]
 fn main() {
     let mut x = 0;
diff --git a/src/tools/clippy/tests/ui/op_ref.rs b/src/tools/clippy/tests/ui/op_ref.rs
index d8bf66603d9..07226b0a1a8 100644
--- a/src/tools/clippy/tests/ui/op_ref.rs
+++ b/src/tools/clippy/tests/ui/op_ref.rs
@@ -1,4 +1,4 @@
-#![allow(unused_variables, clippy::blacklisted_name)]
+#![allow(unused_variables, clippy::disallowed_names)]
 #![warn(clippy::op_ref)]
 use std::collections::HashSet;
 use std::ops::{BitAnd, Mul};
diff --git a/src/tools/clippy/tests/ui/logic_bug.rs b/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs
index dd6b1db5f70..04a30a83250 100644
--- a/src/tools/clippy/tests/ui/logic_bug.rs
+++ b/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs
@@ -1,6 +1,6 @@
 #![feature(lint_reasons)]
 #![allow(unused, clippy::diverging_sub_expression)]
-#![warn(clippy::logic_bug)]
+#![warn(clippy::overly_complex_bool_expr)]
 
 fn main() {
     let a: bool = unimplemented!();
@@ -29,6 +29,6 @@ fn equality_stuff() {
 fn check_expect() {
     let a: i32 = unimplemented!();
     let b: i32 = unimplemented!();
-    #[expect(clippy::logic_bug)]
+    #[expect(clippy::overly_complex_bool_expr)]
     let _ = a < b && a >= b;
 }
diff --git a/src/tools/clippy/tests/ui/logic_bug.stderr b/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr
index 4021fbf4570..158cae8b8f3 100644
--- a/src/tools/clippy/tests/ui/logic_bug.stderr
+++ b/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr
@@ -1,60 +1,60 @@
 error: this boolean expression contains a logic bug
-  --> $DIR/logic_bug.rs:11:13
+  --> $DIR/overly_complex_bool_expr.rs:11:13
    |
 LL |     let _ = a && b || a;
    |             ^^^^^^^^^^^ help: it would look like the following: `a`
    |
-   = note: `-D clippy::logic-bug` implied by `-D warnings`
+   = note: `-D clippy::overly-complex-bool-expr` implied by `-D warnings`
 help: this expression can be optimized out by applying boolean operations to the outer expression
-  --> $DIR/logic_bug.rs:11:18
+  --> $DIR/overly_complex_bool_expr.rs:11:18
    |
 LL |     let _ = a && b || a;
    |                  ^
 
 error: this boolean expression contains a logic bug
-  --> $DIR/logic_bug.rs:13:13
+  --> $DIR/overly_complex_bool_expr.rs:13:13
    |
 LL |     let _ = false && a;
    |             ^^^^^^^^^^ help: it would look like the following: `false`
    |
 help: this expression can be optimized out by applying boolean operations to the outer expression
-  --> $DIR/logic_bug.rs:13:22
+  --> $DIR/overly_complex_bool_expr.rs:13:22
    |
 LL |     let _ = false && a;
    |                      ^
 
 error: this boolean expression contains a logic bug
-  --> $DIR/logic_bug.rs:23:13
+  --> $DIR/overly_complex_bool_expr.rs:23:13
    |
 LL |     let _ = a == b && a != b;
    |             ^^^^^^^^^^^^^^^^ help: it would look like the following: `false`
    |
 help: this expression can be optimized out by applying boolean operations to the outer expression
-  --> $DIR/logic_bug.rs:23:13
+  --> $DIR/overly_complex_bool_expr.rs:23:13
    |
 LL |     let _ = a == b && a != b;
    |             ^^^^^^
 
 error: this boolean expression contains a logic bug
-  --> $DIR/logic_bug.rs:24:13
+  --> $DIR/overly_complex_bool_expr.rs:24:13
    |
 LL |     let _ = a < b && a >= b;
    |             ^^^^^^^^^^^^^^^ help: it would look like the following: `false`
    |
 help: this expression can be optimized out by applying boolean operations to the outer expression
-  --> $DIR/logic_bug.rs:24:13
+  --> $DIR/overly_complex_bool_expr.rs:24:13
    |
 LL |     let _ = a < b && a >= b;
    |             ^^^^^
 
 error: this boolean expression contains a logic bug
-  --> $DIR/logic_bug.rs:25:13
+  --> $DIR/overly_complex_bool_expr.rs:25:13
    |
 LL |     let _ = a > b && a <= b;
    |             ^^^^^^^^^^^^^^^ help: it would look like the following: `false`
    |
 help: this expression can be optimized out by applying boolean operations to the outer expression
-  --> $DIR/logic_bug.rs:25:13
+  --> $DIR/overly_complex_bool_expr.rs:25:13
    |
 LL |     let _ = a > b && a <= b;
    |             ^^^^^
diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.fixed b/src/tools/clippy/tests/ui/partialeq_to_none.fixed
new file mode 100644
index 00000000000..f3e4c58d694
--- /dev/null
+++ b/src/tools/clippy/tests/ui/partialeq_to_none.fixed
@@ -0,0 +1,62 @@
+// run-rustfix
+#![warn(clippy::partialeq_to_none)]
+
+struct Foobar;
+
+impl PartialEq<Option<()>> for Foobar {
+    fn eq(&self, _: &Option<()>) -> bool {
+        false
+    }
+}
+
+#[allow(dead_code)]
+fn foo(f: Option<u32>) -> &'static str {
+    if f.is_some() { "yay" } else { "nay" }
+}
+
+fn foobar() -> Option<()> {
+    None
+}
+
+fn bar() -> Result<(), ()> {
+    Ok(())
+}
+
+fn optref() -> &'static &'static Option<()> {
+    &&None
+}
+
+fn main() {
+    let x = Some(0);
+
+    let _ = x.is_none();
+    let _ = x.is_some();
+    let _ = x.is_none();
+    let _ = x.is_some();
+
+    if foobar().is_none() {}
+
+    if bar().ok().is_some() {}
+
+    let _ = Some(1 + 2).is_some();
+
+    let _ = { Some(0) }.is_none();
+
+    let _ = {
+        /*
+          This comment runs long
+        */
+        Some(1)
+    }.is_some();
+
+    // Should not trigger, as `Foobar` is not an `Option` and has no `is_none`
+    let _ = Foobar == None;
+
+    let _ = optref().is_none();
+    let _ = optref().is_some();
+    let _ = optref().is_none();
+    let _ = optref().is_some();
+
+    let x = Box::new(Option::<()>::None);
+    let _ = (*x).is_some();
+}
diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.rs b/src/tools/clippy/tests/ui/partialeq_to_none.rs
new file mode 100644
index 00000000000..767b2a38bcc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/partialeq_to_none.rs
@@ -0,0 +1,62 @@
+// run-rustfix
+#![warn(clippy::partialeq_to_none)]
+
+struct Foobar;
+
+impl PartialEq<Option<()>> for Foobar {
+    fn eq(&self, _: &Option<()>) -> bool {
+        false
+    }
+}
+
+#[allow(dead_code)]
+fn foo(f: Option<u32>) -> &'static str {
+    if f != None { "yay" } else { "nay" }
+}
+
+fn foobar() -> Option<()> {
+    None
+}
+
+fn bar() -> Result<(), ()> {
+    Ok(())
+}
+
+fn optref() -> &'static &'static Option<()> {
+    &&None
+}
+
+fn main() {
+    let x = Some(0);
+
+    let _ = x == None;
+    let _ = x != None;
+    let _ = None == x;
+    let _ = None != x;
+
+    if foobar() == None {}
+
+    if bar().ok() != None {}
+
+    let _ = Some(1 + 2) != None;
+
+    let _ = { Some(0) } == None;
+
+    let _ = {
+        /*
+          This comment runs long
+        */
+        Some(1)
+    } != None;
+
+    // Should not trigger, as `Foobar` is not an `Option` and has no `is_none`
+    let _ = Foobar == None;
+
+    let _ = optref() == &&None;
+    let _ = &&None != optref();
+    let _ = **optref() == None;
+    let _ = &None != *optref();
+
+    let x = Box::new(Option::<()>::None);
+    let _ = None != *x;
+}
diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.stderr b/src/tools/clippy/tests/ui/partialeq_to_none.stderr
new file mode 100644
index 00000000000..de15a9f7baa
--- /dev/null
+++ b/src/tools/clippy/tests/ui/partialeq_to_none.stderr
@@ -0,0 +1,110 @@
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:14:8
+   |
+LL |     if f != None { "yay" } else { "nay" }
+   |        ^^^^^^^^^ help: use `Option::is_some()` instead: `f.is_some()`
+   |
+   = note: `-D clippy::partialeq-to-none` implied by `-D warnings`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:32:13
+   |
+LL |     let _ = x == None;
+   |             ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:33:13
+   |
+LL |     let _ = x != None;
+   |             ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:34:13
+   |
+LL |     let _ = None == x;
+   |             ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:35:13
+   |
+LL |     let _ = None != x;
+   |             ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:37:8
+   |
+LL |     if foobar() == None {}
+   |        ^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `foobar().is_none()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:39:8
+   |
+LL |     if bar().ok() != None {}
+   |        ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `bar().ok().is_some()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:41:13
+   |
+LL |     let _ = Some(1 + 2) != None;
+   |             ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `Some(1 + 2).is_some()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:43:13
+   |
+LL |     let _ = { Some(0) } == None;
+   |             ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `{ Some(0) }.is_none()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:45:13
+   |
+LL |       let _ = {
+   |  _____________^
+LL | |         /*
+LL | |           This comment runs long
+LL | |         */
+LL | |         Some(1)
+LL | |     } != None;
+   | |_____________^
+   |
+help: use `Option::is_some()` instead
+   |
+LL ~     let _ = {
+LL +         /*
+LL +           This comment runs long
+LL +         */
+LL +         Some(1)
+LL ~     }.is_some();
+   |
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:55:13
+   |
+LL |     let _ = optref() == &&None;
+   |             ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:56:13
+   |
+LL |     let _ = &&None != optref();
+   |             ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:57:13
+   |
+LL |     let _ = **optref() == None;
+   |             ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:58:13
+   |
+LL |     let _ = &None != *optref();
+   |             ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()`
+
+error: binary comparison to literal `Option::None`
+  --> $DIR/partialeq_to_none.rs:61:13
+   |
+LL |     let _ = None != *x;
+   |             ^^^^^^^^^^ help: use `Option::is_some()` instead: `(*x).is_some()`
+
+error: aborting due to 15 previous errors
+
diff --git a/src/tools/clippy/tests/ui/rc_mutex.rs b/src/tools/clippy/tests/ui/rc_mutex.rs
index 18e8a2e01e0..432972bbc31 100644
--- a/src/tools/clippy/tests/ui/rc_mutex.rs
+++ b/src/tools/clippy/tests/ui/rc_mutex.rs
@@ -1,5 +1,5 @@
 #![warn(clippy::rc_mutex)]
-#![allow(unused, clippy::blacklisted_name)]
+#![allow(unused, clippy::disallowed_names)]
 
 use std::rc::Rc;
 use std::sync::Mutex;
diff --git a/src/tools/clippy/tests/ui/redundant_allocation.rs b/src/tools/clippy/tests/ui/redundant_allocation.rs
index cf7d8c6e349..574d34aed2d 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation.rs
+++ b/src/tools/clippy/tests/ui/redundant_allocation.rs
@@ -1,7 +1,5 @@
 #![warn(clippy::all)]
-#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
-#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
-#![allow(unused_imports)]
+#![allow(clippy::boxed_local, clippy::disallowed_names)]
 
 pub struct MyStruct;
 
@@ -9,13 +7,7 @@ pub struct SubT<T> {
     foo: T,
 }
 
-pub enum MyEnum {
-    One,
-    Two,
-}
-
 mod outer_box {
-    use crate::MyEnum;
     use crate::MyStruct;
     use crate::SubT;
     use std::boxed::Box;
@@ -36,7 +28,6 @@ mod outer_box {
 }
 
 mod outer_rc {
-    use crate::MyEnum;
     use crate::MyStruct;
     use crate::SubT;
     use std::boxed::Box;
@@ -57,7 +48,6 @@ mod outer_rc {
 }
 
 mod outer_arc {
-    use crate::MyEnum;
     use crate::MyStruct;
     use crate::SubT;
     use std::boxed::Box;
diff --git a/src/tools/clippy/tests/ui/redundant_allocation.stderr b/src/tools/clippy/tests/ui/redundant_allocation.stderr
index fab1b069fcb..54d4d88dba8 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation.stderr
+++ b/src/tools/clippy/tests/ui/redundant_allocation.stderr
@@ -1,5 +1,5 @@
 error: usage of `Box<Rc<T>>`
-  --> $DIR/redundant_allocation.rs:25:30
+  --> $DIR/redundant_allocation.rs:17:30
    |
 LL |     pub fn box_test6<T>(foo: Box<Rc<T>>) {}
    |                              ^^^^^^^^^^
@@ -9,7 +9,7 @@ LL |     pub fn box_test6<T>(foo: Box<Rc<T>>) {}
    = help: consider using just `Box<T>` or `Rc<T>`
 
 error: usage of `Box<Arc<T>>`
-  --> $DIR/redundant_allocation.rs:27:30
+  --> $DIR/redundant_allocation.rs:19:30
    |
 LL |     pub fn box_test7<T>(foo: Box<Arc<T>>) {}
    |                              ^^^^^^^^^^^
@@ -18,7 +18,7 @@ LL |     pub fn box_test7<T>(foo: Box<Arc<T>>) {}
    = help: consider using just `Box<T>` or `Arc<T>`
 
 error: usage of `Box<Rc<SubT<usize>>>`
-  --> $DIR/redundant_allocation.rs:29:27
+  --> $DIR/redundant_allocation.rs:21:27
    |
 LL |     pub fn box_test8() -> Box<Rc<SubT<usize>>> {
    |                           ^^^^^^^^^^^^^^^^^^^^
@@ -27,7 +27,7 @@ LL |     pub fn box_test8() -> Box<Rc<SubT<usize>>> {
    = help: consider using just `Box<SubT<usize>>` or `Rc<SubT<usize>>`
 
 error: usage of `Box<Arc<T>>`
-  --> $DIR/redundant_allocation.rs:33:30
+  --> $DIR/redundant_allocation.rs:25:30
    |
 LL |     pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
    |                              ^^^^^^^^^^^
@@ -36,7 +36,7 @@ LL |     pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
    = help: consider using just `Box<T>` or `Arc<T>`
 
 error: usage of `Box<Arc<SubT<T>>>`
-  --> $DIR/redundant_allocation.rs:33:46
+  --> $DIR/redundant_allocation.rs:25:46
    |
 LL |     pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
    |                                              ^^^^^^^^^^^^^^^^^
@@ -45,7 +45,7 @@ LL |     pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
    = help: consider using just `Box<SubT<T>>` or `Arc<SubT<T>>`
 
 error: usage of `Rc<Box<bool>>`
-  --> $DIR/redundant_allocation.rs:46:24
+  --> $DIR/redundant_allocation.rs:37:24
    |
 LL |     pub fn rc_test5(a: Rc<Box<bool>>) {}
    |                        ^^^^^^^^^^^^^
@@ -54,7 +54,7 @@ LL |     pub fn rc_test5(a: Rc<Box<bool>>) {}
    = help: consider using just `Rc<bool>` or `Box<bool>`
 
 error: usage of `Rc<Arc<bool>>`
-  --> $DIR/redundant_allocation.rs:48:24
+  --> $DIR/redundant_allocation.rs:39:24
    |
 LL |     pub fn rc_test7(a: Rc<Arc<bool>>) {}
    |                        ^^^^^^^^^^^^^
@@ -63,7 +63,7 @@ LL |     pub fn rc_test7(a: Rc<Arc<bool>>) {}
    = help: consider using just `Rc<bool>` or `Arc<bool>`
 
 error: usage of `Rc<Box<SubT<usize>>>`
-  --> $DIR/redundant_allocation.rs:50:26
+  --> $DIR/redundant_allocation.rs:41:26
    |
 LL |     pub fn rc_test8() -> Rc<Box<SubT<usize>>> {
    |                          ^^^^^^^^^^^^^^^^^^^^
@@ -72,7 +72,7 @@ LL |     pub fn rc_test8() -> Rc<Box<SubT<usize>>> {
    = help: consider using just `Rc<SubT<usize>>` or `Box<SubT<usize>>`
 
 error: usage of `Rc<Arc<T>>`
-  --> $DIR/redundant_allocation.rs:54:29
+  --> $DIR/redundant_allocation.rs:45:29
    |
 LL |     pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
    |                             ^^^^^^^^^^
@@ -81,7 +81,7 @@ LL |     pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
    = help: consider using just `Rc<T>` or `Arc<T>`
 
 error: usage of `Rc<Arc<SubT<T>>>`
-  --> $DIR/redundant_allocation.rs:54:44
+  --> $DIR/redundant_allocation.rs:45:44
    |
 LL |     pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
    |                                            ^^^^^^^^^^^^^^^^
@@ -90,7 +90,7 @@ LL |     pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
    = help: consider using just `Rc<SubT<T>>` or `Arc<SubT<T>>`
 
 error: usage of `Arc<Box<bool>>`
-  --> $DIR/redundant_allocation.rs:67:25
+  --> $DIR/redundant_allocation.rs:57:25
    |
 LL |     pub fn arc_test5(a: Arc<Box<bool>>) {}
    |                         ^^^^^^^^^^^^^^
@@ -99,7 +99,7 @@ LL |     pub fn arc_test5(a: Arc<Box<bool>>) {}
    = help: consider using just `Arc<bool>` or `Box<bool>`
 
 error: usage of `Arc<Rc<bool>>`
-  --> $DIR/redundant_allocation.rs:69:25
+  --> $DIR/redundant_allocation.rs:59:25
    |
 LL |     pub fn arc_test6(a: Arc<Rc<bool>>) {}
    |                         ^^^^^^^^^^^^^
@@ -108,7 +108,7 @@ LL |     pub fn arc_test6(a: Arc<Rc<bool>>) {}
    = help: consider using just `Arc<bool>` or `Rc<bool>`
 
 error: usage of `Arc<Box<SubT<usize>>>`
-  --> $DIR/redundant_allocation.rs:71:27
+  --> $DIR/redundant_allocation.rs:61:27
    |
 LL |     pub fn arc_test8() -> Arc<Box<SubT<usize>>> {
    |                           ^^^^^^^^^^^^^^^^^^^^^
@@ -117,7 +117,7 @@ LL |     pub fn arc_test8() -> Arc<Box<SubT<usize>>> {
    = help: consider using just `Arc<SubT<usize>>` or `Box<SubT<usize>>`
 
 error: usage of `Arc<Rc<T>>`
-  --> $DIR/redundant_allocation.rs:75:30
+  --> $DIR/redundant_allocation.rs:65:30
    |
 LL |     pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
    |                              ^^^^^^^^^^
@@ -126,7 +126,7 @@ LL |     pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
    = help: consider using just `Arc<T>` or `Rc<T>`
 
 error: usage of `Arc<Rc<SubT<T>>>`
-  --> $DIR/redundant_allocation.rs:75:45
+  --> $DIR/redundant_allocation.rs:65:45
    |
 LL |     pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
    |                                             ^^^^^^^^^^^^^^^^
@@ -135,7 +135,7 @@ LL |     pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
    = help: consider using just `Arc<SubT<T>>` or `Rc<SubT<T>>`
 
 error: usage of `Rc<Box<Box<dyn T>>>`
-  --> $DIR/redundant_allocation.rs:97:27
+  --> $DIR/redundant_allocation.rs:87:27
    |
 LL |     pub fn test_rc_box(_: Rc<Box<Box<dyn T>>>) {}
    |                           ^^^^^^^^^^^^^^^^^^^
@@ -144,7 +144,7 @@ LL |     pub fn test_rc_box(_: Rc<Box<Box<dyn T>>>) {}
    = help: consider using just `Rc<Box<dyn T>>` or `Box<Box<dyn T>>`
 
 error: usage of `Rc<Box<Box<str>>>`
-  --> $DIR/redundant_allocation.rs:129:31
+  --> $DIR/redundant_allocation.rs:119:31
    |
 LL |     pub fn test_rc_box_str(_: Rc<Box<Box<str>>>) {}
    |                               ^^^^^^^^^^^^^^^^^
@@ -153,7 +153,7 @@ LL |     pub fn test_rc_box_str(_: Rc<Box<Box<str>>>) {}
    = help: consider using just `Rc<Box<str>>` or `Box<Box<str>>`
 
 error: usage of `Rc<Box<Box<[usize]>>>`
-  --> $DIR/redundant_allocation.rs:130:33
+  --> $DIR/redundant_allocation.rs:120:33
    |
 LL |     pub fn test_rc_box_slice(_: Rc<Box<Box<[usize]>>>) {}
    |                                 ^^^^^^^^^^^^^^^^^^^^^
@@ -162,7 +162,7 @@ LL |     pub fn test_rc_box_slice(_: Rc<Box<Box<[usize]>>>) {}
    = help: consider using just `Rc<Box<[usize]>>` or `Box<Box<[usize]>>`
 
 error: usage of `Rc<Box<Box<Path>>>`
-  --> $DIR/redundant_allocation.rs:131:32
+  --> $DIR/redundant_allocation.rs:121:32
    |
 LL |     pub fn test_rc_box_path(_: Rc<Box<Box<Path>>>) {}
    |                                ^^^^^^^^^^^^^^^^^^
@@ -171,7 +171,7 @@ LL |     pub fn test_rc_box_path(_: Rc<Box<Box<Path>>>) {}
    = help: consider using just `Rc<Box<Path>>` or `Box<Box<Path>>`
 
 error: usage of `Rc<Box<Box<DynSized>>>`
-  --> $DIR/redundant_allocation.rs:132:34
+  --> $DIR/redundant_allocation.rs:122:34
    |
 LL |     pub fn test_rc_box_custom(_: Rc<Box<Box<DynSized>>>) {}
    |                                  ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed b/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed
index e7ed84731c0..6db02718c70 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed
+++ b/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed
@@ -1,7 +1,7 @@
 // run-rustfix
 #![warn(clippy::all)]
 #![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
-#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
+#![allow(clippy::disallowed_names, unused_variables, dead_code)]
 #![allow(unused_imports)]
 
 pub struct MyStruct;
diff --git a/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs b/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs
index de763f98b5c..c15806f30c0 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs
+++ b/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs
@@ -1,7 +1,7 @@
 // run-rustfix
 #![warn(clippy::all)]
 #![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
-#![allow(clippy::blacklisted_name, unused_variables, dead_code)]
+#![allow(clippy::disallowed_names, unused_variables, dead_code)]
 #![allow(unused_imports)]
 
 pub struct MyStruct;
diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed
index 0abca6fca06..7cd687c95a0 100644
--- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed
+++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed
@@ -1,8 +1,28 @@
 // run-rustfix
 
+#![feature(async_closure)]
 #![warn(clippy::redundant_closure_call)]
 #![allow(unused)]
 
+async fn something() -> u32 {
+    21
+}
+
+async fn something_else() -> u32 {
+    2
+}
+
 fn main() {
     let a = 42;
+    let b = async {
+        let x = something().await;
+        let y = something_else().await;
+        x * y
+    };
+    let c = {
+        let x = 21;
+        let y = 2;
+        x * y
+    };
+    let d = async { something().await };
 }
diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs
index f8b9d37a5cc..37e4d223864 100644
--- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs
+++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs
@@ -1,8 +1,28 @@
 // run-rustfix
 
+#![feature(async_closure)]
 #![warn(clippy::redundant_closure_call)]
 #![allow(unused)]
 
+async fn something() -> u32 {
+    21
+}
+
+async fn something_else() -> u32 {
+    2
+}
+
 fn main() {
     let a = (|| 42)();
+    let b = (async || {
+        let x = something().await;
+        let y = something_else().await;
+        x * y
+    })();
+    let c = (|| {
+        let x = 21;
+        let y = 2;
+        x * y
+    })();
+    let d = (async || something().await)();
 }
diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr
index afd704ef12a..56a8e57c0c3 100644
--- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr
+++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr
@@ -1,10 +1,56 @@
 error: try not to call a closure in the expression where it is declared
-  --> $DIR/redundant_closure_call_fixable.rs:7:13
+  --> $DIR/redundant_closure_call_fixable.rs:16:13
    |
 LL |     let a = (|| 42)();
    |             ^^^^^^^^^ help: try doing something like: `42`
    |
    = note: `-D clippy::redundant-closure-call` implied by `-D warnings`
 
-error: aborting due to previous error
+error: try not to call a closure in the expression where it is declared
+  --> $DIR/redundant_closure_call_fixable.rs:17:13
+   |
+LL |       let b = (async || {
+   |  _____________^
+LL | |         let x = something().await;
+LL | |         let y = something_else().await;
+LL | |         x * y
+LL | |     })();
+   | |________^
+   |
+help: try doing something like
+   |
+LL ~     let b = async {
+LL +         let x = something().await;
+LL +         let y = something_else().await;
+LL +         x * y
+LL ~     };
+   |
+
+error: try not to call a closure in the expression where it is declared
+  --> $DIR/redundant_closure_call_fixable.rs:22:13
+   |
+LL |       let c = (|| {
+   |  _____________^
+LL | |         let x = 21;
+LL | |         let y = 2;
+LL | |         x * y
+LL | |     })();
+   | |________^
+   |
+help: try doing something like
+   |
+LL ~     let c = {
+LL +         let x = 21;
+LL +         let y = 2;
+LL +         x * y
+LL ~     };
+   |
+
+error: try not to call a closure in the expression where it is declared
+  --> $DIR/redundant_closure_call_fixable.rs:27:13
+   |
+LL |     let d = (async || something().await)();
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async { something().await }`
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index 53288be9404..9cbad2269a0 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -4,6 +4,7 @@
 
 // run-rustfix
 
+#![allow(clippy::disallowed_names)]
 #![allow(clippy::blocks_in_if_conditions)]
 #![allow(clippy::box_collection)]
 #![allow(clippy::redundant_static_lifetimes)]
@@ -14,6 +15,7 @@
 #![allow(clippy::for_loops_over_fallibles)]
 #![allow(clippy::useless_conversion)]
 #![allow(clippy::match_result_ok)]
+#![allow(clippy::overly_complex_bool_expr)]
 #![allow(clippy::new_without_default)]
 #![allow(clippy::bind_instead_of_map)]
 #![allow(clippy::expect_used)]
@@ -33,6 +35,7 @@
 #![allow(temporary_cstring_as_ptr)]
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
+#![warn(clippy::disallowed_names)]
 #![warn(clippy::blocks_in_if_conditions)]
 #![warn(clippy::blocks_in_if_conditions)]
 #![warn(clippy::box_collection)]
@@ -45,6 +48,7 @@
 #![warn(clippy::for_loops_over_fallibles)]
 #![warn(clippy::useless_conversion)]
 #![warn(clippy::match_result_ok)]
+#![warn(clippy::overly_complex_bool_expr)]
 #![warn(clippy::new_without_default)]
 #![warn(clippy::bind_instead_of_map)]
 #![warn(clippy::expect_used)]
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index 539f34f847a..9153c0dab02 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -4,6 +4,7 @@
 
 // run-rustfix
 
+#![allow(clippy::disallowed_names)]
 #![allow(clippy::blocks_in_if_conditions)]
 #![allow(clippy::box_collection)]
 #![allow(clippy::redundant_static_lifetimes)]
@@ -14,6 +15,7 @@
 #![allow(clippy::for_loops_over_fallibles)]
 #![allow(clippy::useless_conversion)]
 #![allow(clippy::match_result_ok)]
+#![allow(clippy::overly_complex_bool_expr)]
 #![allow(clippy::new_without_default)]
 #![allow(clippy::bind_instead_of_map)]
 #![allow(clippy::expect_used)]
@@ -33,6 +35,7 @@
 #![allow(temporary_cstring_as_ptr)]
 #![allow(unknown_lints)]
 #![allow(unused_labels)]
+#![warn(clippy::blacklisted_name)]
 #![warn(clippy::block_in_if_condition_expr)]
 #![warn(clippy::block_in_if_condition_stmt)]
 #![warn(clippy::box_vec)]
@@ -45,6 +48,7 @@
 #![warn(clippy::for_loop_over_result)]
 #![warn(clippy::identity_conversion)]
 #![warn(clippy::if_let_some_result)]
+#![warn(clippy::logic_bug)]
 #![warn(clippy::new_without_default_derive)]
 #![warn(clippy::option_and_then_some)]
 #![warn(clippy::option_expect_used)]
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index 8ea46b580a8..9c03ea914bb 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,214 +1,226 @@
+error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
+  --> $DIR/rename.rs:38:9
+   |
+LL | #![warn(clippy::blacklisted_name)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
+   |
+   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
+
 error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:36:9
+  --> $DIR/rename.rs:39:9
    |
 LL | #![warn(clippy::block_in_if_condition_expr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
-   |
-   = note: `-D renamed-and-removed-lints` implied by `-D warnings`
 
 error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions`
-  --> $DIR/rename.rs:37:9
+  --> $DIR/rename.rs:40:9
    |
 LL | #![warn(clippy::block_in_if_condition_stmt)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions`
 
 error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
-  --> $DIR/rename.rs:38:9
+  --> $DIR/rename.rs:41:9
    |
 LL | #![warn(clippy::box_vec)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
 
 error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
-  --> $DIR/rename.rs:39:9
+  --> $DIR/rename.rs:42:9
    |
 LL | #![warn(clippy::const_static_lifetime)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
 
 error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
-  --> $DIR/rename.rs:40:9
+  --> $DIR/rename.rs:43:9
    |
 LL | #![warn(clippy::cyclomatic_complexity)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
 
 error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
-  --> $DIR/rename.rs:41:9
+  --> $DIR/rename.rs:44:9
    |
 LL | #![warn(clippy::disallowed_method)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
 
 error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
-  --> $DIR/rename.rs:42:9
+  --> $DIR/rename.rs:45:9
    |
 LL | #![warn(clippy::disallowed_type)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
 
 error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
-  --> $DIR/rename.rs:43:9
+  --> $DIR/rename.rs:46:9
    |
 LL | #![warn(clippy::eval_order_dependence)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
 
 error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles`
-  --> $DIR/rename.rs:44:9
+  --> $DIR/rename.rs:47:9
    |
 LL | #![warn(clippy::for_loop_over_option)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
 
 error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles`
-  --> $DIR/rename.rs:45:9
+  --> $DIR/rename.rs:48:9
    |
 LL | #![warn(clippy::for_loop_over_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles`
 
 error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
-  --> $DIR/rename.rs:46:9
+  --> $DIR/rename.rs:49:9
    |
 LL | #![warn(clippy::identity_conversion)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
 
 error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
-  --> $DIR/rename.rs:47:9
+  --> $DIR/rename.rs:50:9
    |
 LL | #![warn(clippy::if_let_some_result)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
 
+error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
+  --> $DIR/rename.rs:51:9
+   |
+LL | #![warn(clippy::logic_bug)]
+   |         ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
+
 error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
-  --> $DIR/rename.rs:48:9
+  --> $DIR/rename.rs:52:9
    |
 LL | #![warn(clippy::new_without_default_derive)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
 
 error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
-  --> $DIR/rename.rs:49:9
+  --> $DIR/rename.rs:53:9
    |
 LL | #![warn(clippy::option_and_then_some)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
 
 error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:50:9
+  --> $DIR/rename.rs:54:9
    |
 LL | #![warn(clippy::option_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:51:9
+  --> $DIR/rename.rs:55:9
    |
 LL | #![warn(clippy::option_map_unwrap_or)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:52:9
+  --> $DIR/rename.rs:56:9
    |
 LL | #![warn(clippy::option_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:53:9
+  --> $DIR/rename.rs:57:9
    |
 LL | #![warn(clippy::option_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
-  --> $DIR/rename.rs:54:9
+  --> $DIR/rename.rs:58:9
    |
 LL | #![warn(clippy::ref_in_deref)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
 
 error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
-  --> $DIR/rename.rs:55:9
+  --> $DIR/rename.rs:59:9
    |
 LL | #![warn(clippy::result_expect_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
 
 error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
-  --> $DIR/rename.rs:56:9
+  --> $DIR/rename.rs:60:9
    |
 LL | #![warn(clippy::result_map_unwrap_or_else)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
 
 error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
-  --> $DIR/rename.rs:57:9
+  --> $DIR/rename.rs:61:9
    |
 LL | #![warn(clippy::result_unwrap_used)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
 
 error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
-  --> $DIR/rename.rs:58:9
+  --> $DIR/rename.rs:62:9
    |
 LL | #![warn(clippy::single_char_push_str)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
 
 error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
-  --> $DIR/rename.rs:59:9
+  --> $DIR/rename.rs:63:9
    |
 LL | #![warn(clippy::stutter)]
    |         ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
 
 error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
-  --> $DIR/rename.rs:60:9
+  --> $DIR/rename.rs:64:9
    |
 LL | #![warn(clippy::to_string_in_display)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
 
 error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
-  --> $DIR/rename.rs:61:9
+  --> $DIR/rename.rs:65:9
    |
 LL | #![warn(clippy::zero_width_space)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
 
 error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
-  --> $DIR/rename.rs:62:9
+  --> $DIR/rename.rs:66:9
    |
 LL | #![warn(clippy::drop_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
 
 error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
-  --> $DIR/rename.rs:63:9
+  --> $DIR/rename.rs:67:9
    |
 LL | #![warn(clippy::into_iter_on_array)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
 
 error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
-  --> $DIR/rename.rs:64:9
+  --> $DIR/rename.rs:68:9
    |
 LL | #![warn(clippy::invalid_atomic_ordering)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
 
 error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
-  --> $DIR/rename.rs:65:9
+  --> $DIR/rename.rs:69:9
    |
 LL | #![warn(clippy::invalid_ref)]
    |         ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
 
 error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums`
-  --> $DIR/rename.rs:66:9
+  --> $DIR/rename.rs:70:9
    |
 LL | #![warn(clippy::mem_discriminant_non_enum)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums`
 
 error: lint `clippy::panic_params` has been renamed to `non_fmt_panics`
-  --> $DIR/rename.rs:67:9
+  --> $DIR/rename.rs:71:9
    |
 LL | #![warn(clippy::panic_params)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics`
 
 error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr`
-  --> $DIR/rename.rs:68:9
+  --> $DIR/rename.rs:72:9
    |
 LL | #![warn(clippy::temporary_cstring_as_ptr)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr`
 
 error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints`
-  --> $DIR/rename.rs:69:9
+  --> $DIR/rename.rs:73:9
    |
 LL | #![warn(clippy::unknown_clippy_lints)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints`
 
 error: lint `clippy::unused_label` has been renamed to `unused_labels`
-  --> $DIR/rename.rs:70:9
+  --> $DIR/rename.rs:74:9
    |
 LL | #![warn(clippy::unused_label)]
    |         ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels`
 
-error: aborting due to 35 previous errors
+error: aborting due to 37 previous errors
 
diff --git a/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs b/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs
index 3d2295912c9..a48829caac0 100644
--- a/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs
+++ b/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs
@@ -48,9 +48,9 @@ fn ifs_same_cond_fn() {
     }
 
     let mut v = vec![1];
-    if v.pop() == None {
+    if v.pop().is_none() {
         //~ ERROR ifs same condition
-    } else if v.pop() == None {
+    } else if v.pop().is_none() {
     }
 
     if v.len() == 42 {
diff --git a/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr b/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr
index 71e82910ef7..cd438b83040 100644
--- a/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr
+++ b/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr
@@ -50,14 +50,14 @@ LL |     if obj.method_arg(a) {
 error: this `if` has the same function call as a previous `if`
   --> $DIR/same_functions_in_if_condition.rs:53:15
    |
-LL |     } else if v.pop() == None {
-   |               ^^^^^^^^^^^^^^^
+LL |     } else if v.pop().is_none() {
+   |               ^^^^^^^^^^^^^^^^^
    |
 note: same as this
   --> $DIR/same_functions_in_if_condition.rs:51:8
    |
-LL |     if v.pop() == None {
-   |        ^^^^^^^^^^^^^^^
+LL |     if v.pop().is_none() {
+   |        ^^^^^^^^^^^^^^^^^
 
 error: this `if` has the same function call as a previous `if`
   --> $DIR/same_functions_in_if_condition.rs:58:15
diff --git a/src/tools/clippy/tests/ui/skip_while_next.rs b/src/tools/clippy/tests/ui/skip_while_next.rs
index a522c0f08b2..a551c19d98b 100644
--- a/src/tools/clippy/tests/ui/skip_while_next.rs
+++ b/src/tools/clippy/tests/ui/skip_while_next.rs
@@ -1,7 +1,7 @@
 // aux-build:option_helpers.rs
 
 #![warn(clippy::skip_while_next)]
-#![allow(clippy::blacklisted_name)]
+#![allow(clippy::disallowed_names)]
 
 extern crate option_helpers;
 use option_helpers::IteratorFalsePositives;
diff --git a/src/tools/clippy/tests/ui/swap.fixed b/src/tools/clippy/tests/ui/swap.fixed
index 3329efbd4ff..24b229235d3 100644
--- a/src/tools/clippy/tests/ui/swap.fixed
+++ b/src/tools/clippy/tests/ui/swap.fixed
@@ -2,7 +2,7 @@
 
 #![warn(clippy::all)]
 #![allow(
-    clippy::blacklisted_name,
+    clippy::disallowed_names,
     clippy::no_effect,
     clippy::redundant_clone,
     redundant_semicolons,
diff --git a/src/tools/clippy/tests/ui/swap.rs b/src/tools/clippy/tests/ui/swap.rs
index 8179ac1f2ab..a318c27919c 100644
--- a/src/tools/clippy/tests/ui/swap.rs
+++ b/src/tools/clippy/tests/ui/swap.rs
@@ -2,7 +2,7 @@
 
 #![warn(clippy::all)]
 #![allow(
-    clippy::blacklisted_name,
+    clippy::disallowed_names,
     clippy::no_effect,
     clippy::redundant_clone,
     redundant_semicolons,
diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs
index 8f78f16a0a1..c0c64ebcabf 100644
--- a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs
+++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs
@@ -2,7 +2,7 @@
 // normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)"
 
 #![deny(clippy::trivially_copy_pass_by_ref)]
-#![allow(clippy::blacklisted_name, clippy::redundant_field_names)]
+#![allow(clippy::disallowed_names, clippy::redundant_field_names)]
 
 #[derive(Copy, Clone)]
 struct Foo(u32);
diff --git a/src/tools/clippy/tests/ui/unit_arg.rs b/src/tools/clippy/tests/ui/unit_arg.rs
index 38be87bddf1..7bf3adc07ac 100644
--- a/src/tools/clippy/tests/ui/unit_arg.rs
+++ b/src/tools/clippy/tests/ui/unit_arg.rs
@@ -1,3 +1,5 @@
+// aux-build: proc_macro_with_span.rs
+
 #![warn(clippy::unit_arg)]
 #![allow(
     clippy::no_effect,
@@ -8,9 +10,13 @@
     clippy::or_fun_call,
     clippy::needless_question_mark,
     clippy::self_named_constructors,
-    clippy::let_unit_value
+    clippy::let_unit_value,
+    clippy::never_loop
 )]
 
+extern crate proc_macro_with_span;
+
+use proc_macro_with_span::with_span;
 use std::fmt::Debug;
 
 fn foo<T: Debug>(t: T) {
@@ -127,6 +133,10 @@ fn returning_expr() -> Option<()> {
 
 fn taking_multiple_units(a: (), b: ()) {}
 
+fn proc_macro() {
+    with_span!(span taking_multiple_units(unsafe { (); }, 'x: loop { break 'x (); }));
+}
+
 fn main() {
     bad();
     ok();
diff --git a/src/tools/clippy/tests/ui/unit_arg.stderr b/src/tools/clippy/tests/ui/unit_arg.stderr
index 11cfe66a30e..1de9d44bb0d 100644
--- a/src/tools/clippy/tests/ui/unit_arg.stderr
+++ b/src/tools/clippy/tests/ui/unit_arg.stderr
@@ -1,5 +1,5 @@
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:57:5
+  --> $DIR/unit_arg.rs:63:5
    |
 LL | /     foo({
 LL | |         1;
@@ -20,7 +20,7 @@ LL ~     foo(());
    |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:60:5
+  --> $DIR/unit_arg.rs:66:5
    |
 LL |     foo(foo(1));
    |     ^^^^^^^^^^^
@@ -32,7 +32,7 @@ LL ~     foo(());
    |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:61:5
+  --> $DIR/unit_arg.rs:67:5
    |
 LL | /     foo({
 LL | |         foo(1);
@@ -54,7 +54,7 @@ LL ~     foo(());
    |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:66:5
+  --> $DIR/unit_arg.rs:72:5
    |
 LL | /     b.bar({
 LL | |         1;
@@ -74,7 +74,7 @@ LL ~     b.bar(());
    |
 
 error: passing unit values to a function
-  --> $DIR/unit_arg.rs:69:5
+  --> $DIR/unit_arg.rs:75:5
    |
 LL |     taking_multiple_units(foo(0), foo(1));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -87,7 +87,7 @@ LL ~     taking_multiple_units((), ());
    |
 
 error: passing unit values to a function
-  --> $DIR/unit_arg.rs:70:5
+  --> $DIR/unit_arg.rs:76:5
    |
 LL | /     taking_multiple_units(foo(0), {
 LL | |         foo(1);
@@ -110,7 +110,7 @@ LL ~     taking_multiple_units((), ());
    |
 
 error: passing unit values to a function
-  --> $DIR/unit_arg.rs:74:5
+  --> $DIR/unit_arg.rs:80:5
    |
 LL | /     taking_multiple_units(
 LL | |         {
@@ -146,7 +146,7 @@ LL ~     );
    |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:85:13
+  --> $DIR/unit_arg.rs:91:13
    |
 LL |     None.or(Some(foo(2)));
    |             ^^^^^^^^^^^^
@@ -160,7 +160,7 @@ LL ~     });
    |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:88:5
+  --> $DIR/unit_arg.rs:94:5
    |
 LL |     foo(foo(()));
    |     ^^^^^^^^^^^^
@@ -172,7 +172,7 @@ LL ~     foo(());
    |
 
 error: passing a unit value to a function
-  --> $DIR/unit_arg.rs:125:5
+  --> $DIR/unit_arg.rs:131:5
    |
 LL |     Some(foo(1))
    |     ^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/unwrap_expect_used.rs b/src/tools/clippy/tests/ui/unwrap_expect_used.rs
new file mode 100644
index 00000000000..0d4a0504a6e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unwrap_expect_used.rs
@@ -0,0 +1,10 @@
+#![warn(clippy::unwrap_used, clippy::expect_used)]
+
+fn main() {
+    Some(3).unwrap();
+    Some(3).expect("Hello world!");
+
+    let a: Result<i32, i32> = Ok(3);
+    a.unwrap();
+    a.expect("Hello world!");
+}
diff --git a/src/tools/clippy/tests/ui/unwrap_expect_used.stderr b/src/tools/clippy/tests/ui/unwrap_expect_used.stderr
new file mode 100644
index 00000000000..f54bfd617c4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unwrap_expect_used.stderr
@@ -0,0 +1,36 @@
+error: used `unwrap()` on `an Option` value
+  --> $DIR/unwrap_expect_used.rs:4:5
+   |
+LL |     Some(3).unwrap();
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::unwrap-used` implied by `-D warnings`
+   = help: if this value is `None`, it will panic
+
+error: used `expect()` on `an Option` value
+  --> $DIR/unwrap_expect_used.rs:5:5
+   |
+LL |     Some(3).expect("Hello world!");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::expect-used` implied by `-D warnings`
+   = help: if this value is `None`, it will panic
+
+error: used `unwrap()` on `a Result` value
+  --> $DIR/unwrap_expect_used.rs:8:5
+   |
+LL |     a.unwrap();
+   |     ^^^^^^^^^^
+   |
+   = help: if this value is an `Err`, it will panic
+
+error: used `expect()` on `a Result` value
+  --> $DIR/unwrap_expect_used.rs:9:5
+   |
+LL |     a.expect("Hello world!");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: if this value is an `Err`, it will panic
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/used_underscore_binding.rs b/src/tools/clippy/tests/ui/used_underscore_binding.rs
index d20977d55d2..322083511ac 100644
--- a/src/tools/clippy/tests/ui/used_underscore_binding.rs
+++ b/src/tools/clippy/tests/ui/used_underscore_binding.rs
@@ -2,7 +2,7 @@
 
 #![feature(rustc_private)]
 #![warn(clippy::all)]
-#![allow(clippy::blacklisted_name, clippy::eq_op)]
+#![allow(clippy::disallowed_names, clippy::eq_op)]
 #![warn(clippy::used_underscore_binding)]
 
 #[macro_use]
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index 23e49539969..41f97e4326a 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -17,6 +17,7 @@ rustfix = "0.6.0"
 lazy_static = "1.0"
 walkdir = "2"
 glob = "0.3.0"
+lazycell = "1.3.0"
 
 [target.'cfg(unix)'.dependencies]
 libc = "0.2"
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index be81ff881f3..6f17b9e1be9 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -3,9 +3,11 @@ pub use self::Mode::*;
 use std::ffi::OsString;
 use std::fmt;
 use std::path::{Path, PathBuf};
+use std::process::Command;
 use std::str::FromStr;
 
 use crate::util::PathBufExt;
+use lazycell::LazyCell;
 use test::ColorConfig;
 
 #[derive(Clone, Copy, PartialEq, Debug)]
@@ -371,6 +373,8 @@ pub struct Config {
 
     /// Whether to rerun tests even if the inputs are unchanged.
     pub force_rerun: bool,
+
+    pub target_cfg: LazyCell<TargetCfg>,
 }
 
 impl Config {
@@ -380,6 +384,131 @@ impl Config {
             !self.target.ends_with("-fuchsia")
         })
     }
+
+    fn target_cfg(&self) -> &TargetCfg {
+        self.target_cfg.borrow_with(|| TargetCfg::new(&self.rustc_path, &self.target))
+    }
+
+    pub fn matches_arch(&self, arch: &str) -> bool {
+        self.target_cfg().arch == arch ||
+        // Shorthand for convenience. The arch for
+        // asmjs-unknown-emscripten is actually wasm32.
+        (arch == "asmjs" && self.target.starts_with("asmjs")) ||
+        // Matching all the thumb variants as one can be convenient.
+        // (thumbv6m, thumbv7em, thumbv7m, etc.)
+        (arch == "thumb" && self.target.starts_with("thumb"))
+    }
+
+    pub fn matches_os(&self, os: &str) -> bool {
+        self.target_cfg().os == os
+    }
+
+    pub fn matches_env(&self, env: &str) -> bool {
+        self.target_cfg().env == env
+    }
+
+    pub fn matches_abi(&self, abi: &str) -> bool {
+        self.target_cfg().abi == abi
+    }
+
+    pub fn matches_family(&self, family: &str) -> bool {
+        self.target_cfg().families.iter().any(|f| f == family)
+    }
+
+    pub fn is_big_endian(&self) -> bool {
+        self.target_cfg().endian == Endian::Big
+    }
+
+    pub fn get_pointer_width(&self) -> u32 {
+        *&self.target_cfg().pointer_width
+    }
+
+    pub fn has_asm_support(&self) -> bool {
+        static ASM_SUPPORTED_ARCHS: &[&str] = &[
+            "x86", "x86_64", "arm", "aarch64", "riscv32",
+            "riscv64",
+            // These targets require an additional asm_experimental_arch feature.
+            // "nvptx64", "hexagon", "mips", "mips64", "spirv", "wasm32",
+        ];
+        ASM_SUPPORTED_ARCHS.contains(&self.target_cfg().arch.as_str())
+    }
+}
+
+#[derive(Clone, Debug)]
+pub struct TargetCfg {
+    arch: String,
+    os: String,
+    env: String,
+    abi: String,
+    families: Vec<String>,
+    pointer_width: u32,
+    endian: Endian,
+}
+
+#[derive(Eq, PartialEq, Clone, Debug)]
+pub enum Endian {
+    Little,
+    Big,
+}
+
+impl TargetCfg {
+    fn new(rustc_path: &Path, target: &str) -> TargetCfg {
+        let output = match Command::new(rustc_path)
+            .arg("--print=cfg")
+            .arg("--target")
+            .arg(target)
+            .output()
+        {
+            Ok(output) => output,
+            Err(e) => panic!("error: failed to get cfg info from {:?}: {e}", rustc_path),
+        };
+        if !output.status.success() {
+            panic!(
+                "error: failed to get cfg info from {:?}\n--- stdout\n{}\n--- stderr\n{}",
+                rustc_path,
+                String::from_utf8(output.stdout).unwrap(),
+                String::from_utf8(output.stderr).unwrap(),
+            );
+        }
+        let print_cfg = String::from_utf8(output.stdout).unwrap();
+        let mut arch = None;
+        let mut os = None;
+        let mut env = None;
+        let mut abi = None;
+        let mut families = Vec::new();
+        let mut pointer_width = None;
+        let mut endian = None;
+        for line in print_cfg.lines() {
+            if let Some((name, value)) = line.split_once('=') {
+                let value = value.trim_matches('"');
+                match name {
+                    "target_arch" => arch = Some(value),
+                    "target_os" => os = Some(value),
+                    "target_env" => env = Some(value),
+                    "target_abi" => abi = Some(value),
+                    "target_family" => families.push(value.to_string()),
+                    "target_pointer_width" => pointer_width = Some(value.parse().unwrap()),
+                    "target_endian" => {
+                        endian = Some(match value {
+                            "little" => Endian::Little,
+                            "big" => Endian::Big,
+                            s => panic!("unexpected {s}"),
+                        })
+                    }
+                    _ => {}
+                }
+            }
+        }
+        TargetCfg {
+            arch: arch.unwrap().to_string(),
+            os: os.unwrap().to_string(),
+            env: env.unwrap().to_string(),
+            abi: abi.unwrap().to_string(),
+            families,
+            pointer_width: pointer_width.unwrap(),
+            endian: endian.unwrap(),
+        }
+    }
 }
 
 #[derive(Debug, Clone)]
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index f8f193ddf83..8f097f47b45 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -661,17 +661,36 @@ impl Config {
 
         let name = line[prefix.len() + 1..].split(&[':', ' '][..]).next().unwrap();
 
+        let matches_pointer_width = || {
+            name.strip_suffix("bit")
+                .and_then(|width| width.parse::<u32>().ok())
+                .map(|width| self.get_pointer_width() == width)
+                .unwrap_or(false)
+        };
+
+        // If something is ignored for emscripten, it likely also needs to be
+        // ignored for wasm32-unknown-unknown.
+        // `wasm32-bare` is an alias to refer to just wasm32-unknown-unknown
+        // (in contrast to `wasm32` which also matches non-bare targets like
+        // asmjs-unknown-emscripten).
+        let matches_wasm32_alias = || {
+            self.target == "wasm32-unknown-unknown" && matches!(name, "emscripten" | "wasm32-bare")
+        };
+
         let is_match = name == "test" ||
             self.target == name ||                              // triple
-            util::matches_os(&self.target, name) ||             // target
-            util::matches_env(&self.target, name) ||            // env
+            self.matches_os(name) ||
+            self.matches_env(name) ||
+            self.matches_abi(name) ||
+            self.matches_family(name) ||
             self.target.ends_with(name) ||                      // target and env
-            name == util::get_arch(&self.target) ||             // architecture
-            name == util::get_pointer_width(&self.target) ||    // pointer width
+            self.matches_arch(name) ||
+            matches_wasm32_alias() ||
+            matches_pointer_width() ||
             name == self.stage_id.split('-').next().unwrap() || // stage
             name == self.channel ||                             // channel
             (self.target != self.host && name == "cross-compile") ||
-            (name == "endian-big" && util::is_big_endian(&self.target)) ||
+            (name == "endian-big" && self.is_big_endian()) ||
             (self.remote_test_client.is_some() && name == "remote") ||
             match self.compare_mode {
                 Some(CompareMode::Polonius) => name == "compare-mode-polonius",
@@ -869,7 +888,7 @@ pub fn make_test_description<R: Read>(
 
     let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some();
     let rustc_has_sanitizer_support = env::var_os("RUSTC_SANITIZER_SUPPORT").is_some();
-    let has_asm_support = util::has_asm_support(&config.target);
+    let has_asm_support = config.has_asm_support();
     let has_asan = util::ASAN_SUPPORTED_TARGETS.contains(&&*config.target);
     let has_cfi = util::CFI_SUPPORTED_TARGETS.contains(&&*config.target);
     let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target);
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index a8fd4880f07..bcd222b5a93 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -42,7 +42,6 @@ fn config() -> Config {
         "--suite=ui",
         "--compile-lib-path=",
         "--run-lib-path=",
-        "--rustc-path=",
         "--python=",
         "--jsondocck-path=",
         "--src-base=",
@@ -57,7 +56,24 @@ fn config() -> Config {
         "--target=x86_64-unknown-linux-gnu",
         "--channel=nightly",
     ];
-    let args = args.iter().map(ToString::to_string).collect();
+    let mut args: Vec<String> = args.iter().map(ToString::to_string).collect();
+    args.push("--rustc-path".to_string());
+    // This is a subtle/fragile thing. On rust-lang CI, there is no global
+    // `rustc`, and Cargo doesn't offer a convenient way to get the path to
+    // `rustc`. Fortunately bootstrap sets `RUSTC` for us, which is pointing
+    // to the stage0 compiler.
+    //
+    // Otherwise, if you are running compiletests's tests manually, you
+    // probably don't have `RUSTC` set, in which case this falls back to the
+    // global rustc. If your global rustc is too far out of sync with stage0,
+    // then this may cause confusing errors. Or if for some reason you don't
+    // have rustc in PATH, that would also fail.
+    args.push(std::env::var("RUSTC").unwrap_or_else(|_| {
+        eprintln!(
+            "warning: RUSTC not set, using global rustc (are you not running via bootstrap?)"
+        );
+        "rustc".to_string()
+    }));
     crate::parse_config(args)
 }
 
@@ -237,13 +253,20 @@ fn sanitizers() {
 
 #[test]
 fn asm_support() {
-    let mut config = config();
-
-    config.target = "avr-unknown-gnu-atmega328".to_owned();
-    assert!(check_ignore(&config, "// needs-asm-support"));
-
-    config.target = "i686-unknown-netbsd".to_owned();
-    assert!(!check_ignore(&config, "// needs-asm-support"));
+    let asms = [
+        ("avr-unknown-gnu-atmega328", false),
+        ("i686-unknown-netbsd", true),
+        ("riscv32gc-unknown-linux-gnu", true),
+        ("riscv64imac-unknown-none-elf", true),
+        ("x86_64-unknown-linux-gnu", true),
+        ("i686-unknown-netbsd", true),
+    ];
+    for (target, has_asm) in asms {
+        let mut config = config();
+        config.target = target.to_string();
+        assert_eq!(config.has_asm_support(), has_asm);
+        assert_eq!(check_ignore(&config, "// needs-asm-support"), !has_asm)
+    }
 }
 
 #[test]
@@ -281,3 +304,155 @@ fn test_duplicate_revisions() {
     let config = config();
     parse_rs(&config, "// revisions: rpass1 rpass1");
 }
+
+#[test]
+fn ignore_arch() {
+    let archs = [
+        ("x86_64-unknown-linux-gnu", "x86_64"),
+        ("i686-unknown-linux-gnu", "x86"),
+        ("nvptx64-nvidia-cuda", "nvptx64"),
+        ("asmjs-unknown-emscripten", "wasm32"),
+        ("asmjs-unknown-emscripten", "asmjs"),
+        ("thumbv7m-none-eabi", "thumb"),
+    ];
+    for (target, arch) in archs {
+        let mut config = config();
+        config.target = target.to_string();
+        assert!(config.matches_arch(arch), "{target} {arch}");
+        assert!(check_ignore(&config, &format!("// ignore-{arch}")));
+    }
+}
+
+#[test]
+fn matches_os() {
+    let oss = [
+        ("x86_64-unknown-linux-gnu", "linux"),
+        ("x86_64-fortanix-unknown-sgx", "unknown"),
+        ("wasm32-unknown-unknown", "unknown"),
+        ("x86_64-unknown-none", "none"),
+    ];
+    for (target, os) in oss {
+        let mut config = config();
+        config.target = target.to_string();
+        assert!(config.matches_os(os), "{target} {os}");
+        assert!(check_ignore(&config, &format!("// ignore-{os}")));
+    }
+}
+
+#[test]
+fn matches_env() {
+    let envs = [
+        ("x86_64-unknown-linux-gnu", "gnu"),
+        ("x86_64-fortanix-unknown-sgx", "sgx"),
+        ("arm-unknown-linux-musleabi", "musl"),
+    ];
+    for (target, env) in envs {
+        let mut config = config();
+        config.target = target.to_string();
+        assert!(config.matches_env(env), "{target} {env}");
+        assert!(check_ignore(&config, &format!("// ignore-{env}")));
+    }
+}
+
+#[test]
+fn matches_abi() {
+    let abis = [
+        ("aarch64-apple-ios-macabi", "macabi"),
+        ("x86_64-unknown-linux-gnux32", "x32"),
+        ("arm-unknown-linux-gnueabi", "eabi"),
+    ];
+    for (target, abi) in abis {
+        let mut config = config();
+        config.target = target.to_string();
+        assert!(config.matches_abi(abi), "{target} {abi}");
+        assert!(check_ignore(&config, &format!("// ignore-{abi}")));
+    }
+}
+
+#[test]
+fn is_big_endian() {
+    let endians = [
+        ("x86_64-unknown-linux-gnu", false),
+        ("bpfeb-unknown-none", true),
+        ("m68k-unknown-linux-gnu", true),
+        ("aarch64_be-unknown-linux-gnu", true),
+        ("powerpc64-unknown-linux-gnu", true),
+    ];
+    for (target, is_big) in endians {
+        let mut config = config();
+        config.target = target.to_string();
+        assert_eq!(config.is_big_endian(), is_big, "{target} {is_big}");
+        assert_eq!(check_ignore(&config, "// ignore-endian-big"), is_big);
+    }
+}
+
+#[test]
+fn pointer_width() {
+    let widths = [
+        ("x86_64-unknown-linux-gnu", 64),
+        ("i686-unknown-linux-gnu", 32),
+        ("arm64_32-apple-watchos", 32),
+        ("msp430-none-elf", 16),
+    ];
+    for (target, width) in widths {
+        let mut config = config();
+        config.target = target.to_string();
+        assert_eq!(config.get_pointer_width(), width, "{target} {width}");
+        assert_eq!(check_ignore(&config, "// ignore-16bit"), width == 16);
+        assert_eq!(check_ignore(&config, "// ignore-32bit"), width == 32);
+        assert_eq!(check_ignore(&config, "// ignore-64bit"), width == 64);
+    }
+}
+
+#[test]
+fn wasm_special() {
+    let ignores = [
+        ("wasm32-unknown-unknown", "emscripten", true),
+        ("wasm32-unknown-unknown", "wasm32", true),
+        ("wasm32-unknown-unknown", "wasm32-bare", true),
+        ("wasm32-unknown-unknown", "wasm64", false),
+        ("asmjs-unknown-emscripten", "emscripten", true),
+        ("asmjs-unknown-emscripten", "wasm32", true),
+        ("asmjs-unknown-emscripten", "wasm32-bare", false),
+        ("wasm32-unknown-emscripten", "emscripten", true),
+        ("wasm32-unknown-emscripten", "wasm32", true),
+        ("wasm32-unknown-emscripten", "wasm32-bare", false),
+        ("wasm32-wasi", "emscripten", false),
+        ("wasm32-wasi", "wasm32", true),
+        ("wasm32-wasi", "wasm32-bare", false),
+        ("wasm32-wasi", "wasi", true),
+        ("wasm64-unknown-unknown", "emscripten", false),
+        ("wasm64-unknown-unknown", "wasm32", false),
+        ("wasm64-unknown-unknown", "wasm32-bare", false),
+        ("wasm64-unknown-unknown", "wasm64", true),
+    ];
+    for (target, pattern, ignore) in ignores {
+        let mut config = config();
+        config.target = target.to_string();
+        assert_eq!(
+            check_ignore(&config, &format!("// ignore-{pattern}")),
+            ignore,
+            "{target} {pattern}"
+        );
+    }
+}
+
+#[test]
+fn families() {
+    let families = [
+        ("x86_64-unknown-linux-gnu", "unix"),
+        ("x86_64-pc-windows-gnu", "windows"),
+        ("wasm32-unknown-unknown", "wasm"),
+        ("wasm32-unknown-emscripten", "wasm"),
+        ("wasm32-unknown-emscripten", "unix"),
+    ];
+    for (target, family) in families {
+        let mut config = config();
+        config.target = target.to_string();
+        assert!(config.matches_family(family));
+        let other = if family == "windows" { "unix" } else { "windows" };
+        assert!(!config.matches_family(other));
+        assert!(check_ignore(&config, &format!("// ignore-{family}")));
+        assert!(!check_ignore(&config, &format!("// ignore-{other}")));
+    }
+}
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index a8a151ca114..ac6d80bb439 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -11,6 +11,7 @@ use crate::common::{
 use crate::common::{CompareMode, Config, Debugger, Mode, PassMode, TestPaths};
 use crate::util::logv;
 use getopts::Options;
+use lazycell::LazyCell;
 use std::env;
 use std::ffi::OsString;
 use std::fs;
@@ -299,6 +300,8 @@ pub fn parse_config(args: Vec<String>) -> Config {
         npm: matches.opt_str("npm"),
 
         force_rerun: matches.opt_present("force-rerun"),
+
+        target_cfg: LazyCell::new(),
     }
 }
 
@@ -441,7 +444,7 @@ fn configure_cdb(config: &Config) -> Option<Config> {
 fn configure_gdb(config: &Config) -> Option<Config> {
     config.gdb_version?;
 
-    if util::matches_env(&config.target, "msvc") {
+    if config.matches_env("msvc") {
         return None;
     }
 
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index d3e5a2dd644..47f2a2d3482 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -13,7 +13,6 @@ use crate::errors::{self, Error, ErrorKind};
 use crate::header::TestProps;
 use crate::json;
 use crate::read2::read2_abbreviated;
-use crate::util::get_pointer_width;
 use crate::util::{logv, PathBufExt};
 use crate::ColorConfig;
 use regex::{Captures, Regex};
@@ -3127,7 +3126,7 @@ impl<'test> TestCx<'test> {
         output_kind: TestOutput,
         explicit_format: bool,
     ) -> usize {
-        let stderr_bits = format!("{}.stderr", get_pointer_width(&self.config.target));
+        let stderr_bits = format!("{}bit.stderr", self.config.get_pointer_width());
         let (stderr_kind, stdout_kind) = match output_kind {
             TestOutput::Compile => (
                 {
@@ -3402,7 +3401,7 @@ impl<'test> TestCx<'test> {
 
         let mut bit_width = String::new();
         if test_file_contents.lines().any(|l| l == "// EMIT_MIR_FOR_EACH_BIT_WIDTH") {
-            bit_width = format!(".{}", get_pointer_width(&self.config.target));
+            bit_width = format!(".{}bit", self.config.get_pointer_width());
         }
 
         if self.config.bless {
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index 22df18ee9fb..9d047b63c85 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -8,84 +8,6 @@ use tracing::*;
 #[cfg(test)]
 mod tests;
 
-/// Conversion table from triple OS name to Rust SYSNAME
-const OS_TABLE: &[(&str, &str)] = &[
-    ("android", "android"),
-    ("androideabi", "android"),
-    ("cuda", "cuda"),
-    ("darwin", "macos"),
-    ("dragonfly", "dragonfly"),
-    ("emscripten", "emscripten"),
-    ("freebsd", "freebsd"),
-    ("fuchsia", "fuchsia"),
-    ("haiku", "haiku"),
-    ("hermit", "hermit"),
-    ("illumos", "illumos"),
-    ("ios", "ios"),
-    ("l4re", "l4re"),
-    ("linux", "linux"),
-    ("mingw32", "windows"),
-    ("none", "none"),
-    ("netbsd", "netbsd"),
-    ("openbsd", "openbsd"),
-    ("redox", "redox"),
-    ("sgx", "sgx"),
-    ("solaris", "solaris"),
-    ("watchos", "watchos"),
-    ("win32", "windows"),
-    ("windows", "windows"),
-    ("vxworks", "vxworks"),
-];
-
-const ARCH_TABLE: &[(&str, &str)] = &[
-    ("aarch64", "aarch64"),
-    ("aarch64_be", "aarch64"),
-    ("amd64", "x86_64"),
-    ("arm", "arm"),
-    ("arm64", "aarch64"),
-    ("armv4t", "arm"),
-    ("armv5te", "arm"),
-    ("armv7", "arm"),
-    ("armv7s", "arm"),
-    ("asmjs", "asmjs"),
-    ("avr", "avr"),
-    ("bpfeb", "bpf"),
-    ("bpfel", "bpf"),
-    ("hexagon", "hexagon"),
-    ("i386", "x86"),
-    ("i586", "x86"),
-    ("i686", "x86"),
-    ("m68k", "m68k"),
-    ("mips", "mips"),
-    ("mips64", "mips64"),
-    ("mips64el", "mips64"),
-    ("mipsisa32r6", "mips"),
-    ("mipsisa32r6el", "mips"),
-    ("mipsisa64r6", "mips64"),
-    ("mipsisa64r6el", "mips64"),
-    ("mipsel", "mips"),
-    ("mipsisa32r6", "mips"),
-    ("mipsisa32r6el", "mips"),
-    ("mipsisa64r6", "mips64"),
-    ("mipsisa64r6el", "mips64"),
-    ("msp430", "msp430"),
-    ("nvptx64", "nvptx64"),
-    ("powerpc", "powerpc"),
-    ("powerpc64", "powerpc64"),
-    ("powerpc64le", "powerpc64"),
-    ("riscv64gc", "riscv64"),
-    ("s390x", "s390x"),
-    ("sparc", "sparc"),
-    ("sparc64", "sparc64"),
-    ("sparcv9", "sparc64"),
-    ("thumbv6m", "thumb"),
-    ("thumbv7em", "thumb"),
-    ("thumbv7m", "thumb"),
-    ("wasm32", "wasm32"),
-    ("x86_64", "x86_64"),
-    ("xcore", "xcore"),
-];
-
 pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[
     "aarch64-apple-darwin",
     "aarch64-fuchsia",
@@ -140,80 +62,6 @@ pub const MEMTAG_SUPPORTED_TARGETS: &[&str] =
 
 pub const SHADOWCALLSTACK_SUPPORTED_TARGETS: &[&str] = &["aarch64-linux-android"];
 
-const BIG_ENDIAN: &[&str] = &[
-    "aarch64_be",
-    "armebv7r",
-    "mips",
-    "mips64",
-    "mipsisa32r6",
-    "mipsisa64r6",
-    "powerpc",
-    "powerpc64",
-    "s390x",
-    "sparc",
-    "sparc64",
-    "sparcv9",
-];
-
-static ASM_SUPPORTED_ARCHS: &[&str] = &[
-    "x86", "x86_64", "arm", "aarch64", "riscv32",
-    "riscv64",
-    // These targets require an additional asm_experimental_arch feature.
-    // "nvptx64", "hexagon", "mips", "mips64", "spirv", "wasm32",
-];
-
-pub fn has_asm_support(triple: &str) -> bool {
-    ASM_SUPPORTED_ARCHS.contains(&get_arch(triple))
-}
-
-pub fn matches_os(triple: &str, name: &str) -> bool {
-    // For the wasm32 bare target we ignore anything also ignored on emscripten
-    // and then we also recognize `wasm32-bare` as the os for the target
-    if triple == "wasm32-unknown-unknown" {
-        return name == "emscripten" || name == "wasm32-bare";
-    }
-    let triple: Vec<_> = triple.split('-').collect();
-    for &(triple_os, os) in OS_TABLE {
-        if triple.contains(&triple_os) {
-            return os == name;
-        }
-    }
-    panic!("Cannot determine OS from triple");
-}
-
-/// Determine the architecture from `triple`
-pub fn get_arch(triple: &str) -> &'static str {
-    let triple: Vec<_> = triple.split('-').collect();
-    for &(triple_arch, arch) in ARCH_TABLE {
-        if triple.contains(&triple_arch) {
-            return arch;
-        }
-    }
-    panic!("Cannot determine Architecture from triple");
-}
-
-/// Determine the endianness from `triple`
-pub fn is_big_endian(triple: &str) -> bool {
-    let triple_arch = triple.split('-').next().unwrap();
-    BIG_ENDIAN.contains(&triple_arch)
-}
-
-pub fn matches_env(triple: &str, name: &str) -> bool {
-    if let Some(env) = triple.split('-').nth(3) { env.starts_with(name) } else { false }
-}
-
-pub fn get_pointer_width(triple: &str) -> &'static str {
-    if (triple.contains("64") && !triple.ends_with("gnux32") && !triple.ends_with("gnu_ilp32"))
-        || triple.starts_with("s390x")
-    {
-        "64bit"
-    } else if triple.starts_with("avr") {
-        "16bit"
-    } else {
-        "32bit"
-    }
-}
-
 pub fn make_new_path(path: &str) -> String {
     assert!(cfg!(windows));
     // Windows just uses PATH as the library search path, so we have to
diff --git a/src/tools/compiletest/src/util/tests.rs b/src/tools/compiletest/src/util/tests.rs
index 663027173ff..b09a183b14e 100644
--- a/src/tools/compiletest/src/util/tests.rs
+++ b/src/tools/compiletest/src/util/tests.rs
@@ -1,43 +1,6 @@
 use super::*;
 
 #[test]
-#[should_panic(expected = "Cannot determine Architecture from triple")]
-fn test_get_arch_failure() {
-    get_arch("abc");
-}
-
-#[test]
-fn test_get_arch() {
-    assert_eq!("x86_64", get_arch("x86_64-unknown-linux-gnu"));
-    assert_eq!("x86_64", get_arch("amd64"));
-    assert_eq!("nvptx64", get_arch("nvptx64-nvidia-cuda"));
-}
-
-#[test]
-#[should_panic(expected = "Cannot determine OS from triple")]
-fn test_matches_os_failure() {
-    matches_os("abc", "abc");
-}
-
-#[test]
-fn test_matches_os() {
-    assert!(matches_os("x86_64-unknown-linux-gnu", "linux"));
-    assert!(matches_os("wasm32-unknown-unknown", "emscripten"));
-    assert!(matches_os("wasm32-unknown-unknown", "wasm32-bare"));
-    assert!(!matches_os("wasm32-unknown-unknown", "windows"));
-    assert!(matches_os("thumbv6m0-none-eabi", "none"));
-    assert!(matches_os("riscv32imc-unknown-none-elf", "none"));
-    assert!(matches_os("nvptx64-nvidia-cuda", "cuda"));
-    assert!(matches_os("x86_64-fortanix-unknown-sgx", "sgx"));
-}
-
-#[test]
-fn is_big_endian_test() {
-    assert!(!is_big_endian("no"));
-    assert!(is_big_endian("sparc-unknown-unknown"));
-}
-
-#[test]
 fn path_buf_with_extra_extension_test() {
     assert_eq!(
         PathBuf::from("foo.rs.stderr"),
diff --git a/src/tools/miri b/src/tools/miri
-Subproject b938529fb8ed8f7b5b374282ffc3ffa74c31311
+Subproject 39ee5747153bf13324870c4a912acbf1f9bfde3
diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js
index a5121850369..70d5f94472f 100644
--- a/src/tools/rustdoc-gui/tester.js
+++ b/src/tools/rustdoc-gui/tester.js
@@ -201,6 +201,19 @@ async function main(argv) {
         process.setMaxListeners(opts["jobs"] + 1);
     }
 
+    // We catch this "event" to display a nicer message in case of unexpected exit (because of a
+    // missing `--no-sandbox`).
+    const exitHandling = (code) => {
+        if (!opts["no_sandbox"]) {
+            console.log("");
+            console.log(
+                "`browser-ui-test` crashed unexpectedly. Please try again with adding `--test-args \
+--no-sandbox` at the end. For example: `x.py test src/test/rustdoc-gui --test-args --no-sandbox`");
+            console.log("");
+        }
+    };
+    process.on('exit', exitHandling);
+
     const tests_queue = [];
     let results = {
         successful: [],
@@ -247,6 +260,9 @@ async function main(argv) {
     }
     status_bar.finish();
 
+    // We don't need this listener anymore.
+    process.removeListener("exit", exitHandling);
+
     if (debug) {
         results.successful.sort(by_filename);
         results.successful.forEach(r => {
diff --git a/src/tools/rustfmt/src/chains.rs b/src/tools/rustfmt/src/chains.rs
index e26e24ec55a..fcc02eca429 100644
--- a/src/tools/rustfmt/src/chains.rs
+++ b/src/tools/rustfmt/src/chains.rs
@@ -145,7 +145,7 @@ impl ChainItemKind {
 
     fn from_ast(context: &RewriteContext<'_>, expr: &ast::Expr) -> (ChainItemKind, Span) {
         let (kind, span) = match expr.kind {
-            ast::ExprKind::MethodCall(ref segment, ref expressions, _) => {
+            ast::ExprKind::MethodCall(ref segment, ref receiver, ref expressions, _) => {
                 let types = if let Some(ref generic_args) = segment.args {
                     if let ast::GenericArgs::AngleBracketed(ref data) = **generic_args {
                         data.args
@@ -163,7 +163,7 @@ impl ChainItemKind {
                 } else {
                     vec![]
                 };
-                let span = mk_sp(expressions[0].span.hi(), expr.span.hi());
+                let span = mk_sp(receiver.span.hi(), expr.span.hi());
                 let kind = ChainItemKind::MethodCall(segment.clone(), types, expressions.clone());
                 (kind, span)
             }
@@ -253,7 +253,7 @@ impl ChainItem {
             format!("::<{}>", type_list.join(", "))
         };
         let callee_str = format!(".{}{}", rewrite_ident(context, method_name), type_str);
-        rewrite_call(context, &callee_str, &args[1..], span, shape)
+        rewrite_call(context, &callee_str, &args, span, shape)
     }
 }
 
@@ -400,8 +400,8 @@ impl Chain {
     // is a try! macro, we'll convert it to shorthand when the option is set.
     fn pop_expr_chain(expr: &ast::Expr, context: &RewriteContext<'_>) -> Option<ast::Expr> {
         match expr.kind {
-            ast::ExprKind::MethodCall(_, ref expressions, _) => {
-                Some(Self::convert_try(&expressions[0], context))
+            ast::ExprKind::MethodCall(_, ref receiver, _, _) => {
+                Some(Self::convert_try(&receiver, context))
             }
             ast::ExprKind::Field(ref subexpr, _)
             | ast::ExprKind::Try(ref subexpr)
diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs
index 9615c4db6b4..025b8ab9f0a 100644
--- a/src/tools/tidy/src/bins.rs
+++ b/src/tools/tidy/src/bins.rs
@@ -96,6 +96,8 @@ mod os_impl {
 
     #[cfg(unix)]
     pub fn check(path: &Path, bad: &mut bool) {
+        use std::ffi::OsStr;
+
         const ALLOWED: &[&str] = &["configure"];
 
         crate::walk_no_read(
@@ -117,9 +119,9 @@ mod os_impl {
             },
             &mut |entry| {
                 let file = entry.path();
-                let filename = file.file_name().unwrap().to_string_lossy();
-                let extensions = [".py", ".sh"];
-                if extensions.iter().any(|e| filename.ends_with(e)) {
+                let extension = file.extension();
+                let scripts = ["py", "sh", "ps1"];
+                if scripts.into_iter().any(|e| extension == Some(OsStr::new(e))) {
                     return;
                 }
 
diff --git a/x.ps1 b/x.ps1
new file mode 100755
index 00000000000..1225443735f
--- /dev/null
+++ b/x.ps1
@@ -0,0 +1,28 @@
+#!/usr/bin/env pwsh
+
+# See x.sh for why these scripts exist.
+
+$xpy = Join-Path $PSScriptRoot x.py
+# Start-Process for some reason splits arguments on spaces. (Isn't powershell supposed to be simpler than bash?)
+# Double-quote all the arguments so it doesn't do that.
+$xpy_args = @("""$xpy""")
+foreach ($arg in $args) {
+    $xpy_args += """$arg"""
+}
+
+foreach ($python in "py", "python3", "python", "python2") {
+    # NOTE: this only tests that the command exists in PATH, not that it's actually
+    # executable. The latter is not possible in a portable way, see
+    # https://github.com/PowerShell/PowerShell/issues/12625.
+    if (Get-Command $python -ErrorAction SilentlyContinue) {
+        if ($python -eq "py") {
+            # Use python3, not python2
+            $xpy_args = @("-3") + $xpy_args
+        }
+        $process = Start-Process -NoNewWindow -Wait -PassThru $python $xpy_args
+        Exit $process.ExitCode
+    }
+}
+
+Write-Error "${PSCommandPath}: error: did not find python installed"
+Exit 1
diff --git a/x.py b/x.py
index 0289056fdcb..6c68907c581 100755
--- a/x.py
+++ b/x.py
@@ -1,36 +1,16 @@
-#!/usr/bin/env bash
+#!/usr/bin/env python3
+# Some systems don't have `python3` in their PATH. This isn't supported by x.py directly;
+# they should use `x.sh` or `x.ps1` instead.
 
-# Modern Linux and macOS systems commonly only have a thing called `python3` and
-# not `python`, while Windows commonly does not have `python3`, so we cannot
-# directly use python in the shebang and have it consistently work. Instead we
-# embed some bash to look for a python to run the rest of the script.
-#
-# On Windows, `py -3` sometimes works. We need to try it first because `python3`
-# sometimes tries to launch the app store on Windows.
-'''':
-for PYTHON in "py -3" python3 python python2; do
-    if command -v $PYTHON >/dev/null; then
-        exec $PYTHON "$0" "$@"
-        break
-    fi
-done
-echo "$0: error: did not find python installed" >&2
-exit 1
-'''
-
-# The rest of this file is Python.
-#
 # This file is only a "symlink" to bootstrap.py, all logic should go there.
 
 import os
 import sys
 
 # If this is python2, check if python3 is available and re-execute with that
-# interpreter.
+# interpreter. Only python3 allows downloading CI LLVM.
 #
-# `./x.py` would not normally benefit from this because the bash above tries
-# python3 before 2, but this matters if someone ran `python x.py` and their
-# system's `python` is python2.
+# This matters if someone's system `python` is python2.
 if sys.version_info.major < 3:
     try:
         os.execvp("py", ["py", "-3"] + sys.argv)
diff --git a/x.sh b/x.sh
new file mode 100755
index 00000000000..704d0f791f3
--- /dev/null
+++ b/x.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+# Modern Linux and macOS systems commonly only have a thing called `python3` and
+# not `python`, while Windows commonly does not have `python3`, so we cannot
+# directly use python in the x.py shebang and have it consistently work. Instead we
+# have a shell script to look for a python to run x.py.
+
+set -eu
+
+realpath() {
+    if [ -d "$1" ]; then
+        CDPATH='' command cd "$1" && pwd -P   
+    else
+        echo "$(realpath "$(dirname "$1")")/$(basename "$1")"
+    fi
+}
+
+xpy=$(dirname "$(realpath "$0")")/x.py
+
+# On Windows, `py -3` sometimes works. We need to try it first because `python3`
+# sometimes tries to launch the app store on Windows.
+for SEARCH_PYTHON in py python3 python python2; do
+    if python=$(command -v $SEARCH_PYTHON) && [ -x "$python" ]; then
+        if [ $SEARCH_PYTHON = py ]; then
+            extra_arg="-3"
+        else
+            extra_arg=""
+        fi
+        exec "$python" $extra_arg "$xpy" "$@"
+    fi
+done
+echo "$0: error: did not find python installed" >&2
+exit 1