about summary refs log tree commit diff
path: root/clippy_lints
diff options
context:
space:
mode:
authorPhilipp Krones <hello@philkrones.com>2023-07-02 14:35:19 +0200
committerPhilipp Krones <hello@philkrones.com>2023-07-02 14:59:02 +0200
commitcb3ecf7b792fdc4b00e61935b9e40ca836752492 (patch)
treea183611f56d9139413f6ab1c78c0619512d3c751 /clippy_lints
parentbb33e0343fe37815f6180a861619a9fca6771ce9 (diff)
Merge commit '37f4c1725d3fd7e9c3ffd8783246bc5589debc53' into clippyup
Diffstat (limited to 'clippy_lints')
-rw-r--r--clippy_lints/Cargo.toml3
-rw-r--r--clippy_lints/src/allow_attributes.rs7
-rw-r--r--clippy_lints/src/arc_with_non_send_sync.rs72
-rw-r--r--clippy_lints/src/as_conversions.rs11
-rw-r--r--clippy_lints/src/attrs.rs68
-rw-r--r--clippy_lints/src/booleans.rs2
-rw-r--r--clippy_lints/src/casts/borrow_as_ptr.rs10
-rw-r--r--clippy_lints/src/casts/cast_possible_wrap.rs95
-rw-r--r--clippy_lints/src/casts/mod.rs13
-rw-r--r--clippy_lints/src/casts/ptr_cast_constness.rs13
-rw-r--r--clippy_lints/src/casts/unnecessary_cast.rs140
-rw-r--r--clippy_lints/src/declared_lints.rs28
-rw-r--r--clippy_lints/src/default_constructed_unit_structs.rs2
-rw-r--r--clippy_lints/src/default_numeric_fallback.rs2
-rw-r--r--clippy_lints/src/dereference.rs41
-rw-r--r--clippy_lints/src/derivable_impls.rs39
-rw-r--r--clippy_lints/src/derive.rs7
-rw-r--r--clippy_lints/src/doc.rs11
-rw-r--r--clippy_lints/src/drop_forget_ref.rs52
-rw-r--r--clippy_lints/src/endian_bytes.rs216
-rw-r--r--clippy_lints/src/enum_clike.rs2
-rw-r--r--clippy_lints/src/enum_variants.rs31
-rw-r--r--clippy_lints/src/eta_reduction.rs8
-rw-r--r--clippy_lints/src/excessive_nesting.rs181
-rw-r--r--clippy_lints/src/extra_unused_type_parameters.rs2
-rw-r--r--clippy_lints/src/float_literal.rs11
-rw-r--r--clippy_lints/src/floating_point_arithmetic.rs2
-rw-r--r--clippy_lints/src/format_push_string.rs23
-rw-r--r--clippy_lints/src/formatting.rs6
-rw-r--r--clippy_lints/src/from_over_into.rs8
-rw-r--r--clippy_lints/src/incorrect_impls.rs124
-rw-r--r--clippy_lints/src/items_after_test_module.rs3
-rw-r--r--clippy_lints/src/large_stack_frames.rs162
-rw-r--r--clippy_lints/src/let_with_type_underscore.rs12
-rw-r--r--clippy_lints/src/lib.rs121
-rw-r--r--clippy_lints/src/lifetimes.rs17
-rw-r--r--clippy_lints/src/loops/explicit_into_iter_loop.rs69
-rw-r--r--clippy_lints/src/loops/explicit_iter_loop.rs256
-rw-r--r--clippy_lints/src/loops/manual_memcpy.rs4
-rw-r--r--clippy_lints/src/loops/mod.rs95
-rw-r--r--clippy_lints/src/loops/never_loop.rs92
-rw-r--r--clippy_lints/src/loops/same_item_push.rs2
-rw-r--r--clippy_lints/src/macro_use.rs2
-rw-r--r--clippy_lints/src/manual_let_else.rs247
-rw-r--r--clippy_lints/src/manual_range_patterns.rs123
-rw-r--r--clippy_lints/src/matches/match_same_arms.rs29
-rw-r--r--clippy_lints/src/matches/match_wild_err_arm.rs2
-rw-r--r--clippy_lints/src/matches/mod.rs10
-rw-r--r--clippy_lints/src/matches/overlapping_arms.rs4
-rw-r--r--clippy_lints/src/matches/significant_drop_in_scrutinee.rs2
-rw-r--r--clippy_lints/src/matches/single_match.rs24
-rw-r--r--clippy_lints/src/matches/try_err.rs2
-rw-r--r--clippy_lints/src/mem_forget.rs46
-rw-r--r--clippy_lints/src/methods/drain_collect.rs85
-rw-r--r--clippy_lints/src/methods/get_unwrap.rs33
-rw-r--r--clippy_lints/src/methods/iter_nth.rs4
-rw-r--r--clippy_lints/src/methods/iter_nth_zero.rs35
-rw-r--r--clippy_lints/src/methods/manual_try_fold.rs55
-rw-r--r--clippy_lints/src/methods/mod.rs174
-rw-r--r--clippy_lints/src/methods/needless_collect.rs2
-rw-r--r--clippy_lints/src/methods/option_map_unwrap_or.rs115
-rw-r--r--clippy_lints/src/methods/str_splitn.rs2
-rw-r--r--clippy_lints/src/methods/unnecessary_fold.rs211
-rw-r--r--clippy_lints/src/methods/unnecessary_literal_unwrap.rs95
-rw-r--r--clippy_lints/src/methods/unnecessary_to_owned.rs5
-rw-r--r--clippy_lints/src/min_ident_chars.rs153
-rw-r--r--clippy_lints/src/minmax.rs8
-rw-r--r--clippy_lints/src/misc_early/mixed_case_hex_literals.rs2
-rw-r--r--clippy_lints/src/misc_early/mod.rs37
-rw-r--r--clippy_lints/src/misc_early/redundant_at_rest_pattern.rs26
-rw-r--r--clippy_lints/src/mismatching_type_param_order.rs2
-rw-r--r--clippy_lints/src/missing_fields_in_debug.rs5
-rw-r--r--clippy_lints/src/mixed_read_write_in_expression.rs12
-rw-r--r--clippy_lints/src/module_style.rs10
-rw-r--r--clippy_lints/src/needless_if.rs75
-rw-r--r--clippy_lints/src/needless_pass_by_value.rs33
-rw-r--r--clippy_lints/src/no_effect.rs47
-rw-r--r--clippy_lints/src/non_copy_const.rs18
-rw-r--r--clippy_lints/src/operators/eq_op.rs9
-rw-r--r--clippy_lints/src/operators/float_cmp.rs2
-rw-r--r--clippy_lints/src/option_if_let_else.rs3
-rw-r--r--clippy_lints/src/ptr.rs105
-rw-r--r--clippy_lints/src/question_mark.rs250
-rw-r--r--clippy_lints/src/ranges.rs6
-rw-r--r--clippy_lints/src/raw_strings.rs143
-rw-r--r--clippy_lints/src/redundant_clone.rs17
-rw-r--r--clippy_lints/src/redundant_closure_call.rs163
-rw-r--r--clippy_lints/src/redundant_type_annotations.rs210
-rw-r--r--clippy_lints/src/returns.rs8
-rw-r--r--clippy_lints/src/significant_drop_tightening.rs587
-rw-r--r--clippy_lints/src/single_call_fn.rs133
-rw-r--r--clippy_lints/src/single_range_in_vec_init.rs147
-rw-r--r--clippy_lints/src/trait_bounds.rs43
-rw-r--r--clippy_lints/src/tuple_array_conversions.rs235
-rw-r--r--clippy_lints/src/undocumented_unsafe_blocks.rs126
-rw-r--r--clippy_lints/src/unused_async.rs3
-rw-r--r--clippy_lints/src/upper_case_acronyms.rs2
-rw-r--r--clippy_lints/src/useless_conversion.rs121
-rw-r--r--clippy_lints/src/utils/conf.rs47
-rw-r--r--clippy_lints/src/utils/internal_lints.rs1
-rw-r--r--clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs87
-rw-r--r--clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs2
-rw-r--r--clippy_lints/src/utils/internal_lints/metadata_collector.rs28
-rw-r--r--clippy_lints/src/utils/mod.rs12
-rw-r--r--clippy_lints/src/vec.rs156
-rw-r--r--clippy_lints/src/visibility.rs131
106 files changed, 5394 insertions, 1181 deletions
diff --git a/clippy_lints/Cargo.toml b/clippy_lints/Cargo.toml
index be9261a4704..c23054443bb 100644
--- a/clippy_lints/Cargo.toml
+++ b/clippy_lints/Cargo.toml
@@ -22,6 +22,7 @@ serde = { version = "1.0", features = ["derive"] }
 serde_json = { version = "1.0", optional = true }
 tempfile = { version = "3.3.0", optional = true }
 toml = "0.7.3"
+regex = { version = "1.5", optional = true }
 unicode-normalization = "0.1"
 unicode-script = { version = "0.5", default-features = false }
 semver = "1.0"
@@ -31,7 +32,7 @@ url = "2.2"
 [features]
 deny-warnings = ["clippy_utils/deny-warnings"]
 # build clippy with internal lints enabled, off by default
-internal = ["clippy_utils/internal", "serde_json", "tempfile"]
+internal = ["clippy_utils/internal", "serde_json", "tempfile", "regex"]
 
 [package.metadata.rust-analyzer]
 # This crate uses #[feature(rustc_private)]
diff --git a/clippy_lints/src/allow_attributes.rs b/clippy_lints/src/allow_attributes.rs
index 554efdc58e1..eb21184713e 100644
--- a/clippy_lints/src/allow_attributes.rs
+++ b/clippy_lints/src/allow_attributes.rs
@@ -1,5 +1,5 @@
-use ast::AttrStyle;
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use ast::{AttrStyle, Attribute};
+use clippy_utils::{diagnostics::span_lint_and_sugg, is_from_proc_macro};
 use rustc_ast as ast;
 use rustc_errors::Applicability;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -50,13 +50,14 @@ declare_lint_pass!(AllowAttribute => [ALLOW_ATTRIBUTES]);
 
 impl LateLintPass<'_> for AllowAttribute {
     // Separate each crate's features.
-    fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
+    fn check_attribute<'cx>(&mut self, cx: &LateContext<'cx>, attr: &'cx Attribute) {
         if_chain! {
             if !in_external_macro(cx.sess(), attr.span);
             if cx.tcx.features().lint_reasons;
             if let AttrStyle::Outer = attr.style;
             if let Some(ident) = attr.ident();
             if ident.name == rustc_span::symbol::sym::allow;
+            if !is_from_proc_macro(cx, &attr);
             then {
                 span_lint_and_sugg(
                     cx,
diff --git a/clippy_lints/src/arc_with_non_send_sync.rs b/clippy_lints/src/arc_with_non_send_sync.rs
new file mode 100644
index 00000000000..a1e44668e1a
--- /dev/null
+++ b/clippy_lints/src/arc_with_non_send_sync.rs
@@ -0,0 +1,72 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::last_path_segment;
+use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use if_chain::if_chain;
+
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_lint::LateLintPass;
+use rustc_middle::ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::symbol::sym;
+
+declare_clippy_lint! {
+    /// ### What it does.
+    /// This lint warns when you use `Arc` with a type that does not implement `Send` or `Sync`.
+    ///
+    /// ### Why is this bad?
+    /// Wrapping a type in Arc doesn't add thread safety to the underlying data, so data races
+    /// could occur when touching the underlying data.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # use std::cell::RefCell;
+    /// # use std::sync::Arc;
+    ///
+    /// fn main() {
+    ///     // This is safe, as `i32` implements `Send` and `Sync`.
+    ///     let a = Arc::new(42);
+    ///
+    ///     // This is not safe, as `RefCell` does not implement `Sync`.
+    ///     let b = Arc::new(RefCell::new(42));
+    /// }
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub ARC_WITH_NON_SEND_SYNC,
+    correctness,
+    "using `Arc` with a type that does not implement `Send` or `Sync`"
+}
+declare_lint_pass!(ArcWithNonSendSync => [ARC_WITH_NON_SEND_SYNC]);
+
+impl LateLintPass<'_> for ArcWithNonSendSync {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        let ty = cx.typeck_results().expr_ty(expr);
+        if_chain! {
+            if is_type_diagnostic_item(cx, ty, sym::Arc);
+            if let ExprKind::Call(func, [arg]) = expr.kind;
+            if let ExprKind::Path(func_path) = func.kind;
+            if last_path_segment(&func_path).ident.name == sym::new;
+            if let arg_ty = cx.typeck_results().expr_ty(arg);
+            if !matches!(arg_ty.kind(), ty::Param(_));
+            if !cx.tcx
+                .lang_items()
+                .sync_trait()
+                .map_or(false, |id| implements_trait(cx, arg_ty, id, &[])) ||
+                !cx.tcx
+                .get_diagnostic_item(sym::Send)
+                .map_or(false, |id| implements_trait(cx, arg_ty, id, &[]));
+
+            then {
+                span_lint_and_help(
+                    cx,
+                    ARC_WITH_NON_SEND_SYNC,
+                    expr.span,
+                    "usage of `Arc<T>` where `T` is not `Send` or `Sync`",
+                    None,
+                    "consider using `Rc<T>` instead or wrapping `T` in a std::sync type like \
+                    `Mutex<T>`",
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/as_conversions.rs b/clippy_lints/src/as_conversions.rs
index c7a76e5f907..b9dda49ca41 100644
--- a/clippy_lints/src/as_conversions.rs
+++ b/clippy_lints/src/as_conversions.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use rustc_ast::ast::{Expr, ExprKind};
-use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use clippy_utils::is_from_proc_macro;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 
@@ -45,9 +46,9 @@ declare_clippy_lint! {
 
 declare_lint_pass!(AsConversions => [AS_CONVERSIONS]);
 
-impl EarlyLintPass for AsConversions {
-    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if in_external_macro(cx.sess(), expr.span) {
+impl<'tcx> LateLintPass<'tcx> for AsConversions {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
+        if in_external_macro(cx.sess(), expr.span) || is_from_proc_macro(cx, expr) {
             return;
         }
 
diff --git a/clippy_lints/src/attrs.rs b/clippy_lints/src/attrs.rs
index 897495ba108..2ba78f99569 100644
--- a/clippy_lints/src/attrs.rs
+++ b/clippy_lints/src/attrs.rs
@@ -1,9 +1,12 @@
 //! checks for attributes
 
-use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::macros::{is_panic, macro_backtrace};
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments};
+use clippy_utils::{
+    diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then},
+    is_from_proc_macro,
+};
 use if_chain::if_chain;
 use rustc_ast::{AttrKind, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem};
 use rustc_errors::Applicability;
@@ -362,6 +365,32 @@ declare_clippy_lint! {
     "ensure that all `cfg(any())` and `cfg(all())` have more than one condition"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `#[cfg(features = "...")]` and suggests to replace it with
+    /// `#[cfg(feature = "...")]`.
+    ///
+    /// ### Why is this bad?
+    /// Misspelling `feature` as `features` can be sometimes hard to spot. It
+    /// may cause conditional compilation not work quitely.
+    ///
+    /// ### Example
+    /// ```rust
+    /// #[cfg(features = "some-feature")]
+    /// fn conditional() { }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// #[cfg(feature = "some-feature")]
+    /// fn conditional() { }
+    /// ```
+    #[clippy::version = "1.69.0"]
+    pub MAYBE_MISUSED_CFG,
+    suspicious,
+    "prevent from misusing the wrong attr name"
+}
+
 declare_lint_pass!(Attributes => [
     ALLOW_ATTRIBUTES_WITHOUT_REASON,
     INLINE_ALWAYS,
@@ -540,7 +569,7 @@ fn check_clippy_lint_names(cx: &LateContext<'_>, name: Symbol, items: &[NestedMe
     }
 }
 
-fn check_lint_reason(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem], attr: &'_ Attribute) {
+fn check_lint_reason<'cx>(cx: &LateContext<'cx>, name: Symbol, items: &[NestedMetaItem], attr: &'cx Attribute) {
     // Check for the feature
     if !cx.tcx.features().lint_reasons {
         return;
@@ -555,7 +584,7 @@ fn check_lint_reason(cx: &LateContext<'_>, name: Symbol, items: &[NestedMetaItem
     }
 
     // Check if the attribute is in an external macro and therefore out of the developer's control
-    if in_external_macro(cx.sess(), attr.span) {
+    if in_external_macro(cx.sess(), attr.span) || is_from_proc_macro(cx, &attr) {
         return;
     }
 
@@ -676,6 +705,7 @@ impl_lint_pass!(EarlyAttributes => [
     EMPTY_LINE_AFTER_OUTER_ATTR,
     EMPTY_LINE_AFTER_DOC_COMMENTS,
     NON_MINIMAL_CFG,
+    MAYBE_MISUSED_CFG,
 ]);
 
 impl EarlyLintPass for EarlyAttributes {
@@ -687,6 +717,7 @@ impl EarlyLintPass for EarlyAttributes {
         check_deprecated_cfg_attr(cx, attr, &self.msrv);
         check_mismatched_target_os(cx, attr);
         check_minimal_cfg_condition(cx, attr);
+        check_misused_cfg(cx, attr);
     }
 
     extract_msrv_attr!(EarlyContext);
@@ -777,7 +808,7 @@ fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &Msr
 }
 
 fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) {
-    for item in items.iter() {
+    for item in items {
         if let NestedMetaItem::MetaItem(meta) = item {
             if !meta.has_name(sym::any) && !meta.has_name(sym::all) {
                 continue;
@@ -810,6 +841,27 @@ fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) {
     }
 }
 
+fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) {
+    for item in items {
+        if let NestedMetaItem::MetaItem(meta) = item {
+            if meta.has_name(sym!(features)) && let Some(val) = meta.value_str() {
+                span_lint_and_sugg(
+                    cx,
+                    MAYBE_MISUSED_CFG,
+                    meta.span,
+                    "feature may misspelled as features",
+                    "use",
+                    format!("feature = \"{val}\""),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+            if let MetaItemKind::List(list) = &meta.kind {
+                check_nested_misused_cfg(cx, list);
+            }
+        }
+    }
+}
+
 fn check_minimal_cfg_condition(cx: &EarlyContext<'_>, attr: &Attribute) {
     if attr.has_name(sym::cfg) &&
         let Some(items) = attr.meta_item_list()
@@ -818,6 +870,14 @@ fn check_minimal_cfg_condition(cx: &EarlyContext<'_>, attr: &Attribute) {
     }
 }
 
+fn check_misused_cfg(cx: &EarlyContext<'_>, attr: &Attribute) {
+    if attr.has_name(sym::cfg) &&
+        let Some(items) = attr.meta_item_list()
+    {
+        check_nested_misused_cfg(cx, &items);
+    }
+}
+
 fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) {
     fn find_os(name: &str) -> Option<&'static str> {
         UNIX_SYSTEMS
diff --git a/clippy_lints/src/booleans.rs b/clippy_lints/src/booleans.rs
index ff0102255a0..04cca9e3177 100644
--- a/clippy_lints/src/booleans.rs
+++ b/clippy_lints/src/booleans.rs
@@ -440,7 +440,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
                             diag.span_suggestions(
                                 e.span,
                                 "try",
-                                suggestions.into_iter(),
+                                suggestions,
                                 // nonminimal_bool can produce minimal but
                                 // not human readable expressions (#3141)
                                 Applicability::Unspecified,
diff --git a/clippy_lints/src/casts/borrow_as_ptr.rs b/clippy_lints/src/casts/borrow_as_ptr.rs
index 294d22d34de..b7256dd2eae 100644
--- a/clippy_lints/src/casts/borrow_as_ptr.rs
+++ b/clippy_lints/src/casts/borrow_as_ptr.rs
@@ -4,6 +4,7 @@ use clippy_utils::source::snippet_with_context;
 use rustc_errors::Applicability;
 use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind};
 use rustc_lint::LateContext;
+use rustc_middle::ty::adjustment::Adjust;
 
 use super::BORROW_AS_PTR;
 
@@ -23,6 +24,15 @@ pub(super) fn check<'tcx>(
         };
         let mut app = Applicability::MachineApplicable;
         let snip = snippet_with_context(cx, e.span, cast_expr.span.ctxt(), "..", &mut app).0;
+        // Fix #9884
+        if !e.is_place_expr(|base| {
+            cx.typeck_results()
+                .adjustments()
+                .get(base.hir_id)
+                .is_some_and(|x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_))))
+        }) {
+            return;
+        }
 
         span_lint_and_sugg(
             cx,
diff --git a/clippy_lints/src/casts/cast_possible_wrap.rs b/clippy_lints/src/casts/cast_possible_wrap.rs
index 28ecdea7ea0..ffa571abb39 100644
--- a/clippy_lints/src/casts/cast_possible_wrap.rs
+++ b/clippy_lints/src/casts/cast_possible_wrap.rs
@@ -1,41 +1,90 @@
-use clippy_utils::diagnostics::span_lint;
-use clippy_utils::ty::is_isize_or_usize;
 use rustc_hir::Expr;
-use rustc_lint::LateContext;
+use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty::Ty;
 
 use super::{utils, CAST_POSSIBLE_WRAP};
 
+// this should be kept in sync with the allowed bit widths of `usize` and `isize`
+const ALLOWED_POINTER_SIZES: [u64; 3] = [16, 32, 64];
+
+// whether the lint should be emitted, and the required pointer size, if it matters
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum EmitState {
+    NoLint,
+    LintAlways,
+    LintOnPtrSize(u64),
+}
+
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
     if !(cast_from.is_integral() && cast_to.is_integral()) {
         return;
     }
 
-    let arch_64_suffix = " on targets with 64-bit wide pointers";
-    let arch_32_suffix = " on targets with 32-bit wide pointers";
-    let cast_unsigned_to_signed = !cast_from.is_signed() && cast_to.is_signed();
+    // emit a lint if a cast is:
+    // 1. unsigned to signed
+    // and
+    // 2. either:
+    //
+    //    2a. between two types of constant size that are always the same size
+    //    2b. between one target-dependent size and one constant size integer,
+    //        and the constant integer is in the allowed set of target dependent sizes
+    //        (the ptr size could be chosen to be the same as the constant size)
+
+    if cast_from.is_signed() || !cast_to.is_signed() {
+        return;
+    }
+
     let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
     let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
 
-    let (should_lint, suffix) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) {
-        (true, true) | (false, false) => (to_nbits == from_nbits && cast_unsigned_to_signed, ""),
-        (true, false) => (to_nbits <= 32 && cast_unsigned_to_signed, arch_32_suffix),
-        (false, true) => (
-            cast_unsigned_to_signed,
-            if from_nbits == 64 {
-                arch_64_suffix
+    let should_lint = match (cast_from.is_ptr_sized_integral(), cast_to.is_ptr_sized_integral()) {
+        (true, true) => {
+            // casts between two ptr sized integers are trivially always the same size
+            // so do not depend on any specific pointer size to be the same
+            EmitState::LintAlways
+        },
+        (true, false) => {
+            // the first type is `usize` and the second is a constant sized signed integer
+            if ALLOWED_POINTER_SIZES.contains(&to_nbits) {
+                EmitState::LintOnPtrSize(to_nbits)
+            } else {
+                EmitState::NoLint
+            }
+        },
+        (false, true) => {
+            // the first type is a constant sized unsigned integer, and the second is `isize`
+            if ALLOWED_POINTER_SIZES.contains(&from_nbits) {
+                EmitState::LintOnPtrSize(from_nbits)
+            } else {
+                EmitState::NoLint
+            }
+        },
+        (false, false) => {
+            // the types are both a constant known size
+            // and do not depend on any specific pointer size to be the same
+            if from_nbits == to_nbits {
+                EmitState::LintAlways
             } else {
-                arch_32_suffix
-            },
+                EmitState::NoLint
+            }
+        },
+    };
+
+    let message = match should_lint {
+        EmitState::NoLint => return,
+        EmitState::LintAlways => format!("casting `{cast_from}` to `{cast_to}` may wrap around the value"),
+        EmitState::LintOnPtrSize(ptr_size) => format!(
+            "casting `{cast_from}` to `{cast_to}` may wrap around the value on targets with {ptr_size}-bit wide pointers",
         ),
     };
 
-    if should_lint {
-        span_lint(
-            cx,
-            CAST_POSSIBLE_WRAP,
-            expr.span,
-            &format!("casting `{cast_from}` to `{cast_to}` may wrap around the value{suffix}",),
-        );
-    }
+    cx.struct_span_lint(CAST_POSSIBLE_WRAP, expr.span, message, |diag| {
+        if let EmitState::LintOnPtrSize(16) = should_lint {
+            diag
+            .note("`usize` and `isize` may be as small as 16 bits on some platforms")
+            .note("for more information see https://doc.rust-lang.org/reference/types/numeric.html#machine-dependent-integer-types")
+        } else {
+            diag
+        }
+    });
 }
diff --git a/clippy_lints/src/casts/mod.rs b/clippy_lints/src/casts/mod.rs
index b90dab07a27..0ac6ef6496a 100644
--- a/clippy_lints/src/casts/mod.rs
+++ b/clippy_lints/src/casts/mod.rs
@@ -118,9 +118,10 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for casts from an unsigned type to a signed type of
-    /// the same size. Performing such a cast is a 'no-op' for the compiler,
-    /// i.e., nothing is changed at the bit level, and the binary representation of
-    /// the value is reinterpreted. This can cause wrapping if the value is too big
+    /// the same size, or possibly smaller due to target dependent integers.
+    /// Performing such a cast is a 'no-op' for the compiler, i.e., nothing is
+    /// changed at the bit level, and the binary representation of the value is
+    /// reinterpreted. This can cause wrapping if the value is too big
     /// for the target signed type. However, the cast works as defined, so this lint
     /// is `Allow` by default.
     ///
@@ -174,8 +175,8 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts to the same type, casts of int literals to integer types
-    /// and casts of float literals to float types.
+    /// Checks for casts to the same type, casts of int literals to integer types, casts of float
+    /// literals to float types and casts between raw pointers without changing type or constness.
     ///
     /// ### Why is this bad?
     /// It's just unnecessary.
@@ -522,7 +523,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Check for the usage of `as _` conversion using inferred type.
+    /// Checks for the usage of `as _` conversion using inferred type.
     ///
     /// ### Why is this bad?
     /// The conversion might include lossy conversion and dangerous cast that might go
diff --git a/clippy_lints/src/casts/ptr_cast_constness.rs b/clippy_lints/src/casts/ptr_cast_constness.rs
index ab015f8822e..f0c1df01430 100644
--- a/clippy_lints/src/casts/ptr_cast_constness.rs
+++ b/clippy_lints/src/casts/ptr_cast_constness.rs
@@ -9,20 +9,21 @@ use rustc_middle::ty::{self, Ty, TypeAndMut};
 
 use super::PTR_CAST_CONSTNESS;
 
-pub(super) fn check(
+pub(super) fn check<'tcx>(
     cx: &LateContext<'_>,
     expr: &Expr<'_>,
     cast_expr: &Expr<'_>,
-    cast_from: Ty<'_>,
-    cast_to: Ty<'_>,
+    cast_from: Ty<'tcx>,
+    cast_to: Ty<'tcx>,
     msrv: &Msrv,
 ) {
     if_chain! {
         if msrv.meets(POINTER_CAST_CONSTNESS);
-        if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, .. }) = cast_from.kind();
-        if let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, .. }) = cast_to.kind();
+        if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, ty: from_ty }) = cast_from.kind();
+        if let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, ty: to_ty }) = cast_to.kind();
         if matches!((from_mutbl, to_mutbl),
             (Mutability::Not, Mutability::Mut) | (Mutability::Mut, Mutability::Not));
+        if from_ty == to_ty;
         then {
             let sugg = Sugg::hir(cx, cast_expr, "_");
             let constness = match *to_mutbl {
@@ -34,7 +35,7 @@ pub(super) fn check(
                 cx,
                 PTR_CAST_CONSTNESS,
                 expr.span,
-                "`as` casting between raw pointers while changing its constness",
+                "`as` casting between raw pointers while changing only its constness",
                 &format!("try `pointer::cast_{constness}`, a safer alternative"),
                 format!("{}.cast_{constness}()", sugg.maybe_par()),
                 Applicability::MachineApplicable,
diff --git a/clippy_lints/src/casts/unnecessary_cast.rs b/clippy_lints/src/casts/unnecessary_cast.rs
index 804ae841100..71cf2aea0f8 100644
--- a/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/clippy_lints/src/casts/unnecessary_cast.rs
@@ -1,18 +1,21 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::numeric_literal::NumericLiteral;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::{get_parent_expr, path_to_local};
+use clippy_utils::visitors::{for_each_expr, Visitable};
+use clippy_utils::{get_parent_expr, get_parent_node, is_hir_ty_cfg_dependant, is_ty_alias, path_to_local};
 use if_chain::if_chain;
 use rustc_ast::{LitFloatType, LitIntType, LitKind};
 use rustc_errors::Applicability;
-use rustc_hir::def::Res;
-use rustc_hir::{Expr, ExprKind, Lit, QPath, TyKind, UnOp};
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::{Expr, ExprKind, Lit, Node, Path, QPath, TyKind, UnOp};
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::{self, FloatTy, InferTy, Ty};
+use std::ops::ControlFlow;
 
 use super::UNNECESSARY_CAST;
 
+#[expect(clippy::too_many_lines)]
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &Expr<'tcx>,
@@ -20,19 +23,84 @@ pub(super) fn check<'tcx>(
     cast_from: Ty<'tcx>,
     cast_to: Ty<'tcx>,
 ) -> bool {
-    // skip non-primitive type cast
+    let cast_str = snippet_opt(cx, cast_expr.span).unwrap_or_default();
+
+    if_chain! {
+        if let ty::RawPtr(..) = cast_from.kind();
+        // check both mutability and type are the same
+        if cast_from.kind() == cast_to.kind();
+        if let ExprKind::Cast(_, cast_to_hir) = expr.kind;
+        // Ignore casts to e.g. type aliases and infer types
+        // - p as pointer_alias
+        // - p as _
+        if let TyKind::Ptr(to_pointee) = cast_to_hir.kind;
+        then {
+            match to_pointee.ty.kind {
+                // Ignore casts to pointers that are aliases or cfg dependant, e.g.
+                // - p as *const std::ffi::c_char (alias)
+                // - p as *const std::os::raw::c_char (cfg dependant)
+                TyKind::Path(qpath) => {
+                    if is_ty_alias(&qpath) || is_hir_ty_cfg_dependant(cx, to_pointee.ty) {
+                        return false;
+                    }
+                },
+                // Ignore `p as *const _`
+                TyKind::Infer => return false,
+                _ => {},
+            }
+
+            span_lint_and_sugg(
+                cx,
+                UNNECESSARY_CAST,
+                expr.span,
+                &format!("casting raw pointers to the same type and constness is unnecessary (`{cast_from}` -> `{cast_to}`)"),
+                "try",
+                cast_str.clone(),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
+    // skip cast of local that is a type alias
+    if let ExprKind::Cast(inner, ..) = expr.kind
+        && let ExprKind::Path(qpath) = inner.kind
+        && let QPath::Resolved(None, Path { res, .. }) = qpath
+        && let Res::Local(hir_id) = res
+        && let parent = cx.tcx.hir().get_parent(*hir_id)
+        && let Node::Local(local) = parent
+    {
+        if let Some(ty) = local.ty
+            && let TyKind::Path(qpath) = ty.kind
+            && is_ty_alias(&qpath)
+        {
+            return false;
+        }
+
+        if let Some(expr) = local.init
+            && let ExprKind::Cast(.., cast_to) = expr.kind
+            && let TyKind::Path(qpath) = cast_to.kind
+            && is_ty_alias(&qpath)
+        {
+            return false;
+        }
+    }
+
+    // skip cast of fn call that returns type alias
+    if let ExprKind::Cast(inner, ..) = expr.kind && is_cast_from_ty_alias(cx, inner, cast_from) {
+        return false;
+    }
+
+    // skip cast to non-primitive type
     if_chain! {
         if let ExprKind::Cast(_, cast_to) = expr.kind;
         if let TyKind::Path(QPath::Resolved(_, path)) = &cast_to.kind;
         if let Res::PrimTy(_) = path.res;
         then {}
         else {
-            return false
+            return false;
         }
     }
 
-    let cast_str = snippet_opt(cx, cast_expr.span).unwrap_or_default();
-
     if let Some(lit) = get_numeric_literal(cast_expr) {
         let literal_str = &cast_str;
 
@@ -162,3 +230,61 @@ fn fp_ty_mantissa_nbits(typ: Ty<'_>) -> u32 {
         _ => 0,
     }
 }
+
+/// Finds whether an `Expr` returns a type alias.
+///
+/// TODO: Maybe we should move this to `clippy_utils` so others won't need to go down this dark,
+/// dark path reimplementing this (or something similar).
+fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx>, cast_from: Ty<'tcx>) -> bool {
+    for_each_expr(expr, |expr| {
+        // Calls are a `Path`, and usage of locals are a `Path`. So, this checks
+        // - call() as i32
+        // - local as i32
+        if let ExprKind::Path(qpath) = expr.kind {
+            let res = cx.qpath_res(&qpath, expr.hir_id);
+            // Function call
+            if let Res::Def(DefKind::Fn, def_id) = res {
+                let Some(snippet) = snippet_opt(cx, cx.tcx.def_span(def_id)) else {
+                    return ControlFlow::Continue(());
+                };
+                // This is the worst part of this entire function. This is the only way I know of to
+                // check whether a function returns a type alias. Sure, you can get the return type
+                // from a function in the current crate as an hir ty, but how do you get it for
+                // external functions?? Simple: It's impossible. So, we check whether a part of the
+                // function's declaration snippet is exactly equal to the `Ty`. That way, we can
+                // see whether it's a type alias.
+                //
+                // Will this work for more complex types? Probably not!
+                if !snippet
+                    .split("->")
+                    .skip(0)
+                    .map(|s| {
+                        s.trim() == cast_from.to_string()
+                            || s.split("where").any(|ty| ty.trim() == cast_from.to_string())
+                    })
+                    .any(|a| a)
+                {
+                    return ControlFlow::Break(());
+                }
+            // Local usage
+            } else if let Res::Local(hir_id) = res
+                && let Some(parent) = get_parent_node(cx.tcx, hir_id)
+                && let Node::Local(l) = parent
+            {
+                if let Some(e) = l.init && is_cast_from_ty_alias(cx, e, cast_from) {
+                    return ControlFlow::Break::<()>(());
+                }
+
+                if let Some(ty) = l.ty
+                    && let TyKind::Path(qpath) = ty.kind
+                    && is_ty_alias(&qpath)
+                {
+                    return ControlFlow::Break::<()>(());
+                }
+            }
+        }
+
+        ControlFlow::Continue(())
+    })
+    .is_some()
+}
diff --git a/clippy_lints/src/declared_lints.rs b/clippy_lints/src/declared_lints.rs
index f1d1355123a..9d9ee6ba307 100644
--- a/clippy_lints/src/declared_lints.rs
+++ b/clippy_lints/src/declared_lints.rs
@@ -4,6 +4,8 @@
 
 pub(crate) static LINTS: &[&crate::LintInfo] = &[
     #[cfg(feature = "internal")]
+    crate::utils::internal_lints::almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION_INFO,
+    #[cfg(feature = "internal")]
     crate::utils::internal_lints::clippy_lints_internal::CLIPPY_LINTS_INTERNAL_INFO,
     #[cfg(feature = "internal")]
     crate::utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS_INFO,
@@ -38,6 +40,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::allow_attributes::ALLOW_ATTRIBUTES_INFO,
     crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO,
     crate::approx_const::APPROX_CONSTANT_INFO,
+    crate::arc_with_non_send_sync::ARC_WITH_NON_SEND_SYNC_INFO,
     crate::as_conversions::AS_CONVERSIONS_INFO,
     crate::asm_syntax::INLINE_ASM_X86_ATT_SYNTAX_INFO,
     crate::asm_syntax::INLINE_ASM_X86_INTEL_SYNTAX_INFO,
@@ -51,6 +54,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::attrs::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO,
     crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO,
     crate::attrs::INLINE_ALWAYS_INFO,
+    crate::attrs::MAYBE_MISUSED_CFG_INFO,
     crate::attrs::MISMATCHED_TARGET_OS_INFO,
     crate::attrs::NON_MINIMAL_CFG_INFO,
     crate::attrs::USELESS_ATTRIBUTE_INFO,
@@ -136,11 +140,15 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::double_parens::DOUBLE_PARENS_INFO,
     crate::drop_forget_ref::DROP_NON_DROP_INFO,
     crate::drop_forget_ref::FORGET_NON_DROP_INFO,
+    crate::drop_forget_ref::MEM_FORGET_INFO,
     crate::duplicate_mod::DUPLICATE_MOD_INFO,
     crate::else_if_without_else::ELSE_IF_WITHOUT_ELSE_INFO,
     crate::empty_drop::EMPTY_DROP_INFO,
     crate::empty_enum::EMPTY_ENUM_INFO,
     crate::empty_structs_with_brackets::EMPTY_STRUCTS_WITH_BRACKETS_INFO,
+    crate::endian_bytes::BIG_ENDIAN_BYTES_INFO,
+    crate::endian_bytes::HOST_ENDIAN_BYTES_INFO,
+    crate::endian_bytes::LITTLE_ENDIAN_BYTES_INFO,
     crate::entry::MAP_ENTRY_INFO,
     crate::enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT_INFO,
     crate::enum_variants::ENUM_VARIANT_NAMES_INFO,
@@ -152,6 +160,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS_INFO,
     crate::excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS_INFO,
     crate::excessive_bools::STRUCT_EXCESSIVE_BOOLS_INFO,
+    crate::excessive_nesting::EXCESSIVE_NESTING_INFO,
     crate::exhaustive_items::EXHAUSTIVE_ENUMS_INFO,
     crate::exhaustive_items::EXHAUSTIVE_STRUCTS_INFO,
     crate::exit::EXIT_INFO,
@@ -197,6 +206,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::implicit_saturating_add::IMPLICIT_SATURATING_ADD_INFO,
     crate::implicit_saturating_sub::IMPLICIT_SATURATING_SUB_INFO,
     crate::inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR_INFO,
+    crate::incorrect_impls::INCORRECT_CLONE_IMPL_ON_COPY_TYPE_INFO,
     crate::index_refutable_slice::INDEX_REFUTABLE_SLICE_INFO,
     crate::indexing_slicing::INDEXING_SLICING_INFO,
     crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO,
@@ -219,6 +229,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::large_futures::LARGE_FUTURES_INFO,
     crate::large_include_file::LARGE_INCLUDE_FILE_INFO,
     crate::large_stack_arrays::LARGE_STACK_ARRAYS_INFO,
+    crate::large_stack_frames::LARGE_STACK_FRAMES_INFO,
     crate::len_zero::COMPARISON_TO_EMPTY_INFO,
     crate::len_zero::LEN_WITHOUT_IS_EMPTY_INFO,
     crate::len_zero::LEN_ZERO_INFO,
@@ -266,6 +277,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::manual_let_else::MANUAL_LET_ELSE_INFO,
     crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO,
     crate::manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE_INFO,
+    crate::manual_range_patterns::MANUAL_RANGE_PATTERNS_INFO,
     crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO,
     crate::manual_retain::MANUAL_RETAIN_INFO,
     crate::manual_slice_size_calculation::MANUAL_SLICE_SIZE_CALCULATION_INFO,
@@ -299,7 +311,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::matches::TRY_ERR_INFO,
     crate::matches::WILDCARD_ENUM_MATCH_ARM_INFO,
     crate::matches::WILDCARD_IN_OR_PATTERNS_INFO,
-    crate::mem_forget::MEM_FORGET_INFO,
     crate::mem_replace::MEM_REPLACE_OPTION_WITH_NONE_INFO,
     crate::mem_replace::MEM_REPLACE_WITH_DEFAULT_INFO,
     crate::mem_replace::MEM_REPLACE_WITH_UNINIT_INFO,
@@ -314,6 +325,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::CLONE_ON_COPY_INFO,
     crate::methods::CLONE_ON_REF_PTR_INFO,
     crate::methods::COLLAPSIBLE_STR_REPLACE_INFO,
+    crate::methods::DRAIN_COLLECT_INFO,
     crate::methods::ERR_EXPECT_INFO,
     crate::methods::EXPECT_FUN_CALL_INFO,
     crate::methods::EXPECT_USED_INFO,
@@ -352,6 +364,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::MANUAL_SATURATING_ARITHMETIC_INFO,
     crate::methods::MANUAL_SPLIT_ONCE_INFO,
     crate::methods::MANUAL_STR_REPEAT_INFO,
+    crate::methods::MANUAL_TRY_FOLD_INFO,
     crate::methods::MAP_CLONE_INFO,
     crate::methods::MAP_COLLECT_RESULT_UNIT_INFO,
     crate::methods::MAP_ERR_IGNORE_INFO,
@@ -398,6 +411,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::UNNECESSARY_FOLD_INFO,
     crate::methods::UNNECESSARY_JOIN_INFO,
     crate::methods::UNNECESSARY_LAZY_EVALUATIONS_INFO,
+    crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO,
     crate::methods::UNNECESSARY_SORT_BY_INFO,
     crate::methods::UNNECESSARY_TO_OWNED_INFO,
     crate::methods::UNWRAP_OR_ELSE_DEFAULT_INFO,
@@ -407,6 +421,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::methods::VERBOSE_FILE_READS_INFO,
     crate::methods::WRONG_SELF_CONVENTION_INFO,
     crate::methods::ZST_OFFSET_INFO,
+    crate::min_ident_chars::MIN_IDENT_CHARS_INFO,
     crate::minmax::MIN_MAX_INFO,
     crate::misc::SHORT_CIRCUIT_STATEMENT_INFO,
     crate::misc::TOPLEVEL_REF_ARG_INFO,
@@ -416,6 +431,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::misc_early::DOUBLE_NEG_INFO,
     crate::misc_early::DUPLICATE_UNDERSCORE_ARGUMENT_INFO,
     crate::misc_early::MIXED_CASE_HEX_LITERALS_INFO,
+    crate::misc_early::REDUNDANT_AT_REST_PATTERN_INFO,
     crate::misc_early::REDUNDANT_PATTERN_INFO,
     crate::misc_early::SEPARATED_LITERAL_SUFFIX_INFO,
     crate::misc_early::UNNEEDED_FIELD_PATTERN_INFO,
@@ -450,6 +466,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::needless_continue::NEEDLESS_CONTINUE_INFO,
     crate::needless_else::NEEDLESS_ELSE_INFO,
     crate::needless_for_each::NEEDLESS_FOR_EACH_INFO,
+    crate::needless_if::NEEDLESS_IF_INFO,
     crate::needless_late_init::NEEDLESS_LATE_INIT_INFO,
     crate::needless_parens_on_range_literals::NEEDLESS_PARENS_ON_RANGE_LITERALS_INFO,
     crate::needless_pass_by_value::NEEDLESS_PASS_BY_VALUE_INFO,
@@ -524,6 +541,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::ranges::RANGE_MINUS_ONE_INFO,
     crate::ranges::RANGE_PLUS_ONE_INFO,
     crate::ranges::REVERSED_EMPTY_RANGES_INFO,
+    crate::raw_strings::NEEDLESS_RAW_STRINGS_INFO,
+    crate::raw_strings::NEEDLESS_RAW_STRING_HASHES_INFO,
     crate::rc_clone_in_vec_init::RC_CLONE_IN_VEC_INIT_INFO,
     crate::read_zero_byte_vec::READ_ZERO_BYTE_VEC_INFO,
     crate::redundant_async_block::REDUNDANT_ASYNC_BLOCK_INFO,
@@ -535,6 +554,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::redundant_slicing::DEREF_BY_SLICING_INFO,
     crate::redundant_slicing::REDUNDANT_SLICING_INFO,
     crate::redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES_INFO,
+    crate::redundant_type_annotations::REDUNDANT_TYPE_ANNOTATIONS_INFO,
     crate::ref_option_ref::REF_OPTION_REF_INFO,
     crate::ref_patterns::REF_PATTERNS_INFO,
     crate::reference::DEREF_ADDROF_INFO,
@@ -553,8 +573,10 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::shadow::SHADOW_SAME_INFO,
     crate::shadow::SHADOW_UNRELATED_INFO,
     crate::significant_drop_tightening::SIGNIFICANT_DROP_TIGHTENING_INFO,
+    crate::single_call_fn::SINGLE_CALL_FN_INFO,
     crate::single_char_lifetime_names::SINGLE_CHAR_LIFETIME_NAMES_INFO,
     crate::single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS_INFO,
+    crate::single_range_in_vec_init::SINGLE_RANGE_IN_VEC_INIT_INFO,
     crate::size_of_in_element_count::SIZE_OF_IN_ELEMENT_COUNT_INFO,
     crate::size_of_ref::SIZE_OF_REF_INFO,
     crate::slow_vector_initialization::SLOW_VECTOR_INITIALIZATION_INFO,
@@ -602,6 +624,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::transmute::UNSOUND_COLLECTION_TRANSMUTE_INFO,
     crate::transmute::USELESS_TRANSMUTE_INFO,
     crate::transmute::WRONG_TRANSMUTE_INFO,
+    crate::tuple_array_conversions::TUPLE_ARRAY_CONVERSIONS_INFO,
     crate::types::BORROWED_BOX_INFO,
     crate::types::BOX_COLLECTION_INFO,
     crate::types::LINKEDLIST_INFO,
@@ -644,6 +667,9 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::useless_conversion::USELESS_CONVERSION_INFO,
     crate::vec::USELESS_VEC_INFO,
     crate::vec_init_then_push::VEC_INIT_THEN_PUSH_INFO,
+    crate::visibility::NEEDLESS_PUB_SELF_INFO,
+    crate::visibility::PUB_WITHOUT_SHORTHAND_INFO,
+    crate::visibility::PUB_WITH_SHORTHAND_INFO,
     crate::wildcard_imports::ENUM_GLOB_USE_INFO,
     crate::wildcard_imports::WILDCARD_IMPORTS_INFO,
     crate::write::PRINTLN_EMPTY_STRING_INFO,
diff --git a/clippy_lints/src/default_constructed_unit_structs.rs b/clippy_lints/src/default_constructed_unit_structs.rs
index fb037bbcbf3..ca9514ccc7d 100644
--- a/clippy_lints/src/default_constructed_unit_structs.rs
+++ b/clippy_lints/src/default_constructed_unit_structs.rs
@@ -8,7 +8,7 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Check for construction on unit struct using `default`.
+    /// Checks for construction on unit struct using `default`.
     ///
     /// ### Why is this bad?
     /// This adds code complexity and an unnecessary function call.
diff --git a/clippy_lints/src/default_numeric_fallback.rs b/clippy_lints/src/default_numeric_fallback.rs
index 4e1a6cd4d73..e53a9877b20 100644
--- a/clippy_lints/src/default_numeric_fallback.rs
+++ b/clippy_lints/src/default_numeric_fallback.rs
@@ -161,7 +161,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
                         let fields_def = &variant.fields;
 
                         // Push field type then visit each field expr.
-                        for field in fields.iter() {
+                        for field in *fields {
                             let bound =
                                 fields_def
                                     .iter()
diff --git a/clippy_lints/src/dereference.rs b/clippy_lints/src/dereference.rs
index 1ecaa1a123c..73556c1053e 100644
--- a/clippy_lints/src/dereference.rs
+++ b/clippy_lints/src/dereference.rs
@@ -56,9 +56,11 @@ declare_clippy_lint! {
     /// let b = &*a;
     /// ```
     ///
-    /// This lint excludes:
+    /// This lint excludes all of:
     /// ```rust,ignore
     /// let _ = d.unwrap().deref();
+    /// let _ = Foo::deref(&foo);
+    /// let _ = <Foo as Deref>::deref(&foo);
     /// ```
     #[clippy::version = "1.44.0"]
     pub EXPLICIT_DEREF_METHODS,
@@ -355,15 +357,17 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
                         //    start auto-deref.
                         // 4. If the chain of non-user-defined derefs ends with a mutable re-borrow, and re-borrow
                         //    adjustments will not be inserted automatically, then leave one further reference to avoid
-                        //    moving a mutable borrow.
-                        //    e.g.
-                        //        fn foo<T>(x: &mut Option<&mut T>, y: &mut T) {
-                        //            let x = match x {
-                        //                // Removing the borrow will cause `x` to be moved
-                        //                Some(x) => &mut *x,
-                        //                None => y
-                        //            };
-                        //        }
+                        //    moving a mutable borrow. e.g.
+                        //
+                        //    ```rust
+                        //    fn foo<T>(x: &mut Option<&mut T>, y: &mut T) {
+                        //        let x = match x {
+                        //            // Removing the borrow will cause `x` to be moved
+                        //            Some(x) => &mut *x,
+                        //            None => y
+                        //        };
+                        //    }
+                        //    ```
                         let deref_msg =
                             "this expression creates a reference which is immediately dereferenced by the compiler";
                         let borrow_msg = "this expression borrows a value the compiler would automatically borrow";
@@ -1481,7 +1485,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
             target_mut,
         } => {
             let mut app = Applicability::MachineApplicable;
-            let (expr_str, expr_is_macro_call) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
+            let (expr_str, _expr_is_macro_call) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app);
             let ty = cx.typeck_results().expr_ty(expr);
             let (_, ref_count) = peel_mid_ty_refs(ty);
             let deref_str = if ty_changed_count >= ref_count && ref_count != 0 {
@@ -1504,11 +1508,20 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data
                 "&"
             };
 
-            let expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence().order() < PREC_PREFIX {
-                format!("({expr_str})")
+            // expr_str (the suggestion) is never shown if is_final_ufcs is true, since it's
+            // `expr.kind == ExprKind::Call`. Therefore, this is, afaik, always unnecessary.
+            /*
+            expr_str = if !expr_is_macro_call && is_final_ufcs && expr.precedence().order() < PREC_PREFIX {
+                Cow::Owned(format!("({expr_str})"))
             } else {
-                expr_str.into_owned()
+                expr_str
             };
+            */
+
+            // Fix #10850, do not lint if it's `Foo::deref` instead of `foo.deref()`.
+            if is_final_ufcs {
+                return;
+            }
 
             span_lint_and_sugg(
                 cx,
diff --git a/clippy_lints/src/derivable_impls.rs b/clippy_lints/src/derivable_impls.rs
index 8f68f90a2a1..ec0ca50cfec 100644
--- a/clippy_lints/src/derivable_impls.rs
+++ b/clippy_lints/src/derivable_impls.rs
@@ -4,11 +4,13 @@ use clippy_utils::source::indent_of;
 use clippy_utils::{is_default_equivalent, peel_blocks};
 use rustc_errors::Applicability;
 use rustc_hir::{
+    self as hir,
     def::{CtorKind, CtorOf, DefKind, Res},
-    Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, Ty, TyKind,
+    Body, Expr, ExprKind, GenericArg, Impl, ImplItemKind, Item, ItemKind, Node, PathSegment, QPath, TyKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{Adt, AdtDef, SubstsRef};
+use rustc_middle::ty::adjustment::{Adjust, PointerCast};
+use rustc_middle::ty::{self, Adt, AdtDef, SubstsRef, Ty, TypeckResults};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::sym;
 
@@ -75,13 +77,23 @@ fn is_path_self(e: &Expr<'_>) -> bool {
     }
 }
 
+fn contains_trait_object(ty: Ty<'_>) -> bool {
+    match ty.kind() {
+        ty::Ref(_, ty, _) => contains_trait_object(*ty),
+        ty::Adt(def, substs) => def.is_box() && substs[0].as_type().map_or(false, contains_trait_object),
+        ty::Dynamic(..) => true,
+        _ => false,
+    }
+}
+
 fn check_struct<'tcx>(
     cx: &LateContext<'tcx>,
     item: &'tcx Item<'_>,
-    self_ty: &Ty<'_>,
+    self_ty: &hir::Ty<'_>,
     func_expr: &Expr<'_>,
     adt_def: AdtDef<'_>,
     substs: SubstsRef<'_>,
+    typeck_results: &'tcx TypeckResults<'tcx>,
 ) {
     if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind {
         if let Some(PathSegment { args, .. }) = p.segments.last() {
@@ -96,10 +108,23 @@ fn check_struct<'tcx>(
             }
         }
     }
+
+    // the default() call might unsize coerce to a trait object (e.g. Box<T> to Box<dyn Trait>),
+    // which would not be the same if derived (see #10158).
+    // this closure checks both if the expr is equivalent to a `default()` call and does not
+    // have such coercions.
+    let is_default_without_adjusts = |expr| {
+        is_default_equivalent(cx, expr)
+            && typeck_results.expr_adjustments(expr).iter().all(|adj| {
+                !matches!(adj.kind, Adjust::Pointer(PointerCast::Unsize)
+                    if contains_trait_object(adj.target))
+            })
+    };
+
     let should_emit = match peel_blocks(func_expr).kind {
-        ExprKind::Tup(fields) => fields.iter().all(|e| is_default_equivalent(cx, e)),
-        ExprKind::Call(callee, args) if is_path_self(callee) => args.iter().all(|e| is_default_equivalent(cx, e)),
-        ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_equivalent(cx, ef.expr)),
+        ExprKind::Tup(fields) => fields.iter().all(is_default_without_adjusts),
+        ExprKind::Call(callee, args) if is_path_self(callee) => args.iter().all(is_default_without_adjusts),
+        ExprKind::Struct(_, fields, _) => fields.iter().all(|ef| is_default_without_adjusts(ef.expr)),
         _ => false,
     };
 
@@ -197,7 +222,7 @@ impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
 
             then {
                 if adt_def.is_struct() {
-                    check_struct(cx, item, self_ty, func_expr, adt_def, substs);
+                    check_struct(cx, item, self_ty, func_expr, adt_def, substs, cx.tcx.typeck_body(*b));
                 } else if adt_def.is_enum() && self.msrv.meets(msrvs::DEFAULT_ENUM_ATTRIBUTE) {
                     check_enum(cx, item, func_expr, adt_def);
                 }
diff --git a/clippy_lints/src/derive.rs b/clippy_lints/src/derive.rs
index 10a2f0cb1e7..a005a360e9c 100644
--- a/clippy_lints/src/derive.rs
+++ b/clippy_lints/src/derive.rs
@@ -14,8 +14,8 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::{
-    self, BoundConstness, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv,
-    ToPredicate, TraitPredicate, Ty, TyCtxt,
+    self, BoundConstness, ClauseKind, GenericArgKind, GenericParamDefKind, ImplPolarity, ParamEnv, ToPredicate,
+    TraitPredicate, Ty, TyCtxt,
 };
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::def_id::LocalDefId;
@@ -520,7 +520,8 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) ->
                     trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]),
                     constness: BoundConstness::NotConst,
                     polarity: ImplPolarity::Positive,
-                }).to_predicate(tcx)
+                })
+                .to_predicate(tcx)
             }),
         )),
         Reveal::UserFacing,
diff --git a/clippy_lints/src/doc.rs b/clippy_lints/src/doc.rs
index 384aca7fead..87d88f70752 100644
--- a/clippy_lints/src/doc.rs
+++ b/clippy_lints/src/doc.rs
@@ -571,6 +571,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
     let mut in_link = None;
     let mut in_heading = false;
     let mut is_rust = false;
+    let mut no_test = false;
     let mut edition = None;
     let mut ticks_unbalanced = false;
     let mut text_to_check: Vec<(CowStr<'_>, Span)> = Vec::new();
@@ -584,6 +585,8 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                         if item == "ignore" {
                             is_rust = false;
                             break;
+                        } else if item == "no_test" {
+                            no_test = true;
                         }
                         if let Some(stripped) = item.strip_prefix("edition") {
                             is_rust = true;
@@ -648,7 +651,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                 headers.errors |= in_heading && trimmed_text == "Errors";
                 headers.panics |= in_heading && trimmed_text == "Panics";
                 if in_code {
-                    if is_rust {
+                    if is_rust && !no_test {
                         let edition = edition.unwrap_or_else(|| cx.tcx.sess.edition());
                         check_code(cx, &text, edition, span);
                     }
@@ -906,15 +909,15 @@ impl<'a, 'tcx> Visitor<'tcx> for FindPanicUnwrap<'a, 'tcx> {
             if is_panic(self.cx, macro_call.def_id)
                 || matches!(
                     self.cx.tcx.item_name(macro_call.def_id).as_str(),
-                    "assert" | "assert_eq" | "assert_ne" | "todo"
+                    "assert" | "assert_eq" | "assert_ne"
                 )
             {
                 self.panic_span = Some(macro_call.span);
             }
         }
 
-        // check for `unwrap`
-        if let Some(arglists) = method_chain_args(expr, &["unwrap"]) {
+        // check for `unwrap` and `expect` for both `Option` and `Result`
+        if let Some(arglists) = method_chain_args(expr, &["unwrap"]).or(method_chain_args(expr, &["expect"])) {
             let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs();
             if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option)
                 || is_type_diagnostic_item(self.cx, receiver_ty, sym::Result)
diff --git a/clippy_lints/src/drop_forget_ref.rs b/clippy_lints/src/drop_forget_ref.rs
index 7a4b9a87aeb..976ce47e869 100644
--- a/clippy_lints/src/drop_forget_ref.rs
+++ b/clippy_lints/src/drop_forget_ref.rs
@@ -6,6 +6,7 @@ use rustc_hir::{Arm, Expr, ExprKind, LangItem, Node};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
+use std::borrow::Cow;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -47,6 +48,27 @@ declare_clippy_lint! {
     "call to `std::mem::forget` with a value which does not implement `Drop`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `std::mem::forget(t)` where `t` is
+    /// `Drop` or has a field that implements `Drop`.
+    ///
+    /// ### Why is this bad?
+    /// `std::mem::forget(t)` prevents `t` from running its
+    /// destructor, possibly causing leaks.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # use std::mem;
+    /// # use std::rc::Rc;
+    /// mem::forget(Rc::new(55))
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub MEM_FORGET,
+    restriction,
+    "`mem::forget` usage on `Drop` types, likely to cause memory leaks"
+}
+
 const DROP_NON_DROP_SUMMARY: &str = "call to `std::mem::drop` with a value that does not implement `Drop`. \
                                  Dropping such a type only extends its contained lifetimes";
 const FORGET_NON_DROP_SUMMARY: &str = "call to `std::mem::forget` with a value that does not implement `Drop`. \
@@ -55,6 +77,7 @@ const FORGET_NON_DROP_SUMMARY: &str = "call to `std::mem::forget` with a value t
 declare_lint_pass!(DropForgetRef => [
     DROP_NON_DROP,
     FORGET_NON_DROP,
+    MEM_FORGET,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
@@ -67,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
             let arg_ty = cx.typeck_results().expr_ty(arg);
             let is_copy = is_copy(cx, arg_ty);
             let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr);
-            let (lint, msg) = match fn_name {
+            let (lint, msg, note_span) = match fn_name {
                 // early return for uplifted lints: dropping_references, dropping_copy_types, forgetting_references, forgetting_copy_types
                 sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => return,
                 sym::mem_forget if arg_ty.is_ref() => return,
@@ -81,19 +104,34 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
                         || drop_is_single_call_in_arm
                         ) =>
                 {
-                    (DROP_NON_DROP, DROP_NON_DROP_SUMMARY)
-                },
-                sym::mem_forget if !arg_ty.needs_drop(cx.tcx, cx.param_env) => {
-                    (FORGET_NON_DROP, FORGET_NON_DROP_SUMMARY)
+                    (DROP_NON_DROP, DROP_NON_DROP_SUMMARY.into(), Some(arg.span))
                 },
+                sym::mem_forget => {
+                    if arg_ty.needs_drop(cx.tcx, cx.param_env) {
+                        (
+                            MEM_FORGET,
+                            Cow::Owned(format!(
+                                "usage of `mem::forget` on {}",
+                                if arg_ty.ty_adt_def().map_or(false, |def| def.has_dtor(cx.tcx)) {
+                                    "`Drop` type"
+                                } else {
+                                    "type with `Drop` fields"
+                                }
+                            )),
+                            None,
+                        )
+                    } else {
+                        (FORGET_NON_DROP, FORGET_NON_DROP_SUMMARY.into(), Some(arg.span))
+                    }
+                }
                 _ => return,
             };
             span_lint_and_note(
                 cx,
                 lint,
                 expr.span,
-                msg,
-                Some(arg.span),
+                &msg,
+                note_span,
                 &format!("argument has type `{arg_ty}`"),
             );
         }
diff --git a/clippy_lints/src/endian_bytes.rs b/clippy_lints/src/endian_bytes.rs
new file mode 100644
index 00000000000..f470987833e
--- /dev/null
+++ b/clippy_lints/src/endian_bytes.rs
@@ -0,0 +1,216 @@
+use crate::Lint;
+use clippy_utils::{diagnostics::span_lint_and_then, is_lint_allowed};
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::{lint::in_external_macro, ty::Ty};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::Symbol;
+use std::borrow::Cow;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for the usage of the `to_ne_bytes` method and/or the function `from_ne_bytes`.
+    ///
+    /// ### Why is this bad?
+    /// It's not, but some may prefer to specify the target endianness explicitly.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// let _x = 2i32.to_ne_bytes();
+    /// let _y = 2i64.to_ne_bytes();
+    /// ```
+    #[clippy::version = "1.71.0"]
+    pub HOST_ENDIAN_BYTES,
+    restriction,
+    "disallows usage of the `to_ne_bytes` method"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for the usage of the `to_le_bytes` method and/or the function `from_le_bytes`.
+    ///
+    /// ### Why is this bad?
+    /// It's not, but some may wish to lint usage of this method, either to suggest using the host
+    /// endianness or big endian.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// let _x = 2i32.to_le_bytes();
+    /// let _y = 2i64.to_le_bytes();
+    /// ```
+    #[clippy::version = "1.71.0"]
+    pub LITTLE_ENDIAN_BYTES,
+    restriction,
+    "disallows usage of the `to_le_bytes` method"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for the usage of the `to_be_bytes` method and/or the function `from_be_bytes`.
+    ///
+    /// ### Why is this bad?
+    /// It's not, but some may wish to lint usage of this method, either to suggest using the host
+    /// endianness or little endian.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// let _x = 2i32.to_be_bytes();
+    /// let _y = 2i64.to_be_bytes();
+    /// ```
+    #[clippy::version = "1.71.0"]
+    pub BIG_ENDIAN_BYTES,
+    restriction,
+    "disallows usage of the `to_be_bytes` method"
+}
+
+declare_lint_pass!(EndianBytes => [HOST_ENDIAN_BYTES, LITTLE_ENDIAN_BYTES, BIG_ENDIAN_BYTES]);
+
+const HOST_NAMES: [&str; 2] = ["from_ne_bytes", "to_ne_bytes"];
+const LITTLE_NAMES: [&str; 2] = ["from_le_bytes", "to_le_bytes"];
+const BIG_NAMES: [&str; 2] = ["from_be_bytes", "to_be_bytes"];
+
+#[derive(Clone, Debug)]
+enum LintKind {
+    Host,
+    Little,
+    Big,
+}
+
+#[derive(Clone, Copy, PartialEq)]
+enum Prefix {
+    From,
+    To,
+}
+
+impl LintKind {
+    fn allowed(&self, cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+        is_lint_allowed(cx, self.as_lint(), expr.hir_id)
+    }
+
+    fn as_lint(&self) -> &'static Lint {
+        match self {
+            LintKind::Host => HOST_ENDIAN_BYTES,
+            LintKind::Little => LITTLE_ENDIAN_BYTES,
+            LintKind::Big => BIG_ENDIAN_BYTES,
+        }
+    }
+
+    fn as_name(&self, prefix: Prefix) -> &str {
+        let index = usize::from(prefix == Prefix::To);
+
+        match self {
+            LintKind::Host => HOST_NAMES[index],
+            LintKind::Little => LITTLE_NAMES[index],
+            LintKind::Big => BIG_NAMES[index],
+        }
+    }
+}
+
+impl LateLintPass<'_> for EndianBytes {
+    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+        if in_external_macro(cx.sess(), expr.span) {
+            return;
+        }
+
+        if_chain! {
+            if let ExprKind::MethodCall(method_name, receiver, args, ..) = expr.kind;
+            if args.is_empty();
+            let ty = cx.typeck_results().expr_ty(receiver);
+            if ty.is_primitive_ty();
+            if maybe_lint_endian_bytes(cx, expr, Prefix::To, method_name.ident.name, ty);
+            then {
+                return;
+            }
+        }
+
+        if_chain! {
+            if let ExprKind::Call(function, ..) = expr.kind;
+            if let ExprKind::Path(qpath) = function.kind;
+            if let Some(def_id) = cx.qpath_res(&qpath, function.hir_id).opt_def_id();
+            if let Some(function_name) = cx.get_def_path(def_id).last();
+            let ty = cx.typeck_results().expr_ty(expr);
+            if ty.is_primitive_ty();
+            then {
+                maybe_lint_endian_bytes(cx, expr, Prefix::From, *function_name, ty);
+            }
+        }
+    }
+}
+
+fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix, name: Symbol, ty: Ty<'_>) -> bool {
+    let ne = LintKind::Host.as_name(prefix);
+    let le = LintKind::Little.as_name(prefix);
+    let be = LintKind::Big.as_name(prefix);
+
+    let (lint, other_lints) = match name.as_str() {
+        name if name == ne => ((&LintKind::Host), [(&LintKind::Little), (&LintKind::Big)]),
+        name if name == le => ((&LintKind::Little), [(&LintKind::Host), (&LintKind::Big)]),
+        name if name == be => ((&LintKind::Big), [(&LintKind::Host), (&LintKind::Little)]),
+        _ => return false,
+    };
+
+    let mut help = None;
+
+    'build_help: {
+        // all lints disallowed, don't give help here
+        if [&[lint], other_lints.as_slice()]
+            .concat()
+            .iter()
+            .all(|lint| !lint.allowed(cx, expr))
+        {
+            break 'build_help;
+        }
+
+        // ne_bytes and all other lints allowed
+        if lint.as_name(prefix) == ne && other_lints.iter().all(|lint| lint.allowed(cx, expr)) {
+            help = Some(Cow::Borrowed("specify the desired endianness explicitly"));
+            break 'build_help;
+        }
+
+        // le_bytes where ne_bytes allowed but be_bytes is not, or le_bytes where ne_bytes allowed but
+        // le_bytes is not
+        if (lint.as_name(prefix) == le || lint.as_name(prefix) == be) && LintKind::Host.allowed(cx, expr) {
+            help = Some(Cow::Borrowed("use the native endianness instead"));
+            break 'build_help;
+        }
+
+        let allowed_lints = other_lints.iter().filter(|lint| lint.allowed(cx, expr));
+        let len = allowed_lints.clone().count();
+
+        let mut help_str = "use ".to_owned();
+
+        for (i, lint) in allowed_lints.enumerate() {
+            let only_one = len == 1;
+            if !only_one {
+                help_str.push_str("either of ");
+            }
+
+            help_str.push_str(&format!("`{ty}::{}` ", lint.as_name(prefix)));
+
+            if i != len && !only_one {
+                help_str.push_str("or ");
+            }
+        }
+
+        help = Some(Cow::Owned(help_str + "instead"));
+    }
+
+    span_lint_and_then(
+        cx,
+        lint.as_lint(),
+        expr.span,
+        &format!(
+            "usage of the {}`{ty}::{}`{}",
+            if prefix == Prefix::From { "function " } else { "" },
+            lint.as_name(prefix),
+            if prefix == Prefix::To { " method" } else { "" },
+        ),
+        move |diag| {
+            if let Some(help) = help {
+                diag.help(help);
+            }
+        },
+    );
+
+    true
+}
diff --git a/clippy_lints/src/enum_clike.rs b/clippy_lints/src/enum_clike.rs
index e275efaba25..d85650712db 100644
--- a/clippy_lints/src/enum_clike.rs
+++ b/clippy_lints/src/enum_clike.rs
@@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
                         .const_eval_poly(def_id.to_def_id())
                         .ok()
                         .map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty));
-                    if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx.tcx, c)) {
+                    if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx, c)) {
                         if let ty::Adt(adt, _) = ty.kind() {
                             if adt.is_enum() {
                                 ty = adt.repr().discr_type().to_ty(cx.tcx);
diff --git a/clippy_lints/src/enum_variants.rs b/clippy_lints/src/enum_variants.rs
index faac6340419..d4df6f7aa2d 100644
--- a/clippy_lints/src/enum_variants.rs
+++ b/clippy_lints/src/enum_variants.rs
@@ -3,7 +3,7 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir};
 use clippy_utils::source::is_present_in_source;
 use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start};
-use rustc_hir::{EnumDef, Item, ItemKind, Variant};
+use rustc_hir::{EnumDef, Item, ItemKind, OwnerId, Variant};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
@@ -105,18 +105,20 @@ declare_clippy_lint! {
 }
 
 pub struct EnumVariantNames {
-    modules: Vec<(Symbol, String)>,
+    modules: Vec<(Symbol, String, OwnerId)>,
     threshold: u64,
     avoid_breaking_exported_api: bool,
+    allow_private_module_inception: bool,
 }
 
 impl EnumVariantNames {
     #[must_use]
-    pub fn new(threshold: u64, avoid_breaking_exported_api: bool) -> Self {
+    pub fn new(threshold: u64, avoid_breaking_exported_api: bool, allow_private_module_inception: bool) -> Self {
         Self {
             modules: Vec::new(),
             threshold,
             avoid_breaking_exported_api,
+            allow_private_module_inception,
         }
     }
 }
@@ -252,18 +254,19 @@ impl LateLintPass<'_> for EnumVariantNames {
         let item_name = item.ident.name.as_str();
         let item_camel = to_camel_case(item_name);
         if !item.span.from_expansion() && is_present_in_source(cx, item.span) {
-            if let Some((mod_name, mod_camel)) = self.modules.last() {
+            if let [.., (mod_name, mod_camel, owner_id)] = &*self.modules {
                 // constants don't have surrounding modules
                 if !mod_camel.is_empty() {
-                    if mod_name == &item.ident.name {
-                        if let ItemKind::Mod(..) = item.kind {
-                            span_lint(
-                                cx,
-                                MODULE_INCEPTION,
-                                item.span,
-                                "module has the same name as its containing module",
-                            );
-                        }
+                    if mod_name == &item.ident.name
+                        && let ItemKind::Mod(..) = item.kind
+                        && (!self.allow_private_module_inception || cx.tcx.visibility(owner_id.def_id).is_public())
+                    {
+                        span_lint(
+                            cx,
+                            MODULE_INCEPTION,
+                            item.span,
+                            "module has the same name as its containing module",
+                        );
                     }
                     // The `module_name_repetitions` lint should only trigger if the item has the module in its
                     // name. Having the same name is accepted.
@@ -302,6 +305,6 @@ impl LateLintPass<'_> for EnumVariantNames {
                 check_variant(cx, self.threshold, def, item_name, item.span);
             }
         }
-        self.modules.push((item.ident.name, item_camel));
+        self.modules.push((item.ident.name, item_camel, item.owner_id));
     }
 }
diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs
index c919b4de65d..58e62d1f3d3 100644
--- a/clippy_lints/src/eta_reduction.rs
+++ b/clippy_lints/src/eta_reduction.rs
@@ -120,6 +120,13 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
             if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Arc);
             if !is_type_diagnostic_item(cx, callee_ty_unadjusted, sym::Rc);
             if let ty::Closure(_, substs) = *closure_ty.kind();
+            // Don't lint if this is an inclusive range expression.
+            // They desugar to a call to `RangeInclusiveNew` which would have odd suggestions. (#10684)
+            if !matches!(higher::Range::hir(body.value), Some(higher::Range {
+                start: Some(_),
+                end: Some(_),
+                limits: rustc_ast::RangeLimits::Closed
+            }));
             then {
                 span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
                     if let Some(mut snippet) = snippet_opt(cx, callee.span) {
@@ -136,6 +143,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
                                 // Mutable closure is used after current expr; we cannot consume it.
                                 snippet = format!("&mut {snippet}");
                         }
+
                         diag.span_suggestion(
                             expr.span,
                             "replace the closure with the function itself",
diff --git a/clippy_lints/src/excessive_nesting.rs b/clippy_lints/src/excessive_nesting.rs
new file mode 100644
index 00000000000..d04d833e630
--- /dev/null
+++ b/clippy_lints/src/excessive_nesting.rs
@@ -0,0 +1,181 @@
+use clippy_utils::{diagnostics::span_lint_and_help, source::snippet};
+use rustc_ast::{
+    node_id::NodeSet,
+    visit::{walk_block, walk_item, Visitor},
+    Block, Crate, Inline, Item, ItemKind, ModKind, NodeId,
+};
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for blocks which are nested beyond a certain threshold.
+    ///
+    /// Note: Even though this lint is warn-by-default, it will only trigger if a maximum nesting level is defined in the clippy.toml file.
+    ///
+    /// ### Why is this bad?
+    /// It can severely hinder readability.
+    ///
+    /// ### Example
+    /// An example clippy.toml configuration:
+    /// ```toml
+    /// # clippy.toml
+    /// excessive-nesting-threshold = 3
+    /// ```
+    /// ```rust,ignore
+    /// // lib.rs
+    /// pub mod a {
+    ///     pub struct X;
+    ///     impl X {
+    ///         pub fn run(&self) {
+    ///             if true {
+    ///                 // etc...
+    ///             }
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// // a.rs
+    /// fn private_run(x: &X) {
+    ///     if true {
+    ///         // etc...
+    ///     }
+    /// }
+    ///
+    /// pub struct X;
+    /// impl X {
+    ///     pub fn run(&self) {
+    ///         private_run(self);
+    ///     }
+    /// }
+    /// ```
+    /// ```rust,ignore
+    /// // lib.rs
+    /// pub mod a;
+    /// ```
+    #[clippy::version = "1.70.0"]
+    pub EXCESSIVE_NESTING,
+    complexity,
+    "checks for blocks nested beyond a certain threshold"
+}
+impl_lint_pass!(ExcessiveNesting => [EXCESSIVE_NESTING]);
+
+#[derive(Clone)]
+pub struct ExcessiveNesting {
+    pub excessive_nesting_threshold: u64,
+    pub nodes: NodeSet,
+}
+
+impl ExcessiveNesting {
+    pub fn check_node_id(&self, cx: &EarlyContext<'_>, span: Span, node_id: NodeId) {
+        if self.nodes.contains(&node_id) {
+            span_lint_and_help(
+                cx,
+                EXCESSIVE_NESTING,
+                span,
+                "this block is too nested",
+                None,
+                "try refactoring your code to minimize nesting",
+            );
+        }
+    }
+}
+
+impl EarlyLintPass for ExcessiveNesting {
+    fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
+        if self.excessive_nesting_threshold == 0 {
+            return;
+        }
+
+        let mut visitor = NestingVisitor {
+            conf: self,
+            cx,
+            nest_level: 0,
+        };
+
+        for item in &krate.items {
+            visitor.visit_item(item);
+        }
+    }
+
+    fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) {
+        self.check_node_id(cx, block.span, block.id);
+    }
+
+    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+        self.check_node_id(cx, item.span, item.id);
+    }
+}
+
+struct NestingVisitor<'conf, 'cx> {
+    conf: &'conf mut ExcessiveNesting,
+    cx: &'cx EarlyContext<'cx>,
+    nest_level: u64,
+}
+
+impl NestingVisitor<'_, '_> {
+    fn check_indent(&mut self, span: Span, id: NodeId) -> bool {
+        if self.nest_level > self.conf.excessive_nesting_threshold && !in_external_macro(self.cx.sess(), span) {
+            self.conf.nodes.insert(id);
+
+            return true;
+        }
+
+        false
+    }
+}
+
+impl<'conf, 'cx> Visitor<'_> for NestingVisitor<'conf, 'cx> {
+    fn visit_block(&mut self, block: &Block) {
+        if block.span.from_expansion() {
+            return;
+        }
+
+        // TODO: This should be rewritten using `LateLintPass` so we can use `is_from_proc_macro` instead,
+        // but for now, this is fine.
+        let snippet = snippet(self.cx, block.span, "{}").trim().to_owned();
+        if !snippet.starts_with('{') || !snippet.ends_with('}') {
+            return;
+        }
+
+        self.nest_level += 1;
+
+        if !self.check_indent(block.span, block.id) {
+            walk_block(self, block);
+        }
+
+        self.nest_level -= 1;
+    }
+
+    fn visit_item(&mut self, item: &Item) {
+        if item.span.from_expansion() {
+            return;
+        }
+
+        match &item.kind {
+            ItemKind::Trait(_) | ItemKind::Impl(_) | ItemKind::Mod(.., ModKind::Loaded(_, Inline::Yes, _)) => {
+                self.nest_level += 1;
+
+                if !self.check_indent(item.span, item.id) {
+                    walk_item(self, item);
+                }
+
+                self.nest_level -= 1;
+            },
+            // Reset nesting level for non-inline modules (since these are in another file)
+            ItemKind::Mod(..) => walk_item(
+                &mut NestingVisitor {
+                    conf: self.conf,
+                    cx: self.cx,
+                    nest_level: 0,
+                },
+                item,
+            ),
+            _ => walk_item(self, item),
+        }
+    }
+}
diff --git a/clippy_lints/src/extra_unused_type_parameters.rs b/clippy_lints/src/extra_unused_type_parameters.rs
index eeb4de8b58f..126bed6789c 100644
--- a/clippy_lints/src/extra_unused_type_parameters.rs
+++ b/clippy_lints/src/extra_unused_type_parameters.rs
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_then};
+use clippy_utils::is_from_proc_macro;
 use clippy_utils::trait_ref_of_method;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::Applicability;
@@ -265,6 +266,7 @@ impl<'tcx> LateLintPass<'tcx> for ExtraUnusedTypeParameters {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
         if let ItemKind::Fn(_, generics, body_id) = item.kind
             && !self.is_empty_exported_or_macro(cx, item.span, item.owner_id.def_id, body_id)
+            && !is_from_proc_macro(cx, item)
         {
             let mut walker = TypeWalker::new(cx, generics);
             walk_item(&mut walker, item);
diff --git a/clippy_lints/src/float_literal.rs b/clippy_lints/src/float_literal.rs
index 93bf50fd5e7..d182bb62195 100644
--- a/clippy_lints/src/float_literal.rs
+++ b/clippy_lints/src/float_literal.rs
@@ -82,19 +82,24 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral {
                     LitFloatType::Suffixed(ast::FloatTy::F64) => Some("f64"),
                     LitFloatType::Unsuffixed => None
                 };
-                let (is_whole, mut float_str) = match fty {
+                let (is_whole, is_inf, mut float_str) = match fty {
                     FloatTy::F32 => {
                         let value = sym_str.parse::<f32>().unwrap();
 
-                        (value.fract() == 0.0, formatter.format(value))
+                        (value.fract() == 0.0, value.is_infinite(), formatter.format(value))
                     },
                     FloatTy::F64 => {
                         let value = sym_str.parse::<f64>().unwrap();
 
-                        (value.fract() == 0.0, formatter.format(value))
+
+                        (value.fract() == 0.0, value.is_infinite(), formatter.format(value))
                     },
                 };
 
+                if is_inf {
+                    return;
+                }
+
                 if is_whole && !sym_str.contains(|c| c == 'e' || c == 'E') {
                     // Normalize the literal by stripping the fractional portion
                     if sym_str.split('.').next().unwrap() != float_str {
diff --git a/clippy_lints/src/floating_point_arithmetic.rs b/clippy_lints/src/floating_point_arithmetic.rs
index 3c55a563af4..5e0fcd74339 100644
--- a/clippy_lints/src/floating_point_arithmetic.rs
+++ b/clippy_lints/src/floating_point_arithmetic.rs
@@ -215,7 +215,7 @@ fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
 // ranges [-16777215, 16777216) for type f32 as whole number floats outside
 // this range are lossy and ambiguous.
 #[expect(clippy::cast_possible_truncation)]
-fn get_integer_from_float_constant(value: &Constant) -> Option<i32> {
+fn get_integer_from_float_constant(value: &Constant<'_>) -> Option<i32> {
     match value {
         F32(num) if num.fract() == 0.0 => {
             if (-16_777_215.0..16_777_216.0).contains(num) {
diff --git a/clippy_lints/src/format_push_string.rs b/clippy_lints/src/format_push_string.rs
index 68c5c3673fe..45f67020c2d 100644
--- a/clippy_lints/src/format_push_string.rs
+++ b/clippy_lints/src/format_push_string.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::is_type_lang_item;
-use clippy_utils::{match_def_path, paths, peel_hir_expr_refs};
-use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem};
+use clippy_utils::{higher, match_def_path, paths};
+use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem, MatchSource};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
@@ -44,10 +44,24 @@ fn is_string(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
     is_type_lang_item(cx, cx.typeck_results().expr_ty(e).peel_refs(), LangItem::String)
 }
 fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
-    if let Some(macro_def_id) = e.span.ctxt().outer_expn_data().macro_def_id {
+    let e = e.peel_blocks().peel_borrows();
+
+    if e.span.from_expansion()
+        && let Some(macro_def_id) = e.span.ctxt().outer_expn_data().macro_def_id
+    {
         cx.tcx.get_diagnostic_name(macro_def_id) == Some(sym::format_macro)
+    } else if let Some(higher::If { then, r#else, .. }) = higher::If::hir(e) {
+        is_format(cx, then) || r#else.is_some_and(|e| is_format(cx, e))
     } else {
-        false
+        match higher::IfLetOrMatch::parse(cx, e) {
+            Some(higher::IfLetOrMatch::Match(_, arms, MatchSource::Normal)) => {
+                arms.iter().any(|arm| is_format(cx, arm.body))
+            },
+            Some(higher::IfLetOrMatch::IfLet(_, _, then, r#else)) => {
+                is_format(cx, then) ||r#else.is_some_and(|e| is_format(cx, e))
+            },
+            _ => false,
+        }
     }
 }
 
@@ -68,7 +82,6 @@ impl<'tcx> LateLintPass<'tcx> for FormatPushString {
             },
             _ => return,
         };
-        let (arg, _) = peel_hir_expr_refs(arg);
         if is_format(cx, arg) {
             span_lint_and_help(
                 cx,
diff --git a/clippy_lints/src/formatting.rs b/clippy_lints/src/formatting.rs
index 4762b354392..d03480c2108 100644
--- a/clippy_lints/src/formatting.rs
+++ b/clippy_lints/src/formatting.rs
@@ -236,6 +236,12 @@ fn check_else(cx: &EarlyContext<'_>, expr: &Expr) {
                 }
             }
 
+            // Don't warn if the only thing inside post_else_post_eol is a comment block.
+            let trimmed_post_else_post_eol = post_else_post_eol.trim();
+            if trimmed_post_else_post_eol.starts_with("/*") && trimmed_post_else_post_eol.ends_with("*/") {
+                return
+            }
+
             let else_desc = if is_if(else_) { "if" } else { "{..}" };
             span_lint_and_note(
                 cx,
diff --git a/clippy_lints/src/from_over_into.rs b/clippy_lints/src/from_over_into.rs
index 10ce2a0f0c7..92d67ef359d 100644
--- a/clippy_lints/src/from_over_into.rs
+++ b/clippy_lints/src/from_over_into.rs
@@ -134,9 +134,10 @@ impl<'a, 'tcx> Visitor<'tcx> for SelfFinder<'a, 'tcx> {
                 kw::SelfUpper => self.upper.push(segment.ident.span),
                 _ => continue,
             }
+
+            self.invalid |= segment.ident.span.from_expansion();
         }
 
-        self.invalid |= path.span.from_expansion();
         if !self.invalid {
             walk_path(self, path);
         }
@@ -156,6 +157,11 @@ fn convert_to_from(
     self_ty: &Ty<'_>,
     impl_item_ref: &ImplItemRef,
 ) -> Option<Vec<(Span, String)>> {
+    if !target_ty.find_self_aliases().is_empty() {
+        // It's tricky to expand self-aliases correctly, we'll ignore it to not cause a
+        // bad suggestion/fix.
+        return None;
+    }
     let impl_item = cx.tcx.hir().impl_item(impl_item_ref.id);
     let ImplItemKind::Fn(ref sig, body_id) = impl_item.kind else { return None };
     let body = cx.tcx.hir().body(body_id);
diff --git a/clippy_lints/src/incorrect_impls.rs b/clippy_lints/src/incorrect_impls.rs
new file mode 100644
index 00000000000..13cc0b23ba3
--- /dev/null
+++ b/clippy_lints/src/incorrect_impls.rs
@@ -0,0 +1,124 @@
+use clippy_utils::{diagnostics::span_lint_and_sugg, get_parent_node, last_path_segment, ty::implements_trait};
+use rustc_errors::Applicability;
+use rustc_hir::{ExprKind, ImplItem, ImplItemKind, ItemKind, Node, UnOp};
+use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::EarlyBinder;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{sym, symbol};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for manual implementations of `Clone` when `Copy` is already implemented.
+    ///
+    /// ### Why is this bad?
+    /// If both `Clone` and `Copy` are implemented, they must agree. This is done by dereferencing
+    /// `self` in `Clone`'s implementation. Anything else is incorrect.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// #[derive(Eq, PartialEq)]
+    /// struct A(u32);
+    ///
+    /// impl Clone for A {
+    ///     fn clone(&self) -> Self {
+    ///         Self(self.0)
+    ///     }
+    /// }
+    ///
+    /// impl Copy for A {}
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// #[derive(Eq, PartialEq)]
+    /// struct A(u32);
+    ///
+    /// impl Clone for A {
+    ///     fn clone(&self) -> Self {
+    ///         *self
+    ///     }
+    /// }
+    ///
+    /// impl Copy for A {}
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub INCORRECT_CLONE_IMPL_ON_COPY_TYPE,
+    correctness,
+    "manual implementation of `Clone` on a `Copy` type"
+}
+declare_lint_pass!(IncorrectImpls => [INCORRECT_CLONE_IMPL_ON_COPY_TYPE]);
+
+impl LateLintPass<'_> for IncorrectImpls {
+    #[expect(clippy::needless_return)]
+    fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
+        let node = get_parent_node(cx.tcx, impl_item.hir_id());
+        let Some(Node::Item(item)) = node else {
+            return;
+        };
+        let ItemKind::Impl(imp) = item.kind else {
+            return;
+        };
+        let Some(trait_impl) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::skip_binder) else {
+            return;
+        };
+        let trait_impl_def_id = trait_impl.def_id;
+        if cx.tcx.is_automatically_derived(item.owner_id.to_def_id()) {
+            return;
+        }
+        let ImplItemKind::Fn(_, impl_item_id) = cx.tcx.hir().impl_item(impl_item.impl_item_id()).kind else {
+            return;
+        };
+        let body = cx.tcx.hir().body(impl_item_id);
+        let ExprKind::Block(block, ..) = body.value.kind else {
+            return;
+        };
+        // Above is duplicated from the `duplicate_manual_partial_ord_impl` branch.
+        // Remove it while solving conflicts once that PR is merged.
+
+        // Actual implementation; remove this comment once aforementioned PR is merged
+        if cx.tcx.is_diagnostic_item(sym::Clone, trait_impl_def_id)
+            && let Some(copy_def_id) = cx.tcx.get_diagnostic_item(sym::Copy)
+            && implements_trait(
+                    cx,
+                    hir_ty_to_ty(cx.tcx, imp.self_ty),
+                    copy_def_id,
+                    trait_impl.substs,
+                )
+        {
+            if impl_item.ident.name == sym::clone {
+                if block.stmts.is_empty()
+                    && let Some(expr) = block.expr
+                    && let ExprKind::Unary(UnOp::Deref, inner) = expr.kind
+                    && let ExprKind::Path(qpath) = inner.kind
+                    && last_path_segment(&qpath).ident.name == symbol::kw::SelfLower
+                {} else {
+                    span_lint_and_sugg(
+                        cx,
+                        INCORRECT_CLONE_IMPL_ON_COPY_TYPE,
+                        block.span,
+                        "incorrect implementation of `clone` on a `Copy` type",
+                        "change this to",
+                        "{ *self }".to_owned(),
+                        Applicability::MaybeIncorrect,
+                    );
+
+                    return;
+                }
+            }
+
+            if impl_item.ident.name == sym::clone_from {
+                span_lint_and_sugg(
+                    cx,
+                    INCORRECT_CLONE_IMPL_ON_COPY_TYPE,
+                    impl_item.span,
+                    "incorrect implementation of `clone_from` on a `Copy` type",
+                    "remove this",
+                    String::new(),
+                    Applicability::MaybeIncorrect,
+                );
+
+                return;
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/items_after_test_module.rs b/clippy_lints/src/items_after_test_module.rs
index b992d689aa9..40378ee8205 100644
--- a/clippy_lints/src/items_after_test_module.rs
+++ b/clippy_lints/src/items_after_test_module.rs
@@ -1,4 +1,4 @@
-use clippy_utils::{diagnostics::span_lint_and_help, is_in_cfg_test};
+use clippy_utils::{diagnostics::span_lint_and_help, is_from_proc_macro, is_in_cfg_test};
 use rustc_hir::{HirId, ItemId, ItemKind, Mod};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
@@ -59,6 +59,7 @@ impl LateLintPass<'_> for ItemsAfterTestModule {
             if !matches!(item.kind, ItemKind::Mod(_));
             if !is_in_cfg_test(cx.tcx, itid.hir_id()); // The item isn't in the testing module itself
             if !in_external_macro(cx.sess(), item.span);
+            if !is_from_proc_macro(cx, item);
 
             then {
                 span_lint_and_help(cx, ITEMS_AFTER_TEST_MODULE, test_mod_span.unwrap().with_hi(item.span.hi()), "items were found after the testing module", None, "move the items to before the testing module was defined");
diff --git a/clippy_lints/src/large_stack_frames.rs b/clippy_lints/src/large_stack_frames.rs
new file mode 100644
index 00000000000..9c0cc978a39
--- /dev/null
+++ b/clippy_lints/src/large_stack_frames.rs
@@ -0,0 +1,162 @@
+use std::ops::AddAssign;
+
+use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::fn_has_unsatisfiable_preds;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::Body;
+use rustc_hir::FnDecl;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_tool_lint;
+use rustc_session::impl_lint_pass;
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for functions that use a lot of stack space.
+    ///
+    /// This often happens when constructing a large type, such as an array with a lot of elements,
+    /// or constructing *many* smaller-but-still-large structs, or copying around a lot of large types.
+    ///
+    /// This lint is a more general version of [`large_stack_arrays`](https://rust-lang.github.io/rust-clippy/master/#large_stack_arrays)
+    /// that is intended to look at functions as a whole instead of only individual array expressions inside of a function.
+    ///
+    /// ### Why is this bad?
+    /// The stack region of memory is very limited in size (usually *much* smaller than the heap) and attempting to
+    /// use too much will result in a stack overflow and crash the program.
+    /// To avoid this, you should consider allocating large types on the heap instead (e.g. by boxing them).
+    ///
+    /// Keep in mind that the code path to construction of large types does not even need to be reachable;
+    /// it purely needs to *exist* inside of the function to contribute to the stack size.
+    /// For example, this causes a stack overflow even though the branch is unreachable:
+    /// ```rust,ignore
+    /// fn main() {
+    ///     if false {
+    ///         let x = [0u8; 10000000]; // 10 MB stack array
+    ///         black_box(&x);
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// ### Known issues
+    /// False positives. The stack size that clippy sees is an estimated value and can be vastly different
+    /// from the actual stack usage after optimizations passes have run (especially true in release mode).
+    /// Modern compilers are very smart and are able to optimize away a lot of unnecessary stack allocations.
+    /// In debug mode however, it is usually more accurate.
+    ///
+    /// This lint works by summing up the size of all variables that the user typed, variables that were
+    /// implicitly introduced by the compiler for temporaries, function arguments and the return value,
+    /// and comparing them against a (configurable, but high-by-default).
+    ///
+    /// ### Example
+    /// This function creates four 500 KB arrays on the stack. Quite big but just small enough to not trigger `large_stack_arrays`.
+    /// However, looking at the function as a whole, it's clear that this uses a lot of stack space.
+    /// ```rust
+    /// struct QuiteLargeType([u8; 500_000]);
+    /// fn foo() {
+    ///     // ... some function that uses a lot of stack space ...
+    ///     let _x1 = QuiteLargeType([0; 500_000]);
+    ///     let _x2 = QuiteLargeType([0; 500_000]);
+    ///     let _x3 = QuiteLargeType([0; 500_000]);
+    ///     let _x4 = QuiteLargeType([0; 500_000]);
+    /// }
+    /// ```
+    ///
+    /// Instead of doing this, allocate the arrays on the heap.
+    /// This currently requires going through a `Vec` first and then converting it to a `Box`:
+    /// ```rust
+    /// struct NotSoLargeType(Box<[u8]>);
+    ///
+    /// fn foo() {
+    ///     let _x1 = NotSoLargeType(vec![0; 500_000].into_boxed_slice());
+    /// //                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  Now heap allocated.
+    /// //                                                                The size of `NotSoLargeType` is 16 bytes.
+    /// //  ...
+    /// }
+    /// ```
+    #[clippy::version = "1.71.0"]
+    pub LARGE_STACK_FRAMES,
+    nursery,
+    "checks for functions that allocate a lot of stack space"
+}
+
+pub struct LargeStackFrames {
+    maximum_allowed_size: u64,
+}
+
+impl LargeStackFrames {
+    #[must_use]
+    pub fn new(size: u64) -> Self {
+        Self {
+            maximum_allowed_size: size,
+        }
+    }
+}
+
+impl_lint_pass!(LargeStackFrames => [LARGE_STACK_FRAMES]);
+
+#[derive(Copy, Clone)]
+enum Space {
+    Used(u64),
+    Overflow,
+}
+
+impl Space {
+    pub fn exceeds_limit(self, limit: u64) -> bool {
+        match self {
+            Self::Used(used) => used > limit,
+            Self::Overflow => true,
+        }
+    }
+}
+
+impl AddAssign<u64> for Space {
+    fn add_assign(&mut self, rhs: u64) {
+        if let Self::Used(lhs) = self {
+            match lhs.checked_add(rhs) {
+                Some(sum) => *self = Self::Used(sum),
+                None => *self = Self::Overflow,
+            }
+        }
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for LargeStackFrames {
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        _: FnKind<'tcx>,
+        _: &'tcx FnDecl<'tcx>,
+        _: &'tcx Body<'tcx>,
+        span: Span,
+        local_def_id: LocalDefId,
+    ) {
+        let def_id = local_def_id.to_def_id();
+        // Building MIR for `fn`s with unsatisfiable preds results in ICE.
+        if fn_has_unsatisfiable_preds(cx, def_id) {
+            return;
+        }
+
+        let mir = cx.tcx.optimized_mir(def_id);
+        let param_env = cx.tcx.param_env(def_id);
+
+        let mut frame_size = Space::Used(0);
+
+        for local in &mir.local_decls {
+            if let Ok(layout) = cx.tcx.layout_of(param_env.and(local.ty)) {
+                frame_size += layout.size.bytes();
+            }
+        }
+
+        if frame_size.exceeds_limit(self.maximum_allowed_size) {
+            span_lint_and_note(
+                cx,
+                LARGE_STACK_FRAMES,
+                span,
+                "this function allocates a large amount of stack space",
+                None,
+                "allocating large amounts of stack space can overflow the stack",
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/let_with_type_underscore.rs b/clippy_lints/src/let_with_type_underscore.rs
index 2f10e3d2581..4e9d77ea156 100644
--- a/clippy_lints/src/let_with_type_underscore.rs
+++ b/clippy_lints/src/let_with_type_underscore.rs
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::source::snippet;
 use rustc_hir::{Local, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
@@ -25,14 +26,21 @@ declare_clippy_lint! {
 declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]);
 
 impl LateLintPass<'_> for UnderscoreTyped {
-    fn check_local<'tcx>(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) {
+    fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
         if_chain! {
             if !in_external_macro(cx.tcx.sess, local.span);
             if let Some(ty) = local.ty; // Ensure that it has a type defined
             if let TyKind::Infer = &ty.kind; // that type is '_'
             if local.span.ctxt() == ty.span.ctxt();
             then {
-                span_lint_and_help(cx,
+                // NOTE: Using `is_from_proc_macro` on `init` will require that it's initialized,
+                // this doesn't. Alternatively, `WithSearchPat` can be implemented for `Ty`
+                if snippet(cx, ty.span, "_").trim() != "_" {
+                    return;
+                }
+
+                span_lint_and_help(
+                    cx,
                     LET_WITH_TYPE_UNDERSCORE,
                     local.span,
                     "variable declared with type underscore",
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 4a23edb58aa..87329ee5e14 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -68,6 +68,7 @@ mod renamed_lints;
 mod allow_attributes;
 mod almost_complete_range;
 mod approx_const;
+mod arc_with_non_send_sync;
 mod as_conversions;
 mod asm_syntax;
 mod assertions_on_constants;
@@ -114,6 +115,7 @@ mod else_if_without_else;
 mod empty_drop;
 mod empty_enum;
 mod empty_structs_with_brackets;
+mod endian_bytes;
 mod entry;
 mod enum_clike;
 mod enum_variants;
@@ -121,6 +123,7 @@ mod equatable_if_let;
 mod escape;
 mod eta_reduction;
 mod excessive_bools;
+mod excessive_nesting;
 mod exhaustive_items;
 mod exit;
 mod explicit_write;
@@ -147,6 +150,7 @@ mod implicit_return;
 mod implicit_saturating_add;
 mod implicit_saturating_sub;
 mod inconsistent_struct_constructor;
+mod incorrect_impls;
 mod index_refutable_slice;
 mod indexing_slicing;
 mod infinite_iter;
@@ -165,6 +169,7 @@ mod large_enum_variant;
 mod large_futures;
 mod large_include_file;
 mod large_stack_arrays;
+mod large_stack_frames;
 mod len_zero;
 mod let_if_seq;
 mod let_underscore;
@@ -183,6 +188,7 @@ mod manual_is_ascii_check;
 mod manual_let_else;
 mod manual_main_separator_str;
 mod manual_non_exhaustive;
+mod manual_range_patterns;
 mod manual_rem_euclid;
 mod manual_retain;
 mod manual_slice_size_calculation;
@@ -191,9 +197,9 @@ mod manual_strip;
 mod map_unit_fn;
 mod match_result_ok;
 mod matches;
-mod mem_forget;
 mod mem_replace;
 mod methods;
+mod min_ident_chars;
 mod minmax;
 mod misc;
 mod misc_early;
@@ -220,6 +226,7 @@ mod needless_borrowed_ref;
 mod needless_continue;
 mod needless_else;
 mod needless_for_each;
+mod needless_if;
 mod needless_late_init;
 mod needless_parens_on_range_literals;
 mod needless_pass_by_value;
@@ -256,6 +263,7 @@ mod pub_use;
 mod question_mark;
 mod question_mark_used;
 mod ranges;
+mod raw_strings;
 mod rc_clone_in_vec_init;
 mod read_zero_byte_vec;
 mod redundant_async_block;
@@ -266,6 +274,7 @@ mod redundant_field_names;
 mod redundant_pub_crate;
 mod redundant_slicing;
 mod redundant_static_lifetimes;
+mod redundant_type_annotations;
 mod ref_option_ref;
 mod ref_patterns;
 mod reference;
@@ -279,8 +288,10 @@ mod semicolon_if_nothing_returned;
 mod serde_api;
 mod shadow;
 mod significant_drop_tightening;
+mod single_call_fn;
 mod single_char_lifetime_names;
 mod single_component_path_imports;
+mod single_range_in_vec_init;
 mod size_of_in_element_count;
 mod size_of_ref;
 mod slow_vector_initialization;
@@ -300,6 +311,7 @@ mod to_digit_is_some;
 mod trailing_empty_array;
 mod trait_bounds;
 mod transmute;
+mod tuple_array_conversions;
 mod types;
 mod undocumented_unsafe_blocks;
 mod unicode;
@@ -327,6 +339,7 @@ mod use_self;
 mod useless_conversion;
 mod vec;
 mod vec_init_then_push;
+mod visibility;
 mod wildcard_imports;
 mod write;
 mod zero_div_zero;
@@ -486,26 +499,27 @@ pub(crate) struct LintInfo {
     explanation: &'static str,
 }
 
-pub fn explain(name: &str) {
+pub fn explain(name: &str) -> i32 {
     let target = format!("clippy::{}", name.to_ascii_uppercase());
-    match declared_lints::LINTS.iter().find(|info| info.lint.name == target) {
-        Some(info) => {
-            println!("{}", info.explanation);
-            // Check if the lint has configuration
-            let mdconf = get_configuration_metadata();
-            if let Some(config_vec_positions) = mdconf
-                .iter()
-                .find_all(|cconf| cconf.lints.contains(&info.lint.name_lower()[8..].to_owned()))
-            {
-                // If it has, print it
-                println!("### Configuration for {}:\n", info.lint.name_lower());
-                for position in config_vec_positions {
-                    let conf = &mdconf[position];
-                    println!("  - {}: {} (default: {})", conf.name, conf.doc, conf.default);
-                }
+    if let Some(info) = declared_lints::LINTS.iter().find(|info| info.lint.name == target) {
+        println!("{}", info.explanation);
+        // Check if the lint has configuration
+        let mdconf = get_configuration_metadata();
+        if let Some(config_vec_positions) = mdconf
+            .iter()
+            .find_all(|cconf| cconf.lints.contains(&info.lint.name_lower()[8..].to_owned()))
+        {
+            // If it has, print it
+            println!("### Configuration for {}:\n", info.lint.name_lower());
+            for position in config_vec_positions {
+                let conf = &mdconf[position];
+                println!("  - {}: {} (default: {})", conf.name, conf.doc, conf.default);
             }
-        },
-        None => println!("unknown lint: {name}"),
+        }
+        0
+    } else {
+        println!("unknown lint: {name}");
+        1
     }
 }
 
@@ -564,6 +578,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         store.register_late_pass(|_| Box::<utils::internal_lints::unnecessary_def_path::UnnecessaryDefPath>::default());
         store.register_late_pass(|_| Box::new(utils::internal_lints::outer_expn_data_pass::OuterExpnDataPass));
         store.register_late_pass(|_| Box::new(utils::internal_lints::msrv_attr_impl::MsrvAttrImpl));
+        store.register_late_pass(|_| {
+            Box::new(utils::internal_lints::almost_standard_lint_formulation::AlmostStandardFormulation::new())
+        });
     }
 
     let arithmetic_side_effects_allowed = conf.arithmetic_side_effects_allowed.clone();
@@ -672,7 +689,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     });
     store.register_late_pass(|_| Box::<shadow::Shadow>::default());
     store.register_late_pass(|_| Box::new(unit_types::UnitTypes));
-    store.register_late_pass(|_| Box::new(loops::Loops));
+    store.register_late_pass(move |_| Box::new(loops::Loops::new(msrv())));
     store.register_late_pass(|_| Box::<main_recursion::MainRecursion>::default());
     store.register_late_pass(|_| Box::new(lifetimes::Lifetimes));
     store.register_late_pass(|_| Box::new(entry::HashMapPass));
@@ -693,7 +710,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     });
     let too_large_for_stack = conf.too_large_for_stack;
     store.register_late_pass(move |_| Box::new(escape::BoxedLocal { too_large_for_stack }));
-    store.register_late_pass(move |_| Box::new(vec::UselessVec { too_large_for_stack }));
+    store.register_late_pass(move |_| {
+        Box::new(vec::UselessVec {
+            too_large_for_stack,
+            msrv: msrv(),
+        })
+    });
     store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented));
     store.register_late_pass(|_| Box::new(strings::StringLitAsBytes));
     store.register_late_pass(|_| Box::new(derive::Derive));
@@ -725,7 +747,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     let missing_docs_in_crate_items = conf.missing_docs_in_crate_items;
     store.register_late_pass(move |_| Box::new(doc::DocMarkdown::new(doc_valid_idents.clone())));
     store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply));
-    store.register_late_pass(|_| Box::new(mem_forget::MemForget));
     store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq));
     store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence));
     store.register_late_pass(move |_| Box::new(missing_doc::MissingDoc::new(missing_docs_in_crate_items)));
@@ -751,7 +772,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::<useless_conversion::UselessConversion>::default());
     store.register_late_pass(|_| Box::new(implicit_hasher::ImplicitHasher));
     store.register_late_pass(|_| Box::new(fallible_impl_from::FallibleImplFrom));
-    store.register_late_pass(|_| Box::new(question_mark::QuestionMark));
+    store.register_late_pass(|_| Box::<question_mark::QuestionMark>::default());
     store.register_late_pass(|_| Box::new(question_mark_used::QuestionMarkUsed));
     store.register_early_pass(|| Box::new(suspicious_operation_groupings::SuspiciousOperationGroupings));
     store.register_late_pass(|_| Box::new(suspicious_trait_impl::SuspiciousImpl));
@@ -773,7 +794,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(assertions_on_result_states::AssertionsOnResultStates));
     store.register_late_pass(|_| Box::new(inherent_to_string::InherentToString));
     let max_trait_bounds = conf.max_trait_bounds;
-    store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(max_trait_bounds)));
+    store.register_late_pass(move |_| Box::new(trait_bounds::TraitBounds::new(max_trait_bounds, msrv())));
     store.register_late_pass(|_| Box::new(comparison_chain::ComparisonChain));
     let ignore_interior_mutability = conf.ignore_interior_mutability.clone();
     store.register_late_pass(move |_| Box::new(mut_key::MutableKeyType::new(ignore_interior_mutability.clone())));
@@ -785,7 +806,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne));
     store.register_early_pass(|| Box::new(formatting::Formatting));
     store.register_early_pass(|| Box::new(misc_early::MiscEarlyLints));
-    store.register_early_pass(|| Box::new(redundant_closure_call::RedundantClosureCall));
     store.register_late_pass(|_| Box::new(redundant_closure_call::RedundantClosureCall));
     store.register_early_pass(|| Box::new(unused_unit::UnusedUnit));
     store.register_late_pass(|_| Box::new(returns::Return));
@@ -810,10 +830,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
         ))
     });
     let enum_variant_name_threshold = conf.enum_variant_name_threshold;
+    let allow_private_module_inception = conf.allow_private_module_inception;
     store.register_late_pass(move |_| {
         Box::new(enum_variants::EnumVariantNames::new(
             enum_variant_name_threshold,
             avoid_breaking_exported_api,
+            allow_private_module_inception,
         ))
     });
     store.register_early_pass(|| Box::new(tabs_in_doc_comments::TabsInDocComments));
@@ -833,7 +855,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(move |_| Box::new(large_stack_arrays::LargeStackArrays::new(array_size_threshold)));
     store.register_late_pass(move |_| Box::new(large_const_arrays::LargeConstArrays::new(array_size_threshold)));
     store.register_late_pass(|_| Box::new(floating_point_arithmetic::FloatingPointArithmetic));
-    store.register_early_pass(|| Box::new(as_conversions::AsConversions));
+    store.register_late_pass(|_| Box::new(as_conversions::AsConversions));
     store.register_late_pass(|_| Box::new(let_underscore::LetUnderscore));
     store.register_early_pass(|| Box::<single_component_path_imports::SingleComponentPathImports>::default());
     let max_fn_params_bools = conf.max_fn_params_bools;
@@ -909,7 +931,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
             enable_raw_pointer_heuristic_for_send,
         ))
     });
-    store.register_late_pass(move |_| Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks));
+    let accept_comment_above_statement = conf.accept_comment_above_statement;
+    let accept_comment_above_attributes = conf.accept_comment_above_attributes;
+    store.register_late_pass(move |_| {
+        Box::new(undocumented_unsafe_blocks::UndocumentedUnsafeBlocks::new(
+            accept_comment_above_statement,
+            accept_comment_above_attributes,
+        ))
+    });
     let allow_mixed_uninlined = conf.allow_mixed_uninlined_format_args;
     store.register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv(), allow_mixed_uninlined)));
     store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray));
@@ -1002,11 +1031,49 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
     store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule));
     store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation));
     store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments));
+    let excessive_nesting_threshold = conf.excessive_nesting_threshold;
+    store.register_early_pass(move || {
+        Box::new(excessive_nesting::ExcessiveNesting {
+            excessive_nesting_threshold,
+            nodes: rustc_ast::node_id::NodeSet::new(),
+        })
+    });
     store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule));
     store.register_early_pass(|| Box::new(ref_patterns::RefPatterns));
     store.register_late_pass(|_| Box::new(default_constructed_unit_structs::DefaultConstructedUnitStructs));
     store.register_early_pass(|| Box::new(needless_else::NeedlessElse));
     store.register_late_pass(|_| Box::new(missing_fields_in_debug::MissingFieldsInDebug));
+    store.register_late_pass(|_| Box::new(endian_bytes::EndianBytes));
+    store.register_late_pass(|_| Box::new(redundant_type_annotations::RedundantTypeAnnotations));
+    store.register_late_pass(|_| Box::new(arc_with_non_send_sync::ArcWithNonSendSync));
+    store.register_late_pass(|_| Box::new(needless_if::NeedlessIf));
+    let allowed_idents_below_min_chars = conf.allowed_idents_below_min_chars.clone();
+    let min_ident_chars_threshold = conf.min_ident_chars_threshold;
+    store.register_late_pass(move |_| {
+        Box::new(min_ident_chars::MinIdentChars {
+            allowed_idents_below_min_chars: allowed_idents_below_min_chars.clone(),
+            min_ident_chars_threshold,
+        })
+    });
+    let stack_size_threshold = conf.stack_size_threshold;
+    store.register_late_pass(move |_| Box::new(large_stack_frames::LargeStackFrames::new(stack_size_threshold)));
+    store.register_late_pass(|_| Box::new(single_range_in_vec_init::SingleRangeInVecInit));
+    store.register_late_pass(|_| Box::new(incorrect_impls::IncorrectImpls));
+    store.register_late_pass(move |_| {
+        Box::new(single_call_fn::SingleCallFn {
+            avoid_breaking_exported_api,
+            def_id_to_usage: rustc_data_structures::fx::FxHashMap::default(),
+        })
+    });
+    let needless_raw_string_hashes_allow_one = conf.allow_one_hash_in_raw_strings;
+    store.register_early_pass(move || {
+        Box::new(raw_strings::RawStrings {
+            needless_raw_string_hashes_allow_one,
+        })
+    });
+    store.register_late_pass(|_| Box::new(manual_range_patterns::ManualRangePatterns));
+    store.register_early_pass(|| Box::new(visibility::Visibility));
+    store.register_late_pass(move |_| Box::new(tuple_array_conversions::TupleArrayConversions { msrv: msrv() }));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/clippy_lints/src/lifetimes.rs b/clippy_lints/src/lifetimes.rs
index 986ffcad883..852f6736585 100644
--- a/clippy_lints/src/lifetimes.rs
+++ b/clippy_lints/src/lifetimes.rs
@@ -1,5 +1,6 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::trait_ref_of_method;
+use itertools::Itertools;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::nested_filter::{self as hir_nested_filter, NestedFilter};
@@ -201,7 +202,19 @@ fn check_fn_inner<'tcx>(
         span_lint_and_then(
             cx,
             NEEDLESS_LIFETIMES,
-            span.with_hi(sig.decl.output.span().hi()),
+            elidable_lts
+                .iter()
+                .map(|&lt| cx.tcx.def_span(lt))
+                .chain(usages.iter().filter_map(|usage| {
+                    if let LifetimeName::Param(def_id) = usage.res
+                        && elidable_lts.contains(&def_id)
+                    {
+                        return Some(usage.ident.span);
+                    }
+
+                    None
+                }))
+                .collect_vec(),
             &format!("the following explicit lifetimes could be elided: {lts}"),
             |diag| {
                 if sig.header.is_async() {
@@ -562,7 +575,7 @@ fn has_where_lifetimes<'tcx>(cx: &LateContext<'tcx>, generics: &'tcx Generics<'_
                 // if the bounds define new lifetimes, they are fine to occur
                 let allowed_lts = allowed_lts_from(pred.bound_generic_params);
                 // now walk the bounds
-                for bound in pred.bounds.iter() {
+                for bound in pred.bounds {
                     walk_param_bound(&mut visitor, bound);
                 }
                 // and check that all lifetimes are allowed
diff --git a/clippy_lints/src/loops/explicit_into_iter_loop.rs b/clippy_lints/src/loops/explicit_into_iter_loop.rs
index 175e2b382e3..93d6b808646 100644
--- a/clippy_lints/src/loops/explicit_into_iter_loop.rs
+++ b/clippy_lints/src/loops/explicit_into_iter_loop.rs
@@ -5,15 +5,76 @@ use clippy_utils::source::snippet_with_applicability;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
 use rustc_span::symbol::sym;
 
+#[derive(Clone, Copy)]
+enum AdjustKind {
+    None,
+    Borrow,
+    BorrowMut,
+    Reborrow,
+    ReborrowMut,
+}
+impl AdjustKind {
+    fn borrow(mutbl: AutoBorrowMutability) -> Self {
+        match mutbl {
+            AutoBorrowMutability::Not => Self::Borrow,
+            AutoBorrowMutability::Mut { .. } => Self::BorrowMut,
+        }
+    }
+
+    fn reborrow(mutbl: AutoBorrowMutability) -> Self {
+        match mutbl {
+            AutoBorrowMutability::Not => Self::Reborrow,
+            AutoBorrowMutability::Mut { .. } => Self::ReborrowMut,
+        }
+    }
+
+    fn display(self) -> &'static str {
+        match self {
+            Self::None => "",
+            Self::Borrow => "&",
+            Self::BorrowMut => "&mut ",
+            Self::Reborrow => "&*",
+            Self::ReborrowMut => "&mut *",
+        }
+    }
+}
+
 pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr<'_>) {
-    let self_ty = cx.typeck_results().expr_ty(self_arg);
-    let self_ty_adjusted = cx.typeck_results().expr_ty_adjusted(self_arg);
-    if !(self_ty == self_ty_adjusted && is_trait_method(cx, call_expr, sym::IntoIterator)) {
+    if !is_trait_method(cx, call_expr, sym::IntoIterator) {
         return;
     }
 
+    let typeck = cx.typeck_results();
+    let self_ty = typeck.expr_ty(self_arg);
+    let adjust = match typeck.expr_adjustments(self_arg) {
+        [] => AdjustKind::None,
+        &[
+            Adjustment {
+                kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl)),
+                ..
+            },
+        ] => AdjustKind::borrow(mutbl),
+        &[
+            Adjustment {
+                kind: Adjust::Deref(_), ..
+            },
+            Adjustment {
+                kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl)),
+                target,
+            },
+        ] => {
+            if self_ty == target && matches!(mutbl, AutoBorrowMutability::Not) {
+                AdjustKind::None
+            } else {
+                AdjustKind::reborrow(mutbl)
+            }
+        },
+        _ => return,
+    };
+
     let mut applicability = Applicability::MachineApplicable;
     let object = snippet_with_applicability(cx, self_arg.span, "_", &mut applicability);
     span_lint_and_sugg(
@@ -23,7 +84,7 @@ pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr<
         "it is more concise to loop over containers instead of using explicit \
             iteration methods",
         "to write this more concisely, try",
-        object.to_string(),
+        format!("{}{object}", adjust.display()),
         applicability,
     );
 }
diff --git a/clippy_lints/src/loops/explicit_iter_loop.rs b/clippy_lints/src/loops/explicit_iter_loop.rs
index 151c7f1d5d2..f3347e33077 100644
--- a/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -1,75 +1,235 @@
 use super::EXPLICIT_ITER_LOOP;
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_trait_method;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::{
+    implements_trait, implements_trait_with_env, is_copy, make_normalized_projection,
+    make_normalized_projection_with_regions, normalize_with_regions,
+};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Mutability};
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
+use rustc_middle::ty::{self, EarlyBinder, Ty, TypeAndMut};
 use rustc_span::sym;
 
-pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, arg: &Expr<'_>, method_name: &str) {
-    let should_lint = match method_name {
-        "iter" | "iter_mut" => is_ref_iterable_type(cx, self_arg),
-        "into_iter" if is_trait_method(cx, arg, sym::IntoIterator) => {
-            let receiver_ty = cx.typeck_results().expr_ty(self_arg);
-            let receiver_ty_adjusted = cx.typeck_results().expr_ty_adjusted(self_arg);
-            let ref_receiver_ty = cx.tcx.mk_ref(
-                cx.tcx.lifetimes.re_erased,
-                ty::TypeAndMut {
-                    ty: receiver_ty,
-                    mutbl: Mutability::Not,
-                },
-            );
-            receiver_ty_adjusted == ref_receiver_ty
-        },
-        _ => false,
-    };
-
-    if !should_lint {
+pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, call_expr: &Expr<'_>, msrv: &Msrv) {
+    let Some((adjust, ty)) = is_ref_iterable(cx, self_arg, call_expr) else {
         return;
+    };
+    if let ty::Array(_, count) = *ty.peel_refs().kind() {
+        if !ty.is_ref() {
+            if !msrv.meets(msrvs::ARRAY_INTO_ITERATOR) {
+                return;
+            }
+        } else if count
+            .try_eval_target_usize(cx.tcx, cx.param_env)
+            .map_or(true, |x| x > 32)
+            && !msrv.meets(msrvs::ARRAY_IMPL_ANY_LEN)
+        {
+            return;
+        }
     }
 
     let mut applicability = Applicability::MachineApplicable;
     let object = snippet_with_applicability(cx, self_arg.span, "_", &mut applicability);
-    let muta = if method_name == "iter_mut" { "mut " } else { "" };
     span_lint_and_sugg(
         cx,
         EXPLICIT_ITER_LOOP,
-        arg.span,
+        call_expr.span,
         "it is more concise to loop over references to containers instead of using explicit \
          iteration methods",
         "to write this more concisely, try",
-        format!("&{muta}{object}"),
+        format!("{}{object}", adjust.display()),
         applicability,
     );
 }
 
-/// Returns `true` if the type of expr is one that provides `IntoIterator` impls
-/// for `&T` and `&mut T`, such as `Vec`.
-#[rustfmt::skip]
-fn is_ref_iterable_type(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
-    // no walk_ptrs_ty: calling iter() on a reference can make sense because it
-    // will allow further borrows afterwards
-    let ty = cx.typeck_results().expr_ty(e);
-    is_iterable_array(ty, cx) ||
-    is_type_diagnostic_item(cx, ty, sym::Vec) ||
-    is_type_diagnostic_item(cx, ty, sym::LinkedList) ||
-    is_type_diagnostic_item(cx, ty, sym::HashMap) ||
-    is_type_diagnostic_item(cx, ty, sym::HashSet) ||
-    is_type_diagnostic_item(cx, ty, sym::VecDeque) ||
-    is_type_diagnostic_item(cx, ty, sym::BinaryHeap) ||
-    is_type_diagnostic_item(cx, ty, sym::BTreeMap) ||
-    is_type_diagnostic_item(cx, ty, sym::BTreeSet)
+#[derive(Clone, Copy)]
+enum AdjustKind {
+    None,
+    Borrow,
+    BorrowMut,
+    Deref,
+    Reborrow,
+    ReborrowMut,
 }
+impl AdjustKind {
+    fn borrow(mutbl: Mutability) -> Self {
+        match mutbl {
+            Mutability::Not => Self::Borrow,
+            Mutability::Mut => Self::BorrowMut,
+        }
+    }
 
-fn is_iterable_array<'tcx>(ty: Ty<'tcx>, cx: &LateContext<'tcx>) -> bool {
-    // IntoIterator is currently only implemented for array sizes <= 32 in rustc
-    match ty.kind() {
-        ty::Array(_, n) => n
-            .try_eval_target_usize(cx.tcx, cx.param_env)
-            .map_or(false, |val| (0..=32).contains(&val)),
-        _ => false,
+    fn auto_borrow(mutbl: AutoBorrowMutability) -> Self {
+        match mutbl {
+            AutoBorrowMutability::Not => Self::Borrow,
+            AutoBorrowMutability::Mut { .. } => Self::BorrowMut,
+        }
+    }
+
+    fn reborrow(mutbl: Mutability) -> Self {
+        match mutbl {
+            Mutability::Not => Self::Reborrow,
+            Mutability::Mut => Self::ReborrowMut,
+        }
+    }
+
+    fn auto_reborrow(mutbl: AutoBorrowMutability) -> Self {
+        match mutbl {
+            AutoBorrowMutability::Not => Self::Reborrow,
+            AutoBorrowMutability::Mut { .. } => Self::ReborrowMut,
+        }
+    }
+
+    fn display(self) -> &'static str {
+        match self {
+            Self::None => "",
+            Self::Borrow => "&",
+            Self::BorrowMut => "&mut ",
+            Self::Deref => "*",
+            Self::Reborrow => "&*",
+            Self::ReborrowMut => "&mut *",
+        }
+    }
+}
+
+/// Checks if an `iter` or `iter_mut` call returns `IntoIterator::IntoIter`. Returns how the
+/// argument needs to be adjusted.
+#[expect(clippy::too_many_lines)]
+fn is_ref_iterable<'tcx>(
+    cx: &LateContext<'tcx>,
+    self_arg: &Expr<'_>,
+    call_expr: &Expr<'_>,
+) -> Option<(AdjustKind, Ty<'tcx>)> {
+    let typeck = cx.typeck_results();
+    if let Some(trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
+        && let Some(fn_id) = typeck.type_dependent_def_id(call_expr.hir_id)
+        && let sig = cx.tcx.liberate_late_bound_regions(fn_id, cx.tcx.fn_sig(fn_id).skip_binder())
+        && let &[req_self_ty, req_res_ty] = &**sig.inputs_and_output
+        && let param_env = cx.tcx.param_env(fn_id)
+        && implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, [])
+        && let Some(into_iter_ty) =
+            make_normalized_projection_with_regions(cx.tcx, param_env, trait_id, sym!(IntoIter), [req_self_ty])
+        && let req_res_ty = normalize_with_regions(cx.tcx, param_env, req_res_ty)
+        && into_iter_ty == req_res_ty
+    {
+        let adjustments = typeck.expr_adjustments(self_arg);
+        let self_ty = typeck.expr_ty(self_arg);
+        let self_is_copy = is_copy(cx, self_ty);
+
+        if adjustments.is_empty() && self_is_copy {
+            // Exact type match, already checked earlier
+            return Some((AdjustKind::None, self_ty));
+        }
+
+        let res_ty = cx.tcx.erase_regions(EarlyBinder::bind(req_res_ty)
+            .subst(cx.tcx, typeck.node_substs(call_expr.hir_id)));
+        let mutbl = if let ty::Ref(_, _, mutbl) = *req_self_ty.kind() {
+            Some(mutbl)
+        } else {
+            None
+        };
+
+        if !adjustments.is_empty() {
+            if self_is_copy {
+                // Using by value won't consume anything
+                if implements_trait(cx, self_ty, trait_id, &[])
+                    && let Some(ty) =
+                        make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [self_ty])
+                    && ty == res_ty
+                {
+                    return Some((AdjustKind::None, self_ty));
+                }
+            } else if let ty::Ref(region, ty, Mutability::Mut) = *self_ty.kind()
+                && let Some(mutbl) = mutbl
+            {
+                // Attempt to reborrow the mutable reference
+                let self_ty = if mutbl.is_mut() {
+                    self_ty
+                } else {
+                    cx.tcx.mk_ref(region, TypeAndMut { ty, mutbl })
+                };
+                if implements_trait(cx, self_ty, trait_id, &[])
+                    && let Some(ty) =
+                        make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [self_ty])
+                    && ty == res_ty
+                {
+                    return Some((AdjustKind::reborrow(mutbl), self_ty));
+                }
+            }
+        }
+        if let Some(mutbl) = mutbl
+            && !self_ty.is_ref()
+        {
+            // Attempt to borrow
+            let self_ty = cx.tcx.mk_ref(cx.tcx.lifetimes.re_erased, TypeAndMut {
+                ty: self_ty,
+                mutbl,
+            });
+            if implements_trait(cx, self_ty, trait_id, &[])
+                && let Some(ty) = make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [self_ty])
+                && ty == res_ty
+            {
+                return Some((AdjustKind::borrow(mutbl), self_ty));
+            }
+        }
+
+        match adjustments {
+            [] => Some((AdjustKind::None, self_ty)),
+            &[
+                Adjustment { kind: Adjust::Deref(_), ..},
+                Adjustment {
+                    kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl)),
+                    target,
+                },
+                ..
+            ] => {
+                if target != self_ty
+                    && implements_trait(cx, target, trait_id, &[])
+                    && let Some(ty) =
+                        make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [target])
+                    && ty == res_ty
+                {
+                    Some((AdjustKind::auto_reborrow(mutbl), target))
+                } else {
+                    None
+                }
+            }
+            &[Adjustment { kind: Adjust::Deref(_), target }, ..] => {
+                if is_copy(cx, target)
+                    && implements_trait(cx, target, trait_id, &[])
+                    && let Some(ty) =
+                        make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [target])
+                    && ty == res_ty
+                {
+                    Some((AdjustKind::Deref, target))
+                } else {
+                    None
+                }
+            }
+            &[
+                Adjustment {
+                    kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl)),
+                    target,
+                },
+                ..
+            ] => {
+                if self_ty.is_ref()
+                    && implements_trait(cx, target, trait_id, &[])
+                    && let Some(ty) =
+                        make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [target])
+                    && ty == res_ty
+                {
+                    Some((AdjustKind::auto_borrow(mutbl), target))
+                } else {
+                    None
+                }
+            }
+            _ => None,
+        }
+    } else {
+        None
     }
 }
diff --git a/clippy_lints/src/loops/manual_memcpy.rs b/clippy_lints/src/loops/manual_memcpy.rs
index d4c3f76b864..7d1f8ef29c8 100644
--- a/clippy_lints/src/loops/manual_memcpy.rs
+++ b/clippy_lints/src/loops/manual_memcpy.rs
@@ -51,7 +51,7 @@ pub(super) fn check<'tcx>(
                 iter_b = Some(get_assignment(body));
             }
 
-            let assignments = iter_a.into_iter().flatten().chain(iter_b.into_iter());
+            let assignments = iter_a.into_iter().flatten().chain(iter_b);
 
             let big_sugg = assignments
                 // The only statements in the for loops can be indexed assignments from
@@ -402,7 +402,7 @@ fn get_assignments<'a, 'tcx>(
             StmtKind::Local(..) | StmtKind::Item(..) => None,
             StmtKind::Expr(e) | StmtKind::Semi(e) => Some(e),
         })
-        .chain((*expr).into_iter())
+        .chain(*expr)
         .filter(move |e| {
             if let ExprKind::AssignOp(_, place, _) = e.kind {
                 path_to_local(place).map_or(false, |id| {
diff --git a/clippy_lints/src/loops/mod.rs b/clippy_lints/src/loops/mod.rs
index f83ad388a74..529189b52ac 100644
--- a/clippy_lints/src/loops/mod.rs
+++ b/clippy_lints/src/loops/mod.rs
@@ -20,9 +20,10 @@ mod while_let_loop;
 mod while_let_on_iterator;
 
 use clippy_utils::higher;
+use clippy_utils::msrvs::Msrv;
 use rustc_hir::{Expr, ExprKind, LoopSource, Pat};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
 use utils::{make_iterator_snippet, IncrementVisitor, InitializeVisitor};
 
@@ -479,7 +480,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Check for unnecessary `if let` usage in a for loop
+    /// Checks for unnecessary `if let` usage in a for loop
     /// where only the `Some` or `Ok` variant of the iterator element is used.
     ///
     /// ### Why is this bad?
@@ -511,7 +512,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Check for empty spin loops
+    /// Checks for empty spin loops
     ///
     /// ### Why is this bad?
     /// The loop body should have something like `thread::park()` or at least
@@ -547,7 +548,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Check for manual implementations of Iterator::find
+    /// Checks for manual implementations of Iterator::find
     ///
     /// ### Why is this bad?
     /// It doesn't affect performance, but using `find` is shorter and easier to read.
@@ -606,7 +607,15 @@ declare_clippy_lint! {
     "checking for emptiness of a `Vec` in the loop condition and popping an element in the body"
 }
 
-declare_lint_pass!(Loops => [
+pub struct Loops {
+    msrv: Msrv,
+}
+impl Loops {
+    pub fn new(msrv: Msrv) -> Self {
+        Self { msrv }
+    }
+}
+impl_lint_pass!(Loops => [
     MANUAL_MEMCPY,
     MANUAL_FLATTEN,
     NEEDLESS_RANGE_LOOP,
@@ -645,7 +654,7 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
             if body.span.from_expansion() {
                 return;
             }
-            check_for_loop(cx, pat, arg, body, expr, span);
+            self.check_for_loop(cx, pat, arg, body, expr, span);
             if let ExprKind::Block(block, _) = body.kind {
                 never_loop::check(cx, block, loop_id, span, for_loop.as_ref());
             }
@@ -678,46 +687,48 @@ impl<'tcx> LateLintPass<'tcx> for Loops {
             manual_while_let_some::check(cx, condition, body, span);
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
 
-fn check_for_loop<'tcx>(
-    cx: &LateContext<'tcx>,
-    pat: &'tcx Pat<'_>,
-    arg: &'tcx Expr<'_>,
-    body: &'tcx Expr<'_>,
-    expr: &'tcx Expr<'_>,
-    span: Span,
-) {
-    let is_manual_memcpy_triggered = manual_memcpy::check(cx, pat, arg, body, expr);
-    if !is_manual_memcpy_triggered {
-        needless_range_loop::check(cx, pat, arg, body, expr);
-        explicit_counter_loop::check(cx, pat, arg, body, expr);
+impl Loops {
+    fn check_for_loop<'tcx>(
+        &self,
+        cx: &LateContext<'tcx>,
+        pat: &'tcx Pat<'_>,
+        arg: &'tcx Expr<'_>,
+        body: &'tcx Expr<'_>,
+        expr: &'tcx Expr<'_>,
+        span: Span,
+    ) {
+        let is_manual_memcpy_triggered = manual_memcpy::check(cx, pat, arg, body, expr);
+        if !is_manual_memcpy_triggered {
+            needless_range_loop::check(cx, pat, arg, body, expr);
+            explicit_counter_loop::check(cx, pat, arg, body, expr);
+        }
+        self.check_for_loop_arg(cx, pat, arg);
+        for_kv_map::check(cx, pat, arg, body);
+        mut_range_bound::check(cx, arg, body);
+        single_element_loop::check(cx, pat, arg, body, expr);
+        same_item_push::check(cx, pat, arg, body, expr);
+        manual_flatten::check(cx, pat, arg, body, span);
+        manual_find::check(cx, pat, arg, body, span, expr);
     }
-    check_for_loop_arg(cx, pat, arg);
-    for_kv_map::check(cx, pat, arg, body);
-    mut_range_bound::check(cx, arg, body);
-    single_element_loop::check(cx, pat, arg, body, expr);
-    same_item_push::check(cx, pat, arg, body, expr);
-    manual_flatten::check(cx, pat, arg, body, span);
-    manual_find::check(cx, pat, arg, body, span, expr);
-}
 
-fn check_for_loop_arg(cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) {
-    if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind {
-        let method_name = method.ident.as_str();
-        // check for looping over x.iter() or x.iter_mut(), could use &x or &mut x
-        match method_name {
-            "iter" | "iter_mut" => {
-                explicit_iter_loop::check(cx, self_arg, arg, method_name);
-            },
-            "into_iter" => {
-                explicit_iter_loop::check(cx, self_arg, arg, method_name);
-                explicit_into_iter_loop::check(cx, self_arg, arg);
-            },
-            "next" => {
-                iter_next_loop::check(cx, arg);
-            },
-            _ => {},
+    fn check_for_loop_arg(&self, cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) {
+        if let ExprKind::MethodCall(method, self_arg, [], _) = arg.kind {
+            match method.ident.as_str() {
+                "iter" | "iter_mut" => {
+                    explicit_iter_loop::check(cx, self_arg, arg, &self.msrv);
+                },
+                "into_iter" => {
+                    explicit_into_iter_loop::check(cx, self_arg, arg);
+                },
+                "next" => {
+                    iter_next_loop::check(cx, arg);
+                },
+                _ => {},
+            }
         }
     }
 }
diff --git a/clippy_lints/src/loops/never_loop.rs b/clippy_lints/src/loops/never_loop.rs
index 10b5e1edf92..ee338c6beb0 100644
--- a/clippy_lints/src/loops/never_loop.rs
+++ b/clippy_lints/src/loops/never_loop.rs
@@ -1,22 +1,23 @@
 use super::utils::make_iterator_snippet;
 use super::NEVER_LOOP;
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::consts::constant;
 use clippy_utils::higher::ForLoop;
 use clippy_utils::source::snippet;
+use clippy_utils::{consts::Constant, diagnostics::span_lint_and_then};
 use rustc_errors::Applicability;
 use rustc_hir::{Block, Destination, Expr, ExprKind, HirId, InlineAsmOperand, Pat, Stmt, StmtKind};
 use rustc_lint::LateContext;
 use rustc_span::Span;
 use std::iter::{once, Iterator};
 
-pub(super) fn check(
-    cx: &LateContext<'_>,
-    block: &Block<'_>,
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    block: &Block<'tcx>,
     loop_id: HirId,
     span: Span,
     for_loop: Option<&ForLoop<'_>>,
 ) {
-    match never_loop_block(block, &mut Vec::new(), loop_id) {
+    match never_loop_block(cx, block, &mut Vec::new(), loop_id) {
         NeverLoopResult::AlwaysBreak => {
             span_lint_and_then(cx, NEVER_LOOP, span, "this loop never actually loops", |diag| {
                 if let Some(ForLoop {
@@ -95,7 +96,12 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult, ignore_ids: &[HirI
     }
 }
 
-fn never_loop_block(block: &Block<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: HirId) -> NeverLoopResult {
+fn never_loop_block<'tcx>(
+    cx: &LateContext<'tcx>,
+    block: &Block<'tcx>,
+    ignore_ids: &mut Vec<HirId>,
+    main_loop_id: HirId,
+) -> NeverLoopResult {
     let iter = block
         .stmts
         .iter()
@@ -103,10 +109,10 @@ fn never_loop_block(block: &Block<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id
         .chain(block.expr.map(|expr| (expr, None)));
 
     iter.map(|(e, els)| {
-        let e = never_loop_expr(e, ignore_ids, main_loop_id);
+        let e = never_loop_expr(cx, e, ignore_ids, main_loop_id);
         // els is an else block in a let...else binding
         els.map_or(e, |els| {
-            combine_branches(e, never_loop_block(els, ignore_ids, main_loop_id), ignore_ids)
+            combine_branches(e, never_loop_block(cx, els, ignore_ids, main_loop_id), ignore_ids)
         })
     })
     .fold(NeverLoopResult::Otherwise, combine_seq)
@@ -122,7 +128,12 @@ fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<(&'tcx Expr<'tcx>, Option<&'t
 }
 
 #[allow(clippy::too_many_lines)]
-fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: HirId) -> NeverLoopResult {
+fn never_loop_expr<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &Expr<'tcx>,
+    ignore_ids: &mut Vec<HirId>,
+    main_loop_id: HirId,
+) -> NeverLoopResult {
     match expr.kind {
         ExprKind::Unary(_, e)
         | ExprKind::Cast(e, _)
@@ -130,45 +141,51 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
         | ExprKind::Field(e, _)
         | ExprKind::AddrOf(_, _, e)
         | ExprKind::Repeat(e, _)
-        | ExprKind::DropTemps(e) => never_loop_expr(e, ignore_ids, main_loop_id),
-        ExprKind::Let(let_expr) => never_loop_expr(let_expr.init, ignore_ids, main_loop_id),
-        ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(&mut es.iter(), ignore_ids, main_loop_id),
+        | ExprKind::DropTemps(e) => never_loop_expr(cx, e, ignore_ids, main_loop_id),
+        ExprKind::Let(let_expr) => never_loop_expr(cx, let_expr.init, ignore_ids, main_loop_id),
+        ExprKind::Array(es) | ExprKind::Tup(es) => never_loop_expr_all(cx, &mut es.iter(), ignore_ids, main_loop_id),
         ExprKind::MethodCall(_, receiver, es, _) => never_loop_expr_all(
+            cx,
             &mut std::iter::once(receiver).chain(es.iter()),
             ignore_ids,
             main_loop_id,
         ),
         ExprKind::Struct(_, fields, base) => {
-            let fields = never_loop_expr_all(&mut fields.iter().map(|f| f.expr), ignore_ids, main_loop_id);
+            let fields = never_loop_expr_all(cx, &mut fields.iter().map(|f| f.expr), ignore_ids, main_loop_id);
             if let Some(base) = base {
-                combine_seq(fields, never_loop_expr(base, ignore_ids, main_loop_id))
+                combine_seq(fields, never_loop_expr(cx, base, ignore_ids, main_loop_id))
             } else {
                 fields
             }
         },
-        ExprKind::Call(e, es) => never_loop_expr_all(&mut once(e).chain(es.iter()), ignore_ids, main_loop_id),
+        ExprKind::Call(e, es) => never_loop_expr_all(cx, &mut once(e).chain(es.iter()), ignore_ids, main_loop_id),
         ExprKind::Binary(_, e1, e2)
         | ExprKind::Assign(e1, e2, _)
         | ExprKind::AssignOp(_, e1, e2)
-        | ExprKind::Index(e1, e2) => never_loop_expr_all(&mut [e1, e2].iter().copied(), ignore_ids, main_loop_id),
+        | ExprKind::Index(e1, e2) => never_loop_expr_all(cx, &mut [e1, e2].iter().copied(), ignore_ids, main_loop_id),
         ExprKind::Loop(b, _, _, _) => {
             // Break can come from the inner loop so remove them.
-            absorb_break(never_loop_block(b, ignore_ids, main_loop_id))
+            absorb_break(never_loop_block(cx, b, ignore_ids, main_loop_id))
         },
         ExprKind::If(e, e2, e3) => {
-            let e1 = never_loop_expr(e, ignore_ids, main_loop_id);
-            let e2 = never_loop_expr(e2, ignore_ids, main_loop_id);
+            let e1 = never_loop_expr(cx, e, ignore_ids, main_loop_id);
+            let e2 = never_loop_expr(cx, e2, ignore_ids, main_loop_id);
+            // If we know the `if` condition evaluates to `true`, don't check everything past it; it
+            // should just return whatever's evaluated for `e1` and `e2` since `e3` is unreachable
+            if let Some(Constant::Bool(true)) = constant(cx, cx.typeck_results(), e) {
+                return combine_seq(e1, e2);
+            }
             let e3 = e3.as_ref().map_or(NeverLoopResult::Otherwise, |e| {
-                never_loop_expr(e, ignore_ids, main_loop_id)
+                never_loop_expr(cx, e, ignore_ids, main_loop_id)
             });
             combine_seq(e1, combine_branches(e2, e3, ignore_ids))
         },
         ExprKind::Match(e, arms, _) => {
-            let e = never_loop_expr(e, ignore_ids, main_loop_id);
+            let e = never_loop_expr(cx, e, ignore_ids, main_loop_id);
             if arms.is_empty() {
                 e
             } else {
-                let arms = never_loop_expr_branch(&mut arms.iter().map(|a| a.body), ignore_ids, main_loop_id);
+                let arms = never_loop_expr_branch(cx, &mut arms.iter().map(|a| a.body), ignore_ids, main_loop_id);
                 combine_seq(e, arms)
             }
         },
@@ -176,7 +193,7 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
             if l.is_some() {
                 ignore_ids.push(b.hir_id);
             }
-            let ret = never_loop_block(b, ignore_ids, main_loop_id);
+            let ret = never_loop_block(cx, b, ignore_ids, main_loop_id);
             if l.is_some() {
                 ignore_ids.pop();
             }
@@ -198,31 +215,30 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
         // checks if break targets a block instead of a loop
         ExprKind::Break(Destination { target_id: Ok(t), .. }, e) if ignore_ids.contains(&t) => e
             .map_or(NeverLoopResult::IgnoreUntilEnd(t), |e| {
-                never_loop_expr(e, ignore_ids, main_loop_id)
+                never_loop_expr(cx, e, ignore_ids, main_loop_id)
             }),
         ExprKind::Break(_, e) | ExprKind::Ret(e) => e.as_ref().map_or(NeverLoopResult::AlwaysBreak, |e| {
             combine_seq(
-                never_loop_expr(e, ignore_ids, main_loop_id),
+                never_loop_expr(cx, e, ignore_ids, main_loop_id),
                 NeverLoopResult::AlwaysBreak,
             )
         }),
-        ExprKind::Become(e) => {
-            combine_seq(
-                never_loop_expr(e, ignore_ids, main_loop_id),
-                NeverLoopResult::AlwaysBreak,
-            )
-        }
+        ExprKind::Become(e) => combine_seq(
+            never_loop_expr(cx, e, ignore_ids, main_loop_id),
+            NeverLoopResult::AlwaysBreak,
+        ),
         ExprKind::InlineAsm(asm) => asm
             .operands
             .iter()
             .map(|(o, _)| match o {
                 InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
-                    never_loop_expr(expr, ignore_ids, main_loop_id)
+                    never_loop_expr(cx, expr, ignore_ids, main_loop_id)
                 },
                 InlineAsmOperand::Out { expr, .. } => {
-                    never_loop_expr_all(&mut expr.iter().copied(), ignore_ids, main_loop_id)
+                    never_loop_expr_all(cx, &mut expr.iter().copied(), ignore_ids, main_loop_id)
                 },
                 InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => never_loop_expr_all(
+                    cx,
                     &mut once(*in_expr).chain(out_expr.iter().copied()),
                     ignore_ids,
                     main_loop_id,
@@ -242,22 +258,24 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H
     }
 }
 
-fn never_loop_expr_all<'a, T: Iterator<Item = &'a Expr<'a>>>(
+fn never_loop_expr_all<'tcx, T: Iterator<Item = &'tcx Expr<'tcx>>>(
+    cx: &LateContext<'tcx>,
     es: &mut T,
     ignore_ids: &mut Vec<HirId>,
     main_loop_id: HirId,
 ) -> NeverLoopResult {
-    es.map(|e| never_loop_expr(e, ignore_ids, main_loop_id))
+    es.map(|e| never_loop_expr(cx, e, ignore_ids, main_loop_id))
         .fold(NeverLoopResult::Otherwise, combine_seq)
 }
 
-fn never_loop_expr_branch<'a, T: Iterator<Item = &'a Expr<'a>>>(
+fn never_loop_expr_branch<'tcx, T: Iterator<Item = &'tcx Expr<'tcx>>>(
+    cx: &LateContext<'tcx>,
     e: &mut T,
     ignore_ids: &mut Vec<HirId>,
     main_loop_id: HirId,
 ) -> NeverLoopResult {
     e.fold(NeverLoopResult::AlwaysBreak, |a, b| {
-        combine_branches(a, never_loop_expr(b, ignore_ids, main_loop_id), ignore_ids)
+        combine_branches(a, never_loop_expr(cx, b, ignore_ids, main_loop_id), ignore_ids)
     })
 }
 
diff --git a/clippy_lints/src/loops/same_item_push.rs b/clippy_lints/src/loops/same_item_push.rs
index 9d9341559ac..f7b3b2358a0 100644
--- a/clippy_lints/src/loops/same_item_push.rs
+++ b/clippy_lints/src/loops/same_item_push.rs
@@ -148,7 +148,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SameItemPushVisitor<'a, 'tcx> {
     }
 
     fn visit_block(&mut self, b: &'tcx Block<'_>) {
-        for stmt in b.stmts.iter() {
+        for stmt in b.stmts {
             self.visit_stmt(stmt);
         }
     }
diff --git a/clippy_lints/src/macro_use.rs b/clippy_lints/src/macro_use.rs
index e2e6a87a301..8e322a97907 100644
--- a/clippy_lints/src/macro_use.rs
+++ b/clippy_lints/src/macro_use.rs
@@ -100,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports {
             });
             if !id.is_local();
             then {
-                for kid in cx.tcx.module_children(id).iter() {
+                for kid in cx.tcx.module_children(id) {
                     if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res {
                         let span = mac_attr.span;
                         let def_path = cx.tcx.def_path_str(mac_id);
diff --git a/clippy_lints/src/manual_let_else.rs b/clippy_lints/src/manual_let_else.rs
index 389b0a4a62d..59e421c1622 100644
--- a/clippy_lints/src/manual_let_else.rs
+++ b/clippy_lints/src/manual_let_else.rs
@@ -6,17 +6,18 @@ use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::{Descend, Visitable};
 use if_chain::if_chain;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{Expr, ExprKind, HirId, ItemId, Local, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind, Ty};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::symbol::sym;
+use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
 use serde::Deserialize;
 use std::ops::ControlFlow;
+use std::slice;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -81,11 +82,11 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
         {
             match if_let_or_match {
                 IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => if_chain! {
-                    if expr_is_simple_identity(let_pat, if_then);
+                    if let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then);
                     if let Some(if_else) = if_else;
                     if expr_diverges(cx, if_else);
                     then {
-                        emit_manual_let_else(cx, stmt.span, if_let_expr, local.pat, let_pat, if_else);
+                        emit_manual_let_else(cx, stmt.span, if_let_expr, &ident_map, let_pat, if_else);
                     }
                 },
                 IfLetOrMatch::Match(match_expr, arms, source) => {
@@ -118,11 +119,11 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse {
                         return;
                     }
                     let pat_arm = &arms[1 - idx];
-                    if !expr_is_simple_identity(pat_arm.pat, pat_arm.body) {
-                        return;
-                    }
+                    let Some(ident_map) = expr_simple_identity_map(local.pat, pat_arm.pat, pat_arm.body) else {
+                        return
+                    };
 
-                    emit_manual_let_else(cx, stmt.span, match_expr, local.pat, pat_arm.pat, diverging_arm.body);
+                    emit_manual_let_else(cx, stmt.span, match_expr, &ident_map, pat_arm.pat, diverging_arm.body);
                 },
             }
         };
@@ -135,7 +136,7 @@ fn emit_manual_let_else(
     cx: &LateContext<'_>,
     span: Span,
     expr: &Expr<'_>,
-    local: &Pat<'_>,
+    ident_map: &FxHashMap<Symbol, &Pat<'_>>,
     pat: &Pat<'_>,
     else_body: &Expr<'_>,
 ) {
@@ -146,8 +147,8 @@ fn emit_manual_let_else(
         "this could be rewritten as `let...else`",
         |diag| {
             // This is far from perfect, for example there needs to be:
-            // * tracking for multi-binding cases: let (foo, bar) = if let (Some(foo), Ok(bar)) = ...
-            // * renamings of the bindings for many `PatKind`s like structs, slices, etc.
+            // * renamings of the bindings for many `PatKind`s like slices, etc.
+            // * limitations in the existing replacement algorithms
             // * unused binding collision detection with existing ones
             // for this to be machine applicable.
             let mut app = Applicability::HasPlaceholders;
@@ -159,57 +160,126 @@ fn emit_manual_let_else(
             } else {
                 format!("{{ {sn_else} }}")
             };
-            let sn_bl = replace_in_pattern(cx, span, local, pat, &mut app);
+            let sn_bl = replace_in_pattern(cx, span, ident_map, pat, &mut app, true);
             let sugg = format!("let {sn_bl} = {sn_expr} else {else_bl};");
             diag.span_suggestion(span, "consider writing", sugg, app);
         },
     );
 }
 
-// replaces the locals in the pattern
+/// Replaces the locals in the pattern
+///
+/// For this example:
+///
+/// ```ignore
+/// let (a, FooBar { b, c }) = if let Bar { Some(a_i), b_i } = ex { (a_i, b_i) } else { return };
+/// ```
+///
+/// We have:
+///
+/// ```ignore
+/// pat: Bar { Some(a_i), b_i }
+/// ident_map: (a_i) -> (a), (b_i) -> (FooBar { b, c })
+/// ```
+///
+/// We return:
+///
+/// ```ignore
+/// Bar { Some(a), b_i: FooBar { b, c } }
+/// ```
 fn replace_in_pattern(
     cx: &LateContext<'_>,
     span: Span,
-    local: &Pat<'_>,
+    ident_map: &FxHashMap<Symbol, &Pat<'_>>,
     pat: &Pat<'_>,
     app: &mut Applicability,
+    top_level: bool,
 ) -> String {
-    let mut bindings_count = 0;
-    pat.each_binding_or_first(&mut |_, _, _, _| bindings_count += 1);
-    // If the pattern creates multiple bindings, exit early,
-    // as otherwise we might paste the pattern to the positions of multiple bindings.
-    if bindings_count > 1 {
-        let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", app);
-        return sn_pat.into_owned();
-    }
+    // We put a labeled block here so that we can implement the fallback in this function.
+    // As the function has multiple call sites, implementing the fallback via an Option<T>
+    // return type and unwrap_or_else would cause repetition. Similarly, the function also
+    // invokes the fall back multiple times.
+    'a: {
+        // If the ident map is empty, there is no replacement to do.
+        // The code following this if assumes a non-empty ident_map.
+        if ident_map.is_empty() {
+            break 'a;
+        }
 
-    match pat.kind {
-        PatKind::Binding(..) => {
-            let (sn_bdg, _) = snippet_with_context(cx, local.span, span.ctxt(), "", app);
-            return sn_bdg.to_string();
-        },
-        PatKind::Or(pats) => {
-            let patterns = pats
-                .iter()
-                .map(|pat| replace_in_pattern(cx, span, local, pat, app))
-                .collect::<Vec<_>>();
-            let or_pat = patterns.join(" | ");
-            return format!("({or_pat})");
-        },
-        // Replace the variable name iff `TupleStruct` has one argument like `Variant(v)`.
-        PatKind::TupleStruct(ref w, args, dot_dot_pos) => {
-            let mut args = args
-                .iter()
-                .map(|pat| replace_in_pattern(cx, span, local, pat, app))
-                .collect::<Vec<_>>();
-            if let Some(pos) = dot_dot_pos.as_opt_usize() {
-                args.insert(pos, "..".to_owned());
-            }
-            let args = args.join(", ");
-            let sn_wrapper = cx.sess().source_map().span_to_snippet(w.span()).unwrap_or_default();
-            return format!("{sn_wrapper}({args})");
-        },
-        _ => {},
+        match pat.kind {
+            PatKind::Binding(_ann, _id, binding_name, opt_subpt) => {
+                let Some(pat_to_put) = ident_map.get(&binding_name.name) else { break 'a };
+                let (sn_ptp, _) = snippet_with_context(cx, pat_to_put.span, span.ctxt(), "", app);
+                if let Some(subpt) = opt_subpt {
+                    let subpt = replace_in_pattern(cx, span, ident_map, subpt, app, false);
+                    return format!("{sn_ptp} @ {subpt}");
+                }
+                return sn_ptp.to_string();
+            },
+            PatKind::Or(pats) => {
+                let patterns = pats
+                    .iter()
+                    .map(|pat| replace_in_pattern(cx, span, ident_map, pat, app, false))
+                    .collect::<Vec<_>>();
+                let or_pat = patterns.join(" | ");
+                if top_level {
+                    return format!("({or_pat})");
+                }
+                return or_pat;
+            },
+            PatKind::Struct(path, fields, has_dot_dot) => {
+                let fields = fields
+                    .iter()
+                    .map(|fld| {
+                        if let PatKind::Binding(_, _, name, None) = fld.pat.kind &&
+                            let Some(pat_to_put) = ident_map.get(&name.name)
+                        {
+                            let (sn_fld_name, _) = snippet_with_context(cx, fld.ident.span, span.ctxt(), "", app);
+                            let (sn_ptp, _) = snippet_with_context(cx, pat_to_put.span, span.ctxt(), "", app);
+                            // TODO: this is a bit of a hack, but it does its job. Ideally, we'd check if pat_to_put is
+                            // a PatKind::Binding but that is also hard to get right.
+                            if sn_fld_name == sn_ptp {
+                                // Field init shorthand
+                                return format!("{sn_fld_name}");
+                            }
+                            return format!("{sn_fld_name}: {sn_ptp}");
+                        }
+                        let (sn_fld, _) = snippet_with_context(cx, fld.span, span.ctxt(), "", app);
+                        sn_fld.into_owned()
+                    })
+                    .collect::<Vec<_>>();
+                let fields_string = fields.join(", ");
+
+                let dot_dot_str = if has_dot_dot { " .." } else { "" };
+                let (sn_pth, _) = snippet_with_context(cx, path.span(), span.ctxt(), "", app);
+                return format!("{sn_pth} {{ {fields_string}{dot_dot_str} }}");
+            },
+            // Replace the variable name iff `TupleStruct` has one argument like `Variant(v)`.
+            PatKind::TupleStruct(ref w, args, dot_dot_pos) => {
+                let mut args = args
+                    .iter()
+                    .map(|pat| replace_in_pattern(cx, span, ident_map, pat, app, false))
+                    .collect::<Vec<_>>();
+                if let Some(pos) = dot_dot_pos.as_opt_usize() {
+                    args.insert(pos, "..".to_owned());
+                }
+                let args = args.join(", ");
+                let sn_wrapper = cx.sess().source_map().span_to_snippet(w.span()).unwrap_or_default();
+                return format!("{sn_wrapper}({args})");
+            },
+            PatKind::Tuple(args, dot_dot_pos) => {
+                let mut args = args
+                    .iter()
+                    .map(|pat| replace_in_pattern(cx, span, ident_map, pat, app, false))
+                    .collect::<Vec<_>>();
+                if let Some(pos) = dot_dot_pos.as_opt_usize() {
+                    args.insert(pos, "..".to_owned());
+                }
+                let args = args.join(", ");
+                return format!("({args})");
+            },
+            _ => {},
+        }
     }
     let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", app);
     sn_pat.into_owned()
@@ -353,37 +423,74 @@ fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: boo
     !has_disallowed
 }
 
-/// Checks if the passed block is a simple identity referring to bindings created by the pattern
-fn expr_is_simple_identity(pat: &'_ Pat<'_>, expr: &'_ Expr<'_>) -> bool {
-    // We support patterns with multiple bindings and tuples, like:
-    //   let ... = if let (Some(foo), bar) = g() { (foo, bar) } else { ... }
+/// Checks if the passed block is a simple identity referring to bindings created by the pattern,
+/// and if yes, returns a mapping between the relevant sub-pattern and the identifier it corresponds
+/// to.
+///
+/// We support patterns with multiple bindings and tuples, e.g.:
+///
+/// ```ignore
+/// let (foo_o, bar_o) = if let (Some(foo), bar) = g() { (foo, bar) } else { ... }
+/// ```
+///
+/// The expected params would be:
+///
+/// ```ignore
+/// local_pat: (foo_o, bar_o)
+/// let_pat: (Some(foo), bar)
+/// expr: (foo, bar)
+/// ```
+///
+/// We build internal `sub_pats` so that it looks like `[foo_o, bar_o]` and `paths` so that it looks
+/// like `[foo, bar]`. Then we turn that into `FxHashMap [(foo) -> (foo_o), (bar) -> (bar_o)]` which
+/// we return.
+fn expr_simple_identity_map<'a, 'hir>(
+    local_pat: &'a Pat<'hir>,
+    let_pat: &'_ Pat<'hir>,
+    expr: &'_ Expr<'hir>,
+) -> Option<FxHashMap<Symbol, &'a Pat<'hir>>> {
     let peeled = peel_blocks(expr);
-    let paths = match peeled.kind {
-        ExprKind::Tup(exprs) | ExprKind::Array(exprs) => exprs,
-        ExprKind::Path(_) => std::slice::from_ref(peeled),
-        _ => return false,
+    let (sub_pats, paths) = match (local_pat.kind, peeled.kind) {
+        (PatKind::Tuple(pats, _), ExprKind::Tup(exprs)) | (PatKind::Slice(pats, ..), ExprKind::Array(exprs)) => {
+            (pats, exprs)
+        },
+        (_, ExprKind::Path(_)) => (slice::from_ref(local_pat), slice::from_ref(peeled)),
+        _ => return None,
     };
+
+    // There is some length mismatch, which indicates usage of .. in the patterns above e.g.:
+    // let (a, ..) = if let [a, b, _c] = ex { (a, b) } else { ... };
+    // We bail in these cases as they should be rare.
+    if paths.len() != sub_pats.len() {
+        return None;
+    }
+
     let mut pat_bindings = FxHashSet::default();
-    pat.each_binding_or_first(&mut |_ann, _hir_id, _sp, ident| {
+    let_pat.each_binding_or_first(&mut |_ann, _hir_id, _sp, ident| {
         pat_bindings.insert(ident);
     });
     if pat_bindings.len() < paths.len() {
-        return false;
+        // This rebinds some bindings from the outer scope, or it repeats some copy-able bindings multiple
+        // times. We don't support these cases so we bail here. E.g.:
+        // let foo = 0;
+        // let (new_foo, bar, bar_copied) = if let Some(bar) = Some(0) { (foo, bar, bar) } else { .. };
+        return None;
     }
-    for path in paths {
-        if_chain! {
-            if let ExprKind::Path(QPath::Resolved(_ty, path)) = path.kind;
-            if let [path_seg] = path.segments;
-            then {
-                if !pat_bindings.remove(&path_seg.ident) {
-                    return false;
-                }
-            } else {
-                return false;
+    let mut ident_map = FxHashMap::default();
+    for (sub_pat, path) in sub_pats.iter().zip(paths.iter()) {
+        if let ExprKind::Path(QPath::Resolved(_ty, path)) = path.kind &&
+            let [path_seg] = path.segments
+        {
+            let ident = path_seg.ident;
+            if !pat_bindings.remove(&ident) {
+                return None;
             }
+            ident_map.insert(ident.name, sub_pat);
+        } else {
+            return None;
         }
     }
-    true
+    Some(ident_map)
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize)]
diff --git a/clippy_lints/src/manual_range_patterns.rs b/clippy_lints/src/manual_range_patterns.rs
new file mode 100644
index 00000000000..65ff555209a
--- /dev/null
+++ b/clippy_lints/src/manual_range_patterns.rs
@@ -0,0 +1,123 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_ast::LitKind;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_hir::ExprKind;
+use rustc_hir::PatKind;
+use rustc_hir::RangeEnd;
+use rustc_lint::LintContext;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Looks for combined OR patterns that are all contained in a specific range,
+    /// e.g. `6 | 4 | 5 | 9 | 7 | 8` can be rewritten as `4..=9`.
+    ///
+    /// ### Why is this bad?
+    /// Using an explicit range is more concise and easier to read.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let x = 6;
+    /// let foo = matches!(x, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10);
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let x = 6;
+    /// let foo = matches!(x, 1..=10);
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub MANUAL_RANGE_PATTERNS,
+    complexity,
+    "manually writing range patterns using a combined OR pattern (`|`)"
+}
+declare_lint_pass!(ManualRangePatterns => [MANUAL_RANGE_PATTERNS]);
+
+fn expr_as_u128(expr: &Expr<'_>) -> Option<u128> {
+    if let ExprKind::Lit(lit) = expr.kind
+        && let LitKind::Int(num, _) = lit.node
+    {
+        Some(num)
+    } else {
+        None
+    }
+}
+
+impl LateLintPass<'_> for ManualRangePatterns {
+    fn check_pat(&mut self, cx: &LateContext<'_>, pat: &'_ rustc_hir::Pat<'_>) {
+        if in_external_macro(cx.sess(), pat.span) {
+            return;
+        }
+
+        // a pattern like 1 | 2 seems fine, lint if there are at least 3 alternatives
+        if let PatKind::Or(pats) = pat.kind
+            && pats.len() >= 3
+        {
+            let mut min = u128::MAX;
+            let mut max = 0;
+            let mut numbers_found = FxHashSet::default();
+            let mut ranges_found = Vec::new();
+
+            for pat in pats {
+                if let PatKind::Lit(lit) = pat.kind
+                    && let Some(num) = expr_as_u128(lit)
+                {
+                    numbers_found.insert(num);
+
+                    min = min.min(num);
+                    max = max.max(num);
+                } else if let PatKind::Range(Some(left), Some(right), end) = pat.kind
+                    && let Some(left) = expr_as_u128(left)
+                    && let Some(right) = expr_as_u128(right)
+                    && right >= left
+                {
+                    min = min.min(left);
+                    max = max.max(right);
+                    ranges_found.push(left..=match end {
+                        RangeEnd::Included => right,
+                        RangeEnd::Excluded => right - 1,
+                    });
+                } else {
+                    return;
+                }
+            }
+
+            let contains_whole_range = 'contains: {
+                let mut num = min;
+                while num <= max {
+                    if numbers_found.contains(&num) {
+                        num += 1;
+                    }
+                    // Given a list of (potentially overlapping) ranges like:
+                    // 1..=5, 3..=7, 6..=10
+                    // We want to find the range with the highest end that still contains the current number
+                    else if let Some(range) = ranges_found
+                        .iter()
+                        .filter(|range| range.contains(&num))
+                        .max_by_key(|range| range.end())
+                    {
+                        num = range.end() + 1;
+                    } else {
+                        break 'contains false;
+                    }
+                }
+                break 'contains true;
+            };
+
+            if contains_whole_range {
+                span_lint_and_sugg(
+                    cx,
+                    MANUAL_RANGE_PATTERNS,
+                    pat.span,
+                    "this OR pattern can be rewritten using a range",
+                    "try",
+                    format!("{min}..={max}"),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/matches/match_same_arms.rs b/clippy_lints/src/matches/match_same_arms.rs
index ae8262ace96..3d2fbea63f5 100644
--- a/clippy_lints/src/matches/match_same_arms.rs
+++ b/clippy_lints/src/matches/match_same_arms.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet;
-use clippy_utils::{path_to_local, search_same, SpanlessEq, SpanlessHash};
+use clippy_utils::{is_lint_allowed, path_to_local, search_same, SpanlessEq, SpanlessHash};
 use core::cmp::Ordering;
 use core::iter;
 use core::slice;
@@ -9,6 +9,7 @@ use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatKind, RangeEnd};
+use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 use rustc_span::Symbol;
@@ -103,17 +104,21 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
     let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect();
     for (&(i, arm1), &(j, arm2)) in search_same(&indexed_arms, hash, eq) {
         if matches!(arm2.pat.kind, PatKind::Wild) {
-            span_lint_and_then(
-                cx,
-                MATCH_SAME_ARMS,
-                arm1.span,
-                "this match arm has an identical body to the `_` wildcard arm",
-                |diag| {
-                    diag.span_suggestion(arm1.span, "try removing the arm", "", Applicability::MaybeIncorrect)
-                        .help("or try changing either arm body")
-                        .span_note(arm2.span, "`_` wildcard arm here");
-                },
-            );
+            if !cx.tcx.features().non_exhaustive_omitted_patterns_lint
+                || is_lint_allowed(cx, NON_EXHAUSTIVE_OMITTED_PATTERNS, arm2.hir_id)
+            {
+                span_lint_and_then(
+                    cx,
+                    MATCH_SAME_ARMS,
+                    arm1.span,
+                    "this match arm has an identical body to the `_` wildcard arm",
+                    |diag| {
+                        diag.span_suggestion(arm1.span, "try removing the arm", "", Applicability::MaybeIncorrect)
+                            .help("or try changing either arm body")
+                            .span_note(arm2.span, "`_` wildcard arm here");
+                    },
+                );
+            }
         } else {
             let back_block = backwards_blocking_idxs[j];
             let (keep_arm, move_arm) = if back_block < i || (back_block == 0 && forwards_blocking_idxs[i] <= j) {
diff --git a/clippy_lints/src/matches/match_wild_err_arm.rs b/clippy_lints/src/matches/match_wild_err_arm.rs
index 6424ac31d9f..de911f7a028 100644
--- a/clippy_lints/src/matches/match_wild_err_arm.rs
+++ b/clippy_lints/src/matches/match_wild_err_arm.rs
@@ -25,7 +25,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'
                     let mut ident_bind_name = kw::Underscore;
                     if !matching_wild {
                         // Looking for unused bindings (i.e.: `_e`)
-                        for pat in inner.iter() {
+                        for pat in inner {
                             if let PatKind::Binding(_, id, ident, None) = pat.kind {
                                 if ident.as_str().starts_with('_') && !is_local_used(cx, arm.body, id) {
                                     ident_bind_name = ident.name;
diff --git a/clippy_lints/src/matches/mod.rs b/clippy_lints/src/matches/mod.rs
index 0d91051632a..00fa3eb9bfe 100644
--- a/clippy_lints/src/matches/mod.rs
+++ b/clippy_lints/src/matches/mod.rs
@@ -38,6 +38,11 @@ declare_clippy_lint! {
     /// Checks for matches with a single arm where an `if let`
     /// will usually suffice.
     ///
+    /// This intentionally does not lint if there are comments
+    /// inside of the other arm, so as to allow the user to document
+    /// why having another explicit pattern with an empty body is necessary,
+    /// or because the comments need to be preserved for other reasons.
+    ///
     /// ### Why is this bad?
     /// Just readability – `if let` nests less than a `match`.
     ///
@@ -559,6 +564,9 @@ declare_clippy_lint! {
     /// ### What it does
     /// Checks for `match` with identical arm bodies.
     ///
+    /// Note: Does not lint on wildcards if the `non_exhaustive_omitted_patterns_lint` feature is
+    /// enabled and disallowed.
+    ///
     /// ### Why is this bad?
     /// This is probably a copy & paste error. If arm bodies
     /// are the same on purpose, you can factor them
@@ -777,7 +785,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Check for temporaries returned from function calls in a match scrutinee that have the
+    /// Checks for temporaries returned from function calls in a match scrutinee that have the
     /// `clippy::has_significant_drop` attribute.
     ///
     /// ### Why is this bad?
diff --git a/clippy_lints/src/matches/overlapping_arms.rs b/clippy_lints/src/matches/overlapping_arms.rs
index abf2525a61c..8be3c178a29 100644
--- a/clippy_lints/src/matches/overlapping_arms.rs
+++ b/clippy_lints/src/matches/overlapping_arms.rs
@@ -41,7 +41,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
                                 cx.tcx.valtree_to_const_val((ty, min_val_const.to_valtree())),
                                 ty,
                             );
-                            miri_to_const(cx.tcx, min_constant)?
+                            miri_to_const(cx, min_constant)?
                         },
                     };
                     let rhs_const = match rhs {
@@ -52,7 +52,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
                                 cx.tcx.valtree_to_const_val((ty, max_val_const.to_valtree())),
                                 ty,
                             );
-                            miri_to_const(cx.tcx, max_constant)?
+                            miri_to_const(cx, max_constant)?
                         },
                     };
                     let lhs_val = lhs_const.int_value(cx, ty)?;
diff --git a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index 93ef07d36ae..37528d9f7f2 100644
--- a/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -140,7 +140,7 @@ impl<'a, 'tcx> SigDropChecker<'a, 'tcx> {
                     }
                 }
 
-                for generic_arg in b.iter() {
+                for generic_arg in *b {
                     if let GenericArgKind::Type(ty) = generic_arg.unpack() {
                         if self.has_sig_drop_attr(cx, ty) {
                             return true;
diff --git a/clippy_lints/src/matches/single_match.rs b/clippy_lints/src/matches/single_match.rs
index ad47c13896c..35627d6c649 100644
--- a/clippy_lints/src/matches/single_match.rs
+++ b/clippy_lints/src/matches/single_match.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::{expr_block, snippet};
+use clippy_utils::source::{expr_block, get_source_text, snippet};
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item, peel_mid_ty_refs};
 use clippy_utils::{is_lint_allowed, is_unit_expr, is_wild, peel_blocks, peel_hir_pat_refs, peel_n_hir_expr_refs};
 use core::cmp::max;
@@ -7,10 +7,26 @@ use rustc_errors::Applicability;
 use rustc_hir::{Arm, BindingAnnotation, Block, Expr, ExprKind, Pat, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, Ty};
-use rustc_span::sym;
+use rustc_span::{sym, Span};
 
 use super::{MATCH_BOOL, SINGLE_MATCH, SINGLE_MATCH_ELSE};
 
+/// Checks if there are comments contained within a span.
+/// This is a very "naive" check, as it just looks for the literal characters // and /* in the
+/// source text. This won't be accurate if there are potentially expressions contained within the
+/// span, e.g. a string literal `"//"`, but we know that this isn't the case for empty
+/// match arms.
+fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool {
+    if let Some(ff) = get_source_text(cx, span)
+        && let Some(text) = ff.as_str()
+    {
+        text.as_bytes().windows(2)
+            .any(|w| w == b"//" || w == b"/*")
+    } else {
+        false
+    }
+}
+
 #[rustfmt::skip]
 pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr: &Expr<'_>) {
     if arms.len() == 2 && arms[0].guard.is_none() && arms[1].guard.is_none() {
@@ -25,7 +41,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
             return;
         }
         let els = arms[1].body;
-        let els = if is_unit_expr(peel_blocks(els)) {
+        let els = if is_unit_expr(peel_blocks(els)) && !empty_arm_has_comment(cx, els.span) {
             None
         } else if let ExprKind::Block(Block { stmts, expr: block_expr, .. }, _) = els.kind {
             if stmts.len() == 1 && block_expr.is_none() || stmts.is_empty() && block_expr.is_some() {
@@ -35,7 +51,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
             // block with 2+ statements or 1 expr and 1+ statement
             Some(els)
         } else {
-            // not a block, don't lint
+            // not a block or an emtpy block w/ comments, don't lint
             return;
         };
 
diff --git a/clippy_lints/src/matches/try_err.rs b/clippy_lints/src/matches/try_err.rs
index 704c34c32bf..3a7f1e034f3 100644
--- a/clippy_lints/src/matches/try_err.rs
+++ b/clippy_lints/src/matches/try_err.rs
@@ -81,7 +81,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine
 /// Finds function return type by examining return expressions in match arms.
 fn find_return_type<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx ExprKind<'_>) -> Option<Ty<'tcx>> {
     if let ExprKind::Match(_, arms, MatchSource::TryDesugar) = expr {
-        for arm in arms.iter() {
+        for arm in *arms {
             if let ExprKind::Ret(Some(ret)) = arm.body.kind {
                 return Some(cx.typeck_results().expr_ty(ret));
             }
diff --git a/clippy_lints/src/mem_forget.rs b/clippy_lints/src/mem_forget.rs
deleted file mode 100644
index d6c235b5a69..00000000000
--- a/clippy_lints/src/mem_forget.rs
+++ /dev/null
@@ -1,46 +0,0 @@
-use clippy_utils::diagnostics::span_lint;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::sym;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for usage of `std::mem::forget(t)` where `t` is
-    /// `Drop`.
-    ///
-    /// ### Why is this bad?
-    /// `std::mem::forget(t)` prevents `t` from running its
-    /// destructor, possibly causing leaks.
-    ///
-    /// ### Example
-    /// ```rust
-    /// # use std::mem;
-    /// # use std::rc::Rc;
-    /// mem::forget(Rc::new(55))
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub MEM_FORGET,
-    restriction,
-    "`mem::forget` usage on `Drop` types, likely to cause memory leaks"
-}
-
-declare_lint_pass!(MemForget => [MEM_FORGET]);
-
-impl<'tcx> LateLintPass<'tcx> for MemForget {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if let ExprKind::Call(path_expr, [ref first_arg, ..]) = e.kind {
-            if let ExprKind::Path(ref qpath) = path_expr.kind {
-                if let Some(def_id) = cx.qpath_res(qpath, path_expr.hir_id).opt_def_id() {
-                    if cx.tcx.is_diagnostic_item(sym::mem_forget, def_id) {
-                        let forgot_ty = cx.typeck_results().expr_ty(first_arg);
-
-                        if forgot_ty.ty_adt_def().map_or(false, |def| def.has_dtor(cx.tcx)) {
-                            span_lint(cx, MEM_FORGET, e.span, "usage of `mem::forget` on `Drop` type");
-                        }
-                    }
-                }
-            }
-        }
-    }
-}
diff --git a/clippy_lints/src/methods/drain_collect.rs b/clippy_lints/src/methods/drain_collect.rs
new file mode 100644
index 00000000000..d0c79dc11b0
--- /dev/null
+++ b/clippy_lints/src/methods/drain_collect.rs
@@ -0,0 +1,85 @@
+use crate::methods::DRAIN_COLLECT;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_range_full;
+use clippy_utils::source::snippet;
+use clippy_utils::ty::is_type_lang_item;
+use rustc_errors::Applicability;
+use rustc_hir::Expr;
+use rustc_hir::ExprKind;
+use rustc_hir::LangItem;
+use rustc_hir::Path;
+use rustc_hir::QPath;
+use rustc_lint::LateContext;
+use rustc_middle::query::Key;
+use rustc_middle::ty;
+use rustc_middle::ty::Ty;
+use rustc_span::sym;
+use rustc_span::Symbol;
+
+/// Checks if both types match the given diagnostic item, e.g.:
+///
+/// `vec![1,2].drain(..).collect::<Vec<_>>()`
+///  ^^^^^^^^^                     ^^^^^^   true
+/// `vec![1,2].drain(..).collect::<HashSet<_>>()`
+///  ^^^^^^^^^                     ^^^^^^^^^^  false
+fn types_match_diagnostic_item(cx: &LateContext<'_>, expr: Ty<'_>, recv: Ty<'_>, sym: Symbol) -> bool {
+    if let Some(expr_adt_did) = expr.ty_adt_id()
+        && let Some(recv_adt_did) = recv.ty_adt_id()
+    {
+        cx.tcx.is_diagnostic_item(sym, expr_adt_did) && cx.tcx.is_diagnostic_item(sym, recv_adt_did)
+    } else {
+        false
+    }
+}
+
+/// Checks `std::{vec::Vec, collections::VecDeque}`.
+fn check_vec(cx: &LateContext<'_>, args: &[Expr<'_>], expr: Ty<'_>, recv: Ty<'_>, recv_path: &Path<'_>) -> bool {
+    (types_match_diagnostic_item(cx, expr, recv, sym::Vec)
+        || types_match_diagnostic_item(cx, expr, recv, sym::VecDeque))
+        && matches!(args, [arg] if is_range_full(cx, arg, Some(recv_path)))
+}
+
+/// Checks `std::string::String`
+fn check_string(cx: &LateContext<'_>, args: &[Expr<'_>], expr: Ty<'_>, recv: Ty<'_>, recv_path: &Path<'_>) -> bool {
+    is_type_lang_item(cx, expr, LangItem::String)
+        && is_type_lang_item(cx, recv, LangItem::String)
+        && matches!(args, [arg] if is_range_full(cx, arg, Some(recv_path)))
+}
+
+/// Checks `std::collections::{HashSet, HashMap, BinaryHeap}`.
+fn check_collections(cx: &LateContext<'_>, expr: Ty<'_>, recv: Ty<'_>) -> Option<&'static str> {
+    types_match_diagnostic_item(cx, expr, recv, sym::HashSet)
+        .then_some("HashSet")
+        .or_else(|| types_match_diagnostic_item(cx, expr, recv, sym::HashMap).then_some("HashMap"))
+        .or_else(|| types_match_diagnostic_item(cx, expr, recv, sym::BinaryHeap).then_some("BinaryHeap"))
+}
+
+pub(super) fn check(cx: &LateContext<'_>, args: &[Expr<'_>], expr: &Expr<'_>, recv: &Expr<'_>) {
+    let expr_ty = cx.typeck_results().expr_ty(expr);
+    let recv_ty = cx.typeck_results().expr_ty(recv);
+    let recv_ty_no_refs = recv_ty.peel_refs();
+
+    if let ExprKind::Path(QPath::Resolved(_, recv_path)) = recv.kind
+        && let Some(typename) = check_vec(cx, args, expr_ty, recv_ty_no_refs, recv_path)
+            .then_some("Vec")
+            .or_else(|| check_string(cx, args, expr_ty, recv_ty_no_refs, recv_path).then_some("String"))
+            .or_else(|| check_collections(cx, expr_ty, recv_ty_no_refs))
+    {
+        let recv = snippet(cx, recv.span, "<expr>");
+        let sugg = if let ty::Ref(..) = recv_ty.kind() {
+            format!("std::mem::take({recv})")
+        } else {
+            format!("std::mem::take(&mut {recv})")
+        };
+
+        span_lint_and_sugg(
+            cx,
+            DRAIN_COLLECT,
+            expr.span,
+            &format!("you seem to be trying to move all elements into a new `{typename}`"),
+            "consider using `mem::take`",
+            sugg,
+            Applicability::MachineApplicable,
+        );
+    }
+}
diff --git a/clippy_lints/src/methods/get_unwrap.rs b/clippy_lints/src/methods/get_unwrap.rs
index ffc3a4d780e..e35fb12ed79 100644
--- a/clippy_lints/src/methods/get_unwrap.rs
+++ b/clippy_lints/src/methods/get_unwrap.rs
@@ -3,7 +3,6 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::get_parent_expr;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
-use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -23,21 +22,15 @@ pub(super) fn check<'tcx>(
     let mut applicability = Applicability::MachineApplicable;
     let expr_ty = cx.typeck_results().expr_ty(recv);
     let get_args_str = snippet_with_applicability(cx, get_arg.span, "..", &mut applicability);
-    let mut needs_ref;
     let caller_type = if derefs_to_slice(cx, recv, expr_ty).is_some() {
-        needs_ref = get_args_str.parse::<usize>().is_ok();
         "slice"
     } else if is_type_diagnostic_item(cx, expr_ty, sym::Vec) {
-        needs_ref = get_args_str.parse::<usize>().is_ok();
         "Vec"
     } else if is_type_diagnostic_item(cx, expr_ty, sym::VecDeque) {
-        needs_ref = get_args_str.parse::<usize>().is_ok();
         "VecDeque"
     } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym::HashMap) {
-        needs_ref = true;
         "HashMap"
     } else if !is_mut && is_type_diagnostic_item(cx, expr_ty, sym::BTreeMap) {
-        needs_ref = true;
         "BTreeMap"
     } else {
         return; // caller is not a type that we want to lint
@@ -45,18 +38,24 @@ pub(super) fn check<'tcx>(
 
     let mut span = expr.span;
 
-    // Handle the case where the result is immediately dereferenced
-    // by not requiring ref and pulling the dereference into the
-    // suggestion.
-    if_chain! {
-        if needs_ref;
-        if let Some(parent) = get_parent_expr(cx, expr);
-        if let hir::ExprKind::Unary(hir::UnOp::Deref, _) = parent.kind;
-        then {
-            needs_ref = false;
+    // Handle the case where the result is immediately dereferenced,
+    // either directly be the user, or as a result of a method call or the like
+    // by not requiring an explicit reference
+    let needs_ref = if let Some(parent) = get_parent_expr(cx, expr)
+        && let hir::ExprKind::Unary(hir::UnOp::Deref, _)
+            | hir::ExprKind::MethodCall(..)
+            | hir::ExprKind::Field(..)
+            | hir::ExprKind::Index(..) = parent.kind
+    {
+        if let hir::ExprKind::Unary(hir::UnOp::Deref, _) = parent.kind {
+            // if the user explicitly dereferences the result, we can adjust
+            // the span to also include the deref part
             span = parent.span;
         }
-    }
+        false
+    } else {
+        true
+    };
 
     let mut_str = if is_mut { "_mut" } else { "" };
     let borrow_str = if !needs_ref {
diff --git a/clippy_lints/src/methods/iter_nth.rs b/clippy_lints/src/methods/iter_nth.rs
index ceee12784cb..12104310405 100644
--- a/clippy_lints/src/methods/iter_nth.rs
+++ b/clippy_lints/src/methods/iter_nth.rs
@@ -20,9 +20,9 @@ pub(super) fn check<'tcx>(
     let caller_type = if derefs_to_slice(cx, iter_recv, cx.typeck_results().expr_ty(iter_recv)).is_some() {
         "slice"
     } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::Vec) {
-        "Vec"
+        "`Vec`"
     } else if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(iter_recv), sym::VecDeque) {
-        "VecDeque"
+        "`VecDeque`"
     } else {
         iter_nth_zero::check(cx, expr, nth_recv, nth_arg);
         return; // caller is not a type that we want to lint
diff --git a/clippy_lints/src/methods/iter_nth_zero.rs b/clippy_lints/src/methods/iter_nth_zero.rs
index d1609eebfdc..e1f950d5a4a 100644
--- a/clippy_lints/src/methods/iter_nth_zero.rs
+++ b/clippy_lints/src/methods/iter_nth_zero.rs
@@ -1,8 +1,8 @@
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_trait_method;
 use clippy_utils::source::snippet_with_applicability;
-use if_chain::if_chain;
+use clippy_utils::{is_lang_item_or_ctor, is_trait_method};
+use hir::{LangItem, OwnerNode};
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_lint::LateContext;
@@ -11,20 +11,21 @@ use rustc_span::sym;
 use super::ITER_NTH_ZERO;
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
-    if_chain! {
-        if is_trait_method(cx, expr, sym::Iterator);
-        if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg);
-        then {
-            let mut applicability = Applicability::MachineApplicable;
-            span_lint_and_sugg(
-                cx,
-                ITER_NTH_ZERO,
-                expr.span,
-                "called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent",
-                "try calling `.next()` instead of `.nth(0)`",
-                format!("{}.next()", snippet_with_applicability(cx, recv.span, "..", &mut applicability)),
-                applicability,
-            );
-        }
+    if let OwnerNode::Item(item) = cx.tcx.hir().owner(cx.tcx.hir().get_parent_item(expr.hir_id))
+        && let def_id = item.owner_id.to_def_id()
+        && is_trait_method(cx, expr, sym::Iterator)
+        && let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg)
+        && !is_lang_item_or_ctor(cx, def_id, LangItem::IteratorNext)
+    {
+        let mut app = Applicability::MachineApplicable;
+        span_lint_and_sugg(
+            cx,
+            ITER_NTH_ZERO,
+            expr.span,
+            "called `.nth(0)` on a `std::iter::Iterator`, when `.next()` is equivalent",
+            "try calling `.next()` instead of `.nth(0)`",
+            format!("{}.next()", snippet_with_applicability(cx, recv.span, "..", &mut app)),
+            app,
+        );
     }
 }
diff --git a/clippy_lints/src/methods/manual_try_fold.rs b/clippy_lints/src/methods/manual_try_fold.rs
new file mode 100644
index 00000000000..576a58499b1
--- /dev/null
+++ b/clippy_lints/src/methods/manual_try_fold.rs
@@ -0,0 +1,55 @@
+use clippy_utils::{
+    diagnostics::span_lint_and_sugg,
+    is_from_proc_macro,
+    msrvs::{Msrv, ITERATOR_TRY_FOLD},
+    source::snippet_opt,
+    ty::implements_trait,
+};
+use rustc_errors::Applicability;
+use rustc_hir::{
+    def::{DefKind, Res},
+    Expr, ExprKind,
+};
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_span::Span;
+
+use super::MANUAL_TRY_FOLD;
+
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &Expr<'tcx>,
+    init: &Expr<'_>,
+    acc: &Expr<'_>,
+    fold_span: Span,
+    msrv: &Msrv,
+) {
+    if !in_external_macro(cx.sess(), fold_span)
+        && msrv.meets(ITERATOR_TRY_FOLD)
+        && let init_ty = cx.typeck_results().expr_ty(init)
+        && let Some(try_trait) = cx.tcx.lang_items().try_trait()
+        && implements_trait(cx, init_ty, try_trait, &[])
+        && let ExprKind::Call(path, [first, rest @ ..]) = init.kind
+        && let ExprKind::Path(qpath) = path.kind
+        && let Res::Def(DefKind::Ctor(_, _), _) = cx.qpath_res(&qpath, path.hir_id)
+        && let ExprKind::Closure(closure) = acc.kind
+        && !is_from_proc_macro(cx, expr)
+        && let Some(args_snip) = closure.fn_arg_span.and_then(|fn_arg_span| snippet_opt(cx, fn_arg_span))
+    {
+        let init_snip = rest
+            .is_empty()
+            .then_some(first.span)
+            .and_then(|span| snippet_opt(cx, span))
+            .unwrap_or("...".to_owned());
+
+        span_lint_and_sugg(
+            cx,
+            MANUAL_TRY_FOLD,
+            fold_span,
+            "usage of `Iterator::fold` on a type that implements `Try`",
+            "use `try_fold` instead",
+            format!("try_fold({init_snip}, {args_snip} ...)", ),
+            Applicability::HasPlaceholders,
+        );
+    }
+}
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 88cbefbb5d3..24dbe8c1d75 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 drain_collect;
 mod err_expect;
 mod expect_fun_call;
 mod expect_used;
@@ -49,6 +50,7 @@ mod manual_next_back;
 mod manual_ok_or;
 mod manual_saturating_arithmetic;
 mod manual_str_repeat;
+mod manual_try_fold;
 mod map_clone;
 mod map_collect_result_unit;
 mod map_err_ignore;
@@ -93,6 +95,7 @@ mod unnecessary_fold;
 mod unnecessary_iter_cloned;
 mod unnecessary_join;
 mod unnecessary_lazy_eval;
+mod unnecessary_literal_unwrap;
 mod unnecessary_sort_by;
 mod unnecessary_to_owned;
 mod unwrap_or_else_default;
@@ -275,6 +278,32 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks for `.unwrap()` related calls on `Result`s and `Option`s that are constructed.
+    ///
+    /// ### Why is this bad?
+    /// It is better to write the value directly without the indirection.
+    ///
+    /// ### Examples
+    /// ```rust
+    /// let val1 = Some(1).unwrap();
+    /// let val2 = Ok::<_, ()>(1).unwrap();
+    /// let val3 = Err::<(), _>(1).unwrap_err();
+    /// ```
+    ///
+    /// Use instead:
+    /// ```rust
+    /// let val1 = 1;
+    /// let val2 = 1;
+    /// let val3 = 1;
+    /// ```
+    #[clippy::version = "1.69.0"]
+    pub UNNECESSARY_LITERAL_UNWRAP,
+    complexity,
+    "using `unwrap()` related calls on `Result` and `Option` constructors"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks for `.expect()` or `.expect_err()` calls on `Result`s and `.expect()` call on `Option`s.
     ///
     /// ### Why is this bad?
@@ -485,6 +514,7 @@ declare_clippy_lint! {
     /// # let result: Result<usize, ()> = Ok(1);
     /// # fn some_function(foo: ()) -> usize { 1 }
     /// option.map(|a| a + 1).unwrap_or(0);
+    /// option.map(|a| a > 10).unwrap_or(false);
     /// result.map(|a| a + 1).unwrap_or_else(some_function);
     /// ```
     ///
@@ -494,6 +524,7 @@ declare_clippy_lint! {
     /// # let result: Result<usize, ()> = Ok(1);
     /// # fn some_function(foo: ()) -> usize { 1 }
     /// option.map_or(0, |a| a + 1);
+    /// option.is_some_and(|a| a > 10);
     /// result.map_or_else(some_function, |a| a + 1);
     /// ```
     #[clippy::version = "1.45.0"]
@@ -3220,6 +3251,71 @@ declare_clippy_lint! {
     "manual reverse iteration of `DoubleEndedIterator`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for calls to `.drain()` that clear the collection, immediately followed by a call to `.collect()`.
+    ///
+    /// > "Collection" in this context refers to any type with a `drain` method:
+    /// > `Vec`, `VecDeque`, `BinaryHeap`, `HashSet`,`HashMap`, `String`
+    ///
+    /// ### Why is this bad?
+    /// Using `mem::take` is faster as it avoids the allocation.
+    /// When using `mem::take`, the old collection is replaced with an empty one and ownership of
+    /// the old collection is returned.
+    ///
+    /// ### Known issues
+    /// `mem::take(&mut vec)` is almost equivalent to `vec.drain(..).collect()`, except that
+    /// it also moves the **capacity**. The user might have explicitly written it this way
+    /// to keep the capacity on the original `Vec`.
+    ///
+    /// ### Example
+    /// ```rust
+    /// fn remove_all(v: &mut Vec<i32>) -> Vec<i32> {
+    ///     v.drain(..).collect()
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use std::mem;
+    /// fn remove_all(v: &mut Vec<i32>) -> Vec<i32> {
+    ///     mem::take(v)
+    /// }
+    /// ```
+    #[clippy::version = "1.71.0"]
+    pub DRAIN_COLLECT,
+    perf,
+    "calling `.drain(..).collect()` to move all elements into a new collection"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `Iterator::fold` with a type that implements `Try`.
+    ///
+    /// ### Why is this bad?
+    /// The code should use `try_fold` instead, which short-circuits on failure, thus opening the
+    /// door for additional optimizations not possible with `fold` as rustc can guarantee the
+    /// function is never called on `None`, `Err`, etc., alleviating otherwise necessary checks. It's
+    /// also slightly more idiomatic.
+    ///
+    /// ### Known issues
+    /// This lint doesn't take into account whether a function does something on the failure case,
+    /// i.e., whether short-circuiting will affect behavior. Refactoring to `try_fold` is not
+    /// desirable in those cases.
+    ///
+    /// ### Example
+    /// ```rust
+    /// vec![1, 2, 3].iter().fold(Some(0i32), |sum, i| sum?.checked_add(*i));
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// vec![1, 2, 3].iter().try_fold(0i32, |sum, i| sum.checked_add(*i));
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub MANUAL_TRY_FOLD,
+    perf,
+    "checks for usage of `Iterator::fold` with a type that implements `Try`"
+}
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
@@ -3349,6 +3445,9 @@ impl_lint_pass!(Methods => [
     SUSPICIOUS_COMMAND_ARG_SPACE,
     CLEAR_WITH_DRAIN,
     MANUAL_NEXT_BACK,
+    UNNECESSARY_LITERAL_UNWRAP,
+    DRAIN_COLLECT,
+    MANUAL_TRY_FOLD,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -3578,6 +3677,9 @@ impl Methods {
                                 manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg);
                             }
                         },
+                        Some(("drain", recv, args, ..)) => {
+                            drain_collect::check(cx, args, expr, recv);
+                        }
                         _ => {},
                     }
                 },
@@ -3606,12 +3708,18 @@ impl Methods {
                         case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg);
                     }
                 },
-                ("expect", [_]) => match method_call(recv) {
-                    Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv),
-                    Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv),
-                    _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
+                ("expect", [_]) => {
+                    match method_call(recv) {
+                        Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv),
+                        Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv),
+                        _ => expect_used::check(cx, expr, recv, false, self.allow_expect_in_tests),
+                    }
+                    unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
+                },
+                ("expect_err", [_]) => {
+                    unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
+                    expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests);
                 },
-                ("expect_err", [_]) => expect_used::check(cx, expr, recv, true, self.allow_expect_in_tests),
                 ("extend", [arg]) => {
                     string_extend_chars::check(cx, expr, recv, arg);
                     extend_with_drain::check(cx, expr, recv, arg);
@@ -3632,7 +3740,10 @@ impl Methods {
                     Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, false, true),
                     _ => {},
                 },
-                ("fold", [init, acc]) => unnecessary_fold::check(cx, expr, init, acc, span),
+                ("fold", [init, acc]) => {
+                    manual_try_fold::check(cx, expr, init, acc, call_span, &self.msrv);
+                    unnecessary_fold::check(cx, expr, init, acc, span);
+                },
                 ("for_each", [_]) => {
                     if let Some(("inspect", _, [_], span2, _)) = method_call(recv) {
                         inspect_for_each::check(cx, expr, span2);
@@ -3816,28 +3927,41 @@ impl Methods {
                         },
                         _ => {},
                     }
+                    unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                     unwrap_used::check(cx, expr, recv, false, self.allow_unwrap_in_tests);
                 },
-                ("unwrap_err", []) => unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests),
-                ("unwrap_or", [u_arg]) => match method_call(recv) {
-                    Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _, _)) => {
-                        manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
-                    },
-                    Some(("map", m_recv, [m_arg], span, _)) => {
-                        option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span);
-                    },
-                    Some(("then_some", t_recv, [t_arg], _, _)) => {
-                        obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg);
-                    },
-                    _ => {},
+                ("unwrap_err", []) => {
+                    unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
+                    unwrap_used::check(cx, expr, recv, true, self.allow_unwrap_in_tests);
                 },
-                ("unwrap_or_else", [u_arg]) => match method_call(recv) {
-                    Some(("map", recv, [map_arg], _, _))
-                        if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, &self.msrv) => {},
-                    _ => {
-                        unwrap_or_else_default::check(cx, expr, recv, u_arg);
-                        unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
-                    },
+                ("unwrap_or", [u_arg]) => {
+                    match method_call(recv) {
+                        Some((arith @ ("checked_add" | "checked_sub" | "checked_mul"), lhs, [rhs], _, _)) => {
+                            manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]);
+                        },
+                        Some(("map", m_recv, [m_arg], span, _)) => {
+                            option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, &self.msrv);
+                        },
+                        Some(("then_some", t_recv, [t_arg], _, _)) => {
+                            obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg);
+                        },
+                        _ => {},
+                    }
+                    unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
+                },
+                ("unwrap_or_default", []) => {
+                    unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
+                }
+                ("unwrap_or_else", [u_arg]) => {
+                    match method_call(recv) {
+                        Some(("map", recv, [map_arg], _, _))
+                            if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, &self.msrv) => {},
+                        _ => {
+                            unwrap_or_else_default::check(cx, expr, recv, u_arg);
+                            unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
+                        },
+                    }
+                    unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
                 },
                 ("zip", [arg]) => {
                     if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind
diff --git a/clippy_lints/src/methods/needless_collect.rs b/clippy_lints/src/methods/needless_collect.rs
index 0699997d0d2..ac209d01406 100644
--- a/clippy_lints/src/methods/needless_collect.rs
+++ b/clippy_lints/src/methods/needless_collect.rs
@@ -322,7 +322,7 @@ impl<'tcx> Visitor<'tcx> for IterFunctionVisitor<'_, 'tcx> {
 
     fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
         // Check function calls on our collection
-        if let ExprKind::MethodCall(method_name, recv, [args @ ..], _) = &expr.kind {
+        if let ExprKind::MethodCall(method_name, recv, args, _) = &expr.kind {
             if method_name.ident.name == sym!(collect) && is_trait_method(self.cx, expr, sym::Iterator) {
                 self.current_mutably_captured_ids = get_captured_ids(self.cx, self.cx.typeck_results().expr_ty(recv));
                 self.visit_expr(recv);
diff --git a/clippy_lints/src/methods/option_map_unwrap_or.rs b/clippy_lints/src/methods/option_map_unwrap_or.rs
index 4c6328481e4..f4f158c0439 100644
--- a/clippy_lints/src/methods/option_map_unwrap_or.rs
+++ b/clippy_lints/src/methods/option_map_unwrap_or.rs
@@ -1,19 +1,26 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_copy;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
+use rustc_hir::def::Res;
 use rustc_hir::intravisit::{walk_path, Visitor};
+use rustc_hir::ExprKind;
+use rustc_hir::Node;
+use rustc_hir::PatKind;
+use rustc_hir::QPath;
 use rustc_hir::{self, HirId, Path};
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
 use rustc_span::source_map::Span;
-use rustc_span::{sym, Symbol};
+use rustc_span::sym;
 
 use super::MAP_UNWRAP_OR;
 
 /// lint use of `map().unwrap_or()` for `Option`s
+#[expect(clippy::too_many_arguments)]
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &rustc_hir::Expr<'_>,
@@ -22,12 +29,27 @@ pub(super) fn check<'tcx>(
     unwrap_recv: &rustc_hir::Expr<'_>,
     unwrap_arg: &'tcx rustc_hir::Expr<'_>,
     map_span: Span,
+    msrv: &Msrv,
 ) {
     // lint if the caller of `map()` is an `Option`
     if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option) {
         if !is_copy(cx, cx.typeck_results().expr_ty(unwrap_arg)) {
-            // Do not lint if the `map` argument uses identifiers in the `map`
-            // argument that are also used in the `unwrap_or` argument
+            // Replacing `.map(<f>).unwrap_or(<a>)` with `.map_or(<a>, <f>)` can sometimes lead to
+            // borrowck errors, see #10579 for one such instance.
+            // In particular, if `a` causes a move and `f` references that moved binding, then we cannot lint:
+            // ```
+            // let x = vec![1, 2];
+            // x.get(0..1).map(|s| s.to_vec()).unwrap_or(x);
+            // ```
+            // This compiles, but changing it to `map_or` will produce a compile error:
+            // ```
+            // let x = vec![1, 2];
+            // x.get(0..1).map_or(x, |s| s.to_vec())
+            //                    ^ moving `x` here
+            // ^^^^^^^^^^^ while it is borrowed here (and later used in the closure)
+            // ```
+            // So, we have to check that `a` is not referenced anywhere (even outside of the `.map` closure!)
+            // before the call to `unwrap_or`.
 
             let mut unwrap_visitor = UnwrapVisitor {
                 cx,
@@ -35,14 +57,18 @@ pub(super) fn check<'tcx>(
             };
             unwrap_visitor.visit_expr(unwrap_arg);
 
-            let mut map_expr_visitor = MapExprVisitor {
+            let mut reference_visitor = ReferenceVisitor {
                 cx,
                 identifiers: unwrap_visitor.identifiers,
-                found_identifier: false,
+                found_reference: false,
+                unwrap_or_span: unwrap_arg.span,
             };
-            map_expr_visitor.visit_expr(map_arg);
 
-            if map_expr_visitor.found_identifier {
+            let map = cx.tcx.hir();
+            let body = map.body(map.body_owned_by(map.enclosing_body_owner(expr.hir_id)));
+            reference_visitor.visit_body(body);
+
+            if reference_visitor.found_reference {
                 return;
             }
         }
@@ -51,16 +77,29 @@ pub(super) fn check<'tcx>(
             return;
         }
 
+        // is_some_and is stabilised && `unwrap_or` argument is false; suggest `is_some_and` instead
+        let suggest_is_some_and = msrv.meets(msrvs::OPTION_IS_SOME_AND)
+            && matches!(&unwrap_arg.kind, ExprKind::Lit(lit)
+            if matches!(lit.node, rustc_ast::LitKind::Bool(false)));
+
         let mut applicability = Applicability::MachineApplicable;
         // get snippet for unwrap_or()
         let unwrap_snippet = snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability);
         // lint message
         // comparing the snippet from source to raw text ("None") below is safe
         // because we already have checked the type.
-        let arg = if unwrap_snippet == "None" { "None" } else { "<a>" };
+        let arg = if unwrap_snippet == "None" {
+            "None"
+        } else if suggest_is_some_and {
+            "false"
+        } else {
+            "<a>"
+        };
         let unwrap_snippet_none = unwrap_snippet == "None";
         let suggest = if unwrap_snippet_none {
             "and_then(<f>)"
+        } else if suggest_is_some_and {
+            "is_some_and(<f>)"
         } else {
             "map_or(<a>, <f>)"
         };
@@ -75,12 +114,18 @@ pub(super) fn check<'tcx>(
             let mut suggestion = vec![
                 (
                     map_span,
-                    String::from(if unwrap_snippet_none { "and_then" } else { "map_or" }),
+                    String::from(if unwrap_snippet_none {
+                        "and_then"
+                    } else if suggest_is_some_and {
+                        "is_some_and"
+                    } else {
+                        "map_or"
+                    }),
                 ),
                 (expr.span.with_lo(unwrap_recv.span.hi()), String::new()),
             ];
 
-            if !unwrap_snippet_none {
+            if !unwrap_snippet_none && !suggest_is_some_and {
                 suggestion.push((map_arg_span.with_hi(map_arg_span.lo()), format!("{unwrap_snippet}, ")));
             }
 
@@ -91,14 +136,19 @@ pub(super) fn check<'tcx>(
 
 struct UnwrapVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
-    identifiers: FxHashSet<Symbol>,
+    identifiers: FxHashSet<HirId>,
 }
 
 impl<'a, 'tcx> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> {
     type NestedFilter = nested_filter::All;
 
-    fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) {
-        self.identifiers.insert(ident(path));
+    fn visit_path(&mut self, path: &Path<'tcx>, _: HirId) {
+        if let Res::Local(local_id) = path.res
+            && let Some(Node::Pat(pat)) = self.cx.tcx.hir().find(local_id)
+            && let PatKind::Binding(_, local_id, ..) = pat.kind
+        {
+            self.identifiers.insert(local_id);
+        }
         walk_path(self, path);
     }
 
@@ -107,32 +157,35 @@ impl<'a, 'tcx> Visitor<'tcx> for UnwrapVisitor<'a, 'tcx> {
     }
 }
 
-struct MapExprVisitor<'a, 'tcx> {
+struct ReferenceVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
-    identifiers: FxHashSet<Symbol>,
-    found_identifier: bool,
+    identifiers: FxHashSet<HirId>,
+    found_reference: bool,
+    unwrap_or_span: Span,
 }
 
-impl<'a, 'tcx> Visitor<'tcx> for MapExprVisitor<'a, 'tcx> {
+impl<'a, 'tcx> Visitor<'tcx> for ReferenceVisitor<'a, 'tcx> {
     type NestedFilter = nested_filter::All;
-
-    fn visit_path(&mut self, path: &Path<'tcx>, _id: HirId) {
-        if self.identifiers.contains(&ident(path)) {
-            self.found_identifier = true;
-            return;
+    fn visit_expr(&mut self, expr: &'tcx rustc_hir::Expr<'_>) {
+        // If we haven't found a reference yet, check if this references
+        // one of the locals that was moved in the `unwrap_or` argument.
+        // We are only interested in exprs that appear before the `unwrap_or` call.
+        if !self.found_reference {
+            if expr.span < self.unwrap_or_span
+                && let ExprKind::Path(ref path) = expr.kind
+                && let QPath::Resolved(_, path) = path
+                && let Res::Local(local_id) = path.res
+                && let Some(Node::Pat(pat)) = self.cx.tcx.hir().find(local_id)
+                && let PatKind::Binding(_, local_id, ..) = pat.kind
+                && self.identifiers.contains(&local_id)
+            {
+                self.found_reference = true;
+            }
+            rustc_hir::intravisit::walk_expr(self, expr);
         }
-        walk_path(self, path);
     }
 
     fn nested_visit_map(&mut self) -> Self::Map {
         self.cx.tcx.hir()
     }
 }
-
-fn ident(path: &Path<'_>) -> Symbol {
-    path.segments
-        .last()
-        .expect("segments should be composed of at least 1 element")
-        .ident
-        .name
-}
diff --git a/clippy_lints/src/methods/str_splitn.rs b/clippy_lints/src/methods/str_splitn.rs
index 5ea12c44184..88a3c2620a4 100644
--- a/clippy_lints/src/methods/str_splitn.rs
+++ b/clippy_lints/src/methods/str_splitn.rs
@@ -289,7 +289,7 @@ fn parse_iter_usage<'tcx>(
 ) -> Option<IterUsage> {
     let (kind, span) = match iter.next() {
         Some((_, Node::Expr(e))) if e.span.ctxt() == ctxt => {
-            let ExprKind::MethodCall(name, _, [args @ ..], _) = e.kind else {
+            let ExprKind::MethodCall(name, _, args, _) = e.kind else {
                 return None;
             };
             let did = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
diff --git a/clippy_lints/src/methods/unnecessary_fold.rs b/clippy_lints/src/methods/unnecessary_fold.rs
index 5a3d12fd790..8ec15a1c1b7 100644
--- a/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/clippy_lints/src/methods/unnecessary_fold.rs
@@ -7,71 +7,120 @@ use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::PatKind;
 use rustc_lint::LateContext;
+use rustc_middle::ty;
 use rustc_span::{source_map::Span, sym};
 
 use super::UNNECESSARY_FOLD;
 
-pub(super) fn check(
+/// Do we need to suggest turbofish when suggesting a replacement method?
+/// Changing `fold` to `sum` needs it sometimes when the return type can't be
+/// inferred. This checks for some common cases where it can be safely omitted
+fn needs_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
+    let parent = cx.tcx.hir().get_parent(expr.hir_id);
+
+    // some common cases where turbofish isn't needed:
+    // - assigned to a local variable with a type annotation
+    if let hir::Node::Local(local) = parent
+        && local.ty.is_some()
+    {
+        return false;
+    }
+
+    // - part of a function call argument, can be inferred from the function signature (provided that
+    //   the parameter is not a generic type parameter)
+    if let hir::Node::Expr(parent_expr) = parent
+        && let hir::ExprKind::Call(recv, args) = parent_expr.kind
+        && let hir::ExprKind::Path(ref qpath) = recv.kind
+        && let Some(fn_def_id) = cx.qpath_res(qpath, recv.hir_id).opt_def_id()
+        && let fn_sig = cx.tcx.fn_sig(fn_def_id).skip_binder().skip_binder()
+        && let Some(arg_pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
+        && let Some(ty) = fn_sig.inputs().get(arg_pos)
+        && !matches!(ty.kind(), ty::Param(_))
+    {
+        return false;
+    }
+
+    // if it's neither of those, stay on the safe side and suggest turbofish,
+    // even if it could work!
+    true
+}
+
+#[derive(Copy, Clone)]
+struct Replacement {
+    method_name: &'static str,
+    has_args: bool,
+    has_generic_return: bool,
+}
+
+fn check_fold_with_op(
     cx: &LateContext<'_>,
     expr: &hir::Expr<'_>,
-    init: &hir::Expr<'_>,
     acc: &hir::Expr<'_>,
     fold_span: Span,
+    op: hir::BinOpKind,
+    replacement: Replacement,
 ) {
-    fn check_fold_with_op(
-        cx: &LateContext<'_>,
-        expr: &hir::Expr<'_>,
-        acc: &hir::Expr<'_>,
-        fold_span: Span,
-        op: hir::BinOpKind,
-        replacement_method_name: &str,
-        replacement_has_args: bool,
-    ) {
-        if_chain! {
-            // Extract the body of the closure passed to fold
-            if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind;
-            let closure_body = cx.tcx.hir().body(body);
-            let closure_expr = peel_blocks(closure_body.value);
-
-            // Check if the closure body is of the form `acc <op> some_expr(x)`
-            if let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind;
-            if bin_op.node == op;
-
-            // Extract the names of the two arguments to the closure
-            if let [param_a, param_b] = closure_body.params;
-            if let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(param_a.pat).kind;
-            if let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(param_b.pat).kind;
-
-            if path_to_local_id(left_expr, first_arg_id);
-            if replacement_has_args || path_to_local_id(right_expr, second_arg_id);
-
-            then {
-                let mut applicability = Applicability::MachineApplicable;
-                let sugg = if replacement_has_args {
-                    format!(
-                        "{replacement_method_name}(|{second_arg_ident}| {r})",
-                        r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability),
-                    )
-                } else {
-                    format!(
-                        "{replacement_method_name}()",
-                    )
-                };
-
-                span_lint_and_sugg(
-                    cx,
-                    UNNECESSARY_FOLD,
-                    fold_span.with_hi(expr.span.hi()),
-                    // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f)
-                    "this `.fold` can be written more succinctly using another method",
-                    "try",
-                    sugg,
-                    applicability,
-                );
-            }
+    if_chain! {
+        // Extract the body of the closure passed to fold
+        if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = acc.kind;
+        let closure_body = cx.tcx.hir().body(body);
+        let closure_expr = peel_blocks(closure_body.value);
+
+        // Check if the closure body is of the form `acc <op> some_expr(x)`
+        if let hir::ExprKind::Binary(ref bin_op, left_expr, right_expr) = closure_expr.kind;
+        if bin_op.node == op;
+
+        // Extract the names of the two arguments to the closure
+        if let [param_a, param_b] = closure_body.params;
+        if let PatKind::Binding(_, first_arg_id, ..) = strip_pat_refs(param_a.pat).kind;
+        if let PatKind::Binding(_, second_arg_id, second_arg_ident, _) = strip_pat_refs(param_b.pat).kind;
+
+        if path_to_local_id(left_expr, first_arg_id);
+        if replacement.has_args || path_to_local_id(right_expr, second_arg_id);
+
+        then {
+            let mut applicability = Applicability::MachineApplicable;
+
+            let turbofish = if replacement.has_generic_return {
+                format!("::<{}>", cx.typeck_results().expr_ty_adjusted(right_expr).peel_refs())
+            } else {
+                String::new()
+            };
+
+            let sugg = if replacement.has_args {
+                format!(
+                    "{method}{turbofish}(|{second_arg_ident}| {r})",
+                    method = replacement.method_name,
+                    r = snippet_with_applicability(cx, right_expr.span, "EXPR", &mut applicability),
+                )
+            } else {
+                format!(
+                    "{method}{turbofish}()",
+                    method = replacement.method_name,
+                )
+            };
+
+            span_lint_and_sugg(
+                cx,
+                UNNECESSARY_FOLD,
+                fold_span.with_hi(expr.span.hi()),
+                // TODO #2371 don't suggest e.g., .any(|x| f(x)) if we can suggest .any(f)
+                "this `.fold` can be written more succinctly using another method",
+                "try",
+                sugg,
+                applicability,
+            );
         }
     }
+}
 
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    init: &hir::Expr<'_>,
+    acc: &hir::Expr<'_>,
+    fold_span: Span,
+) {
     // Check that this is a call to Iterator::fold rather than just some function called fold
     if !is_trait_method(cx, expr, sym::Iterator) {
         return;
@@ -80,11 +129,59 @@ pub(super) fn check(
     // Check if the first argument to .fold is a suitable literal
     if let hir::ExprKind::Lit(lit) = init.kind {
         match lit.node {
-            ast::LitKind::Bool(false) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, "any", true),
-            ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, "all", true),
-            ast::LitKind::Int(0, _) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, "sum", false),
+            ast::LitKind::Bool(false) => {
+                check_fold_with_op(
+                    cx,
+                    expr,
+                    acc,
+                    fold_span,
+                    hir::BinOpKind::Or,
+                    Replacement {
+                        has_args: true,
+                        has_generic_return: false,
+                        method_name: "any",
+                    },
+                );
+            },
+            ast::LitKind::Bool(true) => {
+                check_fold_with_op(
+                    cx,
+                    expr,
+                    acc,
+                    fold_span,
+                    hir::BinOpKind::And,
+                    Replacement {
+                        has_args: true,
+                        has_generic_return: false,
+                        method_name: "all",
+                    },
+                );
+            },
+            ast::LitKind::Int(0, _) => check_fold_with_op(
+                cx,
+                expr,
+                acc,
+                fold_span,
+                hir::BinOpKind::Add,
+                Replacement {
+                    has_args: false,
+                    has_generic_return: needs_turbofish(cx, expr),
+                    method_name: "sum",
+                },
+            ),
             ast::LitKind::Int(1, _) => {
-                check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, "product", false);
+                check_fold_with_op(
+                    cx,
+                    expr,
+                    acc,
+                    fold_span,
+                    hir::BinOpKind::Mul,
+                    Replacement {
+                        has_args: false,
+                        has_generic_return: needs_turbofish(cx, expr),
+                        method_name: "product",
+                    },
+                );
             },
             _ => (),
         }
diff --git a/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
new file mode 100644
index 00000000000..7877f6a386c
--- /dev/null
+++ b/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
@@ -0,0 +1,95 @@
+use clippy_utils::{diagnostics::span_lint_and_then, is_res_lang_ctor, last_path_segment, path_res, MaybePath};
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+
+use super::UNNECESSARY_LITERAL_UNWRAP;
+
+fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) -> Option<&'a hir::Ty<'a>> {
+    let args = args?;
+
+    if args.len() <= index {
+        return None;
+    }
+
+    match args[index] {
+        hir::GenericArg::Type(ty) => match ty.kind {
+            hir::TyKind::Infer => None,
+            _ => Some(ty),
+        },
+        _ => None,
+    }
+}
+
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    expr: &hir::Expr<'_>,
+    recv: &hir::Expr<'_>,
+    method: &str,
+    args: &[hir::Expr<'_>],
+) {
+    let init = clippy_utils::expr_or_init(cx, recv);
+
+    let (constructor, call_args, ty) = if let hir::ExprKind::Call(call, call_args) = init.kind {
+        let Some(qpath) = call.qpath_opt() else { return };
+
+        let args = last_path_segment(qpath).args.map(|args| args.args);
+        let res = cx.qpath_res(qpath, call.hir_id());
+
+        if is_res_lang_ctor(cx, res, hir::LangItem::OptionSome) {
+            ("Some", call_args, get_ty_from_args(args, 0))
+        } else if is_res_lang_ctor(cx, res, hir::LangItem::ResultOk) {
+            ("Ok", call_args, get_ty_from_args(args, 0))
+        } else if is_res_lang_ctor(cx, res, hir::LangItem::ResultErr) {
+            ("Err", call_args, get_ty_from_args(args, 1))
+        } else {
+            return;
+        }
+    } else if is_res_lang_ctor(cx, path_res(cx, init), hir::LangItem::OptionNone) {
+        let call_args: &[hir::Expr<'_>] = &[];
+        ("None", call_args, None)
+    } else {
+        return;
+    };
+
+    let help_message = format!("used `{method}()` on `{constructor}` value");
+    let suggestion_message = format!("remove the `{constructor}` and `{method}()`");
+
+    span_lint_and_then(cx, UNNECESSARY_LITERAL_UNWRAP, expr.span, &help_message, |diag| {
+        let suggestions = match (constructor, method, ty) {
+            ("None", "unwrap", _) => Some(vec![(expr.span, "panic!()".to_string())]),
+            ("None", "expect", _) => Some(vec![
+                (expr.span.with_hi(args[0].span.lo()), "panic!(".to_string()),
+                (expr.span.with_lo(args[0].span.hi()), ")".to_string()),
+            ]),
+            (_, _, Some(_)) => None,
+            ("Ok", "unwrap_err", None) | ("Err", "unwrap", None) => Some(vec![
+                (
+                    recv.span.with_hi(call_args[0].span.lo()),
+                    "panic!(\"{:?}\", ".to_string(),
+                ),
+                (expr.span.with_lo(call_args[0].span.hi()), ")".to_string()),
+            ]),
+            ("Ok", "expect_err", None) | ("Err", "expect", None) => Some(vec![
+                (
+                    recv.span.with_hi(call_args[0].span.lo()),
+                    "panic!(\"{1}: {:?}\", ".to_string(),
+                ),
+                (call_args[0].span.with_lo(args[0].span.lo()), ", ".to_string()),
+            ]),
+            (_, _, None) => Some(vec![
+                (recv.span.with_hi(call_args[0].span.lo()), String::new()),
+                (expr.span.with_lo(call_args[0].span.hi()), String::new()),
+            ]),
+        };
+
+        match (init.span == recv.span, suggestions) {
+            (true, Some(suggestions)) => {
+                diag.multipart_suggestion(suggestion_message, suggestions, Applicability::MachineApplicable);
+            },
+            _ => {
+                diag.span_help(init.span, suggestion_message);
+            },
+        }
+    });
+}
diff --git a/clippy_lints/src/methods/unnecessary_to_owned.rs b/clippy_lints/src/methods/unnecessary_to_owned.rs
index 80eb00a1b42..16ef24bd4e3 100644
--- a/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -144,6 +144,11 @@ fn check_addr_of_expr(
                 if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref);
                 if implements_trait(cx, receiver_ty, deref_trait_id, &[]);
                 if cx.get_associated_type(receiver_ty, deref_trait_id, "Target") == Some(target_ty);
+                // Make sure that it's actually calling the right `.to_string()`, (#10033)
+                // *or* this is a `Cow::into_owned()` call (which would be the wrong into_owned receiver (str != Cow)
+                // but that's ok for Cow::into_owned specifically)
+                if cx.typeck_results().expr_ty_adjusted(receiver).peel_refs() == target_ty
+                    || is_cow_into_owned(cx, method_name, method_def_id);
                 then {
                     if n_receiver_refs > 0 {
                         span_lint_and_sugg(
diff --git a/clippy_lints/src/min_ident_chars.rs b/clippy_lints/src/min_ident_chars.rs
new file mode 100644
index 00000000000..d49bb0ca6e2
--- /dev/null
+++ b/clippy_lints/src/min_ident_chars.rs
@@ -0,0 +1,153 @@
+use clippy_utils::{diagnostics::span_lint, is_from_proc_macro};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::{
+    def::{DefKind, Res},
+    intravisit::{walk_item, Visitor},
+    GenericParamKind, HirId, Item, ItemKind, ItemLocalId, Node, Pat, PatKind,
+};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::Span;
+use std::borrow::Cow;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for idents which comprise of a single letter.
+    ///
+    /// Note: This lint can be very noisy when enabled; it may be desirable to only enable it
+    /// temporarily.
+    ///
+    /// ### Why is this bad?
+    /// In many cases it's not, but at times it can severely hinder readability. Some codebases may
+    /// wish to disallow this to improve readability.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// for m in movies {
+    ///	    let title = m.t;
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// for movie in movies {
+    ///     let title = movie.title;
+    /// }
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub MIN_IDENT_CHARS,
+    restriction,
+    "disallows idents that are too short"
+}
+impl_lint_pass!(MinIdentChars => [MIN_IDENT_CHARS]);
+
+#[derive(Clone)]
+pub struct MinIdentChars {
+    pub allowed_idents_below_min_chars: FxHashSet<String>,
+    pub min_ident_chars_threshold: u64,
+}
+
+impl MinIdentChars {
+    #[expect(clippy::cast_possible_truncation)]
+    fn is_ident_too_short(&self, cx: &LateContext<'_>, str: &str, span: Span) -> bool {
+        !in_external_macro(cx.sess(), span)
+            && str.len() <= self.min_ident_chars_threshold as usize
+            && !str.starts_with('_')
+            && !str.is_empty()
+            && self.allowed_idents_below_min_chars.get(&str.to_owned()).is_none()
+    }
+}
+
+impl LateLintPass<'_> for MinIdentChars {
+    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
+        if self.min_ident_chars_threshold == 0 {
+            return;
+        }
+
+        walk_item(&mut IdentVisitor { conf: self, cx }, item);
+    }
+
+    // This is necessary as `Node::Pat`s are not visited in `visit_id`. :/
+    fn check_pat(&mut self, cx: &LateContext<'_>, pat: &Pat<'_>) {
+        if let PatKind::Binding(_, _, ident, ..) = pat.kind
+            && let str = ident.as_str()
+            && self.is_ident_too_short(cx, str, ident.span)
+        {
+            emit_min_ident_chars(self, cx, str, ident.span);
+        }
+    }
+}
+
+struct IdentVisitor<'cx, 'tcx> {
+    conf: &'cx MinIdentChars,
+    cx: &'cx LateContext<'tcx>,
+}
+
+impl Visitor<'_> for IdentVisitor<'_, '_> {
+    fn visit_id(&mut self, hir_id: HirId) {
+        let Self { conf, cx } = *self;
+        // FIXME(#112534) Reimplementation of `find`, as it uses indexing, which can (and will in
+        // async functions, or really anything async) panic. This should probably be fixed on the
+        // rustc side, this is just a temporary workaround.
+        let node = if hir_id.local_id == ItemLocalId::from_u32(0) {
+            // In this case, we can just use `find`, `Owner`'s `node` field is private anyway so we can't
+            // reimplement it even if we wanted to
+            cx.tcx.hir().find(hir_id)
+        } else {
+            let Some(owner) = cx.tcx.hir_owner_nodes(hir_id.owner).as_owner() else {
+                return;
+            };
+            owner.nodes.get(hir_id.local_id).copied().flatten().map(|p| p.node)
+        };
+        let Some(node) = node else {
+            return;
+        };
+        let Some(ident) = node.ident() else {
+            return;
+        };
+
+        let str = ident.as_str();
+        if conf.is_ident_too_short(cx, str, ident.span) {
+            if let Node::Item(item) = node && let ItemKind::Use(..) = item.kind {
+                return;
+            }
+            // `struct Awa<T>(T)`
+            //                ^
+            if let Node::PathSegment(path) = node {
+                if let Res::Def(def_kind, ..) = path.res && let DefKind::TyParam = def_kind {
+                    return;
+                }
+                if matches!(path.res, Res::PrimTy(..)) || path.res.opt_def_id().is_some_and(|def_id| !def_id.is_local())
+                {
+                    return;
+                }
+            }
+            // `struct Awa<T>(T)`
+            //             ^
+            if let Node::GenericParam(generic_param) = node
+                && let GenericParamKind::Type { .. } = generic_param.kind
+            {
+                return;
+            }
+
+            if is_from_proc_macro(cx, &ident) {
+                return;
+            }
+
+            emit_min_ident_chars(conf, cx, str, ident.span);
+        }
+    }
+}
+
+fn emit_min_ident_chars(conf: &MinIdentChars, cx: &impl LintContext, ident: &str, span: Span) {
+    let help = if conf.min_ident_chars_threshold == 1 {
+        Cow::Borrowed("this ident consists of a single char")
+    } else {
+        Cow::Owned(format!(
+            "this ident is too short ({} <= {})",
+            ident.len(),
+            conf.min_ident_chars_threshold,
+        ))
+    };
+    span_lint(cx, MIN_IDENT_CHARS, span, &help);
+}
diff --git a/clippy_lints/src/minmax.rs b/clippy_lints/src/minmax.rs
index 4f967755bfa..e0904f17b8d 100644
--- a/clippy_lints/src/minmax.rs
+++ b/clippy_lints/src/minmax.rs
@@ -66,7 +66,7 @@ enum MinMax {
     Max,
 }
 
-fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
+fn min_max<'a, 'tcx>(cx: &LateContext<'tcx>, expr: &'a Expr<'a>) -> Option<(MinMax, Constant<'tcx>, &'a Expr<'a>)> {
     match expr.kind {
         ExprKind::Call(path, args) => {
             if let ExprKind::Path(ref qpath) = path.kind {
@@ -99,12 +99,12 @@ fn min_max<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<(MinMax, Cons
     }
 }
 
-fn fetch_const<'a>(
-    cx: &LateContext<'_>,
+fn fetch_const<'a, 'tcx>(
+    cx: &LateContext<'tcx>,
     receiver: Option<&'a Expr<'a>>,
     args: &'a [Expr<'a>],
     m: MinMax,
-) -> Option<(MinMax, Constant, &'a Expr<'a>)> {
+) -> Option<(MinMax, Constant<'tcx>, &'a Expr<'a>)> {
     let mut args = receiver.into_iter().chain(args);
     let first_arg = args.next()?;
     let second_arg = args.next()?;
diff --git a/clippy_lints/src/misc_early/mixed_case_hex_literals.rs b/clippy_lints/src/misc_early/mixed_case_hex_literals.rs
index ddb8b9173a5..9151cc63320 100644
--- a/clippy_lints/src/misc_early/mixed_case_hex_literals.rs
+++ b/clippy_lints/src/misc_early/mixed_case_hex_literals.rs
@@ -13,7 +13,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, lit_span: Span, suffix: &str, lit_sni
         return;
     }
     let mut seen = (false, false);
-    for ch in lit_snip.as_bytes()[2..=maybe_last_sep_idx].iter() {
+    for ch in &lit_snip.as_bytes()[2..=maybe_last_sep_idx] {
         match ch {
             b'a'..=b'f' => seen.0 = true,
             b'A'..=b'F' => seen.1 = true,
diff --git a/clippy_lints/src/misc_early/mod.rs b/clippy_lints/src/misc_early/mod.rs
index 78be6b9e23f..b226b878123 100644
--- a/clippy_lints/src/misc_early/mod.rs
+++ b/clippy_lints/src/misc_early/mod.rs
@@ -2,6 +2,7 @@ mod builtin_type_shadow;
 mod double_neg;
 mod literal_suffix;
 mod mixed_case_hex_literals;
+mod redundant_at_rest_pattern;
 mod redundant_pattern;
 mod unneeded_field_pattern;
 mod unneeded_wildcard_pattern;
@@ -318,6 +319,36 @@ declare_clippy_lint! {
     "tuple patterns with a wildcard pattern (`_`) is next to a rest pattern (`..`)"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `[all @ ..]` patterns.
+    ///
+    /// ### Why is this bad?
+    /// In all cases, `all` works fine and can often make code simpler, as you possibly won't need
+    /// to convert from say a `Vec` to a slice by dereferencing.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// if let [all @ ..] = &*v {
+    ///     // NOTE: Type is a slice here
+    ///     println!("all elements: {all:#?}");
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// if let all = v {
+    ///     // NOTE: Type is a `Vec` here
+    ///     println!("all elements: {all:#?}");
+    /// }
+    /// // or
+    /// println!("all elements: {v:#?}");
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub REDUNDANT_AT_REST_PATTERN,
+    complexity,
+    "checks for `[all @ ..]` where `all` would suffice"
+}
+
 declare_lint_pass!(MiscEarlyLints => [
     UNNEEDED_FIELD_PATTERN,
     DUPLICATE_UNDERSCORE_ARGUMENT,
@@ -329,6 +360,7 @@ declare_lint_pass!(MiscEarlyLints => [
     BUILTIN_TYPE_SHADOW,
     REDUNDANT_PATTERN,
     UNNEEDED_WILDCARD_PATTERN,
+    REDUNDANT_AT_REST_PATTERN,
 ]);
 
 impl EarlyLintPass for MiscEarlyLints {
@@ -339,8 +371,13 @@ impl EarlyLintPass for MiscEarlyLints {
     }
 
     fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) {
+        if in_external_macro(cx.sess(), pat.span) {
+            return;
+        }
+
         unneeded_field_pattern::check(cx, pat);
         redundant_pattern::check(cx, pat);
+        redundant_at_rest_pattern::check(cx, pat);
         unneeded_wildcard_pattern::check(cx, pat);
     }
 
diff --git a/clippy_lints/src/misc_early/redundant_at_rest_pattern.rs b/clippy_lints/src/misc_early/redundant_at_rest_pattern.rs
new file mode 100644
index 00000000000..0c81ee5eced
--- /dev/null
+++ b/clippy_lints/src/misc_early/redundant_at_rest_pattern.rs
@@ -0,0 +1,26 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_ast::{Pat, PatKind};
+use rustc_errors::Applicability;
+use rustc_lint::{EarlyContext, LintContext};
+use rustc_middle::lint::in_external_macro;
+
+use super::REDUNDANT_AT_REST_PATTERN;
+
+pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
+    if !in_external_macro(cx.sess(), pat.span)
+        && let PatKind::Slice(slice) = &pat.kind
+        && let [one] = &**slice
+        && let PatKind::Ident(annotation, ident, Some(rest)) = &one.kind
+        && let PatKind::Rest = rest.kind
+    {
+        span_lint_and_sugg(
+            cx,
+            REDUNDANT_AT_REST_PATTERN,
+            pat.span,
+            "using a rest pattern to bind an entire slice to a local",
+            "this is better represented with just the binding",
+            format!("{}{ident}", annotation.prefix_str()),
+            Applicability::MachineApplicable,
+        );
+    }
+}
diff --git a/clippy_lints/src/mismatching_type_param_order.rs b/clippy_lints/src/mismatching_type_param_order.rs
index 9de4b56b77b..28e041dee0d 100644
--- a/clippy_lints/src/mismatching_type_param_order.rs
+++ b/clippy_lints/src/mismatching_type_param_order.rs
@@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeParamMismatch {
             then {
                 // get the name and span of the generic parameters in the Impl
                 let mut impl_params = Vec::new();
-                for p in generic_args.args.iter() {
+                for p in generic_args.args {
                     match p {
                         GenericArg::Type(Ty {kind: TyKind::Path(QPath::Resolved(_, path)), ..}) =>
                             impl_params.push((path.segments[0].ident.to_string(), path.span)),
diff --git a/clippy_lints/src/missing_fields_in_debug.rs b/clippy_lints/src/missing_fields_in_debug.rs
index b6f0de7e504..1138d1163a4 100644
--- a/clippy_lints/src/missing_fields_in_debug.rs
+++ b/clippy_lints/src/missing_fields_in_debug.rs
@@ -207,6 +207,11 @@ impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug {
         if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), self_ty, items, .. }) = item.kind
             && let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res
             && let TyKind::Path(QPath::Resolved(_, self_path)) = &self_ty.kind
+            // don't trigger if self is a generic parameter, e.g. `impl<T> Debug for T`
+            // this can only happen in core itself, where the trait is defined,
+            // but it caused ICEs in the past:
+            // https://github.com/rust-lang/rust-clippy/issues/10887
+            && !matches!(self_path.res, Res::Def(DefKind::TyParam, _))
             && cx.match_def_path(trait_def_id, &[sym::core, sym::fmt, sym::Debug])
             // don't trigger if this impl was derived
             && !cx.tcx.has_attr(item.owner_id, sym::automatically_derived)
diff --git a/clippy_lints/src/mixed_read_write_in_expression.rs b/clippy_lints/src/mixed_read_write_in_expression.rs
index f0be7771bb1..57ec3a1f1e6 100644
--- a/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -114,7 +114,7 @@ struct DivergenceVisitor<'a, 'tcx> {
 impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
     fn maybe_walk_expr(&mut self, e: &'tcx Expr<'_>) {
         match e.kind {
-            ExprKind::Closure { .. } => {},
+            ExprKind::Closure(..) | ExprKind::If(..) | ExprKind::Loop(..) => {},
             ExprKind::Match(e, arms, _) => {
                 self.visit_expr(e);
                 for arm in arms {
@@ -128,6 +128,7 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
             _ => walk_expr(self, e),
         }
     }
+
     fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) {
         span_lint(self.cx, DIVERGING_SUB_EXPRESSION, e.span, "sub-expression diverges");
     }
@@ -136,6 +137,15 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
 impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
     fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
         match e.kind {
+            // fix #10776
+            ExprKind::Block(block, ..) => match (block.stmts, block.expr) {
+                ([], Some(e)) => self.visit_expr(e),
+                ([stmt], None) => match stmt.kind {
+                    StmtKind::Expr(e) | StmtKind::Semi(e) => self.visit_expr(e),
+                    _ => {},
+                },
+                _ => {},
+            },
             ExprKind::Continue(_) | ExprKind::Break(_, _) | ExprKind::Ret(_) => self.report_diverging_sub_expr(e),
             ExprKind::Call(func, _) => {
                 let typ = self.cx.typeck_results().expr_ty(func);
diff --git a/clippy_lints/src/module_style.rs b/clippy_lints/src/module_style.rs
index 349fcd2274d..439cae812b7 100644
--- a/clippy_lints/src/module_style.rs
+++ b/clippy_lints/src/module_style.rs
@@ -2,6 +2,7 @@ use rustc_ast::ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_lint::{EarlyContext, EarlyLintPass, Level, LintContext};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::{FileName, SourceFile, Span, SyntaxContext};
 use std::ffi::OsStr;
 use std::path::{Component, Path};
@@ -90,7 +91,14 @@ impl EarlyLintPass for ModStyle {
         // `{ foo => path/to/foo.rs, .. }
         let mut file_map = FxHashMap::default();
         for file in files.iter() {
-            if let FileName::Real(name) = &file.name && let Some(lp) = name.local_path() {
+            if let FileName::Real(name) = &file.name
+                && let Some(lp) = name.local_path()
+                && file.cnum == LOCAL_CRATE
+            {
+                // [#8887](https://github.com/rust-lang/rust-clippy/issues/8887)
+                // Only check files in the current crate.
+                // Fix false positive that crate dependency in workspace sub directory
+                // is checked unintentionally.
                 let path = if lp.is_relative() {
                     lp
                 } else if let Ok(relative) = lp.strip_prefix(trim_to_src) {
diff --git a/clippy_lints/src/needless_if.rs b/clippy_lints/src/needless_if.rs
new file mode 100644
index 00000000000..ad5c3e1dc82
--- /dev/null
+++ b/clippy_lints/src/needless_if.rs
@@ -0,0 +1,75 @@
+use clippy_utils::{diagnostics::span_lint_and_sugg, higher::If, is_from_proc_macro, source::snippet_opt};
+use rustc_errors::Applicability;
+use rustc_hir::{ExprKind, Stmt, StmtKind};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for empty `if` branches with no else branch.
+    ///
+    /// ### Why is this bad?
+    /// It can be entirely omitted, and often the condition too.
+    ///
+    /// ### Known issues
+    /// This will usually only suggest to remove the `if` statement, not the condition. Other lints
+    /// such as `no_effect` will take care of removing the condition if it's unnecessary.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// if really_expensive_condition(&i) {}
+    /// if really_expensive_condition_with_side_effects(&mut i) {}
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// // <omitted>
+    /// really_expensive_condition_with_side_effects(&mut i);
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub NEEDLESS_IF,
+    complexity,
+    "checks for empty if branches"
+}
+declare_lint_pass!(NeedlessIf => [NEEDLESS_IF]);
+
+impl LateLintPass<'_> for NeedlessIf {
+    fn check_stmt<'tcx>(&mut self, cx: &LateContext<'tcx>, stmt: &Stmt<'tcx>) {
+        if let StmtKind::Expr(expr) = stmt.kind
+            && let Some(If {cond, then, r#else: None }) = If::hir(expr)
+            && let ExprKind::Block(block, ..) = then.kind
+            && block.stmts.is_empty()
+            && block.expr.is_none()
+            && !in_external_macro(cx.sess(), expr.span)
+            && !is_from_proc_macro(cx, expr)
+            && let Some(then_snippet) = snippet_opt(cx, then.span)
+            // Ignore
+            // - empty macro expansions
+            // - empty reptitions in macro expansions
+            // - comments
+            // - #[cfg]'d out code
+            && then_snippet.chars().all(|ch| matches!(ch, '{' | '}') || ch.is_ascii_whitespace())
+            && let Some(cond_snippet) = snippet_opt(cx, cond.span)
+        {
+            span_lint_and_sugg(
+                cx,
+                NEEDLESS_IF,
+                stmt.span,
+                "this `if` branch is empty",
+                "you can remove it",
+                if cond.can_have_side_effects() || !cx.tcx.hir().attrs(stmt.hir_id).is_empty() {
+                    // `{ foo }` or `{ foo } && bar` placed into a statement position would be
+                    // interpreted as a block statement, force it to be an expression
+                    if cond_snippet.starts_with('{') {
+                        format!("({cond_snippet});")
+                    } else {
+                        format!("{cond_snippet};")
+                    }
+                } else {
+                    String::new()
+                },
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+}
diff --git a/clippy_lints/src/needless_pass_by_value.rs b/clippy_lints/src/needless_pass_by_value.rs
index c0970048cdf..ece10474715 100644
--- a/clippy_lints/src/needless_pass_by_value.rs
+++ b/clippy_lints/src/needless_pass_by_value.rs
@@ -7,13 +7,12 @@ use clippy_utils::ty::{
 use clippy_utils::{get_trait_def_id, is_self, paths};
 use if_chain::if_chain;
 use rustc_ast::ast::Attribute;
-use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, Diagnostic};
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
     BindingAnnotation, Body, FnDecl, GenericArg, HirId, Impl, ItemKind, Mutability, Node, PatKind, QPath, TyKind,
 };
-use rustc_hir::{HirIdMap, HirIdSet, LangItem};
+use rustc_hir::{HirIdSet, LangItem};
 use rustc_hir_typeck::expr_use_visitor as euv;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
@@ -126,9 +125,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
             .filter_map(|pred| {
                 // Note that we do not want to deal with qualified predicates here.
                 match pred.kind().no_bound_vars() {
-                    Some(ty::ClauseKind::Trait(pred)) if pred.def_id() != sized_trait => {
-                        Some(pred)
-                    },
+                    Some(ty::ClauseKind::Trait(pred)) if pred.def_id() != sized_trait => Some(pred),
                     _ => None,
                 }
             })
@@ -136,11 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
 
         // Collect moved variables and spans which will need dereferencings from the
         // function body.
-        let MovedVariablesCtxt {
-            moved_vars,
-            spans_need_deref,
-            ..
-        } = {
+        let MovedVariablesCtxt { moved_vars } = {
             let mut ctx = MovedVariablesCtxt::default();
             let infcx = cx.tcx.infer_ctxt().build();
             euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
@@ -211,7 +204,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                             }
                         }
 
-                        let deref_span = spans_need_deref.get(&canonical_id);
                         if_chain! {
                             if is_type_diagnostic_item(cx, ty, sym::Vec);
                             if let Some(clone_spans) =
@@ -247,7 +239,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                                 }
 
                                 // cannot be destructured, no need for `*` suggestion
-                                assert!(deref_span.is_none());
                                 return;
                             }
                         }
@@ -275,23 +266,12 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
                                     );
                                 }
 
-                                assert!(deref_span.is_none());
                                 return;
                             }
                         }
 
-                        let mut spans = vec![(input.span, format!("&{}", snippet(cx, input.span, "_")))];
-
-                        // Suggests adding `*` to dereference the added reference.
-                        if let Some(deref_span) = deref_span {
-                            spans.extend(
-                                deref_span
-                                    .iter()
-                                    .copied()
-                                    .map(|span| (span, format!("*{}", snippet(cx, span, "<expr>")))),
-                            );
-                            spans.sort_by_key(|&(span, _)| span);
-                        }
+                        let spans = vec![(input.span, format!("&{}", snippet(cx, input.span, "_")))];
+
                         multispan_sugg(diag, "consider taking a reference instead", spans);
                     };
 
@@ -320,9 +300,6 @@ fn requires_exact_signature(attrs: &[Attribute]) -> bool {
 #[derive(Default)]
 struct MovedVariablesCtxt {
     moved_vars: HirIdSet,
-    /// Spans which need to be prefixed with `*` for dereferencing the
-    /// suggested additional reference.
-    spans_need_deref: HirIdMap<FxHashSet<Span>>,
 }
 
 impl MovedVariablesCtxt {
diff --git a/clippy_lints/src/no_effect.rs b/clippy_lints/src/no_effect.rs
index e3712190e67..a4c7da7e48d 100644
--- a/clippy_lints/src/no_effect.rs
+++ b/clippy_lints/src/no_effect.rs
@@ -1,11 +1,16 @@
 use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
-use clippy_utils::is_lint_allowed;
 use clippy_utils::peel_blocks;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::has_drop;
+use clippy_utils::{get_parent_node, is_lint_allowed};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, PatKind, Stmt, StmtKind, UnsafeSource};
+use rustc_hir::{
+    is_range_literal, BinOpKind, BlockCheckMode, Expr, ExprKind, FnRetTy, ItemKind, Node, PatKind, Stmt, StmtKind,
+    UnsafeSource,
+};
+use rustc_hir_analysis::hir_ty_to_ty;
+use rustc_infer::infer::TyCtxtInferExt as _;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -86,7 +91,43 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect {
 fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
     if let StmtKind::Semi(expr) = stmt.kind {
         if has_no_effect(cx, expr) {
-            span_lint_hir(cx, NO_EFFECT, expr.hir_id, stmt.span, "statement with no effect");
+            span_lint_hir_and_then(
+                cx,
+                NO_EFFECT,
+                expr.hir_id,
+                stmt.span,
+                "statement with no effect",
+                |diag| {
+                    for parent in cx.tcx.hir().parent_iter(stmt.hir_id) {
+                        if let Node::Item(item) = parent.1
+                            && let ItemKind::Fn(sig, ..) = item.kind
+                            && let FnRetTy::Return(ret_ty) = sig.decl.output
+                            && let Some(Node::Block(block)) = get_parent_node(cx.tcx, stmt.hir_id)
+                            && let [.., final_stmt] = block.stmts
+                            && final_stmt.hir_id == stmt.hir_id
+                        {
+                            let expr_ty = cx.typeck_results().expr_ty(expr);
+                            let mut ret_ty = hir_ty_to_ty(cx.tcx, ret_ty);
+
+                            // Remove `impl Future<Output = T>` to get `T`
+                            if cx.tcx.ty_is_opaque_future(ret_ty) &&
+                                let Some(true_ret_ty) = cx.tcx.infer_ctxt().build().get_impl_future_output_ty(ret_ty)
+                            {
+                                ret_ty = true_ret_ty;
+                            }
+
+                            if ret_ty == expr_ty {
+                                diag.span_suggestion(
+                                    stmt.span.shrink_to_lo(),
+                                    "did you mean to return it?",
+                                    "return ",
+                                    Applicability::MaybeIncorrect,
+                                );
+                            }
+                        }
+                    }
+                },
+            );
             return true;
         }
     } else if let StmtKind::Local(local) = stmt.kind {
diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs
index ac49ccdb501..75f1e95276a 100644
--- a/clippy_lints/src/non_copy_const.rs
+++ b/clippy_lints/src/non_copy_const.rs
@@ -182,15 +182,15 @@ fn is_value_unfrozen_raw<'tcx>(
             // have a value that is a frozen variant with a generic param (an example is
             // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::GENERIC_VARIANT`).
             // However, it prevents a number of false negatives that is, I think, important:
-            // 1. assoc consts in trait defs referring to consts of themselves
-            //    (an example is `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`).
-            // 2. a path expr referring to assoc consts whose type is doesn't have
-            //    any frozen variants in trait defs (i.e. without substitute for `Self`).
-            //    (e.g. borrowing `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`)
-            // 3. similar to the false positive above;
-            //    but the value is an unfrozen variant, or the type has no enums. (An example is
-            //    `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT`
-            //    and `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`).
+            // 1. assoc consts in trait defs referring to consts of themselves (an example is
+            //    `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`).
+            // 2. a path expr referring to assoc consts whose type is doesn't have any frozen variants in trait
+            //    defs (i.e. without substitute for `Self`). (e.g. borrowing
+            //    `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`)
+            // 3. similar to the false positive above; but the value is an unfrozen variant, or the type has no
+            //    enums. (An example is
+            //    `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT` and
+            //    `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`).
             // One might be able to prevent these FNs correctly, and replace this with `false`;
             // e.g. implementing `has_frozen_variant` described above, and not running this function
             // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd
diff --git a/clippy_lints/src/operators/eq_op.rs b/clippy_lints/src/operators/eq_op.rs
index 67913f7392c..78965b7d6f7 100644
--- a/clippy_lints/src/operators/eq_op.rs
+++ b/clippy_lints/src/operators/eq_op.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint;
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace};
 use clippy_utils::{ast_utils::is_useless_with_eq_exprs, eq_expr_value, is_in_test_function};
 use rustc_hir::{BinOpKind, Expr};
@@ -35,11 +35,16 @@ pub(crate) fn check<'tcx>(
     right: &'tcx Expr<'_>,
 ) {
     if is_useless_with_eq_exprs(op.into()) && eq_expr_value(cx, left, right) && !is_in_test_function(cx.tcx, e.hir_id) {
-        span_lint(
+        span_lint_and_then(
             cx,
             EQ_OP,
             e.span,
             &format!("equal expressions as operands to `{}`", op.as_str()),
+            |diag| {
+                if let BinOpKind::Ne = op && cx.typeck_results().expr_ty(left).is_floating_point() {
+                    diag.note("if you intended to check if the operand is NaN, use `.is_nan()` instead");
+                }
+            },
         );
     }
 }
diff --git a/clippy_lints/src/operators/float_cmp.rs b/clippy_lints/src/operators/float_cmp.rs
index 15dff126be7..f3e0c58a787 100644
--- a/clippy_lints/src/operators/float_cmp.rs
+++ b/clippy_lints/src/operators/float_cmp.rs
@@ -85,7 +85,7 @@ fn get_lint_and_message(is_local: bool, is_comparing_arrays: bool) -> (&'static
     }
 }
 
-fn is_allowed(val: &Constant) -> bool {
+fn is_allowed(val: &Constant<'_>) -> bool {
     match val {
         &Constant::F32(f) => f == 0.0 || f.is_infinite(),
         &Constant::F64(f) => f == 0.0 || f.is_infinite(),
diff --git a/clippy_lints/src/option_if_let_else.rs b/clippy_lints/src/option_if_let_else.rs
index aa6d4004268..abdccc47f54 100644
--- a/clippy_lints/src/option_if_let_else.rs
+++ b/clippy_lints/src/option_if_let_else.rs
@@ -140,6 +140,9 @@ fn try_get_option_occurrence<'tcx>(
             let (as_ref, as_mut) = match &expr.kind {
                 ExprKind::AddrOf(_, Mutability::Not, _) => (true, false),
                 ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true),
+                _ if let Some(mutb) = cx.typeck_results().expr_ty(expr).ref_mutability() => {
+                    (mutb == Mutability::Not, mutb == Mutability::Mut)
+                }
                 _ => (bind_annotation == BindingAnnotation::REF, bind_annotation == BindingAnnotation::REF_MUT),
             };
 
diff --git a/clippy_lints/src/ptr.rs b/clippy_lints/src/ptr.rs
index b8911f10907..866a04466c9 100644
--- a/clippy_lints/src/ptr.rs
+++ b/clippy_lints/src/ptr.rs
@@ -5,6 +5,7 @@ use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::expr_sig;
 use clippy_utils::visitors::contains_unsafe_block;
 use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, paths};
+use hir::LifetimeName;
 use if_chain::if_chain;
 use rustc_errors::{Applicability, MultiSpan};
 use rustc_hir::def_id::DefId;
@@ -15,6 +16,7 @@ use rustc_hir::{
     ImplItemKind, ItemKind, Lifetime, Mutability, Node, Param, PatKind, QPath, TraitFn, TraitItem, TraitItemKind,
     TyKind, Unsafety,
 };
+use rustc_hir_analysis::hir_ty_to_ty;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::{Obligation, ObligationCause};
 use rustc_lint::{LateContext, LateLintPass};
@@ -166,6 +168,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
                 cx,
                 cx.tcx.fn_sig(item.owner_id).subst_identity().skip_binder().inputs(),
                 sig.decl.inputs,
+                &sig.decl.output,
                 &[],
             )
             .filter(|arg| arg.mutability() == Mutability::Not)
@@ -218,7 +221,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
         check_mut_from_ref(cx, sig, Some(body));
         let decl = sig.decl;
         let sig = cx.tcx.fn_sig(item_id).subst_identity().skip_binder();
-        let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, body.params)
+        let lint_args: Vec<_> = check_fn_args(cx, sig.inputs(), decl.inputs, &decl.output, body.params)
             .filter(|arg| !is_trait_item || arg.mutability() == Mutability::Not)
             .collect();
         let results = check_ptr_arg_usage(cx, body, &lint_args);
@@ -407,29 +410,27 @@ impl<'tcx> DerefTy<'tcx> {
     }
 }
 
+#[expect(clippy::too_many_lines)]
 fn check_fn_args<'cx, 'tcx: 'cx>(
     cx: &'cx LateContext<'tcx>,
     tys: &'tcx [Ty<'tcx>],
     hir_tys: &'tcx [hir::Ty<'tcx>],
+    ret_ty: &'tcx FnRetTy<'tcx>,
     params: &'tcx [Param<'tcx>],
 ) -> impl Iterator<Item = PtrArg<'tcx>> + 'cx {
     tys.iter()
         .zip(hir_tys.iter())
         .enumerate()
-        .filter_map(|(i, (ty, hir_ty))| {
-            if_chain! {
-                if let ty::Ref(_, ty, mutability) = *ty.kind();
-                if let ty::Adt(adt, substs) = *ty.kind();
-
-                if let TyKind::Ref(lt, ref ty) = hir_ty.kind;
-                if let TyKind::Path(QPath::Resolved(None, path)) = ty.ty.kind;
-
+        .filter_map(move |(i, (ty, hir_ty))| {
+            if let ty::Ref(_, ty, mutability) = *ty.kind()
+                && let  ty::Adt(adt, substs) = *ty.kind()
+                && let TyKind::Ref(lt, ref ty) = hir_ty.kind
+                && let TyKind::Path(QPath::Resolved(None, path)) = ty.ty.kind
                 // Check that the name as typed matches the actual name of the type.
                 // e.g. `fn foo(_: &Foo)` shouldn't trigger the lint when `Foo` is an alias for `Vec`
-                if let [.., name] = path.segments;
-                if cx.tcx.item_name(adt.did()) == name.ident.name;
-
-                then {
+                && let [.., name] = path.segments
+                && cx.tcx.item_name(adt.did()) == name.ident.name
+            {
                     let emission_id = params.get(i).map_or(hir_ty.hir_id, |param| param.hir_id);
                     let (method_renames, deref_ty) = match cx.tcx.get_diagnostic_name(adt.did()) {
                         Some(sym::Vec) => (
@@ -454,30 +455,65 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
                             DerefTy::Path,
                         ),
                         Some(sym::Cow) if mutability == Mutability::Not => {
-                            let ty_name = name.args
+                            if let Some((lifetime, ty)) = name.args
                                 .and_then(|args| {
-                                    args.args.iter().find_map(|a| match a {
-                                        GenericArg::Type(x) => Some(x),
-                                        _ => None,
-                                    })
+                                    if let [GenericArg::Lifetime(lifetime), ty] = args.args {
+                                        return Some((lifetime, ty));
+                                    }
+                                    None
                                 })
-                                .and_then(|arg| snippet_opt(cx, arg.span))
-                                .unwrap_or_else(|| substs.type_at(1).to_string());
-                            span_lint_hir_and_then(
-                                cx,
-                                PTR_ARG,
-                                emission_id,
-                                hir_ty.span,
-                                "using a reference to `Cow` is not recommended",
-                                |diag| {
-                                    diag.span_suggestion(
-                                        hir_ty.span,
-                                        "change this to",
-                                        format!("&{}{ty_name}", mutability.prefix_str()),
-                                        Applicability::Unspecified,
-                                    );
+                            {
+                                if !lifetime.is_anonymous()
+                                    && let FnRetTy::Return(ret_ty) = ret_ty
+                                    && let ret_ty = hir_ty_to_ty(cx.tcx, ret_ty)
+                                    && ret_ty
+                                        .walk()
+                                        .filter_map(|arg| {
+                                            arg.as_region().and_then(|lifetime| {
+                                                match lifetime.kind() {
+                                                    ty::ReEarlyBound(r) => Some(r.def_id),
+                                                    ty::ReLateBound(_, r) => r.kind.get_id(),
+                                                    ty::ReFree(r) => r.bound_region.get_id(),
+                                                    ty::ReStatic
+                                                    | ty::ReVar(_)
+                                                    | ty::RePlaceholder(_)
+                                                    | ty::ReErased
+                                                    | ty::ReError(_) => None,
+                                                }
+                                            })
+                                        })
+                                        .any(|def_id| {
+                                            matches!(
+                                                lifetime.res,
+                                                LifetimeName::Param(param_def_id) if def_id
+                                                    .as_local()
+                                                    .is_some_and(|def_id| def_id == param_def_id),
+                                            )
+                                        })
+                                {
+                                    // `&Cow<'a, T>` when the return type uses 'a is okay
+                                    return None;
                                 }
-                            );
+
+                                let ty_name =
+                                    snippet_opt(cx, ty.span()).unwrap_or_else(|| substs.type_at(1).to_string());
+
+                                span_lint_hir_and_then(
+                                    cx,
+                                    PTR_ARG,
+                                    emission_id,
+                                    hir_ty.span,
+                                    "using a reference to `Cow` is not recommended",
+                                    |diag| {
+                                        diag.span_suggestion(
+                                            hir_ty.span,
+                                            "change this to",
+                                            format!("&{}{ty_name}", mutability.prefix_str()),
+                                            Applicability::Unspecified,
+                                        );
+                                    }
+                                );
+                            }
                             return None;
                         },
                         _ => return None,
@@ -495,7 +531,6 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
                         },
                         deref_ty,
                     });
-                }
             }
             None
         })
diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs
index 5269bbd1f1a..e3d940ad2a4 100644
--- a/clippy_lints/src/question_mark.rs
+++ b/clippy_lints/src/question_mark.rs
@@ -1,19 +1,20 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{
     eq_expr_value, get_parent_node, in_constant, is_else_clause, is_res_lang_ctor, path_to_local, path_to_local_id,
     peel_blocks, peel_blocks_with_stmt,
 };
+use clippy_utils::{higher, is_path_lang_item};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
-use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
+use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, Node, PatKind, PathSegment, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_tool_lint;
+use rustc_session::impl_lint_pass;
 use rustc_span::{sym, symbol::Symbol};
 
 declare_clippy_lint! {
@@ -41,7 +42,16 @@ declare_clippy_lint! {
     "checks for expressions that could be replaced by the question mark operator"
 }
 
-declare_lint_pass!(QuestionMark => [QUESTION_MARK]);
+#[derive(Default)]
+pub struct QuestionMark {
+    /// Keeps track of how many try blocks we are in at any point during linting.
+    /// This allows us to answer the question "are we inside of a try block"
+    /// very quickly, without having to walk up the parent chain, by simply checking
+    /// if it is greater than zero.
+    /// As for why we need this in the first place: <https://github.com/rust-lang/rust-clippy/issues/8628>
+    try_block_depth_stack: Vec<u32>,
+}
+impl_lint_pass!(QuestionMark => [QUESTION_MARK]);
 
 enum IfBlockType<'hir> {
     /// An `if x.is_xxx() { a } else { b } ` expression.
@@ -68,98 +78,6 @@ enum IfBlockType<'hir> {
     ),
 }
 
-/// Checks if the given expression on the given context matches the following structure:
-///
-/// ```ignore
-/// if option.is_none() {
-///    return None;
-/// }
-/// ```
-///
-/// ```ignore
-/// if result.is_err() {
-///     return result;
-/// }
-/// ```
-///
-/// If it matches, it will suggest to use the question mark operator instead
-fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
-    if_chain! {
-        if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr);
-        if !is_else_clause(cx.tcx, expr);
-        if let ExprKind::MethodCall(segment, caller, ..) = &cond.kind;
-        let caller_ty = cx.typeck_results().expr_ty(caller);
-        let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else);
-        if is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block);
-        then {
-            let mut applicability = Applicability::MachineApplicable;
-            let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability);
-            let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.param_env) &&
-                !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..));
-            let sugg = if let Some(else_inner) = r#else {
-                if eq_expr_value(cx, caller, peel_blocks(else_inner)) {
-                    format!("Some({receiver_str}?)")
-                } else {
-                    return;
-                }
-            } else {
-                format!("{receiver_str}{}?;", if by_ref { ".as_ref()" } else { "" })
-            };
-
-            span_lint_and_sugg(
-                cx,
-                QUESTION_MARK,
-                expr.span,
-                "this block may be rewritten with the `?` operator",
-                "replace it with",
-                sugg,
-                applicability,
-            );
-        }
-    }
-}
-
-fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
-    if_chain! {
-        if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr);
-        if !is_else_clause(cx.tcx, expr);
-        if let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind;
-        if ddpos.as_opt_usize().is_none();
-        if let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind;
-        let caller_ty = cx.typeck_results().expr_ty(let_expr);
-        let if_block = IfBlockType::IfLet(
-            cx.qpath_res(path1, let_pat.hir_id),
-            caller_ty,
-            ident.name,
-            let_expr,
-            if_then,
-            if_else
-        );
-        if (is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id))
-            || is_early_return(sym::Result, cx, &if_block);
-        if if_else.map(|e| eq_expr_value(cx, let_expr, peel_blocks(e))).filter(|e| *e).is_none();
-        then {
-            let mut applicability = Applicability::MachineApplicable;
-            let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
-            let requires_semi = matches!(get_parent_node(cx.tcx, expr.hir_id), Some(Node::Stmt(_)));
-            let sugg = format!(
-                "{receiver_str}{}?{}",
-                if by_ref == ByRef::Yes { ".as_ref()" } else { "" },
-                if requires_semi { ";" } else { "" }
-            );
-            span_lint_and_sugg(
-                cx,
-                QUESTION_MARK,
-                expr.span,
-                "this block may be rewritten with the `?` operator",
-                "replace it with",
-                sugg,
-                applicability,
-            );
-        }
-    }
-}
-
 fn is_early_return(smbl: Symbol, cx: &LateContext<'_>, if_block: &IfBlockType<'_>) -> bool {
     match *if_block {
         IfBlockType::IfIs(caller, caller_ty, call_sym, if_then, _) => {
@@ -230,11 +148,147 @@ fn expr_return_none_or_err(
     }
 }
 
+impl QuestionMark {
+    fn inside_try_block(&self) -> bool {
+        self.try_block_depth_stack.last() > Some(&0)
+    }
+
+    /// Checks if the given expression on the given context matches the following structure:
+    ///
+    /// ```ignore
+    /// if option.is_none() {
+    ///    return None;
+    /// }
+    /// ```
+    ///
+    /// ```ignore
+    /// if result.is_err() {
+    ///     return result;
+    /// }
+    /// ```
+    ///
+    /// If it matches, it will suggest to use the question mark operator instead
+    fn check_is_none_or_err_and_early_return<'tcx>(&self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
+        if_chain! {
+            if !self.inside_try_block();
+            if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr);
+            if !is_else_clause(cx.tcx, expr);
+            if let ExprKind::MethodCall(segment, caller, ..) = &cond.kind;
+            let caller_ty = cx.typeck_results().expr_ty(caller);
+            let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else);
+            if is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block);
+            then {
+                let mut applicability = Applicability::MachineApplicable;
+                let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability);
+                let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.param_env) &&
+                    !matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..));
+                let sugg = if let Some(else_inner) = r#else {
+                    if eq_expr_value(cx, caller, peel_blocks(else_inner)) {
+                        format!("Some({receiver_str}?)")
+                    } else {
+                        return;
+                    }
+                } else {
+                    format!("{receiver_str}{}?;", if by_ref { ".as_ref()" } else { "" })
+                };
+
+                span_lint_and_sugg(
+                    cx,
+                    QUESTION_MARK,
+                    expr.span,
+                    "this block may be rewritten with the `?` operator",
+                    "replace it with",
+                    sugg,
+                    applicability,
+                );
+            }
+        }
+    }
+
+    fn check_if_let_some_or_err_and_early_return<'tcx>(&self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
+        if_chain! {
+            if !self.inside_try_block();
+            if let Some(higher::IfLet { let_pat, let_expr, if_then, if_else }) = higher::IfLet::hir(cx, expr);
+            if !is_else_clause(cx.tcx, expr);
+            if let PatKind::TupleStruct(ref path1, [field], ddpos) = let_pat.kind;
+            if ddpos.as_opt_usize().is_none();
+            if let PatKind::Binding(BindingAnnotation(by_ref, _), bind_id, ident, None) = field.kind;
+            let caller_ty = cx.typeck_results().expr_ty(let_expr);
+            let if_block = IfBlockType::IfLet(
+                cx.qpath_res(path1, let_pat.hir_id),
+                caller_ty,
+                ident.name,
+                let_expr,
+                if_then,
+                if_else
+            );
+            if (is_early_return(sym::Option, cx, &if_block) && path_to_local_id(peel_blocks(if_then), bind_id))
+                || is_early_return(sym::Result, cx, &if_block);
+            if if_else.map(|e| eq_expr_value(cx, let_expr, peel_blocks(e))).filter(|e| *e).is_none();
+            then {
+                let mut applicability = Applicability::MachineApplicable;
+                let receiver_str = snippet_with_applicability(cx, let_expr.span, "..", &mut applicability);
+                let requires_semi = matches!(get_parent_node(cx.tcx, expr.hir_id), Some(Node::Stmt(_)));
+                let sugg = format!(
+                    "{receiver_str}{}?{}",
+                    if by_ref == ByRef::Yes { ".as_ref()" } else { "" },
+                    if requires_semi { ";" } else { "" }
+                );
+                span_lint_and_sugg(
+                    cx,
+                    QUESTION_MARK,
+                    expr.span,
+                    "this block may be rewritten with the `?` operator",
+                    "replace it with",
+                    sugg,
+                    applicability,
+                );
+            }
+        }
+    }
+}
+
+fn is_try_block(cx: &LateContext<'_>, bl: &rustc_hir::Block<'_>) -> bool {
+    if let Some(expr) = bl.expr
+        && let rustc_hir::ExprKind::Call(callee, _) = expr.kind
+    {
+        is_path_lang_item(cx, callee, LangItem::TryTraitFromOutput)
+    } else {
+        false
+    }
+}
+
 impl<'tcx> LateLintPass<'tcx> for QuestionMark {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if !in_constant(cx, expr.hir_id) {
-            check_is_none_or_err_and_early_return(cx, expr);
-            check_if_let_some_or_err_and_early_return(cx, expr);
+            self.check_is_none_or_err_and_early_return(cx, expr);
+            self.check_if_let_some_or_err_and_early_return(cx, expr);
+        }
+    }
+
+    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx rustc_hir::Block<'tcx>) {
+        if is_try_block(cx, block) {
+            *self
+                .try_block_depth_stack
+                .last_mut()
+                .expect("blocks are always part of bodies and must have a depth") += 1;
+        }
+    }
+
+    fn check_body(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::Body<'tcx>) {
+        self.try_block_depth_stack.push(0);
+    }
+
+    fn check_body_post(&mut self, _: &LateContext<'tcx>, _: &'tcx rustc_hir::Body<'tcx>) {
+        self.try_block_depth_stack.pop();
+    }
+
+    fn check_block_post(&mut self, cx: &LateContext<'tcx>, block: &'tcx rustc_hir::Block<'tcx>) {
+        if is_try_block(cx, block) {
+            *self
+                .try_block_depth_stack
+                .last_mut()
+                .expect("blocks are always part of bodies and must have a depth") -= 1;
         }
     }
 }
diff --git a/clippy_lints/src/ranges.rs b/clippy_lints/src/ranges.rs
index dd7ded491e7..d2018aba9e3 100644
--- a/clippy_lints/src/ranges.rs
+++ b/clippy_lints/src/ranges.rs
@@ -296,8 +296,8 @@ fn check_possible_range_contains(
     }
 }
 
-struct RangeBounds<'a> {
-    val: Constant,
+struct RangeBounds<'a, 'tcx> {
+    val: Constant<'tcx>,
     expr: &'a Expr<'a>,
     id: HirId,
     name_span: Span,
@@ -309,7 +309,7 @@ struct RangeBounds<'a> {
 // Takes a binary expression such as x <= 2 as input
 // Breaks apart into various pieces, such as the value of the number,
 // hir id of the variable, and direction/inclusiveness of the operator
-fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<RangeBounds<'a>> {
+fn check_range_bounds<'a, 'tcx>(cx: &'a LateContext<'tcx>, ex: &'a Expr<'_>) -> Option<RangeBounds<'a, 'tcx>> {
     if let ExprKind::Binary(ref op, l, r) = ex.kind {
         let (inclusive, ordering) = match op.node {
             BinOpKind::Gt => (false, Ordering::Greater),
diff --git a/clippy_lints/src/raw_strings.rs b/clippy_lints/src/raw_strings.rs
new file mode 100644
index 00000000000..f45bb1ef3e1
--- /dev/null
+++ b/clippy_lints/src/raw_strings.rs
@@ -0,0 +1,143 @@
+use std::{iter::once, ops::ControlFlow};
+
+use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet};
+use rustc_ast::{
+    ast::{Expr, ExprKind},
+    token::LitKind,
+};
+use rustc_errors::Applicability;
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for raw string literals where a string literal can be used instead.
+    ///
+    /// ### Why is this bad?
+    /// It's just unnecessary, but there are many cases where using a raw string literal is more
+    /// idiomatic than a string literal, so it's opt-in.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let r = r"Hello, world!";
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let r = "Hello, world!";
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub NEEDLESS_RAW_STRINGS,
+    restriction,
+    "suggests using a string literal when a raw string literal is unnecessary"
+}
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for raw string literals with an unnecessary amount of hashes around them.
+    ///
+    /// ### Why is this bad?
+    /// It's just unnecessary, and makes it look like there's more escaping needed than is actually
+    /// necessary.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let r = r###"Hello, "world"!"###;
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let r = r#"Hello, "world"!"#;
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub NEEDLESS_RAW_STRING_HASHES,
+    style,
+    "suggests reducing the number of hashes around a raw string literal"
+}
+impl_lint_pass!(RawStrings => [NEEDLESS_RAW_STRINGS, NEEDLESS_RAW_STRING_HASHES]);
+
+pub struct RawStrings {
+    pub needless_raw_string_hashes_allow_one: bool,
+}
+
+impl EarlyLintPass for RawStrings {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
+        if !in_external_macro(cx.sess(), expr.span)
+            && let ExprKind::Lit(lit) = expr.kind
+            && let LitKind::StrRaw(max) | LitKind::ByteStrRaw(max) | LitKind::CStrRaw(max) = lit.kind
+        {
+            let str = lit.symbol.as_str();
+            let prefix = match lit.kind {
+                LitKind::StrRaw(..) => "r",
+                LitKind::ByteStrRaw(..) => "br",
+                LitKind::CStrRaw(..) => "cr",
+                _ => unreachable!(),
+            };
+            if !snippet(cx, expr.span, prefix).trim().starts_with(prefix) {
+                return;
+            }
+
+            if !str.contains(['\\', '"']) {
+                span_lint_and_sugg(
+                    cx,
+                    NEEDLESS_RAW_STRINGS,
+                    expr.span,
+                    "unnecessary raw string literal",
+                    "try",
+                    format!("{}\"{}\"", prefix.replace('r', ""), lit.symbol),
+                    Applicability::MachineApplicable,
+                );
+
+                return;
+            }
+
+            let req = {
+                let mut following_quote = false;
+                let mut req = 0;
+                // `once` so a raw string ending in hashes is still checked
+                let num = str.as_bytes().iter().chain(once(&0)).try_fold(0u8, |acc, &b| {
+                    match b {
+                        b'"' => (following_quote, req) = (true, 1),
+                        // I'm a bit surprised the compiler didn't optimize this out, there's no
+                        // branch but it still ends up doing an unnecessary comparison, it's:
+                        // - cmp r9b,1h
+                        // - sbb cl,-1h
+                        // which will add 1 if it's true. With this change, it becomes:
+                        // - add cl,r9b
+                        // isn't that so much nicer?
+                        b'#' => req += u8::from(following_quote),
+                        _ => {
+                            if following_quote {
+                                following_quote = false;
+
+                                if req == max {
+                                    return ControlFlow::Break(req);
+                                }
+
+                                return ControlFlow::Continue(acc.max(req));
+                            }
+                        },
+                    }
+
+                    ControlFlow::Continue(acc)
+                });
+
+                match num {
+                    ControlFlow::Continue(num) | ControlFlow::Break(num) => num,
+                }
+            };
+
+            if req < max {
+                let hashes = "#".repeat(req as usize);
+
+                span_lint_and_sugg(
+                    cx,
+                    NEEDLESS_RAW_STRING_HASHES,
+                    expr.span,
+                    "unnecessary hashes around raw string literal",
+                    "try",
+                    format!(r#"{prefix}{hashes}"{}"{hashes}"#, lit.symbol),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/redundant_clone.rs b/clippy_lints/src/redundant_clone.rs
index 944a33cc3e5..e36adef555e 100644
--- a/clippy_lints/src/redundant_clone.rs
+++ b/clippy_lints/src/redundant_clone.rs
@@ -57,7 +57,7 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "1.32.0"]
     pub REDUNDANT_CLONE,
-    perf,
+    nursery,
     "`clone()` of an owned value that is going to be dropped immediately"
 }
 
@@ -320,8 +320,6 @@ fn base_local_and_movability<'tcx>(
     mir: &mir::Body<'tcx>,
     place: mir::Place<'tcx>,
 ) -> (mir::Local, CannotMoveOut) {
-    use rustc_middle::mir::PlaceRef;
-
     // Dereference. You cannot move things out from a borrowed value.
     let mut deref = false;
     // Accessing a field of an ADT that has `Drop`. Moving the field out will cause E0509.
@@ -330,17 +328,14 @@ fn base_local_and_movability<'tcx>(
     // underlying type implements Copy
     let mut slice = false;
 
-    let PlaceRef { local, mut projection } = place.as_ref();
-    while let [base @ .., elem] = projection {
-        projection = base;
+    for (base, elem) in place.as_ref().iter_projections() {
+        let base_ty = base.ty(&mir.local_decls, cx.tcx).ty;
         deref |= matches!(elem, mir::ProjectionElem::Deref);
-        field |= matches!(elem, mir::ProjectionElem::Field(..))
-            && has_drop(cx, mir::Place::ty_from(local, projection, &mir.local_decls, cx.tcx).ty);
-        slice |= matches!(elem, mir::ProjectionElem::Index(..))
-            && !is_copy(cx, mir::Place::ty_from(local, projection, &mir.local_decls, cx.tcx).ty);
+        field |= matches!(elem, mir::ProjectionElem::Field(..)) && has_drop(cx, base_ty);
+        slice |= matches!(elem, mir::ProjectionElem::Index(..)) && !is_copy(cx, base_ty);
     }
 
-    (local, deref || field || slice)
+    (place.local, deref || field || slice)
 }
 
 #[derive(Default)]
diff --git a/clippy_lints/src/redundant_closure_call.rs b/clippy_lints/src/redundant_closure_call.rs
index 2a42e73488f..b6ce4ebc28f 100644
--- a/clippy_lints/src/redundant_closure_call.rs
+++ b/clippy_lints/src/redundant_closure_call.rs
@@ -1,14 +1,14 @@
+use crate::rustc_lint::LintContext;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
+use clippy_utils::get_parent_expr;
 use clippy_utils::sugg::Sugg;
 use if_chain::if_chain;
-use rustc_ast::ast;
-use rustc_ast::visit as ast_visit;
-use rustc_ast::visit::Visitor as AstVisitor;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::intravisit as hir_visit;
 use rustc_hir::intravisit::Visitor as HirVisitor;
-use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
+use rustc_hir::intravisit::Visitor;
+use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -51,59 +51,136 @@ impl ReturnVisitor {
     }
 }
 
-impl<'ast> ast_visit::Visitor<'ast> for ReturnVisitor {
-    fn visit_expr(&mut self, ex: &'ast ast::Expr) {
-        if let ast::ExprKind::Ret(_) | ast::ExprKind::Try(_) = ex.kind {
+impl<'tcx> Visitor<'tcx> for ReturnVisitor {
+    fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
+        if let hir::ExprKind::Ret(_) | hir::ExprKind::Match(.., hir::MatchSource::TryDesugar) = ex.kind {
             self.found_return = true;
+        } else {
+            hir_visit::walk_expr(self, ex);
         }
+    }
+}
 
-        ast_visit::walk_expr(self, ex);
+/// Checks if the body is owned by an async closure
+fn is_async_closure(body: &hir::Body<'_>) -> bool {
+    if let hir::ExprKind::Closure(closure) = body.value.kind
+        && let [resume_ty] = closure.fn_decl.inputs
+        && let hir::TyKind::Path(hir::QPath::LangItem(hir::LangItem::ResumeTy, ..)) = resume_ty.kind
+    {
+        true
+    } else {
+        false
     }
 }
 
-impl EarlyLintPass for RedundantClosureCall {
-    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
+/// Tries to find the innermost closure:
+/// ```rust,ignore
+/// (|| || || || 42)()()()()
+///  ^^^^^^^^^^^^^^          given this nested closure expression
+///           ^^^^^          we want to return this closure
+/// ```
+/// It also has a parameter for how many steps to go in at most, so as to
+/// not take more closures than there are calls.
+fn find_innermost_closure<'tcx>(
+    cx: &LateContext<'tcx>,
+    mut expr: &'tcx hir::Expr<'tcx>,
+    mut steps: usize,
+) -> Option<(&'tcx hir::Expr<'tcx>, &'tcx hir::FnDecl<'tcx>, hir::IsAsync)> {
+    let mut data = None;
+
+    while let hir::ExprKind::Closure(closure) = expr.kind
+        && let body = cx.tcx.hir().body(closure.body)
+        && {
+            let mut visitor = ReturnVisitor::new();
+            visitor.visit_expr(body.value);
+            !visitor.found_return
+        }
+        && steps > 0
+    {
+        expr = body.value;
+        data = Some((body.value, closure.fn_decl, if is_async_closure(body) {
+            hir::IsAsync::Async
+        } else {
+            hir::IsAsync::NotAsync
+        }));
+        steps -= 1;
+    }
+
+    data
+}
+
+/// "Walks up" the chain of calls to find the outermost call expression, and returns the depth:
+/// ```rust,ignore
+/// (|| || || 3)()()()
+///             ^^      this is the call expression we were given
+///                 ^^  this is what we want to return (and the depth is 3)
+/// ```
+fn get_parent_call_exprs<'tcx>(
+    cx: &LateContext<'tcx>,
+    mut expr: &'tcx hir::Expr<'tcx>,
+) -> (&'tcx hir::Expr<'tcx>, usize) {
+    let mut depth = 1;
+    while let Some(parent) = get_parent_expr(cx, expr)
+        && let hir::ExprKind::Call(recv, _) = parent.kind
+        && expr.span == recv.span
+    {
+        expr = parent;
+        depth += 1;
+    }
+    (expr, depth)
+}
+
+impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
         if in_external_macro(cx.sess(), expr.span) {
             return;
         }
-        if_chain! {
-            if let ast::ExprKind::Call(ref paren, _) = expr.kind;
-            if let ast::ExprKind::Paren(ref closure) = paren.kind;
-            if let ast::ExprKind::Closure(box ast::Closure { ref asyncness, ref fn_decl, ref body, .. }) = closure.kind;
-            then {
-                let mut visitor = ReturnVisitor::new();
-                visitor.visit_expr(body);
-                if !visitor.found_return {
-                    span_lint_and_then(
-                        cx,
-                        REDUNDANT_CLOSURE_CALL,
-                        expr.span,
-                        "try not to call a closure in the expression where it is declared",
-                        |diag| {
-                            if fn_decl.inputs.is_empty() {
-                                let mut app = Applicability::MachineApplicable;
-                                let mut hint = Sugg::ast(cx, body, "..", closure.span.ctxt(), &mut app);
-
-                                if asyncness.is_async() {
-                                    // `async x` is a syntax error, so it becomes `async { x }`
-                                    if !matches!(body.kind, ast::ExprKind::Block(_, _)) {
-                                        hint = hint.blockify();
-                                    }
-
-                                    hint = hint.asyncify();
-                                }
-
-                                diag.span_suggestion(expr.span, "try doing something like", hint.to_string(), app);
+
+        if let hir::ExprKind::Call(recv, _) = expr.kind
+            // don't lint if the receiver is a call, too. 
+            // we do this in order to prevent linting multiple times; consider:
+            // `(|| || 1)()()`
+            //           ^^  we only want to lint for this call (but we walk up the calls to consider both calls).
+            // without this check, we'd end up linting twice.
+            && !matches!(recv.kind, hir::ExprKind::Call(..))
+            && let (full_expr, call_depth) = get_parent_call_exprs(cx, expr)
+            && let Some((body, fn_decl, generator_kind)) = find_innermost_closure(cx, recv, call_depth)
+        {
+            span_lint_and_then(
+                cx,
+                REDUNDANT_CLOSURE_CALL,
+                full_expr.span,
+                "try not to call a closure in the expression where it is declared",
+                |diag| {
+                    if fn_decl.inputs.is_empty() {
+                        let mut applicability = Applicability::MachineApplicable;
+                        let mut hint = Sugg::hir_with_context(cx, body, full_expr.span.ctxt(), "..", &mut applicability);
+
+                        if generator_kind.is_async()
+                            && let hir::ExprKind::Closure(closure) = body.kind
+                        {
+                            let async_closure_body = cx.tcx.hir().body(closure.body);
+
+                            // `async x` is a syntax error, so it becomes `async { x }`
+                            if !matches!(async_closure_body.value.kind, hir::ExprKind::Block(_, _)) {
+                                hint = hint.blockify();
                             }
-                        },
-                    );
+
+                            hint = hint.asyncify();
+                        }
+
+                        diag.span_suggestion(
+                            full_expr.span,
+                            "try doing something like",
+                            hint.maybe_par(),
+                            applicability
+                        );
+                    }
                 }
-            }
+            );
         }
     }
-}
 
-impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
         fn count_closure_usage<'tcx>(
             cx: &LateContext<'tcx>,
diff --git a/clippy_lints/src/redundant_type_annotations.rs b/clippy_lints/src/redundant_type_annotations.rs
new file mode 100644
index 00000000000..8e9234bba3c
--- /dev/null
+++ b/clippy_lints/src/redundant_type_annotations.rs
@@ -0,0 +1,210 @@
+use clippy_utils::diagnostics::span_lint;
+use rustc_ast::LitKind;
+use rustc_hir as hir;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::Ty;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Warns about needless / redundant type annotations.
+    ///
+    /// ### Why is this bad?
+    /// Code without type annotations is shorter and in most cases
+    /// more idiomatic and easier to modify.
+    ///
+    /// ### Limitations
+    /// This lint doesn't support:
+    ///
+    /// - Generics
+    /// - Refs returned from anything else than a `MethodCall`
+    /// - Complex types (tuples, arrays, etc...)
+    /// - `Path` to anything else than a primitive type.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let foo: String = String::new();
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// let foo = String::new();
+    /// ```
+    #[clippy::version = "1.70.0"]
+    pub REDUNDANT_TYPE_ANNOTATIONS,
+    restriction,
+    "warns about needless / redundant type annotations."
+}
+declare_lint_pass!(RedundantTypeAnnotations => [REDUNDANT_TYPE_ANNOTATIONS]);
+
+fn is_same_type<'tcx>(cx: &LateContext<'tcx>, ty_resolved_path: hir::def::Res, func_return_type: Ty<'tcx>) -> bool {
+    // type annotation is primitive
+    if let hir::def::Res::PrimTy(primty) = ty_resolved_path
+        && func_return_type.is_primitive()
+        && let Some(func_return_type_sym) = func_return_type.primitive_symbol()
+    {
+        return primty.name() == func_return_type_sym;
+    }
+
+    // type annotation is any other non generic type
+    if let hir::def::Res::Def(_, defid) = ty_resolved_path
+        && let Some(annotation_ty) = cx.tcx.type_of(defid).no_bound_vars()
+    {
+        return annotation_ty == func_return_type;
+    }
+
+    false
+}
+
+fn func_hir_id_to_func_ty<'tcx>(cx: &LateContext<'tcx>, hir_id: hir::hir_id::HirId) -> Option<Ty<'tcx>> {
+    if let Some((defkind, func_defid)) = cx.typeck_results().type_dependent_def(hir_id)
+        && defkind == hir::def::DefKind::AssocFn
+        && let Some(init_ty) = cx.tcx.type_of(func_defid).no_bound_vars()
+    {
+        Some(init_ty)
+    } else {
+        None
+    }
+}
+
+fn func_ty_to_return_type<'tcx>(cx: &LateContext<'tcx>, func_ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+    if func_ty.is_fn() {
+        Some(func_ty.fn_sig(cx.tcx).output().skip_binder())
+    } else {
+        None
+    }
+}
+
+/// Extracts the fn Ty, e.g. `fn() -> std::string::String {f}`
+fn extract_fn_ty<'tcx>(
+    cx: &LateContext<'tcx>,
+    call: &hir::Expr<'tcx>,
+    func_return_path: &hir::QPath<'tcx>,
+) -> Option<Ty<'tcx>> {
+    match func_return_path {
+        // let a: String = f(); where f: fn f() -> String
+        hir::QPath::Resolved(_, resolved_path) => {
+            if let hir::def::Res::Def(_, defid) = resolved_path.res
+                && let Some(middle_ty_init) = cx.tcx.type_of(defid).no_bound_vars()
+            {
+                Some(middle_ty_init)
+            } else {
+                None
+            }
+        },
+        // Associated functions like
+        // let a: String = String::new();
+        // let a: String = String::get_string();
+        hir::QPath::TypeRelative(..) => func_hir_id_to_func_ty(cx, call.hir_id),
+        hir::QPath::LangItem(..) => None,
+    }
+}
+
+fn is_redundant_in_func_call<'tcx>(
+    cx: &LateContext<'tcx>,
+    ty_resolved_path: hir::def::Res,
+    call: &hir::Expr<'tcx>,
+) -> bool {
+    if let hir::ExprKind::Path(init_path) = &call.kind {
+        let func_type = extract_fn_ty(cx, call, init_path);
+
+        if let Some(func_type) = func_type
+            && let Some(init_return_type) = func_ty_to_return_type(cx, func_type)
+        {
+            return is_same_type(cx, ty_resolved_path, init_return_type);
+        }
+    }
+
+    false
+}
+
+fn extract_primty(ty_kind: &hir::TyKind<'_>) -> Option<hir::PrimTy> {
+    if let hir::TyKind::Path(ty_path) = ty_kind
+        && let hir::QPath::Resolved(_, resolved_path_ty) = ty_path
+        && let hir::def::Res::PrimTy(primty) = resolved_path_ty.res
+    {
+        Some(primty)
+    } else {
+        None
+    }
+}
+
+impl LateLintPass<'_> for RedundantTypeAnnotations {
+    fn check_local<'tcx>(&mut self, cx: &LateContext<'tcx>, local: &'tcx rustc_hir::Local<'tcx>) {
+        // type annotation part
+        if !local.span.from_expansion()
+            && let Some(ty) = &local.ty
+
+            // initialization part
+            && let Some(init) = local.init
+        {
+            match &init.kind {
+                // When the initialization is a call to a function
+                hir::ExprKind::Call(init_call, _) => {
+                    if let hir::TyKind::Path(ty_path) = &ty.kind
+                        && let hir::QPath::Resolved(_, resolved_path_ty) = ty_path
+
+                        && is_redundant_in_func_call(cx, resolved_path_ty.res, init_call) {
+                        span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation");
+                    }
+                },
+                hir::ExprKind::MethodCall(_, _, _, _) => {
+                    let mut is_ref = false;
+                    let mut ty_kind = &ty.kind;
+
+                    // If the annotation is a ref we "peel" it
+                    if let hir::TyKind::Ref(_, mut_ty) = &ty.kind {
+                        is_ref = true;
+                        ty_kind = &mut_ty.ty.kind;
+                    }
+
+                    if let hir::TyKind::Path(ty_path) = ty_kind
+                        && let hir::QPath::Resolved(_, resolved_path_ty) = ty_path
+                        && let Some(func_ty) = func_hir_id_to_func_ty(cx, init.hir_id)
+                        && let Some(return_type) = func_ty_to_return_type(cx, func_ty)
+                        && is_same_type(cx, resolved_path_ty.res, if is_ref {
+                            return_type.peel_refs()
+                        } else {
+                            return_type
+                        })
+                    {
+                        span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation");
+                    }
+                },
+                // When the initialization is a path for example u32::MAX
+                hir::ExprKind::Path(init_path) => {
+                    // TODO: check for non primty
+                    if let Some(primty) = extract_primty(&ty.kind)
+
+                        && let hir::QPath::TypeRelative(init_ty, _) = init_path
+                        && let Some(primty_init) = extract_primty(&init_ty.kind)
+
+                        && primty == primty_init
+                    {
+                        span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation");
+                    }
+                },
+                hir::ExprKind::Lit(init_lit) => {
+                    match init_lit.node {
+                        // In these cases the annotation is redundant
+                        LitKind::Str(..)
+                        | LitKind::ByteStr(..)
+                        | LitKind::Byte(..)
+                        | LitKind::Char(..)
+                        | LitKind::Bool(..)
+                        | LitKind::CStr(..) => {
+                            span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation");
+                        },
+                        LitKind::Int(..) | LitKind::Float(..) => {
+                            // If the initialization value is a suffixed literal we lint
+                            if init_lit.node.is_suffixed() {
+                                span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation");
+                            }
+                        },
+                        LitKind::Err => (),
+                    }
+                }
+                _ => ()
+            }
+        };
+    }
+}
diff --git a/clippy_lints/src/returns.rs b/clippy_lints/src/returns.rs
index 631ecf1428d..958351ad81b 100644
--- a/clippy_lints/src/returns.rs
+++ b/clippy_lints/src/returns.rs
@@ -25,6 +25,12 @@ declare_clippy_lint! {
     /// It is just extraneous code. Remove it to make your code
     /// more rusty.
     ///
+    /// ### Known problems
+    /// In the case of some temporaries, e.g. locks, eliding the variable binding could lead
+    /// to deadlocks. See [this issue](https://github.com/rust-lang/rust/issues/37612).
+    /// This could become relevant if the code is later changed to use the code that would have been
+    /// bound without first assigning it to a let-binding.
+    ///
     /// ### Example
     /// ```rust
     /// fn foo() -> String {
@@ -286,7 +292,7 @@ fn check_final_expr<'tcx>(
         // (except for unit type functions) so we don't match it
         ExprKind::Match(_, arms, MatchSource::Normal) => {
             let match_ty = cx.typeck_results().expr_ty(peeled_drop_expr);
-            for arm in arms.iter() {
+            for arm in *arms {
                 check_final_expr(cx, arm.body, semi_spans.clone(), RetReplacement::Unit, Some(match_ty));
             }
         },
diff --git a/clippy_lints/src/significant_drop_tightening.rs b/clippy_lints/src/significant_drop_tightening.rs
index b930b2c8dd7..fffa8a380c2 100644
--- a/clippy_lints/src/significant_drop_tightening.rs
+++ b/clippy_lints/src/significant_drop_tightening.rs
@@ -1,10 +1,10 @@
 use clippy_utils::{
     diagnostics::span_lint_and_then,
-    get_attr,
+    expr_or_init, get_attr, path_to_local,
     source::{indent_of, snippet},
 };
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{Applicability, Diagnostic};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
+use rustc_errors::Applicability;
 use rustc_hir::{
     self as hir,
     intravisit::{walk_expr, Visitor},
@@ -13,6 +13,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::{subst::GenericArgKind, Ty, TypeAndMut};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{symbol::Ident, Span, DUMMY_SP};
+use std::borrow::Cow;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -56,255 +57,102 @@ impl_lint_pass!(SignificantDropTightening<'_> => [SIGNIFICANT_DROP_TIGHTENING]);
 
 #[derive(Default)]
 pub struct SignificantDropTightening<'tcx> {
+    apas: FxIndexMap<hir::HirId, AuxParamsAttr>,
     /// Auxiliary structure used to avoid having to verify the same type multiple times.
     seen_types: FxHashSet<Ty<'tcx>>,
     type_cache: FxHashMap<Ty<'tcx>, bool>,
 }
 
-impl<'tcx> SignificantDropTightening<'tcx> {
-    /// Unifies the statements of a block with its return expression.
-    fn all_block_stmts<'ret, 'rslt, 'stmts>(
-        block_stmts: &'stmts [hir::Stmt<'tcx>],
-        dummy_ret_stmt: Option<&'ret hir::Stmt<'tcx>>,
-    ) -> impl Iterator<Item = &'rslt hir::Stmt<'tcx>>
-    where
-        'ret: 'rslt,
-        'stmts: 'rslt,
-    {
-        block_stmts.iter().chain(dummy_ret_stmt)
-    }
-
-    /// Searches for at least one statement that could slow down the release of a significant drop.
-    fn at_least_one_stmt_is_expensive<'stmt>(stmts: impl Iterator<Item = &'stmt hir::Stmt<'tcx>>) -> bool
-    where
-        'tcx: 'stmt,
-    {
-        for stmt in stmts {
-            match stmt.kind {
-                hir::StmtKind::Expr(expr) if let hir::ExprKind::Path(_) = expr.kind => {}
-                hir::StmtKind::Local(local) if let Some(expr) = local.init
-                    && let hir::ExprKind::Path(_) = expr.kind => {},
-                _ => return true
-            };
-        }
-        false
-    }
-
-    /// Verifies if the expression is of type `drop(some_lock_path)` to assert that the temporary
-    /// is already being dropped before the end of its scope.
-    fn has_drop(expr: &'tcx hir::Expr<'_>, init_bind_ident: Ident) -> bool {
-        if let hir::ExprKind::Call(fun, args) = expr.kind
-            && let hir::ExprKind::Path(hir::QPath::Resolved(_, fun_path)) = &fun.kind
-            && let [fun_ident, ..] = fun_path.segments
-            && fun_ident.ident.name == rustc_span::sym::drop
-            && let [first_arg, ..] = args
-            && let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &first_arg.kind
-            && let [first_arg_ps, .. ] = arg_path.segments
-        {
-            first_arg_ps.ident == init_bind_ident
-        }
-        else {
-            false
-        }
-    }
-
-    /// Tries to find types marked with `#[has_significant_drop]` of an expression `expr` that is
-    /// originated from `stmt` and then performs common logic on `sdap`.
-    fn modify_sdap_if_sig_drop_exists(
+impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> {
+    fn check_fn(
         &mut self,
         cx: &LateContext<'tcx>,
-        expr: &'tcx hir::Expr<'_>,
-        idx: usize,
-        sdap: &mut SigDropAuxParams,
-        stmt: &hir::Stmt<'_>,
-        cb: impl Fn(&mut SigDropAuxParams),
+        _: hir::intravisit::FnKind<'_>,
+        _: &hir::FnDecl<'_>,
+        body: &'tcx hir::Body<'_>,
+        _: Span,
+        _: hir::def_id::LocalDefId,
     ) {
-        let mut sig_drop_finder = SigDropFinder::new(cx, &mut self.seen_types, &mut self.type_cache);
-        sig_drop_finder.visit_expr(expr);
-        if sig_drop_finder.has_sig_drop {
-            cb(sdap);
-            if sdap.number_of_stmts > 0 {
-                sdap.last_use_stmt_idx = idx;
-                sdap.last_use_stmt_span = stmt.span;
-                if let hir::ExprKind::MethodCall(_, _, _, span) = expr.kind {
-                    sdap.last_use_method_span = span;
-                }
+        self.apas.clear();
+        let initial_dummy_stmt = dummy_stmt_expr(body.value);
+        let mut ap = AuxParams::new(&mut self.apas, &initial_dummy_stmt);
+        StmtsChecker::new(&mut ap, cx, &mut self.seen_types, &mut self.type_cache).visit_body(body);
+        for apa in ap.apas.values() {
+            if apa.counter <= 1 || !apa.has_expensive_expr_after_last_attr {
+                continue;
             }
-            sdap.number_of_stmts = sdap.number_of_stmts.wrapping_add(1);
-        }
-    }
-
-    /// Shows generic overall messages as well as specialized messages depending on the usage.
-    fn set_suggestions(cx: &LateContext<'tcx>, block_span: Span, diag: &mut Diagnostic, sdap: &SigDropAuxParams) {
-        match sdap.number_of_stmts {
-            0 | 1 => {},
-            2 => {
-                let indent = " ".repeat(indent_of(cx, sdap.last_use_stmt_span).unwrap_or(0));
-                let init_method = snippet(cx, sdap.init_method_span, "..");
-                let usage_method = snippet(cx, sdap.last_use_method_span, "..");
-                let stmt = if let Some(last_use_bind_span) = sdap.last_use_bind_span {
-                    format!(
-                        "\n{indent}let {} = {init_method}.{usage_method};",
-                        snippet(cx, last_use_bind_span, ".."),
-                    )
-                } else {
-                    format!("\n{indent}{init_method}.{usage_method};")
-                };
-                diag.span_suggestion_verbose(
-                    sdap.init_stmt_span,
-                    "merge the temporary construction with its single usage",
-                    stmt,
-                    Applicability::MaybeIncorrect,
-                );
-                diag.span_suggestion(
-                    sdap.last_use_stmt_span,
-                    "remove separated single usage",
-                    "",
-                    Applicability::MaybeIncorrect,
-                );
-            },
-            _ => {
-                diag.span_suggestion(
-                    sdap.last_use_stmt_span.shrink_to_hi(),
-                    "drop the temporary after the end of its last usage",
-                    format!(
-                        "\n{}drop({});",
-                        " ".repeat(indent_of(cx, sdap.last_use_stmt_span).unwrap_or(0)),
-                        sdap.init_bind_ident
-                    ),
-                    Applicability::MaybeIncorrect,
-                );
-            },
-        }
-        diag.note("this might lead to unnecessary resource contention");
-        diag.span_label(
-            block_span,
-            format!(
-                "temporary `{}` is currently being dropped at the end of its contained scope",
-                sdap.init_bind_ident
-            ),
-        );
-    }
-}
-
-impl<'tcx> LateLintPass<'tcx> for SignificantDropTightening<'tcx> {
-    fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
-        let dummy_ret_stmt = block.expr.map(|expr| hir::Stmt {
-            hir_id: hir::HirId::INVALID,
-            kind: hir::StmtKind::Expr(expr),
-            span: DUMMY_SP,
-        });
-        let mut sdap = SigDropAuxParams::default();
-        for (idx, stmt) in Self::all_block_stmts(block.stmts, dummy_ret_stmt.as_ref()).enumerate() {
-            match stmt.kind {
-                hir::StmtKind::Expr(expr) => self.modify_sdap_if_sig_drop_exists(
-                    cx,
-                    expr,
-                    idx,
-                    &mut sdap,
-                    stmt,
-                    |_| {}
-                ),
-                hir::StmtKind::Local(local) if let Some(expr) = local.init => self.modify_sdap_if_sig_drop_exists(
-                    cx,
-                    expr,
-                    idx,
-                    &mut sdap,
-                    stmt,
-                    |local_sdap| {
-                        if local_sdap.number_of_stmts == 0 {
-                            if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind {
-                                local_sdap.init_bind_ident = ident;
-                            }
-                            if let hir::ExprKind::MethodCall(_, local_expr, _, span) = expr.kind {
-                                local_sdap.init_method_span = local_expr.span.to(span);
-                            }
-                            local_sdap.init_stmt_span = stmt.span;
-                        }
-                        else if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind {
-                            local_sdap.last_use_bind_span = Some(ident.span);
-                        }
-                    }
-                ),
-                hir::StmtKind::Semi(expr) => {
-                    if Self::has_drop(expr, sdap.init_bind_ident) {
-                        return;
-                    }
-                    self.modify_sdap_if_sig_drop_exists(cx, expr, idx, &mut sdap, stmt, |_| {});
-                },
-                _ => {}
-            };
-        }
-
-        let idx = sdap.last_use_stmt_idx.wrapping_add(1);
-        let stmts_after_last_use = Self::all_block_stmts(block.stmts, dummy_ret_stmt.as_ref()).skip(idx);
-        if sdap.number_of_stmts > 1 && Self::at_least_one_stmt_is_expensive(stmts_after_last_use) {
             span_lint_and_then(
                 cx,
                 SIGNIFICANT_DROP_TIGHTENING,
-                sdap.init_bind_ident.span,
+                apa.first_bind_ident.span,
                 "temporary with significant `Drop` can be early dropped",
                 |diag| {
-                    Self::set_suggestions(cx, block.span, diag, &sdap);
+                    match apa.counter {
+                        0 | 1 => {},
+                        2 => {
+                            let indent = " ".repeat(indent_of(cx, apa.last_stmt_span).unwrap_or(0));
+                            let init_method = snippet(cx, apa.first_method_span, "..");
+                            let usage_method = snippet(cx, apa.last_method_span, "..");
+                            let stmt = if apa.last_bind_ident == Ident::empty() {
+                                format!("\n{indent}{init_method}.{usage_method};")
+                            } else {
+                                format!(
+                                    "\n{indent}let {} = {init_method}.{usage_method};",
+                                    snippet(cx, apa.last_bind_ident.span, ".."),
+                                )
+                            };
+                            diag.span_suggestion_verbose(
+                                apa.first_stmt_span,
+                                "merge the temporary construction with its single usage",
+                                stmt,
+                                Applicability::MaybeIncorrect,
+                            );
+                            diag.span_suggestion(
+                                apa.last_stmt_span,
+                                "remove separated single usage",
+                                "",
+                                Applicability::MaybeIncorrect,
+                            );
+                        },
+                        _ => {
+                            diag.span_suggestion(
+                                apa.last_stmt_span.shrink_to_hi(),
+                                "drop the temporary after the end of its last usage",
+                                format!(
+                                    "\n{}drop({});",
+                                    " ".repeat(indent_of(cx, apa.last_stmt_span).unwrap_or(0)),
+                                    apa.first_bind_ident
+                                ),
+                                Applicability::MaybeIncorrect,
+                            );
+                        },
+                    }
+                    diag.note("this might lead to unnecessary resource contention");
+                    diag.span_label(
+                        apa.first_block_span,
+                        format!(
+                            "temporary `{}` is currently being dropped at the end of its contained scope",
+                            apa.first_bind_ident
+                        ),
+                    );
                 },
             );
         }
     }
 }
 
-/// Auxiliary parameters used on each block check.
-struct SigDropAuxParams {
-    /// The binding or variable that references the initial construction of the type marked with
-    /// `#[has_significant_drop]`.
-    init_bind_ident: Ident,
-    /// Similar to `init_bind_ident` but encompasses the right-hand method call.
-    init_method_span: Span,
-    /// Similar to `init_bind_ident` but encompasses the whole contained statement.
-    init_stmt_span: Span,
-
-    /// The last visited binding or variable span within a block that had any referenced inner type
-    /// marked with `#[has_significant_drop]`.
-    last_use_bind_span: Option<Span>,
-    /// Index of the last visited statement within a block that had any referenced inner type
-    /// marked with `#[has_significant_drop]`.
-    last_use_stmt_idx: usize,
-    /// Similar to `last_use_bind_span` but encompasses the whole contained statement.
-    last_use_stmt_span: Span,
-    /// Similar to `last_use_bind_span` but encompasses the right-hand method call.
-    last_use_method_span: Span,
-
-    /// Total number of statements within a block that have any referenced inner type marked with
-    /// `#[has_significant_drop]`.
-    number_of_stmts: usize,
-}
-
-impl Default for SigDropAuxParams {
-    fn default() -> Self {
-        Self {
-            init_bind_ident: Ident::empty(),
-            init_method_span: DUMMY_SP,
-            init_stmt_span: DUMMY_SP,
-            last_use_bind_span: None,
-            last_use_method_span: DUMMY_SP,
-            last_use_stmt_idx: 0,
-            last_use_stmt_span: DUMMY_SP,
-            number_of_stmts: 0,
-        }
-    }
-}
-
-/// Checks the existence of the `#[has_significant_drop]` attribute
-struct SigDropChecker<'cx, 'sdt, 'tcx> {
+/// Checks the existence of the `#[has_significant_drop]` attribute.
+struct AttrChecker<'cx, 'others, 'tcx> {
     cx: &'cx LateContext<'tcx>,
-    seen_types: &'sdt mut FxHashSet<Ty<'tcx>>,
-    type_cache: &'sdt mut FxHashMap<Ty<'tcx>, bool>,
+    seen_types: &'others mut FxHashSet<Ty<'tcx>>,
+    type_cache: &'others mut FxHashMap<Ty<'tcx>, bool>,
 }
 
-impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> {
+impl<'cx, 'others, 'tcx> AttrChecker<'cx, 'others, 'tcx> {
     pub(crate) fn new(
         cx: &'cx LateContext<'tcx>,
-        seen_types: &'sdt mut FxHashSet<Ty<'tcx>>,
-        type_cache: &'sdt mut FxHashMap<Ty<'tcx>, bool>,
+        seen_types: &'others mut FxHashSet<Ty<'tcx>>,
+        type_cache: &'others mut FxHashMap<Ty<'tcx>, bool>,
     ) -> Self {
         seen_types.clear();
         Self {
@@ -314,7 +162,17 @@ impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> {
         }
     }
 
-    pub(crate) fn has_sig_drop_attr_uncached(&mut self, ty: Ty<'tcx>) -> bool {
+    fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool {
+        // The borrow checker prevents us from using something fancier like or_insert_with.
+        if let Some(ty) = self.type_cache.get(&ty) {
+            return *ty;
+        }
+        let value = self.has_sig_drop_attr_uncached(ty);
+        self.type_cache.insert(ty, value);
+        value
+    }
+
+    fn has_sig_drop_attr_uncached(&mut self, ty: Ty<'tcx>) -> bool {
         if let Some(adt) = ty.ty_adt_def() {
             let mut iter = get_attr(
                 self.cx.sess(),
@@ -333,7 +191,7 @@ impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> {
                         return true;
                     }
                 }
-                for generic_arg in b.iter() {
+                for generic_arg in *b {
                     if let GenericArgKind::Type(ty) = generic_arg.unpack() {
                         if self.has_sig_drop_attr(ty) {
                             return true;
@@ -350,73 +208,244 @@ impl<'cx, 'sdt, 'tcx> SigDropChecker<'cx, 'sdt, 'tcx> {
         }
     }
 
-    pub(crate) fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool {
-        // The borrow checker prevents us from using something fancier like or_insert_with.
-        if let Some(ty) = self.type_cache.get(&ty) {
-            return *ty;
-        }
-        let value = self.has_sig_drop_attr_uncached(ty);
-        self.type_cache.insert(ty, value);
-        value
-    }
-
     fn has_seen_ty(&mut self, ty: Ty<'tcx>) -> bool {
         !self.seen_types.insert(ty)
     }
 }
 
-/// Performs recursive calls to find any inner type marked with `#[has_significant_drop]`.
-struct SigDropFinder<'cx, 'sdt, 'tcx> {
-    cx: &'cx LateContext<'tcx>,
-    has_sig_drop: bool,
-    sig_drop_checker: SigDropChecker<'cx, 'sdt, 'tcx>,
+struct StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx> {
+    ap: &'ap mut AuxParams<'others, 'stmt, 'tcx>,
+    cx: &'lc LateContext<'tcx>,
+    seen_types: &'others mut FxHashSet<Ty<'tcx>>,
+    type_cache: &'others mut FxHashMap<Ty<'tcx>, bool>,
 }
 
-impl<'cx, 'sdt, 'tcx> SigDropFinder<'cx, 'sdt, 'tcx> {
+impl<'ap, 'lc, 'others, 'stmt, 'tcx> StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx> {
     fn new(
-        cx: &'cx LateContext<'tcx>,
-        seen_types: &'sdt mut FxHashSet<Ty<'tcx>>,
-        type_cache: &'sdt mut FxHashMap<Ty<'tcx>, bool>,
+        ap: &'ap mut AuxParams<'others, 'stmt, 'tcx>,
+        cx: &'lc LateContext<'tcx>,
+        seen_types: &'others mut FxHashSet<Ty<'tcx>>,
+        type_cache: &'others mut FxHashMap<Ty<'tcx>, bool>,
     ) -> Self {
         Self {
+            ap,
             cx,
-            has_sig_drop: false,
-            sig_drop_checker: SigDropChecker::new(cx, seen_types, type_cache),
+            seen_types,
+            type_cache,
+        }
+    }
+
+    fn manage_has_expensive_expr_after_last_attr(&mut self) {
+        let has_expensive_stmt = match self.ap.curr_stmt.kind {
+            hir::StmtKind::Expr(expr) if !is_expensive_expr(expr) => false,
+            hir::StmtKind::Local(local) if let Some(expr) = local.init
+                && let hir::ExprKind::Path(_) = expr.kind => false,
+            _ => true
+        };
+        if has_expensive_stmt {
+            for apa in self.ap.apas.values_mut() {
+                let last_stmt_is_not_dummy = apa.last_stmt_span != DUMMY_SP;
+                let last_stmt_is_not_curr = self.ap.curr_stmt.span != apa.last_stmt_span;
+                let block_equals_curr = self.ap.curr_block_hir_id == apa.first_block_hir_id;
+                let block_is_ancestor = self
+                    .cx
+                    .tcx
+                    .hir()
+                    .parent_iter(self.ap.curr_block_hir_id)
+                    .any(|(id, _)| id == apa.first_block_hir_id);
+                if last_stmt_is_not_dummy && last_stmt_is_not_curr && (block_equals_curr || block_is_ancestor) {
+                    apa.has_expensive_expr_after_last_attr = true;
+                }
+            }
         }
     }
 }
 
-impl<'cx, 'sdt, 'tcx> Visitor<'tcx> for SigDropFinder<'cx, 'sdt, 'tcx> {
-    fn visit_expr(&mut self, ex: &'tcx hir::Expr<'_>) {
-        if self
-            .sig_drop_checker
-            .has_sig_drop_attr(self.cx.typeck_results().expr_ty(ex))
-        {
-            self.has_sig_drop = true;
-            return;
+impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx> {
+    fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) {
+        self.ap.curr_block_hir_id = block.hir_id;
+        self.ap.curr_block_span = block.span;
+        for stmt in block.stmts {
+            self.ap.curr_stmt = Cow::Borrowed(stmt);
+            self.visit_stmt(stmt);
+            self.ap.curr_block_hir_id = block.hir_id;
+            self.ap.curr_block_span = block.span;
+            self.manage_has_expensive_expr_after_last_attr();
+        }
+        if let Some(expr) = block.expr {
+            self.ap.curr_stmt = Cow::Owned(dummy_stmt_expr(expr));
+            self.visit_expr(expr);
+            self.ap.curr_block_hir_id = block.hir_id;
+            self.ap.curr_block_span = block.span;
+            self.manage_has_expensive_expr_after_last_attr();
         }
+    }
 
-        match ex.kind {
-            hir::ExprKind::MethodCall(_, expr, ..) => {
-                self.visit_expr(expr);
-            },
-            hir::ExprKind::Array(..)
-            | hir::ExprKind::Assign(..)
-            | hir::ExprKind::AssignOp(..)
-            | hir::ExprKind::Binary(..)
-            | hir::ExprKind::Call(..)
-            | hir::ExprKind::Field(..)
-            | hir::ExprKind::If(..)
-            | hir::ExprKind::Index(..)
-            | hir::ExprKind::Match(..)
-            | hir::ExprKind::Repeat(..)
-            | hir::ExprKind::Ret(..)
-            | hir::ExprKind::Tup(..)
-            | hir::ExprKind::Unary(..)
-            | hir::ExprKind::Yield(..) => {
-                walk_expr(self, ex);
-            },
-            _ => {},
+    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
+        let modify_apa_params = |apa: &mut AuxParamsAttr| {
+            apa.counter = apa.counter.wrapping_add(1);
+            apa.has_expensive_expr_after_last_attr = false;
+        };
+        let mut ac = AttrChecker::new(self.cx, self.seen_types, self.type_cache);
+        if ac.has_sig_drop_attr(self.cx.typeck_results().expr_ty(expr)) {
+            if let hir::StmtKind::Local(local) = self.ap.curr_stmt.kind
+                && let hir::PatKind::Binding(_, hir_id, ident, _) = local.pat.kind
+                && !self.ap.apas.contains_key(&hir_id)
+                && {
+                    if let Some(local_hir_id) = path_to_local(expr) {
+                        local_hir_id == hir_id
+                    }
+                    else {
+                        true
+                    }
+                }
+            {
+                let mut apa = AuxParamsAttr {
+                    first_bind_ident: ident,
+                    first_block_hir_id: self.ap.curr_block_hir_id,
+                    first_block_span: self.ap.curr_block_span,
+                    first_method_span: {
+                        let expr_or_init = expr_or_init(self.cx, expr);
+                        if let hir::ExprKind::MethodCall(_, local_expr, _, span) = expr_or_init.kind {
+                            local_expr.span.to(span)
+                        }
+                        else {
+                            expr_or_init.span
+                        }
+                    },
+                    first_stmt_span: self.ap.curr_stmt.span,
+                    ..Default::default()
+                };
+                modify_apa_params(&mut apa);
+                let _ = self.ap.apas.insert(hir_id, apa);
+            } else {
+                let Some(hir_id) = path_to_local(expr) else { return; };
+                let Some(apa) = self.ap.apas.get_mut(&hir_id) else { return; };
+                match self.ap.curr_stmt.kind {
+                    hir::StmtKind::Local(local) => {
+                        if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind {
+                            apa.last_bind_ident = ident;
+                        }
+                        if let Some(local_init) = local.init
+                            && let hir::ExprKind::MethodCall(_, _, _, span) = local_init.kind
+                        {
+                            apa.last_method_span = span;
+                        }
+                    },
+                    hir::StmtKind::Semi(expr) => {
+                        if has_drop(expr, &apa.first_bind_ident) {
+                            apa.has_expensive_expr_after_last_attr = false;
+                            apa.last_stmt_span = DUMMY_SP;
+                            return;
+                        }
+                        if let hir::ExprKind::MethodCall(_, _, _, span) = expr.kind {
+                            apa.last_method_span = span;
+                        }
+                    },
+                    _ => {},
+                }
+                apa.last_stmt_span = self.ap.curr_stmt.span;
+                modify_apa_params(apa);
+            }
+        }
+        walk_expr(self, expr);
+    }
+}
+
+/// Auxiliary parameters used on each block check of an item
+struct AuxParams<'others, 'stmt, 'tcx> {
+    //// See [AuxParamsAttr].
+    apas: &'others mut FxIndexMap<hir::HirId, AuxParamsAttr>,
+    /// The current block identifier that is being visited.
+    curr_block_hir_id: hir::HirId,
+    /// The current block span that is being visited.
+    curr_block_span: Span,
+    /// The current statement that is being visited.
+    curr_stmt: Cow<'stmt, hir::Stmt<'tcx>>,
+}
+
+impl<'others, 'stmt, 'tcx> AuxParams<'others, 'stmt, 'tcx> {
+    fn new(apas: &'others mut FxIndexMap<hir::HirId, AuxParamsAttr>, curr_stmt: &'stmt hir::Stmt<'tcx>) -> Self {
+        Self {
+            apas,
+            curr_block_hir_id: hir::HirId::INVALID,
+            curr_block_span: DUMMY_SP,
+            curr_stmt: Cow::Borrowed(curr_stmt),
+        }
+    }
+}
+
+/// Auxiliary parameters used on expression created with `#[has_significant_drop]`.
+#[derive(Debug)]
+struct AuxParamsAttr {
+    /// The number of times `#[has_significant_drop]` was referenced.
+    counter: usize,
+    /// If an expensive expression follows the last use of anything marked with
+    /// `#[has_significant_drop]`.
+    has_expensive_expr_after_last_attr: bool,
+
+    /// The identifier of the block that involves the first `#[has_significant_drop]`.
+    first_block_hir_id: hir::HirId,
+    /// The span of the block that involves the first `#[has_significant_drop]`.
+    first_block_span: Span,
+    /// The binding or variable that references the initial construction of the type marked with
+    /// `#[has_significant_drop]`.
+    first_bind_ident: Ident,
+    /// Similar to `init_bind_ident` but encompasses the right-hand method call.
+    first_method_span: Span,
+    /// Similar to `init_bind_ident` but encompasses the whole contained statement.
+    first_stmt_span: Span,
+
+    /// The last visited binding or variable span within a block that had any referenced inner type
+    /// marked with `#[has_significant_drop]`.
+    last_bind_ident: Ident,
+    /// Similar to `last_bind_span` but encompasses the right-hand method call.
+    last_method_span: Span,
+    /// Similar to `last_bind_span` but encompasses the whole contained statement.
+    last_stmt_span: Span,
+}
+
+impl Default for AuxParamsAttr {
+    fn default() -> Self {
+        Self {
+            counter: 0,
+            has_expensive_expr_after_last_attr: false,
+            first_block_hir_id: hir::HirId::INVALID,
+            first_bind_ident: Ident::empty(),
+            first_block_span: DUMMY_SP,
+            first_method_span: DUMMY_SP,
+            first_stmt_span: DUMMY_SP,
+            last_bind_ident: Ident::empty(),
+            last_method_span: DUMMY_SP,
+            last_stmt_span: DUMMY_SP,
         }
     }
 }
+
+fn dummy_stmt_expr<'any>(expr: &'any hir::Expr<'any>) -> hir::Stmt<'any> {
+    hir::Stmt {
+        hir_id: hir::HirId::INVALID,
+        kind: hir::StmtKind::Expr(expr),
+        span: DUMMY_SP,
+    }
+}
+
+fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Ident) -> bool {
+    if let hir::ExprKind::Call(fun, args) = expr.kind
+        && let hir::ExprKind::Path(hir::QPath::Resolved(_, fun_path)) = &fun.kind
+        && let [fun_ident, ..] = fun_path.segments
+        && fun_ident.ident.name == rustc_span::sym::drop
+        && let [first_arg, ..] = args
+        && let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &first_arg.kind
+        && let [first_arg_ps, .. ] = arg_path.segments
+    {
+        &first_arg_ps.ident == first_bind_ident
+    }
+    else {
+        false
+    }
+}
+
+fn is_expensive_expr(expr: &hir::Expr<'_>) -> bool {
+    !matches!(expr.kind, hir::ExprKind::Path(_))
+}
diff --git a/clippy_lints/src/single_call_fn.rs b/clippy_lints/src/single_call_fn.rs
new file mode 100644
index 00000000000..42753d2e951
--- /dev/null
+++ b/clippy_lints/src/single_call_fn.rs
@@ -0,0 +1,133 @@
+use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::{is_from_proc_macro, is_in_test_function};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::{walk_expr, Visitor};
+use rustc_hir::{intravisit::FnKind, Body, Expr, ExprKind, FnDecl};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::hir::nested_filter::OnlyBodies;
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::Span;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for functions that are only used once. Does not lint tests.
+    ///
+    /// ### Why is this bad?
+    /// It's usually not, splitting a function into multiple parts often improves readability and in
+    /// the case of generics, can prevent the compiler from duplicating the function dozens of
+    /// time; instead, only duplicating a thunk. But this can prevent segmentation across a
+    /// codebase, where many small functions are used only once.
+    ///
+    /// Note: If this lint is used, prepare to allow this a lot.
+    ///
+    /// ### Example
+    /// ```rust
+    /// pub fn a<T>(t: &T)
+    /// where
+    ///     T: AsRef<str>,
+    /// {
+    ///     a_inner(t.as_ref())
+    /// }
+    ///
+    /// fn a_inner(t: &str) {
+    ///     /* snip */
+    /// }
+    ///
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// pub fn a<T>(t: &T)
+    /// where
+    ///     T: AsRef<str>,
+    /// {
+    ///     let t = t.as_ref();
+    ///     /* snip */
+    /// }
+    ///
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub SINGLE_CALL_FN,
+    restriction,
+    "checks for functions that are only used once"
+}
+impl_lint_pass!(SingleCallFn => [SINGLE_CALL_FN]);
+
+#[derive(Clone)]
+pub struct SingleCallFn {
+    pub avoid_breaking_exported_api: bool,
+    pub def_id_to_usage: FxHashMap<LocalDefId, (Span, Vec<Span>)>,
+}
+
+impl<'tcx> LateLintPass<'tcx> for SingleCallFn {
+    fn check_fn(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        kind: FnKind<'tcx>,
+        _: &'tcx FnDecl<'_>,
+        body: &'tcx Body<'_>,
+        span: Span,
+        def_id: LocalDefId,
+    ) {
+        if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id)
+            || in_external_macro(cx.sess(), span)
+            || is_from_proc_macro(cx, &(&kind, body, cx.tcx.local_def_id_to_hir_id(def_id), span))
+            || is_in_test_function(cx.tcx, body.value.hir_id)
+        {
+            return;
+        }
+
+        self.def_id_to_usage.insert(def_id, (span, vec![]));
+    }
+
+    fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
+        let mut v = FnUsageVisitor {
+            cx,
+            def_id_to_usage: &mut self.def_id_to_usage,
+        };
+        cx.tcx.hir().visit_all_item_likes_in_crate(&mut v);
+
+        for usage in self.def_id_to_usage.values() {
+            let single_call_fn_span = usage.0;
+            if let [caller_span] = *usage.1 {
+                span_lint_and_help(
+                    cx,
+                    SINGLE_CALL_FN,
+                    single_call_fn_span,
+                    "this function is only used once",
+                    Some(caller_span),
+                    "used here",
+                );
+            }
+        }
+    }
+}
+
+struct FnUsageVisitor<'a, 'tcx> {
+    cx: &'a LateContext<'tcx>,
+    def_id_to_usage: &'a mut FxHashMap<LocalDefId, (Span, Vec<Span>)>,
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for FnUsageVisitor<'a, 'tcx> {
+    type NestedFilter = OnlyBodies;
+
+    fn nested_visit_map(&mut self) -> Self::Map {
+        self.cx.tcx.hir()
+    }
+
+    fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
+        let Self { cx, .. } = *self;
+
+        if let ExprKind::Path(qpath) = expr.kind
+            && let res = cx.qpath_res(&qpath, expr.hir_id)
+            && let Some(call_def_id) = res.opt_def_id()
+            && let Some(def_id) = call_def_id.as_local()
+            && let Some(usage) = self.def_id_to_usage.get_mut(&def_id)
+        {
+            usage.1.push(expr.span);
+        }
+
+        walk_expr(self, expr);
+    }
+}
diff --git a/clippy_lints/src/single_range_in_vec_init.rs b/clippy_lints/src/single_range_in_vec_init.rs
new file mode 100644
index 00000000000..dfe8be7a6a6
--- /dev/null
+++ b/clippy_lints/src/single_range_in_vec_init.rs
@@ -0,0 +1,147 @@
+use clippy_utils::{
+    diagnostics::span_lint_and_then, get_trait_def_id, higher::VecArgs, macros::root_macro_call_first_node,
+    source::snippet_opt, ty::implements_trait,
+};
+use rustc_ast::{LitIntType, LitKind, UintTy};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, LangItem, QPath};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use std::fmt::{self, Display, Formatter};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for `Vec` or array initializations that contain only one range.
+    ///
+    /// ### Why is this bad?
+    /// This is almost always incorrect, as it will result in a `Vec` that has only one element.
+    /// Almost always, the programmer intended for it to include all elements in the range or for
+    /// the end of the range to be the length instead.
+    ///
+    /// ### Example
+    /// ```rust
+    /// let x = [0..200];
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// // If it was intended to include every element in the range...
+    /// let x = (0..200).collect::<Vec<i32>>();
+    /// // ...Or if 200 was meant to be the len
+    /// let x = [0; 200];
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub SINGLE_RANGE_IN_VEC_INIT,
+    suspicious,
+    "checks for initialization of `Vec` or arrays which consist of a single range"
+}
+declare_lint_pass!(SingleRangeInVecInit => [SINGLE_RANGE_IN_VEC_INIT]);
+
+enum SuggestedType {
+    Vec,
+    Array,
+}
+
+impl SuggestedType {
+    fn starts_with(&self) -> &'static str {
+        if matches!(self, SuggestedType::Vec) {
+            "vec!"
+        } else {
+            "["
+        }
+    }
+
+    fn ends_with(&self) -> &'static str {
+        if matches!(self, SuggestedType::Vec) { "" } else { "]" }
+    }
+}
+
+impl Display for SuggestedType {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        if matches!(&self, SuggestedType::Vec) {
+            write!(f, "a `Vec`")
+        } else {
+            write!(f, "an array")
+        }
+    }
+}
+
+impl LateLintPass<'_> for SingleRangeInVecInit {
+    fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
+        // inner_expr: `vec![0..200]` or `[0..200]`
+        //                   ^^^^^^       ^^^^^^^
+        // span: `vec![0..200]` or `[0..200]`
+        //        ^^^^^^^^^^^^      ^^^^^^^^
+        // suggested_type: What to print, "an array" or "a `Vec`"
+        let (inner_expr, span, suggested_type) = if let ExprKind::Array([inner_expr]) = expr.kind
+            && !expr.span.from_expansion()
+        {
+            (inner_expr, expr.span, SuggestedType::Array)
+        } else if let Some(macro_call) = root_macro_call_first_node(cx, expr)
+            && let Some(VecArgs::Vec([expr])) = VecArgs::hir(cx, expr)
+        {
+            (expr, macro_call.span, SuggestedType::Vec)
+        } else {
+            return;
+        };
+
+        let ExprKind::Struct(QPath::LangItem(lang_item, ..), [start, end], None) = inner_expr.kind else {
+            return;
+        };
+
+        if matches!(lang_item, LangItem::Range)
+            && let ty = cx.typeck_results().expr_ty(start.expr)
+            && let Some(snippet) = snippet_opt(cx, span)
+            // `is_from_proc_macro` will skip any `vec![]`. Let's not!
+            && snippet.starts_with(suggested_type.starts_with())
+            && snippet.ends_with(suggested_type.ends_with())
+            && let Some(start_snippet) = snippet_opt(cx, start.span)
+            && let Some(end_snippet) = snippet_opt(cx, end.span)
+        {
+            let should_emit_every_value = if let Some(step_def_id) = get_trait_def_id(cx, &["core", "iter", "Step"])
+                && implements_trait(cx, ty, step_def_id, &[])
+            {
+                true
+            } else {
+                false
+            };
+            let should_emit_of_len = if let Some(copy_def_id) = cx.tcx.lang_items().copy_trait()
+                && implements_trait(cx, ty, copy_def_id, &[])
+                && let ExprKind::Lit(lit_kind) = end.expr.kind
+                && let LitKind::Int(.., suffix_type) = lit_kind.node
+                && let LitIntType::Unsigned(UintTy::Usize) | LitIntType::Unsuffixed = suffix_type
+            {
+                true
+            } else {
+                false
+            };
+
+            if should_emit_every_value || should_emit_of_len {
+                span_lint_and_then(
+                    cx,
+                    SINGLE_RANGE_IN_VEC_INIT,
+                    span,
+                    &format!("{suggested_type} of `Range` that is only one element"),
+                    |diag| {
+                        if should_emit_every_value {
+                            diag.span_suggestion(
+                                span,
+                                "if you wanted a `Vec` that contains the entire range, try",
+                                format!("({start_snippet}..{end_snippet}).collect::<std::vec::Vec<{ty}>>()"),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+
+                        if should_emit_of_len {
+                            diag.span_suggestion(
+                                inner_expr.span,
+                                format!("if you wanted {suggested_type} of len {end_snippet}, try"),
+                                format!("{start_snippet}; {end_snippet}"),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                    },
+                );
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/trait_bounds.rs b/clippy_lints/src/trait_bounds.rs
index 4ccda15068b..6db330dfa61 100644
--- a/clippy_lints/src/trait_bounds.rs
+++ b/clippy_lints/src/trait_bounds.rs
@@ -1,6 +1,7 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
-use clippy_utils::{SpanlessEq, SpanlessHash};
+use clippy_utils::{is_from_proc_macro, SpanlessEq, SpanlessHash};
 use core::hash::{Hash, Hasher};
 use if_chain::if_chain;
 use itertools::Itertools;
@@ -9,7 +10,7 @@ use rustc_data_structures::unhash::UnhashMap;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{
-    GenericArg, GenericBound, Generics, Item, ItemKind, Node, Path, PathSegment, PredicateOrigin, QPath,
+    GenericArg, GenericBound, Generics, Item, ItemKind, LangItem, Node, Path, PathSegment, PredicateOrigin, QPath,
     TraitBoundModifier, TraitItem, TraitRef, Ty, TyKind, WherePredicate,
 };
 use rustc_lint::{LateContext, LateLintPass};
@@ -86,15 +87,16 @@ declare_clippy_lint! {
     "check if the same trait bounds are specified more than once during a generic declaration"
 }
 
-#[derive(Copy, Clone)]
+#[derive(Clone)]
 pub struct TraitBounds {
     max_trait_bounds: u64,
+    msrv: Msrv,
 }
 
 impl TraitBounds {
     #[must_use]
-    pub fn new(max_trait_bounds: u64) -> Self {
-        Self { max_trait_bounds }
+    pub fn new(max_trait_bounds: u64, msrv: Msrv) -> Self {
+        Self { max_trait_bounds, msrv }
     }
 }
 
@@ -139,7 +141,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
                     ) = cx.tcx.hir().get_if_local(*def_id);
                 then {
                     if self_bounds_map.is_empty() {
-                        for bound in self_bounds.iter() {
+                        for bound in *self_bounds {
                             let Some((self_res, self_segments, _)) = get_trait_info_from_bound(bound) else { continue };
                             self_bounds_map.insert(self_res, self_segments);
                         }
@@ -184,7 +186,7 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
 
                 // Iterate the bounds and add them to our seen hash
                 // If we haven't yet seen it, add it to the fixed traits
-                for bound in bounds.iter() {
+                for bound in bounds {
                     let Some(def_id) = bound.trait_ref.trait_def_id() else { continue; };
 
                     let new_trait = seen_def_ids.insert(def_id);
@@ -222,10 +224,24 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds {
             }
         }
     }
+
+    extract_msrv_attr!(LateContext);
 }
 
 impl TraitBounds {
-    fn check_type_repetition<'tcx>(self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) {
+    /// Is the given bound a `?Sized` bound, and is combining it (i.e. `T: X + ?Sized`) an error on
+    /// this MSRV? See <https://github.com/rust-lang/rust-clippy/issues/8772> for details.
+    fn cannot_combine_maybe_bound(&self, cx: &LateContext<'_>, bound: &GenericBound<'_>) -> bool {
+        if !self.msrv.meets(msrvs::MAYBE_BOUND_IN_WHERE)
+            && let GenericBound::Trait(tr, TraitBoundModifier::Maybe) = bound
+        {
+            cx.tcx.lang_items().get(LangItem::Sized) == tr.trait_ref.path.res.opt_def_id()
+        } else {
+            false
+        }
+    }
+
+    fn check_type_repetition<'tcx>(&self, cx: &LateContext<'tcx>, gen: &'tcx Generics<'_>) {
         struct SpanlessTy<'cx, 'tcx> {
             ty: &'tcx Ty<'tcx>,
             cx: &'cx LateContext<'tcx>,
@@ -256,11 +272,10 @@ impl TraitBounds {
                 if p.origin != PredicateOrigin::ImplTrait;
                 if p.bounds.len() as u64 <= self.max_trait_bounds;
                 if !p.span.from_expansion();
-                if let Some(ref v) = map.insert(
-                    SpanlessTy { ty: p.bounded_ty, cx },
-                    p.bounds.iter().collect::<Vec<_>>()
-                );
-
+                let bounds = p.bounds.iter().filter(|b| !self.cannot_combine_maybe_bound(cx, b)).collect::<Vec<_>>();
+                if !bounds.is_empty();
+                if let Some(ref v) = map.insert(SpanlessTy { ty: p.bounded_ty, cx }, bounds);
+                if !is_from_proc_macro(cx, p.bounded_ty);
                 then {
                     let trait_bounds = v
                         .iter()
@@ -342,7 +357,7 @@ fn check_trait_bound_duplication(cx: &LateContext<'_>, gen: &'_ Generics<'_>) {
                             "this trait bound is already specified in the where clause",
                             None,
                             "consider removing this trait bound",
-                            );
+                        );
                     }
                 }
             }
diff --git a/clippy_lints/src/tuple_array_conversions.rs b/clippy_lints/src/tuple_array_conversions.rs
new file mode 100644
index 00000000000..bd983306508
--- /dev/null
+++ b/clippy_lints/src/tuple_array_conversions.rs
@@ -0,0 +1,235 @@
+use clippy_utils::{
+    diagnostics::span_lint_and_help,
+    is_from_proc_macro,
+    msrvs::{self, Msrv},
+    path_to_local,
+};
+use rustc_ast::LitKind;
+use rustc_hir::{Expr, ExprKind, HirId, Node, Pat};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::{lint::in_external_macro, ty};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use std::iter::once;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for tuple<=>array conversions that are not done with `.into()`.
+    ///
+    /// ### Why is this bad?
+    /// It's unnecessary complexity. `.into()` works for tuples<=>arrays at or below 12 elements and
+    /// conveys the intent a lot better, while also leaving less room for hard to spot bugs!
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// let t1 = &[(1, 2), (3, 4)];
+    /// let v1: Vec<[u32; 2]> = t1.iter().map(|&(a, b)| [a, b]).collect();
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// let t1 = &[(1, 2), (3, 4)];
+    /// let v1: Vec<[u32; 2]> = t1.iter().map(|&t| t.into()).collect();
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub TUPLE_ARRAY_CONVERSIONS,
+    complexity,
+    "checks for tuple<=>array conversions that are not done with `.into()`"
+}
+impl_lint_pass!(TupleArrayConversions => [TUPLE_ARRAY_CONVERSIONS]);
+
+#[derive(Clone)]
+pub struct TupleArrayConversions {
+    pub msrv: Msrv,
+}
+
+impl LateLintPass<'_> for TupleArrayConversions {
+    fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        if !in_external_macro(cx.sess(), expr.span) && self.msrv.meets(msrvs::TUPLE_ARRAY_CONVERSIONS) {
+            match expr.kind {
+                ExprKind::Array(elements) if (1..=12).contains(&elements.len()) => check_array(cx, expr, elements),
+                ExprKind::Tup(elements) if (1..=12).contains(&elements.len()) => check_tuple(cx, expr, elements),
+                _ => {},
+            }
+        }
+    }
+
+    extract_msrv_attr!(LateContext);
+}
+
+#[expect(
+    clippy::blocks_in_if_conditions,
+    reason = "not a FP, but this is much easier to understand"
+)]
+fn check_array<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &'tcx [Expr<'tcx>]) {
+    if should_lint(
+        cx,
+        elements,
+        // This is cursed.
+        Some,
+        |(first_id, local)| {
+            if let Node::Pat(pat) = local
+                && let parent = parent_pat(cx, pat)
+                && parent.hir_id == first_id
+            {
+                return matches!(
+                    cx.typeck_results().pat_ty(parent).peel_refs().kind(),
+                    ty::Tuple(len) if len.len() == elements.len()
+                );
+            }
+
+            false
+        },
+    ) || should_lint(
+        cx,
+        elements,
+        |(i, expr)| {
+            if let ExprKind::Field(path, field) = expr.kind && field.as_str() == i.to_string() {
+                return Some((i, path));
+            };
+
+            None
+        },
+        |(first_id, local)| {
+            if let Node::Pat(pat) = local
+                && let parent = parent_pat(cx, pat)
+                && parent.hir_id == first_id
+            {
+                return matches!(
+                    cx.typeck_results().pat_ty(parent).peel_refs().kind(),
+                    ty::Tuple(len) if len.len() == elements.len()
+                );
+            }
+
+            false
+        },
+    ) {
+        emit_lint(cx, expr, ToType::Array);
+    }
+}
+
+#[expect(
+    clippy::blocks_in_if_conditions,
+    reason = "not a FP, but this is much easier to understand"
+)]
+#[expect(clippy::cast_possible_truncation)]
+fn check_tuple<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, elements: &'tcx [Expr<'tcx>]) {
+    if should_lint(cx, elements, Some, |(first_id, local)| {
+        if let Node::Pat(pat) = local
+                && let parent = parent_pat(cx, pat)
+                && parent.hir_id == first_id
+            {
+                return matches!(
+                    cx.typeck_results().pat_ty(parent).peel_refs().kind(),
+                    ty::Array(_, len) if len.eval_target_usize(cx.tcx, cx.param_env) as usize == elements.len()
+                );
+            }
+
+        false
+    }) || should_lint(
+        cx,
+        elements,
+        |(i, expr)| {
+            if let ExprKind::Index(path, index) = expr.kind
+                && let ExprKind::Lit(lit) = index.kind
+                && let LitKind::Int(val, _) = lit.node
+                && val as usize == i
+            {
+                return Some((i, path));
+            };
+
+            None
+        },
+        |(first_id, local)| {
+            if let Node::Pat(pat) = local
+                && let parent = parent_pat(cx, pat)
+                && parent.hir_id == first_id
+            {
+                return matches!(
+                    cx.typeck_results().pat_ty(parent).peel_refs().kind(),
+                    ty::Array(_, len) if len.eval_target_usize(cx.tcx, cx.param_env) as usize == elements.len()
+                );
+            }
+
+            false
+        },
+    ) {
+        emit_lint(cx, expr, ToType::Tuple);
+    }
+}
+
+/// Walks up the `Pat` until it's reached the final containing `Pat`.
+fn parent_pat<'tcx>(cx: &LateContext<'tcx>, start: &'tcx Pat<'tcx>) -> &'tcx Pat<'tcx> {
+    let mut end = start;
+    for (_, node) in cx.tcx.hir().parent_iter(start.hir_id) {
+        if let Node::Pat(pat) = node {
+            end = pat;
+        } else {
+            break;
+        }
+    }
+    end
+}
+
+#[derive(Clone, Copy)]
+enum ToType {
+    Array,
+    Tuple,
+}
+
+impl ToType {
+    fn msg(self) -> &'static str {
+        match self {
+            ToType::Array => "it looks like you're trying to convert a tuple to an array",
+            ToType::Tuple => "it looks like you're trying to convert an array to a tuple",
+        }
+    }
+
+    fn help(self) -> &'static str {
+        match self {
+            ToType::Array => "use `.into()` instead, or `<[T; N]>::from` if type annotations are needed",
+            ToType::Tuple => "use `.into()` instead, or `<(T0, T1, ..., Tn)>::from` if type annotations are needed",
+        }
+    }
+}
+
+fn emit_lint<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, to_type: ToType) -> bool {
+    if !is_from_proc_macro(cx, expr) {
+        span_lint_and_help(
+            cx,
+            TUPLE_ARRAY_CONVERSIONS,
+            expr.span,
+            to_type.msg(),
+            None,
+            to_type.help(),
+        );
+
+        return true;
+    }
+
+    false
+}
+
+fn should_lint<'tcx>(
+    cx: &LateContext<'tcx>,
+    elements: &'tcx [Expr<'tcx>],
+    map: impl FnMut((usize, &'tcx Expr<'tcx>)) -> Option<(usize, &Expr<'_>)>,
+    predicate: impl FnMut((HirId, &Node<'tcx>)) -> bool,
+) -> bool {
+    if let Some(elements) = elements
+            .iter()
+            .enumerate()
+            .map(map)
+            .collect::<Option<Vec<_>>>()
+        && let Some(locals) = elements
+            .iter()
+            .map(|(_, element)| path_to_local(element).and_then(|local| cx.tcx.hir().find(local)))
+            .collect::<Option<Vec<_>>>()
+        && let [first, rest @ ..] = &*locals
+        && let Node::Pat(first_pat) = first
+        && let parent = parent_pat(cx, first_pat).hir_id
+        && rest.iter().chain(once(first)).map(|i| (parent, i)).all(predicate)
+    {
+        return true;
+    }
+
+    false
+}
diff --git a/clippy_lints/src/undocumented_unsafe_blocks.rs b/clippy_lints/src/undocumented_unsafe_blocks.rs
index 2920684ade3..a9deee96784 100644
--- a/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -11,7 +11,7 @@ use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource};
 use rustc_lexer::{tokenize, TokenKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::{BytePos, Pos, Span, SyntaxContext};
 
 declare_clippy_lint! {
@@ -92,7 +92,22 @@ declare_clippy_lint! {
     "annotating safe code with a safety comment"
 }
 
-declare_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS, UNNECESSARY_SAFETY_COMMENT]);
+#[derive(Copy, Clone)]
+pub struct UndocumentedUnsafeBlocks {
+    accept_comment_above_statement: bool,
+    accept_comment_above_attributes: bool,
+}
+
+impl UndocumentedUnsafeBlocks {
+    pub fn new(accept_comment_above_statement: bool, accept_comment_above_attributes: bool) -> Self {
+        Self {
+            accept_comment_above_statement,
+            accept_comment_above_attributes,
+        }
+    }
+}
+
+impl_lint_pass!(UndocumentedUnsafeBlocks => [UNDOCUMENTED_UNSAFE_BLOCKS, UNNECESSARY_SAFETY_COMMENT]);
 
 impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) {
@@ -101,7 +116,12 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
             && !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, block.hir_id)
             && !is_unsafe_from_proc_macro(cx, block.span)
             && !block_has_safety_comment(cx, block.span)
-            && !block_parents_have_safety_comment(cx, block.hir_id)
+            && !block_parents_have_safety_comment(
+                self.accept_comment_above_statement,
+                self.accept_comment_above_attributes,
+                cx,
+                block.hir_id,
+            )
         {
             let source_map = cx.tcx.sess.source_map();
             let span = if source_map.is_multiline(block.span) {
@@ -313,29 +333,95 @@ fn is_unsafe_from_proc_macro(cx: &LateContext<'_>, span: Span) -> bool {
 
 // Checks if any parent {expression, statement, block, local, const, static}
 // has a safety comment
-fn block_parents_have_safety_comment(cx: &LateContext<'_>, id: hir::HirId) -> bool {
+fn block_parents_have_safety_comment(
+    accept_comment_above_statement: bool,
+    accept_comment_above_attributes: bool,
+    cx: &LateContext<'_>,
+    id: hir::HirId,
+) -> bool {
     if let Some(node) = get_parent_node(cx.tcx, id) {
         return match node {
-            Node::Expr(expr) => !is_branchy(expr) && span_in_body_has_safety_comment(cx, expr.span),
+            Node::Expr(expr) => {
+                if let Some(
+                    Node::Local(hir::Local { span, .. })
+                    | Node::Item(hir::Item {
+                        kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
+                        span,
+                        ..
+                    }),
+                ) = get_parent_node(cx.tcx, expr.hir_id)
+                {
+                    let hir_id = match get_parent_node(cx.tcx, expr.hir_id) {
+                        Some(Node::Local(hir::Local { hir_id, .. })) => *hir_id,
+                        Some(Node::Item(hir::Item { owner_id, .. })) => {
+                            cx.tcx.hir().local_def_id_to_hir_id(owner_id.def_id)
+                        },
+                        _ => unreachable!(),
+                    };
+
+                    // if unsafe block is part of a let/const/static statement,
+                    // and accept_comment_above_statement is set to true
+                    // we accept the safety comment in the line the precedes this statement.
+                    accept_comment_above_statement
+                        && span_with_attrs_in_body_has_safety_comment(
+                            cx,
+                            *span,
+                            hir_id,
+                            accept_comment_above_attributes,
+                        )
+                } else {
+                    !is_branchy(expr)
+                        && span_with_attrs_in_body_has_safety_comment(
+                            cx,
+                            expr.span,
+                            expr.hir_id,
+                            accept_comment_above_attributes,
+                        )
+                }
+            },
             Node::Stmt(hir::Stmt {
                 kind:
-                    hir::StmtKind::Local(hir::Local { span, .. })
-                    | hir::StmtKind::Expr(hir::Expr { span, .. })
-                    | hir::StmtKind::Semi(hir::Expr { span, .. }),
+                    hir::StmtKind::Local(hir::Local { span, hir_id, .. })
+                    | hir::StmtKind::Expr(hir::Expr { span, hir_id, .. })
+                    | hir::StmtKind::Semi(hir::Expr { span, hir_id, .. }),
                 ..
             })
-            | Node::Local(hir::Local { span, .. })
-            | Node::Item(hir::Item {
+            | Node::Local(hir::Local { span, hir_id, .. }) => {
+                span_with_attrs_in_body_has_safety_comment(cx, *span, *hir_id, accept_comment_above_attributes)
+            },
+            Node::Item(hir::Item {
                 kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
                 span,
+                owner_id,
                 ..
-            }) => span_in_body_has_safety_comment(cx, *span),
+            }) => span_with_attrs_in_body_has_safety_comment(
+                cx,
+                *span,
+                cx.tcx.hir().local_def_id_to_hir_id(owner_id.def_id),
+                accept_comment_above_attributes,
+            ),
             _ => false,
         };
     }
     false
 }
 
+/// Extends `span` to also include its attributes, then checks if that span has a safety comment.
+fn span_with_attrs_in_body_has_safety_comment(
+    cx: &LateContext<'_>,
+    span: Span,
+    hir_id: HirId,
+    accept_comment_above_attributes: bool,
+) -> bool {
+    let span = if accept_comment_above_attributes {
+        include_attrs_in_span(cx, hir_id, span)
+    } else {
+        span
+    };
+
+    span_in_body_has_safety_comment(cx, span)
+}
+
 /// Checks if an expression is "branchy", e.g. loop, match/if/etc.
 fn is_branchy(expr: &hir::Expr<'_>) -> bool {
     matches!(
@@ -360,6 +446,15 @@ fn block_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
     ) || span_in_body_has_safety_comment(cx, span)
 }
 
+fn include_attrs_in_span(cx: &LateContext<'_>, hir_id: HirId, span: Span) -> Span {
+    span.to(cx
+        .tcx
+        .hir()
+        .attrs(hir_id)
+        .iter()
+        .fold(span, |acc, attr| acc.to(attr.span)))
+}
+
 enum HasSafetyComment {
     Yes(BytePos),
     No,
@@ -546,7 +641,14 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option<Span> {
     for (_, node) in map.parent_iter(body.hir_id) {
         match node {
             Node::Expr(e) => span = e.span,
-            Node::Block(_) | Node::Arm(_) | Node::Stmt(_) | Node::Local(_) => (),
+            Node::Block(_)
+            | Node::Arm(_)
+            | Node::Stmt(_)
+            | Node::Local(_)
+            | Node::Item(hir::Item {
+                kind: hir::ItemKind::Const(..) | ItemKind::Static(..),
+                ..
+            }) => (),
             _ => break,
         }
     }
diff --git a/clippy_lints/src/unused_async.rs b/clippy_lints/src/unused_async.rs
index 117dda09222..5e42cf7e4f3 100644
--- a/clippy_lints/src/unused_async.rs
+++ b/clippy_lints/src/unused_async.rs
@@ -1,4 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_def_id_trait_method;
 use rustc_hir::intravisit::{walk_body, walk_expr, walk_fn, FnKind, Visitor};
 use rustc_hir::{Body, Expr, ExprKind, FnDecl, YieldSource};
 use rustc_lint::{LateContext, LateLintPass};
@@ -91,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
         span: Span,
         def_id: LocalDefId,
     ) {
-        if !span.from_expansion() && fn_kind.asyncness().is_async() {
+        if !span.from_expansion() && fn_kind.asyncness().is_async() && !is_def_id_trait_method(cx, def_id) {
             let mut visitor = AsyncFnVisitor {
                 cx,
                 found_await: false,
diff --git a/clippy_lints/src/upper_case_acronyms.rs b/clippy_lints/src/upper_case_acronyms.rs
index 1d2d3eb12e1..4df1e3299ed 100644
--- a/clippy_lints/src/upper_case_acronyms.rs
+++ b/clippy_lints/src/upper_case_acronyms.rs
@@ -65,7 +65,7 @@ fn correct_ident(ident: &str) -> String {
 
     let mut ident = fragments.clone().next().unwrap();
     for (ref prev, ref curr) in fragments.tuple_windows() {
-        if [prev, curr]
+        if <[&String; 2]>::from((prev, curr))
             .iter()
             .all(|s| s.len() == 1 && s.chars().next().unwrap().is_ascii_uppercase())
         {
diff --git a/clippy_lints/src/useless_conversion.rs b/clippy_lints/src/useless_conversion.rs
index 28c3fc859e3..b6c11cfb355 100644
--- a/clippy_lints/src/useless_conversion.rs
+++ b/clippy_lints/src/useless_conversion.rs
@@ -1,16 +1,17 @@
-use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
+use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::is_ty_alias;
-use clippy_utils::source::{snippet, snippet_with_context};
+use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts};
 use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, path_to_local, paths};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
+use rustc_hir::def_id::DefId;
 use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, MatchSource, Node, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::sym;
+use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -43,6 +44,64 @@ pub struct UselessConversion {
 
 impl_lint_pass!(UselessConversion => [USELESS_CONVERSION]);
 
+enum MethodOrFunction {
+    Method,
+    Function,
+}
+
+impl MethodOrFunction {
+    /// Maps the argument position in `pos` to the parameter position.
+    /// For methods, `self` is skipped.
+    fn param_pos(self, pos: usize) -> usize {
+        match self {
+            MethodOrFunction::Method => pos + 1,
+            MethodOrFunction::Function => pos,
+        }
+    }
+}
+
+/// Returns the span of the `IntoIterator` trait bound in the function pointed to by `fn_did`
+fn into_iter_bound(cx: &LateContext<'_>, fn_did: DefId, into_iter_did: DefId, param_index: u32) -> Option<Span> {
+    cx.tcx
+        .predicates_of(fn_did)
+        .predicates
+        .iter()
+        .find_map(|&(ref pred, span)| {
+            if let ty::ClauseKind::Trait(tr) = pred.kind().skip_binder()
+                && tr.def_id() == into_iter_did
+                && tr.self_ty().is_param(param_index)
+            {
+                Some(span)
+            } else {
+                None
+            }
+        })
+}
+
+/// Extracts the receiver of a `.into_iter()` method call.
+fn into_iter_call<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>) -> Option<&'hir Expr<'hir>> {
+    if let ExprKind::MethodCall(name, recv, _, _) = expr.kind
+        && is_trait_method(cx, expr, sym::IntoIterator)
+        && name.ident.name == sym::into_iter
+    {
+        Some(recv)
+    } else {
+        None
+    }
+}
+
+/// Same as [`into_iter_call`], but tries to look for the innermost `.into_iter()` call, e.g.:
+/// `foo.into_iter().into_iter()`
+///  ^^^  we want this expression
+fn into_iter_deep_call<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> (&'hir Expr<'hir>, usize) {
+    let mut depth = 0;
+    while let Some(recv) = into_iter_call(cx, expr) {
+        expr = recv;
+        depth += 1;
+    }
+    (expr, depth)
+}
+
 #[expect(clippy::too_many_lines)]
 impl<'tcx> LateLintPass<'tcx> for UselessConversion {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
@@ -82,9 +141,59 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
                         );
                     }
                 }
-                if is_trait_method(cx, e, sym::IntoIterator) && name.ident.name == sym::into_iter {
-                    if get_parent_expr(cx, e).is_some() &&
-                       let Some(id) = path_to_local(recv) &&
+                if let Some(into_iter_recv) = into_iter_call(cx, e)
+                    // Make sure that there is no parent expression, or if there is, make sure it's not a `.into_iter()` call.
+                    // The reason for that is that we only want to lint once (the outermost call)
+                    // in cases like `foo.into_iter().into_iter()`
+                    && get_parent_expr(cx, e)
+                        .and_then(|parent| into_iter_call(cx, parent))
+                        .is_none()
+                {
+                    if let Some(parent) = get_parent_expr(cx, e) {
+                        let parent_fn = match parent.kind {
+                            ExprKind::Call(recv, args) if let ExprKind::Path(ref qpath) = recv.kind => {
+                                cx.qpath_res(qpath, recv.hir_id).opt_def_id()
+                                    .map(|did| (did, args, MethodOrFunction::Function))
+                            }
+                            ExprKind::MethodCall(.., args, _) => {
+                                cx.typeck_results().type_dependent_def_id(parent.hir_id)
+                                    .map(|did| (did, args, MethodOrFunction::Method))
+                            }
+                            _ => None,
+                        };
+
+                        if let Some((parent_fn_did, args, kind)) = parent_fn
+                            && let Some(into_iter_did) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
+                            && let sig = cx.tcx.fn_sig(parent_fn_did).skip_binder().skip_binder()
+                            && let Some(arg_pos) = args.iter().position(|x| x.hir_id == e.hir_id)
+                            && let Some(&into_iter_param) = sig.inputs().get(kind.param_pos(arg_pos))
+                            && let ty::Param(param) = into_iter_param.kind()
+                            && let Some(span) = into_iter_bound(cx, parent_fn_did, into_iter_did, param.index)
+                        {
+                            // Get the "innermost" `.into_iter()` call, e.g. given this expression:
+                            // `foo.into_iter().into_iter()`
+                            //  ^^^
+                            let (into_iter_recv, depth) = into_iter_deep_call(cx, into_iter_recv);
+
+                            let plural = if depth == 0 { "" } else { "s" };
+                            let mut applicability = Applicability::MachineApplicable;
+                            let sugg = snippet_with_applicability(cx, into_iter_recv.span.source_callsite(), "<expr>", &mut applicability).into_owned();
+                            span_lint_and_then(cx, USELESS_CONVERSION, e.span, "explicit call to `.into_iter()` in function argument accepting `IntoIterator`", |diag| {
+                                diag.span_suggestion(
+                                    e.span,
+                                    format!("consider removing the `.into_iter()`{plural}"),
+                                    sugg,
+                                    applicability,
+                                );
+                                diag.span_note(span, "this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`");
+                            });
+
+                            // Early return to avoid linting again with contradicting suggestions
+                            return;
+                        }
+                    }
+
+                    if let Some(id) = path_to_local(recv) &&
                        let Node::Pat(pat) = cx.tcx.hir().get(id) &&
                        let PatKind::Binding(ann, ..) = pat.kind &&
                        ann != BindingAnnotation::MUT
diff --git a/clippy_lints/src/utils/conf.rs b/clippy_lints/src/utils/conf.rs
index 35f40830681..f1d05c7529b 100644
--- a/clippy_lints/src/utils/conf.rs
+++ b/clippy_lints/src/utils/conf.rs
@@ -21,6 +21,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[
     "GitHub", "GitLab",
     "IPv4", "IPv6",
     "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript",
+    "WebAssembly",
     "NaN", "NaNs",
     "OAuth", "GraphQL",
     "OCaml",
@@ -34,6 +35,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[
     "CamelCase",
 ];
 const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"];
+const DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS: &[&str] = &["i", "j", "x", "y", "z", "w", "n"];
 
 /// Holds information used by `MISSING_ENFORCED_IMPORT_RENAMES` lint.
 #[derive(Clone, Debug, Deserialize)]
@@ -288,11 +290,11 @@ define_Conf! {
     /// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
     /// ```
     (arithmetic_side_effects_allowed_unary: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
-    /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS.
+    /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN.
     ///
     /// Suppress lints whenever the suggested change would cause breakage for other crates.
     (avoid_breaking_exported_api: bool = true),
-    /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN.
+    /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD.
     ///
     /// The minimum rust version that the project supports
     (msrv: Option<String> = None),
@@ -305,6 +307,10 @@ define_Conf! {
     ///
     /// The maximum cognitive complexity a function can have
     (cognitive_complexity_threshold: u64 = 25),
+    /// Lint: EXCESSIVE_NESTING.
+    ///
+    /// The maximum amount of nesting a block can reside in
+    (excessive_nesting_threshold: u64 = 0),
     /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY.
     ///
     /// Use the Cognitive Complexity lint instead.
@@ -382,6 +388,10 @@ define_Conf! {
     ///
     /// The maximum allowed size for arrays on the stack
     (array_size_threshold: u64 = 512_000),
+    /// Lint: LARGE_STACK_FRAMES.
+    ///
+    /// The maximum allowed stack size for functions in bytes
+    (stack_size_threshold: u64 = 512_000),
     /// Lint: VEC_BOX.
     ///
     /// The size of the boxed type in bytes, where boxing in a `Vec` is allowed
@@ -514,6 +524,33 @@ define_Conf! {
     ///
     /// The byte size a `T` in `Box<T>` can have, below which it triggers the `clippy::unnecessary_box` lint
     (unnecessary_box_size: u64 = 128),
+    /// Lint: MODULE_INCEPTION.
+    ///
+    /// Whether to allow module inception if it's not public.
+    (allow_private_module_inception: bool = false),
+    /// Lint: MIN_IDENT_CHARS.
+    ///
+    /// Allowed names below the minimum allowed characters. The value `".."` can be used as part of
+    /// the list to indicate, that the configured values should be appended to the default
+    /// configuration of Clippy. By default, any configuration will replace the default value.
+    (allowed_idents_below_min_chars: rustc_data_structures::fx::FxHashSet<String> =
+        super::DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect()),
+    /// Lint: MIN_IDENT_CHARS.
+    ///
+    /// Minimum chars an ident can have, anything below or equal to this will be linted.
+    (min_ident_chars_threshold: u64 = 1),
+    /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS.
+    ///
+    /// Whether to accept a safety comment to be placed above the statement containing the `unsafe` block
+    (accept_comment_above_statement: bool = false),
+    /// Lint: UNDOCUMENTED_UNSAFE_BLOCKS.
+    ///
+    /// Whether to accept a safety comment to be placed above the attributes for the `unsafe` block
+    (accept_comment_above_attributes: bool = false),
+    /// Lint: UNNECESSARY_RAW_STRING_HASHES.
+    ///
+    /// Whether to allow `r#""#` when `r""` can be used
+    (allow_one_hash_in_raw_strings: bool = false),
 }
 
 /// Search for the configuration file.
@@ -581,6 +618,12 @@ pub fn read(sess: &Session, path: &Path) -> TryConf {
         Ok(mut conf) => {
             extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS);
             extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES);
+            // TODO: THIS SHOULD BE TESTED, this comment will be gone soon
+            if conf.conf.allowed_idents_below_min_chars.contains(&"..".to_owned()) {
+                conf.conf
+                    .allowed_idents_below_min_chars
+                    .extend(DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string));
+            }
 
             conf
         },
diff --git a/clippy_lints/src/utils/internal_lints.rs b/clippy_lints/src/utils/internal_lints.rs
index 71f6c9909dd..e222a5448c9 100644
--- a/clippy_lints/src/utils/internal_lints.rs
+++ b/clippy_lints/src/utils/internal_lints.rs
@@ -1,3 +1,4 @@
+pub mod almost_standard_lint_formulation;
 pub mod clippy_lints_internal;
 pub mod collapsible_calls;
 pub mod compiler_lint_functions;
diff --git a/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs b/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs
new file mode 100644
index 00000000000..570a88a0ed2
--- /dev/null
+++ b/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs
@@ -0,0 +1,87 @@
+use crate::utils::internal_lints::lint_without_lint_pass::is_lint_ref_type;
+use clippy_utils::diagnostics::span_lint_and_help;
+use regex::Regex;
+use rustc_ast as ast;
+use rustc_hir::{Item, ItemKind, Mutability};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks if lint formulations have a standardized format.
+    ///
+    /// ### Why is this bad?
+    /// It's not neccessarily bad, but we try to enforce a standard in Clippy.
+    ///
+    /// ### Example
+    /// `Checks for use...` can be written as `Checks for usage...` .
+    pub ALMOST_STANDARD_LINT_FORMULATION,
+    internal,
+    "lint formulations must have a standardized format."
+}
+
+impl_lint_pass!(AlmostStandardFormulation => [ALMOST_STANDARD_LINT_FORMULATION]);
+
+pub struct AlmostStandardFormulation {
+    standard_formulations: Vec<StandardFormulations<'static>>,
+}
+
+#[derive(Debug)]
+struct StandardFormulations<'a> {
+    wrong_pattern: Regex,
+    correction: &'a str,
+}
+
+impl AlmostStandardFormulation {
+    pub fn new() -> Self {
+        let standard_formulations = vec![StandardFormulations {
+            wrong_pattern: Regex::new("^(Check for|Detects? uses?)").unwrap(),
+            correction: "Checks for",
+        }];
+        Self { standard_formulations }
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for AlmostStandardFormulation {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
+        let mut check_next = false;
+        if let ItemKind::Static(ty, Mutability::Not, _) = item.kind {
+            let lines = cx
+                .tcx
+                .hir()
+                .attrs(item.hir_id())
+                .iter()
+                .filter_map(|attr| ast::Attribute::doc_str(attr).map(|sym| (sym, attr)));
+            if is_lint_ref_type(cx, ty) {
+                for (line, attr) in lines {
+                    let cur_line = line.as_str().trim();
+                    if check_next && !cur_line.is_empty() {
+                        for formulation in &self.standard_formulations {
+                            let starts_with_correct_formulation = cur_line.starts_with(formulation.correction);
+                            if !starts_with_correct_formulation && formulation.wrong_pattern.is_match(cur_line) {
+                                if let Some(ident) = attr.ident() {
+                                    span_lint_and_help(
+                                        cx,
+                                        ALMOST_STANDARD_LINT_FORMULATION,
+                                        ident.span,
+                                        "non-standard lint formulation",
+                                        None,
+                                        &format!("try using `{}` instead", formulation.correction),
+                                    );
+                                }
+                                return;
+                            }
+                        }
+                        return;
+                    } else if cur_line.contains("What it does") {
+                        check_next = true;
+                    } else if cur_line.contains("Why is this bad") {
+                        // Formulation documentation is done. Can add check to ensure that missing formulation is added
+                        // and add a check if it matches no accepted formulation
+                        return;
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
index f8978e30a8e..dced9fcf9ab 100644
--- a/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
+++ b/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
@@ -75,7 +75,7 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
 
         for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] {
             for def_id in def_path_def_ids(cx, module) {
-                for item in cx.tcx.module_children(def_id).iter() {
+                for item in cx.tcx.module_children(def_id) {
                     if_chain! {
                         if let Res::Def(DefKind::Const, item_def_id) = item.res;
                         let ty = cx.tcx.type_of(item_def_id).subst_identity();
diff --git a/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index 7a1cd3effae..107a62806a8 100644
--- a/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -104,6 +104,8 @@ const APPLICABILITY_UNRESOLVED_STR: &str = "Unresolved";
 /// The version that will be displayed if none has been defined
 const VERSION_DEFAULT_STR: &str = "Unknown";
 
+const CHANGELOG_PATH: &str = "../CHANGELOG.md";
+
 declare_clippy_lint! {
     /// ### What it does
     /// Collects metadata about clippy lints for the website.
@@ -195,8 +197,14 @@ This lint has the following configuration variables:
 
     fn get_markdown_docs(&self) -> String {
         format!(
-            "## Lint Configuration Options\n| <div style=\"width:290px\">Option</div> | Default Value |\n|--|--|\n{}\n\n{}\n",
-            self.configs_to_markdown(ClippyConfiguration::to_markdown_table_entry),
+            r#"# Lint Configuration Options
+
+The following list shows each configuration option, along with a description, its default value, an example
+and lints affected.
+
+---
+
+{}"#,
             self.configs_to_markdown(ClippyConfiguration::to_markdown_paragraph),
         )
     }
@@ -254,6 +262,22 @@ Please use that command to update the file and do not edit it by hand.
             self.get_markdown_docs(),
         )
         .unwrap();
+
+        // Write configuration links to CHANGELOG.md
+        let mut changelog = std::fs::read_to_string(CHANGELOG_PATH).unwrap();
+        let mut changelog_file = OpenOptions::new().read(true).write(true).open(CHANGELOG_PATH).unwrap();
+
+        if let Some(position) = changelog.find("<!-- begin autogenerated links to configuration documentation -->") {
+            // I know this is kinda wasteful, we just don't have regex on `clippy_lints` so... this is the best
+            // we can do AFAIK.
+            changelog = changelog[..position].to_string();
+        }
+        writeln!(
+            changelog_file,
+            "{changelog}<!-- begin autogenerated links to configuration documentation -->\n{}\n<!-- end autogenerated links to configuration documentation -->",
+            self.configs_to_markdown(ClippyConfiguration::to_markdown_link)
+        )
+        .unwrap();
     }
 }
 
diff --git a/clippy_lints/src/utils/mod.rs b/clippy_lints/src/utils/mod.rs
index d3ea7cafa80..fb08256931f 100644
--- a/clippy_lints/src/utils/mod.rs
+++ b/clippy_lints/src/utils/mod.rs
@@ -12,6 +12,9 @@ fn to_kebab(config_name: &str) -> String {
     config_name.replace('_', "-")
 }
 
+#[cfg(feature = "internal")]
+const BOOK_CONFIGS_PATH: &str = "https://doc.rust-lang.org/clippy/lint_configuration.html";
+
 // ==================================================================
 // Configuration
 // ==================================================================
@@ -51,7 +54,7 @@ impl ClippyConfiguration {
     #[cfg(feature = "internal")]
     fn to_markdown_paragraph(&self) -> String {
         format!(
-            "### {}\n{}\n\n**Default Value:** `{}` (`{}`)\n\n{}\n\n",
+            "## `{}`\n{}\n\n**Default Value:** `{}` (`{}`)\n\n---\n**Affected lints:**\n{}\n\n",
             self.name,
             self.doc
                 .lines()
@@ -62,14 +65,13 @@ impl ClippyConfiguration {
             self.lints
                 .iter()
                 .map(|name| name.to_string().split_whitespace().next().unwrap().to_string())
-                .map(|name| format!("* [{name}](https://rust-lang.github.io/rust-clippy/master/index.html#{name})"))
+                .map(|name| format!("* [`{name}`](https://rust-lang.github.io/rust-clippy/master/index.html#{name})"))
                 .join("\n"),
         )
     }
-
     #[cfg(feature = "internal")]
-    fn to_markdown_table_entry(&self) -> String {
-        format!("| [{}](#{}) | `{}` |", self.name, self.name, self.default)
+    fn to_markdown_link(&self) -> String {
+        format!("[`{}`]: {BOOK_CONFIGS_PATH}#{}", self.name, self.name)
     }
 }
 
diff --git a/clippy_lints/src/vec.rs b/clippy_lints/src/vec.rs
index 7329e508106..2a594e750b9 100644
--- a/clippy_lints/src/vec.rs
+++ b/clippy_lints/src/vec.rs
@@ -1,26 +1,32 @@
+use std::ops::ControlFlow;
+
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher;
+use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::is_copy;
+use clippy_utils::visitors::for_each_local_use_after_expr;
+use clippy_utils::{get_parent_expr, higher, is_trait_method};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
+use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Node, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::{declare_tool_lint, impl_lint_pass};
 use rustc_span::source_map::Span;
+use rustc_span::sym;
 
 #[expect(clippy::module_name_repetitions)]
-#[derive(Copy, Clone)]
+#[derive(Clone)]
 pub struct UselessVec {
     pub too_large_for_stack: u64,
+    pub msrv: Msrv,
 }
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for usage of `&vec![..]` when using `&[..]` would
+    /// Checks for usage of `vec![..]` when using `[..]` would
     /// be possible.
     ///
     /// ### Why is this bad?
@@ -46,16 +52,73 @@ declare_clippy_lint! {
 
 impl_lint_pass!(UselessVec => [USELESS_VEC]);
 
+fn adjusts_to_slice(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
+    matches!(cx.typeck_results().expr_ty_adjusted(e).kind(), ty::Ref(_, ty, _) if ty.is_slice())
+}
+
+/// Checks if the given expression is a method call to a `Vec` method
+/// that also exists on slices. If this returns true, it means that
+/// this expression does not actually require a `Vec` and could just work with an array.
+fn is_allowed_vec_method(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
+    const ALLOWED_METHOD_NAMES: &[&str] = &["len", "as_ptr", "is_empty"];
+
+    if let ExprKind::MethodCall(path, ..) = e.kind {
+        ALLOWED_METHOD_NAMES.contains(&path.ident.name.as_str())
+    } else {
+        is_trait_method(cx, e, sym::IntoIterator)
+    }
+}
+
 impl<'tcx> LateLintPass<'tcx> for UselessVec {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        // search for `&vec![_]` expressions where the adjusted type is `&[_]`
+        // search for `&vec![_]` or `vec![_]` expressions where the adjusted type is `&[_]`
         if_chain! {
-            if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(expr).kind();
-            if let ty::Slice(..) = ty.kind();
-            if let ExprKind::AddrOf(BorrowKind::Ref, mutability, addressee) = expr.kind;
-            if let Some(vec_args) = higher::VecArgs::hir(cx, addressee);
+            if adjusts_to_slice(cx, expr);
+            if let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows());
             then {
-                self.check_vec_macro(cx, &vec_args, mutability, expr.span);
+                let (suggest_slice, span) = if let ExprKind::AddrOf(BorrowKind::Ref, mutability, _) = expr.kind {
+                    // `expr` is `&vec![_]`, so suggest `&[_]` (or `&mut[_]` resp.)
+                    (SuggestedType::SliceRef(mutability), expr.span)
+                } else {
+                    // `expr` is the `vec![_]` expansion, so suggest `[_]`
+                    // and also use the span of the actual `vec![_]` expression
+                    (SuggestedType::Array, expr.span.ctxt().outer_expn_data().call_site)
+                };
+
+                self.check_vec_macro(cx, &vec_args, span, suggest_slice);
+            }
+        }
+
+        // search for `let foo = vec![_]` expressions where all uses of `foo`
+        // adjust to slices or call a method that exist on slices (e.g. len)
+        if let Some(vec_args) = higher::VecArgs::hir(cx, expr)
+            && let Node::Local(local) = cx.tcx.hir().get_parent(expr.hir_id)
+            // for now ignore locals with type annotations.
+            // this is to avoid compile errors when doing the suggestion here: let _: Vec<_> = vec![..];
+            && local.ty.is_none()
+            && let PatKind::Binding(_, id, ..) = local.pat.kind
+            && is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(expr)))
+        {
+            let only_slice_uses = for_each_local_use_after_expr(cx, id, expr.hir_id, |expr| {
+                // allow indexing into a vec and some set of allowed method calls that exist on slices, too
+                if let Some(parent) = get_parent_expr(cx, expr)
+                    && (adjusts_to_slice(cx, expr)
+                        || matches!(parent.kind, ExprKind::Index(..))
+                        || is_allowed_vec_method(cx, parent))
+                {
+                    ControlFlow::Continue(())
+                } else {
+                    ControlFlow::Break(())
+                }
+            }).is_continue();
+
+            if only_slice_uses {
+                self.check_vec_macro(
+                    cx,
+                    &vec_args,
+                    expr.span.ctxt().outer_expn_data().call_site,
+                    SuggestedType::Array
+                );
             }
         }
 
@@ -63,25 +126,36 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
         if_chain! {
             if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr);
             if let Some(vec_args) = higher::VecArgs::hir(cx, arg);
-            if is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(arg)));
+            if self.msrv.meets(msrvs::ARRAY_INTO_ITERATOR);
             then {
                 // report the error around the `vec!` not inside `<std macros>:`
                 let span = arg.span.ctxt().outer_expn_data().call_site;
-                self.check_vec_macro(cx, &vec_args, Mutability::Not, span);
+                self.check_vec_macro(cx, &vec_args, span, SuggestedType::Array);
             }
         }
     }
+
+    extract_msrv_attr!(LateContext);
+}
+
+#[derive(Copy, Clone)]
+enum SuggestedType {
+    /// Suggest using a slice `&[..]` / `&mut [..]`
+    SliceRef(Mutability),
+    /// Suggest using an array: `[..]`
+    Array,
 }
 
 impl UselessVec {
     fn check_vec_macro<'tcx>(
-        self,
+        &mut self,
         cx: &LateContext<'tcx>,
         vec_args: &higher::VecArgs<'tcx>,
-        mutability: Mutability,
         span: Span,
+        suggest_slice: SuggestedType,
     ) {
         let mut applicability = Applicability::MachineApplicable;
+
         let snippet = match *vec_args {
             higher::VecArgs::Repeat(elem, len) => {
                 if let Some(Constant::Int(len_constant)) = constant(cx, cx.typeck_results(), len) {
@@ -90,21 +164,13 @@ impl UselessVec {
                         return;
                     }
 
-                    match mutability {
-                        Mutability::Mut => {
-                            format!(
-                                "&mut [{}; {}]",
-                                snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
-                                snippet_with_applicability(cx, len.span, "len", &mut applicability)
-                            )
-                        },
-                        Mutability::Not => {
-                            format!(
-                                "&[{}; {}]",
-                                snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
-                                snippet_with_applicability(cx, len.span, "len", &mut applicability)
-                            )
-                        },
+                    let elem = snippet_with_applicability(cx, elem.span, "elem", &mut applicability);
+                    let len = snippet_with_applicability(cx, len.span, "len", &mut applicability);
+
+                    match suggest_slice {
+                        SuggestedType::SliceRef(Mutability::Mut) => format!("&mut [{elem}; {len}]"),
+                        SuggestedType::SliceRef(Mutability::Not) => format!("&[{elem}; {len}]"),
+                        SuggestedType::Array => format!("[{elem}; {len}]"),
                     }
                 } else {
                     return;
@@ -116,22 +182,24 @@ impl UselessVec {
                         return;
                     }
                     let span = args[0].span.to(last.span);
+                    let args = snippet_with_applicability(cx, span, "..", &mut applicability);
 
-                    match mutability {
-                        Mutability::Mut => {
-                            format!(
-                                "&mut [{}]",
-                                snippet_with_applicability(cx, span, "..", &mut applicability)
-                            )
+                    match suggest_slice {
+                        SuggestedType::SliceRef(Mutability::Mut) => {
+                            format!("&mut [{args}]")
+                        },
+                        SuggestedType::SliceRef(Mutability::Not) => {
+                            format!("&[{args}]")
                         },
-                        Mutability::Not => {
-                            format!("&[{}]", snippet_with_applicability(cx, span, "..", &mut applicability))
+                        SuggestedType::Array => {
+                            format!("[{args}]")
                         },
                     }
                 } else {
-                    match mutability {
-                        Mutability::Mut => "&mut []".into(),
-                        Mutability::Not => "&[]".into(),
+                    match suggest_slice {
+                        SuggestedType::SliceRef(Mutability::Mut) => "&mut []".to_owned(),
+                        SuggestedType::SliceRef(Mutability::Not) => "&[]".to_owned(),
+                        SuggestedType::Array => "[]".to_owned(),
                     }
                 }
             },
@@ -142,7 +210,13 @@ impl UselessVec {
             USELESS_VEC,
             span,
             "useless use of `vec!`",
-            "you can use a slice directly",
+            &format!(
+                "you can use {} directly",
+                match suggest_slice {
+                    SuggestedType::SliceRef(_) => "a slice",
+                    SuggestedType::Array => "an array",
+                }
+            ),
             snippet,
             applicability,
         );
diff --git a/clippy_lints/src/visibility.rs b/clippy_lints/src/visibility.rs
new file mode 100644
index 00000000000..43248bccc13
--- /dev/null
+++ b/clippy_lints/src/visibility.rs
@@ -0,0 +1,131 @@
+use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet_opt};
+use rustc_ast::ast::{Item, VisibilityKind};
+use rustc_errors::Applicability;
+use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{symbol::kw, Span};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `pub(self)` and `pub(in self)`.
+    ///
+    /// ### Why is this bad?
+    /// It's unnecessary, omitting the `pub` entirely will give the same results.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// pub(self) type OptBox<T> = Option<Box<T>>;
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// type OptBox<T> = Option<Box<T>>;
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub NEEDLESS_PUB_SELF,
+    style,
+    "checks for usage of `pub(self)` and `pub(in self)`."
+}
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `pub(<loc>)` with `in`.
+    ///
+    /// ### Why is this bad?
+    /// Consistency. Use it or don't, just be consistent about it.
+    ///
+    /// Also see the `pub_without_shorthand` lint for an alternative.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// pub(super) type OptBox<T> = Option<Box<T>>;
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// pub(in super) type OptBox<T> = Option<Box<T>>;
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub PUB_WITH_SHORTHAND,
+    restriction,
+    "disallows usage of `pub(<loc>)`, without `in`"
+}
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `pub(<loc>)` without `in`.
+    ///
+    /// Note: As you cannot write a module's path in `pub(<loc>)`, this will only trigger on
+    /// `pub(super)` and the like.
+    ///
+    /// ### Why is this bad?
+    /// Consistency. Use it or don't, just be consistent about it.
+    ///
+    /// Also see the `pub_with_shorthand` lint for an alternative.
+    ///
+    /// ### Example
+    /// ```rust,ignore
+    /// pub(in super) type OptBox<T> = Option<Box<T>>;
+    /// ```
+    /// Use instead:
+    /// ```rust,ignore
+    /// pub(super) type OptBox<T> = Option<Box<T>>;
+    /// ```
+    #[clippy::version = "1.72.0"]
+    pub PUB_WITHOUT_SHORTHAND,
+    restriction,
+    "disallows usage of `pub(in <loc>)` with `in`"
+}
+declare_lint_pass!(Visibility => [NEEDLESS_PUB_SELF, PUB_WITH_SHORTHAND, PUB_WITHOUT_SHORTHAND]);
+
+impl EarlyLintPass for Visibility {
+    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+        if !in_external_macro(cx.sess(), item.span)
+            && let VisibilityKind::Restricted { path, shorthand, .. } = &item.vis.kind
+        {
+            if **path == kw::SelfLower && let Some(false) = is_from_proc_macro(cx, item.vis.span) {
+                span_lint_and_sugg(
+                    cx,
+                    NEEDLESS_PUB_SELF,
+                    item.vis.span,
+                    &format!("unnecessary `pub({}self)`", if *shorthand { "" } else { "in " }),
+                    "remove it",
+                    String::new(),
+                    Applicability::MachineApplicable,
+                );
+            }
+
+            if (**path == kw::Super || **path == kw::SelfLower || **path == kw::Crate)
+                && !*shorthand
+                && let [.., last] = &*path.segments
+                && let Some(false) = is_from_proc_macro(cx, item.vis.span)
+            {
+                span_lint_and_sugg(
+                    cx,
+                    PUB_WITHOUT_SHORTHAND,
+                    item.vis.span,
+                    "usage of `pub` with `in`",
+                    "remove it",
+                    format!("pub({})", last.ident),
+                    Applicability::MachineApplicable,
+                );
+            }
+
+            if *shorthand
+                && let [.., last] = &*path.segments
+                && let Some(false) = is_from_proc_macro(cx, item.vis.span)
+            {
+                span_lint_and_sugg(
+                    cx,
+                    PUB_WITH_SHORTHAND,
+                    item.vis.span,
+                    "usage of `pub` without `in`",
+                    "add it",
+                    format!("pub(in {})", last.ident),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
+
+fn is_from_proc_macro(cx: &EarlyContext<'_>, span: Span) -> Option<bool> {
+    snippet_opt(cx, span).map(|s| !s.starts_with("pub"))
+}