about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/clippy_dev.yml3
-rw-r--r--.github/workflows/clippy_mq.yml10
-rw-r--r--.github/workflows/clippy_pr.yml3
-rw-r--r--.github/workflows/deploy.yml10
-rw-r--r--.github/workflows/lintcheck.yml8
-rw-r--r--.github/workflows/remark.yml3
-rw-r--r--CHANGELOG.md46
-rw-r--r--book/src/development/infrastructure/changelog_update.md5
-rw-r--r--clippy_lints/src/attrs/mixed_attributes_style.rs2
-rw-r--r--clippy_lints/src/declared_lints.rs1
-rw-r--r--clippy_lints/src/eta_reduction.rs2
-rw-r--r--clippy_lints/src/len_zero.rs39
-rw-r--r--clippy_lints/src/manual_ignore_case_cmp.rs2
-rw-r--r--clippy_lints/src/matches/redundant_pattern_match.rs8
-rw-r--r--clippy_lints/src/methods/double_ended_iterator_last.rs41
-rw-r--r--clippy_lints/src/methods/mod.rs29
-rw-r--r--clippy_lints/src/methods/needless_character_iteration.rs3
-rw-r--r--clippy_lints/src/methods/read_line_without_trim.rs3
-rw-r--r--clippy_lints/src/methods/unnecessary_to_owned.rs2
-rw-r--r--clippy_lints/src/missing_const_for_fn.rs9
-rw-r--r--clippy_lints/src/needless_arbitrary_self_type.rs7
-rw-r--r--clippy_lints/src/needless_continue.rs137
-rw-r--r--clippy_lints/src/redundant_else.rs1
-rw-r--r--clippy_lints/src/redundant_locals.rs6
-rw-r--r--clippy_lints/src/regex.rs2
-rw-r--r--clippy_lints/src/slow_vector_initialization.rs22
-rw-r--r--clippy_lints/src/transmute/transmute_undefined_repr.rs4
-rw-r--r--clippy_lints/src/unnecessary_literal_bound.rs2
-rw-r--r--clippy_lints/src/utils/internal_lints/invalid_paths.rs1
-rw-r--r--clippy_lints/src/vec.rs16
-rw-r--r--clippy_utils/src/msrvs.rs2
-rw-r--r--clippy_utils/src/paths.rs2
-rw-r--r--tests/missing-test-files.rs2
-rw-r--r--tests/ui/crashes/ice-10972-tait.rs9
-rw-r--r--tests/ui/double_ended_iterator_last.fixed53
-rw-r--r--tests/ui/double_ended_iterator_last.rs53
-rw-r--r--tests/ui/double_ended_iterator_last.stderr17
-rw-r--r--tests/ui/infinite_iter.rs2
-rw-r--r--tests/ui/iter_overeager_cloned.fixed7
-rw-r--r--tests/ui/iter_overeager_cloned.rs7
-rw-r--r--tests/ui/iter_overeager_cloned.stderr38
-rw-r--r--tests/ui/len_zero.fixed22
-rw-r--r--tests/ui/len_zero.rs22
-rw-r--r--tests/ui/len_zero.stderr42
-rw-r--r--tests/ui/missing_const_for_fn/cant_be_const.rs29
-rw-r--r--tests/ui/needless_arbitrary_self_type.fixed5
-rw-r--r--tests/ui/needless_arbitrary_self_type.rs5
-rw-r--r--tests/ui/needless_arbitrary_self_type.stderr14
-rw-r--r--tests/ui/needless_continue.rs65
-rw-r--r--tests/ui/needless_continue.stderr80
-rw-r--r--tests/ui/redundant_pattern_matching_option.fixed8
-rw-r--r--tests/ui/redundant_pattern_matching_option.rs8
-rw-r--r--tests/ui/redundant_pattern_matching_option.stderr8
-rw-r--r--tests/ui/slow_vector_initialization.rs26
-rw-r--r--tests/ui/slow_vector_initialization.stderr143
-rw-r--r--tests/ui/starts_ends_with.fixed2
-rw-r--r--tests/ui/starts_ends_with.rs2
-rw-r--r--tests/ui/useless_vec.rs15
-rw-r--r--tests/ui/useless_vec.stderr21
59 files changed, 929 insertions, 207 deletions
diff --git a/.github/workflows/clippy_dev.yml b/.github/workflows/clippy_dev.yml
index bcb3193ad67..d6534fbaff9 100644
--- a/.github/workflows/clippy_dev.yml
+++ b/.github/workflows/clippy_dev.yml
@@ -17,6 +17,9 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     # Run
     - name: Build
diff --git a/.github/workflows/clippy_mq.yml b/.github/workflows/clippy_mq.yml
index 49622048050..078a278e21a 100644
--- a/.github/workflows/clippy_mq.yml
+++ b/.github/workflows/clippy_mq.yml
@@ -23,6 +23,8 @@ jobs:
       uses: actions/checkout@v4
       with:
         ref: ${{ github.ref }}
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     # Run
     - name: Check Changelog
@@ -63,6 +65,8 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        persist-credentials: false
 
     - name: Install i686 dependencies
       if: matrix.host == 'i686-unknown-linux-gnu'
@@ -121,6 +125,8 @@ jobs:
      # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        persist-credentials: false
 
     - name: Install toolchain
       run: rustup show active-toolchain
@@ -136,6 +142,8 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        persist-credentials: false
 
     - name: Install toolchain
       run: rustup show active-toolchain
@@ -188,6 +196,8 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        persist-credentials: false
 
     - name: Install toolchain
       run: rustup show active-toolchain
diff --git a/.github/workflows/clippy_pr.yml b/.github/workflows/clippy_pr.yml
index 2e5b5bd41df..9e7adc2a5c3 100644
--- a/.github/workflows/clippy_pr.yml
+++ b/.github/workflows/clippy_pr.yml
@@ -25,6 +25,9 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     - name: Install toolchain
       run: rustup show active-toolchain
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 32dc251c836..b42f3e7712f 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -22,19 +22,27 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     - name: Checkout
       uses: actions/checkout@v4
       with:
         ref: ${{ env.TARGET_BRANCH }}
         path: 'out'
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     # Run
     - name: Set tag name
       if: startswith(github.ref, 'refs/tags/')
       run: |
-        TAG=$(basename ${{ github.ref }})
+        TAG=$(basename "${TAGNAME}")
         echo "TAG_NAME=$TAG" >> $GITHUB_ENV
+      env:
+        # Make sure that the reference gets expanded before injecting it
+        TAGNAME: ${{ github.ref }}
     - name: Set beta to true
       if: github.ref == 'refs/heads/beta'
       run: echo "BETA=true" >> $GITHUB_ENV
diff --git a/.github/workflows/lintcheck.yml b/.github/workflows/lintcheck.yml
index 3cbda0b3824..64966f1d189 100644
--- a/.github/workflows/lintcheck.yml
+++ b/.github/workflows/lintcheck.yml
@@ -21,6 +21,8 @@ jobs:
       uses: actions/checkout@v4
       with:
         fetch-depth: 2
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     # HEAD is the generated merge commit `refs/pull/N/merge` between the PR and `master`, `HEAD^`
     # being the commit from `master` that is the base of the merge
@@ -73,6 +75,9 @@ jobs:
     steps:
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     - name: Cache lintcheck bin
       id: cache-lintcheck-bin
@@ -103,6 +108,9 @@ jobs:
     steps:
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     - name: Restore lintcheck bin
       uses: actions/cache/restore@v4
diff --git a/.github/workflows/remark.yml b/.github/workflows/remark.yml
index 0d402fe7064..69d00dc027e 100644
--- a/.github/workflows/remark.yml
+++ b/.github/workflows/remark.yml
@@ -12,6 +12,9 @@ jobs:
     # Setup
     - name: Checkout
       uses: actions/checkout@v4
+      with:
+        # Unsetting this would make so that any malicious package could get our Github Token
+        persist-credentials: false
 
     - name: Setup Node.js
       uses: actions/setup-node@v4
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 664a7e76630..1770e8095a0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,11 +6,52 @@ document.
 
 ## Unreleased / Beta / In Rust Nightly
 
