about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock15
-rw-r--r--RELEASES.md7
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs10
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs5
-rw-r--r--compiler/rustc_borrowck/src/region_infer/values.rs1
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs155
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs6
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs10
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs11
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs5
-rw-r--r--compiler/rustc_error_messages/locales/en-US/borrowck.ftl6
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs23
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/explicit.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/utils.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs19
-rw-r--r--compiler/rustc_infer/src/errors/note_and_explain.rs2
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs11
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs6
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs93
-rw-r--r--compiler/rustc_infer/src/infer/equate.rs17
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs17
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs23
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs6
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs1
-rw-r--r--compiler/rustc_infer/src/infer/glb.rs22
-rw-r--r--compiler/rustc_infer/src/infer/lattice.rs11
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs14
-rw-r--r--compiler/rustc_infer/src/infer/lub.rs28
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs1
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs89
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs1
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs1
-rw-r--r--compiler/rustc_infer/src/infer/projection.rs34
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs8
-rw-r--r--compiler/rustc_infer/src/infer/sub.rs18
-rw-r--r--compiler/rustc_infer/src/traits/util.rs3
-rw-r--r--compiler/rustc_interface/src/callbacks.rs2
-rw-r--r--compiler/rustc_interface/src/passes.rs26
-rw-r--r--compiler/rustc_interface/src/queries.rs27
-rw-r--r--compiler/rustc_lint/src/builtin.rs2
-rw-r--r--compiler/rustc_log/src/lib.rs12
-rw-r--r--compiler/rustc_middle/src/dep_graph/mod.rs2
-rw-r--r--compiler/rustc_middle/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/ty/context.rs40
-rw-r--r--compiler/rustc_middle/src/ty/context/tls.rs9
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs16
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs37
-rw-r--r--compiler/rustc_middle/src/ty/opaque_types.rs9
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs4
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs1
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs7
-rw-r--r--compiler/rustc_mir_transform/src/large_enums.rs298
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs3
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs2
-rw-r--r--compiler/rustc_resolve/src/late.rs1
-rw-r--r--compiler/rustc_session/src/options.rs10
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs1
-rw-r--r--compiler/rustc_trait_selection/Cargo.toml1
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly.rs8
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs5
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs114
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs49
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs4
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs7
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs88
-rw-r--r--compiler/rustc_traits/src/lib.rs1
-rw-r--r--compiler/rustc_traits/src/normalize_erasing_regions.rs1
-rw-r--r--compiler/rustc_type_ir/src/sty.rs17
-rw-r--r--library/core/src/alloc/global.rs9
-rw-r--r--library/std/src/sys/unix/args.rs28
-rw-r--r--library/std/src/sys/wasi/os.rs8
-rw-r--r--library/std/src/sys/windows/fs.rs2
-rw-r--r--src/bootstrap/download.rs13
-rw-r--r--src/doc/rustc/src/codegen-options/index.md64
-rw-r--r--src/librustdoc/clean/mod.rs3
-rw-r--r--src/librustdoc/html/render/context.rs9
-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/static/js/main.js6
-rw-r--r--src/librustdoc/lib.rs4
-rw-r--r--src/tools/clippy/CHANGELOG.md1
-rw-r--r--src/tools/clippy/Cargo.toml1
-rw-r--r--src/tools/clippy/README.md2
-rw-r--r--src/tools/clippy/book/src/README.md2
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md26
-rw-r--r--src/tools/clippy/clippy_dev/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_dev/src/main.rs127
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml2
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs53
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/excessive_bools.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs178
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs253
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_assert.rs97
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs89
-rw-r--r--src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_block.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_io_amount.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/conf.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/dump_hir.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs15
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs8
-rw-r--r--src/tools/clippy/lintcheck/Cargo.toml4
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr16
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/macro_rules.rs19
-rw-r--r--src/tools/clippy/tests/ui/bool_assert_comparison.fixed38
-rw-r--r--src/tools/clippy/tests/ui/bool_assert_comparison.rs10
-rw-r--r--src/tools/clippy/tests/ui/bool_assert_comparison.stderr126
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-2774.stderr5
-rw-r--r--src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr5
-rw-r--r--src/tools/clippy/tests/ui/extra_unused_type_parameters.rs69
-rw-r--r--src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr59
-rw-r--r--src/tools/clippy/tests/ui/len_without_is_empty.rs46
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2018.fixed35
-rw-r--r--src/tools/clippy/tests/ui/manual_assert.edition2018.stderr67
-rw-r--r--src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed2
-rw-r--r--src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr8
-rw-r--r--src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs9
-rw-r--r--src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr40
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.fixed538
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.rs42
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.stderr391
-rw-r--r--src/tools/clippy/tests/ui/needless_range_loop.stderr8
-rw-r--r--src/tools/clippy/tests/ui/new_without_default.rs7
-rw-r--r--src/tools/clippy/tests/ui/new_without_default.stderr14
-rw-r--r--src/tools/clippy/tests/ui/redundant_field_names.fixed2
-rw-r--r--src/tools/clippy/tests/ui/redundant_field_names.rs2
-rw-r--r--src/tools/clippy/tests/ui/regex.rs4
-rw-r--r--src/tools/clippy/tests/ui/regex.stderr66
-rw-r--r--src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed4
-rw-r--r--src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs4
-rw-r--r--src/tools/clippy/tests/ui/suspicious_to_owned.stderr43
-rw-r--r--src/tools/clippy/tests/ui/type_repetition_in_bounds.rs1
-rw-r--r--src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr8
-rw-r--r--src/tools/clippy/tests/ui/unused_io_amount.rs8
-rw-r--r--src/tools/clippy/tests/ui/unused_io_amount.stderr44
-rw-r--r--src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed2
-rw-r--r--src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr4
-rw-r--r--tests/codegen/issue-75659.rs2
-rw-r--r--tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff68
-rw-r--r--tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff68
-rw-r--r--tests/mir-opt/enum_opt.invalid.EnumSizeOpt.32bit.diff28
-rw-r--r--tests/mir-opt/enum_opt.invalid.EnumSizeOpt.64bit.diff28
-rw-r--r--tests/mir-opt/enum_opt.rs86
-rw-r--r--tests/mir-opt/enum_opt.trunc.EnumSizeOpt.32bit.diff37
-rw-r--r--tests/mir-opt/enum_opt.trunc.EnumSizeOpt.64bit.diff37
-rw-r--r--tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff68
-rw-r--r--tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff68
-rw-r--r--tests/run-make/no-input-file/Makefile4
-rw-r--r--tests/run-make/no-input-file/no-input-file.stderr2
-rw-r--r--tests/rustdoc/markdown-summaries.rs27
-rw-r--r--tests/ui/associated-type-bounds/elision.stderr4
-rw-r--r--tests/ui/async-await/async-fn-path-elision.stderr1
-rw-r--r--tests/ui/const-generics/const-param-elided-lifetime.min.stderr10
-rw-r--r--tests/ui/const-generics/const-param-elided-lifetime.rs10
-rw-r--r--tests/ui/const-generics/issues/issue-56445-1.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-56445-1.rs2
-rw-r--r--tests/ui/const-generics/wrong-normalization.rs19
-rw-r--r--tests/ui/const-generics/wrong-normalization.stderr11
-rw-r--r--tests/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs1
-rw-r--r--tests/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr18
-rw-r--r--tests/ui/impl-header-lifetime-elision/path-elided.stderr1
-rw-r--r--tests/ui/impl-header-lifetime-elision/trait-elided.stderr1
-rw-r--r--tests/ui/impl-trait/in-trait/signature-mismatch.stderr4
-rw-r--r--tests/ui/impl-trait/nested-return-type2.rs3
-rw-r--r--tests/ui/impl-trait/nested-return-type2.stderr2
-rw-r--r--tests/ui/inference/issue-107090.rs10
-rw-r--r--tests/ui/inference/issue-107090.stderr115
-rw-r--r--tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.rs19
-rw-r--r--tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr11
-rw-r--r--tests/ui/issues/issue-10412.stderr1
-rw-r--r--tests/ui/issues/issue-16966.stderr6
-rw-r--r--tests/ui/lifetimes/issue-26638.stderr4
-rw-r--r--tests/ui/lifetimes/issue-69314.fixed22
-rw-r--r--tests/ui/lifetimes/issue-69314.rs22
-rw-r--r--tests/ui/lifetimes/issue-69314.stderr26
-rw-r--r--tests/ui/lifetimes/unusual-rib-combinations.rs2
-rw-r--r--tests/ui/lifetimes/unusual-rib-combinations.stderr2
-rw-r--r--tests/ui/lint/reasons-forbidden.rs2
-rw-r--r--tests/ui/mismatched_types/issue-74918-missing-lifetime.stderr4
-rw-r--r--tests/ui/nll/issue-52057.rs4
-rw-r--r--tests/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs2
-rw-r--r--tests/ui/parser/missing-closing-angle-bracket-eq-constraint.rs2
-rw-r--r--tests/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr12
-rw-r--r--tests/ui/rfc-2091-track-caller/call-chain.rs2
-rw-r--r--tests/ui/suggestions/issue-104961.fixed16
-rw-r--r--tests/ui/suggestions/issue-104961.rs16
-rw-r--r--tests/ui/suggestions/issue-104961.stderr37
-rw-r--r--tests/ui/suggestions/suggest-call-on-pat-mismatch.rs16
-rw-r--r--tests/ui/suggestions/suggest-call-on-pat-mismatch.stderr33
-rw-r--r--tests/ui/traits/new-solver/alias_eq_cant_be_furthur_normalized.rs29
-rw-r--r--tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs45
-rw-r--r--tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.stderr9
-rw-r--r--tests/ui/traits/new-solver/alias_eq_simple.rs22
-rw-r--r--tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.rs20
-rw-r--r--tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.stderr9
-rw-r--r--tests/ui/traits/new-solver/normalizes_to_ignores_unnormalizable_candidate.rs40
-rw-r--r--tests/ui/traits/new-solver/normalizes_to_ignores_unnormalizable_candidate.self_infer.stderr14
-rw-r--r--tests/ui/traits/new-solver/param-candidate-doesnt-shadow-project.rs25
-rw-r--r--tests/ui/traits/new-solver/provisional-result-done.rs2
-rw-r--r--tests/ui/traits/new-solver/provisional-result-done.stderr11
-rw-r--r--tests/ui/traits/new-solver/two-projection-param-candidates-are-ambiguous.rs30
-rw-r--r--tests/ui/traits/new-solver/two-projection-param-candidates-are-ambiguous.stderr16
-rw-r--r--tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr2
-rw-r--r--tests/ui/type/type-check/cannot_infer_local_or_vec.stderr6
-rw-r--r--tests/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr6
-rw-r--r--tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.rs2
-rw-r--r--tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr25
245 files changed, 4485 insertions, 1294 deletions
diff --git a/Cargo.lock b/Cargo.lock
index ed5065d7611..6beefb3870f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -449,7 +449,7 @@ dependencies = [
 name = "cargo-miri"
 version = "0.1.0"
 dependencies = [
- "cargo_metadata 0.15.0",
+ "cargo_metadata 0.15.3",
  "directories",
  "rustc-build-sysroot",
  "rustc-workspace-hack",
@@ -540,15 +540,16 @@ dependencies = [
 
 [[package]]
 name = "cargo_metadata"
-version = "0.15.0"
+version = "0.15.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36"
+checksum = "08a1ec454bc3eead8719cb56e15dbbfecdbc14e4b3a3ae4936cc6e31f5fc0d07"
 dependencies = [
  "camino",
  "cargo-platform 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "semver",
  "serde",
  "serde_json",
+ "thiserror",
 ]
 
 [[package]]
@@ -732,6 +733,7 @@ dependencies = [
 name = "clippy"
 version = "0.1.69"
 dependencies = [
+ "clap 4.1.4",
  "clippy_lints",
  "clippy_utils",
  "compiletest_rs",
@@ -762,7 +764,7 @@ name = "clippy_dev"
 version = "0.0.1"
 dependencies = [
  "aho-corasick",
- "clap 3.2.20",
+ "clap 4.1.4",
  "indoc",
  "itertools",
  "opener",
@@ -774,7 +776,7 @@ dependencies = [
 name = "clippy_lints"
 version = "0.1.69"
 dependencies = [
- "cargo_metadata 0.14.0",
+ "cargo_metadata 0.15.3",
  "clippy_utils",
  "declare_clippy_lint",
  "if_chain",
@@ -4774,6 +4776,7 @@ checksum = "8ba09476327c4b70ccefb6180f046ef588c26a24cf5d269a9feba316eb4f029f"
 name = "rustc_trait_selection"
 version = "0.0.0"
 dependencies = [
+ "itertools",
  "rustc_ast",
  "rustc_attr",
  "rustc_data_structures",
@@ -5864,7 +5867,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "54ddb6f31025943e2f9d59237f433711c461a43d9415974c3eb3a4902edc1c1f"
 dependencies = [
  "bstr 1.0.1",
- "cargo_metadata 0.15.0",
+ "cargo_metadata 0.15.3",
  "color-eyre",
  "colored",
  "crossbeam-channel",
diff --git a/RELEASES.md b/RELEASES.md
index a63d4e8a043..00d0171de6d 100644
--- a/RELEASES.md
+++ b/RELEASES.md
@@ -1,3 +1,10 @@
+Version 1.67.1 (2023-02-09)
+===========================
+
+- [Fix interoperability with thin archives.](https://github.com/rust-lang/rust/pull/107360)
+- [Fix an internal error in the compiler build process.](https://github.com/rust-lang/rust/pull/105624)
+- [Downgrade `clippy::uninlined_format_args` to pedantic.](https://github.com/rust-lang/rust-clippy/pull/10265)
+
 Version 1.67.0 (2023-01-26)
 ==========================
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 2440f20502a..237e063d8d1 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -343,11 +343,11 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                     let note = match closure_kind_ty.to_opt_closure_kind() {
                         Some(ty::ClosureKind::Fn) => {
                             "closure implements `Fn`, so references to captured variables \
-                                can't escape the closure"
+                             can't escape the closure"
                         }
                         Some(ty::ClosureKind::FnMut) => {
                             "closure implements `FnMut`, so references to captured variables \
-                                can't escape the closure"
+                             can't escape the closure"
                         }
                         Some(ty::ClosureKind::FnOnce) => {
                             bug!("BrEnv in a `FnOnce` closure");
@@ -364,7 +364,11 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                 ty::BoundRegionKind::BrAnon(..) => None,
             },
 
-            ty::ReLateBound(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => None,
+            ty::ReLateBound(..)
+            | ty::ReVar(..)
+            | ty::RePlaceholder(..)
+            | ty::ReErased
+            | ty::ReError(_) => None,
         }
     }
 
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index e0e814cfc0a..c7b22d5f2e6 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -91,11 +91,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                     }
                     None => {
                         subst_regions.push(vid);
-                        infcx.tcx.sess.delay_span_bug(
+                        infcx.tcx.re_error_with_message(
                             concrete_type.span,
                             "opaque type with non-universal region substs",
-                        );
-                        infcx.tcx.lifetimes.re_static
+                        )
                     }
                 }
             };
diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs
index c3dfeedc205..6a3748fded5 100644
--- a/compiler/rustc_borrowck/src/region_infer/values.rs
+++ b/compiler/rustc_borrowck/src/region_infer/values.rs
@@ -187,6 +187,7 @@ pub(crate) struct PlaceholderIndices {
 }
 
 impl PlaceholderIndices {
+    /// Returns the `PlaceholderIndex` for the inserted `PlaceholderRegion`
     pub(crate) fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex {
         let (index, _) = self.indices.insert_full(placeholder);
         index.into()
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 82ff862479e..2dd24fe0340 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -8,6 +8,7 @@ use rustc_infer::infer::InferCtxt;
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::query::OutlivesBound;
 use rustc_middle::ty::{self, RegionVid, Ty};
+use rustc_span::Span;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
 use std::rc::Rc;
 use type_op::TypeOpOutput;
@@ -217,8 +218,27 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
         self.inverse_outlives.add(fr_b, fr_a);
     }
 
+    #[instrument(level = "debug", skip(self))]
     pub(crate) fn create(mut self) -> CreateResult<'tcx> {
         let span = self.infcx.tcx.def_span(self.universal_regions.defining_ty.def_id());
+
+        // Insert the facts we know from the predicates. Why? Why not.
+        let param_env = self.param_env;
+        self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env));
+
+        // - outlives is reflexive, so `'r: 'r` for every region `'r`
+        // - `'static: 'r` for every region `'r`
+        // - `'r: 'fn_body` for every (other) universally quantified
+        //   region `'r`, all of which are provided by our caller
+        let fr_static = self.universal_regions.fr_static;
+        let fr_fn_body = self.universal_regions.fr_fn_body;
+        for fr in self.universal_regions.universal_regions() {
+            debug!("build: relating free region {:?} to itself and to 'static", fr);
+            self.relate_universal_regions(fr, fr);
+            self.relate_universal_regions(fr_static, fr);
+            self.relate_universal_regions(fr, fr_fn_body);
+        }
+
         let unnormalized_input_output_tys = self
             .universal_regions
             .unnormalized_input_tys
@@ -236,78 +256,58 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
         //   the `relations` is built.
         let mut normalized_inputs_and_output =
             Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
-        let constraint_sets: Vec<_> = unnormalized_input_output_tys
-            .flat_map(|ty| {
-                debug!("build: input_or_output={:?}", ty);
-                // 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))
-                    .fully_perform(self.infcx)
-                    .unwrap_or_else(|_| {
-                        let reported = self
-                            .infcx
-                            .tcx
-                            .sess
-                            .delay_span_bug(span, &format!("failed to normalize {:?}", ty));
-                        TypeOpOutput {
-                            output: self.infcx.tcx.ty_error_with_guaranteed(reported),
-                            constraints: None,
-                            error_info: None,
-                        }
-                    });
-                // Note: we need this in examples like
-                // ```
-                // trait Foo {
-                //   type Bar;
-                //   fn foo(&self) -> &Self::Bar;
-                // }
-                // impl Foo for () {
-                //   type Bar = ();
-                //   fn foo(&self) -> &() {}
-                // }
-                // ```
-                // Both &Self::Bar and &() are WF
-                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_implied1).chain(constraints_implied2)
-            })
-            .collect();
+        let mut constraints = vec![];
+        for ty in unnormalized_input_output_tys {
+            debug!("build: input_or_output={:?}", ty);
+            // We add implied bounds from both the unnormalized and normalized ty.
+            // See issue #87748
+            let constraints_unnorm = self.add_implied_bounds(ty);
+            if let Some(c) = constraints_unnorm {
+                constraints.push(c)
+            }
+            let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self
+                .param_env
+                .and(type_op::normalize::Normalize::new(ty))
+                .fully_perform(self.infcx)
+                .unwrap_or_else(|_| {
+                    self.infcx
+                        .tcx
+                        .sess
+                        .delay_span_bug(span, &format!("failed to normalize {:?}", ty));
+                    TypeOpOutput {
+                        output: self.infcx.tcx.ty_error(),
+                        constraints: None,
+                        error_info: None,
+                    }
+                });
+            if let Some(c) = constraints_normalize {
+                constraints.push(c)
+            }
 
-        // Insert the facts we know from the predicates. Why? Why not.
-        let param_env = self.param_env;
-        self.add_outlives_bounds(outlives::explicit_outlives_bounds(param_env));
+            // Note: we need this in examples like
+            // ```
+            // trait Foo {
+            //   type Bar;
+            //   fn foo(&self) -> &Self::Bar;
+            // }
+            // impl Foo for () {
+            //   type Bar = ();
+            //   fn foo(&self) ->&() {}
+            // }
+            // ```
+            // Both &Self::Bar and &() are WF
+            if ty != norm_ty {
+                let constraints_norm = self.add_implied_bounds(norm_ty);
+                if let Some(c) = constraints_norm {
+                    constraints.push(c)
+                }
+            }
 
-        // Finally:
-        // - outlives is reflexive, so `'r: 'r` for every region `'r`
-        // - `'static: 'r` for every region `'r`
-        // - `'r: 'fn_body` for every (other) universally quantified
-        //   region `'r`, all of which are provided by our caller
-        let fr_static = self.universal_regions.fr_static;
-        let fr_fn_body = self.universal_regions.fr_fn_body;
-        for fr in self.universal_regions.universal_regions() {
-            debug!("build: relating free region {:?} to itself and to 'static", fr);
-            self.relate_universal_regions(fr, fr);
-            self.relate_universal_regions(fr_static, fr);
-            self.relate_universal_regions(fr, fr_fn_body);
+            normalized_inputs_and_output.push(norm_ty);
         }
 
-        for data in &constraint_sets {
-            constraint_conversion::ConstraintConversion::new(
-                self.infcx,
-                &self.universal_regions,
-                &self.region_bound_pairs,
-                self.implicit_region_bound,
-                self.param_env,
-                Locations::All(span),
-                span,
-                ConstraintCategory::Internal,
-                &mut self.constraints,
-            )
-            .convert_all(data);
+        for c in constraints {
+            self.push_region_constraints(c, span);
         }
 
         CreateResult {
@@ -321,6 +321,24 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
         }
     }
 
+    #[instrument(skip(self, data), level = "debug")]
+    fn push_region_constraints(&mut self, data: &QueryRegionConstraints<'tcx>, span: Span) {
+        debug!("constraints generated: {:#?}", data);
+
+        constraint_conversion::ConstraintConversion::new(
+            self.infcx,
+            &self.universal_regions,
+            &self.region_bound_pairs,
+            self.implicit_region_bound,
+            self.param_env,
+            Locations::All(span),
+            span,
+            ConstraintCategory::Internal,
+            &mut self.constraints,
+        )
+        .convert_all(data);
+    }
+
     /// Update the type of a single local, which should represent
     /// either the return type of the MIR or one of its arguments. At
     /// the same time, compute and add any implied bounds that come
@@ -332,6 +350,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
             .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
             .fully_perform(self.infcx)
             .unwrap_or_else(|_| bug!("failed to compute implied bounds {:?}", ty));
+        debug!(?bounds, ?constraints);
         self.add_outlives_bounds(bounds);
         constraints
     }
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 5b52846562f..64c96281ed9 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -910,6 +910,8 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> {
 }
 
 impl<'tcx> MirTypeckRegionConstraints<'tcx> {
+    /// Creates a `Region` for a given `PlaceholderRegion`, or returns the
+    /// region that corresponds to a previously created one.
     fn placeholder_region(
         &mut self,
         infcx: &InferCtxt<'tcx>,
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index b2702eafd33..8dd06187877 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -1,4 +1,4 @@
-use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
+use rustc_infer::infer::nll_relate::{TypeRelating, TypeRelatingDelegate};
 use rustc_infer::infer::NllRegionVariableOrigin;
 use rustc_infer::traits::PredicateObligations;
 use rustc_middle::mir::ConstraintCategory;
@@ -140,10 +140,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
         );
     }
 
-    fn normalization() -> NormalizationStrategy {
-        NormalizationStrategy::Eager
-    }
-
     fn forbid_inference_vars() -> bool {
         true
     }
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 5380913f5c8..56930c89b2c 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -167,6 +167,9 @@ struct UniversalRegionIndices<'tcx> {
     /// contains an entry for `ReStatic` -- it might be nice to just
     /// use a substs, and then handle `ReStatic` another way.
     indices: FxHashMap<ty::Region<'tcx>, RegionVid>,
+
+    /// The vid assigned to `'static`. Used only for diagnostics.
+    pub fr_static: RegionVid,
 }
 
 #[derive(Debug, PartialEq)]
@@ -609,7 +612,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
         let subst_mapping =
             iter::zip(identity_substs.regions(), fr_substs.regions().map(|r| r.to_region_vid()));
 
-        UniversalRegionIndices { indices: global_mapping.chain(subst_mapping).collect() }
+        UniversalRegionIndices { indices: global_mapping.chain(subst_mapping).collect(), fr_static }
     }
 
     fn compute_inputs_and_output(
@@ -821,6 +824,11 @@ impl<'tcx> UniversalRegionIndices<'tcx> {
     pub fn to_region_vid(&self, r: ty::Region<'tcx>) -> RegionVid {
         if let ty::ReVar(..) = *r {
             r.to_region_vid()
+        } else if r.is_error() {
+            // We use the `'static` `RegionVid` because `ReError` doesn't actually exist in the
+            // `UniversalRegionIndices`. This is fine because 1) it is a fallback only used if
+            // errors are being emitted and 2) it leaves the happy path unaffected.
+            self.fr_static
         } else {
             *self
                 .indices
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 18e01567ca3..b4a49e1df61 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -54,7 +54,7 @@ fn eval_body_using_ecx<'mir, 'tcx>(
 
     trace!(
         "eval_body_using_ecx: pushing stack frame for global: {}{}",
-        with_no_trimmed_paths!(ty::tls::with(|tcx| tcx.def_path_str(cid.instance.def_id()))),
+        with_no_trimmed_paths!(ecx.tcx.def_path_str(cid.instance.def_id())),
         cid.promoted.map_or_else(String::new, |p| format!("::promoted[{:?}]", p))
     );
 
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 76b316cdf0c..56c60d59d28 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -13,7 +13,7 @@ use rustc_middle::mir::{
     RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator,
     TerminatorKind, UnOp, START_BLOCK,
 };
-use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitable};
 use rustc_mir_dataflow::impls::MaybeStorageLive;
 use rustc_mir_dataflow::storage::always_storage_live_locals;
 use rustc_mir_dataflow::{Analysis, ResultsCursor};
@@ -231,6 +231,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             return true;
         }
 
+        // We sometimes have to use `defining_opaque_types` for subtyping
+        // to succeed here and figuring out how exactly that should work
+        // is annoying. It is harmless enough to just not validate anything
+        // in that case. We still check this after analysis as all opque
+        // types have been revealed at this point.
+        if (src, dest).has_opaque_types() {
+            return true;
+        }
+
         crate::util::is_subtype(self.tcx, self.param_env, src, dest)
     }
 }
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index bdf2978cee2..37967bfdff5 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -624,7 +624,10 @@ fn print_crate_info(
                 println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap());
             }
             FileNames | CrateName => {
-                let attrs = attrs.as_ref().unwrap();
+                let Some(attrs) = attrs.as_ref() else {
+                    // no crate attributes, print out an error and exit
+                    return Compilation::Continue;
+                };
                 let t_outputs = rustc_interface::util::build_output_filenames(attrs, sess);
                 let id = rustc_session::output::find_crate_name(sess, attrs);
                 if *req == PrintRequest::CrateName {
diff --git a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl
index fe77cf23e8f..a3b6b5e8138 100644
--- a/compiler/rustc_error_messages/locales/en-US/borrowck.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/borrowck.ftl
@@ -18,7 +18,7 @@ borrowck_generic_does_not_live_long_enough =
     `{$kind}` does not live long enough
 
 borrowck_move_borrowed =
-    cannot move out of `{$desc}` beacause it is borrowed
+    cannot move out of `{$desc}` because it is borrowed
 
 borrowck_var_does_not_need_mut =
     variable does not need to be mutable
@@ -87,10 +87,10 @@ borrowck_use_due_to_use_closure =
     use occurs due to use in closure
 
 borrowck_assign_due_to_use_closure =
-    assign occurs due to use in closure
+    assignment occurs due to use in closure
 
 borrowck_assign_part_due_to_use_closure =
-    assign to part occurs due to use in closure
+    assignment to part occurs due to use in closure
 
 borrowck_capture_immute =
     capture is immutable because of use here
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 3d5f189e233..75cc7cbaa60 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -263,11 +263,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     // elision. `resolve_lifetime` should have
                     // reported an error in this case -- but if
                     // not, let's error out.
-                    tcx.sess.delay_span_bug(lifetime.ident.span, "unelided lifetime in signature");
-
-                    // Supply some dummy value. We don't have an
-                    // `re_error`, annoyingly, so use `'static`.
-                    tcx.lifetimes.re_static
+                    tcx.re_error_with_message(lifetime.ident.span, "unelided lifetime in signature")
                 })
             }
         }
@@ -481,11 +477,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                             debug!(?param, "unelided lifetime in signature");
 
                             // This indicates an illegal lifetime in a non-assoc-trait position
-                            tcx.sess.delay_span_bug(self.span, "unelided lifetime in signature");
-
-                            // Supply some dummy value. We don't have an
-                            // `re_error`, annoyingly, so use `'static`.
-                            tcx.lifetimes.re_static
+                            tcx.re_error_with_message(self.span, "unelided lifetime in signature")
                         })
                         .into(),
                     GenericParamDefKind::Type { has_default, .. } => {
@@ -1328,6 +1320,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     ty::Clause::RegionOutlives(_) => bug!(),
                 },
                 ty::PredicateKind::WellFormed(_)
+                | ty::PredicateKind::AliasEq(..)
                 | ty::PredicateKind::ObjectSafe(_)
                 | ty::PredicateKind::ClosureKind(_, _, _)
                 | ty::PredicateKind::Subtype(_)
@@ -1622,14 +1615,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                             "the lifetime bound for this object type cannot be deduced \
                              from context; please supply an explicit bound"
                         );
-                        if borrowed {
+                        let e = if borrowed {
                             // We will have already emitted an error E0106 complaining about a
                             // missing named lifetime in `&dyn Trait`, so we elide this one.
-                            err.delay_as_bug();
+                            err.delay_as_bug()
                         } else {
-                            err.emit();
-                        }
-                        tcx.lifetimes.re_static
+                            err.emit()
+                        };
+                        tcx.re_error(e)
                     })
                 }
             })
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 236e36f28ca..640920638a7 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -786,13 +786,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
                     }
                     let Some(ty::ReEarlyBound(e)) = map.get(&region.into()).map(|r| r.expect_region().kind())
                     else {
-                        tcx
-                            .sess
-                            .delay_span_bug(
-                                return_span,
-                                "expected ReFree to map to ReEarlyBound"
-                            );
-                        return tcx.lifetimes.re_static;
+                        return tcx.re_error_with_message(return_span, "expected ReFree to map to ReEarlyBound")
                     };
                     tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
                         def_id: e.def_id,
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index a5dcfab9be8..02f77f9d6af 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -517,6 +517,7 @@ fn trait_predicate_kind<'tcx>(
         ty::PredicateKind::Clause(ty::Clause::RegionOutlives(_))
         | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_))
         | ty::PredicateKind::Clause(ty::Clause::Projection(_))
+        | ty::PredicateKind::AliasEq(..)
         | ty::PredicateKind::WellFormed(_)
         | ty::PredicateKind::Subtype(_)
         | ty::PredicateKind::Coerce(_)
diff --git a/compiler/rustc_hir_analysis/src/outlives/explicit.rs b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
index 663f1c49db7..ecd6849426d 100644
--- a/compiler/rustc_hir_analysis/src/outlives/explicit.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/explicit.rs
@@ -55,6 +55,7 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> {
                     ty::PredicateKind::Clause(ty::Clause::Trait(..))
                     | ty::PredicateKind::Clause(ty::Clause::Projection(..))
                     | ty::PredicateKind::WellFormed(..)
+                    | ty::PredicateKind::AliasEq(..)
                     | ty::PredicateKind::ObjectSafe(..)
                     | ty::PredicateKind::ClosureKind(..)
                     | ty::PredicateKind::Subtype(..)
diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs
index 9459c5f54ab..c5c5f63a108 100644
--- a/compiler/rustc_hir_analysis/src/outlives/utils.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs
@@ -170,6 +170,8 @@ fn is_free_region(region: Region<'_>) -> bool {
         // ignore it. We can't put it on the struct header anyway.
         ty::ReLateBound(..) => false,
 
+        ty::ReError(_) => false,
+
         // These regions don't appear in types from type declarations:
         ty::ReErased | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReFree(..) => {
             bug!("unexpected region in outlives inference: {:?}", region);
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index 165782f209a..b0cf0387f87 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -409,6 +409,8 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
                 // way early-bound regions do, so we skip them here.
             }
 
+            ty::ReError(_) => {}
+
             ty::ReFree(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => {
                 // We don't expect to see anything but 'static or bound
                 // regions when visiting member types or method types.
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 88fb2653586..e19ef2ff3bf 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -41,7 +41,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // #55810: Type check patterns first so we get types for all bindings.
         let scrut_span = scrut.span.find_ancestor_inside(expr.span).unwrap_or(scrut.span);
         for arm in arms {
-            self.check_pat_top(&arm.pat, scrutinee_ty, Some(scrut_span), true);
+            self.check_pat_top(&arm.pat, scrutinee_ty, Some(scrut_span), Some(scrut));
         }
 
         // Now typecheck the blocks.
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 1c70c1b71e7..cc515e6c853 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -90,7 +90,7 @@ pub(super) fn check_fn<'a, 'tcx>(
     for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() {
         // Check the pattern.
         let ty_span = try { inputs_hir?.get(idx)?.span };
-        fcx.check_pat_top(&param.pat, param_ty, ty_span, false);
+        fcx.check_pat_top(&param.pat, param_ty, ty_span, None);
 
         // Check that argument is Sized.
         // The check for a non-trivial pattern is a hack to avoid duplicate warnings
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index e84b3de124c..52c2dabee29 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -669,6 +669,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
                 | ty::PredicateKind::WellFormed(..)
                 | ty::PredicateKind::ObjectSafe(..)
+                | ty::PredicateKind::AliasEq(..)
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
                 // N.B., this predicate is created by breaking down a
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 2a1265600de..9c7a84ce198 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1330,11 +1330,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Does the expected pattern type originate from an expression and what is the span?
         let (origin_expr, ty_span) = match (decl.ty, decl.init) {
-            (Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type.
+            (Some(ty), _) => (None, Some(ty.span)), // Bias towards the explicit user type.
             (_, Some(init)) => {
-                (true, Some(init.span.find_ancestor_inside(decl.span).unwrap_or(init.span)))
+                (Some(init), Some(init.span.find_ancestor_inside(decl.span).unwrap_or(init.span)))
             } // No explicit type; so use the scrutinee.
-            _ => (false, None), // We have `let $pat;`, so the expected type is unconstrained.
+            _ => (None, None), // We have `let $pat;`, so the expected type is unconstrained.
         };
 
         // Type check the pattern. Override if necessary to avoid knock-on errors.
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 0cf58179ec2..16b0d48002e 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -837,6 +837,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
                 | ty::PredicateKind::Ambiguous
+                | ty::PredicateKind::AliasEq(..)
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
             }
         });
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 46799245222..52236ae56ee 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -46,7 +46,7 @@ struct TopInfo<'tcx> {
     /// Was the origin of the `span` from a scrutinee expression?
     ///
     /// Otherwise there is no scrutinee and it could be e.g. from the type of a formal parameter.
-    origin_expr: bool,
+    origin_expr: Option<&'tcx hir::Expr<'tcx>>,
     /// The span giving rise to the `expected` type, if one could be provided.
     ///
     /// If `origin_expr` is `true`, then this is the span of the scrutinee as in:
@@ -74,7 +74,8 @@ struct TopInfo<'tcx> {
 
 impl<'tcx> FnCtxt<'_, 'tcx> {
     fn pattern_cause(&self, ti: TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
-        let code = Pattern { span: ti.span, root_ty: ti.expected, origin_expr: ti.origin_expr };
+        let code =
+            Pattern { span: ti.span, root_ty: ti.expected, origin_expr: ti.origin_expr.is_some() };
         self.cause(cause_span, code)
     }
 
@@ -85,7 +86,14 @@ impl<'tcx> FnCtxt<'_, 'tcx> {
         actual: Ty<'tcx>,
         ti: TopInfo<'tcx>,
     ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
-        self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)
+        let mut diag =
+            self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)?;
+        if let Some(expr) = ti.origin_expr {
+            self.suggest_fn_call(&mut diag, expr, expected, |output| {
+                self.can_eq(self.param_env, output, actual).is_ok()
+            });
+        }
+        Some(diag)
     }
 
     fn demand_eqtype_pat(
@@ -127,7 +135,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         pat: &'tcx Pat<'tcx>,
         expected: Ty<'tcx>,
         span: Option<Span>,
-        origin_expr: bool,
+        origin_expr: Option<&'tcx hir::Expr<'tcx>>,
     ) {
         let info = TopInfo { expected, origin_expr, span };
         self.check_pat(pat, expected, INITIAL_BM, info);
@@ -2146,7 +2154,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             err.help("the semantics of slice patterns changed recently; see issue #62254");
         } else if self.autoderef(span, expected_ty)
             .any(|(ty, _)| matches!(ty.kind(), ty::Slice(..) | ty::Array(..)))
-            && let (Some(span), true) = (ti.span, ti.origin_expr)
+            && let Some(span) = ti.span
+            && let Some(_) = ti.origin_expr
             && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
         {
             let ty = self.resolve_vars_if_possible(ti.expected);
diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs
index 7aaa5ce2f42..5d861a78af8 100644
--- a/compiler/rustc_infer/src/errors/note_and_explain.rs
+++ b/compiler/rustc_infer/src/errors/note_and_explain.rs
@@ -31,6 +31,8 @@ impl<'a> DescriptionCtx<'a> {
 
             ty::RePlaceholder(_) => return None,
 
+            ty::ReError(_) => return None,
+
             // FIXME(#13998) RePlaceholder should probably print like
             // ReFree rather than dumping Debug output on the user.
             //
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 87c6dfad5fa..f1b32cd941e 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -203,12 +203,10 @@ impl CanonicalizeMode for CanonicalizeQueryResponse {
                 // rust-lang/rust#57464: `impl Trait` can leak local
                 // scopes (in manner violating typeck). Therefore, use
                 // `delay_span_bug` to allow type error over an ICE.
-                ty::tls::with(|tcx| {
-                    tcx.sess.delay_span_bug(
-                        rustc_span::DUMMY_SP,
-                        &format!("unexpected region in query response: `{:?}`", r),
-                    );
-                });
+                canonicalizer.tcx.sess.delay_span_bug(
+                    rustc_span::DUMMY_SP,
+                    &format!("unexpected region in query response: `{:?}`", r),
+                );
                 r
             }
         }
@@ -371,6 +369,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
 
             ty::ReStatic
             | ty::ReEarlyBound(..)
+            | ty::ReError(_)
             | ty::ReFree(_)
             | ty::RePlaceholder(..)
             | ty::ReErased => self.canonicalize_mode.canonicalize_free_region(self, r),
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 7cc9e49b1b6..0c97217bd6a 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -12,7 +12,7 @@ use crate::infer::canonical::{
     Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues,
     QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse,
 };
-use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
+use crate::infer::nll_relate::{TypeRelating, TypeRelatingDelegate};
 use crate::infer::region_constraints::{Constraint, RegionConstraintData};
 use crate::infer::{InferCtxt, InferOk, InferResult, NllRegionVariableOrigin};
 use crate::traits::query::{Fallible, NoSolution};
@@ -717,10 +717,6 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for QueryTypeRelatingDelegate<'_, 'tcx> {
         });
     }
 
-    fn normalization() -> NormalizationStrategy {
-        NormalizationStrategy::Eager
-    }
-
     fn forbid_inference_vars() -> bool {
         true
     }
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index a567b6acdbe..4da2a674144 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -38,8 +38,8 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{
-    self, FallibleTypeFolder, InferConst, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
-    TypeVisitable,
+    self, AliasKind, FallibleTypeFolder, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable,
+    TypeSuperFoldable, TypeVisitable,
 };
 use rustc_middle::ty::{IntType, UintType};
 use rustc_span::{Span, DUMMY_SP};
@@ -74,7 +74,7 @@ impl<'tcx> InferCtxt<'tcx> {
         b: Ty<'tcx>,
     ) -> RelateResult<'tcx, Ty<'tcx>>
     where
-        R: TypeRelation<'tcx>,
+        R: ObligationEmittingRelation<'tcx>,
     {
         let a_is_expected = relation.a_is_expected();
 
@@ -122,6 +122,15 @@ impl<'tcx> InferCtxt<'tcx> {
                 Err(TypeError::Sorts(ty::relate::expected_found(relation, a, b)))
             }
 
+            (ty::Alias(AliasKind::Projection, _), _) if self.tcx.trait_solver_next() => {
+                relation.register_type_equate_obligation(a.into(), b.into());
+                Ok(b)
+            }
+            (_, ty::Alias(AliasKind::Projection, _)) if self.tcx.trait_solver_next() => {
+                relation.register_type_equate_obligation(b.into(), a.into());
+                Ok(a)
+            }
+
             _ => ty::relate::super_relate_tys(relation, a, b),
         }
     }
@@ -133,7 +142,7 @@ impl<'tcx> InferCtxt<'tcx> {
         b: ty::Const<'tcx>,
     ) -> RelateResult<'tcx, ty::Const<'tcx>>
     where
-        R: ConstEquateRelation<'tcx>,
+        R: ObligationEmittingRelation<'tcx>,
     {
         debug!("{}.consts({:?}, {:?})", relation.tag(), a, b);
         if a == b {
@@ -169,7 +178,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 // FIXME(#59490): Need to remove the leak check to accommodate
                 // escaping bound variables here.
                 if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
-                    relation.const_equate_obligation(a, b);
+                    relation.register_const_equate_obligation(a, b);
                 }
                 return Ok(b);
             }
@@ -177,7 +186,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 // FIXME(#59490): Need to remove the leak check to accommodate
                 // escaping bound variables here.
                 if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
-                    relation.const_equate_obligation(a, b);
+                    relation.register_const_equate_obligation(a, b);
                 }
                 return Ok(a);
             }
@@ -435,32 +444,21 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
         Ok(Generalization { ty, needs_wf })
     }
 
-    pub fn add_const_equate_obligation(
+    pub fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
+        self.obligations.extend(obligations.into_iter());
+    }
+
+    pub fn register_predicates(
         &mut self,
-        a_is_expected: bool,
-        a: ty::Const<'tcx>,
-        b: ty::Const<'tcx>,
+        obligations: impl IntoIterator<Item = impl ToPredicate<'tcx>>,
     ) {
-        let predicate = if a_is_expected {
-            ty::PredicateKind::ConstEquate(a, b)
-        } else {
-            ty::PredicateKind::ConstEquate(b, a)
-        };
-        self.obligations.push(Obligation::new(
-            self.tcx(),
-            self.trace.cause.clone(),
-            self.param_env,
-            ty::Binder::dummy(predicate),
-        ));
+        self.obligations.extend(obligations.into_iter().map(|to_pred| {
+            Obligation::new(self.infcx.tcx, self.trace.cause.clone(), self.param_env, to_pred)
+        }))
     }
 
     pub fn mark_ambiguous(&mut self) {
-        self.obligations.push(Obligation::new(
-            self.tcx(),
-            self.trace.cause.clone(),
-            self.param_env,
-            ty::Binder::dummy(ty::PredicateKind::Ambiguous),
-        ));
+        self.register_predicates([ty::Binder::dummy(ty::PredicateKind::Ambiguous)]);
     }
 }
 
@@ -705,6 +703,10 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
                 return Ok(r);
             }
 
+            ty::ReError(_) => {
+                return Ok(r);
+            }
+
             ty::RePlaceholder(..)
             | ty::ReVar(..)
             | ty::ReStatic
@@ -775,11 +777,42 @@ impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
     }
 }
 
-pub trait ConstEquateRelation<'tcx>: TypeRelation<'tcx> {
+pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
+    /// Register obligations that must hold in order for this relation to hold
+    fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>);
+
+    /// Register predicates that must hold in order for this relation to hold. Uses
+    /// a default obligation cause, [`ObligationEmittingRelation::register_obligations`] should
+    /// be used if control over the obligaton causes is required.
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item = impl ToPredicate<'tcx>>,
+    );
+
     /// Register an obligation that both constants must be equal to each other.
     ///
     /// If they aren't equal then the relation doesn't hold.
-    fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
+    fn register_const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
+        let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
+
+        self.register_predicates([ty::Binder::dummy(if self.tcx().trait_solver_next() {
+            ty::PredicateKind::AliasEq(a.into(), b.into())
+        } else {
+            ty::PredicateKind::ConstEquate(a, b)
+        })]);
+    }
+
+    /// Register an obligation that both types must be equal to each other.
+    ///
+    /// If they aren't equal then the relation doesn't hold.
+    fn register_type_equate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) {
+        let (a, b) = if self.a_is_expected() { (a, b) } else { (b, a) };
+
+        self.register_predicates([ty::Binder::dummy(ty::PredicateKind::AliasEq(
+            a.into(),
+            b.into(),
+        ))]);
+    }
 }
 
 fn int_unification_error<'tcx>(
@@ -861,7 +894,7 @@ impl<'tcx> FallibleTypeFolder<'tcx> for ConstInferUnifier<'_, 'tcx> {
         match *r {
             // Never make variables for regions bound within the type itself,
             // nor for erased regions.
-            ty::ReLateBound(..) | ty::ReErased => {
+            ty::ReLateBound(..) | ty::ReErased | ty::ReError(_) => {
                 return Ok(r);
             }
 
diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs
index 7db4d92a177..742c01efff6 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -1,4 +1,6 @@
-use super::combine::{CombineFields, ConstEquateRelation, RelationDir};
+use crate::traits::PredicateObligations;
+
+use super::combine::{CombineFields, ObligationEmittingRelation, RelationDir};
 use super::Subtype;
 
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
@@ -198,8 +200,15 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
     }
 }
 
-impl<'tcx> ConstEquateRelation<'tcx> for Equate<'_, '_, 'tcx> {
-    fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
-        self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
+impl<'tcx> ObligationEmittingRelation<'tcx> for Equate<'_, '_, 'tcx> {
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item = impl ty::ToPredicate<'tcx>>,
+    ) {
+        self.fields.register_predicates(obligations);
+    }
+
+    fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
+        self.fields.register_obligations(obligations);
     }
 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 86f3174b7b2..88a0d6def5e 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -134,6 +134,8 @@ pub(super) fn note_and_explain_region<'tcx>(
 
         ty::RePlaceholder(_) => return,
 
+        ty::ReError(_) => return,
+
         // FIXME(#13998) RePlaceholder should probably print like
         // ReFree rather than dumping Debug output on the user.
         //
@@ -313,6 +315,9 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
                 )
             }
         }
+        ty::ReError(_) => {
+            err.delay_as_bug();
+        }
         _ => {
             // Ugh. This is a painful case: the hidden region is not one
             // that we can easily summarize or explain. This can happen
@@ -2546,7 +2551,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             );
 
             err.note_expected_found(&"", sup_expected, &"", sup_found);
-            err.emit();
+            if sub_region.is_error() | sup_region.is_error() {
+                err.delay_as_bug();
+            } else {
+                err.emit();
+            }
             return;
         }
 
@@ -2562,7 +2571,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         );
 
         self.note_region_origin(&mut err, &sub_origin);
-        err.emit();
+        if sub_region.is_error() | sup_region.is_error() {
+            err.delay_as_bug();
+        } else {
+            err.emit();
+        }
     }
 
     /// Determine whether an error associated with the given span and definition
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index b8c843a8a5a..c092efbb557 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -158,8 +158,12 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte
         if infcx.probe_ty_var(ty_vid).is_ok() {
             warn!("resolved ty var in error message");
         }
-        if let TypeVariableOriginKind::TypeParameterDefinition(name, _) =
-            infcx.inner.borrow_mut().type_variables().var_origin(ty_vid).kind
+
+        let mut infcx_inner = infcx.inner.borrow_mut();
+        let ty_vars = infcx_inner.type_variables();
+        let var_origin = ty_vars.var_origin(ty_vid);
+        if let TypeVariableOriginKind::TypeParameterDefinition(name, _) = var_origin.kind
+            && !var_origin.span.from_expansion()
         {
             Some(name)
         } else {
@@ -254,7 +258,7 @@ impl<'tcx> InferCtxt<'tcx> {
                     if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) =
                         var_origin.kind
                     {
-                        if name != kw::SelfUpper {
+                        if name != kw::SelfUpper && !var_origin.span.from_expansion() {
                             return InferenceDiagnosticsData {
                                 name: name.to_string(),
                                 span: Some(var_origin.span),
@@ -780,7 +784,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
         // The sources are listed in order of preference here.
         let tcx = self.infcx.tcx;
         let ctx = CostCtxt { tcx };
-        let base_cost = match source.kind {
+        match source.kind {
             InferSourceKind::LetBinding { ty, .. } => ctx.ty_cost(ty),
             InferSourceKind::ClosureArg { ty, .. } => ctx.ty_cost(ty),
             InferSourceKind::GenericArg { def_id, generic_args, .. } => {
@@ -797,17 +801,17 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
             InferSourceKind::ClosureReturn { ty, should_wrap_expr, .. } => {
                 30 + ctx.ty_cost(ty) + if should_wrap_expr.is_some() { 10 } else { 0 }
             }
-        };
-
-        let suggestion_may_apply = if source.from_expansion() { 10000 } else { 0 };
-
-        base_cost + suggestion_may_apply
+        }
     }
 
     /// Uses `fn source_cost` to determine whether this inference source is preferable to
     /// previous sources. We generally prefer earlier sources.
     #[instrument(level = "debug", skip(self))]
     fn update_infer_source(&mut self, mut new_source: InferSource<'tcx>) {
+        if new_source.from_expansion() {
+            return;
+        }
+
         let cost = self.source_cost(&new_source) + self.attempt;
         debug!(?cost);
         self.attempt += 1;
@@ -819,6 +823,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
             // `let x: _ = iter.collect();`, as this is a very common case.
             *def_id = Some(did);
         }
+
         if cost < self.infer_source_cost {
             self.infer_source_cost = cost;
             self.infer_source = Some(new_source);
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index b18cbd404d4..bdd09a995dc 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -78,7 +78,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         sub: Region<'tcx>,
         sup: Region<'tcx>,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        match origin {
+        let mut err = match origin {
             infer::Subtype(box trace) => {
                 let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
                 let mut err = self.report_and_explain_type_error(trace, terr);
@@ -299,7 +299,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 );
                 err
             }
+        };
+        if sub.is_error() || sup.is_error() {
+            err.delay_as_bug();
         }
+        err
     }
 
     pub fn suggest_copy_trait_method_bounds(
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index 2355234637c..1c76950cc6c 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -126,6 +126,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
             | ty::ReFree(_)
             | ty::ReVar(_)
             | ty::RePlaceholder(..)
+            | ty::ReError(_)
             | ty::ReErased => {
                 // replace all free regions with 'erased
                 self.tcx().lifetimes.re_erased
diff --git a/compiler/rustc_infer/src/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs
index b92b162a978..74abca7bbea 100644
--- a/compiler/rustc_infer/src/infer/glb.rs
+++ b/compiler/rustc_infer/src/infer/glb.rs
@@ -1,12 +1,11 @@
 //! Greatest lower bound. See [`lattice`].
 
-use super::combine::CombineFields;
+use super::combine::{CombineFields, ObligationEmittingRelation};
 use super::lattice::{self, LatticeDir};
 use super::InferCtxt;
 use super::Subtype;
 
-use crate::infer::combine::ConstEquateRelation;
-use crate::traits::{ObligationCause, PredicateObligation};
+use crate::traits::{ObligationCause, PredicateObligations};
 use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
@@ -136,10 +135,6 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
         &self.fields.trace.cause
     }
 
-    fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>) {
-        self.fields.obligations.extend(obligations)
-    }
-
     fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
         let mut sub = self.fields.sub(self.a_is_expected);
         sub.relate(v, a)?;
@@ -152,8 +147,15 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Glb<'combine, 'infcx,
     }
 }
 
-impl<'tcx> ConstEquateRelation<'tcx> for Glb<'_, '_, 'tcx> {
-    fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
-        self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
+impl<'tcx> ObligationEmittingRelation<'tcx> for Glb<'_, '_, 'tcx> {
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item = impl ty::ToPredicate<'tcx>>,
+    ) {
+        self.fields.register_predicates(obligations);
+    }
+
+    fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
+        self.fields.register_obligations(obligations);
     }
 }
diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs
index 4dbb4b4d7b4..f377ac1d19e 100644
--- a/compiler/rustc_infer/src/infer/lattice.rs
+++ b/compiler/rustc_infer/src/infer/lattice.rs
@@ -17,11 +17,12 @@
 //!
 //! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order)
 
+use super::combine::ObligationEmittingRelation;
 use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use super::InferCtxt;
 
-use crate::traits::{ObligationCause, PredicateObligation};
-use rustc_middle::ty::relate::{RelateResult, TypeRelation};
+use crate::traits::ObligationCause;
+use rustc_middle::ty::relate::RelateResult;
 use rustc_middle::ty::TyVar;
 use rustc_middle::ty::{self, Ty};
 
@@ -30,13 +31,11 @@ use rustc_middle::ty::{self, Ty};
 ///
 /// GLB moves "down" the lattice (to smaller values); LUB moves
 /// "up" the lattice (to bigger values).
-pub trait LatticeDir<'f, 'tcx>: TypeRelation<'tcx> {
+pub trait LatticeDir<'f, 'tcx>: ObligationEmittingRelation<'tcx> {
     fn infcx(&self) -> &'f InferCtxt<'tcx>;
 
     fn cause(&self) -> &ObligationCause<'tcx>;
 
-    fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>);
-
     fn define_opaque_types(&self) -> bool;
 
     // Relates the type `v` to `a` and `b` such that `v` represents
@@ -113,7 +112,7 @@ where
         | (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
             if this.define_opaque_types() && def_id.is_local() =>
         {
-            this.add_obligations(
+            this.register_obligations(
                 infcx
                     .handle_opaque_type(a, b, this.a_is_expected(), this.cause(), this.param_env())?
                     .obligations,
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index ce8aec8044b..4a2210bdb68 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -17,7 +17,7 @@ use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::PlaceholderRegion;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{ReEarlyBound, ReErased, ReFree, ReStatic};
+use rustc_middle::ty::{ReEarlyBound, ReErased, ReError, ReFree, ReStatic};
 use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar};
 use rustc_middle::ty::{Region, RegionVid};
 use rustc_span::Span;
@@ -216,6 +216,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
                 Ok(self.tcx().lifetimes.re_static)
             }
 
+            ReError(_) => Ok(a_region),
+
             ReEarlyBound(_) | ReFree(_) => {
                 // All empty regions are less than early-bound, free,
                 // and scope regions.
@@ -436,7 +438,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
             }
             (VarValue::Value(a), VarValue::Empty(_)) => {
                 match *a {
-                    ReLateBound(..) | ReErased => {
+                    ReLateBound(..) | ReErased | ReError(_) => {
                         bug!("cannot relate region: {:?}", a);
                     }
 
@@ -465,7 +467,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
             }
             (VarValue::Empty(a_ui), VarValue::Value(b)) => {
                 match *b {
-                    ReLateBound(..) | ReErased => {
+                    ReLateBound(..) | ReErased | ReError(_) => {
                         bug!("cannot relate region: {:?}", b);
                     }
 
@@ -546,6 +548,10 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
                 );
             }
 
+            (ReError(_), _) => a,
+
+            (_, ReError(_)) => b,
+
             (ReStatic, _) | (_, ReStatic) => {
                 // nothing lives longer than `'static`
                 self.tcx().lifetimes.re_static
@@ -1040,7 +1046,7 @@ impl<'tcx> LexicalRegionResolutions<'tcx> {
             ty::ReVar(rid) => match self.values[rid] {
                 VarValue::Empty(_) => r,
                 VarValue::Value(r) => r,
-                VarValue::ErrorValue => tcx.lifetimes.re_static,
+                VarValue::ErrorValue => tcx.re_error_misc(),
             },
             _ => r,
         };
diff --git a/compiler/rustc_infer/src/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs
index f6e0554fd1f..f997171b97f 100644
--- a/compiler/rustc_infer/src/infer/lub.rs
+++ b/compiler/rustc_infer/src/infer/lub.rs
@@ -1,12 +1,11 @@
 //! Least upper bound. See [`lattice`].
 
-use super::combine::CombineFields;
+use super::combine::{CombineFields, ObligationEmittingRelation};
 use super::lattice::{self, LatticeDir};
 use super::InferCtxt;
 use super::Subtype;
 
-use crate::infer::combine::ConstEquateRelation;
-use crate::traits::{ObligationCause, PredicateObligation};
+use crate::traits::{ObligationCause, PredicateObligations};
 use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
@@ -127,12 +126,6 @@ impl<'tcx> TypeRelation<'tcx> for Lub<'_, '_, 'tcx> {
     }
 }
 
-impl<'tcx> ConstEquateRelation<'tcx> for Lub<'_, '_, 'tcx> {
-    fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
-        self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
-    }
-}
-
 impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx, 'tcx> {
     fn infcx(&self) -> &'infcx InferCtxt<'tcx> {
         self.fields.infcx
@@ -142,10 +135,6 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
         &self.fields.trace.cause
     }
 
-    fn add_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>) {
-        self.fields.obligations.extend(obligations)
-    }
-
     fn relate_bound(&mut self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> {
         let mut sub = self.fields.sub(self.a_is_expected);
         sub.relate(a, v)?;
@@ -157,3 +146,16 @@ impl<'combine, 'infcx, 'tcx> LatticeDir<'infcx, 'tcx> for Lub<'combine, 'infcx,
         self.fields.define_opaque_types
     }
 }
+
+impl<'tcx> ObligationEmittingRelation<'tcx> for Lub<'_, '_, 'tcx> {
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item = impl ty::ToPredicate<'tcx>>,
+    ) {
+        self.fields.register_predicates(obligations);
+    }
+
+    fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
+        self.fields.register_obligations(obligations)
+    }
+}
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 35918b8bae1..e77924900a0 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -4,6 +4,7 @@ pub use self::LateBoundRegionConversionTime::*;
 pub use self::RegionVariableOrigin::*;
 pub use self::SubregionOrigin::*;
 pub use self::ValuePairs::*;
+pub use combine::ObligationEmittingRelation;
 
 use self::opaque_types::OpaqueTypeStorage;
 pub(crate) use self::undo_log::{InferCtxtUndoLogs, Snapshot, UndoLog};
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index a2cfe8d8881..1dd5062acaf 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -21,11 +21,10 @@
 //!   thing we relate in chalk are basically domain goals and their
 //!   constituents)
 
-use crate::infer::combine::ConstEquateRelation;
 use crate::infer::InferCtxt;
 use crate::infer::{ConstVarValue, ConstVariableValue};
 use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
-use crate::traits::{Obligation, PredicateObligation};
+use crate::traits::{Obligation, PredicateObligations};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::error::TypeError;
@@ -36,11 +35,7 @@ use rustc_span::Span;
 use std::fmt::Debug;
 use std::ops::ControlFlow;
 
-#[derive(PartialEq)]
-pub enum NormalizationStrategy {
-    Lazy,
-    Eager,
-}
+use super::combine::ObligationEmittingRelation;
 
 pub struct TypeRelating<'me, 'tcx, D>
 where
@@ -92,7 +87,7 @@ pub trait TypeRelatingDelegate<'tcx> {
         info: ty::VarianceDiagInfo<'tcx>,
     );
 
-    fn register_obligations(&mut self, obligations: Vec<PredicateObligation<'tcx>>);
+    fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>);
 
     /// Creates a new universe index. Used when instantiating placeholders.
     fn create_next_universe(&mut self) -> ty::UniverseIndex;
@@ -125,9 +120,6 @@ pub trait TypeRelatingDelegate<'tcx> {
     /// relation stating that `'?0: 'a`).
     fn generalize_existential(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>;
 
-    /// Define the normalization strategy to use, eager or lazy.
-    fn normalization() -> NormalizationStrategy;
-
     /// Enables some optimizations if we do not expect inference variables
     /// in the RHS of the relation.
     fn forbid_inference_vars() -> bool;
@@ -265,38 +257,6 @@ where
         self.delegate.push_outlives(sup, sub, info);
     }
 
-    /// Relate a projection type and some value type lazily. This will always
-    /// succeed, but we push an additional `ProjectionEq` goal depending
-    /// on the value type:
-    /// - if the value type is any type `T` which is not a projection, we push
-    ///   `ProjectionEq(projection = T)`.
-    /// - if the value type is another projection `other_projection`, we create
-    ///   a new inference variable `?U` and push the two goals
-    ///   `ProjectionEq(projection = ?U)`, `ProjectionEq(other_projection = ?U)`.
-    fn relate_projection_ty(
-        &mut self,
-        projection_ty: ty::AliasTy<'tcx>,
-        value_ty: Ty<'tcx>,
-    ) -> Ty<'tcx> {
-        use rustc_span::DUMMY_SP;
-
-        match *value_ty.kind() {
-            ty::Alias(ty::Projection, other_projection_ty) => {
-                let var = self.infcx.next_ty_var(TypeVariableOrigin {
-                    kind: TypeVariableOriginKind::MiscVariable,
-                    span: DUMMY_SP,
-                });
-                // FIXME(lazy-normalization): This will always ICE, because the recursive
-                // call will end up in the _ arm below.
-                self.relate_projection_ty(projection_ty, var);
-                self.relate_projection_ty(other_projection_ty, var);
-                var
-            }
-
-            _ => bug!("should never be invoked with eager normalization"),
-        }
-    }
-
     /// Relate a type inference variable with a value type. This works
     /// by creating a "generalization" G of the value where all the
     /// lifetimes are replaced with fresh inference values. This
@@ -335,12 +295,6 @@ where
                 return Ok(value_ty);
             }
 
-            ty::Alias(ty::Projection, projection_ty)
-                if D::normalization() == NormalizationStrategy::Lazy =>
-            {
-                return Ok(self.relate_projection_ty(projection_ty, self.infcx.tcx.mk_ty_var(vid)));
-            }
-
             _ => (),
         }
 
@@ -627,18 +581,6 @@ where
                 self.relate_opaques(a, b)
             }
 
-            (&ty::Alias(ty::Projection, projection_ty), _)
-                if D::normalization() == NormalizationStrategy::Lazy =>
-            {
-                Ok(self.relate_projection_ty(projection_ty, b))
-            }
-
-            (_, &ty::Alias(ty::Projection, projection_ty))
-                if D::normalization() == NormalizationStrategy::Lazy =>
-            {
-                Ok(self.relate_projection_ty(projection_ty, a))
-            }
-
             _ => {
                 debug!(?a, ?b, ?self.ambient_variance);
 
@@ -813,17 +755,26 @@ where
     }
 }
 
-impl<'tcx, D> ConstEquateRelation<'tcx> for TypeRelating<'_, 'tcx, D>
+impl<'tcx, D> ObligationEmittingRelation<'tcx> for TypeRelating<'_, 'tcx, D>
 where
     D: TypeRelatingDelegate<'tcx>,
 {
-    fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
-        self.delegate.register_obligations(vec![Obligation::new(
-            self.tcx(),
-            ObligationCause::dummy(),
-            self.param_env(),
-            ty::Binder::dummy(ty::PredicateKind::ConstEquate(a, b)),
-        )]);
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item = impl ty::ToPredicate<'tcx>>,
+    ) {
+        self.delegate.register_obligations(
+            obligations
+                .into_iter()
+                .map(|to_pred| {
+                    Obligation::new(self.tcx(), ObligationCause::dummy(), self.param_env(), to_pred)
+                })
+                .collect(),
+        );
+    }
+
+    fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
+        self.delegate.register_obligations(obligations);
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index 4daa257672c..a8e668d81ea 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -21,6 +21,7 @@ pub fn explicit_outlives_bounds<'tcx>(
         .filter_map(move |kind| match kind {
             ty::PredicateKind::Clause(ty::Clause::Projection(..))
             | ty::PredicateKind::Clause(ty::Clause::Trait(..))
+            | ty::PredicateKind::AliasEq(..)
             | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::Subtype(..)
             | ty::PredicateKind::WellFormed(..)
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 94de9bc2d02..bae246418b0 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -207,6 +207,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
     ///
     /// In some cases, such as when `erased_ty` represents a `ty::Param`, however,
     /// the result is precise.
+    #[instrument(level = "debug", skip(self))]
     fn declared_generic_bounds_from_env_for_erased_ty(
         &self,
         erased_ty: Ty<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs
index 4667d99ff00..f795047709e 100644
--- a/compiler/rustc_infer/src/infer/projection.rs
+++ b/compiler/rustc_infer/src/infer/projection.rs
@@ -21,16 +21,28 @@ impl<'tcx> InferCtxt<'tcx> {
         recursion_depth: usize,
         obligations: &mut Vec<PredicateObligation<'tcx>>,
     ) -> Ty<'tcx> {
-        let def_id = projection_ty.def_id;
-        let ty_var = self.next_ty_var(TypeVariableOrigin {
-            kind: TypeVariableOriginKind::NormalizeProjectionType,
-            span: self.tcx.def_span(def_id),
-        });
-        let projection =
-            ty::Binder::dummy(ty::ProjectionPredicate { projection_ty, term: ty_var.into() });
-        let obligation =
-            Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection);
-        obligations.push(obligation);
-        ty_var
+        if self.tcx.trait_solver_next() {
+            // FIXME(-Ztrait-solver=next): Instead of branching here,
+            // completely change the normalization routine with the new solver.
+            //
+            // The new solver correctly handles projection equality so this hack
+            // is not necessary. if re-enabled it should emit `PredicateKind::AliasEq`
+            // not `PredicateKind::Clause(Clause::Projection(..))` as in the new solver
+            // `Projection` is used as `normalizes-to` which will fail for `<T as Trait>::Assoc eq ?0`.
+            return projection_ty.to_ty(self.tcx);
+        } else {
+            let def_id = projection_ty.def_id;
+            let ty_var = self.next_ty_var(TypeVariableOrigin {
+                kind: TypeVariableOriginKind::NormalizeProjectionType,
+                span: self.tcx.def_span(def_id),
+            });
+            let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::Clause::Projection(
+                ty::ProjectionPredicate { projection_ty, term: ty_var.into() },
+            )));
+            let obligation =
+                Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection);
+            obligations.push(obligation);
+            ty_var
+        }
     }
 }
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 0428481b7ff..cb24375c7a3 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -696,9 +696,11 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> {
 
     pub fn universe(&self, region: Region<'tcx>) -> ty::UniverseIndex {
         match *region {
-            ty::ReStatic | ty::ReErased | ty::ReFree(..) | ty::ReEarlyBound(..) => {
-                ty::UniverseIndex::ROOT
-            }
+            ty::ReStatic
+            | ty::ReErased
+            | ty::ReFree(..)
+            | ty::ReEarlyBound(..)
+            | ty::ReError(_) => ty::UniverseIndex::ROOT,
             ty::RePlaceholder(placeholder) => placeholder.universe,
             ty::ReVar(vid) => self.var_universe(vid),
             ty::ReLateBound(..) => bug!("universe(): encountered bound region {:?}", region),
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index 532fbd0ffe4..bf1b3441547 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -1,8 +1,7 @@
 use super::combine::{CombineFields, RelationDir};
-use super::SubregionOrigin;
+use super::{ObligationEmittingRelation, SubregionOrigin};
 
-use crate::infer::combine::ConstEquateRelation;
-use crate::traits::Obligation;
+use crate::traits::{Obligation, PredicateObligations};
 use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::visit::TypeVisitable;
 use rustc_middle::ty::TyVar;
@@ -228,8 +227,15 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
     }
 }
 
-impl<'tcx> ConstEquateRelation<'tcx> for Sub<'_, '_, 'tcx> {
-    fn const_equate_obligation(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>) {
-        self.fields.add_const_equate_obligation(self.a_is_expected, a, b);
+impl<'tcx> ObligationEmittingRelation<'tcx> for Sub<'_, '_, 'tcx> {
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item = impl ty::ToPredicate<'tcx>>,
+    ) {
+        self.fields.register_predicates(obligations);
+    }
+
+    fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
+        self.fields.register_obligations(obligations);
     }
 }
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 18a966449aa..e617eb68d47 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -294,6 +294,9 @@ impl<'tcx> Elaborator<'tcx> {
                 // Nothing to elaborate
             }
             ty::PredicateKind::Ambiguous => {}
+            ty::PredicateKind::AliasEq(..) => {
+                // No
+            }
         }
     }
 }
diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs
index ee0552d77ce..bc6d7c20997 100644
--- a/compiler/rustc_interface/src/callbacks.rs
+++ b/compiler/rustc_interface/src/callbacks.rs
@@ -38,7 +38,7 @@ fn track_diagnostic(diagnostic: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnost
 
             // Diagnostics are tracked, we can ignore the dependency.
             let icx = tls::ImplicitCtxt { task_deps: TaskDepsRef::Ignore, ..icx.clone() };
-            return tls::enter_context(&icx, move |_| (*f)(diagnostic));
+            return tls::enter_context(&icx, move || (*f)(diagnostic));
         }
 
         // In any other case, invoke diagnostics anyway.
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 2a373ebc132..33ebbb411ce 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -738,30 +738,16 @@ pub static DEFAULT_EXTERN_QUERY_PROVIDERS: LazyLock<ExternProviders> = LazyLock:
     extern_providers
 });
 
-pub struct QueryContext<'tcx> {
-    gcx: &'tcx GlobalCtxt<'tcx>,
-}
-
-impl<'tcx> QueryContext<'tcx> {
-    pub fn enter<F, R>(&mut self, f: F) -> R
-    where
-        F: FnOnce(TyCtxt<'tcx>) -> R,
-    {
-        let icx = ty::tls::ImplicitCtxt::new(self.gcx);
-        ty::tls::enter_context(&icx, |_| f(icx.tcx))
-    }
-}
-
 pub fn create_global_ctxt<'tcx>(
     compiler: &'tcx Compiler,
     lint_store: Lrc<LintStore>,
     dep_graph: DepGraph,
     untracked: Untracked,
     queries: &'tcx OnceCell<TcxQueries<'tcx>>,
-    global_ctxt: &'tcx OnceCell<GlobalCtxt<'tcx>>,
+    gcx_cell: &'tcx OnceCell<GlobalCtxt<'tcx>>,
     arena: &'tcx WorkerLocal<Arena<'tcx>>,
     hir_arena: &'tcx WorkerLocal<rustc_hir::Arena<'tcx>>,
-) -> QueryContext<'tcx> {
+) -> &'tcx GlobalCtxt<'tcx> {
     // We're constructing the HIR here; we don't care what we will
     // read, since we haven't even constructed the *input* to
     // incr. comp. yet.
@@ -785,8 +771,8 @@ pub fn create_global_ctxt<'tcx>(
         TcxQueries::new(local_providers, extern_providers, query_result_on_disk_cache)
     });
 
-    let gcx = sess.time("setup_global_ctxt", || {
-        global_ctxt.get_or_init(move || {
+    sess.time("setup_global_ctxt", || {
+        gcx_cell.get_or_init(move || {
             TyCtxt::create_global_ctxt(
                 sess,
                 lint_store,
@@ -799,9 +785,7 @@ pub fn create_global_ctxt<'tcx>(
                 rustc_query_impl::query_callbacks(arena),
             )
         })
-    });
-
-    QueryContext { gcx }
+    })
 }
 
 /// Runs the resolution, type-checking, region checking and other
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 4b0180741c1..6512695873e 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -1,6 +1,6 @@
 use crate::errors::{FailedWritingFile, RustcErrorFatal, RustcErrorUnexpectedAnnotation};
 use crate::interface::{Compiler, Result};
-use crate::passes::{self, BoxedResolver, QueryContext};
+use crate::passes::{self, BoxedResolver};
 
 use rustc_ast as ast;
 use rustc_codegen_ssa::traits::CodegenBackend;
@@ -64,7 +64,7 @@ impl<'a, T> std::ops::DerefMut for QueryResult<'a, T> {
     }
 }
 
-impl<'a, 'tcx> QueryResult<'a, QueryContext<'tcx>> {
+impl<'a, 'tcx> QueryResult<'a, &'tcx GlobalCtxt<'tcx>> {
     pub fn enter<T>(&mut self, f: impl FnOnce(TyCtxt<'tcx>) -> T) -> T {
         (*self.0).get_mut().enter(f)
     }
@@ -78,7 +78,7 @@ impl<T> Default for Query<T> {
 
 pub struct Queries<'tcx> {
     compiler: &'tcx Compiler,
-    gcx: OnceCell<GlobalCtxt<'tcx>>,
+    gcx_cell: OnceCell<GlobalCtxt<'tcx>>,
     queries: OnceCell<TcxQueries<'tcx>>,
 
     arena: WorkerLocal<Arena<'tcx>>,
@@ -90,7 +90,8 @@ pub struct Queries<'tcx> {
     register_plugins: Query<(ast::Crate, Lrc<LintStore>)>,
     expansion: Query<(Lrc<ast::Crate>, Rc<RefCell<BoxedResolver>>, Lrc<LintStore>)>,
     dep_graph: Query<DepGraph>,
-    global_ctxt: Query<QueryContext<'tcx>>,
+    // This just points to what's in `gcx_cell`.
+    gcx: Query<&'tcx GlobalCtxt<'tcx>>,
     ongoing_codegen: Query<Box<dyn Any>>,
 }
 
@@ -98,7 +99,7 @@ impl<'tcx> Queries<'tcx> {
     pub fn new(compiler: &'tcx Compiler) -> Queries<'tcx> {
         Queries {
             compiler,
-            gcx: OnceCell::new(),
+            gcx_cell: OnceCell::new(),
             queries: OnceCell::new(),
             arena: WorkerLocal::new(|_| Arena::default()),
             hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()),
@@ -108,7 +109,7 @@ impl<'tcx> Queries<'tcx> {
             register_plugins: Default::default(),
             expansion: Default::default(),
             dep_graph: Default::default(),
-            global_ctxt: Default::default(),
+            gcx: Default::default(),
             ongoing_codegen: Default::default(),
         }
     }
@@ -207,8 +208,8 @@ impl<'tcx> Queries<'tcx> {
         })
     }
 
-    pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, QueryContext<'tcx>>> {
-        self.global_ctxt.compute(|| {
+    pub fn global_ctxt(&'tcx self) -> Result<QueryResult<'_, &'tcx GlobalCtxt<'tcx>>> {
+        self.gcx.compute(|| {
             let crate_name = *self.crate_name()?.borrow();
             let (krate, resolver, lint_store) = self.expansion()?.steal();
 
@@ -218,18 +219,18 @@ impl<'tcx> Queries<'tcx> {
                 ast_lowering: untracked_resolver_for_lowering,
             } = BoxedResolver::to_resolver_outputs(resolver);
 
-            let mut qcx = passes::create_global_ctxt(
+            let gcx = passes::create_global_ctxt(
                 self.compiler,
                 lint_store,
                 self.dep_graph()?.steal(),
                 untracked,
                 &self.queries,
-                &self.gcx,
+                &self.gcx_cell,
                 &self.arena,
                 &self.hir_arena,
             );
 
-            qcx.enter(|tcx| {
+            gcx.enter(|tcx| {
                 let feed = tcx.feed_unit_query();
                 feed.resolver_for_lowering(
                     tcx.arena.alloc(Steal::new((untracked_resolver_for_lowering, krate))),
@@ -239,7 +240,7 @@ impl<'tcx> Queries<'tcx> {
                 let feed = tcx.feed_local_crate();
                 feed.crate_name(crate_name);
             });
-            Ok(qcx)
+            Ok(gcx)
         })
     }
 
@@ -387,7 +388,7 @@ impl Compiler {
 
         // NOTE: intentionally does not compute the global context if it hasn't been built yet,
         // since that likely means there was a parse error.
-        if let Some(Ok(gcx)) = &mut *queries.global_ctxt.result.borrow_mut() {
+        if let Some(Ok(gcx)) = &mut *queries.gcx.result.borrow_mut() {
             let gcx = gcx.get_mut();
             // We assume that no queries are run past here. If there are new queries
             // after this point, they'll show up as "<unknown>" in self-profiling data.
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 5d85cfe330a..7a50b6aec87 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1594,12 +1594,14 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
                     // Ignore projections, as they can only be global
                     // if the trait bound is global
                     Clause(Clause::Projection(..)) |
+                    AliasEq(..) |
                     // Ignore bounds that a user can't type
                     WellFormed(..) |
                     ObjectSafe(..) |
                     ClosureKind(..) |
                     Subtype(..) |
                     Coerce(..) |
+                    // FIXME(generic_const_exprs): `ConstEvaluatable` can be written
                     ConstEvaluatable(..) |
                     ConstEquate(..) |
                     Ambiguous |
diff --git a/compiler/rustc_log/src/lib.rs b/compiler/rustc_log/src/lib.rs
index 019fdc30dce..de26fd61e4d 100644
--- a/compiler/rustc_log/src/lib.rs
+++ b/compiler/rustc_log/src/lib.rs
@@ -14,7 +14,7 @@
 //!
 //! ```
 //! fn main() {
-//!     rustc_log::init_rustc_env_logger().unwrap();
+//!     rustc_log::init_env_logger("LOG").unwrap();
 //!
 //!     let edition = rustc_span::edition::Edition::Edition2021;
 //!     rustc_span::create_session_globals_then(edition, || {
@@ -23,9 +23,9 @@
 //! }
 //! ```
 //!
-//! Now `RUSTC_LOG=debug cargo run` will run your minimal main.rs and show
+//! Now `LOG=debug cargo run` will run your minimal main.rs and show
 //! rustc's debug logging. In a workflow like this, one might also add
-//! `std::env::set_var("RUSTC_LOG", "debug")` to the top of main so that `cargo
+//! `std::env::set_var("LOG", "debug")` to the top of main so that `cargo
 //! run` by itself is sufficient to get logs.
 //!
 //! The reason rustc_log is a tiny separate crate, as opposed to exposing the
@@ -53,12 +53,6 @@ use tracing_subscriber::fmt::{
 };
 use tracing_subscriber::layer::SubscriberExt;
 
-pub fn init_rustc_env_logger() -> Result<(), Error> {
-    init_env_logger("RUSTC_LOG")
-}
-
-/// In contrast to `init_rustc_env_logger` this allows you to choose an env var
-/// other than `RUSTC_LOG`.
 pub fn init_env_logger(env: &str) -> Result<(), Error> {
     let filter = match env::var(env) {
         Ok(env) => EnvFilter::new(env),
diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs
index 2e62bebc852..2e82efba192 100644
--- a/compiler/rustc_middle/src/dep_graph/mod.rs
+++ b/compiler/rustc_middle/src/dep_graph/mod.rs
@@ -55,7 +55,7 @@ impl rustc_query_system::dep_graph::DepKind for DepKind {
         ty::tls::with_context(|icx| {
             let icx = ty::tls::ImplicitCtxt { task_deps, ..icx.clone() };
 
-            ty::tls::enter_context(&icx, |_| op())
+            ty::tls::enter_context(&icx, op)
         })
     }
 
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 95148de2518..56df1a66f9d 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -34,6 +34,7 @@
 #![feature(get_mut_unchecked)]
 #![feature(if_let_guard)]
 #![feature(iter_from_generator)]
+#![feature(local_key_cell_methods)]
 #![feature(negative_impls)]
 #![feature(never_type)]
 #![feature(extern_types)]
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 9205a8a0ffe..04537ad635a 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -468,6 +468,18 @@ pub struct GlobalCtxt<'tcx> {
     pub(crate) alloc_map: Lock<interpret::AllocMap<'tcx>>,
 }
 
+impl<'tcx> GlobalCtxt<'tcx> {
+    /// Installs `self` in a `TyCtxt` and `ImplicitCtxt` for the duration of
+    /// `f`.
+    pub fn enter<'a: 'tcx, F, R>(&'a self, f: F) -> R
+    where
+        F: FnOnce(TyCtxt<'tcx>) -> R,
+    {
+        let icx = tls::ImplicitCtxt::new(self);
+        tls::enter_context(&icx, || f(icx.tcx))
+    }
+}
+
 impl<'tcx> TyCtxt<'tcx> {
     /// Expects a body and returns its codegen attributes.
     ///
@@ -649,6 +661,30 @@ impl<'tcx> TyCtxt<'tcx> {
         self.mk_ty(Error(reported))
     }
 
+    /// Constructs a `RegionKind::ReError` lifetime.
+    #[track_caller]
+    pub fn re_error(self, reported: ErrorGuaranteed) -> Region<'tcx> {
+        self.mk_region(ty::ReError(reported))
+    }
+
+    /// Constructs a `RegionKind::ReError` lifetime and registers a `delay_span_bug` to ensure it
+    /// gets used.
+    #[track_caller]
+    pub fn re_error_misc(self) -> Region<'tcx> {
+        self.re_error_with_message(
+            DUMMY_SP,
+            "RegionKind::ReError constructed but no error reported",
+        )
+    }
+
+    /// Constructs a `RegionKind::ReError` lifetime and registers a `delay_span_bug` with the given
+    /// `msg` to ensure it gets used.
+    #[track_caller]
+    pub fn re_error_with_message<S: Into<MultiSpan>>(self, span: S, msg: &str) -> Region<'tcx> {
+        let reported = self.sess.delay_span_bug(span, msg);
+        self.re_error(reported)
+    }
+
     /// Like [TyCtxt::ty_error] but for constants, with current `ErrorGuaranteed`
     #[track_caller]
     pub fn const_error_with_guaranteed(
@@ -2218,6 +2254,10 @@ impl<'tcx> TyCtxt<'tcx> {
             })
         )
     }
+
+    pub fn trait_solver_next(self) -> bool {
+        self.sess.opts.unstable_opts.trait_solver == rustc_session::config::TraitSolver::Next
+    }
 }
 
 impl<'tcx> TyCtxtAt<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs
index 71b025dc1be..5426ac8d739 100644
--- a/compiler/rustc_middle/src/ty/context/tls.rs
+++ b/compiler/rustc_middle/src/ty/context/tls.rs
@@ -89,9 +89,8 @@ mod tlv {
     /// This is used to set the pointer to the new `ImplicitCtxt`.
     #[inline]
     pub(super) fn with_tlv<F: FnOnce() -> R, R>(value: *const (), f: F) -> R {
-        let old = get_tlv();
-        let _reset = rustc_data_structures::OnDrop(move || TLV.with(|tlv| tlv.set(old)));
-        TLV.with(|tlv| tlv.set(value));
+        let old = TLV.replace(value);
+        let _reset = rustc_data_structures::OnDrop(move || TLV.set(old));
         f()
     }
 }
@@ -110,9 +109,9 @@ unsafe fn downcast<'a, 'tcx>(context: *const ()) -> &'a ImplicitCtxt<'a, 'tcx> {
 #[inline]
 pub fn enter_context<'a, 'tcx, F, R>(context: &ImplicitCtxt<'a, 'tcx>, f: F) -> R
 where
-    F: FnOnce(&ImplicitCtxt<'a, 'tcx>) -> R,
+    F: FnOnce() -> R,
 {
-    tlv::with_tlv(erase(context), || f(&context))
+    tlv::with_tlv(erase(context), f)
 }
 
 /// Allows access to the current `ImplicitCtxt` in a closure if one is available.
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index dc6f5851b7d..258bc9c3e41 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -264,10 +264,7 @@ impl FlagComputation {
                 term,
             })) => {
                 self.add_projection_ty(projection_ty);
-                match term.unpack() {
-                    ty::TermKind::Ty(ty) => self.add_ty(ty),
-                    ty::TermKind::Const(c) => self.add_const(c),
-                }
+                self.add_term(term);
             }
             ty::PredicateKind::WellFormed(arg) => {
                 self.add_substs(slice::from_ref(&arg));
@@ -287,6 +284,10 @@ impl FlagComputation {
                 self.add_ty(ty);
             }
             ty::PredicateKind::Ambiguous => {}
+            ty::PredicateKind::AliasEq(t1, t2) => {
+                self.add_term(t1);
+                self.add_term(t2);
+            }
         }
     }
 
@@ -380,4 +381,11 @@ impl FlagComputation {
             }
         }
     }
+
+    fn add_term(&mut self, term: ty::Term<'_>) {
+        match term.unpack() {
+            ty::TermKind::Ty(ty) => self.add_ty(ty),
+            ty::TermKind::Const(ct) => self.add_const(ct),
+        }
+    }
 }
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 801ca600445..ea95a38f272 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -100,7 +100,7 @@ impl GenericParamDef {
         preceding_substs: &[ty::GenericArg<'tcx>],
     ) -> ty::GenericArg<'tcx> {
         match &self.kind {
-            ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_static.into(),
+            ty::GenericParamDefKind::Lifetime => tcx.re_error_misc().into(),
             ty::GenericParamDefKind::Type { .. } => tcx.ty_error().into(),
             ty::GenericParamDefKind::Const { .. } => {
                 tcx.const_error(tcx.bound_type_of(self.def_id).subst(tcx, preceding_substs)).into()
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index cff3ba194bd..fa2d3b89cf4 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -547,6 +547,7 @@ impl<'tcx> Predicate<'tcx> {
             | PredicateKind::Clause(Clause::RegionOutlives(_))
             | PredicateKind::Clause(Clause::TypeOutlives(_))
             | PredicateKind::Clause(Clause::Projection(_))
+            | PredicateKind::AliasEq(..)
             | PredicateKind::ObjectSafe(_)
             | PredicateKind::ClosureKind(_, _, _)
             | PredicateKind::Subtype(_)
@@ -634,6 +635,12 @@ pub enum PredicateKind<'tcx> {
     /// A marker predicate that is always ambiguous.
     /// Used for coherence to mark opaque types as possibly equal to each other but ambiguous.
     Ambiguous,
+
+    /// Separate from `Clause::Projection` which is used for normalization in new solver.
+    /// This predicate requires two terms to be equal to eachother.
+    ///
+    /// Only used for new solver
+    AliasEq(Term<'tcx>, Term<'tcx>),
 }
 
 /// The crate outlives map is computed during typeck and contains the
@@ -965,6 +972,33 @@ impl<'tcx> Term<'tcx> {
             TermKind::Const(c) => c.into(),
         }
     }
+
+    /// This function returns `None` for `AliasKind::Opaque`.
+    ///
+    /// FIXME: rename `AliasTy` to `AliasTerm` and make sure we correctly
+    /// deal with constants.
+    pub fn to_alias_term_no_opaque(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> {
+        match self.unpack() {
+            TermKind::Ty(ty) => match ty.kind() {
+                ty::Alias(kind, alias_ty) => match kind {
+                    AliasKind::Projection => Some(*alias_ty),
+                    AliasKind::Opaque => None,
+                },
+                _ => None,
+            },
+            TermKind::Const(ct) => match ct.kind() {
+                ConstKind::Unevaluated(uv) => Some(tcx.mk_alias_ty(uv.def.did, uv.substs)),
+                _ => None,
+            },
+        }
+    }
+
+    pub fn is_infer(&self) -> bool {
+        match self.unpack() {
+            TermKind::Ty(ty) => ty.is_ty_or_numeric_infer(),
+            TermKind::Const(ct) => ct.is_ct_infer(),
+        }
+    }
 }
 
 const TAG_MASK: usize = 0b11;
@@ -1154,6 +1188,7 @@ impl<'tcx> Predicate<'tcx> {
         match predicate.skip_binder() {
             PredicateKind::Clause(Clause::Trait(t)) => Some(predicate.rebind(t)),
             PredicateKind::Clause(Clause::Projection(..))
+            | PredicateKind::AliasEq(..)
             | PredicateKind::Subtype(..)
             | PredicateKind::Coerce(..)
             | PredicateKind::Clause(Clause::RegionOutlives(..))
@@ -1173,6 +1208,7 @@ impl<'tcx> Predicate<'tcx> {
         match predicate.skip_binder() {
             PredicateKind::Clause(Clause::Projection(t)) => Some(predicate.rebind(t)),
             PredicateKind::Clause(Clause::Trait(..))
+            | PredicateKind::AliasEq(..)
             | PredicateKind::Subtype(..)
             | PredicateKind::Coerce(..)
             | PredicateKind::Clause(Clause::RegionOutlives(..))
@@ -1193,6 +1229,7 @@ impl<'tcx> Predicate<'tcx> {
             PredicateKind::Clause(Clause::TypeOutlives(data)) => Some(predicate.rebind(data)),
             PredicateKind::Clause(Clause::Trait(..))
             | PredicateKind::Clause(Clause::Projection(..))
+            | PredicateKind::AliasEq(..)
             | PredicateKind::Subtype(..)
             | PredicateKind::Coerce(..)
             | PredicateKind::Clause(Clause::RegionOutlives(..))
diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs
index 7ff58f02623..a5ebdbc8792 100644
--- a/compiler/rustc_middle/src/ty/opaque_types.rs
+++ b/compiler/rustc_middle/src/ty/opaque_types.rs
@@ -109,6 +109,8 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
             // them.
             ty::ReErased => return r,
 
+            ty::ReError(_) => return r,
+
             // The regions that we expect from borrow checking.
             ty::ReEarlyBound(_) | ty::ReFree(_) => {}
 
@@ -125,20 +127,21 @@ impl<'tcx> TypeFolder<'tcx> for ReverseMapper<'tcx> {
             Some(u) => panic!("region mapped to unexpected kind: {:?}", u),
             None if self.do_not_error => self.tcx.lifetimes.re_static,
             None => {
-                self.tcx
+                let e = self
+                    .tcx
                     .sess
                     .struct_span_err(self.span, "non-defining opaque type use in defining scope")
                     .span_label(
                         self.span,
                         format!(
                             "lifetime `{}` is part of concrete type but not used in \
-                                 parameter list of the `impl Trait` type alias",
+                             parameter list of the `impl Trait` type alias",
                             r
                         ),
                     )
                     .emit();
 
-                self.tcx().lifetimes.re_static
+                self.tcx().re_error(e)
             }
         }
     }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index bbb4fd999bc..7ba531fba78 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -2114,7 +2114,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
 
             ty::ReVar(_) if identify_regions => true,
 
-            ty::ReVar(_) | ty::ReErased => false,
+            ty::ReVar(_) | ty::ReErased | ty::ReError(_) => false,
 
             ty::ReStatic => true,
         }
@@ -2194,6 +2194,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
             }
             ty::ReVar(_) => {}
             ty::ReErased => {}
+            ty::ReError(_) => {}
             ty::ReStatic => {
                 p!("'static");
                 return Ok(self);
@@ -2841,6 +2842,7 @@ define_print_and_forward_display! {
                 p!("the type `", print(ty), "` is found in the environment")
             }
             ty::PredicateKind::Ambiguous => p!("ambiguous"),
+            ty::PredicateKind::AliasEq(t1, t2) => p!(print(t1), " == ", print(t2)),
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 8df639750c7..1ef66b01ea0 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -177,6 +177,7 @@ impl<'tcx> fmt::Debug for ty::PredicateKind<'tcx> {
                 write!(f, "TypeWellFormedFromEnv({:?})", ty)
             }
             ty::PredicateKind::Ambiguous => write!(f, "Ambiguous"),
+            ty::PredicateKind::AliasEq(t1, t2) => write!(f, "AliasEq({t1:?}, {t2:?})"),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 98d6b683563..b3b2a4fd0e5 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1623,10 +1623,16 @@ impl<'tcx> Region<'tcx> {
             ty::ReVar(..) => false,
             ty::RePlaceholder(placeholder) => placeholder.name.is_named(),
             ty::ReErased => false,
+            ty::ReError(_) => false,
         }
     }
 
     #[inline]
+    pub fn is_error(self) -> bool {
+        matches!(*self, ty::ReError(_))
+    }
+
+    #[inline]
     pub fn is_static(self) -> bool {
         matches!(*self, ty::ReStatic)
     }
@@ -1686,6 +1692,7 @@ impl<'tcx> Region<'tcx> {
             ty::ReErased => {
                 flags = flags | TypeFlags::HAS_RE_ERASED;
             }
+            ty::ReError(_) => {}
         }
 
         debug!("type_flags({:?}) = {:?}", self, flags);
diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs
new file mode 100644
index 00000000000..89f8de23583
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/large_enums.rs
@@ -0,0 +1,298 @@
+use crate::rustc_middle::ty::util::IntTypeExt;
+use crate::MirPass;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::mir::interpret::AllocId;
+use rustc_middle::mir::*;
+use rustc_middle::ty::{self, AdtDef, Const, ParamEnv, Ty, TyCtxt};
+use rustc_session::Session;
+use rustc_target::abi::{HasDataLayout, Size, TagEncoding, Variants};
+
+/// A pass that seeks to optimize unnecessary moves of large enum types, if there is a large
+/// enough discrepancy between them.
+///
+/// i.e. If there is are two variants:
+/// ```
+/// enum Example {
+///   Small,
+///   Large([u32; 1024]),
+/// }
+/// ```
+/// Instead of emitting moves of the large variant,
+/// Perform a memcpy instead.
+/// Based off of [this HackMD](https://hackmd.io/@ft4bxUsFT5CEUBmRKYHr7w/rJM8BBPzD).
+///
+/// In summary, what this does is at runtime determine which enum variant is active,
+/// and instead of copying all the bytes of the largest possible variant,
+/// copy only the bytes for the currently active variant.
+pub struct EnumSizeOpt {
+    pub(crate) discrepancy: u64,
+}
+
+impl<'tcx> MirPass<'tcx> for EnumSizeOpt {
+    fn is_enabled(&self, sess: &Session) -> bool {
+        sess.opts.unstable_opts.unsound_mir_opts || sess.mir_opt_level() >= 3
+    }
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        // NOTE: This pass may produce different MIR based on the alignment of the target
+        // platform, but it will still be valid.
+        self.optim(tcx, body);
+    }
+}
+
+impl EnumSizeOpt {
+    fn candidate<'tcx>(
+        &self,
+        tcx: TyCtxt<'tcx>,
+        param_env: ParamEnv<'tcx>,
+        ty: Ty<'tcx>,
+        alloc_cache: &mut FxHashMap<Ty<'tcx>, AllocId>,
+    ) -> Option<(AdtDef<'tcx>, usize, AllocId)> {
+        let adt_def = match ty.kind() {
+            ty::Adt(adt_def, _substs) if adt_def.is_enum() => adt_def,
+            _ => return None,
+        };
+        let layout = tcx.layout_of(param_env.and(ty)).ok()?;
+        let variants = match &layout.variants {
+            Variants::Single { .. } => return None,
+            Variants::Multiple { tag_encoding, .. }
+                if matches!(tag_encoding, TagEncoding::Niche { .. }) =>
+            {
+                return None;
+            }
+            Variants::Multiple { variants, .. } if variants.len() <= 1 => return None,
+            Variants::Multiple { variants, .. } => variants,
+        };
+        let min = variants.iter().map(|v| v.size).min().unwrap();
+        let max = variants.iter().map(|v| v.size).max().unwrap();
+        if max.bytes() - min.bytes() < self.discrepancy {
+            return None;
+        }
+
+        let num_discrs = adt_def.discriminants(tcx).count();
+        if variants.iter_enumerated().any(|(var_idx, _)| {
+            let discr_for_var = adt_def.discriminant_for_variant(tcx, var_idx).val;
+            (discr_for_var > usize::MAX as u128) || (discr_for_var as usize >= num_discrs)
+        }) {
+            return None;
+        }
+        if let Some(alloc_id) = alloc_cache.get(&ty) {
+            return Some((*adt_def, num_discrs, *alloc_id));
+        }
+
+        let data_layout = tcx.data_layout();
+        let ptr_sized_int = data_layout.ptr_sized_integer();
+        let target_bytes = ptr_sized_int.size().bytes() as usize;
+        let mut data = vec![0; target_bytes * num_discrs];
+        macro_rules! encode_store {
+            ($curr_idx: expr, $endian: expr, $bytes: expr) => {
+                let bytes = match $endian {
+                    rustc_target::abi::Endian::Little => $bytes.to_le_bytes(),
+                    rustc_target::abi::Endian::Big => $bytes.to_be_bytes(),
+                };
+                for (i, b) in bytes.into_iter().enumerate() {
+                    data[$curr_idx + i] = b;
+                }
+            };
+        }
+
+        for (var_idx, layout) in variants.iter_enumerated() {
+            let curr_idx =
+                target_bytes * adt_def.discriminant_for_variant(tcx, var_idx).val as usize;
+            let sz = layout.size;
+            match ptr_sized_int {
+                rustc_target::abi::Integer::I32 => {
+                    encode_store!(curr_idx, data_layout.endian, sz.bytes() as u32);
+                }
+                rustc_target::abi::Integer::I64 => {
+                    encode_store!(curr_idx, data_layout.endian, sz.bytes());
+                }
+                _ => unreachable!(),
+            };
+        }
+        let alloc = interpret::Allocation::from_bytes(
+            data,
+            tcx.data_layout.ptr_sized_integer().align(&tcx.data_layout).abi,
+            Mutability::Not,
+        );
+        let alloc = tcx.create_memory_alloc(tcx.intern_const_alloc(alloc));
+        Some((*adt_def, num_discrs, *alloc_cache.entry(ty).or_insert(alloc)))
+    }
+    fn optim<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        let mut alloc_cache = FxHashMap::default();
+        let body_did = body.source.def_id();
+        let param_env = tcx.param_env(body_did);
+
+        let blocks = body.basic_blocks.as_mut();
+        let local_decls = &mut body.local_decls;
+
+        for bb in blocks {
+            bb.expand_statements(|st| {
+                if let StatementKind::Assign(box (
+                    lhs,
+                    Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)),
+                )) = &st.kind
+                {
+                    let ty = lhs.ty(local_decls, tcx).ty;
+
+                    let source_info = st.source_info;
+                    let span = source_info.span;
+
+                    let (adt_def, num_variants, alloc_id) =
+                        self.candidate(tcx, param_env, ty, &mut alloc_cache)?;
+                    let alloc = tcx.global_alloc(alloc_id).unwrap_memory();
+
+                    let tmp_ty = tcx.mk_ty(ty::Array(
+                        tcx.types.usize,
+                        Const::from_usize(tcx, num_variants as u64),
+                    ));
+
+                    let size_array_local = local_decls.push(LocalDecl::new(tmp_ty, span));
+                    let store_live = Statement {
+                        source_info,
+                        kind: StatementKind::StorageLive(size_array_local),
+                    };
+
+                    let place = Place::from(size_array_local);
+                    let constant_vals = Constant {
+                        span,
+                        user_ty: None,
+                        literal: ConstantKind::Val(
+                            interpret::ConstValue::ByRef { alloc, offset: Size::ZERO },
+                            tmp_ty,
+                        ),
+                    };
+                    let rval = Rvalue::Use(Operand::Constant(box (constant_vals)));
+
+                    let const_assign =
+                        Statement { source_info, kind: StatementKind::Assign(box (place, rval)) };
+
+                    let discr_place = Place::from(
+                        local_decls
+                            .push(LocalDecl::new(adt_def.repr().discr_type().to_ty(tcx), span)),
+                    );
+
+                    let store_discr = Statement {
+                        source_info,
+                        kind: StatementKind::Assign(box (discr_place, Rvalue::Discriminant(*rhs))),
+                    };
+
+                    let discr_cast_place =
+                        Place::from(local_decls.push(LocalDecl::new(tcx.types.usize, span)));
+
+                    let cast_discr = Statement {
+                        source_info,
+                        kind: StatementKind::Assign(box (
+                            discr_cast_place,
+                            Rvalue::Cast(
+                                CastKind::IntToInt,
+                                Operand::Copy(discr_place),
+                                tcx.types.usize,
+                            ),
+                        )),
+                    };
+
+                    let size_place =
+                        Place::from(local_decls.push(LocalDecl::new(tcx.types.usize, span)));
+
+                    let store_size = Statement {
+                        source_info,
+                        kind: StatementKind::Assign(box (
+                            size_place,
+                            Rvalue::Use(Operand::Copy(Place {
+                                local: size_array_local,
+                                projection: tcx.intern_place_elems(&[PlaceElem::Index(
+                                    discr_cast_place.local,
+                                )]),
+                            })),
+                        )),
+                    };
+
+                    let dst =
+                        Place::from(local_decls.push(LocalDecl::new(tcx.mk_mut_ptr(ty), span)));
+
+                    let dst_ptr = Statement {
+                        source_info,
+                        kind: StatementKind::Assign(box (
+                            dst,
+                            Rvalue::AddressOf(Mutability::Mut, *lhs),
+                        )),
+                    };
+
+                    let dst_cast_ty = tcx.mk_mut_ptr(tcx.types.u8);
+                    let dst_cast_place =
+                        Place::from(local_decls.push(LocalDecl::new(dst_cast_ty, span)));
+
+                    let dst_cast = Statement {
+                        source_info,
+                        kind: StatementKind::Assign(box (
+                            dst_cast_place,
+                            Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(dst), dst_cast_ty),
+                        )),
+                    };
+
+                    let src =
+                        Place::from(local_decls.push(LocalDecl::new(tcx.mk_imm_ptr(ty), span)));
+
+                    let src_ptr = Statement {
+                        source_info,
+                        kind: StatementKind::Assign(box (
+                            src,
+                            Rvalue::AddressOf(Mutability::Not, *rhs),
+                        )),
+                    };
+
+                    let src_cast_ty = tcx.mk_imm_ptr(tcx.types.u8);
+                    let src_cast_place =
+                        Place::from(local_decls.push(LocalDecl::new(src_cast_ty, span)));
+
+                    let src_cast = Statement {
+                        source_info,
+                        kind: StatementKind::Assign(box (
+                            src_cast_place,
+                            Rvalue::Cast(CastKind::PtrToPtr, Operand::Copy(src), src_cast_ty),
+                        )),
+                    };
+
+                    let deinit_old =
+                        Statement { source_info, kind: StatementKind::Deinit(box dst) };
+
+                    let copy_bytes = Statement {
+                        source_info,
+                        kind: StatementKind::Intrinsic(
+                            box NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
+                                src: Operand::Copy(src_cast_place),
+                                dst: Operand::Copy(dst_cast_place),
+                                count: Operand::Copy(size_place),
+                            }),
+                        ),
+                    };
+
+                    let store_dead = Statement {
+                        source_info,
+                        kind: StatementKind::StorageDead(size_array_local),
+                    };
+                    let iter = [
+                        store_live,
+                        const_assign,
+                        store_discr,
+                        cast_discr,
+                        store_size,
+                        dst_ptr,
+                        dst_cast,
+                        src_ptr,
+                        src_cast,
+                        deinit_old,
+                        copy_bytes,
+                        store_dead,
+                    ]
+                    .into_iter();
+
+                    st.make_nop();
+                    Some(iter)
+                } else {
+                    None
+                }
+            });
+        }
+    }
+}
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 9070a7368b1..45cd4024c9f 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -1,6 +1,7 @@
 #![allow(rustc::potential_query_instability)]
 #![feature(box_patterns)]
 #![feature(drain_filter)]
+#![feature(box_syntax)]
 #![feature(let_chains)]
 #![feature(map_try_insert)]
 #![feature(min_specialization)]
@@ -73,6 +74,7 @@ mod function_item_references;
 mod generator;
 mod inline;
 mod instcombine;
+mod large_enums;
 mod lower_intrinsics;
 mod lower_slice_len;
 mod match_branches;
@@ -583,6 +585,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             &simplify::SimplifyLocals::new("final"),
             &multiple_return_terminators::MultipleReturnTerminators,
             &deduplicate_blocks::DeduplicateBlocks,
+            &large_enums::EnumSizeOpt { discrepancy: 128 },
             // Some cleanup necessary at least for LLVM and potentially other codegen backends.
             &add_call_guards::CriticalCallEdges,
             // Dump the end result for testing and debugging purposes.
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index 4dea03c1ef6..49309db564e 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -124,7 +124,7 @@ impl QueryContext for QueryCtxt<'_> {
             };
 
             // Use the `ImplicitCtxt` while we execute the query.
-            tls::enter_context(&new_icx, |_| {
+            tls::enter_context(&new_icx, || {
                 rustc_data_structures::stack::ensure_sufficient_stack(compute)
             })
         })
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index ca2a99971c3..bd74a010fa3 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1763,7 +1763,6 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
                             !segment.has_generic_args,
                             elided_lifetime_span,
                         );
-                        err.note("assuming a `'static` lifetime...");
                         err.emit();
                         should_lint = false;
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 2305ac19a33..c975a52e3f3 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -351,7 +351,7 @@ fn build_options<O: Default>(
 #[allow(non_upper_case_globals)]
 mod desc {
     pub const parse_no_flag: &str = "no value";
-    pub const parse_bool: &str = "one of: `y`, `yes`, `on`, `n`, `no`, or `off`";
+    pub const parse_bool: &str = "one of: `y`, `yes`, `on`, `true`, `n`, `no`, `off` or `false`";
     pub const parse_opt_bool: &str = parse_bool;
     pub const parse_string: &str = "a string";
     pub const parse_opt_string: &str = parse_string;
@@ -435,11 +435,11 @@ mod parse {
     /// Use this for any boolean option that has a static default.
     pub(crate) fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
         match v {
-            Some("y") | Some("yes") | Some("on") | None => {
+            Some("y") | Some("yes") | Some("on") | Some("true") | None => {
                 *slot = true;
                 true
             }
-            Some("n") | Some("no") | Some("off") => {
+            Some("n") | Some("no") | Some("off") | Some("false") => {
                 *slot = false;
                 true
             }
@@ -452,11 +452,11 @@ mod parse {
     /// other factors, such as other options, or target options.)
     pub(crate) fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
         match v {
-            Some("y") | Some("yes") | Some("on") | None => {
+            Some("y") | Some("yes") | Some("on") | Some("true") | None => {
                 *slot = Some(true);
                 true
             }
-            Some("n") | Some("no") | Some("off") => {
+            Some("n") | Some("no") | Some("off") | Some("false") => {
                 *slot = Some(false);
                 true
             }
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index c9b4ab0a38d..710f3826403 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -299,6 +299,7 @@ fn encode_region<'tcx>(
         RegionKind::ReEarlyBound(..)
         | RegionKind::ReFree(..)
         | RegionKind::ReStatic
+        | RegionKind::ReError(_)
         | RegionKind::ReVar(..)
         | RegionKind::RePlaceholder(..) => {
             bug!("encode_region: unexpected `{:?}`", region.kind());
diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml
index 3f863038efb..d3eba43b47e 100644
--- a/compiler/rustc_trait_selection/Cargo.toml
+++ b/compiler/rustc_trait_selection/Cargo.toml
@@ -24,3 +24,4 @@ rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
 rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
+itertools = "0.10.1"
diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs
index 775974d8e9a..126ec60b3d6 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly.rs
@@ -4,6 +4,7 @@ use super::infcx_ext::InferCtxtExt;
 #[cfg(doc)]
 use super::trait_goals::structural_traits::*;
 use super::{CanonicalResponse, Certainty, EvalCtxt, Goal, MaybeCause, QueryResult};
+use itertools::Itertools;
 use rustc_hir::def_id::DefId;
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::util::elaborate_predicates;
@@ -489,9 +490,9 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                 i += 1;
             }
 
-            // If there are *STILL* multiple candidates, give up
-            // and report ambiguity.
-            if candidates.len() > 1 {
+            // If there are *STILL* multiple candidates that have *different* response
+            // results, give up and report ambiguity.
+            if candidates.len() > 1 && !candidates.iter().map(|cand| cand.result).all_equal() {
                 let certainty = if candidates.iter().all(|x| {
                     matches!(x.result.value.certainty, Certainty::Maybe(MaybeCause::Overflow))
                 }) {
@@ -503,6 +504,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             }
         }
 
+        // FIXME: What if there are >1 candidates left with the same response, and one is a reservation impl?
         Ok(self.discard_reservation_impl(candidates.pop().unwrap()).result)
     }
 
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index c1936b7dbe4..a55b984fd63 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -73,6 +73,11 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
                                         MismatchedProjectionTypes { err: TypeError::Mismatch },
                                     )
                                 }
+                                ty::PredicateKind::AliasEq(_, _) => {
+                                    FulfillmentErrorCode::CodeProjectionError(
+                                        MismatchedProjectionTypes { err: TypeError::Mismatch },
+                                    )
+                                }
                                 ty::PredicateKind::Subtype(pred) => {
                                     let (a, b) = infcx.instantiate_binder_with_placeholders(
                                         goal.predicate.kind().rebind((pred.a, pred.b)),
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 9f092b6018f..e56588c58bd 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -42,6 +42,8 @@ mod trait_goals;
 
 pub use fulfill::FulfillmentCtxt;
 
+use self::infcx_ext::InferCtxtExt;
+
 /// A goal is a statement, i.e. `predicate`, we want to prove
 /// given some assumptions, i.e. `param_env`.
 ///
@@ -81,6 +83,21 @@ pub struct Response<'tcx> {
     pub certainty: Certainty,
 }
 
+trait CanonicalResponseExt {
+    fn has_no_inference_or_external_constraints(&self) -> bool;
+}
+
+impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> {
+    fn has_no_inference_or_external_constraints(&self) -> bool {
+        // so that we get a compile error when regions are supported
+        // so this code can be checked for being correct
+        let _: () = self.value.external_constraints.regions;
+
+        self.value.var_values.is_identity()
+            && self.value.external_constraints.opaque_types.is_empty()
+    }
+}
+
 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
 pub enum Certainty {
     Yes,
@@ -302,6 +319,9 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for Chalk")
                 }
+                ty::PredicateKind::AliasEq(lhs, rhs) => {
+                    self.compute_alias_eq_goal(Goal { param_env, predicate: (lhs, rhs) })
+                }
             }
         } else {
             let kind = self.infcx.instantiate_binder_with_placeholders(kind);
@@ -398,6 +418,63 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
             None => self.make_canonical_response(Certainty::AMBIGUOUS),
         }
     }
+
+    #[instrument(level = "debug", skip(self), ret)]
+    fn compute_alias_eq_goal(
+        &mut self,
+        goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>)>,
+    ) -> QueryResult<'tcx> {
+        let tcx = self.tcx();
+
+        let evaluate_normalizes_to = |ecx: &mut EvalCtxt<'_, 'tcx>, alias, other| {
+            debug!("evaluate_normalizes_to(alias={:?}, other={:?})", alias, other);
+            let r = ecx.infcx.probe(|_| {
+                let (_, certainty) = ecx.evaluate_goal(goal.with(
+                    tcx,
+                    ty::Binder::dummy(ty::ProjectionPredicate {
+                        projection_ty: alias,
+                        term: other,
+                    }),
+                ))?;
+                ecx.make_canonical_response(certainty)
+            });
+            debug!("evaluate_normalizes_to(..) -> {:?}", r);
+            r
+        };
+
+        if goal.predicate.0.is_infer() || goal.predicate.1.is_infer() {
+            bug!(
+                "`AliasEq` goal with an infer var on lhs or rhs which should have been instantiated"
+            );
+        }
+
+        match (
+            goal.predicate.0.to_alias_term_no_opaque(tcx),
+            goal.predicate.1.to_alias_term_no_opaque(tcx),
+        ) {
+            (None, None) => bug!("`AliasEq` goal without an alias on either lhs or rhs"),
+            (Some(alias), None) => evaluate_normalizes_to(self, alias, goal.predicate.1),
+            (None, Some(alias)) => evaluate_normalizes_to(self, alias, goal.predicate.0),
+            (Some(alias_lhs), Some(alias_rhs)) => {
+                debug!("compute_alias_eq_goal: both sides are aliases");
+
+                let mut candidates = Vec::with_capacity(3);
+
+                // Evaluate all 3 potential candidates for the alias' being equal
+                candidates.push(evaluate_normalizes_to(self, alias_lhs, goal.predicate.1));
+                candidates.push(evaluate_normalizes_to(self, alias_rhs, goal.predicate.0));
+                candidates.push(self.infcx.probe(|_| {
+                    debug!("compute_alias_eq_goal: alias defids are equal, equating substs");
+                    let nested_goals = self.infcx.eq(goal.param_env, alias_lhs, alias_rhs)?;
+                    self.evaluate_all_and_make_canonical_response(nested_goals)
+                }));
+
+                debug!(?candidates);
+
+                self.try_merge_responses(candidates.into_iter())
+            }
+        }
+    }
 }
 
 impl<'tcx> EvalCtxt<'_, 'tcx> {
@@ -449,6 +526,43 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
     ) -> QueryResult<'tcx> {
         self.evaluate_all(goals).and_then(|certainty| self.make_canonical_response(certainty))
     }
+
+    fn try_merge_responses(
+        &mut self,
+        responses: impl Iterator<Item = QueryResult<'tcx>>,
+    ) -> QueryResult<'tcx> {
+        let candidates = responses.into_iter().flatten().collect::<Box<[_]>>();
+
+        if candidates.is_empty() {
+            return Err(NoSolution);
+        }
+
+        // FIXME(-Ztreat-solver=next): We should instead try to find a `Certainty::Yes` response with
+        // a subset of the constraints that all the other responses have.
+        let one = candidates[0];
+        if candidates[1..].iter().all(|resp| resp == &one) {
+            return Ok(one);
+        }
+
+        if let Some(response) = candidates.iter().find(|response| {
+            response.value.certainty == Certainty::Yes
+                && response.has_no_inference_or_external_constraints()
+        }) {
+            return Ok(response.clone());
+        }
+
+        let certainty = candidates.iter().fold(Certainty::AMBIGUOUS, |certainty, response| {
+            certainty.unify_and(response.value.certainty)
+        });
+        // FIXME(-Ztrait-solver=next): We should take the intersection of the constraints on all the
+        // responses and use that for the constraints of this ambiguous response.
+        let response = self.make_canonical_response(certainty);
+        if let Ok(response) = &response {
+            assert!(response.has_no_inference_or_external_constraints());
+        }
+
+        response
+    }
 }
 
 #[instrument(level = "debug", skip(infcx), ret)]
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 948632ccc6c..6a840704e86 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -823,14 +823,17 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                         _ => return false,
                     }
                 }
+
                 // There's not really much we can do with these predicates -
                 // we start out with a `ParamEnv` with no inference variables,
                 // and these don't correspond to adding any new bounds to
                 // the `ParamEnv`.
                 ty::PredicateKind::WellFormed(..)
+                | ty::PredicateKind::AliasEq(..)
                 | ty::PredicateKind::ObjectSafe(..)
                 | ty::PredicateKind::ClosureKind(..)
                 | ty::PredicateKind::Subtype(..)
+                // FIXME(generic_const_exprs): you can absolutely add this as a where clauses
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::Coerce(..)
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
index ba9ee57d409..9474c70cb53 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
@@ -1,5 +1,7 @@
 use crate::infer::InferCtxt;
 
+use rustc_infer::infer::ObligationEmittingRelation;
+use rustc_infer::traits::PredicateObligations;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -88,3 +90,16 @@ impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
         Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
     }
 }
+
+impl<'tcx> ObligationEmittingRelation<'tcx> for CollectAllMismatches<'_, 'tcx> {
+    fn register_obligations(&mut self, _obligations: PredicateObligations<'tcx>) {
+        // FIXME(deferred_projection_equality)
+    }
+
+    fn register_predicates(
+        &mut self,
+        _obligations: impl IntoIterator<Item = impl ty::ToPredicate<'tcx>>,
+    ) {
+        // FIXME(deferred_projection_equality)
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index cf1e05ada47..4867855c2ae 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1278,6 +1278,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         span,
                         "TypeWellFormedFromEnv predicate should only exist in the environment"
                     ),
+
+                    ty::PredicateKind::AliasEq(..) => span_bug!(
+                        span,
+                        "AliasEq predicate should never be the predicate cause of a SelectionError"
+                    ),
                 }
             }
 
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 59aef52910e..048a5471994 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -19,6 +19,7 @@ use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
+use rustc_hir::is_range_literal;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
 use rustc_hir::{Expr, HirId};
@@ -98,6 +99,7 @@ impl<'tcx, 'a> GeneratorData<'tcx, 'a> {
     // obligation
     fn get_from_await_ty<F>(
         &self,
+        tcx: TyCtxt<'tcx>,
         visitor: AwaitsVisitor,
         hir: map::Map<'tcx>,
         ty_matches: F,
@@ -134,9 +136,7 @@ impl<'tcx, 'a> GeneratorData<'tcx, 'a> {
                                         .unwrap_or_else(|| {
                                             bug!(
                                                 "node_type: no type for node {}",
-                                                ty::tls::with(|tcx| tcx
-                                                    .hir()
-                                                    .node_to_string(await_expr.hir_id))
+                                                tcx.hir().node_to_string(await_expr.hir_id)
                                             )
                                         })
                                 },
@@ -1350,14 +1350,41 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             Applicability::MaybeIncorrect,
                         );
                     } else {
+                        // Issue #104961, we need to add parentheses properly for compond expressions
+                        // for example, `x.starts_with("hi".to_string() + "you")`
+                        // should be `x.starts_with(&("hi".to_string() + "you"))`
+                        let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return false; };
+                        let body = self.tcx.hir().body(body_id);
+                        let mut expr_finder = FindExprBySpan::new(span);
+                        expr_finder.visit_expr(body.value);
+                        let Some(expr) = expr_finder.result else { return false; };
+                        let needs_parens = match expr.kind {
+                            // parenthesize if needed (Issue #46756)
+                            hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
+                            // parenthesize borrows of range literals (Issue #54505)
+                            _ if is_range_literal(expr) => true,
+                            _ => false,
+                        };
+
                         let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut;
-                        err.span_suggestion_verbose(
-                            span.shrink_to_lo(),
-                            &format!(
-                                "consider{} borrowing here",
-                                if is_mut { " mutably" } else { "" }
-                            ),
-                            format!("&{}", if is_mut { "mut " } else { "" }),
+                        let span = if needs_parens { span } else { span.shrink_to_lo() };
+                        let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" });
+                        let sugg_msg = &format!(
+                            "consider{} borrowing here",
+                            if is_mut { " mutably" } else { "" }
+                        );
+
+                        let suggestions = if !needs_parens {
+                            vec![(span.shrink_to_lo(), format!("{}", sugg_prefix))]
+                        } else {
+                            vec![
+                                (span.shrink_to_lo(), format!("{}(", sugg_prefix)),
+                                (span.shrink_to_hi(), ")".to_string()),
+                            ]
+                        };
+                        err.multipart_suggestion_verbose(
+                            sugg_msg,
+                            suggestions,
                             Applicability::MaybeIncorrect,
                         );
                     }
@@ -2351,7 +2378,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
         let mut interior_or_upvar_span = None;
 
-        let from_awaited_ty = generator_data.get_from_await_ty(visitor, hir, ty_matches);
+        let from_awaited_ty = generator_data.get_from_await_ty(self.tcx, visitor, hir, ty_matches);
         debug!(?from_awaited_ty);
 
         // The generator interior types share the same binders
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 3adc1e62e0d..19d47d33f67 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -328,6 +328,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for Chalk")
                 }
+                ty::PredicateKind::AliasEq(..) => {
+                    bug!("AliasEq is only used for new solver")
+                }
             },
             Some(pred) => match pred {
                 ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
@@ -594,6 +597,9 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for Chalk")
                 }
+                ty::PredicateKind::AliasEq(..) => {
+                    bug!("AliasEq is only used for new solver")
+                }
             },
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index bafa2981a87..977446894e7 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -327,6 +327,8 @@ fn predicate_references_self<'tcx>(
             // possible alternatives.
             if data.projection_ty.substs[1..].iter().any(has_self_ty) { Some(sp) } else { None }
         }
+        ty::PredicateKind::AliasEq(..) => bug!("`AliasEq` not allowed as assumption"),
+
         ty::PredicateKind::WellFormed(..)
         | ty::PredicateKind::ObjectSafe(..)
         | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
@@ -334,6 +336,7 @@ fn predicate_references_self<'tcx>(
         | ty::PredicateKind::ClosureKind(..)
         | ty::PredicateKind::Subtype(..)
         | ty::PredicateKind::Coerce(..)
+        // FIXME(generic_const_exprs): this can mention `Self`
         | ty::PredicateKind::ConstEvaluatable(..)
         | ty::PredicateKind::ConstEquate(..)
         | ty::PredicateKind::Ambiguous
@@ -368,6 +371,7 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
             | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..))
             | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::ConstEquate(..)
+            | ty::PredicateKind::AliasEq(..)
             | ty::PredicateKind::Ambiguous
             | ty::PredicateKind::TypeWellFormedFromEnv(..) => false,
         }
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 984d6fde268..45c4811321a 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -991,6 +991,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ty::PredicateKind::TypeWellFormedFromEnv(..) => {
                     bug!("TypeWellFormedFromEnv is only used for chalk")
                 }
+                ty::PredicateKind::AliasEq(..) => {
+                    bug!("AliasEq is only used for new solver")
+                }
                 ty::PredicateKind::Ambiguous => Ok(EvaluatedToAmbig),
             }
         })
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 7c5e147a950..1136b70a0b9 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -187,6 +187,9 @@ pub fn predicate_obligations<'tcx>(
         ty::PredicateKind::TypeWellFormedFromEnv(..) => {
             bug!("TypeWellFormedFromEnv is only used for Chalk")
         }
+        ty::PredicateKind::AliasEq(..) => {
+            bug!("We should only wf check where clauses and `AliasEq` is not a `Clause`")
+        }
     }
 
     wf.normalize(infcx)
@@ -928,6 +931,7 @@ pub(crate) fn required_region_bounds<'tcx>(
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
                 | ty::PredicateKind::Ambiguous
+                | ty::PredicateKind::AliasEq(..)
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
                 ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
                     ref t,
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 9c5db3314c5..7c9a014e2ab 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -116,6 +116,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment<chalk_ir::Goal<RustInterner<'
                     )),
                 },
                 ty::PredicateKind::ObjectSafe(..)
+                | ty::PredicateKind::AliasEq(..)
                 | ty::PredicateKind::ClosureKind(..)
                 | ty::PredicateKind::Subtype(..)
                 | ty::PredicateKind::Coerce(..)
@@ -210,6 +211,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData<RustInterner<'tcx>>> for ty::Predi
             // We can defer this, but ultimately we'll want to express
             // some of these in terms of chalk operations.
             ty::PredicateKind::ClosureKind(..)
+            | ty::PredicateKind::AliasEq(..)
             | ty::PredicateKind::Coerce(..)
             | ty::PredicateKind::ConstEvaluatable(..)
             | ty::PredicateKind::Ambiguous
@@ -493,6 +495,9 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime<RustInterner<'tcx>>> for Region<'t
             ty::ReEarlyBound(_) => {
                 panic!("Should have already been substituted.");
             }
+            ty::ReError(_) => {
+                panic!("Error lifetime should not have already been lowered.");
+            }
             ty::ReLateBound(db, br) => chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new(
                 chalk_ir::DebruijnIndex::new(db.as_u32()),
                 br.var.as_usize(),
@@ -642,6 +647,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'
             ty::PredicateKind::WellFormed(_ty) => None,
 
             ty::PredicateKind::ObjectSafe(..)
+            | ty::PredicateKind::AliasEq(..)
             | ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::Subtype(..)
             | ty::PredicateKind::Coerce(..)
@@ -775,6 +781,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_solve::rust_ir::QuantifiedInlineBound<Ru
             ty::PredicateKind::WellFormed(_ty) => None,
 
             ty::PredicateKind::Clause(ty::Clause::RegionOutlives(..))
+            | ty::PredicateKind::AliasEq(..)
             | ty::PredicateKind::ObjectSafe(..)
             | ty::PredicateKind::ClosureKind(..)
             | ty::PredicateKind::Subtype(..)
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index fe633d687d9..93f9b66e0f8 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -70,47 +70,63 @@ fn compute_implied_outlives_bounds<'tcx>(
         let obligations = wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, DUMMY_SP)
             .unwrap_or_default();
 
-        // While these predicates should all be implied by other parts of
-        // the program, they are still relevant as they may constrain
-        // inference variables, which is necessary to add the correct
-        // implied bounds in some cases, mostly when dealing with projections.
-        ocx.register_obligations(
-            obligations.iter().filter(|o| o.predicate.has_non_region_infer()).cloned(),
-        );
-
-        // From the full set of obligations, just filter down to the
-        // region relationships.
-        outlives_bounds.extend(obligations.into_iter().filter_map(|obligation| {
+        for obligation in obligations {
+            debug!(?obligation);
             assert!(!obligation.has_escaping_bound_vars());
-            match obligation.predicate.kind().no_bound_vars() {
-                None => None,
-                Some(pred) => match pred {
-                    ty::PredicateKind::Clause(ty::Clause::Trait(..))
-                    | ty::PredicateKind::Subtype(..)
-                    | ty::PredicateKind::Coerce(..)
-                    | ty::PredicateKind::Clause(ty::Clause::Projection(..))
-                    | ty::PredicateKind::ClosureKind(..)
-                    | ty::PredicateKind::ObjectSafe(..)
-                    | ty::PredicateKind::ConstEvaluatable(..)
-                    | ty::PredicateKind::ConstEquate(..)
-                    | ty::PredicateKind::Ambiguous
-                    | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
-                    ty::PredicateKind::WellFormed(arg) => {
-                        wf_args.push(arg);
-                        None
+
+            // While these predicates should all be implied by other parts of
+            // the program, they are still relevant as they may constrain
+            // inference variables, which is necessary to add the correct
+            // implied bounds in some cases, mostly when dealing with projections.
+            //
+            // Another important point here: we only register `Projection`
+            // predicates, since otherwise we might register outlives
+            // predicates containing inference variables, and we don't
+            // learn anything new from those.
+            if obligation.predicate.has_non_region_infer() {
+                match obligation.predicate.kind().skip_binder() {
+                    ty::PredicateKind::Clause(ty::Clause::Projection(..))
+                    | ty::PredicateKind::AliasEq(..) => {
+                        ocx.register_obligation(obligation.clone());
                     }
+                    _ => {}
+                }
+            }
 
-                    ty::PredicateKind::Clause(ty::Clause::RegionOutlives(
-                        ty::OutlivesPredicate(r_a, r_b),
-                    )) => Some(ty::OutlivesPredicate(r_a.into(), r_b)),
+            let pred = match obligation.predicate.kind().no_bound_vars() {
+                None => continue,
+                Some(pred) => pred,
+            };
+            match pred {
+                ty::PredicateKind::Clause(ty::Clause::Trait(..))
+                | ty::PredicateKind::Subtype(..)
+                | ty::PredicateKind::Coerce(..)
+                | ty::PredicateKind::Clause(ty::Clause::Projection(..))
+                | ty::PredicateKind::ClosureKind(..)
+                | ty::PredicateKind::ObjectSafe(..)
+                | ty::PredicateKind::ConstEvaluatable(..)
+                | ty::PredicateKind::ConstEquate(..)
+                | ty::PredicateKind::Ambiguous
+                | ty::PredicateKind::AliasEq(..)
+                | ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
+
+                // We need to search through *all* WellFormed predicates
+                ty::PredicateKind::WellFormed(arg) => {
+                    wf_args.push(arg);
+                }
+
+                // We need to register region relationships
+                ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate(
+                    r_a,
+                    r_b,
+                ))) => outlives_bounds.push(ty::OutlivesPredicate(r_a.into(), r_b)),
 
-                    ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
-                        ty_a,
-                        r_b,
-                    ))) => Some(ty::OutlivesPredicate(ty_a.into(), r_b)),
-                },
+                ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
+                    ty_a,
+                    r_b,
+                ))) => outlives_bounds.push(ty::OutlivesPredicate(ty_a.into(), r_b)),
             }
-        }));
+        }
     }
 
     // This call to `select_all_or_error` is necessary to constrain inference variables, which we
diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs
index 9aa26667e7b..8bea5588ae7 100644
--- a/compiler/rustc_traits/src/lib.rs
+++ b/compiler/rustc_traits/src/lib.rs
@@ -4,6 +4,7 @@
 #![deny(rustc::untranslatable_diagnostic)]
 #![deny(rustc::diagnostic_outside_of_impl)]
 #![feature(let_chains)]
+#![feature(drain_filter)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index 5cad2c2ccb0..07e716cda42 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -60,6 +60,7 @@ fn not_outlives_predicate(p: ty::Predicate<'_>) -> bool {
         | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(..)) => false,
         ty::PredicateKind::Clause(ty::Clause::Trait(..))
         | ty::PredicateKind::Clause(ty::Clause::Projection(..))
+        | ty::PredicateKind::AliasEq(..)
         | ty::PredicateKind::WellFormed(..)
         | ty::PredicateKind::ObjectSafe(..)
         | ty::PredicateKind::ClosureKind(..)
diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs
index 3ede95e8431..61557fdc0ed 100644
--- a/compiler/rustc_type_ir/src/sty.rs
+++ b/compiler/rustc_type_ir/src/sty.rs
@@ -960,6 +960,9 @@ pub enum RegionKind<I: Interner> {
 
     /// Erased region, used by trait selection, in MIR and during codegen.
     ReErased,
+
+    /// A region that resulted from some other error. Used exclusively for diagnostics.
+    ReError(I::ErrorGuaranteed),
 }
 
 // This is manually implemented for `RegionKind` because `std::mem::discriminant`
@@ -974,6 +977,7 @@ const fn regionkind_discriminant<I: Interner>(value: &RegionKind<I>) -> usize {
         ReVar(_) => 4,
         RePlaceholder(_) => 5,
         ReErased => 6,
+        ReError(_) => 7,
     }
 }
 
@@ -985,6 +989,7 @@ where
     I::FreeRegion: Copy,
     I::RegionVid: Copy,
     I::PlaceholderRegion: Copy,
+    I::ErrorGuaranteed: Copy,
 {
 }
 
@@ -999,6 +1004,7 @@ impl<I: Interner> Clone for RegionKind<I> {
             ReVar(r) => ReVar(r.clone()),
             RePlaceholder(r) => RePlaceholder(r.clone()),
             ReErased => ReErased,
+            ReError(r) => ReError(r.clone()),
         }
     }
 }
@@ -1016,10 +1022,11 @@ impl<I: Interner> PartialEq for RegionKind<I> {
                 (ReVar(a_r), ReVar(b_r)) => a_r == b_r,
                 (RePlaceholder(a_r), RePlaceholder(b_r)) => a_r == b_r,
                 (ReErased, ReErased) => true,
+                (ReError(_), ReError(_)) => true,
                 _ => {
                     debug_assert!(
                         false,
-                        "This branch must be unreachable, maybe the match is missing an arm? self = self = {self:?}, other = {other:?}"
+                        "This branch must be unreachable, maybe the match is missing an arm? self = {self:?}, other = {other:?}"
                     );
                     true
                 }
@@ -1077,6 +1084,7 @@ impl<I: Interner> hash::Hash for RegionKind<I> {
             ReVar(r) => r.hash(state),
             RePlaceholder(r) => r.hash(state),
             ReErased => (),
+            ReError(_) => (),
         }
     }
 }
@@ -1100,6 +1108,8 @@ impl<I: Interner> fmt::Debug for RegionKind<I> {
             RePlaceholder(placeholder) => write!(f, "RePlaceholder({placeholder:?})"),
 
             ReErased => f.write_str("ReErased"),
+
+            ReError(_) => f.write_str("ReError"),
         }
     }
 }
@@ -1134,6 +1144,7 @@ where
                 a.encode(e);
             }),
             ReErased => e.emit_enum_variant(disc, |_| {}),
+            ReError(_) => e.emit_enum_variant(disc, |_| {}),
         }
     }
 }
@@ -1146,6 +1157,7 @@ where
     I::FreeRegion: Decodable<D>,
     I::RegionVid: Decodable<D>,
     I::PlaceholderRegion: Decodable<D>,
+    I::ErrorGuaranteed: Decodable<D>,
 {
     fn decode(d: &mut D) -> Self {
         match Decoder::read_usize(d) {
@@ -1156,6 +1168,7 @@ where
             4 => ReVar(Decodable::decode(d)),
             5 => RePlaceholder(Decodable::decode(d)),
             6 => ReErased,
+            7 => ReError(Decodable::decode(d)),
             _ => panic!(
                 "{}",
                 format!(
@@ -1184,7 +1197,7 @@ where
     ) {
         std::mem::discriminant(self).hash_stable(hcx, hasher);
         match self {
-            ReErased | ReStatic => {
+            ReErased | ReStatic | ReError(_) => {
                 // No variant fields to hash for these ...
             }
             ReLateBound(d, r) => {
diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs
index 1d80b8bf9ec..18da70451f2 100644
--- a/library/core/src/alloc/global.rs
+++ b/library/core/src/alloc/global.rs
@@ -203,7 +203,7 @@ pub unsafe trait GlobalAlloc {
         ptr
     }
 
-    /// Shrink or grow a block of memory to the given `new_size`.
+    /// Shrink or grow a block of memory to the given `new_size` in bytes.
     /// The block is described by the given `ptr` pointer and `layout`.
     ///
     /// If this returns a non-null pointer, then ownership of the memory block
@@ -211,10 +211,11 @@ pub unsafe trait GlobalAlloc {
     /// Any access to the old `ptr` is Undefined Behavior, even if the
     /// allocation remained in-place. The newly returned pointer is the only valid pointer
     /// for accessing this memory now.
+    ///
     /// The new memory block is allocated with `layout`,
-    /// but with the `size` updated to `new_size`. This new layout must be
-    /// used when deallocating the new memory block with `dealloc`. The range
-    /// `0..min(layout.size(), new_size)` of the new memory block is
+    /// but with the `size` updated to `new_size` in bytes.
+    /// This new layout must be used when deallocating the new memory block with `dealloc`.
+    /// The range `0..min(layout.size(), new_size)` of the new memory block is
     /// guaranteed to have the same values as the original block.
     ///
     /// If this method returns null, then ownership of the memory
diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs
index a342f0f5e85..a5ce6d5120d 100644
--- a/library/std/src/sys/unix/args.rs
+++ b/library/std/src/sys/unix/args.rs
@@ -141,12 +141,28 @@ mod imp {
             // list.
             let argv = ARGV.load(Ordering::Relaxed);
             let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) };
-            (0..argc)
-                .map(|i| {
-                    let cstr = CStr::from_ptr(*argv.offset(i) as *const libc::c_char);
-                    OsStringExt::from_vec(cstr.to_bytes().to_vec())
-                })
-                .collect()
+            let mut args = Vec::with_capacity(argc as usize);
+            for i in 0..argc {
+                let ptr = *argv.offset(i) as *const libc::c_char;
+
+                // Some C commandline parsers (e.g. GLib and Qt) are replacing already
+                // handled arguments in `argv` with `NULL` and move them to the end. That
+                // means that `argc` might be bigger than the actual number of non-`NULL`
+                // pointers in `argv` at this point.
+                //
+                // To handle this we simply stop iterating at the first `NULL` argument.
+                //
+                // `argv` is also guaranteed to be `NULL`-terminated so any non-`NULL` arguments
+                // after the first `NULL` can safely be ignored.
+                if ptr.is_null() {
+                    break;
+                }
+
+                let cstr = CStr::from_ptr(ptr);
+                args.push(OsStringExt::from_vec(cstr.to_bytes().to_vec()));
+            }
+
+            args
         }
     }
 }
diff --git a/library/std/src/sys/wasi/os.rs b/library/std/src/sys/wasi/os.rs
index f5513e9996d..9919dc7087e 100644
--- a/library/std/src/sys/wasi/os.rs
+++ b/library/std/src/sys/wasi/os.rs
@@ -21,6 +21,7 @@ mod libc {
     extern "C" {
         pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char;
         pub fn chdir(dir: *const c_char) -> c_int;
+        pub fn __wasilibc_get_environ() -> *mut *mut c_char;
     }
 }
 
@@ -161,7 +162,12 @@ impl Iterator for Env {
 pub fn env() -> Env {
     unsafe {
         let _guard = env_read_lock();
-        let mut environ = libc::environ;
+
+        // Use `__wasilibc_get_environ` instead of `environ` here so that we
+        // don't require wasi-libc to eagerly initialize the environment
+        // variables.
+        let mut environ = libc::__wasilibc_get_environ();
+
         let mut result = Vec::new();
         if !environ.is_null() {
             while !(*environ).is_null() {
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index 37809803828..f1a784b5fd2 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -1393,6 +1393,8 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> {
         let mut data = Align8([MaybeUninit::<u8>::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
         let data_ptr = data.0.as_mut_ptr();
         let db = data_ptr.cast::<c::REPARSE_MOUNTPOINT_DATA_BUFFER>();
+        // Zero the header to ensure it's fully initialized, including reserved parameters.
+        *db = mem::zeroed();
         let buf = ptr::addr_of_mut!((*db).ReparseTarget).cast::<c::WCHAR>();
         let mut i = 0;
         // FIXME: this conversion is very hacky
diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs
index 5c863015adb..6dcba117c24 100644
--- a/src/bootstrap/download.rs
+++ b/src/bootstrap/download.rs
@@ -229,10 +229,10 @@ impl Config {
             "--retry",
             "3",
             "-Sf",
-            "-o",
         ]);
-        curl.arg(tempfile);
         curl.arg(url);
+        let f = File::create(tempfile).unwrap();
+        curl.stdout(Stdio::from(f));
         if !self.check_run(&mut curl) {
             if self.build.contains("windows-msvc") {
                 println!("Fallback to PowerShell");
@@ -340,9 +340,12 @@ impl Config {
         let rustfmt_path = bin_root.join("bin").join(exe("rustfmt", host));
         let rustfmt_stamp = bin_root.join(".rustfmt-stamp");
 
-        let legacy_rustfmt = self.initial_rustc.with_file_name(exe("rustfmt", host));
-        if !legacy_rustfmt.exists() {
-            t!(self.symlink_file(&rustfmt_path, &legacy_rustfmt));
+        #[cfg(not(windows))]
+        {
+            let legacy_rustfmt = self.initial_rustc.with_file_name(exe("rustfmt", host));
+            if !legacy_rustfmt.exists() {
+                t!(self.symlink_file(&rustfmt_path, &legacy_rustfmt));
+            }
         }
 
         if rustfmt_path.exists() && !program_out_of_date(&rustfmt_stamp, &channel) {
diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index 1770c121a0e..c7f120dafea 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -49,10 +49,10 @@ Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard)
 platform security feature. This flag is currently ignored for non-Windows targets.
 It takes one of the following values:
 
-* `y`, `yes`, `on`, `checks`, or no value: enable Control Flow Guard.
+* `y`, `yes`, `on`, `true`, `checks`, or no value: enable Control Flow Guard.
 * `nochecks`: emit Control Flow Guard metadata without runtime enforcement checks (this
 should only be used for testing purposes as it does not provide security enforcement).
-* `n`, `no`, `off`: do not enable Control Flow Guard (the default).
+* `n`, `no`, `off`, `false`: do not enable Control Flow Guard (the default).
 
 ## debug-assertions
 
@@ -60,8 +60,8 @@ This flag lets you turn `cfg(debug_assertions)` [conditional
 compilation](../../reference/conditional-compilation.md#debug_assertions) on
 or off. It takes one of the following values:
 
-* `y`, `yes`, `on`, or no value: enable debug-assertions.
-* `n`, `no`, or `off`: disable debug-assertions.
+* `y`, `yes`, `on`, `true`, or no value: enable debug-assertions.
+* `n`, `no`, `off` or `false`: disable debug-assertions.
 
 If not specified, debug assertions are automatically enabled only if the
 [opt-level](#opt-level) is 0.
@@ -82,8 +82,8 @@ Note: The [`-g` flag][option-g-debug] is an alias for `-C debuginfo=2`.
 This flag controls whether or not the linker includes its default libraries.
 It takes one of the following values:
 
-* `y`, `yes`, `on`, or no value: include default libraries (the default).
-* `n`, `no`, or `off`: exclude default libraries.
+* `y`, `yes`, `on`, `true` or no value: include default libraries (the default).
+* `n`, `no`, `off` or `false`: exclude default libraries.
 
 For example, for gcc flavor linkers, this issues the `-nodefaultlibs` flag to
 the linker.
@@ -93,8 +93,8 @@ the linker.
 This flag controls whether or not the compiler embeds LLVM bitcode into object
 files. It takes one of the following values:
 
-* `y`, `yes`, `on`, or no value: put bitcode in rlibs (the default).
-* `n`, `no`, or `off`: omit bitcode from rlibs.
+* `y`, `yes`, `on`, `true` or no value: put bitcode in rlibs (the default).
+* `n`, `no`, `off` or `false`: omit bitcode from rlibs.
 
 LLVM bitcode is required when rustc is performing link-time optimization (LTO).
 It is also required on some targets like iOS ones where vendors look for LLVM
@@ -135,8 +135,8 @@ flag][option-emit] for more information.
 This flag forces the use of frame pointers. It takes one of the following
 values:
 
-* `y`, `yes`, `on`, or no value: force-enable frame pointers.
-* `n`, `no`, or `off`: do not force-enable frame pointers. This does
+* `y`, `yes`, `on`, `true` or no value: force-enable frame pointers.
+* `n`, `no`, `off` or `false`: do not force-enable frame pointers. This does
   not necessarily mean frame pointers will be removed.
 
 The default behaviour, if frame pointers are not force-enabled, depends on the
@@ -147,8 +147,8 @@ target.
 This flag forces the generation of unwind tables. It takes one of the following
 values:
 
-* `y`, `yes`, `on`, or no value: Unwind tables are forced to be generated.
-* `n`, `no`, or `off`: Unwind tables are not forced to be generated. If unwind
+* `y`, `yes`, `on`, `true` or no value: Unwind tables are forced to be generated.
+* `n`, `no`, `off` or `false`: Unwind tables are not forced to be generated. If unwind
   tables are required by the target an error will be emitted.
 
 The default if not specified depends on the target.
@@ -202,8 +202,8 @@ options should be separated by spaces.
 This flag controls whether the linker will keep dead code. It takes one of
 the following values:
 
-* `y`, `yes`, `on`, or no value: keep dead code.
-* `n`, `no`, or `off`: remove dead code (the default).
+* `y`, `yes`, `on`, `true` or no value: keep dead code.
+* `n`, `no`, `off` or `false`: remove dead code (the default).
 
 An example of when this flag might be useful is when trying to construct code coverage
 metrics.
@@ -215,8 +215,8 @@ linker will use libraries and objects shipped with Rust instead or those in the
 It takes one of the following values:
 
 * no value: rustc will use heuristic to disable self-contained mode if system has necessary tools.
-* `y`, `yes`, `on`: use only libraries/objects shipped with Rust.
-* `n`, `no`, or `off`: rely on the user or the linker to provide non-Rust libraries/objects.
+* `y`, `yes`, `on`, `true`: use only libraries/objects shipped with Rust.
+* `n`, `no`, `off` or `false`: rely on the user or the linker to provide non-Rust libraries/objects.
 
 This allows overriding cases when detection fails or user wants to use shipped libraries.
 
@@ -261,8 +261,8 @@ This flag defers LTO optimizations to the linker. See
 [linker-plugin-LTO](../linker-plugin-lto.md) for more details. It takes one of
 the following values:
 
-* `y`, `yes`, `on`, or no value: enable linker plugin LTO.
-* `n`, `no`, or `off`: disable linker plugin LTO (the default).
+* `y`, `yes`, `on`, `true` or no value: enable linker plugin LTO.
+* `n`, `no`, `off` or `false`: disable linker plugin LTO (the default).
 * A path to the linker plugin.
 
 More specifically this flag will cause the compiler to replace its typical
@@ -292,9 +292,9 @@ optimizations](https://llvm.org/docs/LinkTimeOptimization.html) to produce
 better optimized code, using whole-program analysis, at the cost of longer
 linking time. It takes one of the following values:
 
-* `y`, `yes`, `on`, `fat`, or no value: perform "fat" LTO which attempts to
+* `y`, `yes`, `on`, `true`, `fat`, or no value: perform "fat" LTO which attempts to
   perform optimizations across all crates within the dependency graph.
-* `n`, `no`, `off`: disables LTO.
+* `n`, `no`, `off`, `false`: disables LTO.
 * `thin`: perform ["thin"
   LTO](http://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html).
   This is similar to "fat", but takes substantially less time to run while
@@ -333,8 +333,8 @@ This flag allows you to disable [the
 red zone](https://en.wikipedia.org/wiki/Red_zone_\(computing\)). It takes one
 of the following values:
 
-* `y`, `yes`, `on`, or no value: disable the red zone.
-* `n`, `no`, or `off`: enable the red zone.
+* `y`, `yes`, `on`, `true` or no value: disable the red zone.
+* `n`, `no`, `off` or `false`: enable the red zone.
 
 The default behaviour, if the flag is not specified, depends on the target.
 
@@ -376,8 +376,8 @@ overflow](../../reference/expressions/operator-expr.md#overflow). When
 overflow-checks are enabled, a panic will occur on overflow. This flag takes
 one of the following values:
 
-* `y`, `yes`, `on`, or no value: enable overflow checks.
-* `n`, `no`, or `off`: disable overflow checks.
+* `y`, `yes`, `on`, `true` or no value: enable overflow checks.
+* `n`, `no`, `off` or `false`: disable overflow checks.
 
 If not specified, overflow checks are enabled if
 [debug-assertions](#debug-assertions) are enabled, disabled otherwise.
@@ -409,8 +409,8 @@ for determining whether or not it is possible to statically or dynamically
 link with a dependency. For example, `cdylib` crate types may only use static
 linkage. This flag takes one of the following values:
 
-* `y`, `yes`, `on`, or no value: use dynamic linking.
-* `n`, `no`, or `off`: use static linking (the default).
+* `y`, `yes`, `on`, `true` or no value: use dynamic linking.
+* `n`, `no`, `off` or `false`: use static linking (the default).
 
 ## profile-generate
 
@@ -487,24 +487,24 @@ The list of passes should be separated by spaces.
 This flag controls whether [`rpath`](https://en.wikipedia.org/wiki/Rpath) is
 enabled. It takes one of the following values:
 
-* `y`, `yes`, `on`, or no value: enable rpath.
-* `n`, `no`, or `off`: disable rpath (the default).
+* `y`, `yes`, `on`, `true` or no value: enable rpath.
+* `n`, `no`, `off` or `false`: disable rpath (the default).
 
 ## save-temps
 
 This flag controls whether temporary files generated during compilation are
 deleted once compilation finishes. It takes one of the following values:
 
-* `y`, `yes`, `on`, or no value: save temporary files.
-* `n`, `no`, or `off`: delete temporary files (the default).
+* `y`, `yes`, `on`, `true` or no value: save temporary files.
+* `n`, `no`, `off` or `false`: delete temporary files (the default).
 
 ## soft-float
 
 This option controls whether `rustc` generates code that emulates floating
 point instructions in software. It takes one of the following values:
 
-* `y`, `yes`, `on`, or no value: use soft floats.
-* `n`, `no`, or `off`: use hardware floats (the default).
+* `y`, `yes`, `on`, `true` or no value: use soft floats.
+* `n`, `no`, `off` or `false`: use hardware floats (the default).
 
 ## split-debuginfo
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 80493b100bb..d497f7ea679 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -242,6 +242,7 @@ pub(crate) fn clean_middle_region<'tcx>(region: ty::Region<'tcx>) -> Option<Life
         ty::ReLateBound(..)
         | ty::ReFree(..)
         | ty::ReVar(..)
+        | ty::ReError(_)
         | ty::RePlaceholder(..)
         | ty::ReErased => {
             debug!("cannot clean region {:?}", region);
@@ -310,10 +311,12 @@ pub(crate) fn clean_predicate<'tcx>(
         ty::PredicateKind::Clause(ty::Clause::Projection(pred)) => {
             Some(clean_projection_predicate(bound_predicate.rebind(pred), cx))
         }
+        // FIXME(generic_const_exprs): should this do something?
         ty::PredicateKind::ConstEvaluatable(..) => None,
         ty::PredicateKind::WellFormed(..) => None,
 
         ty::PredicateKind::Subtype(..)
+        | ty::PredicateKind::AliasEq(..)
         | ty::PredicateKind::Coerce(..)
         | ty::PredicateKind::ObjectSafe(..)
         | ty::PredicateKind::ClosureKind(..)
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index b59645ec2e2..1216a8d71c8 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -18,7 +18,7 @@ use super::search_index::build_index;
 use super::write_shared::write_shared;
 use super::{
     collect_spans_and_sources, print_sidebar, scrape_examples_help, sidebar_module_like, AllTypes,
-    LinkFromSrc, NameDoc, StylePath,
+    LinkFromSrc, StylePath,
 };
 
 use crate::clean::{self, types::ExternalLocation, ExternalCrate};
@@ -256,7 +256,7 @@ impl<'tcx> Context<'tcx> {
     }
 
     /// Construct a map of items shown in the sidebar to a plain-text summary of their docs.
-    fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap<String, Vec<NameDoc>> {
+    fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap<String, Vec<String>> {
         // BTreeMap instead of HashMap to get a sorted output
         let mut map: BTreeMap<_, Vec<_>> = BTreeMap::new();
         let mut inserted: FxHashMap<ItemType, FxHashSet<Symbol>> = FxHashMap::default();
@@ -274,10 +274,7 @@ impl<'tcx> Context<'tcx> {
             if inserted.entry(short).or_default().insert(myname) {
                 let short = short.to_string();
                 let myname = myname.to_string();
-                map.entry(short).or_default().push((
-                    myname,
-                    Some(item.doc_value().map_or_else(String::new, |s| plain_text_summary(&s))),
-                ));
+                map.entry(short).or_default().push(myname);
             }
         }
 
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index fa22c461205..6a9a7a6b1a0 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -83,9 +83,6 @@ use crate::scrape_examples::{CallData, CallLocation};
 use crate::try_none;
 use crate::DOC_RUST_LANG_ORG_CHANNEL;
 
-/// A pair of name and its optional document.
-pub(crate) type NameDoc = (String, Option<String>);
-
 pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
     crate::html::format::display_fn(move |f| {
         if !v.ends_with('/') && !v.is_empty() { write!(f, "{}/", v) } else { f.write_str(v) }
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index c2d24e51484..82a51a8467b 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1109,7 +1109,7 @@ fn item_typedef(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clea
 fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean::Union) {
     wrap_item(w, |w| {
         render_attributes_in_pre(w, it, "");
-        render_union(w, it, Some(&s.generics), &s.fields, "", cx);
+        render_union(w, it, Some(&s.generics), &s.fields, cx);
     });
 
     document(w, cx, it, None, HeadingOffset::H2);
@@ -1628,7 +1628,6 @@ fn render_union(
     it: &clean::Item,
     g: Option<&clean::Generics>,
     fields: &[clean::Item],
-    tab: &str,
     cx: &Context<'_>,
 ) {
     let tcx = cx.tcx();
@@ -1651,7 +1650,7 @@ fn render_union(
         w.write_str(" ");
     }
 
-    write!(w, "{{\n{}", tab);
+    write!(w, "{{\n");
     let count_fields =
         fields.iter().filter(|f| matches!(*f.kind, clean::StructFieldItem(..))).count();
     let toggle = should_hide_fields(count_fields);
@@ -1663,17 +1662,16 @@ fn render_union(
         if let clean::StructFieldItem(ref ty) = *field.kind {
             write!(
                 w,
-                "    {}{}: {},\n{}",
+                "    {}{}: {},\n",
                 visibility_print_with_space(field.visibility(tcx), field.item_id, cx),
                 field.name.unwrap(),
-                ty.print(cx),
-                tab
+                ty.print(cx)
             );
         }
     }
 
     if it.has_stripped_entries().unwrap() {
-        write!(w, "    /* private fields */\n{}", tab);
+        write!(w, "    /* private fields */\n");
     }
     if toggle {
         toggle_close(w);
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index c66f500f423..aa4d65b4bfb 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -455,10 +455,7 @@ function loadCss(cssUrl) {
             const ul = document.createElement("ul");
             ul.className = "block " + shortty;
 
-            for (const item of filtered) {
-                const name = item[0];
-                const desc = item[1]; // can be null
-
+            for (const name of filtered) {
                 let path;
                 if (shortty === "mod") {
                     path = name + "/index.html";
@@ -468,7 +465,6 @@ function loadCss(cssUrl) {
                 const current_page = document.location.href.split("/").pop();
                 const link = document.createElement("a");
                 link.href = path;
-                link.title = desc;
                 if (path === current_page) {
                     link.className = "current";
                 }
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index b22c12fa810..feefb8b69d1 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -806,9 +806,9 @@ fn main_args(at_args: &[String]) -> MainResult {
                 sess.fatal("Compilation failed, aborting rustdoc");
             }
 
-            let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess);
+            let mut gcx = abort_on_err(queries.global_ctxt(), sess);
 
-            global_ctxt.enter(|tcx| {
+            gcx.enter(|tcx| {
                 let (krate, render_opts, mut cache) = sess.time("run_global_ctxt", || {
                     core::run_global_ctxt(
                         tcx,
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index e2cde09776f..659e8aebcd5 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -4383,6 +4383,7 @@ Released 2018-09-13
 [`extend_from_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_from_slice
 [`extend_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#extend_with_drain
 [`extra_unused_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes
+[`extra_unused_type_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_type_parameters
 [`fallible_impl_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#fallible_impl_from
 [`field_reassign_with_default`]: https://rust-lang.github.io/rust-clippy/master/index.html#field_reassign_with_default
 [`filetype_is_file`]: https://rust-lang.github.io/rust-clippy/master/index.html#filetype_is_file
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 2cfb47dd758..70d1268090f 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -42,6 +42,7 @@ filetime = "0.2"
 rustc-workspace-hack = "1.0"
 
 # UI test dependencies
+clap = { version = "4.1.4", features = ["derive"] }
 clippy_utils = { path = "clippy_utils" }
 derive-new = "0.5"
 if_chain = "1.0"
diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md
index ab44db69483..95f6d2cc45c 100644
--- a/src/tools/clippy/README.md
+++ b/src/tools/clippy/README.md
@@ -5,7 +5,7 @@
 
 A collection of lints to catch common mistakes and improve your [Rust](https://github.com/rust-lang/rust) code.
 
-[There are over 550 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
+[There are over 600 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
 
 Lints are divided into categories, each with a default [lint level](https://doc.rust-lang.org/rustc/lints/levels.html).
 You can choose how much Clippy is supposed to ~~annoy~~ help you by changing the lint level by category.
diff --git a/src/tools/clippy/book/src/README.md b/src/tools/clippy/book/src/README.md
index 23867df8efe..df4a1f2702e 100644
--- a/src/tools/clippy/book/src/README.md
+++ b/src/tools/clippy/book/src/README.md
@@ -6,7 +6,7 @@
 A collection of lints to catch common mistakes and improve your
 [Rust](https://github.com/rust-lang/rust) code.
 
-[There are over 550 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
+[There are over 600 lints included in this crate!](https://rust-lang.github.io/rust-clippy/master/index.html)
 
 Lints are divided into categories, each with a default [lint
 level](https://doc.rust-lang.org/rustc/lints/levels.html). You can choose how
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index f79dbb50ff4..32e8e218c40 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -43,6 +43,7 @@ Please use that command to update the file and do not edit it by hand.
 | [allowed-scripts](#allowed-scripts) | `["Latin"]` |
 | [enable-raw-pointer-heuristic-for-send](#enable-raw-pointer-heuristic-for-send) | `true` |
 | [max-suggested-slice-pattern-length](#max-suggested-slice-pattern-length) | `3` |
+| [await-holding-invalid-types](#await-holding-invalid-types) | `[]` |
 | [max-include-file-size](#max-include-file-size) | `1000000` |
 | [allow-expect-in-tests](#allow-expect-in-tests) | `false` |
 | [allow-unwrap-in-tests](#allow-unwrap-in-tests) | `false` |
@@ -167,6 +168,17 @@ The minimum rust version that the project supports
 * [manual_clamp](https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp)
 * [manual_let_else](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else)
 * [unchecked_duration_subtraction](https://rust-lang.github.io/rust-clippy/master/index.html#unchecked_duration_subtraction)
+* [collapsible_str_replace](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_str_replace)
+* [seek_from_current](https://rust-lang.github.io/rust-clippy/master/index.html#seek_from_current)
+* [seek_rewind](https://rust-lang.github.io/rust-clippy/master/index.html#seek_rewind)
+* [unnecessary_lazy_evaluations](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_lazy_evaluations)
+* [transmute_ptr_to_ref](https://rust-lang.github.io/rust-clippy/master/index.html#transmute_ptr_to_ref)
+* [almost_complete_range](https://rust-lang.github.io/rust-clippy/master/index.html#almost_complete_range)
+* [needless_borrow](https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow)
+* [derivable_impls](https://rust-lang.github.io/rust-clippy/master/index.html#derivable_impls)
+* [manual_is_ascii_check](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check)
+* [manual_rem_euclid](https://rust-lang.github.io/rust-clippy/master/index.html#manual_rem_euclid)
+* [manual_retain](https://rust-lang.github.io/rust-clippy/master/index.html#manual_retain)
 
 
 ### cognitive-complexity-threshold
@@ -279,7 +291,7 @@ The minimum size (in bytes) to consider a type for passing by reference instead
 
 **Default Value:** `256` (`u64`)
 
-* [large_type_pass_by_move](https://rust-lang.github.io/rust-clippy/master/index.html#large_type_pass_by_move)
+* [large_types_passed_by_value](https://rust-lang.github.io/rust-clippy/master/index.html#large_types_passed_by_value)
 
 
 ### too-many-lines-threshold
@@ -442,6 +454,14 @@ For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
 * [index_refutable_slice](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice)
 
 
+### await-holding-invalid-types
+
+
+**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
+
+* [await_holding_invalid_type](https://rust-lang.github.io/rust-clippy/master/index.html#await_holding_invalid_type)
+
+
 ### max-include-file-size
 The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes
 
@@ -497,7 +517,7 @@ for the generic parameters for determining interior mutability
 
 **Default Value:** `["bytes::Bytes"]` (`Vec<String>`)
 
-* [mutable_key](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key)
+* [mutable_key_type](https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type)
 
 
 ### allow-mixed-uninlined-format-args
@@ -509,7 +529,7 @@ Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)
 
 
 ### suppress-restriction-lint-in-const
-In same
+Whether to suppress a restriction lint in constant code. In same
 cases the restructured operation might not be unavoidable, as the
 suggested counterparts are unavailable in constant code. This
 configuration will cause restriction lints to trigger even
diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml
index 510c7e852af..c3f8a782d27 100644
--- a/src/tools/clippy/clippy_dev/Cargo.toml
+++ b/src/tools/clippy/clippy_dev/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
 
 [dependencies]
 aho-corasick = "0.7"
-clap = "3.2"
+clap = "4.1.4"
 indoc = "1.0"
 itertools = "0.10.1"
 opener = "0.5"
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index d3e03669204..e2457e5a8a5 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -2,7 +2,7 @@
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
-use clap::{Arg, ArgAction, ArgMatches, Command, PossibleValue};
+use clap::{Arg, ArgAction, ArgMatches, Command};
 use clippy_dev::{bless, dogfood, fmt, lint, new_lint, serve, setup, update_lints};
 use indoc::indoc;
 
@@ -11,22 +11,22 @@ fn main() {
 
     match matches.subcommand() {
         Some(("bless", matches)) => {
-            bless::bless(matches.contains_id("ignore-timestamp"));
+            bless::bless(matches.get_flag("ignore-timestamp"));
         },
         Some(("dogfood", matches)) => {
             dogfood::dogfood(
-                matches.contains_id("fix"),
-                matches.contains_id("allow-dirty"),
-                matches.contains_id("allow-staged"),
+                matches.get_flag("fix"),
+                matches.get_flag("allow-dirty"),
+                matches.get_flag("allow-staged"),
             );
         },
         Some(("fmt", matches)) => {
-            fmt::run(matches.contains_id("check"), matches.contains_id("verbose"));
+            fmt::run(matches.get_flag("check"), matches.get_flag("verbose"));
         },
         Some(("update_lints", matches)) => {
-            if matches.contains_id("print-only") {
+            if matches.get_flag("print-only") {
                 update_lints::print_lints();
-            } else if matches.contains_id("check") {
+            } else if matches.get_flag("check") {
                 update_lints::update(update_lints::UpdateMode::Check);
             } else {
                 update_lints::update(update_lints::UpdateMode::Change);
@@ -38,7 +38,7 @@ fn main() {
                 matches.get_one::<String>("name"),
                 matches.get_one::<String>("category").map(String::as_str),
                 matches.get_one::<String>("type").map(String::as_str),
-                matches.contains_id("msrv"),
+                matches.get_flag("msrv"),
             ) {
                 Ok(_) => update_lints::update(update_lints::UpdateMode::Change),
                 Err(e) => eprintln!("Unable to create lint: {e}"),
@@ -46,7 +46,7 @@ fn main() {
         },
         Some(("setup", sub_command)) => match sub_command.subcommand() {
             Some(("intellij", matches)) => {
-                if matches.contains_id("remove") {
+                if matches.get_flag("remove") {
                     setup::intellij::remove_rustc_src();
                 } else {
                     setup::intellij::setup_rustc_src(
@@ -57,17 +57,17 @@ fn main() {
                 }
             },
             Some(("git-hook", matches)) => {
-                if matches.contains_id("remove") {
+                if matches.get_flag("remove") {
                     setup::git_hook::remove_hook();
                 } else {
-                    setup::git_hook::install_hook(matches.contains_id("force-override"));
+                    setup::git_hook::install_hook(matches.get_flag("force-override"));
                 }
             },
             Some(("vscode-tasks", matches)) => {
-                if matches.contains_id("remove") {
+                if matches.get_flag("remove") {
                     setup::vscode::remove_tasks();
                 } else {
-                    setup::vscode::install_tasks(matches.contains_id("force-override"));
+                    setup::vscode::install_tasks(matches.get_flag("force-override"));
                 }
             },
             _ => {},
@@ -91,7 +91,7 @@ fn main() {
         Some(("rename_lint", matches)) => {
             let old_name = matches.get_one::<String>("old_name").unwrap();
             let new_name = matches.get_one::<String>("new_name").unwrap_or(old_name);
-            let uplift = matches.contains_id("uplift");
+            let uplift = matches.get_flag("uplift");
             update_lints::rename(old_name, new_name, uplift);
         },
         Some(("deprecate", matches)) => {
@@ -110,24 +110,37 @@ fn get_clap_config() -> ArgMatches {
             Command::new("bless").about("bless the test output changes").arg(
                 Arg::new("ignore-timestamp")
                     .long("ignore-timestamp")
+                    .action(ArgAction::SetTrue)
                     .help("Include files updated before clippy was built"),
             ),
             Command::new("dogfood").about("Runs the dogfood test").args([
-                Arg::new("fix").long("fix").help("Apply the suggestions when possible"),
+                Arg::new("fix")
+                    .long("fix")
+                    .action(ArgAction::SetTrue)
+                    .help("Apply the suggestions when possible"),
                 Arg::new("allow-dirty")
                     .long("allow-dirty")
+                    .action(ArgAction::SetTrue)
                     .help("Fix code even if the working directory has changes")
                     .requires("fix"),
                 Arg::new("allow-staged")
                     .long("allow-staged")
+                    .action(ArgAction::SetTrue)
                     .help("Fix code even if the working directory has staged changes")
                     .requires("fix"),
             ]),
             Command::new("fmt")
                 .about("Run rustfmt on all projects and tests")
                 .args([
-                    Arg::new("check").long("check").help("Use the rustfmt --check option"),
-                    Arg::new("verbose").short('v').long("verbose").help("Echo commands run"),
+                    Arg::new("check")
+                        .long("check")
+                        .action(ArgAction::SetTrue)
+                        .help("Use the rustfmt --check option"),
+                    Arg::new("verbose")
+                        .short('v')
+                        .long("verbose")
+                        .action(ArgAction::SetTrue)
+                        .help("Echo commands run"),
                 ]),
             Command::new("update_lints")
                 .about("Updates lint registration and information from the source code")
@@ -140,13 +153,17 @@ fn get_clap_config() -> ArgMatches {
                     * all lints are registered in the lint store",
                 )
                 .args([
-                    Arg::new("print-only").long("print-only").help(
-                        "Print a table of lints to STDOUT. \
-                        This does not include deprecated and internal lints. \
-                        (Does not modify any files)",
-                    ),
+                    Arg::new("print-only")
+                        .long("print-only")
+                        .action(ArgAction::SetTrue)
+                        .help(
+                            "Print a table of lints to STDOUT. \
+                            This does not include deprecated and internal lints. \
+                            (Does not modify any files)",
+                        ),
                     Arg::new("check")
                         .long("check")
+                        .action(ArgAction::SetTrue)
                         .help("Checks that `cargo dev update_lints` has been run. Used on CI."),
                 ]),
             Command::new("new_lint")
@@ -156,15 +173,13 @@ fn get_clap_config() -> ArgMatches {
                         .short('p')
                         .long("pass")
                         .help("Specify whether the lint runs during the early or late pass")
-                        .takes_value(true)
-                        .value_parser([PossibleValue::new("early"), PossibleValue::new("late")])
+                        .value_parser(["early", "late"])
                         .conflicts_with("type")
                         .required_unless_present("type"),
                     Arg::new("name")
                         .short('n')
                         .long("name")
                         .help("Name of the new lint in snake case, ex: fn_too_long")
-                        .takes_value(true)
                         .required(true),
                     Arg::new("category")
                         .short('c')
@@ -172,25 +187,23 @@ fn get_clap_config() -> ArgMatches {
                         .help("What category the lint belongs to")
                         .default_value("nursery")
                         .value_parser([
-                            PossibleValue::new("style"),
-                            PossibleValue::new("correctness"),
-                            PossibleValue::new("suspicious"),
-                            PossibleValue::new("complexity"),
-                            PossibleValue::new("perf"),
-                            PossibleValue::new("pedantic"),
-                            PossibleValue::new("restriction"),
-                            PossibleValue::new("cargo"),
-                            PossibleValue::new("nursery"),
-                            PossibleValue::new("internal"),
-                            PossibleValue::new("internal_warn"),
-                        ])
-                        .takes_value(true),
-                    Arg::new("type")
-                        .long("type")
-                        .help("What directory the lint belongs in")
-                        .takes_value(true)
-                        .required(false),
-                    Arg::new("msrv").long("msrv").help("Add MSRV config code to the lint"),
+                            "style",
+                            "correctness",
+                            "suspicious",
+                            "complexity",
+                            "perf",
+                            "pedantic",
+                            "restriction",
+                            "cargo",
+                            "nursery",
+                            "internal",
+                            "internal_warn",
+                        ]),
+                    Arg::new("type").long("type").help("What directory the lint belongs in"),
+                    Arg::new("msrv")
+                        .long("msrv")
+                        .action(ArgAction::SetTrue)
+                        .help("Add MSRV config code to the lint"),
                 ]),
             Command::new("setup")
                 .about("Support for setting up your personal development environment")
@@ -201,13 +214,12 @@ fn get_clap_config() -> ArgMatches {
                         .args([
                             Arg::new("remove")
                                 .long("remove")
-                                .help("Remove the dependencies added with 'cargo dev setup intellij'")
-                                .required(false),
+                                .action(ArgAction::SetTrue)
+                                .help("Remove the dependencies added with 'cargo dev setup intellij'"),
                             Arg::new("rustc-repo-path")
                                 .long("repo-path")
                                 .short('r')
                                 .help("The path to a rustc repo that will be used for setting the dependencies")
-                                .takes_value(true)
                                 .value_name("path")
                                 .conflicts_with("remove")
                                 .required(true),
@@ -217,26 +229,26 @@ fn get_clap_config() -> ArgMatches {
                         .args([
                             Arg::new("remove")
                                 .long("remove")
-                                .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'")
-                                .required(false),
+                                .action(ArgAction::SetTrue)
+                                .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'"),
                             Arg::new("force-override")
                                 .long("force-override")
                                 .short('f')
-                                .help("Forces the override of an existing git pre-commit hook")
-                                .required(false),
+                                .action(ArgAction::SetTrue)
+                                .help("Forces the override of an existing git pre-commit hook"),
                         ]),
                     Command::new("vscode-tasks")
                         .about("Add several tasks to vscode for formatting, validation and testing")
                         .args([
                             Arg::new("remove")
                                 .long("remove")
-                                .help("Remove the tasks added with 'cargo dev setup vscode-tasks'")
-                                .required(false),
+                                .action(ArgAction::SetTrue)
+                                .help("Remove the tasks added with 'cargo dev setup vscode-tasks'"),
                             Arg::new("force-override")
                                 .long("force-override")
                                 .short('f')
-                                .help("Forces the override of existing vscode tasks")
-                                .required(false),
+                                .action(ArgAction::SetTrue)
+                                .help("Forces the override of existing vscode tasks"),
                         ]),
                 ]),
             Command::new("remove")
@@ -295,6 +307,7 @@ fn get_clap_config() -> ArgMatches {
                     .help("The new name of the lint"),
                 Arg::new("uplift")
                     .long("uplift")
+                    .action(ArgAction::SetTrue)
                     .help("This lint will be uplifted into rustc"),
             ]),
             Command::new("deprecate").about("Deprecates the given lint").args([
@@ -305,8 +318,6 @@ fn get_clap_config() -> ArgMatches {
                 Arg::new("reason")
                     .long("reason")
                     .short('r')
-                    .required(false)
-                    .takes_value(true)
                     .help("The reason for deprecation"),
             ]),
         ])
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 4c40483e3ec..796f1ff1695 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -9,7 +9,7 @@ keywords = ["clippy", "lint", "plugin"]
 edition = "2021"
 
 [dependencies]
-cargo_metadata = "0.14"
+cargo_metadata = "0.15.3"
 clippy_utils = { path = "../clippy_utils" }
 declare_clippy_lint = { path = "../declare_clippy_lint" }
 if_chain = "1.0"
diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
index 556fa579000..1d9096ea64d 100644
--- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::{find_assert_eq_args, root_macro_call_first_node};
+use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{implements_trait, is_copy};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -34,14 +35,16 @@ declare_clippy_lint! {
 
 declare_lint_pass!(BoolAssertComparison => [BOOL_ASSERT_COMPARISON]);
 
-fn is_bool_lit(e: &Expr<'_>) -> bool {
-    matches!(
-        e.kind,
-        ExprKind::Lit(Lit {
-            node: LitKind::Bool(_),
-            ..
-        })
-    ) && !e.span.from_expansion()
+fn extract_bool_lit(e: &Expr<'_>) -> Option<bool> {
+    if let ExprKind::Lit(Lit {
+        node: LitKind::Bool(b), ..
+    }) = e.kind
+        && !e.span.from_expansion()
+    {
+        Some(b)
+    } else {
+        None
+    }
 }
 
 fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
@@ -69,24 +72,23 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         let Some(macro_call) = root_macro_call_first_node(cx, expr) else { return };
         let macro_name = cx.tcx.item_name(macro_call.def_id);
-        if !matches!(
-            macro_name.as_str(),
-            "assert_eq" | "debug_assert_eq" | "assert_ne" | "debug_assert_ne"
-        ) {
-            return;
-        }
+        let eq_macro = match macro_name.as_str() {
+            "assert_eq" | "debug_assert_eq" => true,
+            "assert_ne" | "debug_assert_ne" => false,
+            _ => return,
+        };
         let Some ((a, b, _)) = find_assert_eq_args(cx, expr, macro_call.expn) else { return };
 
         let a_span = a.span.source_callsite();
         let b_span = b.span.source_callsite();
 
-        let (lit_span, non_lit_expr) = match (is_bool_lit(a), is_bool_lit(b)) {
-            // assert_eq!(true, b)
-            //            ^^^^^^
-            (true, false) => (a_span.until(b_span), b),
-            // assert_eq!(a, true)
-            //             ^^^^^^
-            (false, true) => (b_span.with_lo(a_span.hi()), a),
+        let (lit_span, bool_value, non_lit_expr) = match (extract_bool_lit(a), extract_bool_lit(b)) {
+            // assert_eq!(true/false, b)
+            //            ^^^^^^^^^^^^
+            (Some(bool_value), None) => (a_span.until(b_span), bool_value, b),
+            // assert_eq!(a, true/false)
+            //             ^^^^^^^^^^^^
+            (None, Some(bool_value)) => (b_span.with_lo(a_span.hi()), bool_value, a),
             // If there are two boolean arguments, we definitely don't understand
             // what's going on, so better leave things as is...
             //
@@ -121,9 +123,16 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
                 // ^^^^^^^^^
                 let name_span = cx.sess().source_map().span_until_char(macro_call.span, '!');
 
+                let mut suggestions = vec![(name_span, non_eq_mac.to_string()), (lit_span, String::new())];
+
+                if bool_value ^ eq_macro {
+                    let Some(sugg) = Sugg::hir_opt(cx, non_lit_expr) else { return };
+                    suggestions.push((non_lit_expr.span, (!sugg).to_string()));
+                }
+
                 diag.multipart_suggestion(
                     format!("replace it with `{non_eq_mac}!(..)`"),
-                    vec![(name_span, non_eq_mac.to_string()), (lit_span, String::new())],
+                    suggestions,
                     Applicability::MachineApplicable,
                 );
             },
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 36a366fc974..457a25826e7 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -156,6 +156,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::exhaustive_items::EXHAUSTIVE_STRUCTS_INFO,
     crate::exit::EXIT_INFO,
     crate::explicit_write::EXPLICIT_WRITE_INFO,
+    crate::extra_unused_type_parameters::EXTRA_UNUSED_TYPE_PARAMETERS_INFO,
     crate::fallible_impl_from::FALLIBLE_IMPL_FROM_INFO,
     crate::float_literal::EXCESSIVE_PRECISION_INFO,
     crate::float_literal::LOSSY_FLOAT_LITERAL_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
index 9d089fcad70..aef2db38583 100644
--- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs
+++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
@@ -4,8 +4,8 @@ use rustc_hir::intravisit::FnKind;
 use rustc_hir::{Body, FnDecl, Item, ItemKind, TraitFn, TraitItem, TraitItemKind, Ty};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::Span;
 use rustc_span::def_id::LocalDefId;
+use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
 declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
new file mode 100644
index 00000000000..2fdd8a71466
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
@@ -0,0 +1,178 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::trait_ref_of_method;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::MultiSpan;
+use rustc_hir::intravisit::{walk_impl_item, walk_item, walk_param_bound, walk_ty, Visitor};
+use rustc_hir::{
+    GenericParamKind, Generics, ImplItem, ImplItemKind, Item, ItemKind, PredicateOrigin, Ty, TyKind, WherePredicate,
+};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::hir::nested_filter;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{def_id::DefId, Span};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for type parameters in generics that are never used anywhere else.
+    ///
+    /// ### Why is this bad?
+    /// Functions cannot infer the value of unused type parameters; therefore, calling them
+    /// requires using a turbofish, which serves no purpose but to satisfy the compiler.
+    ///
+    /// ### Example
+    /// ```rust
+    /// // unused type parameters
+    /// fn unused_ty<T>(x: u8) {
+    ///     // ..
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// fn no_unused_ty(x: u8) {
+    ///     // ..
+    /// }
+    /// ```
+    #[clippy::version = "1.69.0"]
+    pub EXTRA_UNUSED_TYPE_PARAMETERS,
+    complexity,
+    "unused type parameters in function definitions"
+}
+declare_lint_pass!(ExtraUnusedTypeParameters => [EXTRA_UNUSED_TYPE_PARAMETERS]);
+
+/// A visitor struct that walks a given function and gathers generic type parameters, plus any
+/// trait bounds those parameters have.
+struct TypeWalker<'cx, 'tcx> {
+    cx: &'cx LateContext<'tcx>,
+    /// Collection of all the type parameters and their spans.
+    ty_params: FxHashMap<DefId, Span>,
+    /// Collection of any (inline) trait bounds corresponding to each type parameter.
+    bounds: FxHashMap<DefId, Span>,
+    /// The entire `Generics` object of the function, useful for querying purposes.
+    generics: &'tcx Generics<'tcx>,
+    /// The value of this will remain `true` if *every* parameter:
+    ///   1. Is a type parameter, and
+    ///   2. Goes unused in the function.
+    /// Otherwise, if any type parameters end up being used, or if any lifetime or const-generic
+    /// parameters are present, this will be set to `false`.
+    all_params_unused: bool,
+}
+
+impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
+    fn new(cx: &'cx LateContext<'tcx>, generics: &'tcx Generics<'tcx>) -> Self {
+        let mut all_params_unused = true;
+        let ty_params = generics
+            .params
+            .iter()
+            .filter_map(|param| {
+                if let GenericParamKind::Type { .. } = param.kind {
+                    Some((param.def_id.into(), param.span))
+                } else {
+                    if !param.is_elided_lifetime() {
+                        all_params_unused = false;
+                    }
+                    None
+                }
+            })
+            .collect();
+        Self {
+            cx,
+            ty_params,
+            bounds: FxHashMap::default(),
+            generics,
+            all_params_unused,
+        }
+    }
+
+    fn emit_lint(&self) {
+        let (msg, help) = match self.ty_params.len() {
+            0 => return,
+            1 => (
+                "type parameter goes unused in function definition",
+                "consider removing the parameter",
+            ),
+            _ => (
+                "type parameters go unused in function definition",
+                "consider removing the parameters",
+            ),
+        };
+
+        let source_map = self.cx.tcx.sess.source_map();
+        let span = if self.all_params_unused {
+            self.generics.span.into() // Remove the entire list of generics
+        } else {
+            MultiSpan::from_spans(
+                self.ty_params
+                    .iter()
+                    .map(|(def_id, &span)| {
+                        // Extend the span past any trait bounds, and include the comma at the end.
+                        let span_to_extend = self.bounds.get(def_id).copied().map_or(span, Span::shrink_to_hi);
+                        let comma_range = source_map.span_extend_to_next_char(span_to_extend, '>', false);
+                        let comma_span = source_map.span_through_char(comma_range, ',');
+                        span.with_hi(comma_span.hi())
+                    })
+                    .collect(),
+            )
+        };
+
+        span_lint_and_help(self.cx, EXTRA_UNUSED_TYPE_PARAMETERS, span, msg, None, help);
+    }
+}
+
+impl<'cx, 'tcx> Visitor<'tcx> for TypeWalker<'cx, 'tcx> {
+    type NestedFilter = nested_filter::OnlyBodies;
+
+    fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) {
+        if let Some((def_id, _)) = t.peel_refs().as_generic_param() {
+            if self.ty_params.remove(&def_id).is_some() {
+                self.all_params_unused = false;
+            }
+        } else if let TyKind::OpaqueDef(id, _, _) = t.kind {
+            // Explicitly walk OpaqueDef. Normally `walk_ty` would do the job, but it calls
+            // `visit_nested_item`, which checks that `Self::NestedFilter::INTER` is set. We're
+            // using `OnlyBodies`, so the check ends up failing and the type isn't fully walked.
+            let item = self.nested_visit_map().item(id);
+            walk_item(self, item);
+        } else {
+            walk_ty(self, t);
+        }
+    }
+
+    fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate<'tcx>) {
+        if let WherePredicate::BoundPredicate(predicate) = predicate {
+            // Collect spans for bounds that appear in the list of generics (not in a where-clause)
+            // for use in forming the help message
+            if let Some((def_id, _)) = predicate.bounded_ty.peel_refs().as_generic_param()
+                && let PredicateOrigin::GenericParam = predicate.origin
+            {
+                self.bounds.insert(def_id, predicate.span);
+            }
+            // Only walk the right-hand side of where-bounds
+            for bound in predicate.bounds {
+                walk_param_bound(self, bound);
+            }
+        }
+    }
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        if let ItemKind::Fn(_, generics, _) = item.kind {
+            let mut walker = TypeWalker::new(cx, generics);
+            walk_item(&mut walker, item);
+            walker.emit_lint();
+        }
+    }
+
+    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) {
+        // Only lint on inherent methods, not trait methods.
+        if let ImplItemKind::Fn(..) = item.kind && trait_ref_of_method(cx, item.owner_id.def_id).is_none() {
+            let mut walker = TypeWalker::new(cx, item.generics);
+            walk_impl_item(&mut walker, item);
+            walker.emit_lint();
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index d376ad3bfe3..ea26b96ee07 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -125,7 +125,7 @@ declare_clippy_lint! {
     /// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`.
     #[clippy::version = "1.66.0"]
     pub UNINLINED_FORMAT_ARGS,
-    style,
+    pedantic,
     "using non-inlined variables in `format!` calls"
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
index d6b50537c2e..8b53ee68ebd 100644
--- a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
@@ -10,13 +10,7 @@ use std::iter;
 
 use super::MISNAMED_GETTERS;
 
-pub fn check_fn(
-    cx: &LateContext<'_>,
-    kind: FnKind<'_>,
-    decl: &FnDecl<'_>,
-    body: &Body<'_>,
-    span: Span,
-) {
+pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body: &Body<'_>, span: Span) {
     let FnKind::Method(ref ident, sig) = kind else {
             return;
         };
diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
index a13909a2cdb..f2aa7b597a7 100644
--- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -25,7 +25,7 @@ pub(super) fn check_fn<'tcx>(
         intravisit::FnKind::Closure => return,
     };
 
-    check_raw_ptr(cx, unsafety, decl, body, def_id)
+    check_raw_ptr(cx, unsafety, decl, body, def_id);
 }
 
 pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
index 7557a9ce13f..c924d7361ce 100644
--- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
@@ -66,7 +66,9 @@ impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator {
 
 fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) {
     if sig.decl.implicit_self.has_implicit_self() {
-        let ret_ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(fn_id).subst_identity().output());
+        let ret_ty = cx
+            .tcx
+            .erase_late_bound_regions(cx.tcx.fn_sig(fn_id).subst_identity().output());
         let ret_ty = cx
             .tcx
             .try_normalize_erasing_regions(cx.param_env, ret_ty)
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 80ed2862a41..e13bc47973b 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -135,6 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
             if item.ident.name == sym::len;
             if let ImplItemKind::Fn(sig, _) = &item.kind;
             if sig.decl.implicit_self.has_implicit_self();
+            if sig.decl.inputs.len() == 1;
             if cx.effective_visibilities.is_exported(item.owner_id.def_id);
             if matches!(sig.decl.output, FnRetTy::Return(_));
             if let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id());
@@ -196,7 +197,15 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items
     fn is_named_self(cx: &LateContext<'_>, item: &TraitItemRef, name: Symbol) -> bool {
         item.ident.name == name
             && if let AssocItemKind::Fn { has_self } = item.kind {
-                has_self && { cx.tcx.fn_sig(item.id.owner_id).skip_binder().inputs().skip_binder().len() == 1 }
+                has_self && {
+                    cx.tcx
+                        .fn_sig(item.id.owner_id)
+                        .skip_binder()
+                        .inputs()
+                        .skip_binder()
+                        .len()
+                        == 1
+                }
             } else {
                 false
             }
@@ -342,7 +351,11 @@ fn check_for_is_empty<'tcx>(
         ),
         Some(is_empty)
             if !(is_empty.fn_has_self_parameter
-                && check_is_empty_sig(cx.tcx.fn_sig(is_empty.def_id).subst_identity().skip_binder(), self_kind, output)) =>
+                && check_is_empty_sig(
+                    cx.tcx.fn_sig(is_empty.def_id).subst_identity().skip_binder(),
+                    self_kind,
+                    output,
+                )) =>
         {
             (
                 format!(
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index d0683039776..565c5b7af00 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -121,6 +121,7 @@ mod excessive_bools;
 mod exhaustive_items;
 mod exit;
 mod explicit_write;
+mod extra_unused_type_parameters;
 mod fallible_impl_from;
 mod float_literal;
 mod floating_point_arithmetic;
@@ -909,6 +910,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse));
     store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef));
     store.register_late_pass(|_| Box::new(multiple_unsafe_ops_per_block::MultipleUnsafeOpsPerBlock));
+    store.register_late_pass(|_| Box::new(extra_unused_type_parameters::ExtraUnusedTypeParameters));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 747a94ba5a6..43a1a65a43a 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -1,20 +1,21 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::trait_ref_of_method;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_errors::Applicability;
 use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter};
 use rustc_hir::intravisit::{
-    walk_fn_decl, walk_generic_arg, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound,
+    walk_fn_decl, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound,
     walk_poly_trait_ref, walk_trait_ref, walk_ty, Visitor,
 };
-use rustc_hir::lang_items;
 use rustc_hir::FnRetTy::Return;
 use rustc_hir::{
-    BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
-    ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, PolyTraitRef, PredicateOrigin, TraitFn,
-    TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
+    lang_items, BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics,
+    Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node, PolyTraitRef,
+    PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
 };
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::nested_filter as middle_nested_filter;
+use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::Span;
@@ -33,8 +34,6 @@ declare_clippy_lint! {
     /// ### Known problems
     /// - We bail out if the function has a `where` clause where lifetimes
     /// are mentioned due to potential false positives.
-    /// - Lifetime bounds such as `impl Foo + 'a` and `T: 'a` must be elided with the
-    /// placeholder notation `'_` because the fully elided notation leaves the type bound to `'static`.
     ///
     /// ### Example
     /// ```rust
@@ -92,7 +91,7 @@ declare_lint_pass!(Lifetimes => [NEEDLESS_LIFETIMES, EXTRA_UNUSED_LIFETIMES]);
 impl<'tcx> LateLintPass<'tcx> for Lifetimes {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if let ItemKind::Fn(ref sig, generics, id) = item.kind {
-            check_fn_inner(cx, sig.decl, Some(id), None, generics, item.span, true);
+            check_fn_inner(cx, sig, Some(id), None, generics, item.span, true);
         } else if let ItemKind::Impl(impl_) = item.kind {
             if !item.span.from_expansion() {
                 report_extra_impl_lifetimes(cx, impl_);
@@ -105,7 +104,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
             let report_extra_lifetimes = trait_ref_of_method(cx, item.owner_id.def_id).is_none();
             check_fn_inner(
                 cx,
-                sig.decl,
+                sig,
                 Some(id),
                 None,
                 item.generics,
@@ -121,29 +120,21 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
                 TraitFn::Required(sig) => (None, Some(sig)),
                 TraitFn::Provided(id) => (Some(id), None),
             };
-            check_fn_inner(cx, sig.decl, body, trait_sig, item.generics, item.span, true);
+            check_fn_inner(cx, sig, body, trait_sig, item.generics, item.span, true);
         }
     }
 }
 
-/// The lifetime of a &-reference.
-#[derive(PartialEq, Eq, Hash, Debug, Clone)]
-enum RefLt {
-    Unnamed,
-    Static,
-    Named(LocalDefId),
-}
-
 fn check_fn_inner<'tcx>(
     cx: &LateContext<'tcx>,
-    decl: &'tcx FnDecl<'_>,
+    sig: &'tcx FnSig<'_>,
     body: Option<BodyId>,
     trait_sig: Option<&[Ident]>,
     generics: &'tcx Generics<'_>,
     span: Span,
     report_extra_lifetimes: bool,
 ) {
-    if span.from_expansion() || has_where_lifetimes(cx, generics) {
+    if in_external_macro(cx.sess(), span) || has_where_lifetimes(cx, generics) {
         return;
     }
 
@@ -162,7 +153,7 @@ fn check_fn_inner<'tcx>(
             for bound in pred.bounds {
                 let mut visitor = RefVisitor::new(cx);
                 walk_param_bound(&mut visitor, bound);
-                if visitor.lts.iter().any(|lt| matches!(lt, RefLt::Named(_))) {
+                if visitor.lts.iter().any(|lt| matches!(lt.res, LifetimeName::Param(_))) {
                     return;
                 }
                 if let GenericBound::Trait(ref trait_ref, _) = *bound {
@@ -189,12 +180,12 @@ fn check_fn_inner<'tcx>(
         }
     }
 
-    if let Some(elidable_lts) = could_use_elision(cx, decl, body, trait_sig, generics.params) {
+    if let Some((elidable_lts, usages)) = could_use_elision(cx, sig.decl, body, trait_sig, generics.params) {
         let lts = elidable_lts
             .iter()
             // In principle, the result of the call to `Node::ident` could be `unwrap`ped, as `DefId` should refer to a
             // `Node::GenericParam`.
-            .filter_map(|&(def_id, _)| cx.tcx.hir().get_by_def_id(def_id).ident())
+            .filter_map(|&def_id| cx.tcx.hir().get_by_def_id(def_id).ident())
             .map(|ident| ident.to_string())
             .collect::<Vec<_>>()
             .join(", ");
@@ -202,21 +193,99 @@ fn check_fn_inner<'tcx>(
         span_lint_and_then(
             cx,
             NEEDLESS_LIFETIMES,
-            span.with_hi(decl.output.span().hi()),
+            span.with_hi(sig.decl.output.span().hi()),
             &format!("the following explicit lifetimes could be elided: {lts}"),
             |diag| {
-                if let Some(span) = elidable_lts.iter().find_map(|&(_, span)| span) {
-                    diag.span_help(span, "replace with `'_` in generic arguments such as here");
+                if sig.header.is_async() {
+                    // async functions have usages whose spans point at the lifetime declaration which messes up
+                    // suggestions
+                    return;
+                };
+
+                if let Some(suggestions) = elision_suggestions(cx, generics, &elidable_lts, &usages) {
+                    diag.multipart_suggestion("elide the lifetimes", suggestions, Applicability::MachineApplicable);
                 }
             },
         );
     }
 
     if report_extra_lifetimes {
-        self::report_extra_lifetimes(cx, decl, generics);
+        self::report_extra_lifetimes(cx, sig.decl, generics);
     }
 }
 
+fn elision_suggestions(
+    cx: &LateContext<'_>,
+    generics: &Generics<'_>,
+    elidable_lts: &[LocalDefId],
+    usages: &[Lifetime],
+) -> Option<Vec<(Span, String)>> {
+    let explicit_params = generics
+        .params
+        .iter()
+        .filter(|param| !param.is_elided_lifetime() && !param.is_impl_trait())
+        .collect::<Vec<_>>();
+
+    let mut suggestions = if elidable_lts.len() == explicit_params.len() {
+        // if all the params are elided remove the whole generic block
+        //
+        // fn x<'a>() {}
+        //     ^^^^
+        vec![(generics.span, String::new())]
+    } else {
+        elidable_lts
+            .iter()
+            .map(|&id| {
+                let pos = explicit_params.iter().position(|param| param.def_id == id)?;
+                let param = explicit_params.get(pos)?;
+
+                let span = if let Some(next) = explicit_params.get(pos + 1) {
+                    // fn x<'prev, 'a, 'next>() {}
+                    //             ^^^^
+                    param.span.until(next.span)
+                } else {
+                    // `pos` should be at least 1 here, because the param in position 0 would either have a `next`
+                    // param or would have taken the `elidable_lts.len() == explicit_params.len()` branch.
+                    let prev = explicit_params.get(pos - 1)?;
+
+                    // fn x<'prev, 'a>() {}
+                    //           ^^^^
+                    param.span.with_lo(prev.span.hi())
+                };
+
+                Some((span, String::new()))
+            })
+            .collect::<Option<Vec<_>>>()?
+    };
+
+    suggestions.extend(
+        usages
+            .iter()
+            .filter(|usage| named_lifetime(usage).map_or(false, |id| elidable_lts.contains(&id)))
+            .map(|usage| {
+                match cx.tcx.hir().get_parent(usage.hir_id) {
+                    Node::Ty(Ty {
+                        kind: TyKind::Ref(..), ..
+                    }) => {
+                        // expand `&'a T` to `&'a T`
+                        //          ^^         ^^^
+                        let span = cx
+                            .sess()
+                            .source_map()
+                            .span_extend_while(usage.ident.span, |ch| ch.is_ascii_whitespace())
+                            .unwrap_or(usage.ident.span);
+
+                        (span, String::new())
+                    },
+                    // `T<'a>` and `impl Foo + 'a` should be replaced by `'_`
+                    _ => (usage.ident.span, String::from("'_")),
+                }
+            }),
+    );
+
+    Some(suggestions)
+}
+
 // elision doesn't work for explicit self types, see rust-lang/rust#69064
 fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option<Ident>) -> bool {
     if_chain! {
@@ -236,13 +305,20 @@ fn explicit_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident:
     }
 }
 
+fn named_lifetime(lt: &Lifetime) -> Option<LocalDefId> {
+    match lt.res {
+        LifetimeName::Param(id) if !lt.is_anonymous() => Some(id),
+        _ => None,
+    }
+}
+
 fn could_use_elision<'tcx>(
     cx: &LateContext<'tcx>,
     func: &'tcx FnDecl<'_>,
     body: Option<BodyId>,
     trait_sig: Option<&[Ident]>,
     named_generics: &'tcx [GenericParam<'_>],
-) -> Option<Vec<(LocalDefId, Option<Span>)>> {
+) -> Option<(Vec<LocalDefId>, Vec<Lifetime>)> {
     // There are two scenarios where elision works:
     // * no output references, all input references have different LT
     // * output references, exactly one input reference with same LT
@@ -300,32 +376,24 @@ fn could_use_elision<'tcx>(
 
     // check for lifetimes from higher scopes
     for lt in input_lts.iter().chain(output_lts.iter()) {
-        if !allowed_lts.contains(lt) {
+        if let Some(id) = named_lifetime(lt)
+            && !allowed_lts.contains(&id)
+        {
             return None;
         }
     }
 
     // check for higher-ranked trait bounds
     if !input_visitor.nested_elision_site_lts.is_empty() || !output_visitor.nested_elision_site_lts.is_empty() {
-        let allowed_lts: FxHashSet<_> = allowed_lts
-            .iter()
-            .filter_map(|lt| match lt {
-                RefLt::Named(def_id) => Some(cx.tcx.item_name(def_id.to_def_id())),
-                _ => None,
-            })
-            .collect();
+        let allowed_lts: FxHashSet<_> = allowed_lts.iter().map(|id| cx.tcx.item_name(id.to_def_id())).collect();
         for lt in input_visitor.nested_elision_site_lts {
-            if let RefLt::Named(def_id) = lt {
-                if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) {
-                    return None;
-                }
+            if allowed_lts.contains(&lt.ident.name) {
+                return None;
             }
         }
         for lt in output_visitor.nested_elision_site_lts {
-            if let RefLt::Named(def_id) = lt {
-                if allowed_lts.contains(&cx.tcx.item_name(def_id.to_def_id())) {
-                    return None;
-                }
+            if allowed_lts.contains(&lt.ident.name) {
+                return None;
             }
         }
     }
@@ -337,15 +405,10 @@ fn could_use_elision<'tcx>(
     let elidable_lts = named_lifetime_occurrences(&input_lts)
         .into_iter()
         .filter_map(|(def_id, occurrences)| {
-            if occurrences == 1 && (input_lts.len() == 1 || !output_lts.contains(&RefLt::Named(def_id))) {
-                Some((
-                    def_id,
-                    input_visitor
-                        .lifetime_generic_arg_spans
-                        .get(&def_id)
-                        .or_else(|| output_visitor.lifetime_generic_arg_spans.get(&def_id))
-                        .copied(),
-                ))
+            if occurrences == 1
+                && (input_lts.len() == 1 || !output_lts.iter().any(|lt| named_lifetime(lt) == Some(def_id)))
+            {
+                Some(def_id)
             } else {
                 None
             }
@@ -353,31 +416,34 @@ fn could_use_elision<'tcx>(
         .collect::<Vec<_>>();
 
     if elidable_lts.is_empty() {
-        None
-    } else {
-        Some(elidable_lts)
+        return None;
     }
+
+    let usages = itertools::chain(input_lts, output_lts).collect();
+
+    Some((elidable_lts, usages))
 }
 
-fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<RefLt> {
-    let mut allowed_lts = FxHashSet::default();
-    for par in named_generics.iter() {
-        if let GenericParamKind::Lifetime { .. } = par.kind {
-            allowed_lts.insert(RefLt::Named(par.def_id));
-        }
-    }
-    allowed_lts.insert(RefLt::Unnamed);
-    allowed_lts.insert(RefLt::Static);
-    allowed_lts
+fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxHashSet<LocalDefId> {
+    named_generics
+        .iter()
+        .filter_map(|par| {
+            if let GenericParamKind::Lifetime { .. } = par.kind {
+                Some(par.def_id)
+            } else {
+                None
+            }
+        })
+        .collect()
 }
 
 /// Number of times each named lifetime occurs in the given slice. Returns a vector to preserve
 /// relative order.
 #[must_use]
-fn named_lifetime_occurrences(lts: &[RefLt]) -> Vec<(LocalDefId, usize)> {
+fn named_lifetime_occurrences(lts: &[Lifetime]) -> Vec<(LocalDefId, usize)> {
     let mut occurrences = Vec::new();
     for lt in lts {
-        if let &RefLt::Named(curr_def_id) = lt {
+        if let Some(curr_def_id) = named_lifetime(lt) {
             if let Some(pair) = occurrences
                 .iter_mut()
                 .find(|(prev_def_id, _)| *prev_def_id == curr_def_id)
@@ -391,12 +457,10 @@ fn named_lifetime_occurrences(lts: &[RefLt]) -> Vec<(LocalDefId, usize)> {
     occurrences
 }
 
-/// A visitor usable for `rustc_front::visit::walk_ty()`.
 struct RefVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
-    lts: Vec<RefLt>,
-    lifetime_generic_arg_spans: FxHashMap<LocalDefId, Span>,
-    nested_elision_site_lts: Vec<RefLt>,
+    lts: Vec<Lifetime>,
+    nested_elision_site_lts: Vec<Lifetime>,
     unelided_trait_object_lifetime: bool,
 }
 
@@ -405,32 +469,16 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
         Self {
             cx,
             lts: Vec::new(),
-            lifetime_generic_arg_spans: FxHashMap::default(),
             nested_elision_site_lts: Vec::new(),
             unelided_trait_object_lifetime: false,
         }
     }
 
-    fn record(&mut self, lifetime: &Option<Lifetime>) {
-        if let Some(ref lt) = *lifetime {
-            if lt.is_static() {
-                self.lts.push(RefLt::Static);
-            } else if lt.is_anonymous() {
-                // Fresh lifetimes generated should be ignored.
-                self.lts.push(RefLt::Unnamed);
-            } else if let LifetimeName::Param(def_id) = lt.res {
-                self.lts.push(RefLt::Named(def_id));
-            }
-        } else {
-            self.lts.push(RefLt::Unnamed);
-        }
-    }
-
-    fn all_lts(&self) -> Vec<RefLt> {
+    fn all_lts(&self) -> Vec<Lifetime> {
         self.lts
             .iter()
             .chain(self.nested_elision_site_lts.iter())
-            .cloned()
+            .copied()
             .collect::<Vec<_>>()
     }
 
@@ -442,7 +490,7 @@ impl<'a, 'tcx> RefVisitor<'a, 'tcx> {
 impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
     // for lifetimes as parameters of generics
     fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
-        self.record(&Some(*lifetime));
+        self.lts.push(*lifetime);
     }
 
     fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>) {
@@ -467,11 +515,7 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
                 walk_item(self, item);
                 self.lts.truncate(len);
                 self.lts.extend(bounds.iter().filter_map(|bound| match bound {
-                    GenericArg::Lifetime(l) => Some(if let LifetimeName::Param(def_id) = l.res {
-                        RefLt::Named(def_id)
-                    } else {
-                        RefLt::Unnamed
-                    }),
+                    GenericArg::Lifetime(&l) => Some(l),
                     _ => None,
                 }));
             },
@@ -491,13 +535,6 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
             _ => walk_ty(self, ty),
         }
     }
-
-    fn visit_generic_arg(&mut self, generic_arg: &'tcx GenericArg<'tcx>) {
-        if let GenericArg::Lifetime(l) = generic_arg && let LifetimeName::Param(def_id) = l.res {
-            self.lifetime_generic_arg_spans.entry(def_id).or_insert(l.ident.span);
-        }
-        walk_generic_arg(self, generic_arg);
-    }
 }
 
 /// Are any lifetimes mentioned in the `where` clause? If so, we don't try to
@@ -521,8 +558,12 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
                     walk_param_bound(&mut visitor, bound);
                 }
                 // and check that all lifetimes are allowed
-                if visitor.all_lts().iter().any(|it| !allowed_lts.contains(it)) {
-                    return true;
+                for lt in visitor.all_lts() {
+                    if let Some(id) = named_lifetime(&lt)
+                        && !allowed_lts.contains(&id)
+                    {
+                        return true;
+                    }
                 }
             },
             WherePredicate::EqPredicate(ref pred) => {
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index 8e52cac4323..610a0233eee 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -61,7 +61,8 @@ declare_clippy_lint! {
     ///
     /// ### Why is this bad?
     /// Just iterating the collection itself makes the intent
-    /// more clear and is probably faster.
+    /// more clear and is probably faster because it eliminates
+    /// the bounds check that is done when indexing.
     ///
     /// ### Example
     /// ```rust
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 e6ed4ea7a5d..25a1a5842f7 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
@@ -149,7 +149,7 @@ pub(super) fn check<'tcx>(
                         |diag| {
                             multispan_sugg(
                                 diag,
-                                "consider using an iterator",
+                                "consider using an iterator and enumerate()",
                                 vec![
                                     (pat.span, format!("({}, <item>)", ident.name)),
                                     (
diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs
index 4277455a3a2..ce5d657bcf0 100644
--- a/src/tools/clippy/clippy_lints/src/manual_assert.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs
@@ -1,7 +1,6 @@
 use crate::rustc_lint::LintContext;
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::macros::{root_macro_call, FormatArgsExpn};
-use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::macros::root_macro_call;
 use clippy_utils::{is_else_clause, peel_blocks_with_stmt, span_extract_comment, sugg};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, UnOp};
@@ -38,57 +37,57 @@ declare_lint_pass!(ManualAssert => [MANUAL_ASSERT]);
 
 impl<'tcx> LateLintPass<'tcx> for ManualAssert {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
-        if_chain! {
-            if let ExprKind::If(cond, then, None) = expr.kind;
-            if !matches!(cond.kind, ExprKind::Let(_));
-            if !expr.span.from_expansion();
-            let then = peel_blocks_with_stmt(then);
-            if let Some(macro_call) = root_macro_call(then.span);
-            if cx.tcx.item_name(macro_call.def_id) == sym::panic;
-            if !cx.tcx.sess.source_map().is_multiline(cond.span);
-            if let Some(format_args) = FormatArgsExpn::find_nested(cx, then, macro_call.expn);
+        if let ExprKind::If(cond, then, None) = expr.kind
+            && !matches!(cond.kind, ExprKind::Let(_))
+            && !expr.span.from_expansion()
+            && let then = peel_blocks_with_stmt(then)
+            && let Some(macro_call) = root_macro_call(then.span)
+            && cx.tcx.item_name(macro_call.def_id) == sym::panic
+            && !cx.tcx.sess.source_map().is_multiline(cond.span)
+            && let Ok(panic_snippet) = cx.sess().source_map().span_to_snippet(macro_call.span)
+            && let Some(panic_snippet) = panic_snippet.strip_suffix(')')
+            && let Some((_, format_args_snip)) = panic_snippet.split_once('(')
             // Don't change `else if foo { panic!(..) }` to `else { assert!(foo, ..) }` as it just
             // shuffles the condition around.
             // Should this have a config value?
-            if !is_else_clause(cx.tcx, expr);
-            then {
-                let mut applicability = Applicability::MachineApplicable;
-                let format_args_snip = snippet_with_applicability(cx, format_args.inputs_span(), "..", &mut applicability);
-                let cond = cond.peel_drop_temps();
-                let mut comments = span_extract_comment(cx.sess().source_map(), expr.span);
-                if !comments.is_empty() {
-                    comments += "\n";
-                }
-                let (cond, not) = match cond.kind {
-                    ExprKind::Unary(UnOp::Not, e) => (e, ""),
-                    _ => (cond, "!"),
-                };
-                let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par();
-                let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});");
-                // we show to the user the suggestion without the comments, but when applicating the fix, include the comments in the block
-                span_lint_and_then(
-                    cx,
-                    MANUAL_ASSERT,
-                    expr.span,
-                    "only a `panic!` in `if`-then statement",
-                    |diag| {
-                        // comments can be noisy, do not show them to the user
-                        if !comments.is_empty() {
-                            diag.tool_only_span_suggestion(
-                                        expr.span.shrink_to_lo(),
-                                        "add comments back",
-                                        comments,
-                                        applicability);
-                        }
-                        diag.span_suggestion(
-                                    expr.span,
-                                    "try instead",
-                                    sugg,
-                                    applicability);
-                                     }
-
-                );
+            && !is_else_clause(cx.tcx, expr)
+        {
+            let mut applicability = Applicability::MachineApplicable;
+            let cond = cond.peel_drop_temps();
+            let mut comments = span_extract_comment(cx.sess().source_map(), expr.span);
+            if !comments.is_empty() {
+                comments += "\n";
             }
+            let (cond, not) = match cond.kind {
+                ExprKind::Unary(UnOp::Not, e) => (e, ""),
+                _ => (cond, "!"),
+            };
+            let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par();
+            let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});");
+            // we show to the user the suggestion without the comments, but when applicating the fix, include the comments in the block
+            span_lint_and_then(
+                cx,
+                MANUAL_ASSERT,
+                expr.span,
+                "only a `panic!` in `if`-then statement",
+                |diag| {
+                    // comments can be noisy, do not show them to the user
+                    if !comments.is_empty() {
+                        diag.tool_only_span_suggestion(
+                            expr.span.shrink_to_lo(),
+                            "add comments back",
+                            comments,
+                            applicability
+                        );
+                    }
+                    diag.span_suggestion(
+                        expr.span,
+                        "try instead",
+                        sugg,
+                        applicability
+                    );
+                }
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
index 59de8c0384b..3126b590180 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
@@ -45,8 +45,13 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
 
     // Accumulate the variants which should be put in place of the wildcard because they're not
     // already covered.
-    let has_hidden = adt_def.variants().iter().any(|x| is_hidden(cx, x));
-    let mut missing_variants: Vec<_> = adt_def.variants().iter().filter(|x| !is_hidden(cx, x)).collect();
+    let is_external = adt_def.did().as_local().is_none();
+    let has_external_hidden = is_external && adt_def.variants().iter().any(|x| is_hidden(cx, x));
+    let mut missing_variants: Vec<_> = adt_def
+        .variants()
+        .iter()
+        .filter(|x| !(is_external && is_hidden(cx, x)))
+        .collect();
 
     let mut path_prefix = CommonPrefixSearcher::None;
     for arm in arms {
@@ -133,7 +138,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
 
     match missing_variants.as_slice() {
         [] => (),
-        [x] if !adt_def.is_variant_list_non_exhaustive() && !has_hidden => span_lint_and_sugg(
+        [x] if !adt_def.is_variant_list_non_exhaustive() && !has_external_hidden => span_lint_and_sugg(
             cx,
             MATCH_WILDCARD_FOR_SINGLE_VARIANTS,
             wildcard_span,
@@ -144,7 +149,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
         ),
         variants => {
             let mut suggestions: Vec<_> = variants.iter().copied().map(format_suggestion).collect();
-            let message = if adt_def.is_variant_list_non_exhaustive() || has_hidden {
+            let message = if adt_def.is_variant_list_non_exhaustive() || has_external_hidden {
                 suggestions.push("_".into());
                 "wildcard matches known variants and will also match future added variants"
             } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index fb94dfa5980..f1e8be7f2b8 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -1818,6 +1818,7 @@ declare_clippy_lint! {
     ///  - `or_else` to `or`
     ///  - `get_or_insert_with` to `get_or_insert`
     ///  - `ok_or_else` to `ok_or`
+    ///  - `then` to `then_some` (for msrv >= 1.62.0)
     ///
     /// ### Why is this bad?
     /// Using eager evaluation is shorter and simpler in some cases.
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
index fe88fa41fd9..e818f1892e5 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_to_owned.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::is_diag_trait_item;
 use clippy_utils::source::snippet_with_context;
 use if_chain::if_chain;
@@ -17,19 +17,31 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) -
         let input_type = cx.typeck_results().expr_ty(expr);
         if let ty::Adt(adt, _) = cx.typeck_results().expr_ty(expr).kind();
         if cx.tcx.is_diagnostic_item(sym::Cow, adt.did());
+
         then {
             let mut app = Applicability::MaybeIncorrect;
             let recv_snip = snippet_with_context(cx, recv.span, expr.span.ctxt(), "..", &mut app).0;
-            span_lint_and_sugg(
+            span_lint_and_then(
                 cx,
                 SUSPICIOUS_TO_OWNED,
                 expr.span,
                 &with_forced_trimmed_paths!(format!(
                     "this `to_owned` call clones the {input_type} itself and does not cause the {input_type} contents to become owned"
                 )),
-                "consider using, depending on intent",
-                format!("{recv_snip}.clone()` or `{recv_snip}.into_owned()"),
-                app,
+                |diag| {
+                    diag.span_suggestion(
+                        expr.span,
+                        "depending on intent, either make the Cow an Owned variant",
+                        format!("{recv_snip}.into_owned()"),
+                        app
+                    );
+                    diag.span_suggestion(
+                        expr.span,
+                        "or clone the Cow itself",
+                        format!("{recv_snip}.clone()"),
+                        app
+                    );
+                }
             );
             return true;
         }
diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
index 2814c92e67a..63c575fca30 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
@@ -10,6 +10,7 @@ use hir::{
 use rustc_ast::Mutability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::Span;
 
@@ -66,7 +67,7 @@ declare_lint_pass!(MultipleUnsafeOpsPerBlock => [MULTIPLE_UNSAFE_OPS_PER_BLOCK])
 
 impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock {
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
-        if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) {
+        if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) || in_external_macro(cx.tcx.sess, block.span) {
             return;
         }
         let mut unsafe_ops = vec![];
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index 472f52380bb..c5ea09590d3 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -25,11 +25,11 @@ declare_clippy_lint! {
     /// Using the dedicated functions of the `Option` type is clearer and
     /// more concise than an `if let` expression.
     ///
-    /// ### Known problems
-    /// This lint uses a deliberately conservative metric for checking
-    /// if the inside of either body contains breaks or continues which will
-    /// cause it to not suggest a fix if either block contains a loop with
-    /// continues or breaks contained within the loop.
+    /// ### Notes
+    /// This lint uses a deliberately conservative metric for checking if the
+    /// inside of either body contains loop control expressions `break` or
+    /// `continue` (which cannot be used within closures). If these are found,
+    /// this lint will not be raised.
     ///
     /// ### Example
     /// ```rust
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 8afe286fbd5..d88409c356e 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -624,7 +624,10 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args:
                             return;
                         };
 
-                        match *self.cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i].peel_refs().kind() {
+                        match *self.cx.tcx.fn_sig(id).subst_identity().skip_binder().inputs()[i]
+                            .peel_refs()
+                            .kind()
+                        {
                             ty::Dynamic(preds, _, _) if !matches_preds(self.cx, args.deref_ty.ty(self.cx), preds) => {
                                 set_skip_flag();
                             },
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index 1fda58fa54d..9e6c6c73d4f 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -1,5 +1,8 @@
+use std::fmt::Display;
+
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
+use clippy_utils::source::snippet_opt;
 use clippy_utils::{match_def_path, paths};
 use if_chain::if_chain;
 use rustc_ast::ast::{LitKind, StrStyle};
@@ -77,13 +80,45 @@ impl<'tcx> LateLintPass<'tcx> for Regex {
     }
 }
 
-#[must_use]
-fn str_span(base: Span, c: regex_syntax::ast::Span, offset: u8) -> Span {
-    let offset = u32::from(offset);
-    let end = base.lo() + BytePos(u32::try_from(c.end.offset).expect("offset too large") + offset);
-    let start = base.lo() + BytePos(u32::try_from(c.start.offset).expect("offset too large") + offset);
-    assert!(start <= end);
-    Span::new(start, end, base.ctxt(), base.parent())
+fn lint_syntax_error(cx: &LateContext<'_>, error: &regex_syntax::Error, unescaped: &str, base: Span, offset: u8) {
+    let parts: Option<(_, _, &dyn Display)> = match &error {
+        regex_syntax::Error::Parse(e) => Some((e.span(), e.auxiliary_span(), e.kind())),
+        regex_syntax::Error::Translate(e) => Some((e.span(), None, e.kind())),
+        _ => None,
+    };
+
+    let convert_span = |regex_span: &regex_syntax::ast::Span| {
+        let offset = u32::from(offset);
+        let start = base.lo() + BytePos(u32::try_from(regex_span.start.offset).expect("offset too large") + offset);
+        let end = base.lo() + BytePos(u32::try_from(regex_span.end.offset).expect("offset too large") + offset);
+
+        Span::new(start, end, base.ctxt(), base.parent())
+    };
+
+    if let Some((primary, auxiliary, kind)) = parts
+        && let Some(literal_snippet) = snippet_opt(cx, base)
+        && let Some(inner) = literal_snippet.get(offset as usize..)
+        // Only convert to native rustc spans if the parsed regex matches the
+        // source snippet exactly, to ensure the span offsets are correct
+        && inner.get(..unescaped.len()) == Some(unescaped)
+    {
+        let spans = if let Some(auxiliary) = auxiliary {
+            vec![convert_span(primary), convert_span(auxiliary)]
+        } else {
+            vec![convert_span(primary)]
+        };
+
+        span_lint(cx, INVALID_REGEX, spans, &format!("regex syntax error: {kind}"));
+    } else {
+        span_lint_and_help(
+            cx,
+            INVALID_REGEX,
+            base,
+            &error.to_string(),
+            None,
+            "consider using a raw string literal: `r\"..\"`",
+        );
+    }
 }
 
 fn const_str<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<String> {
@@ -155,25 +190,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
                         span_lint_and_help(cx, TRIVIAL_REGEX, expr.span, "trivial regex", None, repl);
                     }
                 },
-                Err(regex_syntax::Error::Parse(e)) => {
-                    span_lint(
-                        cx,
-                        INVALID_REGEX,
-                        str_span(expr.span, *e.span(), offset),
-                        &format!("regex syntax error: {}", e.kind()),
-                    );
-                },
-                Err(regex_syntax::Error::Translate(e)) => {
-                    span_lint(
-                        cx,
-                        INVALID_REGEX,
-                        str_span(expr.span, *e.span(), offset),
-                        &format!("regex syntax error: {}", e.kind()),
-                    );
-                },
-                Err(e) => {
-                    span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {e}"));
-                },
+                Err(e) => lint_syntax_error(cx, &e, r, expr.span, offset),
             }
         }
     } else if let Some(r) = const_str(cx, expr) {
@@ -183,25 +200,7 @@ fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) {
                     span_lint_and_help(cx, TRIVIAL_REGEX, expr.span, "trivial regex", None, repl);
                 }
             },
-            Err(regex_syntax::Error::Parse(e)) => {
-                span_lint(
-                    cx,
-                    INVALID_REGEX,
-                    expr.span,
-                    &format!("regex syntax error on position {}: {}", e.span().start.offset, e.kind()),
-                );
-            },
-            Err(regex_syntax::Error::Translate(e)) => {
-                span_lint(
-                    cx,
-                    INVALID_REGEX,
-                    expr.span,
-                    &format!("regex syntax error on position {}: {}", e.span().start.offset, e.kind()),
-                );
-            },
-            Err(e) => {
-                span_lint(cx, INVALID_REGEX, expr.span, &format!("regex syntax error: {e}"));
-            },
+            Err(e) => span_lint(cx, INVALID_REGEX, expr.span, &e.to_string()),
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
index 8c39b4fc569..bccf421e8f3 100644
--- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
@@ -78,8 +78,8 @@ fn check_method(cx: &LateContext<'_>, decl: &FnDecl<'_>, fn_def: LocalDefId, spa
         // We don't want to emit this lint if the `#[must_use]` attribute is already there.
         if !cx.tcx.hir().attrs(owner_id.into()).iter().any(|attr| attr.has_name(sym::must_use));
         if cx.tcx.visibility(fn_def.to_def_id()).is_public();
-        let ret_ty = return_ty(cx, owner_id.into());
-        let self_arg = nth_arg(cx, owner_id.into(), 0);
+        let ret_ty = return_ty(cx, owner_id);
+        let self_arg = nth_arg(cx, owner_id, 0);
         // If `Self` has the same type as the returned type, then we want to warn.
         //
         // For this check, we don't want to remove the reference on the returned type because if
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
index 8f1d1490e1f..34a3e5ddf4f 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
@@ -30,7 +30,7 @@ declare_clippy_lint! {
     /// # let x = 0;
     /// unsafe { f(x); }
     /// ```
-    #[clippy::version = "1.66.0"]
+    #[clippy::version = "1.68.0"]
     pub SEMICOLON_INSIDE_BLOCK,
     restriction,
     "add a semicolon inside the block"
@@ -59,7 +59,7 @@ declare_clippy_lint! {
     /// # let x = 0;
     /// unsafe { f(x) };
     /// ```
-    #[clippy::version = "1.66.0"]
+    #[clippy::version = "1.68.0"]
     pub SEMICOLON_OUTSIDE_BLOCK,
     restriction,
     "add a semicolon outside the block"
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index 585e2075fa9..c1f228d5f90 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -392,9 +392,7 @@ impl<'tcx> LateLintPass<'tcx> for Types {
     }
 
     fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
-        let is_exported = cx
-            .effective_visibilities
-            .is_exported(field.def_id);
+        let is_exported = cx.effective_visibilities.is_exported(field.def_id);
 
         self.check_ty(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
index 92053cec59f..0e526c216be 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -65,7 +65,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount {
                 }
             },
             hir::ExprKind::MethodCall(path, arg_0, ..) => match path.ident.as_str() {
-                "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" => {
+                "expect" | "unwrap" | "unwrap_or" | "unwrap_or_else" | "is_ok" | "is_err" => {
                     check_map_error(cx, arg_0, expr);
                 },
                 _ => (),
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs
index f48be27592b..1d78c7cfae0 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs
@@ -253,7 +253,7 @@ define_Conf! {
     ///
     /// Suppress lints whenever the suggested change would cause breakage for other crates.
     (avoid_breaking_exported_api: bool = true),
-    /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION.
+    /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN.
     ///
     /// The minimum rust version that the project supports
     (msrv: Option<String> = None),
@@ -323,7 +323,7 @@ define_Conf! {
     ///
     /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
     (trivial_copy_size_limit: Option<u64> = None),
-    /// Lint: LARGE_TYPE_PASS_BY_MOVE.
+    /// Lint: LARGE_TYPES_PASSED_BY_VALUE.
     ///
     /// The minimum size (in bytes) to consider a type for passing by reference instead of by value.
     (pass_by_value_size_limit: u64 = 256),
@@ -411,7 +411,7 @@ define_Conf! {
     /// the slice pattern that is suggested. If more elements would be necessary, the lint is suppressed.
     /// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
     (max_suggested_slice_pattern_length: u64 = 3),
-    /// Lint: AWAIT_HOLDING_INVALID_TYPE
+    /// Lint: AWAIT_HOLDING_INVALID_TYPE.
     (await_holding_invalid_types: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
     /// Lint: LARGE_INCLUDE_FILE.
     ///
@@ -437,7 +437,7 @@ define_Conf! {
     ///
     /// The maximum size of the `Err`-variant in a `Result` returned from a function
     (large_error_threshold: u64 = 128),
-    /// Lint: MUTABLE_KEY.
+    /// Lint: MUTABLE_KEY_TYPE.
     ///
     /// A list of paths to types that should be treated like `Arc`, i.e. ignored but
     /// for the generic parameters for determining interior mutability
@@ -446,7 +446,7 @@ define_Conf! {
     ///
     /// Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)`
     (allow_mixed_uninlined_format_args: bool = true),
-    /// Lint: INDEXING_SLICING
+    /// Lint: INDEXING_SLICING.
     ///
     /// Whether to suppress a restriction lint in constant code. In same
     /// cases the restructured operation might not be unavoidable, as the
diff --git a/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs b/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs
index 01efc527a8c..092041aecf2 100644
--- a/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs
@@ -1,4 +1,5 @@
 use clippy_utils::get_attr;
+use hir::TraitItem;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -47,6 +48,18 @@ impl<'tcx> LateLintPass<'tcx> for DumpHir {
             println!("{stmt:#?}");
         }
     }
+
+    fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) {
+        if has_attr(cx, item.hir_id()) {
+            println!("{item:#?}");
+        }
+    }
+
+    fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &hir::ImplItem<'_>) {
+        if has_attr(cx, item.hir_id()) {
+            println!("{item:#?}");
+        }
+    }
 }
 
 fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
index 4c3b1b131fd..f718207654f 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
@@ -215,14 +215,13 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
                     cx,
                 };
                 let body_id = cx.tcx.hir().body_owned_by(
-                    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(),
-                    ),
+                    impl_item_refs
+                        .iter()
+                        .find(|iiref| iiref.ident.as_str() == "get_lints")
+                        .expect("LintPass needs to implement get_lints")
+                        .id
+                        .owner_id
+                        .def_id,
                 );
                 collector.visit_expr(cx.tcx.hir().body(body_id).value);
             }
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index d7f466c1976..63dccbf697c 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -770,10 +770,7 @@ impl<'tcx> FormatSpec<'tcx> {
     /// Has no other formatting specifiers than setting the format trait. returns true for `{}`,
     /// `{foo}`, `{:?}`, but false for `{foo:5}`, `{3:.5?}`
     pub fn is_default_for_trait(&self) -> bool {
-        self.width.is_implied()
-            && self.precision.is_implied()
-            && self.align == Alignment::AlignUnknown
-            && self.no_flags
+        self.width.is_implied() && self.precision.is_implied() && self.align == Alignment::AlignUnknown && self.no_flags
     }
 }
 
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 72705878075..26b1d019749 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -36,6 +36,7 @@ pub fn is_min_const_fn<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, msrv: &Msrv)
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..)
                 | ty::PredicateKind::TypeWellFormedFromEnv(..) => continue,
+                ty::PredicateKind::AliasEq(..) => panic!("alias eq predicate on function: {predicate:#?}"),
                 ty::PredicateKind::ObjectSafe(_) => panic!("object safe predicate on function: {predicate:#?}"),
                 ty::PredicateKind::ClosureKind(..) => panic!("closure kind predicate on function: {predicate:#?}"),
                 ty::PredicateKind::Subtype(_) => panic!("subtype predicate on function: {predicate:#?}"),
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index b8c87aa5e1e..78fb2e0eb7e 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -809,7 +809,10 @@ pub struct DerefClosure {
 ///
 /// note: this only works on single line immutable closures with exactly one input parameter.
 pub fn deref_closure_args(cx: &LateContext<'_>, closure: &hir::Expr<'_>) -> Option<DerefClosure> {
-    if let hir::ExprKind::Closure(&Closure { fn_decl, def_id, body, .. }) = closure.kind {
+    if let hir::ExprKind::Closure(&Closure {
+        fn_decl, def_id, body, ..
+    }) = closure.kind
+    {
         let closure_body = cx.tcx.hir().body(body);
         // is closure arg a type annotated double reference (i.e.: `|x: &&i32| ...`)
         // a type annotation is present if param `kind` is different from `TyKind::Infer`
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index d18b62d1bf1..00073bcd82a 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -392,12 +392,16 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
                         .cx
                         .typeck_results()
                         .type_dependent_def_id(e.hir_id)
-                        .map_or(false, |id| self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe) =>
+                        .map_or(false, |id| {
+                            self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe
+                        }) =>
                 {
                     self.is_unsafe = true;
                 },
                 ExprKind::Call(func, _) => match *self.cx.typeck_results().expr_ty(func).peel_refs().kind() {
-                    ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe => self.is_unsafe = true,
+                    ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe => {
+                        self.is_unsafe = true;
+                    },
                     ty::FnPtr(sig) if sig.unsafety() == Unsafety::Unsafe => self.is_unsafe = true,
                     _ => walk_expr(self, e),
                 },
diff --git a/src/tools/clippy/lintcheck/Cargo.toml b/src/tools/clippy/lintcheck/Cargo.toml
index de31c16b819..653121af54d 100644
--- a/src/tools/clippy/lintcheck/Cargo.toml
+++ b/src/tools/clippy/lintcheck/Cargo.toml
@@ -10,8 +10,8 @@ edition = "2021"
 publish = false
 
 [dependencies]
-cargo_metadata = "0.14"
-clap = "3.2"
+cargo_metadata = "0.15.3"
+clap = "4.1.4"
 crossbeam-channel = "0.5.6"
 flate2 = "1.0"
 rayon = "1.5.1"
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 4e7fc565a32..adea8c53df2 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2023-01-27"
+channel = "nightly-2023-02-10"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
index 2a240cc249b..c1a10ba55ef 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
@@ -1,19 +1,19 @@
 error: hardcoded path to a diagnostic item
-  --> $DIR/unnecessary_def_path_hardcoded_path.rs:10:36
+  --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
    |
-LL |     const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
-   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: convert all references to use `sym::Deref`
+   = help: convert all references to use `sym::deref_method`
    = note: `-D clippy::unnecessary-def-path` implied by `-D warnings`
 
 error: hardcoded path to a diagnostic item
-  --> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
+  --> $DIR/unnecessary_def_path_hardcoded_path.rs:10:36
    |
-LL |     const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
-   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     const DEREF_TRAIT: [&str; 4] = ["core", "ops", "deref", "Deref"];
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: convert all references to use `sym::deref_method`
+   = help: convert all references to use `sym::Deref`
 
 error: hardcoded path to a language item
   --> $DIR/unnecessary_def_path_hardcoded_path.rs:11:40
diff --git a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
index 1e5f20e8c39..a13af565203 100644
--- a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs
@@ -149,3 +149,22 @@ macro_rules! almost_complete_range {
         let _ = '0'..'9';
     };
 }
+
+#[macro_export]
+macro_rules! unsafe_macro {
+    () => {
+        unsafe {
+            *core::ptr::null::<()>();
+            *core::ptr::null::<()>();
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! needless_lifetime {
+    () => {
+        fn needless_lifetime<'a>(x: &'a u8) -> &'a u8 {
+            unimplemented!()
+        }
+    };
+}
diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.fixed b/src/tools/clippy/tests/ui/bool_assert_comparison.fixed
index 95f35a61bb2..b8dd92906c8 100644
--- a/src/tools/clippy/tests/ui/bool_assert_comparison.fixed
+++ b/src/tools/clippy/tests/ui/bool_assert_comparison.fixed
@@ -86,7 +86,7 @@ fn main() {
     let b = ImplNotTraitWithBool;
 
     assert_eq!("a".len(), 1);
-    assert!("a".is_empty());
+    assert!(!"a".is_empty());
     assert!("".is_empty());
     assert!("".is_empty());
     assert_eq!(a!(), b!());
@@ -97,16 +97,16 @@ fn main() {
 
     assert_ne!("a".len(), 1);
     assert!("a".is_empty());
-    assert!("".is_empty());
-    assert!("".is_empty());
+    assert!(!"".is_empty());
+    assert!(!"".is_empty());
     assert_ne!(a!(), b!());
     assert_ne!(a!(), "".is_empty());
     assert_ne!("".is_empty(), b!());
     assert_ne!(a, true);
-    assert!(b);
+    assert!(!b);
 
     debug_assert_eq!("a".len(), 1);
-    debug_assert!("a".is_empty());
+    debug_assert!(!"a".is_empty());
     debug_assert!("".is_empty());
     debug_assert!("".is_empty());
     debug_assert_eq!(a!(), b!());
@@ -117,27 +117,27 @@ fn main() {
 
     debug_assert_ne!("a".len(), 1);
     debug_assert!("a".is_empty());
-    debug_assert!("".is_empty());
-    debug_assert!("".is_empty());
+    debug_assert!(!"".is_empty());
+    debug_assert!(!"".is_empty());
     debug_assert_ne!(a!(), b!());
     debug_assert_ne!(a!(), "".is_empty());
     debug_assert_ne!("".is_empty(), b!());
     debug_assert_ne!(a, true);
-    debug_assert!(b);
+    debug_assert!(!b);
 
     // assert with error messages
     assert_eq!("a".len(), 1, "tadam {}", 1);
     assert_eq!("a".len(), 1, "tadam {}", true);
-    assert!("a".is_empty(), "tadam {}", 1);
-    assert!("a".is_empty(), "tadam {}", true);
-    assert!("a".is_empty(), "tadam {}", true);
+    assert!(!"a".is_empty(), "tadam {}", 1);
+    assert!(!"a".is_empty(), "tadam {}", true);
+    assert!(!"a".is_empty(), "tadam {}", true);
     assert_eq!(a, true, "tadam {}", false);
 
     debug_assert_eq!("a".len(), 1, "tadam {}", 1);
     debug_assert_eq!("a".len(), 1, "tadam {}", true);
-    debug_assert!("a".is_empty(), "tadam {}", 1);
-    debug_assert!("a".is_empty(), "tadam {}", true);
-    debug_assert!("a".is_empty(), "tadam {}", true);
+    debug_assert!(!"a".is_empty(), "tadam {}", 1);
+    debug_assert!(!"a".is_empty(), "tadam {}", true);
+    debug_assert!(!"a".is_empty(), "tadam {}", true);
     debug_assert_eq!(a, true, "tadam {}", false);
 
     assert!(a!());
@@ -158,4 +158,14 @@ fn main() {
         }};
     }
     in_macro!(a);
+
+    assert!("".is_empty());
+    assert!("".is_empty());
+    assert!(!"requires negation".is_empty());
+    assert!(!"requires negation".is_empty());
+
+    debug_assert!("".is_empty());
+    debug_assert!("".is_empty());
+    debug_assert!(!"requires negation".is_empty());
+    debug_assert!(!"requires negation".is_empty());
 }
diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.rs b/src/tools/clippy/tests/ui/bool_assert_comparison.rs
index 88e7560b4f9..0a8ad34fda5 100644
--- a/src/tools/clippy/tests/ui/bool_assert_comparison.rs
+++ b/src/tools/clippy/tests/ui/bool_assert_comparison.rs
@@ -158,4 +158,14 @@ fn main() {
         }};
     }
     in_macro!(a);
+
+    assert_eq!("".is_empty(), true);
+    assert_ne!("".is_empty(), false);
+    assert_ne!("requires negation".is_empty(), true);
+    assert_eq!("requires negation".is_empty(), false);
+
+    debug_assert_eq!("".is_empty(), true);
+    debug_assert_ne!("".is_empty(), false);
+    debug_assert_ne!("requires negation".is_empty(), true);
+    debug_assert_eq!("requires negation".is_empty(), false);
 }
diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.stderr b/src/tools/clippy/tests/ui/bool_assert_comparison.stderr
index 3d9f8573e61..89cefc95a9f 100644
--- a/src/tools/clippy/tests/ui/bool_assert_comparison.stderr
+++ b/src/tools/clippy/tests/ui/bool_assert_comparison.stderr
@@ -8,7 +8,7 @@ LL |     assert_eq!("a".is_empty(), false);
 help: replace it with `assert!(..)`
    |
 LL -     assert_eq!("a".is_empty(), false);
-LL +     assert!("a".is_empty());
+LL +     assert!(!"a".is_empty());
    |
 
 error: used `assert_eq!` with a literal bool
@@ -68,7 +68,7 @@ LL |     assert_ne!("".is_empty(), true);
 help: replace it with `assert!(..)`
    |
 LL -     assert_ne!("".is_empty(), true);
-LL +     assert!("".is_empty());
+LL +     assert!(!"".is_empty());
    |
 
 error: used `assert_ne!` with a literal bool
@@ -80,7 +80,7 @@ LL |     assert_ne!(true, "".is_empty());
 help: replace it with `assert!(..)`
    |
 LL -     assert_ne!(true, "".is_empty());
-LL +     assert!("".is_empty());
+LL +     assert!(!"".is_empty());
    |
 
 error: used `assert_ne!` with a literal bool
@@ -92,7 +92,7 @@ LL |     assert_ne!(b, true);
 help: replace it with `assert!(..)`
    |
 LL -     assert_ne!(b, true);
-LL +     assert!(b);
+LL +     assert!(!b);
    |
 
 error: used `debug_assert_eq!` with a literal bool
@@ -104,7 +104,7 @@ LL |     debug_assert_eq!("a".is_empty(), false);
 help: replace it with `debug_assert!(..)`
    |
 LL -     debug_assert_eq!("a".is_empty(), false);
-LL +     debug_assert!("a".is_empty());
+LL +     debug_assert!(!"a".is_empty());
    |
 
 error: used `debug_assert_eq!` with a literal bool
@@ -164,7 +164,7 @@ LL |     debug_assert_ne!("".is_empty(), true);
 help: replace it with `debug_assert!(..)`
    |
 LL -     debug_assert_ne!("".is_empty(), true);
-LL +     debug_assert!("".is_empty());
+LL +     debug_assert!(!"".is_empty());
    |
 
 error: used `debug_assert_ne!` with a literal bool
@@ -176,7 +176,7 @@ LL |     debug_assert_ne!(true, "".is_empty());
 help: replace it with `debug_assert!(..)`
    |
 LL -     debug_assert_ne!(true, "".is_empty());
-LL +     debug_assert!("".is_empty());
+LL +     debug_assert!(!"".is_empty());
    |
 
 error: used `debug_assert_ne!` with a literal bool
@@ -188,7 +188,7 @@ LL |     debug_assert_ne!(b, true);
 help: replace it with `debug_assert!(..)`
    |
 LL -     debug_assert_ne!(b, true);
-LL +     debug_assert!(b);
+LL +     debug_assert!(!b);
    |
 
 error: used `assert_eq!` with a literal bool
@@ -200,7 +200,7 @@ LL |     assert_eq!("a".is_empty(), false, "tadam {}", 1);
 help: replace it with `assert!(..)`
    |
 LL -     assert_eq!("a".is_empty(), false, "tadam {}", 1);
-LL +     assert!("a".is_empty(), "tadam {}", 1);
+LL +     assert!(!"a".is_empty(), "tadam {}", 1);
    |
 
 error: used `assert_eq!` with a literal bool
@@ -212,7 +212,7 @@ LL |     assert_eq!("a".is_empty(), false, "tadam {}", true);
 help: replace it with `assert!(..)`
    |
 LL -     assert_eq!("a".is_empty(), false, "tadam {}", true);
-LL +     assert!("a".is_empty(), "tadam {}", true);
+LL +     assert!(!"a".is_empty(), "tadam {}", true);
    |
 
 error: used `assert_eq!` with a literal bool
@@ -224,7 +224,7 @@ LL |     assert_eq!(false, "a".is_empty(), "tadam {}", true);
 help: replace it with `assert!(..)`
    |
 LL -     assert_eq!(false, "a".is_empty(), "tadam {}", true);
-LL +     assert!("a".is_empty(), "tadam {}", true);
+LL +     assert!(!"a".is_empty(), "tadam {}", true);
    |
 
 error: used `debug_assert_eq!` with a literal bool
@@ -236,7 +236,7 @@ LL |     debug_assert_eq!("a".is_empty(), false, "tadam {}", 1);
 help: replace it with `debug_assert!(..)`
    |
 LL -     debug_assert_eq!("a".is_empty(), false, "tadam {}", 1);
-LL +     debug_assert!("a".is_empty(), "tadam {}", 1);
+LL +     debug_assert!(!"a".is_empty(), "tadam {}", 1);
    |
 
 error: used `debug_assert_eq!` with a literal bool
@@ -248,7 +248,7 @@ LL |     debug_assert_eq!("a".is_empty(), false, "tadam {}", true);
 help: replace it with `debug_assert!(..)`
    |
 LL -     debug_assert_eq!("a".is_empty(), false, "tadam {}", true);
-LL +     debug_assert!("a".is_empty(), "tadam {}", true);
+LL +     debug_assert!(!"a".is_empty(), "tadam {}", true);
    |
 
 error: used `debug_assert_eq!` with a literal bool
@@ -260,7 +260,7 @@ LL |     debug_assert_eq!(false, "a".is_empty(), "tadam {}", true);
 help: replace it with `debug_assert!(..)`
    |
 LL -     debug_assert_eq!(false, "a".is_empty(), "tadam {}", true);
-LL +     debug_assert!("a".is_empty(), "tadam {}", true);
+LL +     debug_assert!(!"a".is_empty(), "tadam {}", true);
    |
 
 error: used `assert_eq!` with a literal bool
@@ -299,5 +299,101 @@ LL -     renamed!(b, true);
 LL +     debug_assert!(b);
    |
 
-error: aborting due to 25 previous errors
+error: used `assert_eq!` with a literal bool
+  --> $DIR/bool_assert_comparison.rs:162:5
+   |
+LL |     assert_eq!("".is_empty(), true);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `assert!(..)`
+   |
+LL -     assert_eq!("".is_empty(), true);
+LL +     assert!("".is_empty());
+   |
+
+error: used `assert_ne!` with a literal bool
+  --> $DIR/bool_assert_comparison.rs:163:5
+   |
+LL |     assert_ne!("".is_empty(), false);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `assert!(..)`
+   |
+LL -     assert_ne!("".is_empty(), false);
+LL +     assert!("".is_empty());
+   |
+
+error: used `assert_ne!` with a literal bool
+  --> $DIR/bool_assert_comparison.rs:164:5
+   |
+LL |     assert_ne!("requires negation".is_empty(), true);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `assert!(..)`
+   |
+LL -     assert_ne!("requires negation".is_empty(), true);
+LL +     assert!(!"requires negation".is_empty());
+   |
+
+error: used `assert_eq!` with a literal bool
+  --> $DIR/bool_assert_comparison.rs:165:5
+   |
+LL |     assert_eq!("requires negation".is_empty(), false);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `assert!(..)`
+   |
+LL -     assert_eq!("requires negation".is_empty(), false);
+LL +     assert!(!"requires negation".is_empty());
+   |
+
+error: used `debug_assert_eq!` with a literal bool
+  --> $DIR/bool_assert_comparison.rs:167:5
+   |
+LL |     debug_assert_eq!("".is_empty(), true);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `debug_assert!(..)`
+   |
+LL -     debug_assert_eq!("".is_empty(), true);
+LL +     debug_assert!("".is_empty());
+   |
+
+error: used `debug_assert_ne!` with a literal bool
+  --> $DIR/bool_assert_comparison.rs:168:5
+   |
+LL |     debug_assert_ne!("".is_empty(), false);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `debug_assert!(..)`
+   |
+LL -     debug_assert_ne!("".is_empty(), false);
+LL +     debug_assert!("".is_empty());
+   |
+
+error: used `debug_assert_ne!` with a literal bool
+  --> $DIR/bool_assert_comparison.rs:169:5
+   |
+LL |     debug_assert_ne!("requires negation".is_empty(), true);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `debug_assert!(..)`
+   |
+LL -     debug_assert_ne!("requires negation".is_empty(), true);
+LL +     debug_assert!(!"requires negation".is_empty());
+   |
+
+error: used `debug_assert_eq!` with a literal bool
+  --> $DIR/bool_assert_comparison.rs:170:5
+   |
+LL |     debug_assert_eq!("requires negation".is_empty(), false);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `debug_assert!(..)`
+   |
+LL -     debug_assert_eq!("requires negation".is_empty(), false);
+LL +     debug_assert!(!"requires negation".is_empty());
+   |
+
+error: aborting due to 33 previous errors
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-2774.stderr b/src/tools/clippy/tests/ui/crashes/ice-2774.stderr
index 1f26c7f4db6..c5ea0b16d1b 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-2774.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-2774.stderr
@@ -5,6 +5,11 @@ LL | pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::needless-lifetimes` implied by `-D warnings`
+help: elide the lifetimes
+   |
+LL - pub fn add_barfoos_to_foos<'a>(bars: &HashSet<&'a Bar>) {
+LL + pub fn add_barfoos_to_foos(bars: &HashSet<&Bar>) {
+   |
 
 error: aborting due to previous error
 
diff --git a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr b/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr
index 875d5ab4f21..0b0e0ad2684 100644
--- a/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr
+++ b/src/tools/clippy/tests/ui/crashes/needless_lifetimes_impl_trait.stderr
@@ -9,6 +9,11 @@ note: the lint level is defined here
    |
 LL | #![deny(clippy::needless_lifetimes)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: elide the lifetimes
+   |
+LL -     fn baz<'a>(&'a self) -> impl Foo + 'a {
+LL +     fn baz(&self) -> impl Foo + '_ {
+   |
 
 error: aborting due to previous error
 
diff --git a/src/tools/clippy/tests/ui/extra_unused_type_parameters.rs b/src/tools/clippy/tests/ui/extra_unused_type_parameters.rs
new file mode 100644
index 00000000000..5cb80cb6233
--- /dev/null
+++ b/src/tools/clippy/tests/ui/extra_unused_type_parameters.rs
@@ -0,0 +1,69 @@
+#![allow(unused, clippy::needless_lifetimes)]
+#![warn(clippy::extra_unused_type_parameters)]
+
+fn unused_ty<T>(x: u8) {}
+
+fn unused_multi<T, U>(x: u8) {}
+
+fn unused_with_lt<'a, T>(x: &'a u8) {}
+
+fn used_ty<T>(x: T, y: u8) {}
+
+fn used_ref<'a, T>(x: &'a T) {}
+
+fn used_ret<T: Default>(x: u8) -> T {
+    T::default()
+}
+
+fn unused_bounded<T: Default, U>(x: U) {}
+
+fn unused_where_clause<T, U>(x: U)
+where
+    T: Default,
+{
+}
+
+fn some_unused<A, B, C, D: Iterator<Item = (B, C)>, E>(b: B, c: C) {}
+
+fn used_opaque<A>(iter: impl Iterator<Item = A>) -> usize {
+    iter.count()
+}
+
+fn used_ret_opaque<A>() -> impl Iterator<Item = A> {
+    std::iter::empty()
+}
+
+fn used_vec_box<T>(x: Vec<Box<T>>) {}
+
+fn used_body<T: Default + ToString>() -> String {
+    T::default().to_string()
+}
+
+fn used_closure<T: Default + ToString>() -> impl Fn() {
+    || println!("{}", T::default().to_string())
+}
+
+struct S;
+
+impl S {
+    fn unused_ty_impl<T>(&self) {}
+}
+
+// Don't lint on trait methods
+trait Foo {
+    fn bar<T>(&self);
+}
+
+impl Foo for S {
+    fn bar<T>(&self) {}
+}
+
+fn skip_index<A, Iter>(iter: Iter, index: usize) -> impl Iterator<Item = A>
+where
+    Iter: Iterator<Item = A>,
+{
+    iter.enumerate()
+        .filter_map(move |(i, a)| if i == index { None } else { Some(a) })
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr b/src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr
new file mode 100644
index 00000000000..1c8dd53e638
--- /dev/null
+++ b/src/tools/clippy/tests/ui/extra_unused_type_parameters.stderr
@@ -0,0 +1,59 @@
+error: type parameter goes unused in function definition
+  --> $DIR/extra_unused_type_parameters.rs:4:13
+   |
+LL | fn unused_ty<T>(x: u8) {}
+   |             ^^^
+   |
+   = help: consider removing the parameter
+   = note: `-D clippy::extra-unused-type-parameters` implied by `-D warnings`
+
+error: type parameters go unused in function definition
+  --> $DIR/extra_unused_type_parameters.rs:6:16
+   |
+LL | fn unused_multi<T, U>(x: u8) {}
+   |                ^^^^^^
+   |
+   = help: consider removing the parameters
+
+error: type parameter goes unused in function definition
+  --> $DIR/extra_unused_type_parameters.rs:8:23
+   |
+LL | fn unused_with_lt<'a, T>(x: &'a u8) {}
+   |                       ^
+   |
+   = help: consider removing the parameter
+
+error: type parameter goes unused in function definition
+  --> $DIR/extra_unused_type_parameters.rs:18:19
+   |
+LL | fn unused_bounded<T: Default, U>(x: U) {}
+   |                   ^^^^^^^^^^^
+   |
+   = help: consider removing the parameter
+
+error: type parameter goes unused in function definition
+  --> $DIR/extra_unused_type_parameters.rs:20:24
+   |
+LL | fn unused_where_clause<T, U>(x: U)
+   |                        ^^
+   |
+   = help: consider removing the parameter
+
+error: type parameters go unused in function definition
+  --> $DIR/extra_unused_type_parameters.rs:26:16
+   |
+LL | fn some_unused<A, B, C, D: Iterator<Item = (B, C)>, E>(b: B, c: C) {}
+   |                ^^       ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^
+   |
+   = help: consider removing the parameters
+
+error: type parameter goes unused in function definition
+  --> $DIR/extra_unused_type_parameters.rs:49:22
+   |
+LL |     fn unused_ty_impl<T>(&self) {}
+   |                      ^^^
+   |
+   = help: consider removing the parameter
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/len_without_is_empty.rs b/src/tools/clippy/tests/ui/len_without_is_empty.rs
index 78397c2af34..b5dec6c46bd 100644
--- a/src/tools/clippy/tests/ui/len_without_is_empty.rs
+++ b/src/tools/clippy/tests/ui/len_without_is_empty.rs
@@ -282,4 +282,50 @@ impl AsyncLen {
     }
 }
 
+// issue #9520
+pub struct NonStandardLenAndIsEmptySignature;
+impl NonStandardLenAndIsEmptySignature {
+    // don't lint
+    pub fn len(&self, something: usize) -> usize {
+        something
+    }
+
+    pub fn is_empty(&self, something: usize) -> bool {
+        something == 0
+    }
+}
+
+// test case for #9520 with generics in the function signature
+pub trait TestResource {
+    type NonStandardSignatureWithGenerics: Copy;
+    fn lookup_content(&self, item: Self::NonStandardSignatureWithGenerics) -> Result<Option<&[u8]>, String>;
+}
+pub struct NonStandardSignatureWithGenerics(u32);
+impl NonStandardSignatureWithGenerics {
+    pub fn is_empty<T, U>(self, resource: &T) -> bool
+    where
+        T: TestResource<NonStandardSignatureWithGenerics = U>,
+        U: Copy + From<NonStandardSignatureWithGenerics>,
+    {
+        if let Ok(Some(content)) = resource.lookup_content(self.into()) {
+            content.is_empty()
+        } else {
+            true
+        }
+    }
+
+    // test case for #9520 with generics in the function signature
+    pub fn len<T, U>(self, resource: &T) -> usize
+    where
+        T: TestResource<NonStandardSignatureWithGenerics = U>,
+        U: Copy + From<NonStandardSignatureWithGenerics>,
+    {
+        if let Ok(Some(content)) = resource.lookup_content(self.into()) {
+            content.len()
+        } else {
+            0_usize
+        }
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
index 638320dd6ee..8c7e919bf62 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed
@@ -29,9 +29,7 @@ fn main() {
         panic!("qaqaq{:?}", a);
     }
     assert!(a.is_empty(), "qaqaq{:?}", a);
-    if !a.is_empty() {
-        panic!("qwqwq");
-    }
+    assert!(a.is_empty(), "qwqwq");
     if a.len() == 3 {
         println!("qwq");
         println!("qwq");
@@ -46,21 +44,11 @@ fn main() {
         println!("qwq");
     }
     let b = vec![1, 2, 3];
-    if b.is_empty() {
-        panic!("panic1");
-    }
-    if b.is_empty() && a.is_empty() {
-        panic!("panic2");
-    }
-    if a.is_empty() && !b.is_empty() {
-        panic!("panic3");
-    }
-    if b.is_empty() || a.is_empty() {
-        panic!("panic4");
-    }
-    if a.is_empty() || !b.is_empty() {
-        panic!("panic5");
-    }
+    assert!(!b.is_empty(), "panic1");
+    assert!(!(b.is_empty() && a.is_empty()), "panic2");
+    assert!(!(a.is_empty() && !b.is_empty()), "panic3");
+    assert!(!(b.is_empty() || a.is_empty()), "panic4");
+    assert!(!(a.is_empty() || !b.is_empty()), "panic5");
     assert!(!a.is_empty(), "with expansion {}", one!());
     if a.is_empty() {
         let _ = 0;
@@ -71,12 +59,11 @@ fn main() {
 
 fn issue7730(a: u8) {
     // Suggestion should preserve comment
-    if a > 2 {
-        // comment
-        /* this is a
+    // comment
+/* this is a
         multiline
         comment */
-        /// Doc comment
-        panic!("panic with comment") // comment after `panic!`
-    }
+/// Doc comment
+// comment after `panic!`
+assert!(!(a > 2), "panic with comment");
 }
diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
index 1f2e1e3087b..3555ac29243 100644
--- a/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
+++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.stderr
@@ -9,6 +9,54 @@ LL | |     }
    = note: `-D clippy::manual-assert` implied by `-D warnings`
 
 error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:34:5
+   |
+LL | /     if !a.is_empty() {
+LL | |         panic!("qwqwq");
+LL | |     }
+   | |_____^ help: try instead: `assert!(a.is_empty(), "qwqwq");`
+
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:51:5
+   |
+LL | /     if b.is_empty() {
+LL | |         panic!("panic1");
+LL | |     }
+   | |_____^ help: try instead: `assert!(!b.is_empty(), "panic1");`
+
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:54:5
+   |
+LL | /     if b.is_empty() && a.is_empty() {
+LL | |         panic!("panic2");
+LL | |     }
+   | |_____^ help: try instead: `assert!(!(b.is_empty() && a.is_empty()), "panic2");`
+
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:57:5
+   |
+LL | /     if a.is_empty() && !b.is_empty() {
+LL | |         panic!("panic3");
+LL | |     }
+   | |_____^ help: try instead: `assert!(!(a.is_empty() && !b.is_empty()), "panic3");`
+
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:60:5
+   |
+LL | /     if b.is_empty() || a.is_empty() {
+LL | |         panic!("panic4");
+LL | |     }
+   | |_____^ help: try instead: `assert!(!(b.is_empty() || a.is_empty()), "panic4");`
+
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:63:5
+   |
+LL | /     if a.is_empty() || !b.is_empty() {
+LL | |         panic!("panic5");
+LL | |     }
+   | |_____^ help: try instead: `assert!(!(a.is_empty() || !b.is_empty()), "panic5");`
+
+error: only a `panic!` in `if`-then statement
   --> $DIR/manual_assert.rs:66:5
    |
 LL | /     if a.is_empty() {
@@ -16,5 +64,22 @@ LL | |         panic!("with expansion {}", one!())
 LL | |     }
    | |_____^ help: try instead: `assert!(!a.is_empty(), "with expansion {}", one!());`
 
-error: aborting due to 2 previous errors
+error: only a `panic!` in `if`-then statement
+  --> $DIR/manual_assert.rs:78:5
+   |
+LL | /     if a > 2 {
+LL | |         // comment
+LL | |         /* this is a
+LL | |         multiline
+...  |
+LL | |         panic!("panic with comment") // comment after `panic!`
+LL | |     }
+   | |_____^
+   |
+help: try instead
+   |
+LL |     assert!(!(a > 2), "panic with comment");
+   |
+
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed
index fc252cdd352..9fd3739b69c 100644
--- a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed
+++ b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed
@@ -123,7 +123,7 @@ fn main() {
             Enum::A => (),
             Enum::B => (),
             Enum::C => (),
-            _ => (),
+            Enum::__Private => (),
         }
         match Enum::A {
             Enum::A => (),
diff --git a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr
index 6fa313dc911..105b4c4b41d 100644
--- a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr
+++ b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.stderr
@@ -49,10 +49,16 @@ LL |         _ => (),
    |         ^ help: try this: `Color::Blue`
 
 error: wildcard matches only a single variant and will also match any future added variants
+  --> $DIR/match_wildcard_for_single_variants.rs:126:13
+   |
+LL |             _ => (),
+   |             ^ help: try this: `Enum::__Private`
+
+error: wildcard matches only a single variant and will also match any future added variants
   --> $DIR/match_wildcard_for_single_variants.rs:153:13
    |
 LL |             _ => 2,
    |             ^ help: try this: `Foo::B`
 
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs
index 41263535df6..4511bc99c3c 100644
--- a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs
@@ -1,9 +1,13 @@
+// aux-build:macro_rules.rs
 #![allow(unused)]
 #![allow(deref_nullptr)]
 #![allow(clippy::unnecessary_operation)]
 #![allow(clippy::drop_copy)]
 #![warn(clippy::multiple_unsafe_ops_per_block)]
 
+#[macro_use]
+extern crate macro_rules;
+
 use core::arch::asm;
 
 fn raw_ptr() -> *const () {
@@ -107,4 +111,9 @@ unsafe fn read_char_good(ptr: *const u8) -> char {
     unsafe { core::char::from_u32_unchecked(int_value) }
 }
 
+// no lint
+fn issue10259() {
+    unsafe_macro!();
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr
index f6b8341795d..303aeb7aee0 100644
--- a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr
+++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.stderr
@@ -1,5 +1,5 @@
 error: this `unsafe` block contains 2 unsafe operations, expected only one
-  --> $DIR/multiple_unsafe_ops_per_block.rs:32:5
+  --> $DIR/multiple_unsafe_ops_per_block.rs:36:5
    |
 LL | /     unsafe {
 LL | |         STATIC += 1;
@@ -8,19 +8,19 @@ LL | |     }
    | |_____^
    |
 note: modification of a mutable static occurs here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:33:9
+  --> $DIR/multiple_unsafe_ops_per_block.rs:37:9
    |
 LL |         STATIC += 1;
    |         ^^^^^^^^^^^
 note: unsafe function call occurs here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:34:9
+  --> $DIR/multiple_unsafe_ops_per_block.rs:38:9
    |
 LL |         not_very_safe();
    |         ^^^^^^^^^^^^^^^
    = note: `-D clippy::multiple-unsafe-ops-per-block` implied by `-D warnings`
 
 error: this `unsafe` block contains 2 unsafe operations, expected only one
-  --> $DIR/multiple_unsafe_ops_per_block.rs:41:5
+  --> $DIR/multiple_unsafe_ops_per_block.rs:45:5
    |
 LL | /     unsafe {
 LL | |         drop(u.u);
@@ -29,18 +29,18 @@ LL | |     }
    | |_____^
    |
 note: union field access occurs here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:42:14
+  --> $DIR/multiple_unsafe_ops_per_block.rs:46:14
    |
 LL |         drop(u.u);
    |              ^^^
 note: raw pointer dereference occurs here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:43:9
+  --> $DIR/multiple_unsafe_ops_per_block.rs:47:9
    |
 LL |         *raw_ptr();
    |         ^^^^^^^^^^
 
 error: this `unsafe` block contains 3 unsafe operations, expected only one
-  --> $DIR/multiple_unsafe_ops_per_block.rs:48:5
+  --> $DIR/multiple_unsafe_ops_per_block.rs:52:5
    |
 LL | /     unsafe {
 LL | |         asm!("nop");
@@ -50,23 +50,23 @@ LL | |     }
    | |_____^
    |
 note: inline assembly used here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:49:9
+  --> $DIR/multiple_unsafe_ops_per_block.rs:53:9
    |
 LL |         asm!("nop");
    |         ^^^^^^^^^^^
 note: unsafe method call occurs here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:50:9
+  --> $DIR/multiple_unsafe_ops_per_block.rs:54:9
    |
 LL |         sample.not_very_safe();
    |         ^^^^^^^^^^^^^^^^^^^^^^
 note: modification of a mutable static occurs here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:51:9
+  --> $DIR/multiple_unsafe_ops_per_block.rs:55:9
    |
 LL |         STATIC = 0;
    |         ^^^^^^^^^^
 
 error: this `unsafe` block contains 6 unsafe operations, expected only one
-  --> $DIR/multiple_unsafe_ops_per_block.rs:57:5
+  --> $DIR/multiple_unsafe_ops_per_block.rs:61:5
    |
 LL | /     unsafe {
 LL | |         drop(u.u);
@@ -78,49 +78,49 @@ LL | |     }
    | |_____^
    |
 note: union field access occurs here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:58:14
+  --> $DIR/multiple_unsafe_ops_per_block.rs:62:14
    |
 LL |         drop(u.u);
    |              ^^^
 note: access of a mutable static occurs here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:59:14
+  --> $DIR/multiple_unsafe_ops_per_block.rs:63:14
    |
 LL |         drop(STATIC);
    |              ^^^^^^
 note: unsafe method call occurs here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:60:9
+  --> $DIR/multiple_unsafe_ops_per_block.rs:64:9
    |
 LL |         sample.not_very_safe();
    |         ^^^^^^^^^^^^^^^^^^^^^^
 note: unsafe function call occurs here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:61:9
+  --> $DIR/multiple_unsafe_ops_per_block.rs:65:9
    |
 LL |         not_very_safe();
    |         ^^^^^^^^^^^^^^^
 note: raw pointer dereference occurs here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:62:9
+  --> $DIR/multiple_unsafe_ops_per_block.rs:66:9
    |
 LL |         *raw_ptr();
    |         ^^^^^^^^^^
 note: inline assembly used here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:63:9
+  --> $DIR/multiple_unsafe_ops_per_block.rs:67:9
    |
 LL |         asm!("nop");
    |         ^^^^^^^^^^^
 
 error: this `unsafe` block contains 2 unsafe operations, expected only one
-  --> $DIR/multiple_unsafe_ops_per_block.rs:101:5
+  --> $DIR/multiple_unsafe_ops_per_block.rs:105:5
    |
 LL |     unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: unsafe function call occurs here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:101:14
+  --> $DIR/multiple_unsafe_ops_per_block.rs:105:14
    |
 LL |     unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: raw pointer dereference occurs here
-  --> $DIR/multiple_unsafe_ops_per_block.rs:101:39
+  --> $DIR/multiple_unsafe_ops_per_block.rs:105:39
    |
 LL |     unsafe { char::from_u32_unchecked(*ptr.cast::<u32>()) }
    |                                       ^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.fixed b/src/tools/clippy/tests/ui/needless_lifetimes.fixed
new file mode 100644
index 00000000000..d286ef4ba37
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.fixed
@@ -0,0 +1,538 @@
+// run-rustfix
+// aux-build:macro_rules.rs
+
+#![warn(clippy::needless_lifetimes)]
+#![allow(
+    unused,
+    clippy::boxed_local,
+    clippy::extra_unused_type_parameters,
+    clippy::needless_pass_by_value,
+    clippy::unnecessary_wraps,
+    dyn_drop,
+    clippy::get_first
+)]
+
+#[macro_use]
+extern crate macro_rules;
+
+fn distinct_lifetimes(_x: &u8, _y: &u8, _z: u8) {}
+
+fn distinct_and_static(_x: &u8, _y: &u8, _z: &'static u8) {}
+
+// No error; same lifetime on two params.
+fn same_lifetime_on_input<'a>(_x: &'a u8, _y: &'a u8) {}
+
+// No error; static involved.
+fn only_static_on_input(_x: &u8, _y: &u8, _z: &'static u8) {}
+
+fn mut_and_static_input(_x: &mut u8, _y: &'static str) {}
+
+fn in_and_out(x: &u8, _y: u8) -> &u8 {
+    x
+}
+
+// No error; multiple input refs.
+fn multiple_in_and_out_1<'a>(x: &'a u8, _y: &'a u8) -> &'a u8 {
+    x
+}
+
+// Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid:
+//   fn multiple_in_and_out_2a<'a>(x: &'a u8, _y: &u8) -> &'a u8
+//                                                ^^^
+fn multiple_in_and_out_2a<'a>(x: &'a u8, _y: &u8) -> &'a u8 {
+    x
+}
+
+// Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid:
+//   fn multiple_in_and_out_2b<'b>(_x: &u8, y: &'b u8) -> &'b u8
+//                                     ^^^
+fn multiple_in_and_out_2b<'b>(_x: &u8, y: &'b u8) -> &'b u8 {
+    y
+}
+
+// No error; multiple input refs
+async fn func<'a>(args: &[&'a str]) -> Option<&'a str> {
+    args.get(0).cloned()
+}
+
+// No error; static involved.
+fn in_static_and_out<'a>(x: &'a u8, _y: &'static u8) -> &'a u8 {
+    x
+}
+
+// Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid:
+//   fn deep_reference_1a<'a>(x: &'a u8, _y: &u8) -> Result<&'a u8, ()>
+//                                           ^^^
+fn deep_reference_1a<'a>(x: &'a u8, _y: &u8) -> Result<&'a u8, ()> {
+    Ok(x)
+}
+
+// Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid:
+//   fn deep_reference_1b<'b>(_x: &u8, y: &'b u8) -> Result<&'b u8, ()>
+//                                ^^^
+fn deep_reference_1b<'b>(_x: &u8, y: &'b u8) -> Result<&'b u8, ()> {
+    Ok(y)
+}
+
+// No error; two input refs.
+fn deep_reference_2<'a>(x: Result<&'a u8, &'a u8>) -> &'a u8 {
+    x.unwrap()
+}
+
+fn deep_reference_3(x: &u8, _y: u8) -> Result<&u8, ()> {
+    Ok(x)
+}
+
+// Where-clause, but without lifetimes.
+fn where_clause_without_lt<T>(x: &u8, _y: u8) -> Result<&u8, ()>
+where
+    T: Copy,
+{
+    Ok(x)
+}
+
+type Ref<'r> = &'r u8;
+
+// No error; same lifetime on two params.
+fn lifetime_param_1<'a>(_x: Ref<'a>, _y: &'a u8) {}
+
+fn lifetime_param_2(_x: Ref<'_>, _y: &u8) {}
+
+// No error; bounded lifetime.
+fn lifetime_param_3<'a, 'b: 'a>(_x: Ref<'a>, _y: &'b u8) {}
+
+// No error; bounded lifetime.
+fn lifetime_param_4<'a, 'b>(_x: Ref<'a>, _y: &'b u8)
+where
+    'b: 'a,
+{
+}
+
+struct Lt<'a, I: 'static> {
+    x: &'a I,
+}
+
+// No error; fn bound references `'a`.
+fn fn_bound<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
+where
+    F: Fn(Lt<'a, I>) -> Lt<'a, I>,
+{
+    unreachable!()
+}
+
+fn fn_bound_2<F, I>(_m: Lt<'_, I>, _f: F) -> Lt<'_, I>
+where
+    for<'x> F: Fn(Lt<'x, I>) -> Lt<'x, I>,
+{
+    unreachable!()
+}
+
+// No error; see below.
+fn fn_bound_3<'a, F: FnOnce(&'a i32)>(x: &'a i32, f: F) {
+    f(x);
+}
+
+fn fn_bound_3_cannot_elide() {
+    let x = 42;
+    let p = &x;
+    let mut q = &x;
+    // This will fail if we elide lifetimes of `fn_bound_3`.
+    fn_bound_3(p, |y| q = y);
+}
+
+// No error; multiple input refs.
+fn fn_bound_4<'a, F: FnOnce() -> &'a ()>(cond: bool, x: &'a (), f: F) -> &'a () {
+    if cond { x } else { f() }
+}
+
+struct X {
+    x: u8,
+}
+
+impl X {
+    fn self_and_out(&self) -> &u8 {
+        &self.x
+    }
+
+    // Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid:
+    //   fn self_and_in_out_1<'s>(&'s self, _x: &u8) -> &'s u8
+    //                                          ^^^
+    fn self_and_in_out_1<'s>(&'s self, _x: &u8) -> &'s u8 {
+        &self.x
+    }
+
+    // Error; multiple input refs, but the output lifetime is not elided, i.e., the following is valid:
+    //   fn self_and_in_out_2<'t>(&self, x: &'t u8) -> &'t u8
+    //                            ^^^^^
+    fn self_and_in_out_2<'t>(&self, x: &'t u8) -> &'t u8 {
+        x
+    }
+
+    fn distinct_self_and_in(&self, _x: &u8) {}
+
+    // No error; same lifetimes on two params.
+    fn self_and_same_in<'s>(&'s self, _x: &'s u8) {}
+}
+
+struct Foo<'a>(&'a u8);
+
+impl<'a> Foo<'a> {
+    // No error; lifetime `'a` not defined in method.
+    fn self_shared_lifetime(&self, _: &'a u8) {}
+    // No error; bounds exist.
+    fn self_bound_lifetime<'b: 'a>(&self, _: &'b u8) {}
+}
+
+fn already_elided<'a>(_: &u8, _: &'a u8) -> &'a u8 {
+    unimplemented!()
+}
+
+fn struct_with_lt(_foo: Foo<'_>) -> &str {
+    unimplemented!()
+}
+
+// No warning; two input lifetimes (named on the reference, anonymous on `Foo`).
+fn struct_with_lt2<'a>(_foo: &'a Foo) -> &'a str {
+    unimplemented!()
+}
+
+// No warning; two input lifetimes (anonymous on the reference, named on `Foo`).
+fn struct_with_lt3<'a>(_foo: &Foo<'a>) -> &'a str {
+    unimplemented!()
+}
+
+// Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is
+// valid:
+//   fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str
+//                                         ^^
+fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str {
+    unimplemented!()
+}
+
+// Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is
+// valid:
+//   fn struct_with_lt4b<'b>(_foo: &Foo<'b>) -> &'b str
+//                                 ^^^^
+fn struct_with_lt4b<'b>(_foo: &Foo<'b>) -> &'b str {
+    unimplemented!()
+}
+
+trait WithLifetime<'a> {}
+
+type WithLifetimeAlias<'a> = dyn WithLifetime<'a>;
+
+// Should not warn because it won't build without the lifetime.
+fn trait_obj_elided<'a>(_arg: &'a dyn WithLifetime) -> &'a str {
+    unimplemented!()
+}
+
+// Should warn because there is no lifetime on `Drop`, so this would be
+// unambiguous if we elided the lifetime.
+fn trait_obj_elided2(_arg: &dyn Drop) -> &str {
+    unimplemented!()
+}
+
+type FooAlias<'a> = Foo<'a>;
+
+fn alias_with_lt(_foo: FooAlias<'_>) -> &str {
+    unimplemented!()
+}
+
+// No warning; two input lifetimes (named on the reference, anonymous on `FooAlias`).
+fn alias_with_lt2<'a>(_foo: &'a FooAlias) -> &'a str {
+    unimplemented!()
+}
+
+// No warning; two input lifetimes (anonymous on the reference, named on `FooAlias`).
+fn alias_with_lt3<'a>(_foo: &FooAlias<'a>) -> &'a str {
+    unimplemented!()
+}
+
+// Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is
+// valid:
+//   fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str
+//                                             ^^
+fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str {
+    unimplemented!()
+}
+
+// Warning; two input lifetimes, but the output lifetime is not elided, i.e., the following is
+// valid:
+//   fn alias_with_lt4b<'b>(_foo: &FooAlias<'b>) -> &'b str
+//                                ^^^^^^^^^
+fn alias_with_lt4b<'b>(_foo: &FooAlias<'b>) -> &'b str {
+    unimplemented!()
+}
+
+fn named_input_elided_output(_arg: &str) -> &str {
+    unimplemented!()
+}
+
+fn elided_input_named_output<'a>(_arg: &str) -> &'a str {
+    unimplemented!()
+}
+
+fn trait_bound_ok<T: WithLifetime<'static>>(_: &u8, _: T) {
+    unimplemented!()
+}
+fn trait_bound<'a, T: WithLifetime<'a>>(_: &'a u8, _: T) {
+    unimplemented!()
+}
+
+// Don't warn on these; see issue #292.
+fn trait_bound_bug<'a, T: WithLifetime<'a>>() {
+    unimplemented!()
+}
+
+// See issue #740.
+struct Test {
+    vec: Vec<usize>,
+}
+
+impl Test {
+    fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = usize> + 'a> {
+        unimplemented!()
+    }
+}
+
+trait LintContext<'a> {}
+
+fn f<'a, T: LintContext<'a>>(_: &T) {}
+
+fn test<'a>(x: &'a [u8]) -> u8 {
+    let y: &'a u8 = &x[5];
+    *y
+}
+
+// Issue #3284: give hint regarding lifetime in return type.
+struct Cow<'a> {
+    x: &'a str,
+}
+fn out_return_type_lts(e: &str) -> Cow<'_> {
+    unimplemented!()
+}
+
+// Make sure we still warn on implementations
+mod issue4291 {
+    trait BadTrait {
+        fn needless_lt(x: &u8) {}
+    }
+
+    impl BadTrait for () {
+        fn needless_lt(_x: &u8) {}
+    }
+}
+
+mod issue2944 {
+    trait Foo {}
+    struct Bar;
+    struct Baz<'a> {
+        bar: &'a Bar,
+    }
+
+    impl<'a> Foo for Baz<'a> {}
+    impl Bar {
+        fn baz(&self) -> impl Foo + '_ {
+            Baz { bar: self }
+        }
+    }
+}
+
+mod nested_elision_sites {
+    // issue #issue2944
+
+    // closure trait bounds subject to nested elision
+    // don't lint because they refer to outer lifetimes
+    fn trait_fn<'a>(i: &'a i32) -> impl Fn() -> &'a i32 {
+        move || i
+    }
+    fn trait_fn_mut<'a>(i: &'a i32) -> impl FnMut() -> &'a i32 {
+        move || i
+    }
+    fn trait_fn_once<'a>(i: &'a i32) -> impl FnOnce() -> &'a i32 {
+        move || i
+    }
+
+    // don't lint
+    fn impl_trait_in_input_position<'a>(f: impl Fn() -> &'a i32) -> &'a i32 {
+        f()
+    }
+    fn impl_trait_in_output_position<'a>(i: &'a i32) -> impl Fn() -> &'a i32 {
+        move || i
+    }
+    // lint
+    fn impl_trait_elidable_nested_named_lifetimes<'a>(i: &'a i32, f: impl for<'b> Fn(&'b i32) -> &'b i32) -> &'a i32 {
+        f(i)
+    }
+    fn impl_trait_elidable_nested_anonymous_lifetimes(i: &i32, f: impl Fn(&i32) -> &i32) -> &i32 {
+        f(i)
+    }
+
+    // don't lint
+    fn generics_not_elidable<'a, T: Fn() -> &'a i32>(f: T) -> &'a i32 {
+        f()
+    }
+    // lint
+    fn generics_elidable<T: Fn(&i32) -> &i32>(i: &i32, f: T) -> &i32 {
+        f(i)
+    }
+
+    // don't lint
+    fn where_clause_not_elidable<'a, T>(f: T) -> &'a i32
+    where
+        T: Fn() -> &'a i32,
+    {
+        f()
+    }
+    // lint
+    fn where_clause_elidadable<T>(i: &i32, f: T) -> &i32
+    where
+        T: Fn(&i32) -> &i32,
+    {
+        f(i)
+    }
+
+    // don't lint
+    fn pointer_fn_in_input_position<'a>(f: fn(&'a i32) -> &'a i32, i: &'a i32) -> &'a i32 {
+        f(i)
+    }
+    fn pointer_fn_in_output_position<'a>(_: &'a i32) -> fn(&'a i32) -> &'a i32 {
+        |i| i
+    }
+    // lint
+    fn pointer_fn_elidable(i: &i32, f: fn(&i32) -> &i32) -> &i32 {
+        f(i)
+    }
+
+    // don't lint
+    fn nested_fn_pointer_1<'a>(_: &'a i32) -> fn(fn(&'a i32) -> &'a i32) -> i32 {
+        |f| 42
+    }
+    fn nested_fn_pointer_2<'a>(_: &'a i32) -> impl Fn(fn(&'a i32)) {
+        |f| ()
+    }
+
+    // lint
+    fn nested_fn_pointer_3(_: &i32) -> fn(fn(&i32) -> &i32) -> i32 {
+        |f| 42
+    }
+    fn nested_fn_pointer_4(_: &i32) -> impl Fn(fn(&i32)) {
+        |f| ()
+    }
+}
+
+mod issue6159 {
+    use std::ops::Deref;
+    pub fn apply_deref<'a, T, F, R>(x: &'a T, f: F) -> R
+    where
+        T: Deref,
+        F: FnOnce(&'a T::Target) -> R,
+    {
+        f(x.deref())
+    }
+}
+
+mod issue7296 {
+    use std::rc::Rc;
+    use std::sync::Arc;
+
+    struct Foo;
+    impl Foo {
+        fn implicit(&self) -> &() {
+            &()
+        }
+        fn implicit_mut(&mut self) -> &() {
+            &()
+        }
+
+        fn explicit<'a>(self: &'a Arc<Self>) -> &'a () {
+            &()
+        }
+        fn explicit_mut<'a>(self: &'a mut Rc<Self>) -> &'a () {
+            &()
+        }
+
+        fn lifetime_elsewhere(self: Box<Self>, here: &()) -> &() {
+            &()
+        }
+    }
+
+    trait Bar {
+        fn implicit(&self) -> &();
+        fn implicit_provided(&self) -> &() {
+            &()
+        }
+
+        fn explicit<'a>(self: &'a Arc<Self>) -> &'a ();
+        fn explicit_provided<'a>(self: &'a Arc<Self>) -> &'a () {
+            &()
+        }
+
+        fn lifetime_elsewhere(self: Box<Self>, here: &()) -> &();
+        fn lifetime_elsewhere_provided(self: Box<Self>, here: &()) -> &() {
+            &()
+        }
+    }
+}
+
+mod pr_9743_false_negative_fix {
+    #![allow(unused)]
+
+    fn foo(x: &u8, y: &'_ u8) {}
+
+    fn bar(x: &u8, y: &'_ u8, z: &'_ u8) {}
+}
+
+mod pr_9743_output_lifetime_checks {
+    #![allow(unused)]
+
+    // lint: only one input
+    fn one_input(x: &u8) -> &u8 {
+        unimplemented!()
+    }
+
+    // lint: multiple inputs, output would not be elided
+    fn multiple_inputs_output_not_elided<'b>(x: &u8, y: &'b u8, z: &'b u8) -> &'b u8 {
+        unimplemented!()
+    }
+
+    // don't lint: multiple inputs, output would be elided (which would create an ambiguity)
+    fn multiple_inputs_output_would_be_elided<'a, 'b>(x: &'a u8, y: &'b u8, z: &'b u8) -> &'a u8 {
+        unimplemented!()
+    }
+}
+
+mod in_macro {
+    macro_rules! local_one_input_macro {
+        () => {
+            fn one_input(x: &u8) -> &u8 {
+                unimplemented!()
+            }
+        };
+    }
+
+    // lint local macro expands to function with needless lifetimes
+    local_one_input_macro!();
+
+    // no lint on external macro
+    macro_rules::needless_lifetime!();
+}
+
+mod issue5787 {
+    use std::sync::MutexGuard;
+
+    struct Foo;
+
+    impl Foo {
+        // doesn't get linted without async
+        pub async fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> {
+            guard
+        }
+    }
+
+    async fn foo<'a>(_x: &i32, y: &'a str) -> &'a str {
+        y
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs
index 2efc936752e..409528b291d 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.rs
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs
@@ -1,13 +1,20 @@
+// run-rustfix
+// aux-build:macro_rules.rs
+
 #![warn(clippy::needless_lifetimes)]
 #![allow(
-    dead_code,
+    unused,
     clippy::boxed_local,
+    clippy::extra_unused_type_parameters,
     clippy::needless_pass_by_value,
     clippy::unnecessary_wraps,
     dyn_drop,
     clippy::get_first
 )]
 
+#[macro_use]
+extern crate macro_rules;
+
 fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
 
 fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {}
@@ -495,4 +502,37 @@ mod pr_9743_output_lifetime_checks {
     }
 }
 
+mod in_macro {
+    macro_rules! local_one_input_macro {
+        () => {
+            fn one_input<'a>(x: &'a u8) -> &'a u8 {
+                unimplemented!()
+            }
+        };
+    }
+
+    // lint local macro expands to function with needless lifetimes
+    local_one_input_macro!();
+
+    // no lint on external macro
+    macro_rules::needless_lifetime!();
+}
+
+mod issue5787 {
+    use std::sync::MutexGuard;
+
+    struct Foo;
+
+    impl Foo {
+        // doesn't get linted without async
+        pub async fn wait<'a, T>(&self, guard: MutexGuard<'a, T>) -> MutexGuard<'a, T> {
+            guard
+        }
+    }
+
+    async fn foo<'a>(_x: &i32, y: &'a str) -> &'a str {
+        y
+    }
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.stderr b/src/tools/clippy/tests/ui/needless_lifetimes.stderr
index 5a7cf13c86d..4e3c8f20d8c 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.stderr
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.stderr
@@ -1,316 +1,559 @@
 error: the following explicit lifetimes could be elided: 'a, 'b
-  --> $DIR/needless_lifetimes.rs:11:1
+  --> $DIR/needless_lifetimes.rs:18:1
    |
 LL | fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `-D clippy::needless-lifetimes` implied by `-D warnings`
+help: elide the lifetimes
+   |
+LL - fn distinct_lifetimes<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: u8) {}
+LL + fn distinct_lifetimes(_x: &u8, _y: &u8, _z: u8) {}
+   |
 
 error: the following explicit lifetimes could be elided: 'a, 'b
-  --> $DIR/needless_lifetimes.rs:13:1
+  --> $DIR/needless_lifetimes.rs:20:1
    |
 LL | fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL - fn distinct_and_static<'a, 'b>(_x: &'a u8, _y: &'b u8, _z: &'static u8) {}
+LL + fn distinct_and_static(_x: &u8, _y: &u8, _z: &'static u8) {}
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:23:1
+  --> $DIR/needless_lifetimes.rs:30:1
    |
 LL | fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL - fn in_and_out<'a>(x: &'a u8, _y: u8) -> &'a u8 {
+LL + fn in_and_out(x: &u8, _y: u8) -> &u8 {
+   |
 
 error: the following explicit lifetimes could be elided: 'b
-  --> $DIR/needless_lifetimes.rs:35:1
+  --> $DIR/needless_lifetimes.rs:42:1
    |
 LL | fn multiple_in_and_out_2a<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL - fn multiple_in_and_out_2a<'a, 'b>(x: &'a u8, _y: &'b u8) -> &'a u8 {
+LL + fn multiple_in_and_out_2a<'a>(x: &'a u8, _y: &u8) -> &'a u8 {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:42:1
+  --> $DIR/needless_lifetimes.rs:49:1
    |
 LL | fn multiple_in_and_out_2b<'a, 'b>(_x: &'a u8, y: &'b u8) -> &'b u8 {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL - fn multiple_in_and_out_2b<'a, 'b>(_x: &'a u8, y: &'b u8) -> &'b u8 {
+LL + fn multiple_in_and_out_2b<'b>(_x: &u8, y: &'b u8) -> &'b u8 {
+   |
 
 error: the following explicit lifetimes could be elided: 'b
-  --> $DIR/needless_lifetimes.rs:59:1
+  --> $DIR/needless_lifetimes.rs:66:1
    |
 LL | fn deep_reference_1a<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL - fn deep_reference_1a<'a, 'b>(x: &'a u8, _y: &'b u8) -> Result<&'a u8, ()> {
+LL + fn deep_reference_1a<'a>(x: &'a u8, _y: &u8) -> Result<&'a u8, ()> {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:66:1
+  --> $DIR/needless_lifetimes.rs:73:1
    |
 LL | fn deep_reference_1b<'a, 'b>(_x: &'a u8, y: &'b u8) -> Result<&'b u8, ()> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL - fn deep_reference_1b<'a, 'b>(_x: &'a u8, y: &'b u8) -> Result<&'b u8, ()> {
+LL + fn deep_reference_1b<'b>(_x: &u8, y: &'b u8) -> Result<&'b u8, ()> {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:75:1
+  --> $DIR/needless_lifetimes.rs:82:1
    |
 LL | fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL - fn deep_reference_3<'a>(x: &'a u8, _y: u8) -> Result<&'a u8, ()> {
+LL + fn deep_reference_3(x: &u8, _y: u8) -> Result<&u8, ()> {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:80:1
+  --> $DIR/needless_lifetimes.rs:87:1
    |
 LL | fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL - fn where_clause_without_lt<'a, T>(x: &'a u8, _y: u8) -> Result<&'a u8, ()>
+LL + fn where_clause_without_lt<T>(x: &u8, _y: u8) -> Result<&u8, ()>
+   |
 
 error: the following explicit lifetimes could be elided: 'a, 'b
-  --> $DIR/needless_lifetimes.rs:92:1
+  --> $DIR/needless_lifetimes.rs:99:1
    |
 LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: replace with `'_` in generic arguments such as here
-  --> $DIR/needless_lifetimes.rs:92:37
+help: elide the lifetimes
+   |
+LL - fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
+LL + fn lifetime_param_2(_x: Ref<'_>, _y: &u8) {}
    |
-LL | fn lifetime_param_2<'a, 'b>(_x: Ref<'a>, _y: &'b u8) {}
-   |                                     ^^
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:116:1
+  --> $DIR/needless_lifetimes.rs:123:1
    |
 LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: replace with `'_` in generic arguments such as here
-  --> $DIR/needless_lifetimes.rs:116:32
+help: elide the lifetimes
+   |
+LL - fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
+LL + fn fn_bound_2<F, I>(_m: Lt<'_, I>, _f: F) -> Lt<'_, I>
    |
-LL | fn fn_bound_2<'a, F, I>(_m: Lt<'a, I>, _f: F) -> Lt<'a, I>
-   |                                ^^
 
 error: the following explicit lifetimes could be elided: 's
-  --> $DIR/needless_lifetimes.rs:146:5
+  --> $DIR/needless_lifetimes.rs:153:5
    |
 LL |     fn self_and_out<'s>(&'s self) -> &'s u8 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -     fn self_and_out<'s>(&'s self) -> &'s u8 {
+LL +     fn self_and_out(&self) -> &u8 {
+   |
 
 error: the following explicit lifetimes could be elided: 't
-  --> $DIR/needless_lifetimes.rs:153:5
+  --> $DIR/needless_lifetimes.rs:160:5
    |
 LL |     fn self_and_in_out_1<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -     fn self_and_in_out_1<'s, 't>(&'s self, _x: &'t u8) -> &'s u8 {
+LL +     fn self_and_in_out_1<'s>(&'s self, _x: &u8) -> &'s u8 {
+   |
 
 error: the following explicit lifetimes could be elided: 's
-  --> $DIR/needless_lifetimes.rs:160:5
+  --> $DIR/needless_lifetimes.rs:167:5
    |
 LL |     fn self_and_in_out_2<'s, 't>(&'s self, x: &'t u8) -> &'t u8 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -     fn self_and_in_out_2<'s, 't>(&'s self, x: &'t u8) -> &'t u8 {
+LL +     fn self_and_in_out_2<'t>(&self, x: &'t u8) -> &'t u8 {
+   |
 
 error: the following explicit lifetimes could be elided: 's, 't
-  --> $DIR/needless_lifetimes.rs:164:5
+  --> $DIR/needless_lifetimes.rs:171:5
    |
 LL |     fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -     fn distinct_self_and_in<'s, 't>(&'s self, _x: &'t u8) {}
+LL +     fn distinct_self_and_in(&self, _x: &u8) {}
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:183:1
+  --> $DIR/needless_lifetimes.rs:190:1
    |
 LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: replace with `'_` in generic arguments such as here
-  --> $DIR/needless_lifetimes.rs:183:33
+help: elide the lifetimes
+   |
+LL - fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
+LL + fn struct_with_lt(_foo: Foo<'_>) -> &str {
    |
-LL | fn struct_with_lt<'a>(_foo: Foo<'a>) -> &'a str {
-   |                                 ^^
 
 error: the following explicit lifetimes could be elided: 'b
-  --> $DIR/needless_lifetimes.rs:201:1
+  --> $DIR/needless_lifetimes.rs:208:1
    |
 LL | fn struct_with_lt4a<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: replace with `'_` in generic arguments such as here
-  --> $DIR/needless_lifetimes.rs:201:43
+help: elide the lifetimes
+   |
+LL - fn struct_with_lt4a<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str {
+LL + fn struct_with_lt4a<'a>(_foo: &'a Foo<'_>) -> &'a str {
    |
-LL | fn struct_with_lt4a<'a, 'b>(_foo: &'a Foo<'b>) -> &'a str {
-   |                                           ^^
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:209:1
+  --> $DIR/needless_lifetimes.rs:216:1
    |
 LL | fn struct_with_lt4b<'a, 'b>(_foo: &'a Foo<'b>) -> &'b str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL - fn struct_with_lt4b<'a, 'b>(_foo: &'a Foo<'b>) -> &'b str {
+LL + fn struct_with_lt4b<'b>(_foo: &Foo<'b>) -> &'b str {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:224:1
+  --> $DIR/needless_lifetimes.rs:231:1
    |
 LL | fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL - fn trait_obj_elided2<'a>(_arg: &'a dyn Drop) -> &'a str {
+LL + fn trait_obj_elided2(_arg: &dyn Drop) -> &str {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:230:1
+  --> $DIR/needless_lifetimes.rs:237:1
    |
 LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: replace with `'_` in generic arguments such as here
-  --> $DIR/needless_lifetimes.rs:230:37
+help: elide the lifetimes
+   |
+LL - fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
+LL + fn alias_with_lt(_foo: FooAlias<'_>) -> &str {
    |
-LL | fn alias_with_lt<'a>(_foo: FooAlias<'a>) -> &'a str {
-   |                                     ^^
 
 error: the following explicit lifetimes could be elided: 'b
-  --> $DIR/needless_lifetimes.rs:248:1
+  --> $DIR/needless_lifetimes.rs:255:1
    |
 LL | fn alias_with_lt4a<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: replace with `'_` in generic arguments such as here
-  --> $DIR/needless_lifetimes.rs:248:47
+help: elide the lifetimes
+   |
+LL - fn alias_with_lt4a<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str {
+LL + fn alias_with_lt4a<'a>(_foo: &'a FooAlias<'_>) -> &'a str {
    |
-LL | fn alias_with_lt4a<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'a str {
-   |                                               ^^
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:256:1
+  --> $DIR/needless_lifetimes.rs:263:1
    |
 LL | fn alias_with_lt4b<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'b str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL - fn alias_with_lt4b<'a, 'b>(_foo: &'a FooAlias<'b>) -> &'b str {
+LL + fn alias_with_lt4b<'b>(_foo: &FooAlias<'b>) -> &'b str {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:260:1
+  --> $DIR/needless_lifetimes.rs:267:1
    |
 LL | fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL - fn named_input_elided_output<'a>(_arg: &'a str) -> &str {
+LL + fn named_input_elided_output(_arg: &str) -> &str {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:268:1
+  --> $DIR/needless_lifetimes.rs:275:1
    |
 LL | fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL - fn trait_bound_ok<'a, T: WithLifetime<'static>>(_: &'a u8, _: T) {
+LL + fn trait_bound_ok<T: WithLifetime<'static>>(_: &u8, _: T) {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:304:1
+  --> $DIR/needless_lifetimes.rs:311:1
    |
 LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-help: replace with `'_` in generic arguments such as here
-  --> $DIR/needless_lifetimes.rs:304:47
+help: elide the lifetimes
+   |
+LL - fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
+LL + fn out_return_type_lts(e: &str) -> Cow<'_> {
    |
-LL | fn out_return_type_lts<'a>(e: &'a str) -> Cow<'a> {
-   |                                               ^^
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:311:9
+  --> $DIR/needless_lifetimes.rs:318:9
    |
 LL |         fn needless_lt<'a>(x: &'a u8) {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -         fn needless_lt<'a>(x: &'a u8) {}
+LL +         fn needless_lt(x: &u8) {}
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:315:9
+  --> $DIR/needless_lifetimes.rs:322:9
    |
 LL |         fn needless_lt<'a>(_x: &'a u8) {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -         fn needless_lt<'a>(_x: &'a u8) {}
+LL +         fn needless_lt(_x: &u8) {}
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:328:9
+  --> $DIR/needless_lifetimes.rs:335:9
    |
 LL |         fn baz<'a>(&'a self) -> impl Foo + 'a {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -         fn baz<'a>(&'a self) -> impl Foo + 'a {
+LL +         fn baz(&self) -> impl Foo + '_ {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:360:5
+  --> $DIR/needless_lifetimes.rs:367:5
    |
 LL |     fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -     fn impl_trait_elidable_nested_anonymous_lifetimes<'a>(i: &'a i32, f: impl Fn(&i32) -> &i32) -> &'a i32 {
+LL +     fn impl_trait_elidable_nested_anonymous_lifetimes(i: &i32, f: impl Fn(&i32) -> &i32) -> &i32 {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:369:5
+  --> $DIR/needless_lifetimes.rs:376:5
    |
 LL |     fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -     fn generics_elidable<'a, T: Fn(&i32) -> &i32>(i: &'a i32, f: T) -> &'a i32 {
+LL +     fn generics_elidable<T: Fn(&i32) -> &i32>(i: &i32, f: T) -> &i32 {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:381:5
+  --> $DIR/needless_lifetimes.rs:388:5
    |
 LL |     fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -     fn where_clause_elidadable<'a, T>(i: &'a i32, f: T) -> &'a i32
+LL +     fn where_clause_elidadable<T>(i: &i32, f: T) -> &i32
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:396:5
+  --> $DIR/needless_lifetimes.rs:403:5
    |
 LL |     fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -     fn pointer_fn_elidable<'a>(i: &'a i32, f: fn(&i32) -> &i32) -> &'a i32 {
+LL +     fn pointer_fn_elidable(i: &i32, f: fn(&i32) -> &i32) -> &i32 {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:409:5
+  --> $DIR/needless_lifetimes.rs:416:5
    |
 LL |     fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -     fn nested_fn_pointer_3<'a>(_: &'a i32) -> fn(fn(&i32) -> &i32) -> i32 {
+LL +     fn nested_fn_pointer_3(_: &i32) -> fn(fn(&i32) -> &i32) -> i32 {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:412:5
+  --> $DIR/needless_lifetimes.rs:419:5
    |
 LL |     fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -     fn nested_fn_pointer_4<'a>(_: &'a i32) -> impl Fn(fn(&i32)) {
+LL +     fn nested_fn_pointer_4(_: &i32) -> impl Fn(fn(&i32)) {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:434:9
+  --> $DIR/needless_lifetimes.rs:441:9
    |
 LL |         fn implicit<'a>(&'a self) -> &'a () {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -         fn implicit<'a>(&'a self) -> &'a () {
+LL +         fn implicit(&self) -> &() {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:437:9
+  --> $DIR/needless_lifetimes.rs:444:9
    |
 LL |         fn implicit_mut<'a>(&'a mut self) -> &'a () {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -         fn implicit_mut<'a>(&'a mut self) -> &'a () {
+LL +         fn implicit_mut(&mut self) -> &() {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:448:9
+  --> $DIR/needless_lifetimes.rs:455:9
    |
 LL |         fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -         fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
+LL +         fn lifetime_elsewhere(self: Box<Self>, here: &()) -> &() {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:454:9
+  --> $DIR/needless_lifetimes.rs:461:9
    |
 LL |         fn implicit<'a>(&'a self) -> &'a ();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -         fn implicit<'a>(&'a self) -> &'a ();
+LL +         fn implicit(&self) -> &();
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:455:9
+  --> $DIR/needless_lifetimes.rs:462:9
    |
 LL |         fn implicit_provided<'a>(&'a self) -> &'a () {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -         fn implicit_provided<'a>(&'a self) -> &'a () {
+LL +         fn implicit_provided(&self) -> &() {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:464:9
+  --> $DIR/needless_lifetimes.rs:471:9
    |
 LL |         fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a ();
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -         fn lifetime_elsewhere<'a>(self: Box<Self>, here: &'a ()) -> &'a ();
+LL +         fn lifetime_elsewhere(self: Box<Self>, here: &()) -> &();
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:465:9
+  --> $DIR/needless_lifetimes.rs:472:9
    |
 LL |         fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -         fn lifetime_elsewhere_provided<'a>(self: Box<Self>, here: &'a ()) -> &'a () {
+LL +         fn lifetime_elsewhere_provided(self: Box<Self>, here: &()) -> &() {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:474:5
+  --> $DIR/needless_lifetimes.rs:481:5
    |
 LL |     fn foo<'a>(x: &'a u8, y: &'_ u8) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -     fn foo<'a>(x: &'a u8, y: &'_ u8) {}
+LL +     fn foo(x: &u8, y: &'_ u8) {}
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:476:5
+  --> $DIR/needless_lifetimes.rs:483:5
    |
 LL |     fn bar<'a>(x: &'a u8, y: &'_ u8, z: &'_ u8) {}
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -     fn bar<'a>(x: &'a u8, y: &'_ u8, z: &'_ u8) {}
+LL +     fn bar(x: &u8, y: &'_ u8, z: &'_ u8) {}
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:483:5
+  --> $DIR/needless_lifetimes.rs:490:5
    |
 LL |     fn one_input<'a>(x: &'a u8) -> &'a u8 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -     fn one_input<'a>(x: &'a u8) -> &'a u8 {
+LL +     fn one_input(x: &u8) -> &u8 {
+   |
 
 error: the following explicit lifetimes could be elided: 'a
-  --> $DIR/needless_lifetimes.rs:488:5
+  --> $DIR/needless_lifetimes.rs:495:5
    |
 LL |     fn multiple_inputs_output_not_elided<'a, 'b>(x: &'a u8, y: &'b u8, z: &'b u8) -> &'b u8 {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: elide the lifetimes
+   |
+LL -     fn multiple_inputs_output_not_elided<'a, 'b>(x: &'a u8, y: &'b u8, z: &'b u8) -> &'b u8 {
+LL +     fn multiple_inputs_output_not_elided<'b>(x: &u8, y: &'b u8, z: &'b u8) -> &'b u8 {
+   |
+
+error: the following explicit lifetimes could be elided: 'a
+  --> $DIR/needless_lifetimes.rs:508:13
+   |
+LL |             fn one_input<'a>(x: &'a u8) -> &'a u8 {
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     local_one_input_macro!();
+   |     ------------------------ in this macro invocation
+   |
+   = note: this error originates in the macro `local_one_input_macro` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: elide the lifetimes
+   |
+LL -             fn one_input<'a>(x: &'a u8) -> &'a u8 {
+LL +             fn one_input(x: &u8) -> &u8 {
+   |
 
-error: aborting due to 45 previous errors
+error: aborting due to 46 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_range_loop.stderr b/src/tools/clippy/tests/ui/needless_range_loop.stderr
index b31544ec334..cffa19bec3a 100644
--- a/src/tools/clippy/tests/ui/needless_range_loop.stderr
+++ b/src/tools/clippy/tests/ui/needless_range_loop.stderr
@@ -49,7 +49,7 @@ error: the loop variable `i` is used to index `vec`
 LL |     for i in 0..vec.len() {
    |              ^^^^^^^^^^^^
    |
-help: consider using an iterator
+help: consider using an iterator and enumerate()
    |
 LL |     for (i, <item>) in vec.iter().enumerate() {
    |         ~~~~~~~~~~~    ~~~~~~~~~~~~~~~~~~~~~~
@@ -126,7 +126,7 @@ error: the loop variable `i` is used to index `vec`
 LL |     for i in 5..vec.len() {
    |              ^^^^^^^^^^^^
    |
-help: consider using an iterator
+help: consider using an iterator and enumerate()
    |
 LL |     for (i, <item>) in vec.iter().enumerate().skip(5) {
    |         ~~~~~~~~~~~    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -137,7 +137,7 @@ error: the loop variable `i` is used to index `vec`
 LL |     for i in 5..10 {
    |              ^^^^^
    |
-help: consider using an iterator
+help: consider using an iterator and enumerate()
    |
 LL |     for (i, <item>) in vec.iter().enumerate().take(10).skip(5) {
    |         ~~~~~~~~~~~    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -148,7 +148,7 @@ error: the loop variable `i` is used to index `vec`
 LL |     for i in 0..vec.len() {
    |              ^^^^^^^^^^^^
    |
-help: consider using an iterator
+help: consider using an iterator and enumerate()
    |
 LL |     for (i, <item>) in vec.iter_mut().enumerate() {
    |         ~~~~~~~~~~~    ~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/src/tools/clippy/tests/ui/new_without_default.rs b/src/tools/clippy/tests/ui/new_without_default.rs
index 65809023f8d..7803418cb04 100644
--- a/src/tools/clippy/tests/ui/new_without_default.rs
+++ b/src/tools/clippy/tests/ui/new_without_default.rs
@@ -1,4 +1,9 @@
-#![allow(dead_code, clippy::missing_safety_doc, clippy::extra_unused_lifetimes)]
+#![allow(
+    dead_code,
+    clippy::missing_safety_doc,
+    clippy::extra_unused_lifetimes,
+    clippy::extra_unused_type_parameters
+)]
 #![warn(clippy::new_without_default)]
 
 pub struct Foo;
diff --git a/src/tools/clippy/tests/ui/new_without_default.stderr b/src/tools/clippy/tests/ui/new_without_default.stderr
index 212a69ab94e..583dd327d6a 100644
--- a/src/tools/clippy/tests/ui/new_without_default.stderr
+++ b/src/tools/clippy/tests/ui/new_without_default.stderr
@@ -1,5 +1,5 @@
 error: you should consider adding a `Default` implementation for `Foo`
-  --> $DIR/new_without_default.rs:7:5
+  --> $DIR/new_without_default.rs:12:5
    |
 LL | /     pub fn new() -> Foo {
 LL | |         Foo
@@ -17,7 +17,7 @@ LL + }
    |
 
 error: you should consider adding a `Default` implementation for `Bar`
-  --> $DIR/new_without_default.rs:15:5
+  --> $DIR/new_without_default.rs:20:5
    |
 LL | /     pub fn new() -> Self {
 LL | |         Bar
@@ -34,7 +34,7 @@ LL + }
    |
 
 error: you should consider adding a `Default` implementation for `LtKo<'c>`
-  --> $DIR/new_without_default.rs:79:5
+  --> $DIR/new_without_default.rs:84:5
    |
 LL | /     pub fn new() -> LtKo<'c> {
 LL | |         unimplemented!()
@@ -51,7 +51,7 @@ LL + }
    |
 
 error: you should consider adding a `Default` implementation for `NewNotEqualToDerive`
-  --> $DIR/new_without_default.rs:172:5
+  --> $DIR/new_without_default.rs:177:5
    |
 LL | /     pub fn new() -> Self {
 LL | |         NewNotEqualToDerive { foo: 1 }
@@ -68,7 +68,7 @@ LL + }
    |
 
 error: you should consider adding a `Default` implementation for `FooGenerics<T>`
-  --> $DIR/new_without_default.rs:180:5
+  --> $DIR/new_without_default.rs:185:5
    |
 LL | /     pub fn new() -> Self {
 LL | |         Self(Default::default())
@@ -85,7 +85,7 @@ LL + }
    |
 
 error: you should consider adding a `Default` implementation for `BarGenerics<T>`
-  --> $DIR/new_without_default.rs:187:5
+  --> $DIR/new_without_default.rs:192:5
    |
 LL | /     pub fn new() -> Self {
 LL | |         Self(Default::default())
@@ -102,7 +102,7 @@ LL + }
    |
 
 error: you should consider adding a `Default` implementation for `Foo<T>`
-  --> $DIR/new_without_default.rs:198:9
+  --> $DIR/new_without_default.rs:203:9
    |
 LL | /         pub fn new() -> Self {
 LL | |             todo!()
diff --git a/src/tools/clippy/tests/ui/redundant_field_names.fixed b/src/tools/clippy/tests/ui/redundant_field_names.fixed
index ec7f8ae923a..276266a2dd8 100644
--- a/src/tools/clippy/tests/ui/redundant_field_names.fixed
+++ b/src/tools/clippy/tests/ui/redundant_field_names.fixed
@@ -1,7 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::redundant_field_names)]
-#![allow(clippy::no_effect, dead_code, unused_variables)]
+#![allow(clippy::extra_unused_type_parameters, clippy::no_effect, dead_code, unused_variables)]
 
 #[macro_use]
 extern crate derive_new;
diff --git a/src/tools/clippy/tests/ui/redundant_field_names.rs b/src/tools/clippy/tests/ui/redundant_field_names.rs
index 73122016cf6..f674141c138 100644
--- a/src/tools/clippy/tests/ui/redundant_field_names.rs
+++ b/src/tools/clippy/tests/ui/redundant_field_names.rs
@@ -1,7 +1,7 @@
 // run-rustfix
 
 #![warn(clippy::redundant_field_names)]
-#![allow(clippy::no_effect, dead_code, unused_variables)]
+#![allow(clippy::extra_unused_type_parameters, clippy::no_effect, dead_code, unused_variables)]
 
 #[macro_use]
 extern crate derive_new;
diff --git a/src/tools/clippy/tests/ui/regex.rs b/src/tools/clippy/tests/ui/regex.rs
index f0e1a8128d7..ab8ac97a0e7 100644
--- a/src/tools/clippy/tests/ui/regex.rs
+++ b/src/tools/clippy/tests/ui/regex.rs
@@ -36,6 +36,10 @@ fn syntax_error() {
 
     let raw_string_error = Regex::new(r"[...\/...]");
     let raw_string_error = Regex::new(r#"[...\/...]"#);
+
+    let escaped_string_span = Regex::new("\\b\\c");
+
+    let aux_span = Regex::new("(?ixi)");
 }
 
 fn trivial_regex() {
diff --git a/src/tools/clippy/tests/ui/regex.stderr b/src/tools/clippy/tests/ui/regex.stderr
index 2424644c6f6..c2440f39e0a 100644
--- a/src/tools/clippy/tests/ui/regex.stderr
+++ b/src/tools/clippy/tests/ui/regex.stderr
@@ -29,7 +29,10 @@ error: regex syntax error: invalid character class range, the start must be <= t
 LL |     let some_unicode = Regex::new("[é-è]");
    |                                     ^^^
 
-error: regex syntax error on position 0: unclosed group
+error: regex parse error:
+           (
+           ^
+       error: unclosed group
   --> $DIR/regex.rs:18:33
    |
 LL |     let some_regex = Regex::new(OPENING_PAREN);
@@ -43,25 +46,37 @@ LL |     let binary_pipe_in_wrong_position = BRegex::new("|");
    |
    = help: the regex is unlikely to be useful as it is
 
-error: regex syntax error on position 0: unclosed group
+error: regex parse error:
+           (
+           ^
+       error: unclosed group
   --> $DIR/regex.rs:21:41
    |
 LL |     let some_binary_regex = BRegex::new(OPENING_PAREN);
    |                                         ^^^^^^^^^^^^^
 
-error: regex syntax error on position 0: unclosed group
+error: regex parse error:
+           (
+           ^
+       error: unclosed group
   --> $DIR/regex.rs:22:56
    |
 LL |     let some_binary_regex_builder = BRegexBuilder::new(OPENING_PAREN);
    |                                                        ^^^^^^^^^^^^^
 
-error: regex syntax error on position 0: unclosed group
+error: regex parse error:
+           (
+           ^
+       error: unclosed group
   --> $DIR/regex.rs:34:37
    |
 LL |     let set_error = RegexSet::new(&[OPENING_PAREN, r"[a-z]+/.(com|org|net)"]);
    |                                     ^^^^^^^^^^^^^
 
-error: regex syntax error on position 0: unclosed group
+error: regex parse error:
+           (
+           ^
+       error: unclosed group
   --> $DIR/regex.rs:35:39
    |
 LL |     let bset_error = BRegexSet::new(&[OPENING_PAREN, r"[a-z]+/.(com|org|net)"]);
@@ -79,8 +94,25 @@ error: regex syntax error: unrecognized escape sequence
 LL |     let raw_string_error = Regex::new(r#"[...//...]"#);
    |                                              ^^
 
+error: regex parse error:
+           /b/c
+             ^^
+       error: unrecognized escape sequence
+  --> $DIR/regex.rs:40:42
+   |
+LL |     let escaped_string_span = Regex::new("/b/c");
+   |                                          ^^^^^^^^
+   |
+   = help: consider using a raw string literal: `r".."`
+
+error: regex syntax error: duplicate flag
+  --> $DIR/regex.rs:42:34
+   |
+LL |     let aux_span = Regex::new("(?ixi)");
+   |                                  ^ ^
+
 error: trivial regex
-  --> $DIR/regex.rs:42:33
+  --> $DIR/regex.rs:46:33
    |
 LL |     let trivial_eq = Regex::new("^foobar$");
    |                                 ^^^^^^^^^^
@@ -88,7 +120,7 @@ LL |     let trivial_eq = Regex::new("^foobar$");
    = help: consider using `==` on `str`s
 
 error: trivial regex
-  --> $DIR/regex.rs:44:48
+  --> $DIR/regex.rs:48:48
    |
 LL |     let trivial_eq_builder = RegexBuilder::new("^foobar$");
    |                                                ^^^^^^^^^^
@@ -96,7 +128,7 @@ LL |     let trivial_eq_builder = RegexBuilder::new("^foobar$");
    = help: consider using `==` on `str`s
 
 error: trivial regex
-  --> $DIR/regex.rs:46:42
+  --> $DIR/regex.rs:50:42
    |
 LL |     let trivial_starts_with = Regex::new("^foobar");
    |                                          ^^^^^^^^^
@@ -104,7 +136,7 @@ LL |     let trivial_starts_with = Regex::new("^foobar");
    = help: consider using `str::starts_with`
 
 error: trivial regex
-  --> $DIR/regex.rs:48:40
+  --> $DIR/regex.rs:52:40
    |
 LL |     let trivial_ends_with = Regex::new("foobar$");
    |                                        ^^^^^^^^^
@@ -112,7 +144,7 @@ LL |     let trivial_ends_with = Regex::new("foobar$");
    = help: consider using `str::ends_with`
 
 error: trivial regex
-  --> $DIR/regex.rs:50:39
+  --> $DIR/regex.rs:54:39
    |
 LL |     let trivial_contains = Regex::new("foobar");
    |                                       ^^^^^^^^
@@ -120,7 +152,7 @@ LL |     let trivial_contains = Regex::new("foobar");
    = help: consider using `str::contains`
 
 error: trivial regex
-  --> $DIR/regex.rs:52:39
+  --> $DIR/regex.rs:56:39
    |
 LL |     let trivial_contains = Regex::new(NOT_A_REAL_REGEX);
    |                                       ^^^^^^^^^^^^^^^^
@@ -128,7 +160,7 @@ LL |     let trivial_contains = Regex::new(NOT_A_REAL_REGEX);
    = help: consider using `str::contains`
 
 error: trivial regex
-  --> $DIR/regex.rs:54:40
+  --> $DIR/regex.rs:58:40
    |
 LL |     let trivial_backslash = Regex::new("a/.b");
    |                                        ^^^^^^^
@@ -136,7 +168,7 @@ LL |     let trivial_backslash = Regex::new("a/.b");
    = help: consider using `str::contains`
 
 error: trivial regex
-  --> $DIR/regex.rs:57:36
+  --> $DIR/regex.rs:61:36
    |
 LL |     let trivial_empty = Regex::new("");
    |                                    ^^
@@ -144,7 +176,7 @@ LL |     let trivial_empty = Regex::new("");
    = help: the regex is unlikely to be useful as it is
 
 error: trivial regex
-  --> $DIR/regex.rs:59:36
+  --> $DIR/regex.rs:63:36
    |
 LL |     let trivial_empty = Regex::new("^");
    |                                    ^^^
@@ -152,7 +184,7 @@ LL |     let trivial_empty = Regex::new("^");
    = help: the regex is unlikely to be useful as it is
 
 error: trivial regex
-  --> $DIR/regex.rs:61:36
+  --> $DIR/regex.rs:65:36
    |
 LL |     let trivial_empty = Regex::new("^$");
    |                                    ^^^^
@@ -160,12 +192,12 @@ LL |     let trivial_empty = Regex::new("^$");
    = help: consider using `str::is_empty`
 
 error: trivial regex
-  --> $DIR/regex.rs:63:44
+  --> $DIR/regex.rs:67:44
    |
 LL |     let binary_trivial_empty = BRegex::new("^$");
    |                                            ^^^^
    |
    = help: consider using `str::is_empty`
 
-error: aborting due to 23 previous errors
+error: aborting due to 25 previous errors
 
diff --git a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed
index 713cff604a1..dc24d447c60 100644
--- a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed
+++ b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed
@@ -26,7 +26,7 @@ fn seek_to_start_false_method(t: &mut StructWithSeekMethod) {
 
 // This should NOT trigger clippy warning because
 // StructWithSeekMethod does not implement std::io::Seek;
-fn seek_to_start_method_owned_false<T>(mut t: StructWithSeekMethod) {
+fn seek_to_start_method_owned_false(mut t: StructWithSeekMethod) {
     t.seek(SeekFrom::Start(0));
 }
 
@@ -38,7 +38,7 @@ fn seek_to_start_false_trait(t: &mut StructWithSeekTrait) {
 
 // This should NOT trigger clippy warning because
 // StructWithSeekMethod does not implement std::io::Seek;
-fn seek_to_start_false_trait_owned<T>(mut t: StructWithSeekTrait) {
+fn seek_to_start_false_trait_owned(mut t: StructWithSeekTrait) {
     t.seek(SeekFrom::Start(0));
 }
 
diff --git a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs
index 467003a1a66..4adde2c4018 100644
--- a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs
+++ b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs
@@ -26,7 +26,7 @@ fn seek_to_start_false_method(t: &mut StructWithSeekMethod) {
 
 // This should NOT trigger clippy warning because
 // StructWithSeekMethod does not implement std::io::Seek;
-fn seek_to_start_method_owned_false<T>(mut t: StructWithSeekMethod) {
+fn seek_to_start_method_owned_false(mut t: StructWithSeekMethod) {
     t.seek(SeekFrom::Start(0));
 }
 
@@ -38,7 +38,7 @@ fn seek_to_start_false_trait(t: &mut StructWithSeekTrait) {
 
 // This should NOT trigger clippy warning because
 // StructWithSeekMethod does not implement std::io::Seek;
-fn seek_to_start_false_trait_owned<T>(mut t: StructWithSeekTrait) {
+fn seek_to_start_false_trait_owned(mut t: StructWithSeekTrait) {
     t.seek(SeekFrom::Start(0));
 }
 
diff --git a/src/tools/clippy/tests/ui/suspicious_to_owned.stderr b/src/tools/clippy/tests/ui/suspicious_to_owned.stderr
index dec3f50d6f1..c4ec7aa88a2 100644
--- a/src/tools/clippy/tests/ui/suspicious_to_owned.stderr
+++ b/src/tools/clippy/tests/ui/suspicious_to_owned.stderr
@@ -2,27 +2,62 @@ error: this `to_owned` call clones the Cow<'_, str> itself and does not cause th
   --> $DIR/suspicious_to_owned.rs:16:13
    |
 LL |     let _ = cow.to_owned();
-   |             ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
+   |             ^^^^^^^^^^^^^^
    |
    = note: `-D clippy::suspicious-to-owned` implied by `-D warnings`
+help: depending on intent, either make the Cow an Owned variant
+   |
+LL |     let _ = cow.into_owned();
+   |             ~~~~~~~~~~~~~~~~
+help: or clone the Cow itself
+   |
+LL |     let _ = cow.clone();
+   |             ~~~~~~~~~~~
 
 error: this `to_owned` call clones the Cow<'_, [char; 3]> itself and does not cause the Cow<'_, [char; 3]> contents to become owned
   --> $DIR/suspicious_to_owned.rs:26:13
    |
 LL |     let _ = cow.to_owned();
-   |             ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
+   |             ^^^^^^^^^^^^^^
+   |
+help: depending on intent, either make the Cow an Owned variant
+   |
+LL |     let _ = cow.into_owned();
+   |             ~~~~~~~~~~~~~~~~
+help: or clone the Cow itself
+   |
+LL |     let _ = cow.clone();
+   |             ~~~~~~~~~~~
 
 error: this `to_owned` call clones the Cow<'_, Vec<char>> itself and does not cause the Cow<'_, Vec<char>> contents to become owned
   --> $DIR/suspicious_to_owned.rs:36:13
    |
 LL |     let _ = cow.to_owned();
-   |             ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
+   |             ^^^^^^^^^^^^^^
+   |
+help: depending on intent, either make the Cow an Owned variant
+   |
+LL |     let _ = cow.into_owned();
+   |             ~~~~~~~~~~~~~~~~
+help: or clone the Cow itself
+   |
+LL |     let _ = cow.clone();
+   |             ~~~~~~~~~~~
 
 error: this `to_owned` call clones the Cow<'_, str> itself and does not cause the Cow<'_, str> contents to become owned
   --> $DIR/suspicious_to_owned.rs:46:13
    |
 LL |     let _ = cow.to_owned();
-   |             ^^^^^^^^^^^^^^ help: consider using, depending on intent: `cow.clone()` or `cow.into_owned()`
+   |             ^^^^^^^^^^^^^^
+   |
+help: depending on intent, either make the Cow an Owned variant
+   |
+LL |     let _ = cow.into_owned();
+   |             ~~~~~~~~~~~~~~~~
+help: or clone the Cow itself
+   |
+LL |     let _ = cow.clone();
+   |             ~~~~~~~~~~~
 
 error: implicitly cloning a `String` by calling `to_owned` on its dereferenced type
   --> $DIR/suspicious_to_owned.rs:60:13
diff --git a/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs b/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs
index 2eca1f4701c..8b4613b3f6e 100644
--- a/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs
+++ b/src/tools/clippy/tests/ui/type_repetition_in_bounds.rs
@@ -1,4 +1,5 @@
 #![deny(clippy::type_repetition_in_bounds)]
+#![allow(clippy::extra_unused_type_parameters)]
 
 use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
 
diff --git a/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr b/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr
index 70d700c1cc4..a90df03c04f 100644
--- a/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr
+++ b/src/tools/clippy/tests/ui/type_repetition_in_bounds.stderr
@@ -1,5 +1,5 @@
 error: this type has already been used as a bound predicate
-  --> $DIR/type_repetition_in_bounds.rs:8:5
+  --> $DIR/type_repetition_in_bounds.rs:9:5
    |
 LL |     T: Clone,
    |     ^^^^^^^^
@@ -12,7 +12,7 @@ LL | #![deny(clippy::type_repetition_in_bounds)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: this type has already been used as a bound predicate
-  --> $DIR/type_repetition_in_bounds.rs:25:5
+  --> $DIR/type_repetition_in_bounds.rs:26:5
    |
 LL |     Self: Copy + Default + Ord,
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -20,7 +20,7 @@ LL |     Self: Copy + Default + Ord,
    = help: consider combining the bounds: `Self: Clone + Copy + Default + Ord`
 
 error: this type has already been used as a bound predicate
-  --> $DIR/type_repetition_in_bounds.rs:85:5
+  --> $DIR/type_repetition_in_bounds.rs:86:5
    |
 LL |     T: Clone,
    |     ^^^^^^^^
@@ -28,7 +28,7 @@ LL |     T: Clone,
    = help: consider combining the bounds: `T: ?Sized + Clone`
 
 error: this type has already been used as a bound predicate
-  --> $DIR/type_repetition_in_bounds.rs:90:5
+  --> $DIR/type_repetition_in_bounds.rs:91:5
    |
 LL |     T: ?Sized,
    |     ^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/unused_io_amount.rs b/src/tools/clippy/tests/ui/unused_io_amount.rs
index 4b059558173..8d3e094b759 100644
--- a/src/tools/clippy/tests/ui/unused_io_amount.rs
+++ b/src/tools/clippy/tests/ui/unused_io_amount.rs
@@ -63,6 +63,14 @@ fn combine_or(file: &str) -> Result<(), Error> {
     Ok(())
 }
 
+fn is_ok_err<T: io::Read + io::Write>(s: &mut T) {
+    s.write(b"ok").is_ok();
+    s.write(b"err").is_err();
+    let mut buf = [0u8; 0];
+    s.read(&mut buf).is_ok();
+    s.read(&mut buf).is_err();
+}
+
 async fn bad_async_write<W: AsyncWrite + Unpin>(w: &mut W) {
     w.write(b"hello world").await.unwrap();
 }
diff --git a/src/tools/clippy/tests/ui/unused_io_amount.stderr b/src/tools/clippy/tests/ui/unused_io_amount.stderr
index 7ba7e09c0f0..0865c5213f6 100644
--- a/src/tools/clippy/tests/ui/unused_io_amount.stderr
+++ b/src/tools/clippy/tests/ui/unused_io_amount.stderr
@@ -82,13 +82,45 @@ LL | |         .expect("error");
 error: written amount is not handled
   --> $DIR/unused_io_amount.rs:67:5
    |
+LL |     s.write(b"ok").is_ok();
+   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `Write::write_all` instead, or handle partial writes
+
+error: written amount is not handled
+  --> $DIR/unused_io_amount.rs:68:5
+   |
+LL |     s.write(b"err").is_err();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `Write::write_all` instead, or handle partial writes
+
+error: read amount is not handled
+  --> $DIR/unused_io_amount.rs:70:5
+   |
+LL |     s.read(&mut buf).is_ok();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `Read::read_exact` instead, or handle partial reads
+
+error: read amount is not handled
+  --> $DIR/unused_io_amount.rs:71:5
+   |
+LL |     s.read(&mut buf).is_err();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: use `Read::read_exact` instead, or handle partial reads
+
+error: written amount is not handled
+  --> $DIR/unused_io_amount.rs:75:5
+   |
 LL |     w.write(b"hello world").await.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: use `AsyncWriteExt::write_all` instead, or handle partial writes
 
 error: read amount is not handled
-  --> $DIR/unused_io_amount.rs:72:5
+  --> $DIR/unused_io_amount.rs:80:5
    |
 LL |     r.read(&mut buf[..]).await.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -96,7 +128,7 @@ LL |     r.read(&mut buf[..]).await.unwrap();
    = help: use `AsyncReadExt::read_exact` instead, or handle partial reads
 
 error: written amount is not handled
-  --> $DIR/unused_io_amount.rs:85:9
+  --> $DIR/unused_io_amount.rs:93:9
    |
 LL |         w.write(b"hello world").await?;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -104,7 +136,7 @@ LL |         w.write(b"hello world").await?;
    = help: use `AsyncWriteExt::write_all` instead, or handle partial writes
 
 error: read amount is not handled
-  --> $DIR/unused_io_amount.rs:93:9
+  --> $DIR/unused_io_amount.rs:101:9
    |
 LL |         r.read(&mut buf[..]).await.or(Err(Error::Kind))?;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -112,7 +144,7 @@ LL |         r.read(&mut buf[..]).await.or(Err(Error::Kind))?;
    = help: use `AsyncReadExt::read_exact` instead, or handle partial reads
 
 error: written amount is not handled
-  --> $DIR/unused_io_amount.rs:101:5
+  --> $DIR/unused_io_amount.rs:109:5
    |
 LL |     w.write(b"hello world").await.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -120,12 +152,12 @@ LL |     w.write(b"hello world").await.unwrap();
    = help: use `AsyncWriteExt::write_all` instead, or handle partial writes
 
 error: read amount is not handled
-  --> $DIR/unused_io_amount.rs:106:5
+  --> $DIR/unused_io_amount.rs:114:5
    |
 LL |     r.read(&mut buf[..]).await.unwrap();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: use `AsyncReadExt::read_exact` instead, or handle partial reads
 
-error: aborting due to 16 previous errors
+error: aborting due to 20 previous errors
 
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
index 23607497841..293bf75a717 100644
--- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed
@@ -96,7 +96,7 @@ fn main() {
         }
         match Enum::A {
             Enum::A => (),
-            Enum::B | _ => (),
+            Enum::B | Enum::__Private => (),
         }
     }
 }
diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
index efecc9576cc..30d29aa4e77 100644
--- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.stderr
@@ -34,11 +34,11 @@ error: wildcard matches known variants and will also match future added variants
 LL |         _ => {},
    |         ^ help: try this: `ErrorKind::PermissionDenied | _`
 
-error: wildcard matches known variants and will also match future added variants
+error: wildcard match will also match any future added variants
   --> $DIR/wildcard_enum_match_arm.rs:99:13
    |
 LL |             _ => (),
-   |             ^ help: try this: `Enum::B | _`
+   |             ^ help: try this: `Enum::B | Enum::__Private`
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/codegen/issue-75659.rs b/tests/codegen/issue-75659.rs
index 6bcb59affe3..9394868c08d 100644
--- a/tests/codegen/issue-75659.rs
+++ b/tests/codegen/issue-75659.rs
@@ -1,7 +1,7 @@
 // This test checks that the call to memchr/slice_contains is optimized away
 // when searching in small slices.
 
-// compile-flags: -O -Zinline-mir=no
+// compile-flags: -O -Zinline-mir=false
 // only-x86_64
 
 #![crate_type = "lib"]
diff --git a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff
new file mode 100644
index 00000000000..b139deeee1f
--- /dev/null
+++ b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.32bit.diff
@@ -0,0 +1,68 @@
+- // MIR for `cand` before EnumSizeOpt
++ // MIR for `cand` after EnumSizeOpt
+  
+  fn cand() -> Candidate {
+      let mut _0: Candidate;               // return place in scope 0 at $DIR/enum_opt.rs:+0:18: +0:27
+      let mut _1: Candidate;               // in scope 0 at $DIR/enum_opt.rs:+1:7: +1:12
+      let mut _2: Candidate;               // in scope 0 at $DIR/enum_opt.rs:+2:7: +2:34
+      let mut _3: [u8; 8196];              // in scope 0 at $DIR/enum_opt.rs:+2:24: +2:33
++     let mut _4: [usize; 2];              // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
++     let mut _5: isize;                   // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
++     let mut _6: usize;                   // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
++     let mut _7: usize;                   // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
++     let mut _8: *mut Candidate;          // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
++     let mut _9: *mut u8;                 // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
++     let mut _10: *const Candidate;       // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
++     let mut _11: *const u8;              // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
++     let mut _12: [usize; 2];             // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _13: isize;                  // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _14: usize;                  // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _15: usize;                  // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _16: *mut Candidate;         // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _17: *mut u8;                // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _18: *const Candidate;       // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _19: *const u8;              // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/enum_opt.rs:+1:7: +1:12
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/enum_opt.rs:+1:7: +1:12
+          _1 = Candidate::Small(const 1_u8); // scope 0 at $DIR/enum_opt.rs:+1:15: +1:34
+          StorageLive(_2);                 // scope 1 at $DIR/enum_opt.rs:+2:7: +2:34
+          StorageLive(_3);                 // scope 1 at $DIR/enum_opt.rs:+2:24: +2:33
+          _3 = [const 1_u8; 8196];         // scope 1 at $DIR/enum_opt.rs:+2:24: +2:33
+          _2 = Candidate::Large(move _3);  // scope 1 at $DIR/enum_opt.rs:+2:7: +2:34
+          StorageDead(_3);                 // scope 1 at $DIR/enum_opt.rs:+2:33: +2:34
+-         _1 = move _2;                    // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         StorageLive(_4);                 // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         _4 = const [2_usize, 8197_usize]; // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         _5 = discriminant(_2);           // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         _6 = _5 as usize (IntToInt);     // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         _7 = _4[_6];                     // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         _8 = &raw mut _1;                // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         _9 = _8 as *mut u8 (PtrToPtr);   // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         _10 = &raw const _2;             // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         _11 = _10 as *const u8 (PtrToPtr); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         Deinit(_8);                      // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         copy_nonoverlapping(dst = _9, src = _11, count = _7); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         StorageDead(_4);                 // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+          StorageDead(_2);                 // scope 1 at $DIR/enum_opt.rs:+2:33: +2:34
+-         _0 = move _1;                    // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         StorageLive(_12);                // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _12 = const [2_usize, 8197_usize]; // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _13 = discriminant(_1);          // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _14 = _13 as usize (IntToInt);   // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _15 = _12[_14];                  // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _16 = &raw mut _0;               // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _17 = _16 as *mut u8 (PtrToPtr); // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _18 = &raw const _1;             // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _19 = _18 as *const u8 (PtrToPtr); // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         Deinit(_16);                     // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         copy_nonoverlapping(dst = _17, src = _19, count = _15); // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         StorageDead(_12);                // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
+          StorageDead(_1);                 // scope 0 at $DIR/enum_opt.rs:+4:1: +4:2
+          return;                          // scope 0 at $DIR/enum_opt.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff
new file mode 100644
index 00000000000..b139deeee1f
--- /dev/null
+++ b/tests/mir-opt/enum_opt.cand.EnumSizeOpt.64bit.diff
@@ -0,0 +1,68 @@
+- // MIR for `cand` before EnumSizeOpt
++ // MIR for `cand` after EnumSizeOpt
+  
+  fn cand() -> Candidate {
+      let mut _0: Candidate;               // return place in scope 0 at $DIR/enum_opt.rs:+0:18: +0:27
+      let mut _1: Candidate;               // in scope 0 at $DIR/enum_opt.rs:+1:7: +1:12
+      let mut _2: Candidate;               // in scope 0 at $DIR/enum_opt.rs:+2:7: +2:34
+      let mut _3: [u8; 8196];              // in scope 0 at $DIR/enum_opt.rs:+2:24: +2:33
++     let mut _4: [usize; 2];              // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
++     let mut _5: isize;                   // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
++     let mut _6: usize;                   // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
++     let mut _7: usize;                   // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
++     let mut _8: *mut Candidate;          // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
++     let mut _9: *mut u8;                 // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
++     let mut _10: *const Candidate;       // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
++     let mut _11: *const u8;              // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:34
++     let mut _12: [usize; 2];             // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _13: isize;                  // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _14: usize;                  // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _15: usize;                  // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _16: *mut Candidate;         // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _17: *mut u8;                // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _18: *const Candidate;       // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _19: *const u8;              // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/enum_opt.rs:+1:7: +1:12
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/enum_opt.rs:+1:7: +1:12
+          _1 = Candidate::Small(const 1_u8); // scope 0 at $DIR/enum_opt.rs:+1:15: +1:34
+          StorageLive(_2);                 // scope 1 at $DIR/enum_opt.rs:+2:7: +2:34
+          StorageLive(_3);                 // scope 1 at $DIR/enum_opt.rs:+2:24: +2:33
+          _3 = [const 1_u8; 8196];         // scope 1 at $DIR/enum_opt.rs:+2:24: +2:33
+          _2 = Candidate::Large(move _3);  // scope 1 at $DIR/enum_opt.rs:+2:7: +2:34
+          StorageDead(_3);                 // scope 1 at $DIR/enum_opt.rs:+2:33: +2:34
+-         _1 = move _2;                    // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         StorageLive(_4);                 // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         _4 = const [2_usize, 8197_usize]; // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         _5 = discriminant(_2);           // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         _6 = _5 as usize (IntToInt);     // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         _7 = _4[_6];                     // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         _8 = &raw mut _1;                // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         _9 = _8 as *mut u8 (PtrToPtr);   // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         _10 = &raw const _2;             // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         _11 = _10 as *const u8 (PtrToPtr); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         Deinit(_8);                      // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         copy_nonoverlapping(dst = _9, src = _11, count = _7); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
++         StorageDead(_4);                 // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+          StorageDead(_2);                 // scope 1 at $DIR/enum_opt.rs:+2:33: +2:34
+-         _0 = move _1;                    // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         StorageLive(_12);                // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _12 = const [2_usize, 8197_usize]; // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _13 = discriminant(_1);          // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _14 = _13 as usize (IntToInt);   // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _15 = _12[_14];                  // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _16 = &raw mut _0;               // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _17 = _16 as *mut u8 (PtrToPtr); // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _18 = &raw const _1;             // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _19 = _18 as *const u8 (PtrToPtr); // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         Deinit(_16);                     // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         copy_nonoverlapping(dst = _17, src = _19, count = _15); // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         StorageDead(_12);                // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
+          StorageDead(_1);                 // scope 0 at $DIR/enum_opt.rs:+4:1: +4:2
+          return;                          // scope 0 at $DIR/enum_opt.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/tests/mir-opt/enum_opt.invalid.EnumSizeOpt.32bit.diff b/tests/mir-opt/enum_opt.invalid.EnumSizeOpt.32bit.diff
new file mode 100644
index 00000000000..a80001149eb
--- /dev/null
+++ b/tests/mir-opt/enum_opt.invalid.EnumSizeOpt.32bit.diff
@@ -0,0 +1,28 @@
+- // MIR for `invalid` before EnumSizeOpt
++ // MIR for `invalid` after EnumSizeOpt
+  
+  fn invalid() -> InvalidIdxs {
+      let mut _0: InvalidIdxs;             // return place in scope 0 at $DIR/enum_opt.rs:+0:21: +0:32
+      let mut _1: InvalidIdxs;             // in scope 0 at $DIR/enum_opt.rs:+1:7: +1:12
+      let mut _2: InvalidIdxs;             // in scope 0 at $DIR/enum_opt.rs:+2:7: +2:36
+      let mut _3: [u64; 1024];             // in scope 0 at $DIR/enum_opt.rs:+2:26: +2:35
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/enum_opt.rs:+1:7: +1:12
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/enum_opt.rs:+1:7: +1:12
+          _1 = InvalidIdxs::A;             // scope 0 at $DIR/enum_opt.rs:+1:15: +1:29
+          StorageLive(_2);                 // scope 1 at $DIR/enum_opt.rs:+2:7: +2:36
+          StorageLive(_3);                 // scope 1 at $DIR/enum_opt.rs:+2:26: +2:35
+          _3 = [const 0_u64; 1024];        // scope 1 at $DIR/enum_opt.rs:+2:26: +2:35
+          _2 = InvalidIdxs::Large(move _3); // scope 1 at $DIR/enum_opt.rs:+2:7: +2:36
+          StorageDead(_3);                 // scope 1 at $DIR/enum_opt.rs:+2:35: +2:36
+          _1 = move _2;                    // scope 1 at $DIR/enum_opt.rs:+2:3: +2:36
+          StorageDead(_2);                 // scope 1 at $DIR/enum_opt.rs:+2:35: +2:36
+          _0 = move _1;                    // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
+          StorageDead(_1);                 // scope 0 at $DIR/enum_opt.rs:+4:1: +4:2
+          return;                          // scope 0 at $DIR/enum_opt.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/tests/mir-opt/enum_opt.invalid.EnumSizeOpt.64bit.diff b/tests/mir-opt/enum_opt.invalid.EnumSizeOpt.64bit.diff
new file mode 100644
index 00000000000..a80001149eb
--- /dev/null
+++ b/tests/mir-opt/enum_opt.invalid.EnumSizeOpt.64bit.diff
@@ -0,0 +1,28 @@
+- // MIR for `invalid` before EnumSizeOpt
++ // MIR for `invalid` after EnumSizeOpt
+  
+  fn invalid() -> InvalidIdxs {
+      let mut _0: InvalidIdxs;             // return place in scope 0 at $DIR/enum_opt.rs:+0:21: +0:32
+      let mut _1: InvalidIdxs;             // in scope 0 at $DIR/enum_opt.rs:+1:7: +1:12
+      let mut _2: InvalidIdxs;             // in scope 0 at $DIR/enum_opt.rs:+2:7: +2:36
+      let mut _3: [u64; 1024];             // in scope 0 at $DIR/enum_opt.rs:+2:26: +2:35
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/enum_opt.rs:+1:7: +1:12
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/enum_opt.rs:+1:7: +1:12
+          _1 = InvalidIdxs::A;             // scope 0 at $DIR/enum_opt.rs:+1:15: +1:29
+          StorageLive(_2);                 // scope 1 at $DIR/enum_opt.rs:+2:7: +2:36
+          StorageLive(_3);                 // scope 1 at $DIR/enum_opt.rs:+2:26: +2:35
+          _3 = [const 0_u64; 1024];        // scope 1 at $DIR/enum_opt.rs:+2:26: +2:35
+          _2 = InvalidIdxs::Large(move _3); // scope 1 at $DIR/enum_opt.rs:+2:7: +2:36
+          StorageDead(_3);                 // scope 1 at $DIR/enum_opt.rs:+2:35: +2:36
+          _1 = move _2;                    // scope 1 at $DIR/enum_opt.rs:+2:3: +2:36
+          StorageDead(_2);                 // scope 1 at $DIR/enum_opt.rs:+2:35: +2:36
+          _0 = move _1;                    // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
+          StorageDead(_1);                 // scope 0 at $DIR/enum_opt.rs:+4:1: +4:2
+          return;                          // scope 0 at $DIR/enum_opt.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/tests/mir-opt/enum_opt.rs b/tests/mir-opt/enum_opt.rs
new file mode 100644
index 00000000000..2768d708049
--- /dev/null
+++ b/tests/mir-opt/enum_opt.rs
@@ -0,0 +1,86 @@
+// unit-test: EnumSizeOpt
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+// compile-flags: -Zunsound-mir-opts
+
+#![feature(arbitrary_enum_discriminant, repr128)]
+
+// Tests that an enum with a variant with no data gets correctly transformed.
+pub enum NoData {
+  Large([u8; 8196]),
+  None,
+}
+
+// Tests that an enum with a variant with data that is a valid candidate gets transformed.
+pub enum Candidate {
+  Small(u8),
+  Large([u8; 8196]),
+}
+
+// Tests that an enum which has a discriminant much higher than the variant does not get
+// tformed.
+#[repr(u32)]
+pub enum InvalidIdxs {
+  A = 302,
+  Large([u64; 1024]),
+}
+
+// Tests that an enum with too high of a discriminant index (not in bounds of usize) does not
+// get tformed.
+#[repr(u128)]
+pub enum NotTrunctable {
+    A = 0,
+    B([u8; 1024]) = 1,
+    C([u8; 4096]) = 0x10000000000000001,
+}
+
+// Tests that an enum with discriminants in random order still gets tformed correctly.
+#[repr(u32)]
+pub enum RandOrderDiscr {
+  A = 13,
+  B([u8; 1024]) = 5,
+  C = 7,
+}
+
+// EMIT_MIR enum_opt.unin.EnumSizeOpt.diff
+pub fn unin() -> NoData {
+  let mut a = NoData::None;
+  a = NoData::Large([1; 8196]);
+  a
+}
+
+// EMIT_MIR enum_opt.cand.EnumSizeOpt.diff
+pub fn cand() -> Candidate {
+  let mut a = Candidate::Small(1);
+  a = Candidate::Large([1; 8196]);
+  a
+}
+
+// EMIT_MIR enum_opt.invalid.EnumSizeOpt.diff
+pub fn invalid() -> InvalidIdxs {
+  let mut a = InvalidIdxs::A;
+  a = InvalidIdxs::Large([0; 1024]);
+  a
+}
+
+// EMIT_MIR enum_opt.trunc.EnumSizeOpt.diff
+pub fn trunc() -> NotTrunctable {
+  let mut a = NotTrunctable::A;
+  a = NotTrunctable::B([0; 1024]);
+  a = NotTrunctable::C([0; 4096]);
+  a
+}
+
+pub fn rand_order() -> RandOrderDiscr {
+  let mut a = RandOrderDiscr::A;
+  a = RandOrderDiscr::B([0; 1024]);
+  a = RandOrderDiscr::C;
+  a
+}
+
+pub fn main() {
+  unin();
+  cand();
+  invalid();
+  trunc();
+  rand_order();
+}
diff --git a/tests/mir-opt/enum_opt.trunc.EnumSizeOpt.32bit.diff b/tests/mir-opt/enum_opt.trunc.EnumSizeOpt.32bit.diff
new file mode 100644
index 00000000000..1ef79044d4f
--- /dev/null
+++ b/tests/mir-opt/enum_opt.trunc.EnumSizeOpt.32bit.diff
@@ -0,0 +1,37 @@
+- // MIR for `trunc` before EnumSizeOpt
++ // MIR for `trunc` after EnumSizeOpt
+  
+  fn trunc() -> NotTrunctable {
+      let mut _0: NotTrunctable;           // return place in scope 0 at $DIR/enum_opt.rs:+0:19: +0:32
+      let mut _1: NotTrunctable;           // in scope 0 at $DIR/enum_opt.rs:+1:7: +1:12
+      let mut _2: NotTrunctable;           // in scope 0 at $DIR/enum_opt.rs:+2:7: +2:34
+      let mut _3: [u8; 1024];              // in scope 0 at $DIR/enum_opt.rs:+2:24: +2:33
+      let mut _4: NotTrunctable;           // in scope 0 at $DIR/enum_opt.rs:+3:7: +3:34
+      let mut _5: [u8; 4096];              // in scope 0 at $DIR/enum_opt.rs:+3:24: +3:33
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/enum_opt.rs:+1:7: +1:12
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/enum_opt.rs:+1:7: +1:12
+          _1 = NotTrunctable::A;           // scope 0 at $DIR/enum_opt.rs:+1:15: +1:31
+          StorageLive(_2);                 // scope 1 at $DIR/enum_opt.rs:+2:7: +2:34
+          StorageLive(_3);                 // scope 1 at $DIR/enum_opt.rs:+2:24: +2:33
+          _3 = [const 0_u8; 1024];         // scope 1 at $DIR/enum_opt.rs:+2:24: +2:33
+          _2 = NotTrunctable::B(move _3);  // scope 1 at $DIR/enum_opt.rs:+2:7: +2:34
+          StorageDead(_3);                 // scope 1 at $DIR/enum_opt.rs:+2:33: +2:34
+          _1 = move _2;                    // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+          StorageDead(_2);                 // scope 1 at $DIR/enum_opt.rs:+2:33: +2:34
+          StorageLive(_4);                 // scope 1 at $DIR/enum_opt.rs:+3:7: +3:34
+          StorageLive(_5);                 // scope 1 at $DIR/enum_opt.rs:+3:24: +3:33
+          _5 = [const 0_u8; 4096];         // scope 1 at $DIR/enum_opt.rs:+3:24: +3:33
+          _4 = NotTrunctable::C(move _5);  // scope 1 at $DIR/enum_opt.rs:+3:7: +3:34
+          StorageDead(_5);                 // scope 1 at $DIR/enum_opt.rs:+3:33: +3:34
+          _1 = move _4;                    // scope 1 at $DIR/enum_opt.rs:+3:3: +3:34
+          StorageDead(_4);                 // scope 1 at $DIR/enum_opt.rs:+3:33: +3:34
+          _0 = move _1;                    // scope 1 at $DIR/enum_opt.rs:+4:3: +4:4
+          StorageDead(_1);                 // scope 0 at $DIR/enum_opt.rs:+5:1: +5:2
+          return;                          // scope 0 at $DIR/enum_opt.rs:+5:2: +5:2
+      }
+  }
+  
diff --git a/tests/mir-opt/enum_opt.trunc.EnumSizeOpt.64bit.diff b/tests/mir-opt/enum_opt.trunc.EnumSizeOpt.64bit.diff
new file mode 100644
index 00000000000..1ef79044d4f
--- /dev/null
+++ b/tests/mir-opt/enum_opt.trunc.EnumSizeOpt.64bit.diff
@@ -0,0 +1,37 @@
+- // MIR for `trunc` before EnumSizeOpt
++ // MIR for `trunc` after EnumSizeOpt
+  
+  fn trunc() -> NotTrunctable {
+      let mut _0: NotTrunctable;           // return place in scope 0 at $DIR/enum_opt.rs:+0:19: +0:32
+      let mut _1: NotTrunctable;           // in scope 0 at $DIR/enum_opt.rs:+1:7: +1:12
+      let mut _2: NotTrunctable;           // in scope 0 at $DIR/enum_opt.rs:+2:7: +2:34
+      let mut _3: [u8; 1024];              // in scope 0 at $DIR/enum_opt.rs:+2:24: +2:33
+      let mut _4: NotTrunctable;           // in scope 0 at $DIR/enum_opt.rs:+3:7: +3:34
+      let mut _5: [u8; 4096];              // in scope 0 at $DIR/enum_opt.rs:+3:24: +3:33
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/enum_opt.rs:+1:7: +1:12
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/enum_opt.rs:+1:7: +1:12
+          _1 = NotTrunctable::A;           // scope 0 at $DIR/enum_opt.rs:+1:15: +1:31
+          StorageLive(_2);                 // scope 1 at $DIR/enum_opt.rs:+2:7: +2:34
+          StorageLive(_3);                 // scope 1 at $DIR/enum_opt.rs:+2:24: +2:33
+          _3 = [const 0_u8; 1024];         // scope 1 at $DIR/enum_opt.rs:+2:24: +2:33
+          _2 = NotTrunctable::B(move _3);  // scope 1 at $DIR/enum_opt.rs:+2:7: +2:34
+          StorageDead(_3);                 // scope 1 at $DIR/enum_opt.rs:+2:33: +2:34
+          _1 = move _2;                    // scope 1 at $DIR/enum_opt.rs:+2:3: +2:34
+          StorageDead(_2);                 // scope 1 at $DIR/enum_opt.rs:+2:33: +2:34
+          StorageLive(_4);                 // scope 1 at $DIR/enum_opt.rs:+3:7: +3:34
+          StorageLive(_5);                 // scope 1 at $DIR/enum_opt.rs:+3:24: +3:33
+          _5 = [const 0_u8; 4096];         // scope 1 at $DIR/enum_opt.rs:+3:24: +3:33
+          _4 = NotTrunctable::C(move _5);  // scope 1 at $DIR/enum_opt.rs:+3:7: +3:34
+          StorageDead(_5);                 // scope 1 at $DIR/enum_opt.rs:+3:33: +3:34
+          _1 = move _4;                    // scope 1 at $DIR/enum_opt.rs:+3:3: +3:34
+          StorageDead(_4);                 // scope 1 at $DIR/enum_opt.rs:+3:33: +3:34
+          _0 = move _1;                    // scope 1 at $DIR/enum_opt.rs:+4:3: +4:4
+          StorageDead(_1);                 // scope 0 at $DIR/enum_opt.rs:+5:1: +5:2
+          return;                          // scope 0 at $DIR/enum_opt.rs:+5:2: +5:2
+      }
+  }
+  
diff --git a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff
new file mode 100644
index 00000000000..ad9f12cf959
--- /dev/null
+++ b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.32bit.diff
@@ -0,0 +1,68 @@
+- // MIR for `unin` before EnumSizeOpt
++ // MIR for `unin` after EnumSizeOpt
+  
+  fn unin() -> NoData {
+      let mut _0: NoData;                  // return place in scope 0 at $DIR/enum_opt.rs:+0:18: +0:24
+      let mut _1: NoData;                  // in scope 0 at $DIR/enum_opt.rs:+1:7: +1:12
+      let mut _2: NoData;                  // in scope 0 at $DIR/enum_opt.rs:+2:7: +2:31
+      let mut _3: [u8; 8196];              // in scope 0 at $DIR/enum_opt.rs:+2:21: +2:30
++     let mut _4: [usize; 2];              // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:31
++     let mut _5: isize;                   // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:31
++     let mut _6: usize;                   // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:31
++     let mut _7: usize;                   // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:31
++     let mut _8: *mut NoData;             // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:31
++     let mut _9: *mut u8;                 // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:31
++     let mut _10: *const NoData;          // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:31
++     let mut _11: *const u8;              // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:31
++     let mut _12: [usize; 2];             // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _13: isize;                  // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _14: usize;                  // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _15: usize;                  // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _16: *mut NoData;            // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _17: *mut u8;                // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _18: *const NoData;          // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _19: *const u8;              // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/enum_opt.rs:+1:7: +1:12
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/enum_opt.rs:+1:7: +1:12
+          _1 = NoData::None;               // scope 0 at $DIR/enum_opt.rs:+1:15: +1:27
+          StorageLive(_2);                 // scope 1 at $DIR/enum_opt.rs:+2:7: +2:31
+          StorageLive(_3);                 // scope 1 at $DIR/enum_opt.rs:+2:21: +2:30
+          _3 = [const 1_u8; 8196];         // scope 1 at $DIR/enum_opt.rs:+2:21: +2:30
+          _2 = NoData::Large(move _3);     // scope 1 at $DIR/enum_opt.rs:+2:7: +2:31
+          StorageDead(_3);                 // scope 1 at $DIR/enum_opt.rs:+2:30: +2:31
+-         _1 = move _2;                    // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         StorageLive(_4);                 // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         _4 = const [8197_usize, 1_usize]; // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         _5 = discriminant(_2);           // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         _6 = _5 as usize (IntToInt);     // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         _7 = _4[_6];                     // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         _8 = &raw mut _1;                // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         _9 = _8 as *mut u8 (PtrToPtr);   // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         _10 = &raw const _2;             // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         _11 = _10 as *const u8 (PtrToPtr); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         Deinit(_8);                      // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         copy_nonoverlapping(dst = _9, src = _11, count = _7); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         StorageDead(_4);                 // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
+          StorageDead(_2);                 // scope 1 at $DIR/enum_opt.rs:+2:30: +2:31
+-         _0 = move _1;                    // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         StorageLive(_12);                // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _12 = const [8197_usize, 1_usize]; // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _13 = discriminant(_1);          // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _14 = _13 as usize (IntToInt);   // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _15 = _12[_14];                  // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _16 = &raw mut _0;               // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _17 = _16 as *mut u8 (PtrToPtr); // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _18 = &raw const _1;             // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _19 = _18 as *const u8 (PtrToPtr); // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         Deinit(_16);                     // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         copy_nonoverlapping(dst = _17, src = _19, count = _15); // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         StorageDead(_12);                // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
+          StorageDead(_1);                 // scope 0 at $DIR/enum_opt.rs:+4:1: +4:2
+          return;                          // scope 0 at $DIR/enum_opt.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff
new file mode 100644
index 00000000000..ad9f12cf959
--- /dev/null
+++ b/tests/mir-opt/enum_opt.unin.EnumSizeOpt.64bit.diff
@@ -0,0 +1,68 @@
+- // MIR for `unin` before EnumSizeOpt
++ // MIR for `unin` after EnumSizeOpt
+  
+  fn unin() -> NoData {
+      let mut _0: NoData;                  // return place in scope 0 at $DIR/enum_opt.rs:+0:18: +0:24
+      let mut _1: NoData;                  // in scope 0 at $DIR/enum_opt.rs:+1:7: +1:12
+      let mut _2: NoData;                  // in scope 0 at $DIR/enum_opt.rs:+2:7: +2:31
+      let mut _3: [u8; 8196];              // in scope 0 at $DIR/enum_opt.rs:+2:21: +2:30
++     let mut _4: [usize; 2];              // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:31
++     let mut _5: isize;                   // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:31
++     let mut _6: usize;                   // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:31
++     let mut _7: usize;                   // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:31
++     let mut _8: *mut NoData;             // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:31
++     let mut _9: *mut u8;                 // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:31
++     let mut _10: *const NoData;          // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:31
++     let mut _11: *const u8;              // in scope 0 at $DIR/enum_opt.rs:+2:3: +2:31
++     let mut _12: [usize; 2];             // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _13: isize;                  // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _14: usize;                  // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _15: usize;                  // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _16: *mut NoData;            // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _17: *mut u8;                // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _18: *const NoData;          // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
++     let mut _19: *const u8;              // in scope 0 at $DIR/enum_opt.rs:+3:3: +3:4
+      scope 1 {
+          debug a => _1;                   // in scope 1 at $DIR/enum_opt.rs:+1:7: +1:12
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/enum_opt.rs:+1:7: +1:12
+          _1 = NoData::None;               // scope 0 at $DIR/enum_opt.rs:+1:15: +1:27
+          StorageLive(_2);                 // scope 1 at $DIR/enum_opt.rs:+2:7: +2:31
+          StorageLive(_3);                 // scope 1 at $DIR/enum_opt.rs:+2:21: +2:30
+          _3 = [const 1_u8; 8196];         // scope 1 at $DIR/enum_opt.rs:+2:21: +2:30
+          _2 = NoData::Large(move _3);     // scope 1 at $DIR/enum_opt.rs:+2:7: +2:31
+          StorageDead(_3);                 // scope 1 at $DIR/enum_opt.rs:+2:30: +2:31
+-         _1 = move _2;                    // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         StorageLive(_4);                 // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         _4 = const [8197_usize, 1_usize]; // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         _5 = discriminant(_2);           // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         _6 = _5 as usize (IntToInt);     // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         _7 = _4[_6];                     // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         _8 = &raw mut _1;                // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         _9 = _8 as *mut u8 (PtrToPtr);   // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         _10 = &raw const _2;             // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         _11 = _10 as *const u8 (PtrToPtr); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         Deinit(_8);                      // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         copy_nonoverlapping(dst = _9, src = _11, count = _7); // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
++         StorageDead(_4);                 // scope 1 at $DIR/enum_opt.rs:+2:3: +2:31
+          StorageDead(_2);                 // scope 1 at $DIR/enum_opt.rs:+2:30: +2:31
+-         _0 = move _1;                    // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         StorageLive(_12);                // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _12 = const [8197_usize, 1_usize]; // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _13 = discriminant(_1);          // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _14 = _13 as usize (IntToInt);   // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _15 = _12[_14];                  // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _16 = &raw mut _0;               // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _17 = _16 as *mut u8 (PtrToPtr); // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _18 = &raw const _1;             // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         _19 = _18 as *const u8 (PtrToPtr); // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         Deinit(_16);                     // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         copy_nonoverlapping(dst = _17, src = _19, count = _15); // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
++         StorageDead(_12);                // scope 1 at $DIR/enum_opt.rs:+3:3: +3:4
+          StorageDead(_1);                 // scope 0 at $DIR/enum_opt.rs:+4:1: +4:2
+          return;                          // scope 0 at $DIR/enum_opt.rs:+4:2: +4:2
+      }
+  }
+  
diff --git a/tests/run-make/no-input-file/Makefile b/tests/run-make/no-input-file/Makefile
new file mode 100644
index 00000000000..2f02159229d
--- /dev/null
+++ b/tests/run-make/no-input-file/Makefile
@@ -0,0 +1,4 @@
+include ../../run-make-fulldeps/tools.mk
+
+all:
+	$(RUSTC) --print crate-name 2>&1 | diff - no-input-file.stderr
diff --git a/tests/run-make/no-input-file/no-input-file.stderr b/tests/run-make/no-input-file/no-input-file.stderr
new file mode 100644
index 00000000000..b843eb524f3
--- /dev/null
+++ b/tests/run-make/no-input-file/no-input-file.stderr
@@ -0,0 +1,2 @@
+error: no input filename given
+
diff --git a/tests/rustdoc/markdown-summaries.rs b/tests/rustdoc/markdown-summaries.rs
deleted file mode 100644
index 31e7072b5ce..00000000000
--- a/tests/rustdoc/markdown-summaries.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-#![crate_type = "lib"]
-#![crate_name = "summaries"]
-
-//! This *summary* has a [link] and `code`.
-//!
-//! This is the second paragraph.
-//!
-//! [link]: https://example.com
-
-// @hasraw search-index.js 'This <em>summary</em> has a link and <code>code</code>.'
-// @!hasraw - 'second paragraph'
-
-/// This `code` will be rendered in a code tag.
-///
-/// This text should not be rendered.
-pub struct Sidebar;
-
-// @hasraw search-index.js 'This <code>code</code> will be rendered in a code tag.'
-// @hasraw summaries/sidebar-items.js 'This `code` will be rendered in a code tag.'
-// @!hasraw - 'text should not be rendered'
-
-/// ```text
-/// this block should not be rendered
-/// ```
-pub struct Sidebar2;
-
-// @!hasraw summaries/sidebar-items.js 'block should not be rendered'
diff --git a/tests/ui/associated-type-bounds/elision.stderr b/tests/ui/associated-type-bounds/elision.stderr
index b64a4dab206..cc10bbcc0b5 100644
--- a/tests/ui/associated-type-bounds/elision.stderr
+++ b/tests/ui/associated-type-bounds/elision.stderr
@@ -16,10 +16,10 @@ error[E0308]: mismatched types
 LL | fn f(x: &mut dyn Iterator<Item: Iterator<Item = &'_ ()>>) -> Option<&'_ ()> { x.next() }
    |                           -----------------------------      --------------   ^^^^^^^^ expected `Option<&()>`, found `Option<impl Iterator<Item = &'_ ()>>`
    |                           |                                  |
-   |                           |                                  expected `Option<&'static ()>` because of return type
+   |                           |                                  expected `Option<&()>` because of return type
    |                           this type parameter
    |
-   = note: expected enum `Option<&'static ()>`
+   = note: expected enum `Option<&()>`
               found enum `Option<impl Iterator<Item = &'_ ()>>`
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/async-await/async-fn-path-elision.stderr b/tests/ui/async-await/async-fn-path-elision.stderr
index 5e0c8c29989..224198653dc 100644
--- a/tests/ui/async-await/async-fn-path-elision.stderr
+++ b/tests/ui/async-await/async-fn-path-elision.stderr
@@ -4,7 +4,6 @@ error[E0726]: implicit elided lifetime not allowed here
 LL | async fn error(lt: HasLifetime) {
    |                    ^^^^^^^^^^^ expected lifetime parameter
    |
-   = note: assuming a `'static` lifetime...
 help: indicate the anonymous lifetime
    |
 LL | async fn error(lt: HasLifetime<'_>) {
diff --git a/tests/ui/const-generics/const-param-elided-lifetime.min.stderr b/tests/ui/const-generics/const-param-elided-lifetime.min.stderr
index 4bba42c7782..656bc29466f 100644
--- a/tests/ui/const-generics/const-param-elided-lifetime.min.stderr
+++ b/tests/ui/const-generics/const-param-elided-lifetime.min.stderr
@@ -28,7 +28,7 @@ error[E0637]: `&` without an explicit lifetime name cannot be used here
 LL | fn bar<const N: &u8>() {}
    |                 ^ explicit lifetime name needed here
 
-error: `&'static u8` is forbidden as the type of a const generic parameter
+error: `&u8` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-elided-lifetime.rs:9:19
    |
 LL | struct A<const N: &u8>;
@@ -37,7 +37,7 @@ LL | struct A<const N: &u8>;
    = note: the only supported types are integers, `bool` and `char`
    = help: more complex types are supported with `#![feature(adt_const_params)]`
 
-error: `&'static u8` is forbidden as the type of a const generic parameter
+error: `&u8` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-elided-lifetime.rs:14:15
    |
 LL | impl<const N: &u8> A<N> {
@@ -46,7 +46,7 @@ LL | impl<const N: &u8> A<N> {
    = note: the only supported types are integers, `bool` and `char`
    = help: more complex types are supported with `#![feature(adt_const_params)]`
 
-error: `&'static u8` is forbidden as the type of a const generic parameter
+error: `&u8` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-elided-lifetime.rs:22:15
    |
 LL | impl<const N: &u8> B for A<N> {}
@@ -55,7 +55,7 @@ LL | impl<const N: &u8> B for A<N> {}
    = note: the only supported types are integers, `bool` and `char`
    = help: more complex types are supported with `#![feature(adt_const_params)]`
 
-error: `&'static u8` is forbidden as the type of a const generic parameter
+error: `&u8` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-elided-lifetime.rs:26:17
    |
 LL | fn bar<const N: &u8>() {}
@@ -64,7 +64,7 @@ LL | fn bar<const N: &u8>() {}
    = note: the only supported types are integers, `bool` and `char`
    = help: more complex types are supported with `#![feature(adt_const_params)]`
 
-error: `&'static u8` is forbidden as the type of a const generic parameter
+error: `&u8` is forbidden as the type of a const generic parameter
   --> $DIR/const-param-elided-lifetime.rs:17:21
    |
 LL |     fn foo<const M: &u8>(&self) {}
diff --git a/tests/ui/const-generics/const-param-elided-lifetime.rs b/tests/ui/const-generics/const-param-elided-lifetime.rs
index 487b82dbf4a..45611d6bf5f 100644
--- a/tests/ui/const-generics/const-param-elided-lifetime.rs
+++ b/tests/ui/const-generics/const-param-elided-lifetime.rs
@@ -8,23 +8,23 @@
 
 struct A<const N: &u8>;
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
-//[min]~^^ ERROR `&'static u8` is forbidden
+//[min]~^^ ERROR `&u8` is forbidden
 trait B {}
 
 impl<const N: &u8> A<N> {
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
-//[min]~^^ ERROR `&'static u8` is forbidden
+//[min]~^^ ERROR `&u8` is forbidden
     fn foo<const M: &u8>(&self) {}
     //~^ ERROR `&` without an explicit lifetime name cannot be used here
-    //[min]~^^ ERROR `&'static u8` is forbidden
+    //[min]~^^ ERROR `&u8` is forbidden
 }
 
 impl<const N: &u8> B for A<N> {}
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
-//[min]~^^ ERROR `&'static u8` is forbidden
+//[min]~^^ ERROR `&u8` is forbidden
 
 fn bar<const N: &u8>() {}
 //~^ ERROR `&` without an explicit lifetime name cannot be used here
-//[min]~^^ ERROR `&'static u8` is forbidden
+//[min]~^^ ERROR `&u8` is forbidden
 
 fn main() {}
diff --git a/tests/ui/const-generics/issues/issue-56445-1.min.stderr b/tests/ui/const-generics/issues/issue-56445-1.min.stderr
index 43a5df117fd..9f880134162 100644
--- a/tests/ui/const-generics/issues/issue-56445-1.min.stderr
+++ b/tests/ui/const-generics/issues/issue-56445-1.min.stderr
@@ -6,7 +6,7 @@ LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
    |
    = note: for more information, see issue #74052 <https://github.com/rust-lang/rust/issues/74052>
 
-error: `&'static str` is forbidden as the type of a const generic parameter
+error: `&str` is forbidden as the type of a const generic parameter
   --> $DIR/issue-56445-1.rs:9:25
    |
 LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
diff --git a/tests/ui/const-generics/issues/issue-56445-1.rs b/tests/ui/const-generics/issues/issue-56445-1.rs
index 13eb2ea9f69..0741c3796ad 100644
--- a/tests/ui/const-generics/issues/issue-56445-1.rs
+++ b/tests/ui/const-generics/issues/issue-56445-1.rs
@@ -8,6 +8,6 @@ use std::marker::PhantomData;
 
 struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
 //~^ ERROR: use of non-static lifetime `'a` in const generic
-//[min]~| ERROR: `&'static str` is forbidden as the type of a const generic parameter
+//[min]~| ERROR: `&str` is forbidden as the type of a const generic parameter
 
 impl Bug<'_, ""> {}
diff --git a/tests/ui/const-generics/wrong-normalization.rs b/tests/ui/const-generics/wrong-normalization.rs
new file mode 100644
index 00000000000..f1ce317b3f7
--- /dev/null
+++ b/tests/ui/const-generics/wrong-normalization.rs
@@ -0,0 +1,19 @@
+// This test ensures that if implementation on projections is supported,
+// it doesn't end in very weird cycle error.
+
+#![crate_type = "lib"]
+
+pub trait Identity {
+    type Identity: ?Sized;
+}
+
+impl<T: ?Sized> Identity for T {
+    type Identity = Self;
+}
+
+pub struct I8<const F: i8>;
+
+impl <I8<{i8::MIN}> as Identity>::Identity {
+//~^ ERROR no nominal type found for inherent implementation
+    pub fn foo(&self) {}
+}
diff --git a/tests/ui/const-generics/wrong-normalization.stderr b/tests/ui/const-generics/wrong-normalization.stderr
new file mode 100644
index 00000000000..fb806bdb1e7
--- /dev/null
+++ b/tests/ui/const-generics/wrong-normalization.stderr
@@ -0,0 +1,11 @@
+error[E0118]: no nominal type found for inherent implementation
+  --> $DIR/wrong-normalization.rs:16:6
+   |
+LL | impl <I8<{i8::MIN}> as Identity>::Identity {
+   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type
+   |
+   = note: either implement a trait on it or create a newtype to wrap it instead
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0118`.
diff --git a/tests/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs b/tests/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs
index 9ea9fc71b55..54b483f53d4 100644
--- a/tests/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs
+++ b/tests/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.rs
@@ -8,7 +8,6 @@ fn should_error<T>() where T : Into<&u32> {}
 trait X<'a, K: 'a> {
     fn foo<'b, L: X<&'b Nested<K>>>();
     //~^ ERROR missing lifetime specifier [E0106]
-    //~| ERROR the type `&'b Nested<K>` does not fulfill the required lifetime
 }
 
 fn bar<'b, L: X<&'b Nested<i32>>>(){}
diff --git a/tests/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr b/tests/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr
index 9d859fddf56..faf4c9eb872 100644
--- a/tests/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr
+++ b/tests/ui/generics/issue-65285-incorrect-explicit-lifetime-name-needed.stderr
@@ -29,7 +29,7 @@ LL |     fn foo<'b, L: X<'lifetime, &'b Nested<K>>>();
    |                     ++++++++++
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:14:16
+  --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:13:16
    |
 LL | fn bar<'b, L: X<&'b Nested<i32>>>(){}
    |                ^ expected named lifetime parameter
@@ -39,19 +39,7 @@ help: consider using the `'b` lifetime
 LL | fn bar<'b, L: X<'b, &'b Nested<i32>>>(){}
    |                 +++
 
-error[E0477]: the type `&'b Nested<K>` does not fulfill the required lifetime
-  --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:9:19
-   |
-LL |     fn foo<'b, L: X<&'b Nested<K>>>();
-   |                   ^^^^^^^^^^^^^^^^
-   |
-note: type must satisfy the static lifetime as required by this binding
-  --> $DIR/issue-65285-incorrect-explicit-lifetime-name-needed.rs:8:16
-   |
-LL | trait X<'a, K: 'a> {
-   |                ^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0106, E0477, E0637.
+Some errors have detailed explanations: E0106, E0637.
 For more information about an error, try `rustc --explain E0106`.
diff --git a/tests/ui/impl-header-lifetime-elision/path-elided.stderr b/tests/ui/impl-header-lifetime-elision/path-elided.stderr
index 0b7d3f1e851..18e4c618dba 100644
--- a/tests/ui/impl-header-lifetime-elision/path-elided.stderr
+++ b/tests/ui/impl-header-lifetime-elision/path-elided.stderr
@@ -4,7 +4,6 @@ error[E0726]: implicit elided lifetime not allowed here
 LL | impl MyTrait for Foo {
    |                  ^^^ expected lifetime parameter
    |
-   = note: assuming a `'static` lifetime...
 help: indicate the anonymous lifetime
    |
 LL | impl MyTrait for Foo<'_> {
diff --git a/tests/ui/impl-header-lifetime-elision/trait-elided.stderr b/tests/ui/impl-header-lifetime-elision/trait-elided.stderr
index 412bba6be71..74631a03786 100644
--- a/tests/ui/impl-header-lifetime-elision/trait-elided.stderr
+++ b/tests/ui/impl-header-lifetime-elision/trait-elided.stderr
@@ -4,7 +4,6 @@ error[E0726]: implicit elided lifetime not allowed here
 LL | impl MyTrait for u32 {}
    |      ^^^^^^^ expected lifetime parameter
    |
-   = note: assuming a `'static` lifetime...
 help: indicate the anonymous lifetime
    |
 LL | impl MyTrait<'_> for u32 {}
diff --git a/tests/ui/impl-trait/in-trait/signature-mismatch.stderr b/tests/ui/impl-trait/in-trait/signature-mismatch.stderr
index e105660173b..c4fcaabe446 100644
--- a/tests/ui/impl-trait/in-trait/signature-mismatch.stderr
+++ b/tests/ui/impl-trait/in-trait/signature-mismatch.stderr
@@ -2,12 +2,12 @@ error: `impl` item signature doesn't match `trait` item signature
   --> $DIR/signature-mismatch.rs:15:5
    |
 LL |     fn async_fn(&self, buff: &[u8]) -> impl Future<Output = Vec<u8>>;
-   |     ----------------------------------------------------------------- expected `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + 'static`
+   |     ----------------------------------------------------------------- expected `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '3`
 ...
 LL |     fn async_fn<'a>(&self, buff: &'a [u8]) -> impl Future<Output = Vec<u8>> + 'a {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '2`
    |
-   = note: expected signature `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + 'static`
+   = note: expected signature `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '3`
               found signature `fn(&'1 Struct, &'2 [u8]) -> impl Future<Output = Vec<u8>> + '2`
    = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
    = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
diff --git a/tests/ui/impl-trait/nested-return-type2.rs b/tests/ui/impl-trait/nested-return-type2.rs
index cc1f1f4ec44..fe883ce6fc8 100644
--- a/tests/ui/impl-trait/nested-return-type2.rs
+++ b/tests/ui/impl-trait/nested-return-type2.rs
@@ -1,4 +1,7 @@
 // check-pass
+// compile-flags: -Zvalidate-mir
+
+// Using -Zvalidate-mir as a regression test for #107346.
 
 trait Duh {}
 
diff --git a/tests/ui/impl-trait/nested-return-type2.stderr b/tests/ui/impl-trait/nested-return-type2.stderr
index 3aed05ca132..09ad3bd05c1 100644
--- a/tests/ui/impl-trait/nested-return-type2.stderr
+++ b/tests/ui/impl-trait/nested-return-type2.stderr
@@ -1,5 +1,5 @@
 warning: opaque type `impl Trait<Assoc = impl Send>` does not satisfy its associated type bounds
-  --> $DIR/nested-return-type2.rs:25:24
+  --> $DIR/nested-return-type2.rs:28:24
    |
 LL |     type Assoc: Duh;
    |                 --- this associated type bound is unsatisfied for `impl Send`
diff --git a/tests/ui/inference/issue-107090.rs b/tests/ui/inference/issue-107090.rs
index 9426445656f..a22e12c6d88 100644
--- a/tests/ui/inference/issue-107090.rs
+++ b/tests/ui/inference/issue-107090.rs
@@ -2,9 +2,7 @@ use std::marker::PhantomData;
 struct Foo<'a, 'b, T>(PhantomData<(&'a (), &'b (), T)>)
 where
     Foo<'short, 'out, T>: Convert<'a, 'b>;
-    //~^ ERROR mismatched types
-    //~^^ ERROR mismatched types
-    //~^^^ ERROR use of undeclared lifetime name
+    //~^ ERROR use of undeclared lifetime name
     //~| ERROR use of undeclared lifetime name `'out`
 
 trait Convert<'a, 'b>: Sized {
@@ -13,19 +11,15 @@ trait Convert<'a, 'b>: Sized {
 impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> {
     //~^ ERROR use of undeclared lifetime name
     //~^^ ERROR use of undeclared lifetime name `'out`
-    //~| ERROR cannot infer an appropriate lifetime for lifetime parameter
     fn cast(&'long self) -> &'short Foo<'short, 'out, T> {
         //~^ ERROR use of undeclared lifetime name
-        //~| ERROR cannot infer an appropriate lifetime for lifetime parameter
         self
     }
 }
 
 fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ Foo<'short, 'out, T>) -> &'out T {
     //~^ ERROR use of undeclared lifetime name
-    //~^^ ERROR incompatible lifetime on type
-    //~| ERROR `x` has lifetime `'in_` but it needs to satisfy a `'static` lifetime requirement
-    sadness.cast()
+    sadness.cast() //~ ERROR mismatched types
 }
 
 fn main() {}
diff --git a/tests/ui/inference/issue-107090.stderr b/tests/ui/inference/issue-107090.stderr
index 33cb39014ac..6233b629ad6 100644
--- a/tests/ui/inference/issue-107090.stderr
+++ b/tests/ui/inference/issue-107090.stderr
@@ -30,7 +30,7 @@ LL | struct Foo<'out, 'a, 'b, T>(PhantomData<(&'a (), &'b (), T)>)
    |            +++++
 
 error[E0261]: use of undeclared lifetime name `'b`
-  --> $DIR/issue-107090.rs:13:47
+  --> $DIR/issue-107090.rs:11:47
    |
 LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> {
    |      -                                        ^^ undeclared lifetime
@@ -38,13 +38,13 @@ LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T>
    |      help: consider introducing lifetime `'b` here: `'b,`
 
 error[E0261]: use of undeclared lifetime name `'out`
-  --> $DIR/issue-107090.rs:13:67
+  --> $DIR/issue-107090.rs:11:67
    |
 LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> {
    |      - help: consider introducing lifetime `'out` here: `'out,`   ^^^^ undeclared lifetime
 
 error[E0261]: use of undeclared lifetime name `'out`
-  --> $DIR/issue-107090.rs:17:49
+  --> $DIR/issue-107090.rs:14:49
    |
 LL |     fn cast(&'long self) -> &'short Foo<'short, 'out, T> {
    |                                                 ^^^^ undeclared lifetime
@@ -59,7 +59,7 @@ LL | impl<'out, 'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'ou
    |      +++++
 
 error[E0261]: use of undeclared lifetime name `'short`
-  --> $DIR/issue-107090.rs:24:68
+  --> $DIR/issue-107090.rs:20:68
    |
 LL | fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ Foo<'short, 'out, T>) -> &'out T {
    |           -                                                        ^^^^^^ undeclared lifetime
@@ -67,107 +67,18 @@ LL | fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ Foo<'short,
    |           help: consider introducing lifetime `'short` here: `'short,`
 
 error[E0308]: mismatched types
-  --> $DIR/issue-107090.rs:4:27
-   |
-LL |     Foo<'short, 'out, T>: Convert<'a, 'b>;
-   |                           ^^^^^^^^^^^^^^^ lifetime mismatch
-   |
-   = note: expected trait `Convert<'static, 'static>`
-              found trait `Convert<'a, 'b>`
-note: the lifetime `'a` as defined here...
-  --> $DIR/issue-107090.rs:2:12
-   |
-LL | struct Foo<'a, 'b, T>(PhantomData<(&'a (), &'b (), T)>)
-   |            ^^
-   = note: ...does not necessarily outlive the static lifetime
-
-error[E0308]: mismatched types
-  --> $DIR/issue-107090.rs:4:27
-   |
-LL |     Foo<'short, 'out, T>: Convert<'a, 'b>;
-   |                           ^^^^^^^^^^^^^^^ lifetime mismatch
-   |
-   = note: expected trait `Convert<'static, 'static>`
-              found trait `Convert<'a, 'b>`
-note: the lifetime `'b` as defined here...
-  --> $DIR/issue-107090.rs:2:16
-   |
-LL | struct Foo<'a, 'b, T>(PhantomData<(&'a (), &'b (), T)>)
-   |                ^^
-   = note: ...does not necessarily outlive the static lifetime
-
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'long` due to conflicting requirements
-  --> $DIR/issue-107090.rs:13:55
-   |
-LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> {
-   |                                                       ^^^^^^^^^^^^^^^^^^^^
-   |
-note: first, the lifetime cannot outlive the lifetime `'short` as defined here...
-  --> $DIR/issue-107090.rs:13:21
-   |
-LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> {
-   |                     ^^^^^^
-   = note: ...but the lifetime must also be valid for the static lifetime...
-note: ...so that the types are compatible
-  --> $DIR/issue-107090.rs:13:55
-   |
-LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> {
-   |                                                       ^^^^^^^^^^^^^^^^^^^^
-   = note: expected `Convert<'short, 'static>`
-              found `Convert<'_, 'static>`
-
-error: incompatible lifetime on type
-  --> $DIR/issue-107090.rs:24:29
-   |
-LL | fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ Foo<'short, 'out, T>) -> &'out T {
-   |                             ^^^^^^^^^^^^^^^^^^
-   |
-note: because this has an unmet lifetime requirement
-  --> $DIR/issue-107090.rs:4:27
-   |
-LL |     Foo<'short, 'out, T>: Convert<'a, 'b>;
-   |                           ^^^^^^^^^^^^^^^ introduces a `'static` lifetime requirement
-note: the lifetime `'out` as defined here...
-  --> $DIR/issue-107090.rs:24:17
-   |
-LL | fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ Foo<'short, 'out, T>) -> &'out T {
-   |                 ^^^^
-note: ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
-  --> $DIR/issue-107090.rs:13:1
-   |
-LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0759]: `x` has lifetime `'in_` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/issue-107090.rs:24:29
+  --> $DIR/issue-107090.rs:22:5
    |
 LL | fn badboi<'in_, 'out, T>(x: Foo<'in_, 'out, T>, sadness: &'in_ Foo<'short, 'out, T>) -> &'out T {
-   |                             ^^^^^^^^^^^^^^^^^^
-   |                             |
-   |                             this data with lifetime `'in_`...
-   |                             ...is used and required to live as long as `'static` here
-
-error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'long` due to conflicting requirements
-  --> $DIR/issue-107090.rs:17:13
-   |
-LL |     fn cast(&'long self) -> &'short Foo<'short, 'out, T> {
-   |             ^^^^^^^^^^^
+   |                       - this type parameter                                             ------- expected `&'out T` because of return type
+LL |
+LL |     sadness.cast()
+   |     ^^^^^^^^^^^^^^ expected `&T`, found `&Foo<'_, '_, T>`
    |
-note: first, the lifetime cannot outlive the lifetime `'short` as defined here...
-  --> $DIR/issue-107090.rs:13:21
-   |
-LL | impl<'long: 'short, 'short, T> Convert<'long, 'b> for Foo<'short, 'out, T> {
-   |                     ^^^^^^
-   = note: ...but the lifetime must also be valid for the static lifetime...
-note: ...so that the types are compatible
-  --> $DIR/issue-107090.rs:17:13
-   |
-LL |     fn cast(&'long self) -> &'short Foo<'short, 'out, T> {
-   |             ^^^^^^^^^^^
-   = note: expected `Convert<'short, 'static>`
-              found `Convert<'_, 'static>`
+   = note: expected reference `&'out T`
+              found reference `&Foo<'_, '_, T>`
 
-error: aborting due to 12 previous errors
+error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0261, E0308, E0495, E0759.
+Some errors have detailed explanations: E0261, E0308.
 For more information about an error, try `rustc --explain E0261`.
diff --git a/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.rs b/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.rs
new file mode 100644
index 00000000000..7f6758f47f8
--- /dev/null
+++ b/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.rs
@@ -0,0 +1,19 @@
+// ignore-tidy-linelength
+
+// Regression test for #107745.
+// Previously need_type_info::update_infer_source will consider expressions originating from
+// macro expressions as candiate "previous sources". This unfortunately can mean that
+// for macros expansions such as `format!()` internal implementation details can leak, such as:
+//
+// ```
+// error[E0282]: type annotations needed
+// --> src/main.rs:2:22
+//  |
+//2 |     println!("{:?}", []);
+//  |                      ^^ cannot infer type of the type parameter `T` declared on the associated function `new_debug`
+// ```
+
+fn main() {
+    println!("{:?}", []);
+    //~^ ERROR type annotations needed
+}
diff --git a/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr b/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr
new file mode 100644
index 00000000000..464655bbcf4
--- /dev/null
+++ b/tests/ui/inference/need_type_info/issue-107745-avoid-expr-from-macro-expansion.stderr
@@ -0,0 +1,11 @@
+error[E0282]: type annotations needed
+  --> $DIR/issue-107745-avoid-expr-from-macro-expansion.rs:17:22
+   |
+LL |     println!("{:?}", []);
+   |                      ^^ cannot infer type
+   |
+   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/issues/issue-10412.stderr b/tests/ui/issues/issue-10412.stderr
index 46b9fd541ad..26666782d2a 100644
--- a/tests/ui/issues/issue-10412.stderr
+++ b/tests/ui/issues/issue-10412.stderr
@@ -46,7 +46,6 @@ error[E0726]: implicit elided lifetime not allowed here
 LL | impl<'self> Serializable<str> for &'self str {
    |             ^^^^^^^^^^^^^^^^^ expected lifetime parameter
    |
-   = note: assuming a `'static` lifetime...
 help: indicate the anonymous lifetime
    |
 LL | impl<'self> Serializable<'_, str> for &'self str {
diff --git a/tests/ui/issues/issue-16966.stderr b/tests/ui/issues/issue-16966.stderr
index 60f5190dbd0..8c92505b5eb 100644
--- a/tests/ui/issues/issue-16966.stderr
+++ b/tests/ui/issues/issue-16966.stderr
@@ -1,10 +1,8 @@
 error[E0282]: type annotations needed
-  --> $DIR/issue-16966.rs:2:5
+  --> $DIR/issue-16966.rs:2:12
    |
 LL |     panic!(std::default::Default::default());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type of the type parameter `M` declared on the function `begin_panic`
-   |
-   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info)
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type
 
 error: aborting due to previous error
 
diff --git a/tests/ui/lifetimes/issue-26638.stderr b/tests/ui/lifetimes/issue-26638.stderr
index 4dfacb93801..30afcecf827 100644
--- a/tests/ui/lifetimes/issue-26638.stderr
+++ b/tests/ui/lifetimes/issue-26638.stderr
@@ -40,9 +40,9 @@ error[E0308]: mismatched types
 LL | fn parse_type(iter: Box<dyn Iterator<Item=&str>+'static>) -> &str { iter.next() }
    |                                                              ----   ^^^^^^^^^^^ expected `&str`, found `Option<&str>`
    |                                                              |
-   |                                                              expected `&'static str` because of return type
+   |                                                              expected `&str` because of return type
    |
-   = note: expected reference `&'static str`
+   = note: expected reference `&str`
                    found enum `Option<&str>`
 
 error[E0061]: this function takes 1 argument but 0 arguments were supplied
diff --git a/tests/ui/lifetimes/issue-69314.fixed b/tests/ui/lifetimes/issue-69314.fixed
new file mode 100644
index 00000000000..41116d4ea61
--- /dev/null
+++ b/tests/ui/lifetimes/issue-69314.fixed
@@ -0,0 +1,22 @@
+// run-rustfix
+// edition:2021
+#![allow(dead_code, unused_mut, unused_variables)]
+struct A {}
+struct Msg<'a> {
+    s: &'a [i32],
+}
+impl A {
+    async fn g(buf: &[i32]) -> Msg<'_> {
+        Msg { s: &buf[0..1] }
+    }
+    async fn f() {
+        let mut buf = [0; 512];
+        let m2 = &buf[..]; //~ ERROR `buf` does not live long enough
+        let m = Self::g(m2).await;
+        Self::f2(m).await;
+    }
+    async fn f2(m: Msg<'_>) {}
+    //~^ ERROR implicit elided lifetime not allowed here
+}
+
+fn main() {}
diff --git a/tests/ui/lifetimes/issue-69314.rs b/tests/ui/lifetimes/issue-69314.rs
new file mode 100644
index 00000000000..17445341eb6
--- /dev/null
+++ b/tests/ui/lifetimes/issue-69314.rs
@@ -0,0 +1,22 @@
+// run-rustfix
+// edition:2021
+#![allow(dead_code, unused_mut, unused_variables)]
+struct A {}
+struct Msg<'a> {
+    s: &'a [i32],
+}
+impl A {
+    async fn g(buf: &[i32]) -> Msg<'_> {
+        Msg { s: &buf[0..1] }
+    }
+    async fn f() {
+        let mut buf = [0; 512];
+        let m2 = &buf[..]; //~ ERROR `buf` does not live long enough
+        let m = Self::g(m2).await;
+        Self::f2(m).await;
+    }
+    async fn f2(m: Msg) {}
+    //~^ ERROR implicit elided lifetime not allowed here
+}
+
+fn main() {}
diff --git a/tests/ui/lifetimes/issue-69314.stderr b/tests/ui/lifetimes/issue-69314.stderr
new file mode 100644
index 00000000000..7ae6789285b
--- /dev/null
+++ b/tests/ui/lifetimes/issue-69314.stderr
@@ -0,0 +1,26 @@
+error[E0726]: implicit elided lifetime not allowed here
+  --> $DIR/issue-69314.rs:18:20
+   |
+LL |     async fn f2(m: Msg) {}
+   |                    ^^^ expected lifetime parameter
+   |
+help: indicate the anonymous lifetime
+   |
+LL |     async fn f2(m: Msg<'_>) {}
+   |                       ++++
+
+error[E0597]: `buf` does not live long enough
+  --> $DIR/issue-69314.rs:14:19
+   |
+LL |         let m2 = &buf[..];
+   |                   ^^^ borrowed value does not live long enough
+LL |         let m = Self::g(m2).await;
+   |                 ----------- argument requires that `buf` is borrowed for `'static`
+LL |         Self::f2(m).await;
+LL |     }
+   |     - `buf` dropped here while still borrowed
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0597, E0726.
+For more information about an error, try `rustc --explain E0597`.
diff --git a/tests/ui/lifetimes/unusual-rib-combinations.rs b/tests/ui/lifetimes/unusual-rib-combinations.rs
index b4c86aab863..1c122f42e59 100644
--- a/tests/ui/lifetimes/unusual-rib-combinations.rs
+++ b/tests/ui/lifetimes/unusual-rib-combinations.rs
@@ -23,6 +23,6 @@ fn c<T = u8()>() {}
 // Elided lifetime in path in ConstGeneric
 fn d<const C: S>() {}
 //~^ ERROR missing lifetime specifier
-//~| ERROR `S<'static>` is forbidden as the type of a const generic parameter
+//~| ERROR `S<'_>` is forbidden as the type of a const generic parameter
 
 fn main() {}
diff --git a/tests/ui/lifetimes/unusual-rib-combinations.stderr b/tests/ui/lifetimes/unusual-rib-combinations.stderr
index 6d7b4250698..68f4fce0178 100644
--- a/tests/ui/lifetimes/unusual-rib-combinations.stderr
+++ b/tests/ui/lifetimes/unusual-rib-combinations.stderr
@@ -46,7 +46,7 @@ LL | fn a() -> [u8; foo::()] {
    = note: expected type `usize`
            found fn item `fn() {foo}`
 
-error: `S<'static>` is forbidden as the type of a const generic parameter
+error: `S<'_>` is forbidden as the type of a const generic parameter
   --> $DIR/unusual-rib-combinations.rs:24:15
    |
 LL | fn d<const C: S>() {}
diff --git a/tests/ui/lint/reasons-forbidden.rs b/tests/ui/lint/reasons-forbidden.rs
index 9c2edec4d52..947099fdd13 100644
--- a/tests/ui/lint/reasons-forbidden.rs
+++ b/tests/ui/lint/reasons-forbidden.rs
@@ -8,7 +8,7 @@
 //
 // The test is much cleaner if we deduplicate, though.
 
-// compile-flags: -Z deduplicate-diagnostics=yes
+// compile-flags: -Z deduplicate-diagnostics=true
 
 #![forbid(
     unsafe_code,
diff --git a/tests/ui/mismatched_types/issue-74918-missing-lifetime.stderr b/tests/ui/mismatched_types/issue-74918-missing-lifetime.stderr
index 9ddea162944..b5231823099 100644
--- a/tests/ui/mismatched_types/issue-74918-missing-lifetime.stderr
+++ b/tests/ui/mismatched_types/issue-74918-missing-lifetime.stderr
@@ -16,9 +16,9 @@ LL |     fn next(&mut self) -> Option<IteratorChunk<T, S>> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'1, T, S>>`
   --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
    |
-   = note: expected `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'static, T, S>>`
+   = note: expected `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'2, T, S>>`
    |
-   = note: expected signature `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'static, T, S>>`
+   = note: expected signature `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'2, T, S>>`
               found signature `fn(&'1 mut ChunkingIterator<T, S>) -> Option<IteratorChunk<'1, T, S>>`
    = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
    = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
diff --git a/tests/ui/nll/issue-52057.rs b/tests/ui/nll/issue-52057.rs
index 98f49fe8f55..5991c1104c8 100644
--- a/tests/ui/nll/issue-52057.rs
+++ b/tests/ui/nll/issue-52057.rs
@@ -1,6 +1,6 @@
 // Regression test for #52057. There is an implied bound
-// that `I: 'a` where `'a` is the lifetime of `self` in `parse_first`;
-// but to observe that, one must normalize first.
+// that `I: 'x` where `'x` is the lifetime of the reference `&mut Self::Input`
+// in `parse_first`; but to observe that, one must normalize first.
 //
 // run-pass
 
diff --git a/tests/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs b/tests/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs
index 79d78da3328..0e487a700b8 100644
--- a/tests/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs
+++ b/tests/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs
@@ -1,5 +1,5 @@
 // run-pass
-// compile-flags: -C debug_assertions=yes
+// compile-flags: -C debug_assertions=true
 // needs-unwind
 // ignore-emscripten dies with an LLVM error
 
diff --git a/tests/ui/parser/missing-closing-angle-bracket-eq-constraint.rs b/tests/ui/parser/missing-closing-angle-bracket-eq-constraint.rs
index da95c1bfa27..a56cd17773d 100644
--- a/tests/ui/parser/missing-closing-angle-bracket-eq-constraint.rs
+++ b/tests/ui/parser/missing-closing-angle-bracket-eq-constraint.rs
@@ -17,7 +17,7 @@ fn test2<T1, T2>(arg1 : T1, arg2 : T2) {
 fn test3<'a>(arg : &'a u32) {
   let v : Vec<'a = vec![];
     //~^ ERROR: expected one of
-    //~| ERROR: type annotations needed for `Vec<T>`
+    //~| ERROR: type annotations needed for `Vec<_>`
 }
 
 fn main() {}
diff --git a/tests/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr b/tests/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr
index bad241634cb..b2448774ae9 100644
--- a/tests/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr
+++ b/tests/ui/parser/missing-closing-angle-bracket-eq-constraint.stderr
@@ -39,26 +39,26 @@ help: you might have meant to end the type parameters here
 LL |   let v : Vec<'a> = vec![];
    |                 +
 
-error[E0282]: type annotations needed for `Vec<T>`
+error[E0282]: type annotations needed for `Vec<_>`
   --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:7:7
    |
 LL |   let v : Vec<(u32,_) = vec![];
    |       ^
    |
-help: consider giving `v` an explicit type, where the type for type parameter `T` is specified
+help: consider giving `v` an explicit type, where the placeholders `_` are specified
    |
-LL |   let v: Vec<T> : Vec<(u32,_) = vec![];
+LL |   let v: Vec<_> : Vec<(u32,_) = vec![];
    |        ++++++++
 
-error[E0282]: type annotations needed for `Vec<T>`
+error[E0282]: type annotations needed for `Vec<_>`
   --> $DIR/missing-closing-angle-bracket-eq-constraint.rs:18:7
    |
 LL |   let v : Vec<'a = vec![];
    |       ^
    |
-help: consider giving `v` an explicit type, where the type for type parameter `T` is specified
+help: consider giving `v` an explicit type, where the placeholders `_` are specified
    |
-LL |   let v: Vec<T> : Vec<'a = vec![];
+LL |   let v: Vec<_> : Vec<'a = vec![];
    |        ++++++++
 
 error: aborting due to 5 previous errors
diff --git a/tests/ui/rfc-2091-track-caller/call-chain.rs b/tests/ui/rfc-2091-track-caller/call-chain.rs
index 28b3f76c9d5..a8814ce2852 100644
--- a/tests/ui/rfc-2091-track-caller/call-chain.rs
+++ b/tests/ui/rfc-2091-track-caller/call-chain.rs
@@ -1,6 +1,6 @@
 // run-pass
 // revisions: default mir-opt
-//[default] compile-flags: -Zinline-mir=no
+//[default] compile-flags: -Zinline-mir=false
 //[mir-opt] compile-flags: -Zmir-opt-level=4
 
 use std::panic::Location;
diff --git a/tests/ui/suggestions/issue-104961.fixed b/tests/ui/suggestions/issue-104961.fixed
new file mode 100644
index 00000000000..520d638b174
--- /dev/null
+++ b/tests/ui/suggestions/issue-104961.fixed
@@ -0,0 +1,16 @@
+// run-rustfix
+
+fn foo(x: &str) -> bool {
+    x.starts_with(&("hi".to_string() + " you"))
+    //~^ ERROR expected a `FnMut<(char,)>` closure, found `String`
+}
+
+fn foo2(x: &str) -> bool {
+    x.starts_with(&"hi".to_string())
+    //~^ ERROR expected a `FnMut<(char,)>` closure, found `String`
+}
+
+fn main() {
+    foo("hi you");
+    foo2("hi");
+}
diff --git a/tests/ui/suggestions/issue-104961.rs b/tests/ui/suggestions/issue-104961.rs
new file mode 100644
index 00000000000..aeb787abb6f
--- /dev/null
+++ b/tests/ui/suggestions/issue-104961.rs
@@ -0,0 +1,16 @@
+// run-rustfix
+
+fn foo(x: &str) -> bool {
+    x.starts_with("hi".to_string() + " you")
+    //~^ ERROR expected a `FnMut<(char,)>` closure, found `String`
+}
+
+fn foo2(x: &str) -> bool {
+    x.starts_with("hi".to_string())
+    //~^ ERROR expected a `FnMut<(char,)>` closure, found `String`
+}
+
+fn main() {
+    foo("hi you");
+    foo2("hi");
+}
diff --git a/tests/ui/suggestions/issue-104961.stderr b/tests/ui/suggestions/issue-104961.stderr
new file mode 100644
index 00000000000..8cec6a3f827
--- /dev/null
+++ b/tests/ui/suggestions/issue-104961.stderr
@@ -0,0 +1,37 @@
+error[E0277]: expected a `FnMut<(char,)>` closure, found `String`
+  --> $DIR/issue-104961.rs:4:19
+   |
+LL |     x.starts_with("hi".to_string() + " you")
+   |       ----------- ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Pattern<'_>` is not implemented for `String`
+   |       |
+   |       required by a bound introduced by this call
+   |
+   = note: the trait bound `String: Pattern<'_>` is not satisfied
+   = note: required for `String` to implement `Pattern<'_>`
+note: required by a bound in `core::str::<impl str>::starts_with`
+  --> $SRC_DIR/core/src/str/mod.rs:LL:COL
+help: consider borrowing here
+   |
+LL |     x.starts_with(&("hi".to_string() + " you"))
+   |                   ++                         +
+
+error[E0277]: expected a `FnMut<(char,)>` closure, found `String`
+  --> $DIR/issue-104961.rs:9:19
+   |
+LL |     x.starts_with("hi".to_string())
+   |       ----------- ^^^^^^^^^^^^^^^^ the trait `Pattern<'_>` is not implemented for `String`
+   |       |
+   |       required by a bound introduced by this call
+   |
+   = note: the trait bound `String: Pattern<'_>` is not satisfied
+   = note: required for `String` to implement `Pattern<'_>`
+note: required by a bound in `core::str::<impl str>::starts_with`
+  --> $SRC_DIR/core/src/str/mod.rs:LL:COL
+help: consider borrowing here
+   |
+LL |     x.starts_with(&"hi".to_string())
+   |                   +
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/suggestions/suggest-call-on-pat-mismatch.rs b/tests/ui/suggestions/suggest-call-on-pat-mismatch.rs
new file mode 100644
index 00000000000..657dd9c22c2
--- /dev/null
+++ b/tests/ui/suggestions/suggest-call-on-pat-mismatch.rs
@@ -0,0 +1,16 @@
+enum E {
+    One(i32, i32),
+}
+
+fn main() {
+    let var = E::One;
+    if let E::One(var1, var2) = var {
+        //~^ ERROR mismatched types
+        //~| HELP use parentheses to construct this tuple variant
+        println!("{var1} {var2}");
+    }
+
+    let Some(x) = Some;
+    //~^ ERROR mismatched types
+    //~| HELP use parentheses to construct this tuple variant
+}
diff --git a/tests/ui/suggestions/suggest-call-on-pat-mismatch.stderr b/tests/ui/suggestions/suggest-call-on-pat-mismatch.stderr
new file mode 100644
index 00000000000..7338312bab6
--- /dev/null
+++ b/tests/ui/suggestions/suggest-call-on-pat-mismatch.stderr
@@ -0,0 +1,33 @@
+error[E0308]: mismatched types
+  --> $DIR/suggest-call-on-pat-mismatch.rs:7:12
+   |
+LL |     if let E::One(var1, var2) = var {
+   |            ^^^^^^^^^^^^^^^^^^   --- this expression has type `fn(i32, i32) -> E {E::One}`
+   |            |
+   |            expected enum constructor, found `E`
+   |
+   = note: expected enum constructor `fn(i32, i32) -> E {E::One}`
+                          found enum `E`
+help: use parentheses to construct this tuple variant
+   |
+LL |     if let E::One(var1, var2) = var(/* i32 */, /* i32 */) {
+   |                                    ++++++++++++++++++++++
+
+error[E0308]: mismatched types
+  --> $DIR/suggest-call-on-pat-mismatch.rs:13:9
+   |
+LL |     let Some(x) = Some;
+   |         ^^^^^^^   ---- this expression has type `fn(_) -> Option<_> {Option::<_>::Some}`
+   |         |
+   |         expected enum constructor, found `Option<_>`
+   |
+   = note: expected enum constructor `fn(_) -> Option<_> {Option::<_>::Some}`
+                          found enum `Option<_>`
+help: use parentheses to construct this tuple variant
+   |
+LL |     let Some(x) = Some(/* value */);
+   |                       +++++++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/new-solver/alias_eq_cant_be_furthur_normalized.rs b/tests/ui/traits/new-solver/alias_eq_cant_be_furthur_normalized.rs
new file mode 100644
index 00000000000..dc726ba51f9
--- /dev/null
+++ b/tests/ui/traits/new-solver/alias_eq_cant_be_furthur_normalized.rs
@@ -0,0 +1,29 @@
+// check-pass
+// compile-flags: -Ztrait-solver=next
+
+// check that a goal such as `alias-eq(<T as TraitB>::Assoc<bool>, <T as TraitB>::Assoc<?0>)`
+// succeeds with a constraint that `?0 = bool`
+
+// FIXME(deferred_projection_equality): add a test that this is true during coherence
+
+trait TraitA {}
+
+trait TraitB {
+    type Assoc<T: ?Sized>;
+}
+
+impl<T: TraitB> TraitA for (T, T::Assoc<bool>) {}
+
+impl TraitB for i32 {
+    type Assoc<T: ?Sized> = u32;
+}
+
+fn needs_a<T: TraitA>() {}
+
+fn bar<T: TraitB>() {
+    needs_a::<(T, <T as TraitB>::Assoc<_>)>();
+}
+
+fn main() {
+    bar::<i32>();
+}
diff --git a/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs b/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs
new file mode 100644
index 00000000000..fd5d0e3b194
--- /dev/null
+++ b/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.rs
@@ -0,0 +1,45 @@
+// compile-flags: -Ztrait-solver=next
+
+// check that when computing `alias-eq(<() as Foo<u16, T>>::Assoc, <() as Foo<?0, T>>::Assoc)`
+//  we do not infer `?0 = u8` via the `for<STOP> (): Foo<u8, STOP>` impl or `?0 = u16` by
+// relating substs as either could be a valid solution.
+
+trait Foo<T, STOP> {
+    type Assoc;
+}
+
+impl<STOP> Foo<u8, STOP> for ()
+where
+    (): Foo<u16, STOP>,
+{
+    type Assoc = <() as Foo<u16, STOP>>::Assoc;
+}
+
+impl Foo<u16, i8> for () {
+    type Assoc = u8;
+}
+
+impl Foo<u16, i16> for () {
+    type Assoc = u16;
+}
+
+fn output<T, U>() -> <() as Foo<T, U>>::Assoc
+where
+    (): Foo<T, U>,
+{
+    todo!()
+}
+
+fn incomplete<T>()
+where
+    (): Foo<u16, T>,
+{
+    // `<() as Foo<u16, STOP>>::Assoc == <() as Foo<_, STOP>>::Assoc`
+    let _: <() as Foo<u16, T>>::Assoc = output::<_, T>();
+    //~^ error: type annotations needed
+
+    // let _: <() as Foo<u16, T>>::Assoc = output::<u8, T>(); // OK
+    // let _: <() as Foo<u16, T>>::Assoc = output::<u16, T>(); // OK
+}
+
+fn main() {}
diff --git a/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.stderr b/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.stderr
new file mode 100644
index 00000000000..a6712332c37
--- /dev/null
+++ b/tests/ui/traits/new-solver/alias_eq_dont_use_normalizes_to_if_substs_eq.stderr
@@ -0,0 +1,9 @@
+error[E0282]: type annotations needed
+  --> $DIR/alias_eq_dont_use_normalizes_to_if_substs_eq.rs:38:41
+   |
+LL |     let _: <() as Foo<u16, T>>::Assoc = output::<_, T>();
+   |                                         ^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the function `output`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/traits/new-solver/alias_eq_simple.rs b/tests/ui/traits/new-solver/alias_eq_simple.rs
new file mode 100644
index 00000000000..6792cf3ce35
--- /dev/null
+++ b/tests/ui/traits/new-solver/alias_eq_simple.rs
@@ -0,0 +1,22 @@
+// check-pass
+// compile-flags: -Ztrait-solver=next
+
+// test that the new solver can handle `alias-eq(<i32 as TraitB>::Assoc, u32)`
+
+trait TraitA {}
+
+trait TraitB {
+    type Assoc;
+}
+
+impl<T: TraitB> TraitA for (T, T::Assoc) {}
+
+impl TraitB for i32 {
+    type Assoc = u32;
+}
+
+fn needs_a<T: TraitA>() {}
+
+fn main() {
+    needs_a::<(i32, u32)>();
+}
diff --git a/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.rs b/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.rs
new file mode 100644
index 00000000000..d4cc380fa21
--- /dev/null
+++ b/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.rs
@@ -0,0 +1,20 @@
+// compile-flags: -Ztrait-solver=next
+
+// check that a `alias-eq(<?0 as TraitB>::Assoc, <T as TraitB>::Assoc)` goal fails.
+
+// FIXME(deferred_projection_equality): add a test that this is true during coherence
+
+trait TraitB {
+    type Assoc;
+}
+
+fn needs_a<T: TraitB>() -> T::Assoc {
+    unimplemented!()
+}
+
+fn bar<T: TraitB>() {
+    let _: <_ as TraitB>::Assoc = needs_a::<T>();
+    //~^ error: type annotations needed
+}
+
+fn main() {}
diff --git a/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.stderr b/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.stderr
new file mode 100644
index 00000000000..d063d8fce11
--- /dev/null
+++ b/tests/ui/traits/new-solver/alias_eq_substs_eq_not_intercrate.stderr
@@ -0,0 +1,9 @@
+error[E0282]: type annotations needed
+  --> $DIR/alias_eq_substs_eq_not_intercrate.rs:16:12
+   |
+LL |     let _: <_ as TraitB>::Assoc = needs_a::<T>();
+   |            ^^^^^^^^^^^^^^^^^^^^ cannot infer type for associated type `<_ as TraitB>::Assoc`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/traits/new-solver/normalizes_to_ignores_unnormalizable_candidate.rs b/tests/ui/traits/new-solver/normalizes_to_ignores_unnormalizable_candidate.rs
new file mode 100644
index 00000000000..46343241b45
--- /dev/null
+++ b/tests/ui/traits/new-solver/normalizes_to_ignores_unnormalizable_candidate.rs
@@ -0,0 +1,40 @@
+// [no_self_infer] check-pass
+// compile-flags: -Ztrait-solver=next
+// revisions: self_infer no_self_infer
+
+// checks that the new solver is smart enough to infer `?0 = U` when solving:
+// `normalizes-to(<Vec<?0> as Trait>::Assoc, u8)`
+// with `normalizes-to(<Vec<U> as Trait>::Assoc, u8)` in the paramenv even when
+// there is a separate `Vec<T>: Trait` bound  in the paramenv.
+//
+// FIXME(-Ztrait-solver=next)
+// This could also compile for `normalizes-to(<?0 as Trait>::Assoc, u8)` but
+// we currently immediately consider a goal ambiguous if the self type is an
+// inference variable.
+
+trait Trait {
+    type Assoc;
+}
+
+fn foo<T: Trait<Assoc = u8>>(x: T) {}
+
+#[cfg(self_infer)]
+fn unconstrained<T>() -> T {
+    todo!()
+}
+
+#[cfg(no_self_infer)]
+fn unconstrained<T>() -> Vec<T> {
+    todo!()
+}
+
+fn bar<T, U>()
+where
+    Vec<T>: Trait,
+    Vec<U>: Trait<Assoc = u8>,
+{
+    foo(unconstrained())
+    //[self_infer]~^ ERROR type annotations needed
+}
+
+fn main() {}
diff --git a/tests/ui/traits/new-solver/normalizes_to_ignores_unnormalizable_candidate.self_infer.stderr b/tests/ui/traits/new-solver/normalizes_to_ignores_unnormalizable_candidate.self_infer.stderr
new file mode 100644
index 00000000000..06283201261
--- /dev/null
+++ b/tests/ui/traits/new-solver/normalizes_to_ignores_unnormalizable_candidate.self_infer.stderr
@@ -0,0 +1,14 @@
+error[E0282]: type annotations needed
+  --> $DIR/normalizes_to_ignores_unnormalizable_candidate.rs:36:5
+   |
+LL |     foo(unconstrained())
+   |     ^^^ cannot infer type of the type parameter `T` declared on the function `foo`
+   |
+help: consider specifying the generic argument
+   |
+LL |     foo::<T>(unconstrained())
+   |        +++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/traits/new-solver/param-candidate-doesnt-shadow-project.rs b/tests/ui/traits/new-solver/param-candidate-doesnt-shadow-project.rs
new file mode 100644
index 00000000000..bdf999ec5dd
--- /dev/null
+++ b/tests/ui/traits/new-solver/param-candidate-doesnt-shadow-project.rs
@@ -0,0 +1,25 @@
+// compile-flags: -Ztrait-solver=next
+// check-pass
+
+trait Foo {
+    type Assoc;
+}
+
+trait Bar {}
+
+impl<T> Foo for T {
+    type Assoc = i32;
+}
+
+impl<T> Bar for T where T: Foo<Assoc = i32> {}
+
+fn require_bar<T: Bar>() {}
+
+fn foo<T: Foo>() {
+    // Unlike the classic solver, `<T as Foo>::Assoc = _` will still project
+    // down to `i32` even though there's a param-env candidate here, since we
+    // don't assemble any param-env projection candidates for `T: Foo` alone.
+    require_bar::<T>();
+}
+
+fn main() {}
diff --git a/tests/ui/traits/new-solver/provisional-result-done.rs b/tests/ui/traits/new-solver/provisional-result-done.rs
index 254ab356ad8..589d34dd7ab 100644
--- a/tests/ui/traits/new-solver/provisional-result-done.rs
+++ b/tests/ui/traits/new-solver/provisional-result-done.rs
@@ -1,5 +1,5 @@
-// known-bug: unknown
 // compile-flags: -Ztrait-solver=next
+// check-pass
 
 // This tests checks that we update results in the provisional cache when
 // we pop a goal from the stack.
diff --git a/tests/ui/traits/new-solver/provisional-result-done.stderr b/tests/ui/traits/new-solver/provisional-result-done.stderr
deleted file mode 100644
index 5bd0613d259..00000000000
--- a/tests/ui/traits/new-solver/provisional-result-done.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0283]: type annotations needed: cannot satisfy `Bar<T>: Coinductive`
-  --> $DIR/provisional-result-done.rs:16:25
-   |
-LL | impl<T> Coinductive for Bar<T>
-   |                         ^^^^^^
-   |
-   = note: cannot satisfy `Bar<T>: Coinductive`
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/traits/new-solver/two-projection-param-candidates-are-ambiguous.rs b/tests/ui/traits/new-solver/two-projection-param-candidates-are-ambiguous.rs
new file mode 100644
index 00000000000..cde2059ca9b
--- /dev/null
+++ b/tests/ui/traits/new-solver/two-projection-param-candidates-are-ambiguous.rs
@@ -0,0 +1,30 @@
+// compile-flags: -Ztrait-solver=next
+
+// When we're solving `<T as Foo>::Assoc = i32`, we actually first solve
+// `<T as Foo>::Assoc = _#1t`, then unify `_#1t` with `i32`. That goal
+// with the inference variable is ambiguous when there are >1 param-env
+// candidates.
+
+// We don't unify the RHS of a projection goal eagerly when solving, both
+// for caching reasons and partly to make sure that we don't make the new
+// trait solver smarter than it should be.
+
+// This is (as far as I can tell) a forwards-compatible decision, but if you
+// make this test go from fail to pass, be sure you understand the implications!
+
+trait Foo {
+    type Assoc;
+}
+
+trait Bar {}
+
+impl<T> Bar for T where T: Foo<Assoc = i32> {}
+
+fn needs_bar<T: Bar>() {}
+
+fn foo<T: Foo<Assoc = i32> + Foo<Assoc = u32>>() {
+    needs_bar::<T>();
+    //~^ ERROR type annotations needed: cannot satisfy `T: Bar`
+}
+
+fn main() {}
diff --git a/tests/ui/traits/new-solver/two-projection-param-candidates-are-ambiguous.stderr b/tests/ui/traits/new-solver/two-projection-param-candidates-are-ambiguous.stderr
new file mode 100644
index 00000000000..fa5e780ee5e
--- /dev/null
+++ b/tests/ui/traits/new-solver/two-projection-param-candidates-are-ambiguous.stderr
@@ -0,0 +1,16 @@
+error[E0283]: type annotations needed: cannot satisfy `T: Bar`
+  --> $DIR/two-projection-param-candidates-are-ambiguous.rs:26:5
+   |
+LL |     needs_bar::<T>();
+   |     ^^^^^^^^^^^^^^
+   |
+   = note: cannot satisfy `T: Bar`
+note: required by a bound in `needs_bar`
+  --> $DIR/two-projection-param-candidates-are-ambiguous.rs:23:17
+   |
+LL | fn needs_bar<T: Bar>() {}
+   |                 ^^^ required by this bound in `needs_bar`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs b/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs
index d3e169a70d3..cdd8f6f1976 100644
--- a/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs
+++ b/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs
@@ -4,7 +4,7 @@ fn main() {
     let y = 42;
     let x = wrong_generic(&y);
     let z: i32 = x;
-    //~^ ERROR expected generic type parameter, found `&'static i32
+    //~^ ERROR expected generic type parameter, found `&i32`
 }
 
 type WrongGeneric<T> = impl 'static;
diff --git a/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr b/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr
index 19115fd2866..fa79e51e9f7 100644
--- a/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr
+++ b/tests/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.stderr
@@ -4,7 +4,7 @@ error: at least one trait must be specified
 LL | type WrongGeneric<T> = impl 'static;
    |                        ^^^^^^^^^^^^
 
-error[E0792]: expected generic type parameter, found `&'static i32`
+error[E0792]: expected generic type parameter, found `&i32`
   --> $DIR/generic_type_does_not_live_long_enough.rs:6:18
    |
 LL |     let z: i32 = x;
diff --git a/tests/ui/type/type-check/cannot_infer_local_or_vec.stderr b/tests/ui/type/type-check/cannot_infer_local_or_vec.stderr
index b63d2a3b61c..09c4b2053b2 100644
--- a/tests/ui/type/type-check/cannot_infer_local_or_vec.stderr
+++ b/tests/ui/type/type-check/cannot_infer_local_or_vec.stderr
@@ -1,12 +1,12 @@
-error[E0282]: type annotations needed for `Vec<T>`
+error[E0282]: type annotations needed for `Vec<_>`
   --> $DIR/cannot_infer_local_or_vec.rs:2:9
    |
 LL |     let x = vec![];
    |         ^
    |
-help: consider giving `x` an explicit type, where the type for type parameter `T` is specified
+help: consider giving `x` an explicit type, where the placeholders `_` are specified
    |
-LL |     let x: Vec<T> = vec![];
+LL |     let x: Vec<_> = vec![];
    |          ++++++++
 
 error: aborting due to previous error
diff --git a/tests/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr b/tests/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr
index e544b369515..1fa253052e6 100644
--- a/tests/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr
+++ b/tests/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr
@@ -1,12 +1,12 @@
-error[E0282]: type annotations needed for `(Vec<T>,)`
+error[E0282]: type annotations needed for `(Vec<_>,)`
   --> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:9
    |
 LL |     let (x, ) = (vec![], );
    |         ^^^^^   ---------- type must be known at this point
    |
-help: consider giving this pattern a type, where the type for type parameter `T` is specified
+help: consider giving this pattern a type, where the placeholders `_` are specified
    |
-LL |     let (x, ): (Vec<T>,) = (vec![], );
+LL |     let (x, ): (Vec<_>,) = (vec![], );
    |              +++++++++++
 
 error: aborting due to previous error
diff --git a/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.rs b/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.rs
index 4fcf8f403bb..0be5127dcc4 100644
--- a/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.rs
+++ b/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.rs
@@ -13,5 +13,5 @@ pub struct Ref<'a>(&'a u8);
 impl Trait for Ref {} //~ ERROR:  implicit elided lifetime not allowed here
 
 extern "C" {
-    pub fn repro(_: Wrapper<Ref>); //~ ERROR: incompatible lifetime on type
+    pub fn repro(_: Wrapper<Ref>);
 }
diff --git a/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr b/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr
index 94f6dc26624..b10856571a6 100644
--- a/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr
+++ b/tests/ui/wf/wf-in-foreign-fn-decls-issue-80468.stderr
@@ -4,34 +4,11 @@ error[E0726]: implicit elided lifetime not allowed here
 LL | impl Trait for Ref {}
    |                ^^^ expected lifetime parameter
    |
-   = note: assuming a `'static` lifetime...
 help: indicate the anonymous lifetime
    |
 LL | impl Trait for Ref<'_> {}
    |                   ++++
 
-error: incompatible lifetime on type
-  --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:16:21
-   |
-LL |     pub fn repro(_: Wrapper<Ref>);
-   |                     ^^^^^^^^^^^^
-   |
-note: because this has an unmet lifetime requirement
-  --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:8:23
-   |
-LL | pub struct Wrapper<T: Trait>(T);
-   |                       ^^^^^ introduces a `'static` lifetime requirement
-note: the anonymous lifetime as defined here...
-  --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:16:29
-   |
-LL |     pub fn repro(_: Wrapper<Ref>);
-   |                             ^^^
-note: ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
-  --> $DIR/wf-in-foreign-fn-decls-issue-80468.rs:13:1
-   |
-LL | impl Trait for Ref {}
-   | ^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
 
 For more information about this error, try `rustc --explain E0726`.