-[aa0d5513...master](https://github.com/rust-lang/rust-clippy/compare/aa0d5513...master)
+[786fbd6d...master](https://github.com/rust-lang/rust-clippy/compare/786fbd6d...master)
+
+## Rust 1.84
+
+Current stable, released 2025-01-09
+
+[View all 84 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-10-03T21%3A23%3A58Z..2024-11-14T17%3A41%3A37Z+base%3Amaster)
+
+### New Lints
+
+* Added [`unnecessary_map_or`] to `style`
+  [#11796](https://github.com/rust-lang/rust-clippy/pull/11796)
+* Added [`arbitrary_source_item_ordering`] to `restriction`
+  [#13376](https://github.com/rust-lang/rust-clippy/pull/13376)
+* Added [`map_with_unused_argument_over_ranges`] to `restriction`
+  [#13034](https://github.com/rust-lang/rust-clippy/pull/13034)
+* Added [`map_all_any_identity`] to `complexity`
+  [#13499](https://github.com/rust-lang/rust-clippy/pull/13499)
+* Added [`needless_as_bytes`] to `complexity`
+  [#13437](https://github.com/rust-lang/rust-clippy/pull/13437)
+* Added [`unnecessary_literal_bound`] to `pedantic`
+  [#13395](https://github.com/rust-lang/rust-clippy/pull/13395)
+* Added [`manual_ignore_case_cmp`] to `perf`
+  [#13334](https://github.com/rust-lang/rust-clippy/pull/13334)
+* Added [`regex_creation_in_loops`] to `perf`
+  [#13412](https://github.com/rust-lang/rust-clippy/pull/13412)
+
+### Moves and Deprecations
+
+* Moved [`manual_is_power_of_two`] to `pedantic` (From `complexity`, now allow-by-default)
+  [#13553](https://github.com/rust-lang/rust-clippy/pull/13553)
+* Move [`module_name_repetitions`] to `restriction` (from `pedantic`)
+  [#13541](https://github.com/rust-lang/rust-clippy/pull/13541)
+
+### Enhancements
+
+* [`doc_markdown`]: Added the following identifiers to [`doc-valid-idents`]:
+  CoAP, MHz, GHz, and THz
+  [#13633](https://github.com/rust-lang/rust-clippy/pull/13633)
+  [#13460](https://github.com/rust-lang/rust-clippy/pull/13460)
+* [`large_const_arrays`]: Changed the default of [`array-size-threshold`] to `16kb` (from `512kb`)
+  [#13485](https://github.com/rust-lang/rust-clippy/pull/13485)
 
 ## Rust 1.83
 
-Current stable, released 2024-11-28
+Released 2024-11-28
 
 [View all 64 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-08-25T09%3A59%3A01Z..2024-10-03T13%3A42%3A56Z+base%3Amaster)
 
@@ -5493,6 +5534,7 @@ Released 2018-09-13
 [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
 [`doc_nested_refdefs`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_nested_refdefs
 [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
+[`double_ended_iterator_last`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_ended_iterator_last
 [`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use
 [`double_neg`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_neg
 [`double_parens`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_parens
diff --git a/book/src/development/infrastructure/changelog_update.md b/book/src/development/infrastructure/changelog_update.md
index df9b1bbe18f..2b2c096b049 100644
--- a/book/src/development/infrastructure/changelog_update.md
+++ b/book/src/development/infrastructure/changelog_update.md
@@ -83,7 +83,12 @@ As section headers, we use:
 
 ```
 ### New Lints
+* Added [`LINT`] to `GROUP`
+
 ### Moves and Deprecations
+* Moved [`LINT`] to `GROUP` (From `GROUP`, now LEVEL-by-default)
+* Renamed `LINT` to [`LINT`]
+
 ### Enhancements
 ### False Positive Fixes
 ### Suggestion Fixes/Improvements
diff --git a/clippy_lints/src/attrs/mixed_attributes_style.rs b/clippy_lints/src/attrs/mixed_attributes_style.rs
index 32c28c09c36..8c91c65eaf7 100644
--- a/clippy_lints/src/attrs/mixed_attributes_style.rs
+++ b/clippy_lints/src/attrs/mixed_attributes_style.rs
@@ -66,7 +66,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item_span: Span, attrs: &[Attribute])
 
 fn lint_mixed_attrs(cx: &EarlyContext<'_>, attrs: &[Attribute]) {
     let mut attrs_iter = attrs.iter().filter(|attr| !attr.span.from_expansion());
-    let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.last()) {
+    let span = if let (Some(first), Some(last)) = (attrs_iter.next(), attrs_iter.next_back()) {
         first.span.with_hi(last.span.hi())
     } else {
         return;
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index 7451fb909ef..3ff10d850f8 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -372,6 +372,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::methods::CLONE_ON_REF_PTR_INFO,
     crate::methods::COLLAPSIBLE_STR_REPLACE_INFO,
     crate::methods::CONST_IS_EMPTY_INFO,
+    crate::methods::DOUBLE_ENDED_ITERATOR_LAST_INFO,
     crate::methods::DRAIN_COLLECT_INFO,
     crate::methods::ERR_EXPECT_INFO,
     crate::methods::EXPECT_FUN_CALL_INFO,
diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs
index 2cd48ef98e5..c0b4743fd71 100644
--- a/clippy_lints/src/eta_reduction.rs
+++ b/clippy_lints/src/eta_reduction.rs
@@ -182,7 +182,7 @@ fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tc
                 // will succeed iff `T: 'static`. But the region of `T` is always erased by `typeck.expr_ty()` when
                 // T is a generic type. For example, return type of `Option<String>::as_deref()` is a generic.
                 // So we have a hack like this.
-                && generic_args.len() > 0
+                && !generic_args.is_empty()
             {
                 return;
             }
diff --git a/clippy_lints/src/len_zero.rs b/clippy_lints/src/len_zero.rs
index 3ea758e176f..fb93a195b83 100644
--- a/clippy_lints/src/len_zero.rs
+++ b/clippy_lints/src/len_zero.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::source::{SpanRangeExt, snippet_with_context};
 use clippy_utils::sugg::{Sugg, has_enclosing_paren};
+use clippy_utils::ty::implements_trait;
 use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, is_trait_method, peel_ref_operators};
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -620,18 +621,30 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
         })
     }
 
-    let ty = &cx.typeck_results().expr_ty(expr).peel_refs();
-    match ty.kind() {
-        ty::Dynamic(tt, ..) => tt.principal().is_some_and(|principal| {
-            let is_empty = sym!(is_empty);
-            cx.tcx
-                .associated_items(principal.def_id())
-                .filter_by_name_unhygienic(is_empty)
-                .any(|item| is_is_empty(cx, item))
-        }),
-        ty::Alias(ty::Projection, proj) => has_is_empty_impl(cx, proj.def_id),
-        ty::Adt(id, _) => has_is_empty_impl(cx, id.did()),
-        ty::Array(..) | ty::Slice(..) | ty::Str => true,
-        _ => false,
+    fn ty_has_is_empty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, depth: usize) -> bool {
+        match ty.kind() {
+            ty::Dynamic(tt, ..) => tt.principal().is_some_and(|principal| {
+                let is_empty = sym!(is_empty);
+                cx.tcx
+                    .associated_items(principal.def_id())
+                    .filter_by_name_unhygienic(is_empty)
+                    .any(|item| is_is_empty(cx, item))
+            }),
+            ty::Alias(ty::Projection, proj) => has_is_empty_impl(cx, proj.def_id),
+            ty::Adt(id, _) => {
+                has_is_empty_impl(cx, id.did())
+                    || (cx.tcx.recursion_limit().value_within_limit(depth)
+                        && cx.tcx.get_diagnostic_item(sym::Deref).is_some_and(|deref_id| {
+                            implements_trait(cx, ty, deref_id, &[])
+                                && cx
+                                    .get_associated_type(ty, deref_id, "Target")
+                                    .is_some_and(|deref_ty| ty_has_is_empty(cx, deref_ty, depth + 1))
+                        }))
+            },
+            ty::Array(..) | ty::Slice(..) | ty::Str => true,
+            _ => false,
+        }
     }
+
+    ty_has_is_empty(cx, cx.typeck_results().expr_ty(expr).peel_refs(), 0)
 }
diff --git a/clippy_lints/src/manual_ignore_case_cmp.rs b/clippy_lints/src/manual_ignore_case_cmp.rs
index dabfac3f613..506f4f6d9de 100644
--- a/clippy_lints/src/manual_ignore_case_cmp.rs
+++ b/clippy_lints/src/manual_ignore_case_cmp.rs
@@ -32,7 +32,7 @@ declare_clippy_lint! {
     ///    a.eq_ignore_ascii_case(b) || a.eq_ignore_ascii_case("abc")
     /// }
     /// ```
-    #[clippy::version = "1.82.0"]
+    #[clippy::version = "1.84.0"]
     pub MANUAL_IGNORE_CASE_CMP,
     perf,
     "manual case-insensitive ASCII comparison"
diff --git a/clippy_lints/src/matches/redundant_pattern_match.rs b/clippy_lints/src/matches/redundant_pattern_match.rs
index 264458a86ef..897e3f5f7f2 100644
--- a/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -1,6 +1,6 @@
 use super::REDUNDANT_PATTERN_MATCHING;
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::source::{snippet, walk_span_to_context};
+use clippy_utils::source::walk_span_to_context;
 use clippy_utils::sugg::{Sugg, make_unop};
 use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop};
 use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr_without_closures};
@@ -274,7 +274,9 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
                 ExprKind::AddrOf(_, _, borrowed) => borrowed,
                 _ => op,
             };
-            let mut sugg = format!("{}.{good_method}", snippet(cx, result_expr.span, "_"));
+            let mut app = Applicability::MachineApplicable;
+            let receiver_sugg = Sugg::hir_with_applicability(cx, result_expr, "_", &mut app).maybe_par();
+            let mut sugg = format!("{receiver_sugg}.{good_method}");
 
             if let Some(guard) = maybe_guard {
                 // wow, the HIR for match guards in `PAT if let PAT = expr && expr => ...` is annoying!
@@ -307,7 +309,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
                 format!("redundant pattern matching, consider using `{good_method}`"),
                 "try",
                 sugg,
-                Applicability::MachineApplicable,
+                app,
             );
         }
     }
diff --git a/clippy_lints/src/methods/double_ended_iterator_last.rs b/clippy_lints/src/methods/double_ended_iterator_last.rs
new file mode 100644
index 00000000000..208172980c9
--- /dev/null
+++ b/clippy_lints/src/methods/double_ended_iterator_last.rs
@@ -0,0 +1,41 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_trait_method;
+use clippy_utils::ty::implements_trait;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_lint::LateContext;
+use rustc_middle::ty::Instance;
+use rustc_span::{Span, sym};
+
+use super::DOUBLE_ENDED_ITERATOR_LAST;
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Expr<'_>, call_span: Span) {
+    let typeck = cx.typeck_results();
+
+    // if the "last" method is that of Iterator
+    if is_trait_method(cx, expr, sym::Iterator)
+        // if self implements DoubleEndedIterator
+        && let Some(deiter_id) = cx.tcx.get_diagnostic_item(sym::DoubleEndedIterator)
+        && let self_type = cx.typeck_results().expr_ty(self_expr)
+        && implements_trait(cx, self_type.peel_refs(), deiter_id, &[])
+        // resolve the method definition
+        && let id = typeck.type_dependent_def_id(expr.hir_id).unwrap()
+        && let args = typeck.node_args(expr.hir_id)
+        && let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args)
+        // find the provided definition of Iterator::last
+        && let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator)
+        && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name.as_str() == "last")
+        // if the resolved method is the same as the provided definition
+        && fn_def.def_id() == last_def.def_id
+    {
+        span_lint_and_sugg(
+            cx,
+            DOUBLE_ENDED_ITERATOR_LAST,
+            call_span,
+            "called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator",
+            "try",
+            "next_back()".to_string(),
+            Applicability::MachineApplicable,
+        );
+    }
+}
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 810287fa541..51351f6b7cd 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -14,6 +14,7 @@ mod clone_on_copy;
 mod clone_on_ref_ptr;
 mod cloned_instead_of_copied;
 mod collapsible_str_replace;
+mod double_ended_iterator_last;
 mod drain_collect;
 mod err_expect;
 mod expect_fun_call;
@@ -4284,6 +4285,32 @@ declare_clippy_lint! {
     "map of a trivial closure (not dependent on parameter) over a range"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Checks for `Iterator::last` being called on a  `DoubleEndedIterator`, which can be replaced
+    /// with `DoubleEndedIterator::next_back`.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// `Iterator::last` is implemented by consuming the iterator, which is unnecessary if
+    /// the iterator is a `DoubleEndedIterator`. Since Rust traits do not allow specialization,
+    /// `Iterator::last` cannot be optimized for `DoubleEndedIterator`.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let last_arg = "echo hello world".split(' ').last();
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let last_arg = "echo hello world".split(' ').next_back();
+    /// ```
+    #[clippy::version = "1.85.0"]
+    pub DOUBLE_ENDED_ITERATOR_LAST,
+    perf,
+    "using `Iterator::last` on a `DoubleEndedIterator`"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
@@ -4449,6 +4476,7 @@ impl_lint_pass!(Methods => [
     MAP_ALL_ANY_IDENTITY,
     MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES,
     UNNECESSARY_MAP_OR,
+    DOUBLE_ENDED_ITERATOR_LAST,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -4931,6 +4959,7 @@ impl Methods {
                             false,
                         );
                     }
+                    double_ended_iterator_last::check(cx, expr, recv, call_span);
                 },
                 ("len", []) => {
                     if let Some(("as_bytes", prev_recv, [], _, _)) = method_call(recv) {
diff --git a/clippy_lints/src/methods/needless_character_iteration.rs b/clippy_lints/src/methods/needless_character_iteration.rs
index 348f740e7dd..6993150fb57 100644
--- a/clippy_lints/src/methods/needless_character_iteration.rs
+++ b/clippy_lints/src/methods/needless_character_iteration.rs
@@ -7,6 +7,7 @@ use rustc_span::Span;
 use super::NEEDLESS_CHARACTER_ITERATION;
 use super::utils::get_last_chain_binding_hir_id;
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::paths::CHAR_IS_ASCII;
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::{match_def_path, path_to_local_id, peel_blocks};
 
@@ -77,7 +78,7 @@ fn handle_expr(
             if revert != is_all
                 && let ExprKind::Path(path) = fn_path.kind
                 && let Some(fn_def_id) = cx.qpath_res(&path, fn_path.hir_id).opt_def_id()
-                && match_def_path(cx, fn_def_id, &["core", "char", "methods", "<impl char>", "is_ascii"])
+                && match_def_path(cx, fn_def_id, &CHAR_IS_ASCII)
                 && path_to_local_id(peels_expr_ref(arg), first_param)
                 && let Some(snippet) = before_chars.get_source_text(cx)
             {
diff --git a/clippy_lints/src/methods/read_line_without_trim.rs b/clippy_lints/src/methods/read_line_without_trim.rs
index db2b9d4d92f..82e66a0500a 100644
--- a/clippy_lints/src/methods/read_line_without_trim.rs
+++ b/clippy_lints/src/methods/read_line_without_trim.rs
@@ -1,6 +1,7 @@
 use std::ops::ControlFlow;
 
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::paths::STDIN;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::for_each_local_use_after_expr;
@@ -33,7 +34,7 @@ fn parse_fails_on_trailing_newline(ty: Ty<'_>) -> bool {
 
 pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<'_>) {
     if let Some(recv_adt) = cx.typeck_results().expr_ty(recv).ty_adt_def()
-        && match_def_path(cx, recv_adt.did(), &["std", "io", "stdio", "Stdin"])
+        && match_def_path(cx, recv_adt.did(), &STDIN)
         && let ExprKind::Path(QPath::Resolved(_, path)) = arg.peel_borrows().kind
         && let Res::Local(local_id) = path.res
     {
diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs
index d19064fd57e..a52851c9a1a 100644
--- a/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -494,7 +494,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
     for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) {
         match node {
             Node::Stmt(_) => return true,
-            Node::Block(..) => continue,
+            Node::Block(..) => {},
             Node::Item(item) => {
                 if let ItemKind::Fn(_, _, body_id) = &item.kind
                     && let output_ty = return_ty(cx, item.owner_id)
diff --git a/clippy_lints/src/missing_const_for_fn.rs b/clippy_lints/src/missing_const_for_fn.rs
index 121c4326d64..2572e186ce6 100644
--- a/clippy_lints/src/missing_const_for_fn.rs
+++ b/clippy_lints/src/missing_const_for_fn.rs
@@ -2,7 +2,7 @@ use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::qualify_min_const_fn::is_min_const_fn;
-use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method};
+use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, is_in_test, trait_ref_of_method};
 use rustc_errors::Applicability;
 use rustc_hir::def_id::CRATE_DEF_ID;
 use rustc_hir::intravisit::FnKind;
@@ -97,6 +97,11 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
         span: Span,
         def_id: LocalDefId,
     ) {
+        let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
+        if is_in_test(cx.tcx, hir_id) {
+            return;
+        }
+
         if !self.msrv.meets(msrvs::CONST_IF_MATCH) {
             return;
         }
@@ -136,8 +141,6 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
             return;
         }
 
-        let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
-
         // Const fns are not allowed as methods in a trait.
         {
             let parent = cx.tcx.hir().get_parent_item(hir_id).def_id;
diff --git a/clippy_lints/src/needless_arbitrary_self_type.rs b/clippy_lints/src/needless_arbitrary_self_type.rs
index 3c47d0edfdc..5f7fde30f03 100644
--- a/clippy_lints/src/needless_arbitrary_self_type.rs
+++ b/clippy_lints/src/needless_arbitrary_self_type.rs
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
 use rustc_ast::ast::{BindingMode, ByRef, Lifetime, Mutability, Param, PatKind, Path, TyKind};
 use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass};
@@ -80,7 +81,8 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
                     applicability = Applicability::HasPlaceholders;
                     "&'_ mut self".to_string()
                 } else {
-                    format!("&{} mut self", &lifetime.ident.name)
+                    let lt_name = snippet_with_applicability(cx, lifetime.ident.span, "..", &mut applicability);
+                    format!("&{lt_name} mut self")
                 }
             },
             (Mode::Ref(None), Mutability::Not) => "&self".to_string(),
@@ -89,7 +91,8 @@ fn check_param_inner(cx: &EarlyContext<'_>, path: &Path, span: Span, binding_mod
                     applicability = Applicability::HasPlaceholders;
                     "&'_ self".to_string()
                 } else {
-                    format!("&{} self", &lifetime.ident.name)
+                    let lt_name = snippet_with_applicability(cx, lifetime.ident.span, "..", &mut applicability);
+                    format!("&{lt_name} self")
                 }
             },
             (Mode::Value, Mutability::Mut) => "mut self".to_string(),
diff --git a/clippy_lints/src/needless_continue.rs b/clippy_lints/src/needless_continue.rs
index a7cd29bb8e3..05b31fc84b9 100644
--- a/clippy_lints/src/needless_continue.rs
+++ b/clippy_lints/src/needless_continue.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::source::{indent_of, snippet, snippet_block};
-use rustc_ast::ast;
+use rustc_ast::{Block, Label, ast};
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_session::declare_lint_pass;
 use rustc_span::Span;
@@ -11,6 +11,7 @@ declare_clippy_lint! {
     /// that contain a `continue` statement in either their main blocks or their
     /// `else`-blocks, when omitting the `else`-block possibly with some
     /// rearrangement of code can make the code easier to understand.
+    /// The lint also checks if the last statement in the loop is a `continue`
     ///
     /// ### Why is this bad?
     /// Having explicit `else` blocks for `if` statements
@@ -75,6 +76,49 @@ declare_clippy_lint! {
     ///     # break;
     /// }
     /// ```
+    ///
+    /// ```rust
+    /// # use std::io::ErrorKind;
+    ///
+    /// fn foo() -> ErrorKind { ErrorKind::NotFound }
+    /// for _ in 0..10 {
+    ///     match foo() {
+    ///         ErrorKind::NotFound => {
+    ///             eprintln!("not found");
+    ///             continue
+    ///         }
+    ///         ErrorKind::TimedOut => {
+    ///             eprintln!("timeout");
+    ///             continue
+    ///         }
+    ///         _ => {
+    ///             eprintln!("other error");
+    ///             continue
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    /// Could be rewritten as
+    ///
+    ///
+    /// ```rust
+    /// # use std::io::ErrorKind;
+    ///
+    /// fn foo() -> ErrorKind { ErrorKind::NotFound }
+    /// for _ in 0..10 {
+    ///     match foo() {
+    ///         ErrorKind::NotFound => {
+    ///             eprintln!("not found");
+    ///         }
+    ///         ErrorKind::TimedOut => {
+    ///             eprintln!("timeout");
+    ///         }
+    ///         _ => {
+    ///             eprintln!("other error");
+    ///         }
+    ///     }
+    /// }
+    /// ```
     #[clippy::version = "pre 1.29.0"]
     pub NEEDLESS_CONTINUE,
     pedantic,
@@ -144,7 +188,7 @@ impl EarlyLintPass for NeedlessContinue {
 ///
 /// - The expression is a `continue` node.
 /// - The expression node is a block with the first statement being a `continue`.
-fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>) -> bool {
+fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&Label>) -> bool {
     match else_expr.kind {
         ast::ExprKind::Block(ref else_block, _) => is_first_block_stmt_continue(else_block, label),
         ast::ExprKind::Continue(l) => compare_labels(label, l.as_ref()),
@@ -152,7 +196,7 @@ fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>)
     }
 }
 
-fn is_first_block_stmt_continue(block: &ast::Block, label: Option<&ast::Label>) -> bool {
+fn is_first_block_stmt_continue(block: &Block, label: Option<&Label>) -> bool {
     block.stmts.first().is_some_and(|stmt| match stmt.kind {
         ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => {
             if let ast::ExprKind::Continue(ref l) = e.kind {
@@ -166,7 +210,7 @@ fn is_first_block_stmt_continue(block: &ast::Block, label: Option<&ast::Label>)
 }
 
 /// If the `continue` has a label, check it matches the label of the loop.
-fn compare_labels(loop_label: Option<&ast::Label>, continue_label: Option<&ast::Label>) -> bool {
+fn compare_labels(loop_label: Option<&Label>, continue_label: Option<&Label>) -> bool {
     match (loop_label, continue_label) {
         // `loop { continue; }` or `'a loop { continue; }`
         (_, None) => true,
@@ -181,7 +225,7 @@ fn compare_labels(loop_label: Option<&ast::Label>, continue_label: Option<&ast::
 /// the AST object representing the loop block of `expr`.
 fn with_loop_block<F>(expr: &ast::Expr, mut func: F)
 where
-    F: FnMut(&ast::Block, Option<&ast::Label>),
+    F: FnMut(&Block, Option<&Label>),
 {
     if let ast::ExprKind::While(_, loop_block, label)
     | ast::ExprKind::ForLoop {
@@ -205,7 +249,7 @@ where
 /// - The `else` expression.
 fn with_if_expr<F>(stmt: &ast::Stmt, mut func: F)
 where
-    F: FnMut(&ast::Expr, &ast::Expr, &ast::Block, &ast::Expr),
+    F: FnMut(&ast::Expr, &ast::Expr, &Block, &ast::Expr),
 {
     match stmt.kind {
         ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => {
@@ -231,14 +275,14 @@ struct LintData<'a> {
     /// The condition expression for the above `if`.
     if_cond: &'a ast::Expr,
     /// The `then` block of the `if` statement.
-    if_block: &'a ast::Block,
+    if_block: &'a Block,
     /// The `else` block of the `if` statement.
     /// Note that we only work with `if` exprs that have an `else` branch.
     else_expr: &'a ast::Expr,
     /// The 0-based index of the `if` statement in the containing loop block.
     stmt_idx: usize,
     /// The statements of the loop block.
-    loop_block: &'a ast::Block,
+    loop_block: &'a Block,
 }
 
 const MSG_REDUNDANT_CONTINUE_EXPRESSION: &str = "this `continue` expression is redundant";
@@ -329,24 +373,63 @@ fn suggestion_snippet_for_continue_inside_else(cx: &EarlyContext<'_>, data: &Lin
     )
 }
 
-fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
-    if let ast::ExprKind::Loop(loop_block, loop_label, ..) = &expr.kind
-        && let Some(last_stmt) = loop_block.stmts.last()
+fn check_last_stmt_in_expr<F>(inner_expr: &ast::Expr, func: &F)
+where
+    F: Fn(Option<&Label>, Span),
+{
+    match &inner_expr.kind {
+        ast::ExprKind::Continue(continue_label) => {
+            func(continue_label.as_ref(), inner_expr.span);
+        },
+        ast::ExprKind::If(_, then_block, else_block) => {
+            check_last_stmt_in_block(then_block, func);
+            if let Some(else_block) = else_block {
+                check_last_stmt_in_expr(else_block, func);
+            }
+        },
+        ast::ExprKind::Match(_, arms, _) => {
+            for arm in arms {
+                if let Some(expr) = &arm.body {
+                    check_last_stmt_in_expr(expr, func);
+                }
+            }
+        },
+        ast::ExprKind::Block(b, _) => {
+            check_last_stmt_in_block(b, func);
+        },
+        _ => {},
+    }
+}
+
+fn check_last_stmt_in_block<F>(b: &Block, func: &F)
+where
+    F: Fn(Option<&Label>, Span),
+{
+    if let Some(last_stmt) = b.stmts.last()
         && let ast::StmtKind::Expr(inner_expr) | ast::StmtKind::Semi(inner_expr) = &last_stmt.kind
-        && let ast::ExprKind::Continue(continue_label) = inner_expr.kind
-        && compare_labels(loop_label.as_ref(), continue_label.as_ref())
     {
-        span_lint_and_help(
-            cx,
-            NEEDLESS_CONTINUE,
-            last_stmt.span,
-            MSG_REDUNDANT_CONTINUE_EXPRESSION,
-            None,
-            DROP_CONTINUE_EXPRESSION_MSG,
-        );
+        check_last_stmt_in_expr(inner_expr, func);
     }
+}
+
+fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
     with_loop_block(expr, |loop_block, label| {
-        for (i, stmt) in loop_block.stmts.iter().enumerate() {
+        let p = |continue_label: Option<&Label>, span: Span| {
+            if compare_labels(label, continue_label) {
+                span_lint_and_help(
+                    cx,
+                    NEEDLESS_CONTINUE,
+                    span,
+                    MSG_REDUNDANT_CONTINUE_EXPRESSION,
+                    None,
+                    DROP_CONTINUE_EXPRESSION_MSG,
+                );
+            }
+        };
+
+        let stmts = &loop_block.stmts;
+        for (i, stmt) in stmts.iter().enumerate() {
+            let mut maybe_emitted_in_if = false;
             with_if_expr(stmt, |if_expr, cond, then_block, else_expr| {
                 let data = &LintData {
                     if_expr,
@@ -356,6 +439,8 @@ fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
                     stmt_idx: i,
                     loop_block,
                 };
+
+                maybe_emitted_in_if = true;
                 if needless_continue_in_else(else_expr, label) {
                     emit_warning(
                         cx,
@@ -365,8 +450,14 @@ fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
                     );
                 } else if is_first_block_stmt_continue(then_block, label) {
                     emit_warning(cx, data, DROP_ELSE_BLOCK_MSG, LintType::ContinueInsideThenBlock);
+                } else {
+                    maybe_emitted_in_if = false;
                 }
             });
+
+            if i == stmts.len() - 1 && !maybe_emitted_in_if {
+                check_last_stmt_in_block(loop_block, &p);
+            }
         }
     });
 }
@@ -400,7 +491,7 @@ fn erode_from_back(s: &str) -> String {
     if ret.is_empty() { s.to_string() } else { ret }
 }
 
-fn span_of_first_expr_in_block(block: &ast::Block) -> Option<Span> {
+fn span_of_first_expr_in_block(block: &Block) -> Option<Span> {
     block.stmts.first().map(|stmt| stmt.span)
 }
 
diff --git a/clippy_lints/src/redundant_else.rs b/clippy_lints/src/redundant_else.rs
index 6a1d40334e7..a27f9b63114 100644
--- a/clippy_lints/src/redundant_else.rs
+++ b/clippy_lints/src/redundant_else.rs
@@ -69,7 +69,6 @@ impl EarlyLintPass for RedundantElse {
                 ExprKind::If(_, next_then, Some(next_els)) => {
                     then = next_then;
                     els = next_els;
-                    continue;
                 },
                 // else if without else
                 ExprKind::If(..) => return,
diff --git a/clippy_lints/src/redundant_locals.rs b/clippy_lints/src/redundant_locals.rs
index 4f46ca3c715..658d93e634c 100644
--- a/clippy_lints/src/redundant_locals.rs
+++ b/clippy_lints/src/redundant_locals.rs
@@ -17,9 +17,9 @@ declare_clippy_lint! {
     /// Checks for redundant redefinitions of local bindings.
     ///
     /// ### Why is this bad?
-    /// Redundant redefinitions of local bindings do not change behavior and are likely to be unintended.
+    /// Redundant redefinitions of local bindings do not change behavior other than variable's lifetimes and are likely to be unintended.
     ///
-    /// Note that although these bindings do not affect your code's meaning, they _may_ affect `rustc`'s stack allocation.
+    /// These rebindings can be intentional to shorten the lifetimes of variables because they affect when the `Drop` implementation is called. Other than that, they do not affect your code's meaning but they _may_ affect `rustc`'s stack allocation.
     ///
     /// ### Example
     /// ```no_run
@@ -41,7 +41,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.73.0"]
     pub REDUNDANT_LOCALS,
-    correctness,
+    suspicious,
     "redundant redefinition of a local binding"
 }
 declare_lint_pass!(RedundantLocals => [REDUNDANT_LOCALS]);
diff --git a/clippy_lints/src/regex.rs b/clippy_lints/src/regex.rs
index 2f77989b379..9443dca154e 100644
--- a/clippy_lints/src/regex.rs
+++ b/clippy_lints/src/regex.rs
@@ -97,7 +97,7 @@ declare_clippy_lint! {
     ///     }
     /// }
     /// ```
-    #[clippy::version = "1.83.0"]
+    #[clippy::version = "1.84.0"]
     pub REGEX_CREATION_IN_LOOPS,
     perf,
     "regular expression compilation performed in a loop"
diff --git a/clippy_lints/src/slow_vector_initialization.rs b/clippy_lints/src/slow_vector_initialization.rs
index 8c8f11569c8..d2d693eaa1f 100644
--- a/clippy_lints/src/slow_vector_initialization.rs
+++ b/clippy_lints/src/slow_vector_initialization.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::macros::matching_root_macro_call;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
@@ -203,14 +203,18 @@ impl SlowVectorInit {
             "len",
         );
 
-        span_lint_and_then(cx, SLOW_VECTOR_INITIALIZATION, slow_fill.span, msg, |diag| {
-            diag.span_suggestion(
-                vec_alloc.allocation_expr.span.source_callsite(),
-                "consider replacing this with",
-                format!("vec![0; {len_expr}]"),
-                Applicability::Unspecified,
-            );
-        });
+        let span_to_replace = slow_fill
+            .span
+            .with_lo(vec_alloc.allocation_expr.span.source_callsite().lo());
+        span_lint_and_sugg(
+            cx,
+            SLOW_VECTOR_INITIALIZATION,
+            span_to_replace,
+            msg,
+            "consider replacing this with",
+            format!("vec![0; {len_expr}]"),
+            Applicability::Unspecified,
+        );
     }
 }
 
diff --git a/clippy_lints/src/transmute/transmute_undefined_repr.rs b/clippy_lints/src/transmute/transmute_undefined_repr.rs
index 48d65eb15d9..26323af3122 100644
--- a/clippy_lints/src/transmute/transmute_undefined_repr.rs
+++ b/clippy_lints/src/transmute/transmute_undefined_repr.rs
@@ -30,17 +30,14 @@ pub(super) fn check<'tcx>(
             | (ReducedTy::UnorderedFields(from_sub_ty), ReducedTy::OrderedFields(Some(to_sub_ty))) => {
                 from_ty = from_sub_ty;
                 to_ty = to_sub_ty;
-                continue;
             },
             (ReducedTy::OrderedFields(Some(from_sub_ty)), ReducedTy::Other(to_sub_ty)) if reduced_tys.to_fat_ptr => {
                 from_ty = from_sub_ty;
                 to_ty = to_sub_ty;
-                continue;
             },
             (ReducedTy::Other(from_sub_ty), ReducedTy::OrderedFields(Some(to_sub_ty))) if reduced_tys.from_fat_ptr => {
                 from_ty = from_sub_ty;
                 to_ty = to_sub_ty;
-                continue;
             },
 
             // ptr <-> ptr
@@ -50,7 +47,6 @@ pub(super) fn check<'tcx>(
             {
                 from_ty = from_sub_ty;
                 to_ty = to_sub_ty;
-                continue;
             },
 
             // fat ptr <-> (*size, *size)
diff --git a/clippy_lints/src/unnecessary_literal_bound.rs b/clippy_lints/src/unnecessary_literal_bound.rs
index 8165a45bc5b..9f107fbeec0 100644
--- a/clippy_lints/src/unnecessary_literal_bound.rs
+++ b/clippy_lints/src/unnecessary_literal_bound.rs
@@ -47,7 +47,7 @@ declare_clippy_lint! {
     ///     }
     /// }
     /// ```
-    #[clippy::version = "1.83.0"]
+    #[clippy::version = "1.84.0"]
     pub UNNECESSARY_LITERAL_BOUND,
     pedantic,
     "detects &str that could be &'static str in function return types"
diff --git a/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/clippy_lints/src/utils/internal_lints/invalid_paths.rs
index a5fad68eea1..08c178ed229 100644
--- a/clippy_lints/src/utils/internal_lints/invalid_paths.rs
+++ b/clippy_lints/src/utils/internal_lints/invalid_paths.rs
@@ -73,6 +73,7 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
         SimplifiedType::Slice,
         SimplifiedType::Str,
         SimplifiedType::Bool,
+        SimplifiedType::Char,
     ]
     .iter()
     .flat_map(|&ty| cx.tcx.incoherent_impls(ty).iter())
diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs
index ef1c46154d2..0730b561bc2 100644
--- a/clippy_lints/src/vec.rs
+++ b/clippy_lints/src/vec.rs
@@ -8,7 +8,7 @@ use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::ty::is_copy;
 use clippy_utils::visitors::for_each_local_use_after_expr;
-use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method};
+use clippy_utils::{get_parent_expr, higher, is_in_test, is_trait_method, span_contains_comment};
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, HirId, LetStmt, Mutability, Node, Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -132,9 +132,19 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
     fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
         for (span, lint_opt) in &self.span_to_lint_map {
             if let Some((hir_id, suggest_slice, snippet, applicability)) = lint_opt {
-                let help_msg = format!("you can use {} directly", suggest_slice.desc(),);
+                let help_msg = format!("you can use {} directly", suggest_slice.desc());
                 span_lint_hir_and_then(cx, USELESS_VEC, *hir_id, *span, "useless use of `vec!`", |diag| {
-                    diag.span_suggestion(*span, help_msg, snippet, *applicability);
+                    // If the `vec!` macro contains comment, better not make the suggestion machine
+                    // applicable as it would remove them.
+                    let applicability = if *applicability != Applicability::Unspecified
+                        && let source_map = cx.tcx.sess.source_map()
+                        && span_contains_comment(source_map, *span)
+                    {
+                        Applicability::Unspecified
+                    } else {
+                        *applicability
+                    };
+                    diag.span_suggestion(*span, help_msg, snippet, applicability);
                 });
             }
         }
diff --git a/clippy_utils/src/msrvs.rs b/clippy_utils/src/msrvs.rs
index 98bcedecccc..2169a5fdd63 100644
--- a/clippy_utils/src/msrvs.rs
+++ b/clippy_utils/src/msrvs.rs
@@ -130,7 +130,7 @@ impl Msrv {
         let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym_msrv]));
 
         if let Some(msrv_attr) = msrv_attrs.next() {
-            if let Some(duplicate) = msrv_attrs.last() {
+            if let Some(duplicate) = msrv_attrs.next_back() {
                 sess.dcx()
                     .struct_span_err(duplicate.span(), "`clippy::msrv` is defined multiple times")
                     .with_span_note(msrv_attr.span(), "first definition found here")
diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs
index 8cb8cd59014..f15fffc09e8 100644
--- a/clippy_utils/src/paths.rs
+++ b/clippy_utils/src/paths.rs
@@ -33,6 +33,8 @@ pub const CHILD: [&str; 3] = ["std", "process", "Child"];
 pub const CHILD_ID: [&str; 4] = ["std", "process", "Child", "id"];
 pub const CHILD_KILL: [&str; 4] = ["std", "process", "Child", "kill"];
 pub const PANIC_ANY: [&str; 3] = ["std", "panic", "panic_any"];
+pub const CHAR_IS_ASCII: [&str; 5] = ["core", "char", "methods", "<impl char>", "is_ascii"];
+pub const STDIN: [&str; 4] = ["std", "io", "stdio", "Stdin"];
 
 // Paths in clippy itself
 pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"];
diff --git a/tests/missing-test-files.rs b/tests/missing-test-files.rs
index a8225d037e8..64eba5e0888 100644
--- a/tests/missing-test-files.rs
+++ b/tests/missing-test-files.rs
@@ -59,7 +59,7 @@ fn explore_directory(dir: &Path) -> Vec<String> {
                             missing_files.push(path.to_str().unwrap().to_string());
                         }
                     },
-                    _ => continue,
+                    _ => {},
                 };
             }
         }
diff --git a/tests/ui/crashes/ice-10972-tait.rs b/tests/ui/crashes/ice-10972-tait.rs
new file mode 100644
index 00000000000..f3ab9cebb7c
--- /dev/null
+++ b/tests/ui/crashes/ice-10972-tait.rs
@@ -0,0 +1,9 @@
+// ICE: #10972
+// asked to assemble constituent types of unexpected type: Binder(Foo, [])
+#![feature(type_alias_impl_trait)]
+
+use std::fmt::Debug;
+type Foo = impl Debug;
+const FOO2: Foo = 22_u32;
+
+pub fn main() {}
diff --git a/tests/ui/double_ended_iterator_last.fixed b/tests/ui/double_ended_iterator_last.fixed
new file mode 100644
index 00000000000..06c48e33753
--- /dev/null
+++ b/tests/ui/double_ended_iterator_last.fixed
@@ -0,0 +1,53 @@
+#![warn(clippy::double_ended_iterator_last)]
+
+// Typical case
+pub fn last_arg(s: &str) -> Option<&str> {
+    s.split(' ').next_back()
+}
+
+fn main() {
+    // General case
+    struct DeIterator;
+    impl Iterator for DeIterator {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    impl DoubleEndedIterator for DeIterator {
+        fn next_back(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    let _ = DeIterator.next_back();
+    // Should not apply to other methods of Iterator
+    let _ = DeIterator.count();
+
+    // Should not apply to simple iterators
+    struct SimpleIterator;
+    impl Iterator for SimpleIterator {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    let _ = SimpleIterator.last();
+
+    // Should not apply to custom implementations of last()
+    struct CustomLast;
+    impl Iterator for CustomLast {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+        fn last(self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    impl DoubleEndedIterator for CustomLast {
+        fn next_back(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    let _ = CustomLast.last();
+}
diff --git a/tests/ui/double_ended_iterator_last.rs b/tests/ui/double_ended_iterator_last.rs
new file mode 100644
index 00000000000..9c13b496d11
--- /dev/null
+++ b/tests/ui/double_ended_iterator_last.rs
@@ -0,0 +1,53 @@
+#![warn(clippy::double_ended_iterator_last)]
+
+// Typical case
+pub fn last_arg(s: &str) -> Option<&str> {
+    s.split(' ').last()
+}
+
+fn main() {
+    // General case
+    struct DeIterator;
+    impl Iterator for DeIterator {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    impl DoubleEndedIterator for DeIterator {
+        fn next_back(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    let _ = DeIterator.last();
+    // Should not apply to other methods of Iterator
+    let _ = DeIterator.count();
+
+    // Should not apply to simple iterators
+    struct SimpleIterator;
+    impl Iterator for SimpleIterator {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    let _ = SimpleIterator.last();
+
+    // Should not apply to custom implementations of last()
+    struct CustomLast;
+    impl Iterator for CustomLast {
+        type Item = ();
+        fn next(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+        fn last(self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    impl DoubleEndedIterator for CustomLast {
+        fn next_back(&mut self) -> Option<Self::Item> {
+            Some(())
+        }
+    }
+    let _ = CustomLast.last();
+}
diff --git a/tests/ui/double_ended_iterator_last.stderr b/tests/ui/double_ended_iterator_last.stderr
new file mode 100644
index 00000000000..b795c18a736
--- /dev/null
+++ b/tests/ui/double_ended_iterator_last.stderr
@@ -0,0 +1,17 @@
+error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
+  --> tests/ui/double_ended_iterator_last.rs:5:18
+   |
+LL |     s.split(' ').last()
+   |                  ^^^^^^ help: try: `next_back()`
+   |
+   = note: `-D clippy::double-ended-iterator-last` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::double_ended_iterator_last)]`
+
+error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
+  --> tests/ui/double_ended_iterator_last.rs:22:24
+   |
+LL |     let _ = DeIterator.last();
+   |                        ^^^^^^ help: try: `next_back()`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/infinite_iter.rs b/tests/ui/infinite_iter.rs
index da95ba04b82..178e300ff5b 100644
--- a/tests/ui/infinite_iter.rs
+++ b/tests/ui/infinite_iter.rs
@@ -1,4 +1,4 @@
-#![allow(clippy::uninlined_format_args)]
+#![allow(clippy::uninlined_format_args, clippy::double_ended_iterator_last)]
 
 use std::iter::repeat;
 fn square_is_lower_64(x: &u32) -> bool {
diff --git a/tests/ui/iter_overeager_cloned.fixed b/tests/ui/iter_overeager_cloned.fixed
index 7d8a584b022..d7d3d299349 100644
--- a/tests/ui/iter_overeager_cloned.fixed
+++ b/tests/ui/iter_overeager_cloned.fixed
@@ -1,5 +1,10 @@
 #![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)]
-#![allow(dead_code, clippy::let_unit_value, clippy::useless_vec)]
+#![allow(
+    dead_code,
+    clippy::let_unit_value,
+    clippy::useless_vec,
+    clippy::double_ended_iterator_last
+)]
 
 fn main() {
     let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()];
diff --git a/tests/ui/iter_overeager_cloned.rs b/tests/ui/iter_overeager_cloned.rs
index 58c374ab8cd..45e1349febd 100644
--- a/tests/ui/iter_overeager_cloned.rs
+++ b/tests/ui/iter_overeager_cloned.rs
@@ -1,5 +1,10 @@
 #![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)]
-#![allow(dead_code, clippy::let_unit_value, clippy::useless_vec)]
+#![allow(
+    dead_code,
+    clippy::let_unit_value,
+    clippy::useless_vec,
+    clippy::double_ended_iterator_last
+)]
 
 fn main() {
     let vec = vec!["1".to_string(), "2".to_string(), "3".to_string()];
diff --git a/tests/ui/iter_overeager_cloned.stderr b/tests/ui/iter_overeager_cloned.stderr
index 7a822a79494..e6680266f10 100644
--- a/tests/ui/iter_overeager_cloned.stderr
+++ b/tests/ui/iter_overeager_cloned.stderr
@@ -1,5 +1,5 @@
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:7:29
+  --> tests/ui/iter_overeager_cloned.rs:12:29
    |
 LL |     let _: Option<String> = vec.iter().cloned().last();
    |                             ^^^^^^^^^^----------------
@@ -10,7 +10,7 @@ LL |     let _: Option<String> = vec.iter().cloned().last();
    = help: to override `-D warnings` add `#[allow(clippy::iter_overeager_cloned)]`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:9:29
+  --> tests/ui/iter_overeager_cloned.rs:14:29
    |
 LL |     let _: Option<String> = vec.iter().chain(vec.iter()).cloned().next();
    |                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------
@@ -18,7 +18,7 @@ LL |     let _: Option<String> = vec.iter().chain(vec.iter()).cloned().next();
    |                                                         help: try: `.next().cloned()`
 
 error: unneeded cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:11:20
+  --> tests/ui/iter_overeager_cloned.rs:16:20
    |
 LL |     let _: usize = vec.iter().filter(|x| x == &"2").cloned().count();
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-----------------
@@ -29,7 +29,7 @@ LL |     let _: usize = vec.iter().filter(|x| x == &"2").cloned().count();
    = help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:13:21
+  --> tests/ui/iter_overeager_cloned.rs:18:21
    |
 LL |     let _: Vec<_> = vec.iter().cloned().take(2).collect();
    |                     ^^^^^^^^^^-----------------
@@ -37,7 +37,7 @@ LL |     let _: Vec<_> = vec.iter().cloned().take(2).collect();
    |                               help: try: `.take(2).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:15:21
+  --> tests/ui/iter_overeager_cloned.rs:20:21
    |
 LL |     let _: Vec<_> = vec.iter().cloned().skip(2).collect();
    |                     ^^^^^^^^^^-----------------
@@ -45,7 +45,7 @@ LL |     let _: Vec<_> = vec.iter().cloned().skip(2).collect();
    |                               help: try: `.skip(2).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:17:13
+  --> tests/ui/iter_overeager_cloned.rs:22:13
    |
 LL |     let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------
@@ -53,7 +53,7 @@ LL |     let _ = vec.iter().filter(|x| x == &"2").cloned().nth(2);
    |                                             help: try: `.nth(2).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:19:13
+  --> tests/ui/iter_overeager_cloned.rs:24:13
    |
 LL |       let _ = [Some(Some("str".to_string())), Some(Some("str".to_string()))]
    |  _____________^
@@ -69,7 +69,7 @@ LL ~         .flatten().cloned();
    |
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:24:13
+  --> tests/ui/iter_overeager_cloned.rs:29:13
    |
 LL |     let _ = vec.iter().cloned().filter(|x| x.starts_with('2'));
    |             ^^^^^^^^^^----------------------------------------
@@ -77,7 +77,7 @@ LL |     let _ = vec.iter().cloned().filter(|x| x.starts_with('2'));
    |                       help: try: `.filter(|&x| x.starts_with('2')).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:26:13
+  --> tests/ui/iter_overeager_cloned.rs:31:13
    |
 LL |     let _ = vec.iter().cloned().find(|x| x == "2");
    |             ^^^^^^^^^^----------------------------
@@ -85,7 +85,7 @@ LL |     let _ = vec.iter().cloned().find(|x| x == "2");
    |                       help: try: `.find(|&x| x == "2").cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:30:17
+  --> tests/ui/iter_overeager_cloned.rs:35:17
    |
 LL |         let _ = vec.iter().cloned().filter(f);
    |                 ^^^^^^^^^^-------------------
@@ -93,7 +93,7 @@ LL |         let _ = vec.iter().cloned().filter(f);
    |                           help: try: `.filter(|&x| f(x)).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:31:17
+  --> tests/ui/iter_overeager_cloned.rs:36:17
    |
 LL |         let _ = vec.iter().cloned().find(f);
    |                 ^^^^^^^^^^-----------------
@@ -101,7 +101,7 @@ LL |         let _ = vec.iter().cloned().find(f);
    |                           help: try: `.find(|&x| f(x)).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:37:17
+  --> tests/ui/iter_overeager_cloned.rs:42:17
    |
 LL |         let _ = vec.iter().cloned().filter(f);
    |                 ^^^^^^^^^^-------------------
@@ -109,7 +109,7 @@ LL |         let _ = vec.iter().cloned().filter(f);
    |                           help: try: `.filter(|&x| f(x)).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:38:17
+  --> tests/ui/iter_overeager_cloned.rs:43:17
    |
 LL |         let _ = vec.iter().cloned().find(f);
    |                 ^^^^^^^^^^-----------------
@@ -117,7 +117,7 @@ LL |         let _ = vec.iter().cloned().find(f);
    |                           help: try: `.find(|&x| f(x)).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:45:9
+  --> tests/ui/iter_overeager_cloned.rs:50:9
    |
 LL |         iter.cloned().filter(move |(&a, b)| a == 1 && b == &target)
    |         ^^^^-------------------------------------------------------
@@ -125,7 +125,7 @@ LL |         iter.cloned().filter(move |(&a, b)| a == 1 && b == &target)
    |             help: try: `.filter(move |&(&a, b)| a == 1 && b == &target).cloned()`
 
 error: unnecessarily eager cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:56:13
+  --> tests/ui/iter_overeager_cloned.rs:61:13
    |
 LL |             iter.cloned().filter(move |S { a, b }| **a == 1 && b == &target)
    |             ^^^^------------------------------------------------------------
@@ -133,7 +133,7 @@ LL |             iter.cloned().filter(move |S { a, b }| **a == 1 && b == &target
    |                 help: try: `.filter(move |&S { a, b }| **a == 1 && b == &target).cloned()`
 
 error: unneeded cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:60:13
+  --> tests/ui/iter_overeager_cloned.rs:65:13
    |
 LL |     let _ = vec.iter().cloned().map(|x| x.len());
    |             ^^^^^^^^^^--------------------------
@@ -141,7 +141,7 @@ LL |     let _ = vec.iter().cloned().map(|x| x.len());
    |                       help: try: `.map(|x| x.len())`
 
 error: unneeded cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:65:13
+  --> tests/ui/iter_overeager_cloned.rs:70:13
    |
 LL |     let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty()));
    |             ^^^^^^^^^^----------------------------------------------
@@ -149,7 +149,7 @@ LL |     let _ = vec.iter().cloned().for_each(|x| assert!(!x.is_empty()));
    |                       help: try: `.for_each(|x| assert!(!x.is_empty()))`
 
 error: unneeded cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:67:13
+  --> tests/ui/iter_overeager_cloned.rs:72:13
    |
 LL |     let _ = vec.iter().cloned().all(|x| x.len() == 1);
    |             ^^^^^^^^^^-------------------------------
@@ -157,7 +157,7 @@ LL |     let _ = vec.iter().cloned().all(|x| x.len() == 1);
    |                       help: try: `.all(|x| x.len() == 1)`
 
 error: unneeded cloning of iterator items
-  --> tests/ui/iter_overeager_cloned.rs:69:13
+  --> tests/ui/iter_overeager_cloned.rs:74:13
    |
 LL |     let _ = vec.iter().cloned().any(|x| x.len() == 1);
    |             ^^^^^^^^^^-------------------------------
diff --git a/tests/ui/len_zero.fixed b/tests/ui/len_zero.fixed
index 27319d9c20e..c9c476ba421 100644
--- a/tests/ui/len_zero.fixed
+++ b/tests/ui/len_zero.fixed
@@ -108,6 +108,8 @@ fn main() {
     let d2s = DerefToDerefToString {};
     println!("{}", (**d2s).is_empty());
 
+    println!("{}", std::borrow::Cow::Borrowed("").is_empty());
+
     let y = One;
     if y.len() == 0 {
         // No error; `One` does not have `.is_empty()`.
@@ -226,3 +228,23 @@ fn binop_with_macros() {
 
     (!has_is_empty.is_empty()).then(|| println!("This can happen."));
 }
+
+fn no_infinite_recursion() -> bool {
+    struct S;
+
+    impl Deref for S {
+        type Target = Self;
+        fn deref(&self) -> &Self::Target {
+            self
+        }
+    }
+
+    impl PartialEq<&'static str> for S {
+        fn eq(&self, _other: &&'static str) -> bool {
+            false
+        }
+    }
+
+    // Do not crash while checking if S implements `.is_empty()`
+    S == ""
+}
diff --git a/tests/ui/len_zero.rs b/tests/ui/len_zero.rs
index 03c05bc6ed7..610a5448d10 100644
--- a/tests/ui/len_zero.rs
+++ b/tests/ui/len_zero.rs
@@ -108,6 +108,8 @@ fn main() {
     let d2s = DerefToDerefToString {};
     println!("{}", &**d2s == "");
 
+    println!("{}", std::borrow::Cow::Borrowed("") == "");
+
     let y = One;
     if y.len() == 0 {
         // No error; `One` does not have `.is_empty()`.
@@ -226,3 +228,23 @@ fn binop_with_macros() {
 
     (compare_to!(0) < has_is_empty.len()).then(|| println!("This can happen."));
 }
+
+fn no_infinite_recursion() -> bool {
+    struct S;
+
+    impl Deref for S {
+        type Target = Self;
+        fn deref(&self) -> &Self::Target {
+            self
+        }
+    }
+
+    impl PartialEq<&'static str> for S {
+        fn eq(&self, _other: &&'static str) -> bool {
+            false
+        }
+    }
+
+    // Do not crash while checking if S implements `.is_empty()`
+    S == ""
+}
diff --git a/tests/ui/len_zero.stderr b/tests/ui/len_zero.stderr
index 5c849a2aca6..8d6b57e4b6d 100644
--- a/tests/ui/len_zero.stderr
+++ b/tests/ui/len_zero.stderr
@@ -58,107 +58,113 @@ error: comparison to empty slice
 LL |     println!("{}", &**d2s == "");
    |                    ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `(**d2s).is_empty()`
 
+error: comparison to empty slice
+  --> tests/ui/len_zero.rs:111:20
+   |
+LL |     println!("{}", std::borrow::Cow::Borrowed("") == "");
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `std::borrow::Cow::Borrowed("").is_empty()`
+
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:124:8
+  --> tests/ui/len_zero.rs:126:8
    |
 LL |     if has_is_empty.len() == 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:127:8
+  --> tests/ui/len_zero.rs:129:8
    |
 LL |     if has_is_empty.len() != 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:130:8
+  --> tests/ui/len_zero.rs:132:8
    |
 LL |     if has_is_empty.len() > 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> tests/ui/len_zero.rs:133:8
+  --> tests/ui/len_zero.rs:135:8
    |
 LL |     if has_is_empty.len() < 1 {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> tests/ui/len_zero.rs:136:8
+  --> tests/ui/len_zero.rs:138:8
    |
 LL |     if has_is_empty.len() >= 1 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:147:8
+  --> tests/ui/len_zero.rs:149:8
    |
 LL |     if 0 == has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:150:8
+  --> tests/ui/len_zero.rs:152:8
    |
 LL |     if 0 != has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:153:8
+  --> tests/ui/len_zero.rs:155:8
    |
 LL |     if 0 < has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> tests/ui/len_zero.rs:156:8
+  --> tests/ui/len_zero.rs:158:8
    |
 LL |     if 1 <= has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to one
-  --> tests/ui/len_zero.rs:159:8
+  --> tests/ui/len_zero.rs:161:8
    |
 LL |     if 1 > has_is_empty.len() {
    |        ^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:173:8
+  --> tests/ui/len_zero.rs:175:8
    |
 LL |     if with_is_empty.len() == 0 {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `with_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:185:6
+  --> tests/ui/len_zero.rs:187:6
    |
 LL |     (has_is_empty.len() > 0).then(|| println!("This can happen."));
    |      ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:186:6
+  --> tests/ui/len_zero.rs:188:6
    |
 LL |     (has_is_empty.len() == 0).then(|| println!("Or this!"));
    |      ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:190:8
+  --> tests/ui/len_zero.rs:192:8
    |
 LL |     if b.len() != 0 {}
    |        ^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!b.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:224:8
+  --> tests/ui/len_zero.rs:226:8
    |
 LL |     if has_is_empty.len() == compare_to!(0) {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:225:8
+  --> tests/ui/len_zero.rs:227:8
    |
 LL |     if has_is_empty.len() == zero!() {}
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()`
 
 error: length comparison to zero
-  --> tests/ui/len_zero.rs:227:6
+  --> tests/ui/len_zero.rs:229:6
    |
 LL |     (compare_to!(0) < has_is_empty.len()).then(|| println!("This can happen."));
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()`
 
-error: aborting due to 26 previous errors
+error: aborting due to 27 previous errors
 
diff --git a/tests/ui/missing_const_for_fn/cant_be_const.rs b/tests/ui/missing_const_for_fn/cant_be_const.rs
index ca323dcf173..d2f9e34a5ce 100644
--- a/tests/ui/missing_const_for_fn/cant_be_const.rs
+++ b/tests/ui/missing_const_for_fn/cant_be_const.rs
@@ -47,7 +47,34 @@ fn get_y() -> u32 {
     Y
 }
 
-// Don't lint entrypoint functions
+#[cfg(test)]
+mod with_test_fn {
+    #[derive(Clone, Copy)]
+    pub struct Foo {
+        pub n: u32,
+    }
+
+    impl Foo {
+        #[must_use]
+        pub const fn new(n: u32) -> Foo {
+            Foo { n }
+        }
+    }
+
+    #[test]
+    fn foo_is_copy() {
+        let foo = Foo::new(42);
+        let one = foo;
+        let two = foo;
+        _ = one;
+        _ = two;
+    }
+}
+
+// Allowing on this function, because it would lint, which we don't want in this case.
+// if we have `#[start]` and `#[test]` check `is_entrypoint_fn(cx, def_id.to_def_id())` is stopped
+// working
+#[allow(clippy::missing_const_for_fn)]
 #[start]
 fn init(num: isize, something: *const *const u8) -> isize {
     1
diff --git a/tests/ui/needless_arbitrary_self_type.fixed b/tests/ui/needless_arbitrary_self_type.fixed
index 9da60c687d4..530eb77d83d 100644
--- a/tests/ui/needless_arbitrary_self_type.fixed
+++ b/tests/ui/needless_arbitrary_self_type.fixed
@@ -64,4 +64,9 @@ impl ValType {
     }
 }
 
+trait Foo<'r#struct> {
+    fn f1(&'r#struct self) {}
+    fn f2(&'r#struct mut self) {}
+}
+
 fn main() {}
diff --git a/tests/ui/needless_arbitrary_self_type.rs b/tests/ui/needless_arbitrary_self_type.rs
index fc4ec5cb0b3..5a1ff96a11c 100644
--- a/tests/ui/needless_arbitrary_self_type.rs
+++ b/tests/ui/needless_arbitrary_self_type.rs
@@ -64,4 +64,9 @@ impl ValType {
     }
 }
 
+trait Foo<'r#struct> {
+    fn f1(self: &'r#struct Self) {}
+    fn f2(self: &'r#struct mut Self) {}
+}
+
 fn main() {}
diff --git a/tests/ui/needless_arbitrary_self_type.stderr b/tests/ui/needless_arbitrary_self_type.stderr
index c653267f752..7ebbbaa122f 100644
--- a/tests/ui/needless_arbitrary_self_type.stderr
+++ b/tests/ui/needless_arbitrary_self_type.stderr
@@ -37,5 +37,17 @@ error: the type of the `self` parameter does not need to be arbitrary
 LL |     pub fn mut_ref_bad_with_lifetime<'a>(self: &'a mut Self) {
    |                                          ^^^^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'a mut self`
 
-error: aborting due to 6 previous errors
+error: the type of the `self` parameter does not need to be arbitrary
+  --> tests/ui/needless_arbitrary_self_type.rs:68:11
+   |
+LL |     fn f1(self: &'r#struct Self) {}
+   |           ^^^^^^^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'r#struct self`
+
+error: the type of the `self` parameter does not need to be arbitrary
+  --> tests/ui/needless_arbitrary_self_type.rs:69:11
+   |
+LL |     fn f2(self: &'r#struct mut Self) {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'r#struct mut self`
+
+error: aborting due to 8 previous errors
 
diff --git a/tests/ui/needless_continue.rs b/tests/ui/needless_continue.rs
index b6d8a8f61ae..334a2b32775 100644
--- a/tests/ui/needless_continue.rs
+++ b/tests/ui/needless_continue.rs
@@ -87,6 +87,14 @@ fn simple_loop4() {
     }
 }
 
+fn simple_loop5() {
+    loop {
+        println!("bleh");
+        { continue }
+        //~^ ERROR: this `continue` expression is redundant
+    }
+}
+
 mod issue_2329 {
     fn condition() -> bool {
         unimplemented!()
@@ -168,3 +176,60 @@ fn issue_13641() {
         }
     }
 }
+
+mod issue_4077 {
+    fn main() {
+        'outer: loop {
+            'inner: loop {
+                do_something();
+                if some_expr() {
+                    println!("bar-7");
+                    continue 'outer;
+                } else if !some_expr() {
+                    println!("bar-8");
+                    continue 'inner;
+                } else {
+                    println!("bar-9");
+                    continue 'inner;
+                }
+            }
+        }
+
+        for _ in 0..10 {
+            match "foo".parse::<i32>() {
+                Ok(_) => do_something(),
+                Err(_) => {
+                    println!("bar-10");
+                    continue;
+                },
+            }
+        }
+
+        loop {
+            if true {
+            } else {
+                // redundant `else`
+                continue; // redundant `continue`
+            }
+        }
+
+        loop {
+            if some_expr() {
+                continue;
+            } else {
+                do_something();
+            }
+        }
+    }
+
+    // The contents of these functions are irrelevant, the purpose of this file is
+    // shown in main.
+
+    fn do_something() {
+        std::process::exit(0);
+    }
+
+    fn some_expr() -> bool {
+        true
+    }
+}
diff --git a/tests/ui/needless_continue.stderr b/tests/ui/needless_continue.stderr
index 0741ba69248..ec39d623419 100644
--- a/tests/ui/needless_continue.stderr
+++ b/tests/ui/needless_continue.stderr
@@ -63,7 +63,7 @@ error: this `continue` expression is redundant
   --> tests/ui/needless_continue.rs:60:9
    |
 LL |         continue;
-   |         ^^^^^^^^^
+   |         ^^^^^^^^
    |
    = help: consider dropping the `continue` expression
 
@@ -71,7 +71,7 @@ error: this `continue` expression is redundant
   --> tests/ui/needless_continue.rs:68:9
    |
 LL |         continue;
-   |         ^^^^^^^^^
+   |         ^^^^^^^^
    |
    = help: consider dropping the `continue` expression
 
@@ -91,8 +91,16 @@ LL |         continue
    |
    = help: consider dropping the `continue` expression
 
+error: this `continue` expression is redundant
+  --> tests/ui/needless_continue.rs:93:11
+   |
+LL |         { continue }
+   |           ^^^^^^^^
+   |
+   = help: consider dropping the `continue` expression
+
 error: this `else` block is redundant
-  --> tests/ui/needless_continue.rs:136:24
+  --> tests/ui/needless_continue.rs:144:24
    |
 LL |                   } else {
    |  ________________________^
@@ -117,7 +125,7 @@ LL | |                 }
                            }
 
 error: there is no need for an explicit `else` block for this `if` expression
-  --> tests/ui/needless_continue.rs:143:17
+  --> tests/ui/needless_continue.rs:151:17
    |
 LL | /                 if condition() {
 LL | |
@@ -137,12 +145,70 @@ LL | |                 }
                            }
 
 error: this `continue` expression is redundant
-  --> tests/ui/needless_continue.rs:166:13
+  --> tests/ui/needless_continue.rs:174:13
    |
 LL |             continue 'b;
-   |             ^^^^^^^^^^^^
+   |             ^^^^^^^^^^^
    |
    = help: consider dropping the `continue` expression
 
-error: aborting due to 9 previous errors
+error: this `continue` expression is redundant
+  --> tests/ui/needless_continue.rs:190:21
+   |
+LL |                     continue 'inner;
+   |                     ^^^^^^^^^^^^^^^
+   |
+   = help: consider dropping the `continue` expression
+
+error: this `continue` expression is redundant
+  --> tests/ui/needless_continue.rs:193:21
+   |
+LL |                     continue 'inner;
+   |                     ^^^^^^^^^^^^^^^
+   |
+   = help: consider dropping the `continue` expression
+
+error: this `continue` expression is redundant
+  --> tests/ui/needless_continue.rs:203:21
+   |
+LL |                     continue;
+   |                     ^^^^^^^^
+   |
+   = help: consider dropping the `continue` expression
+
+error: this `else` block is redundant
+  --> tests/ui/needless_continue.rs:210:20
+   |
+LL |               } else {
+   |  ____________________^
+LL | |                 // redundant `else`
+LL | |                 continue; // redundant `continue`
+LL | |             }
+   | |_____________^
+   |
+   = help: consider dropping the `else` clause and merging the code that follows (in the loop) with the `if` block
+                       if true {
+           // merged code follows:
+           
+                       }
+
+error: there is no need for an explicit `else` block for this `if` expression
+  --> tests/ui/needless_continue.rs:217:13
+   |
+LL | /             if some_expr() {
+LL | |                 continue;
+LL | |             } else {
+LL | |                 do_something();
+LL | |             }
+   | |_____________^
+   |
+   = help: consider dropping the `else` clause
+                       if some_expr() {
+                           continue;
+                       }
+                       {
+                           do_something();
+                       }
+
+error: aborting due to 15 previous errors
 
diff --git a/tests/ui/redundant_pattern_matching_option.fixed b/tests/ui/redundant_pattern_matching_option.fixed
index c9b76262d70..c7e0cd2610f 100644
--- a/tests/ui/redundant_pattern_matching_option.fixed
+++ b/tests/ui/redundant_pattern_matching_option.fixed
@@ -137,3 +137,11 @@ fn issue10803() {
     // Don't lint
     let _ = matches!(x, Some(16));
 }
+
+fn issue13902() {
+    let x = Some(0);
+    let p = &raw const x;
+    unsafe {
+        let _ = (*p).is_none();
+    }
+}
diff --git a/tests/ui/redundant_pattern_matching_option.rs b/tests/ui/redundant_pattern_matching_option.rs
index a5f9caf659c..6d9a9f7f942 100644
--- a/tests/ui/redundant_pattern_matching_option.rs
+++ b/tests/ui/redundant_pattern_matching_option.rs
@@ -164,3 +164,11 @@ fn issue10803() {
     // Don't lint
     let _ = matches!(x, Some(16));
 }
+
+fn issue13902() {
+    let x = Some(0);
+    let p = &raw const x;
+    unsafe {
+        let _ = matches!(*p, None);
+    }
+}
diff --git a/tests/ui/redundant_pattern_matching_option.stderr b/tests/ui/redundant_pattern_matching_option.stderr
index 575f199be42..34d80f5ca78 100644
--- a/tests/ui/redundant_pattern_matching_option.stderr
+++ b/tests/ui/redundant_pattern_matching_option.stderr
@@ -209,5 +209,11 @@ error: redundant pattern matching, consider using `is_none()`
 LL |     let _ = matches!(x, None);
    |             ^^^^^^^^^^^^^^^^^ help: try: `x.is_none()`
 
-error: aborting due to 30 previous errors
+error: redundant pattern matching, consider using `is_none()`
+  --> tests/ui/redundant_pattern_matching_option.rs:172:17
+   |
+LL |         let _ = matches!(*p, None);
+   |                 ^^^^^^^^^^^^^^^^^^ help: try: `(*p).is_none()`
+
+error: aborting due to 31 previous errors
 
diff --git a/tests/ui/slow_vector_initialization.rs b/tests/ui/slow_vector_initialization.rs
index 16f81019574..2ba87f41250 100644
--- a/tests/ui/slow_vector_initialization.rs
+++ b/tests/ui/slow_vector_initialization.rs
@@ -11,22 +11,22 @@ fn extend_vector() {
     // Extend with constant expression
     let len = 300;
     let mut vec1 = Vec::with_capacity(len);
-    vec1.extend(repeat(0).take(len));
     //~^ ERROR: slow zero-filling initialization
     //~| NOTE: `-D clippy::slow-vector-initialization` implied by `-D warnings`
+    vec1.extend(repeat(0).take(len));
 
     // Extend with len expression
     let mut vec2 = Vec::with_capacity(len - 10);
-    vec2.extend(repeat(0).take(len - 10));
     //~^ ERROR: slow zero-filling initialization
+    vec2.extend(repeat(0).take(len - 10));
 
     // Extend with mismatching expression should not be warned
     let mut vec3 = Vec::with_capacity(24322);
     vec3.extend(repeat(0).take(2));
 
     let mut vec4 = Vec::with_capacity(len);
-    vec4.extend(repeat(0).take(vec4.capacity()));
     //~^ ERROR: slow zero-filling initialization
+    vec4.extend(repeat(0).take(vec4.capacity()));
 }
 
 fn mixed_extend_resize_vector() {
@@ -36,20 +36,20 @@ fn mixed_extend_resize_vector() {
 
     // Slow initialization
     let mut resized_vec = Vec::with_capacity(30);
-    resized_vec.resize(30, 0);
     //~^ ERROR: slow zero-filling initialization
+    resized_vec.resize(30, 0);
 
     let mut extend_vec = Vec::with_capacity(30);
-    extend_vec.extend(repeat(0).take(30));
     //~^ ERROR: slow zero-filling initialization
+    extend_vec.extend(repeat(0).take(30));
 }
 
 fn resize_vector() {
     // Resize with constant expression
     let len = 300;
     let mut vec1 = Vec::with_capacity(len);
-    vec1.resize(len, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec1.resize(len, 0);
 
     // Resize mismatch len
     let mut vec2 = Vec::with_capacity(200);
@@ -57,39 +57,39 @@ fn resize_vector() {
 
     // Resize with len expression
     let mut vec3 = Vec::with_capacity(len - 10);
-    vec3.resize(len - 10, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec3.resize(len - 10, 0);
 
     let mut vec4 = Vec::with_capacity(len);
-    vec4.resize(vec4.capacity(), 0);
     //~^ ERROR: slow zero-filling initialization
+    vec4.resize(vec4.capacity(), 0);
 
     // Reinitialization should be warned
     vec1 = Vec::with_capacity(10);
-    vec1.resize(10, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec1.resize(10, 0);
 }
 
 fn from_empty_vec() {
     // Resize with constant expression
     let len = 300;
     let mut vec1 = Vec::new();
-    vec1.resize(len, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec1.resize(len, 0);
 
     // Resize with len expression
     let mut vec3 = Vec::new();
-    vec3.resize(len - 10, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec3.resize(len - 10, 0);
 
     // Reinitialization should be warned
     vec1 = Vec::new();
-    vec1.resize(10, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec1.resize(10, 0);
 
     vec1 = vec![];
-    vec1.resize(10, 0);
     //~^ ERROR: slow zero-filling initialization
+    vec1.resize(10, 0);
 
     macro_rules! x {
         () => {
diff --git a/tests/ui/slow_vector_initialization.stderr b/tests/ui/slow_vector_initialization.stderr
index 353c677097b..7f4b9f7b67a 100644
--- a/tests/ui/slow_vector_initialization.stderr
+++ b/tests/ui/slow_vector_initialization.stderr
@@ -1,109 +1,122 @@
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:14:5
+  --> tests/ui/slow_vector_initialization.rs:13:20
    |
-LL |     let mut vec1 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
-LL |     vec1.extend(repeat(0).take(len));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec1 = Vec::with_capacity(len);
+   |  ____________________^
+...  |
+LL | |     vec1.extend(repeat(0).take(len));
+   | |____________________________________^ help: consider replacing this with: `vec![0; len]`
    |
    = note: `-D clippy::slow-vector-initialization` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::slow_vector_initialization)]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:20:5
+  --> tests/ui/slow_vector_initialization.rs:19:20
    |
-LL |     let mut vec2 = Vec::with_capacity(len - 10);
-   |                    ---------------------------- help: consider replacing this with: `vec![0; len - 10]`
-LL |     vec2.extend(repeat(0).take(len - 10));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec2 = Vec::with_capacity(len - 10);
+   |  ____________________^
+LL | |
+LL | |     vec2.extend(repeat(0).take(len - 10));
+   | |_________________________________________^ help: consider replacing this with: `vec![0; len - 10]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:28:5
+  --> tests/ui/slow_vector_initialization.rs:27:20
    |
-LL |     let mut vec4 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
-LL |     vec4.extend(repeat(0).take(vec4.capacity()));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec4 = Vec::with_capacity(len);
+   |  ____________________^
+LL | |
+LL | |     vec4.extend(repeat(0).take(vec4.capacity()));
+   | |________________________________________________^ help: consider replacing this with: `vec![0; len]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:39:5
+  --> tests/ui/slow_vector_initialization.rs:38:27
    |
-LL |     let mut resized_vec = Vec::with_capacity(30);
-   |                           ---------------------- help: consider replacing this with: `vec![0; 30]`
-LL |     resized_vec.resize(30, 0);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut resized_vec = Vec::with_capacity(30);
+   |  ___________________________^
+LL | |
+LL | |     resized_vec.resize(30, 0);
+   | |_____________________________^ help: consider replacing this with: `vec![0; 30]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:43:5
+  --> tests/ui/slow_vector_initialization.rs:42:26
    |
-LL |     let mut extend_vec = Vec::with_capacity(30);
-   |                          ---------------------- help: consider replacing this with: `vec![0; 30]`
-LL |     extend_vec.extend(repeat(0).take(30));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut extend_vec = Vec::with_capacity(30);
+   |  __________________________^
+LL | |
+LL | |     extend_vec.extend(repeat(0).take(30));
+   | |_________________________________________^ help: consider replacing this with: `vec![0; 30]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:51:5
+  --> tests/ui/slow_vector_initialization.rs:50:20
    |
-LL |     let mut vec1 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
-LL |     vec1.resize(len, 0);
-   |     ^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec1 = Vec::with_capacity(len);
+   |  ____________________^
+LL | |
+LL | |     vec1.resize(len, 0);
+   | |_______________________^ help: consider replacing this with: `vec![0; len]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:60:5
+  --> tests/ui/slow_vector_initialization.rs:59:20
    |
-LL |     let mut vec3 = Vec::with_capacity(len - 10);
-   |                    ---------------------------- help: consider replacing this with: `vec![0; len - 10]`
-LL |     vec3.resize(len - 10, 0);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec3 = Vec::with_capacity(len - 10);
+   |  ____________________^
+LL | |
+LL | |     vec3.resize(len - 10, 0);
+   | |____________________________^ help: consider replacing this with: `vec![0; len - 10]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:64:5
+  --> tests/ui/slow_vector_initialization.rs:63:20
    |
-LL |     let mut vec4 = Vec::with_capacity(len);
-   |                    ----------------------- help: consider replacing this with: `vec![0; len]`
-LL |     vec4.resize(vec4.capacity(), 0);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec4 = Vec::with_capacity(len);
+   |  ____________________^
+LL | |
+LL | |     vec4.resize(vec4.capacity(), 0);
+   | |___________________________________^ help: consider replacing this with: `vec![0; len]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:69:5
+  --> tests/ui/slow_vector_initialization.rs:68:12
    |
-LL |     vec1 = Vec::with_capacity(10);
-   |            ---------------------- help: consider replacing this with: `vec![0; 10]`
-LL |     vec1.resize(10, 0);
-   |     ^^^^^^^^^^^^^^^^^^
+LL |       vec1 = Vec::with_capacity(10);
+   |  ____________^
+LL | |
+LL | |     vec1.resize(10, 0);
+   | |______________________^ help: consider replacing this with: `vec![0; 10]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:77:5
+  --> tests/ui/slow_vector_initialization.rs:76:20
    |
-LL |     let mut vec1 = Vec::new();
-   |                    ---------- help: consider replacing this with: `vec![0; len]`
-LL |     vec1.resize(len, 0);
-   |     ^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec1 = Vec::new();
+   |  ____________________^
+LL | |
+LL | |     vec1.resize(len, 0);
+   | |_______________________^ help: consider replacing this with: `vec![0; len]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:82:5
+  --> tests/ui/slow_vector_initialization.rs:81:20
    |
-LL |     let mut vec3 = Vec::new();
-   |                    ---------- help: consider replacing this with: `vec![0; len - 10]`
-LL |     vec3.resize(len - 10, 0);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+LL |       let mut vec3 = Vec::new();
+   |  ____________________^
+LL | |
+LL | |     vec3.resize(len - 10, 0);
+   | |____________________________^ help: consider replacing this with: `vec![0; len - 10]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:87:5
+  --> tests/ui/slow_vector_initialization.rs:86:12
    |
-LL |     vec1 = Vec::new();
-   |            ---------- help: consider replacing this with: `vec![0; 10]`
-LL |     vec1.resize(10, 0);
-   |     ^^^^^^^^^^^^^^^^^^
+LL |       vec1 = Vec::new();
+   |  ____________^
+LL | |
+LL | |     vec1.resize(10, 0);
+   | |______________________^ help: consider replacing this with: `vec![0; 10]`
 
 error: slow zero-filling initialization
-  --> tests/ui/slow_vector_initialization.rs:91:5
+  --> tests/ui/slow_vector_initialization.rs:90:12
    |
-LL |     vec1 = vec![];
-   |            ------ help: consider replacing this with: `vec![0; 10]`
-LL |     vec1.resize(10, 0);
-   |     ^^^^^^^^^^^^^^^^^^
+LL |       vec1 = vec![];
+   |  ____________^
+LL | |
+LL | |     vec1.resize(10, 0);
+   | |______________________^ help: consider replacing this with: `vec![0; 10]`
 
 error: aborting due to 13 previous errors
 
diff --git a/tests/ui/starts_ends_with.fixed b/tests/ui/starts_ends_with.fixed
index 4a66ca7ec91..252b6e5a98c 100644
--- a/tests/ui/starts_ends_with.fixed
+++ b/tests/ui/starts_ends_with.fixed
@@ -1,4 +1,4 @@
-#![allow(clippy::needless_if, dead_code, unused_must_use)]
+#![allow(clippy::needless_if, dead_code, unused_must_use, clippy::double_ended_iterator_last)]
 
 fn main() {}
 
diff --git a/tests/ui/starts_ends_with.rs b/tests/ui/starts_ends_with.rs
index 16a68e02d66..6c5655f3178 100644
--- a/tests/ui/starts_ends_with.rs
+++ b/tests/ui/starts_ends_with.rs
@@ -1,4 +1,4 @@
-#![allow(clippy::needless_if, dead_code, unused_must_use)]
+#![allow(clippy::needless_if, dead_code, unused_must_use, clippy::double_ended_iterator_last)]
 
 fn main() {}
 
diff --git a/tests/ui/useless_vec.rs b/tests/ui/useless_vec.rs
new file mode 100644
index 00000000000..880809f81d7
--- /dev/null
+++ b/tests/ui/useless_vec.rs
@@ -0,0 +1,15 @@
+//@no-rustfix: no suggestions
+
+#![warn(clippy::useless_vec)]
+
+// Regression test for <https://github.com/rust-lang/rust-clippy/issues/13692>.
+fn foo() {
+    // There should be no suggestion in this case.
+    let _some_variable = vec![
+        //~^ useless_vec
+        1, 2, // i'm here to stay
+        3, 4, // but this one going away ;-;
+    ]; // that is life anyways
+}
+
+fn main() {}
diff --git a/tests/ui/useless_vec.stderr b/tests/ui/useless_vec.stderr
new file mode 100644
index 00000000000..e47364fb06d
--- /dev/null
+++ b/tests/ui/useless_vec.stderr
@@ -0,0 +1,21 @@
+error: useless use of `vec!`
+  --> tests/ui/useless_vec.rs:8:26
+   |
+LL |       let _some_variable = vec![
+   |  __________________________^
+LL | |
+LL | |         1, 2, // i'm here to stay
+LL | |         3, 4, // but this one going away ;-;
+LL | |     ]; // that is life anyways
+   | |_____^
+   |
+   = note: `-D clippy::useless-vec` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::useless_vec)]`
+help: you can use an array directly
+   |
+LL ~     let _some_variable = [1, 2, // i'm here to stay
+LL ~         3, 4]; // that is life anyways
+   |
+
+error: aborting due to 1 previous error
+