summary refs log tree commit diff
path: root/src/tools/clippy/clippy_lints
diff options
context:
space:
mode:
authorPhilipp Krones <hello@philkrones.com>2024-07-11 15:44:03 +0200
committerPhilipp Krones <hello@philkrones.com>2024-07-11 15:44:03 +0200
commit2ed6ed41beebb2aa2ffc91ab0da4c5f70c40366b (patch)
treef7ee58daa96b6179271bf0ccf98b5ff00ec17d4d /src/tools/clippy/clippy_lints
parentfdf7ea6b5b1cac83c0f29e681202cf18bf25b01c (diff)
parentb794b8e08c16517a941dc598bb1483e8e12a8592 (diff)
downloadrust-2ed6ed41beebb2aa2ffc91ab0da4c5f70c40366b.tar.gz
rust-2ed6ed41beebb2aa2ffc91ab0da4c5f70c40366b.zip
Merge commit 'b794b8e08c16517a941dc598bb1483e8e12a8592' into clippy-subtree-update
Diffstat (limited to 'src/tools/clippy/clippy_lints')
-rw-r--r--src/tools/clippy/clippy_lints/src/almost_complete_range.rs104
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_constants.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/assigning_clones.rs496
-rw-r--r--src/tools/clippy/clippy_lints/src/await_holding_invalid.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs134
-rw-r--r--src/tools/clippy/clippy_lints/src/byte_char_slices.rs80
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs113
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/cfg_not_test.rs60
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/default.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_methods.rs42
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_names.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/endian_bytes.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/incompatible_msrv.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/init_numbered_fields.rs87
-rw-r--r--src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs41
-rw-r--r--src/tools/clippy/clippy_lints/src/instant_subtraction.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/items_after_statements.rs59
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/large_const_arrays.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/large_enum_variant.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/large_futures.rs43
-rw-r--r--src/tools/clippy/clippy_lints/src/large_include_file.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs46
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/let_if_seq.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_bits.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_float_methods.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_let_else.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_range_patterns.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs49
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_retain.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rotate.rs117
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs111
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs70
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/minmax.rs37
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_assert_message.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_thread_local.rs (renamed from src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs)14
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/float_cmp.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/mod.rs140
-rw-r--r--src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs70
-rw-r--r--src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs86
-rw-r--r--src/tools/clippy/clippy_lints/src/renamed_lints.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs47
-rw-r--r--src/tools/clippy/clippy_lints/src/same_name_method.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs125
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs73
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs5
77 files changed, 1681 insertions, 1273 deletions
diff --git a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
index 57a5cd8fba8..96e9c949b75 100644
--- a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
+++ b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
@@ -6,7 +6,6 @@ use rustc_errors::Applicability;
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::impl_lint_pass;
-use rustc_span::Span;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -41,61 +40,80 @@ impl AlmostCompleteRange {
 }
 impl EarlyLintPass for AlmostCompleteRange {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &Expr) {
-        if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind {
-            let ctxt = e.span.ctxt();
-            let sugg = if let Some(start) = walk_span_to_context(start.span, ctxt)
-                && let Some(end) = walk_span_to_context(end.span, ctxt)
-                && self.msrv.meets(msrvs::RANGE_INCLUSIVE)
-            {
-                Some((trim_span(cx.sess().source_map(), start.between(end)), "..="))
-            } else {
-                None
-            };
-            check_range(cx, e.span, start, end, sugg);
+        if let ExprKind::Range(Some(start), Some(end), RangeLimits::HalfOpen) = &e.kind
+            && is_incomplete_range(start, end)
+            && !in_external_macro(cx.sess(), e.span)
+        {
+            span_lint_and_then(
+                cx,
+                ALMOST_COMPLETE_RANGE,
+                e.span,
+                "almost complete ascii range",
+                |diag| {
+                    let ctxt = e.span.ctxt();
+                    if let Some(start) = walk_span_to_context(start.span, ctxt)
+                        && let Some(end) = walk_span_to_context(end.span, ctxt)
+                        && self.msrv.meets(msrvs::RANGE_INCLUSIVE)
+                    {
+                        diag.span_suggestion(
+                            trim_span(cx.sess().source_map(), start.between(end)),
+                            "use an inclusive range",
+                            "..=".to_owned(),
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                },
+            );
         }
     }
 
     fn check_pat(&mut self, cx: &EarlyContext<'_>, p: &Pat) {
         if let PatKind::Range(Some(start), Some(end), kind) = &p.kind
             && matches!(kind.node, RangeEnd::Excluded)
+            && is_incomplete_range(start, end)
+            && !in_external_macro(cx.sess(), p.span)
         {
-            let sugg = if self.msrv.meets(msrvs::RANGE_INCLUSIVE) {
-                "..="
-            } else {
-                "..."
-            };
-            check_range(cx, p.span, start, end, Some((kind.span, sugg)));
+            span_lint_and_then(
+                cx,
+                ALMOST_COMPLETE_RANGE,
+                p.span,
+                "almost complete ascii range",
+                |diag| {
+                    diag.span_suggestion(
+                        kind.span,
+                        "use an inclusive range",
+                        if self.msrv.meets(msrvs::RANGE_INCLUSIVE) {
+                            "..=".to_owned()
+                        } else {
+                            "...".to_owned()
+                        },
+                        Applicability::MaybeIncorrect,
+                    );
+                },
+            );
         }
     }
 
     extract_msrv_attr!(EarlyContext);
 }
 
-fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg: Option<(Span, &str)>) {
-    if let ExprKind::Lit(start_token_lit) = start.peel_parens().kind
-        && let ExprKind::Lit(end_token_lit) = end.peel_parens().kind
-        && matches!(
-            (
-                LitKind::from_token_lit(start_token_lit),
-                LitKind::from_token_lit(end_token_lit),
-            ),
-            (
-                Ok(LitKind::Byte(b'a') | LitKind::Char('a')),
-                Ok(LitKind::Byte(b'z') | LitKind::Char('z'))
-            ) | (
-                Ok(LitKind::Byte(b'A') | LitKind::Char('A')),
-                Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')),
-            ) | (
-                Ok(LitKind::Byte(b'0') | LitKind::Char('0')),
-                Ok(LitKind::Byte(b'9') | LitKind::Char('9')),
+fn is_incomplete_range(start: &Expr, end: &Expr) -> bool {
+    match (&start.peel_parens().kind, &end.peel_parens().kind) {
+        (&ExprKind::Lit(start_lit), &ExprKind::Lit(end_lit)) => {
+            matches!(
+                (LitKind::from_token_lit(start_lit), LitKind::from_token_lit(end_lit),),
+                (
+                    Ok(LitKind::Byte(b'a') | LitKind::Char('a')),
+                    Ok(LitKind::Byte(b'z') | LitKind::Char('z'))
+                ) | (
+                    Ok(LitKind::Byte(b'A') | LitKind::Char('A')),
+                    Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')),
+                ) | (
+                    Ok(LitKind::Byte(b'0') | LitKind::Char('0')),
+                    Ok(LitKind::Byte(b'9') | LitKind::Char('9')),
+                )
             )
-        )
-        && !in_external_macro(cx.sess(), span)
-    {
-        span_lint_and_then(cx, ALMOST_COMPLETE_RANGE, span, "almost complete ascii range", |diag| {
-            if let Some((span, sugg)) = sugg {
-                diag.span_suggestion(span, "use an inclusive range", sugg, Applicability::MaybeIncorrect);
-            }
-        });
+        },
+        _ => false,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
index 2003dd1fb0e..ed4cdce8cb8 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
@@ -1,7 +1,8 @@
-use clippy_utils::consts::{constant_with_source, Constant, ConstantSource};
+use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_inside_always_const_context;
 use clippy_utils::macros::{find_assert_args, root_macro_call_first_node, PanicExpn};
-use rustc_hir::{Expr, Item, ItemKind, Node};
+use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
@@ -42,17 +43,16 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
         let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else {
             return;
         };
-        let Some((Constant::Bool(val), source)) = constant_with_source(cx, cx.typeck_results(), condition) else {
+        let Some(Constant::Bool(val)) = constant(cx, cx.typeck_results(), condition) else {
             return;
         };
-        if let ConstantSource::Constant = source
-            && let Node::Item(Item {
-                kind: ItemKind::Const(..),
-                ..
-            }) = cx.tcx.parent_hir_node(e.hir_id)
-        {
-            return;
+
+        match condition.kind {
+            ExprKind::Path(..) | ExprKind::Lit(_) => {},
+            _ if is_inside_always_const_context(cx.tcx, e.hir_id) => return,
+            _ => {},
         }
+
         if val {
             span_lint_and_help(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
index 406f38f411e..0de0031ed24 100644
--- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs
+++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
@@ -1,18 +1,16 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::macros::HirNode;
 use clippy_utils::mir::{enclosing_mir, PossibleBorrowerMap};
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{is_trait_method, local_is_initialized, path_to_local};
+use clippy_utils::{is_diag_trait_item, last_path_segment, local_is_initialized, path_to_local};
 use rustc_errors::Applicability;
 use rustc_hir::{self as hir, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir;
 use rustc_middle::ty::{self, Instance, Mutability};
 use rustc_session::impl_lint_pass;
-use rustc_span::def_id::DefId;
 use rustc_span::symbol::sym;
-use rustc_span::{ExpnKind, Span, SyntaxContext};
+use rustc_span::{Span, SyntaxContext};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -68,165 +66,82 @@ impl AssigningClones {
 impl_lint_pass!(AssigningClones => [ASSIGNING_CLONES]);
 
 impl<'tcx> LateLintPass<'tcx> for AssigningClones {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, assign_expr: &'tcx Expr<'_>) {
-        // Do not fire the lint in macros
-        let ctxt = assign_expr.span().ctxt();
-        let expn_data = ctxt.outer_expn_data();
-        match expn_data.kind {
-            ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) | ExpnKind::Macro(..) => return,
-            ExpnKind::Root => {},
-        }
-
-        let ExprKind::Assign(lhs, rhs, _span) = assign_expr.kind else {
-            return;
-        };
-
-        let Some(call) = extract_call(cx, rhs) else {
-            return;
-        };
-
-        if is_ok_to_suggest(cx, lhs, &call, &self.msrv) {
-            suggest(cx, ctxt, assign_expr, lhs, &call);
-        }
-    }
-
-    extract_msrv_attr!(LateContext);
-}
-
-// Try to resolve the call to `Clone::clone` or `ToOwned::to_owned`.
-fn extract_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<CallCandidate<'tcx>> {
-    let fn_def_id = clippy_utils::fn_def_id(cx, expr)?;
-
-    // Fast paths to only check method calls without arguments or function calls with a single argument
-    let (target, kind, resolved_method) = match expr.kind {
-        ExprKind::MethodCall(path, receiver, [], _span) => {
-            let args = cx.typeck_results().node_args(expr.hir_id);
-
-            // If we could not resolve the method, don't apply the lint
-            let Ok(Some(resolved_method)) = Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args) else {
-                return None;
-            };
-            if is_trait_method(cx, expr, sym::Clone) && path.ident.name == sym::clone {
-                (TargetTrait::Clone, CallKind::MethodCall { receiver }, resolved_method)
-            } else if is_trait_method(cx, expr, sym::ToOwned) && path.ident.name.as_str() == "to_owned" {
-                (TargetTrait::ToOwned, CallKind::MethodCall { receiver }, resolved_method)
-            } else {
-                return None;
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
+        if let ExprKind::Assign(lhs, rhs, _) = e.kind
+            && let typeck = cx.typeck_results()
+            && let (call_kind, fn_name, fn_id, fn_arg, fn_gen_args) = match rhs.kind {
+                ExprKind::Call(f, [arg])
+                    if let ExprKind::Path(fn_path) = &f.kind
+                        && let Some(id) = typeck.qpath_res(fn_path, f.hir_id).opt_def_id() =>
+                {
+                    (CallKind::Ufcs, last_path_segment(fn_path).ident.name, id, arg, typeck.node_args(f.hir_id))
+                },
+                ExprKind::MethodCall(name, recv, [], _) if let Some(id) = typeck.type_dependent_def_id(rhs.hir_id) => {
+                    (CallKind::Method, name.ident.name, id, recv, typeck.node_args(rhs.hir_id))
+                },
+                _ => return,
             }
-        },
-        ExprKind::Call(function, [arg]) => {
-            let kind = cx.typeck_results().node_type(function.hir_id).kind();
-
-            // If we could not resolve the method, don't apply the lint
-            let Ok(Some(resolved_method)) = (match kind {
-                ty::FnDef(_, args) => Instance::try_resolve(cx.tcx, cx.param_env, fn_def_id, args),
-                _ => Ok(None),
-            }) else {
-                return None;
-            };
-            if cx.tcx.is_diagnostic_item(sym::to_owned_method, fn_def_id) {
-                (
-                    TargetTrait::ToOwned,
-                    CallKind::FunctionCall { self_arg: arg },
-                    resolved_method,
-                )
-            } else if let Some(trait_did) = cx.tcx.trait_of_item(fn_def_id)
-                && cx.tcx.is_diagnostic_item(sym::Clone, trait_did)
-            {
-                (
-                    TargetTrait::Clone,
-                    CallKind::FunctionCall { self_arg: arg },
-                    resolved_method,
-                )
-            } else {
-                return None;
+            && let ctxt = e.span.ctxt()
+            // Don't lint in macros.
+            && ctxt.is_root()
+            && let which_trait = match fn_name {
+                sym::clone if is_diag_trait_item(cx, fn_id, sym::Clone) => CloneTrait::Clone,
+                _ if fn_name.as_str() == "to_owned"
+                    && is_diag_trait_item(cx, fn_id, sym::ToOwned)
+                    && self.msrv.meets(msrvs::CLONE_INTO) =>
+                {
+                    CloneTrait::ToOwned
+                },
+                _ => return,
             }
-        },
-        _ => return None,
-    };
-
-    Some(CallCandidate {
-        span: expr.span,
-        target,
-        kind,
-        method_def_id: resolved_method.def_id(),
-    })
-}
-
-// Return true if we find that the called method has a custom implementation and isn't derived or
-// provided by default by the corresponding trait.
-fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallCandidate<'tcx>, msrv: &Msrv) -> bool {
-    // For calls to .to_owned we suggest using .clone_into(), which was only stablilized in 1.63.
-    // If the current MSRV is below that, don't suggest the lint.
-    if !msrv.meets(msrvs::CLONE_INTO) && matches!(call.target, TargetTrait::ToOwned) {
-        return false;
-    }
-
-    // If the left-hand side is a local variable, it might be uninitialized at this point.
-    // In that case we do not want to suggest the lint.
-    if let Some(local) = path_to_local(lhs) {
-        // TODO: This check currently bails if the local variable has no initializer.
-        // That is overly conservative - the lint should fire even if there was no initializer,
-        // but the variable has been initialized before `lhs` was evaluated.
-        if !local_is_initialized(cx, local) {
-            return false;
-        }
-    }
-
-    let Some(impl_block) = cx.tcx.impl_of_method(call.method_def_id) else {
-        return false;
-    };
-
-    // If the method implementation comes from #[derive(Clone)], then don't suggest the lint.
-    // Automatically generated Clone impls do not currently override `clone_from`.
-    // See e.g. https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305 for more details.
-    if cx.tcx.is_builtin_derived(impl_block) {
-        return false;
-    }
-
-    // If the call expression is inside an impl block that contains the method invoked by the
-    // call expression, we bail out to avoid suggesting something that could result in endless
-    // recursion.
-    if let Some(local_block_id) = impl_block.as_local()
-        && let Some(block) = cx.tcx.hir_node_by_def_id(local_block_id).as_owner()
-    {
-        let impl_block_owner = block.def_id();
-        if cx
-            .tcx
-            .hir()
-            .parent_id_iter(lhs.hir_id)
-            .any(|parent| parent.owner == impl_block_owner)
+            && let Ok(Some(resolved_fn)) = Instance::try_resolve(cx.tcx, cx.param_env, fn_id, fn_gen_args)
+            // TODO: This check currently bails if the local variable has no initializer.
+            // That is overly conservative - the lint should fire even if there was no initializer,
+            // but the variable has been initialized before `lhs` was evaluated.
+            && path_to_local(lhs).map_or(true, |lhs| local_is_initialized(cx, lhs))
+            && let Some(resolved_impl) = cx.tcx.impl_of_method(resolved_fn.def_id())
+            // Derived forms don't implement `clone_from`/`clone_into`.
+            // See https://github.com/rust-lang/rust/pull/98445#issuecomment-1190681305
+            && !cx.tcx.is_builtin_derived(resolved_impl)
+            // Don't suggest calling a function we're implementing.
+            && resolved_impl.as_local().map_or(true, |block_id| {
+                cx.tcx.hir().parent_owner_iter(e.hir_id).all(|(id, _)| id.def_id != block_id)
+            })
+            && let resolved_assoc_items = cx.tcx.associated_items(resolved_impl)
+            // Only suggest if `clone_from`/`clone_into` is explicitly implemented
+            && resolved_assoc_items.in_definition_order().any(|assoc|
+                match which_trait {
+                    CloneTrait::Clone => assoc.name == sym::clone_from,
+                    CloneTrait::ToOwned => assoc.name.as_str() == "clone_into",
+                }
+            )
+            && !clone_source_borrows_from_dest(cx, lhs, rhs.span)
         {
-            return false;
+            span_lint_and_then(
+                cx,
+                ASSIGNING_CLONES,
+                e.span,
+                match which_trait {
+                    CloneTrait::Clone => "assigning the result of `Clone::clone()` may be inefficient",
+                    CloneTrait::ToOwned => "assigning the result of `ToOwned::to_owned()` may be inefficient",
+                },
+                |diag| {
+                    let mut app = Applicability::Unspecified;
+                    diag.span_suggestion(
+                        e.span,
+                        match which_trait {
+                            CloneTrait::Clone => "use `clone_from()`",
+                            CloneTrait::ToOwned => "use `clone_into()`",
+                        },
+                        build_sugg(cx, ctxt, lhs, fn_arg, which_trait, call_kind, &mut app),
+                        app,
+                    );
+                },
+            );
         }
     }
 
-    // Find the function for which we want to check that it is implemented.
-    let provided_fn = match call.target {
-        TargetTrait::Clone => cx.tcx.get_diagnostic_item(sym::Clone).and_then(|clone| {
-            cx.tcx
-                .provided_trait_methods(clone)
-                .find(|item| item.name == sym::clone_from)
-        }),
-        TargetTrait::ToOwned => cx.tcx.get_diagnostic_item(sym::ToOwned).and_then(|to_owned| {
-            cx.tcx
-                .provided_trait_methods(to_owned)
-                .find(|item| item.name.as_str() == "clone_into")
-        }),
-    };
-    let Some(provided_fn) = provided_fn else {
-        return false;
-    };
-
-    if clone_source_borrows_from_dest(cx, lhs, call.span) {
-        return false;
-    }
-
-    // Now take a look if the impl block defines an implementation for the method that we're interested
-    // in. If not, then we're using a default implementation, which is not interesting, so we will
-    // not suggest the lint.
-    let implemented_fns = cx.tcx.impl_item_implementor_ids(impl_block);
-    implemented_fns.contains_key(&provided_fn.def_id)
+    extract_msrv_attr!(LateContext);
 }
 
 /// Checks if the data being cloned borrows from the place that is being assigned to:
@@ -239,16 +154,6 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC
 ///
 /// This cannot be written `s2.clone_into(&mut s)` because it has conflicting borrows.
 fn clone_source_borrows_from_dest(cx: &LateContext<'_>, lhs: &Expr<'_>, call_span: Span) -> bool {
-    /// If this basic block only exists to drop a local as part of an assignment, returns its
-    /// successor. Otherwise returns the basic block that was passed in.
-    fn skip_drop_block(mir: &mir::Body<'_>, bb: mir::BasicBlock) -> mir::BasicBlock {
-        if let mir::TerminatorKind::Drop { target, .. } = mir.basic_blocks[bb].terminator().kind {
-            target
-        } else {
-            bb
-        }
-    }
-
     let Some(mir) = enclosing_mir(cx.tcx, lhs.hir_id) else {
         return false;
     };
@@ -267,172 +172,123 @@ fn clone_source_borrows_from_dest(cx: &LateContext<'_>, lhs: &Expr<'_>, call_spa
     //
     // bb2:
     //  s = s_temp
-    for bb in mir.basic_blocks.iter() {
-        let terminator = bb.terminator();
-
-        // Look for the to_owned/clone call.
-        if terminator.source_info.span != call_span {
-            continue;
+    if let Some(terminator) = mir.basic_blocks.iter()
+            .map(mir::BasicBlockData::terminator)
+            .find(|term| term.source_info.span == call_span)
+        && let mir::TerminatorKind::Call { ref args, target: Some(assign_bb), .. } = terminator.kind
+        && let [source] = &**args
+        && let mir::Operand::Move(source) = &source.node
+        && let assign_bb = &mir.basic_blocks[assign_bb]
+        && let assign_bb = match assign_bb.terminator().kind {
+            // Skip the drop of the assignment's destination.
+            mir::TerminatorKind::Drop { target, .. } => &mir.basic_blocks[target],
+            _ => assign_bb,
         }
-
-        if let mir::TerminatorKind::Call { ref args, target: Some(assign_bb), .. } = terminator.kind
-            && let [source] = &**args
-            && let mir::Operand::Move(source) = &source.node
-            && let assign_bb = skip_drop_block(mir, assign_bb)
-            // Skip any storage statements as they are just noise
-            && let Some(assignment) = mir.basic_blocks[assign_bb].statements
-                .iter()
-                .find(|stmt| {
-                    !matches!(stmt.kind, mir::StatementKind::StorageDead(_) | mir::StatementKind::StorageLive(_))
-                })
-            && let mir::StatementKind::Assign(box (borrowed, _)) = &assignment.kind
-            && let Some(borrowers) = borrow_map.get(&borrowed.local)
-            && borrowers.contains(source.local)
-        {
-            return true;
-        }
-
-        return false;
+        // Skip any storage statements as they are just noise
+        && let Some(assignment) = assign_bb.statements
+            .iter()
+            .find(|stmt| {
+                !matches!(stmt.kind, mir::StatementKind::StorageDead(_) | mir::StatementKind::StorageLive(_))
+            })
+        && let mir::StatementKind::Assign(box (borrowed, _)) = &assignment.kind
+        && let Some(borrowers) = borrow_map.get(&borrowed.local)
+    {
+        borrowers.contains(source.local)
+    } else {
+        false
     }
-    false
-}
-
-fn suggest<'tcx>(
-    cx: &LateContext<'tcx>,
-    ctxt: SyntaxContext,
-    assign_expr: &Expr<'tcx>,
-    lhs: &Expr<'tcx>,
-    call: &CallCandidate<'tcx>,
-) {
-    span_lint_and_then(cx, ASSIGNING_CLONES, assign_expr.span, call.message(), |diag| {
-        let mut applicability = Applicability::Unspecified;
-
-        diag.span_suggestion(
-            assign_expr.span,
-            call.suggestion_msg(),
-            call.suggested_replacement(cx, ctxt, lhs, &mut applicability),
-            applicability,
-        );
-    });
 }
 
-#[derive(Copy, Clone, Debug)]
-enum CallKind<'tcx> {
-    MethodCall { receiver: &'tcx Expr<'tcx> },
-    FunctionCall { self_arg: &'tcx Expr<'tcx> },
-}
-
-#[derive(Copy, Clone, Debug)]
-enum TargetTrait {
+#[derive(Clone, Copy)]
+enum CloneTrait {
     Clone,
     ToOwned,
 }
 
-#[derive(Debug)]
-struct CallCandidate<'tcx> {
-    span: Span,
-    target: TargetTrait,
-    kind: CallKind<'tcx>,
-    // DefId of the called method from an impl block that implements the target trait
-    method_def_id: DefId,
+#[derive(Copy, Clone)]
+enum CallKind {
+    Ufcs,
+    Method,
 }
 
-impl<'tcx> CallCandidate<'tcx> {
-    #[inline]
-    fn message(&self) -> &'static str {
-        match self.target {
-            TargetTrait::Clone => "assigning the result of `Clone::clone()` may be inefficient",
-            TargetTrait::ToOwned => "assigning the result of `ToOwned::to_owned()` may be inefficient",
-        }
-    }
-
-    #[inline]
-    fn suggestion_msg(&self) -> &'static str {
-        match self.target {
-            TargetTrait::Clone => "use `clone_from()`",
-            TargetTrait::ToOwned => "use `clone_into()`",
-        }
-    }
-
-    fn suggested_replacement(
-        &self,
-        cx: &LateContext<'tcx>,
-        ctxt: SyntaxContext,
-        lhs: &Expr<'tcx>,
-        applicability: &mut Applicability,
-    ) -> String {
-        match self.target {
-            TargetTrait::Clone => {
-                match self.kind {
-                    CallKind::MethodCall { receiver } => {
-                        let receiver_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
-                            // `*lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)`
-                            Sugg::hir_with_applicability(cx, ref_expr, "_", applicability)
-                        } else {
-                            // `lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)`
-                            Sugg::hir_with_applicability(cx, lhs, "_", applicability)
-                        }
-                        .maybe_par();
-
-                        // Determine whether we need to reference the argument to clone_from().
-                        let clone_receiver_type = cx.typeck_results().expr_ty(receiver);
-                        let clone_receiver_adj_type = cx.typeck_results().expr_ty_adjusted(receiver);
-                        let mut arg_sugg = Sugg::hir_with_context(cx, receiver, ctxt, "_", applicability);
-                        if clone_receiver_type != clone_receiver_adj_type {
-                            // The receiver may have been a value type, so we need to add an `&` to
-                            // be sure the argument to clone_from will be a reference.
-                            arg_sugg = arg_sugg.addr();
-                        };
-
-                        format!("{receiver_sugg}.clone_from({arg_sugg})")
-                    },
-                    CallKind::FunctionCall { self_arg, .. } => {
-                        let self_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
-                            // `*lhs = Clone::clone(self_expr);` -> `Clone::clone_from(lhs, self_expr)`
-                            Sugg::hir_with_applicability(cx, ref_expr, "_", applicability)
-                        } else {
-                            // `lhs = Clone::clone(self_expr);` -> `Clone::clone_from(&mut lhs, self_expr)`
-                            Sugg::hir_with_applicability(cx, lhs, "_", applicability).mut_addr()
-                        };
-                        // The RHS had to be exactly correct before the call, there is no auto-deref for function calls.
-                        let rhs_sugg = Sugg::hir_with_context(cx, self_arg, ctxt, "_", applicability);
-
-                        format!("Clone::clone_from({self_sugg}, {rhs_sugg})")
-                    },
-                }
-            },
-            TargetTrait::ToOwned => {
-                let rhs_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
-                    // `*lhs = rhs.to_owned()` -> `rhs.clone_into(lhs)`
-                    // `*lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, lhs)`
-                    let sugg = Sugg::hir_with_applicability(cx, ref_expr, "_", applicability).maybe_par();
-                    let inner_type = cx.typeck_results().expr_ty(ref_expr);
-                    // If after unwrapping the dereference, the type is not a mutable reference, we add &mut to make it
-                    // deref to a mutable reference.
-                    if matches!(inner_type.kind(), ty::Ref(_, _, Mutability::Mut)) {
-                        sugg
+fn build_sugg<'tcx>(
+    cx: &LateContext<'tcx>,
+    ctxt: SyntaxContext,
+    lhs: &'tcx Expr<'_>,
+    fn_arg: &'tcx Expr<'_>,
+    which_trait: CloneTrait,
+    call_kind: CallKind,
+    app: &mut Applicability,
+) -> String {
+    match which_trait {
+        CloneTrait::Clone => {
+            match call_kind {
+                CallKind::Method => {
+                    let receiver_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
+                        // `*lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)`
+                        Sugg::hir_with_applicability(cx, ref_expr, "_", app)
                     } else {
-                        sugg.mut_addr()
+                        // `lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)`
+                        Sugg::hir_with_applicability(cx, lhs, "_", app)
                     }
+                    .maybe_par();
+
+                    // Determine whether we need to reference the argument to clone_from().
+                    let clone_receiver_type = cx.typeck_results().expr_ty(fn_arg);
+                    let clone_receiver_adj_type = cx.typeck_results().expr_ty_adjusted(fn_arg);
+                    let mut arg_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app);
+                    if clone_receiver_type != clone_receiver_adj_type {
+                        // The receiver may have been a value type, so we need to add an `&` to
+                        // be sure the argument to clone_from will be a reference.
+                        arg_sugg = arg_sugg.addr();
+                    };
+
+                    format!("{receiver_sugg}.clone_from({arg_sugg})")
+                },
+                CallKind::Ufcs => {
+                    let self_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
+                        // `*lhs = Clone::clone(self_expr);` -> `Clone::clone_from(lhs, self_expr)`
+                        Sugg::hir_with_applicability(cx, ref_expr, "_", app)
+                    } else {
+                        // `lhs = Clone::clone(self_expr);` -> `Clone::clone_from(&mut lhs, self_expr)`
+                        Sugg::hir_with_applicability(cx, lhs, "_", app).mut_addr()
+                    };
+                    // The RHS had to be exactly correct before the call, there is no auto-deref for function calls.
+                    let rhs_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app);
+
+                    format!("Clone::clone_from({self_sugg}, {rhs_sugg})")
+                },
+            }
+        },
+        CloneTrait::ToOwned => {
+            let rhs_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
+                // `*lhs = rhs.to_owned()` -> `rhs.clone_into(lhs)`
+                // `*lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, lhs)`
+                let sugg = Sugg::hir_with_applicability(cx, ref_expr, "_", app).maybe_par();
+                let inner_type = cx.typeck_results().expr_ty(ref_expr);
+                // If after unwrapping the dereference, the type is not a mutable reference, we add &mut to make it
+                // deref to a mutable reference.
+                if matches!(inner_type.kind(), ty::Ref(_, _, Mutability::Mut)) {
+                    sugg
                 } else {
-                    // `lhs = rhs.to_owned()` -> `rhs.clone_into(&mut lhs)`
-                    // `lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, &mut lhs)`
-                    Sugg::hir_with_applicability(cx, lhs, "_", applicability)
-                        .maybe_par()
-                        .mut_addr()
-                };
-
-                match self.kind {
-                    CallKind::MethodCall { receiver } => {
-                        let receiver_sugg = Sugg::hir_with_context(cx, receiver, ctxt, "_", applicability);
-                        format!("{receiver_sugg}.clone_into({rhs_sugg})")
-                    },
-                    CallKind::FunctionCall { self_arg, .. } => {
-                        let self_sugg = Sugg::hir_with_context(cx, self_arg, ctxt, "_", applicability);
-                        format!("ToOwned::clone_into({self_sugg}, {rhs_sugg})")
-                    },
+                    sugg.mut_addr()
                 }
-            },
-        }
+            } else {
+                // `lhs = rhs.to_owned()` -> `rhs.clone_into(&mut lhs)`
+                // `lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, &mut lhs)`
+                Sugg::hir_with_applicability(cx, lhs, "_", app).maybe_par().mut_addr()
+            };
+
+            match call_kind {
+                CallKind::Method => {
+                    let receiver_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app);
+                    format!("{receiver_sugg}.clone_into({rhs_sugg})")
+                },
+                CallKind::Ufcs => {
+                    let self_sugg = Sugg::hir_with_context(cx, fn_arg, ctxt, "_", app);
+                    format!("ToOwned::clone_into({self_sugg}, {rhs_sugg})")
+                },
+            }
+        },
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
index f25a474d9bb..d4a1e2780d0 100644
--- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
+++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
@@ -11,21 +11,25 @@ use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for calls to await while holding a non-async-aware MutexGuard.
+    /// Checks for calls to `await` while holding a non-async-aware
+    /// `MutexGuard`.
     ///
     /// ### Why is this bad?
-    /// The Mutex types found in std::sync and parking_lot
-    /// are not designed to operate in an async context across await points.
+    /// The Mutex types found in [`std::sync`][https://doc.rust-lang.org/stable/std/sync/] and
+    /// [`parking_lot`](https://docs.rs/parking_lot/latest/parking_lot/) are
+    /// not designed to operate in an async context across await points.
     ///
-    /// There are two potential solutions. One is to use an async-aware Mutex
-    /// type. Many asynchronous foundation crates provide such a Mutex type. The
-    /// other solution is to ensure the mutex is unlocked before calling await,
-    /// either by introducing a scope or an explicit call to Drop::drop.
+    /// There are two potential solutions. One is to use an async-aware `Mutex`
+    /// type. Many asynchronous foundation crates provide such a `Mutex` type.
+    /// The other solution is to ensure the mutex is unlocked before calling
+    /// `await`, either by introducing a scope or an explicit call to
+    /// [`Drop::drop`](https://doc.rust-lang.org/std/ops/trait.Drop.html).
     ///
     /// ### Known problems
     /// Will report false positive for explicitly dropped guards
-    /// ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A workaround for this is
-    /// to wrap the `.lock()` call in a block instead of explicitly dropping the guard.
+    /// ([#6446](https://github.com/rust-lang/rust-clippy/issues/6446)). A
+    /// workaround for this is to wrap the `.lock()` call in a block instead of
+    /// explicitly dropping the guard.
     ///
     /// ### Example
     /// ```no_run
@@ -73,11 +77,11 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for calls to await while holding a `RefCell` `Ref` or `RefMut`.
+    /// Checks for calls to `await` while holding a `RefCell`, `Ref`, or `RefMut`.
     ///
     /// ### Why is this bad?
     /// `RefCell` refs only check for exclusive mutable access
-    /// at runtime. Holding onto a `RefCell` ref across an `await` suspension point
+    /// at runtime. Holding a `RefCell` ref across an await suspension point
     /// risks panics from a mutable ref shared while other refs are outstanding.
     ///
     /// ### Known problems
@@ -131,13 +135,13 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Allows users to configure types which should not be held across `await`
+    /// Allows users to configure types which should not be held across await
     /// suspension points.
     ///
     /// ### Why is this bad?
-    /// There are some types which are perfectly "safe" to be used concurrently
-    /// from a memory access perspective but will cause bugs at runtime if they
-    /// are held in such a way.
+    /// There are some types which are perfectly safe to use concurrently from
+    /// a memory access perspective, but that will cause bugs at runtime if
+    /// they are held in such a way.
     ///
     /// ### Example
     ///
@@ -228,15 +232,15 @@ impl AwaitHolding {
                         cx,
                         AWAIT_HOLDING_LOCK,
                         ty_cause.source_info.span,
-                        "this `MutexGuard` is held across an `await` point",
+                        "this `MutexGuard` is held across an await point",
                         |diag| {
                             diag.help(
                                 "consider using an async-aware `Mutex` type or ensuring the \
-                                `MutexGuard` is dropped before calling await",
+                                `MutexGuard` is dropped before calling `await`",
                             );
                             diag.span_note(
                                 await_points(),
-                                "these are all the `await` points this lock is held through",
+                                "these are all the await points this lock is held through",
                             );
                         },
                     );
@@ -245,12 +249,12 @@ impl AwaitHolding {
                         cx,
                         AWAIT_HOLDING_REFCELL_REF,
                         ty_cause.source_info.span,
-                        "this `RefCell` reference is held across an `await` point",
+                        "this `RefCell` reference is held across an await point",
                         |diag| {
                             diag.help("ensure the reference is dropped before calling `await`");
                             diag.span_note(
                                 await_points(),
-                                "these are all the `await` points this reference is held through",
+                                "these are all the await points this reference is held through",
                             );
                         },
                     );
@@ -268,7 +272,7 @@ fn emit_invalid_type(cx: &LateContext<'_>, span: Span, disallowed: &DisallowedPa
         AWAIT_HOLDING_INVALID_TYPE,
         span,
         format!(
-            "`{}` may not be held across an `await` point per `clippy.toml`",
+            "`{}` may not be held across an await point per `clippy.toml`",
             disallowed.path()
         ),
         |diag| {
diff --git a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
index cfb76cab6dc..561ca9bd986 100644
--- a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
@@ -1,13 +1,11 @@
-use clippy_utils::higher::If;
-use rustc_ast::LitKind;
-use rustc_hir::{Block, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_lint_pass;
-
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{in_constant, is_else_clause, is_integer_literal};
+use clippy_utils::{in_constant, is_else_clause};
+use rustc_ast::LitKind;
 use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -47,80 +45,64 @@ declare_clippy_lint! {
 declare_lint_pass!(BoolToIntWithIf => [BOOL_TO_INT_WITH_IF]);
 
 impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
-        if !expr.span.from_expansion() && !in_constant(cx, expr.hir_id) {
-            check_if_else(cx, expr);
-        }
-    }
-}
-
-fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
-    if let Some(If {
-        cond,
-        then,
-        r#else: Some(r#else),
-    }) = If::hir(expr)
-        && let Some(then_lit) = int_literal(then)
-        && let Some(else_lit) = int_literal(r#else)
-    {
-        let inverted = if is_integer_literal(then_lit, 1) && is_integer_literal(else_lit, 0) {
-            false
-        } else if is_integer_literal(then_lit, 0) && is_integer_literal(else_lit, 1) {
-            true
-        } else {
-            // Expression isn't boolean, exit
-            return;
-        };
-        let mut applicability = Applicability::MachineApplicable;
-        let snippet = {
-            let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
-            if inverted {
-                sugg = !sugg;
-            }
-            sugg
-        };
-
-        let ty = cx.typeck_results().expr_ty(then_lit); // then and else must be of same type
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        if let ExprKind::If(cond, then, Some(else_)) = expr.kind
+            && matches!(cond.kind, ExprKind::DropTemps(_))
+            && let Some(then_lit) = as_int_bool_lit(then)
+            && let Some(else_lit) = as_int_bool_lit(else_)
+            && then_lit != else_lit
+            && !expr.span.from_expansion()
+            && !in_constant(cx, expr.hir_id)
+        {
+            let ty = cx.typeck_results().expr_ty(then);
+            let mut applicability = Applicability::MachineApplicable;
+            let snippet = {
+                let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
+                if !then_lit {
+                    sugg = !sugg;
+                }
+                sugg
+            };
+            let suggestion = {
+                let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into());
+                // when used in else clause if statement should be wrapped in curly braces
+                if is_else_clause(cx.tcx, expr) {
+                    s = s.blockify();
+                }
+                s
+            };
 
-        let suggestion = {
-            let wrap_in_curly = is_else_clause(cx.tcx, expr);
-            let mut s = Sugg::NonParen(format!("{ty}::from({snippet})").into());
-            if wrap_in_curly {
-                s = s.blockify();
-            }
-            s
-        }; // when used in else clause if statement should be wrapped in curly braces
+            let into_snippet = snippet.clone().maybe_par();
+            let as_snippet = snippet.as_ty(ty);
 
-        let into_snippet = snippet.clone().maybe_par();
-        let as_snippet = snippet.as_ty(ty);
-
-        span_lint_and_then(
-            cx,
-            BOOL_TO_INT_WITH_IF,
-            expr.span,
-            "boolean to int conversion using if",
-            |diag| {
-                diag.span_suggestion(expr.span, "replace with from", suggestion, applicability);
-                diag.note(format!(
-                    "`{as_snippet}` or `{into_snippet}.into()` can also be valid options"
-                ));
-            },
-        );
-    };
+            span_lint_and_then(
+                cx,
+                BOOL_TO_INT_WITH_IF,
+                expr.span,
+                "boolean to int conversion using if",
+                |diag| {
+                    diag.span_suggestion(expr.span, "replace with from", suggestion, applicability);
+                    diag.note(format!(
+                        "`{as_snippet}` or `{into_snippet}.into()` can also be valid options"
+                    ));
+                },
+            );
+        }
+    }
 }
 
-// If block contains only a int literal expression, return literal expression
-fn int_literal<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>) -> Option<&'tcx rustc_hir::Expr<'tcx>> {
-    if let ExprKind::Block(block, _) = expr.kind
-        && let Block {
-            stmts: [], // Shouldn't lint if statements with side effects
-            expr: Some(expr),
-            ..
-        } = block
-        && let ExprKind::Lit(lit) = &expr.kind
-        && let LitKind::Int(_, _) = lit.node
+fn as_int_bool_lit(e: &Expr<'_>) -> Option<bool> {
+    if let ExprKind::Block(b, _) = e.kind
+        && b.stmts.is_empty()
+        && let Some(e) = b.expr
+        && let ExprKind::Lit(lit) = e.kind
+        && let LitKind::Int(x, _) = lit.node
     {
-        Some(expr)
+        match x.get() {
+            0 => Some(false),
+            1 => Some(true),
+            _ => None,
+        }
     } else {
         None
     }
diff --git a/src/tools/clippy/clippy_lints/src/byte_char_slices.rs b/src/tools/clippy/clippy_lints/src/byte_char_slices.rs
new file mode 100644
index 00000000000..a9fe190f177
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/byte_char_slices.rs
@@ -0,0 +1,80 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use rustc_ast::ast::{BorrowKind, Expr, ExprKind, Mutability};
+use rustc_ast::token::{Lit, LitKind};
+use rustc_errors::Applicability;
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::declare_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for hard to read slices of byte characters, that could be more easily expressed as a
+    /// byte string.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// Potentially makes the string harder to read.
+    ///
+    /// ### Example
+    /// ```ignore
+    /// &[b'H', b'e', b'l', b'l', b'o'];
+    /// ```
+    /// Use instead:
+    /// ```ignore
+    /// b"Hello"
+    /// ```
+    #[clippy::version = "1.68.0"]
+    pub BYTE_CHAR_SLICES,
+    style,
+    "hard to read byte char slice"
+}
+declare_lint_pass!(ByteCharSlice => [BYTE_CHAR_SLICES]);
+
+impl EarlyLintPass for ByteCharSlice {
+    fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
+        if let Some(slice) = is_byte_char_slices(expr)
+            && !expr.span.from_expansion()
+        {
+            span_lint_and_sugg(
+                cx,
+                BYTE_CHAR_SLICES,
+                expr.span,
+                "can be more succinctly written as a byte str",
+                "try",
+                format!("b\"{slice}\""),
+                Applicability::MaybeIncorrect,
+            );
+        }
+    }
+}
+
+fn is_byte_char_slices(expr: &Expr) -> Option<String> {
+    if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, expr) = &expr.kind {
+        match &expr.kind {
+            ExprKind::Array(members) => {
+                if members.is_empty() {
+                    return None;
+                }
+
+                members
+                    .iter()
+                    .map(|member| match &member.kind {
+                        ExprKind::Lit(Lit {
+                            kind: LitKind::Byte,
+                            symbol,
+                            ..
+                        }) => Some(symbol.as_str()),
+                        _ => None,
+                    })
+                    .map(|maybe_quote| match maybe_quote {
+                        Some("\"") => Some("\\\""),
+                        Some("\\'") => Some("'"),
+                        other => other,
+                    })
+                    .collect::<Option<String>>()
+            },
+            _ => None,
+        }
+    } else {
+        None
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index e60c36ced75..54f0c7c4687 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -32,7 +32,7 @@ use rustc_session::impl_lint_pass;
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts from any numerical to a float type where
+    /// Checks for casts from any numeric type to a float type where
     /// the receiving type cannot store all values from the original type without
     /// rounding errors. This possible rounding is to be expected, so this lint is
     /// `Allow` by default.
@@ -58,14 +58,14 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts from a signed to an unsigned numerical
+    /// Checks for casts from a signed to an unsigned numeric
     /// type. In this case, negative values wrap around to large positive values,
-    /// which can be quite surprising in practice. However, as the cast works as
+    /// which can be quite surprising in practice. However, since the cast works as
     /// defined, this lint is `Allow` by default.
     ///
     /// ### Why is this bad?
     /// Possibly surprising results. You can activate this lint
-    /// as a one-time check to see where numerical wrapping can arise.
+    /// as a one-time check to see where numeric wrapping can arise.
     ///
     /// ### Example
     /// ```no_run
@@ -80,7 +80,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts between numerical types that may
+    /// Checks for casts between numeric types that may
     /// truncate large values. This is expected behavior, so the cast is `Allow` by
     /// default. It suggests user either explicitly ignore the lint,
     /// or use `try_from()` and handle the truncation, default, or panic explicitly.
@@ -120,17 +120,16 @@ declare_clippy_lint! {
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for casts from an unsigned type to a signed type of
-    /// 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
+    /// the same size, or possibly smaller due to target-dependent integers.
+    /// Performing such a cast is a no-op for the compiler (that is, 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.
     ///
     /// ### Why is this bad?
     /// While such a cast is not bad in itself, the results can
-    /// be surprising when this is not the intended behavior, as demonstrated by the
-    /// example below.
+    /// be surprising when this is not the intended behavior:
     ///
     /// ### Example
     /// ```no_run
@@ -144,16 +143,16 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts between numerical types that may
-    /// be replaced by safe conversion functions.
+    /// Checks for casts between numeric types that can be replaced by safe
+    /// conversion functions.
     ///
     /// ### Why is this bad?
-    /// Rust's `as` keyword will perform many kinds of
-    /// conversions, including silently lossy conversions. Conversion functions such
-    /// as `i32::from` will only perform lossless conversions. Using the conversion
-    /// functions prevents conversions from turning into silent lossy conversions if
-    /// the types of the input expressions ever change, and make it easier for
-    /// people reading the code to know that the conversion is lossless.
+    /// Rust's `as` keyword will perform many kinds of conversions, including
+    /// silently lossy conversions. Conversion functions such as `i32::from`
+    /// will only perform lossless conversions. Using the conversion functions
+    /// prevents conversions from becoming silently lossy if the input types
+    /// ever change, and makes it clear for people reading the code that the
+    /// conversion is lossless.
     ///
     /// ### Example
     /// ```no_run
@@ -177,19 +176,21 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// 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.
+    /// 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 that don't change type or constness.
     ///
     /// ### Why is this bad?
     /// It's just unnecessary.
     ///
     /// ### Known problems
-    /// When the expression on the left is a function call, the lint considers the return type to be
-    /// a type alias if it's aliased through a `use` statement
-    /// (like `use std::io::Result as IoResult`). It will not lint such cases.
+    /// When the expression on the left is a function call, the lint considers
+    /// the return type to be a type alias if it's aliased through a `use`
+    /// statement (like `use std::io::Result as IoResult`). It will not lint
+    /// such cases.
     ///
-    /// This check is also rather primitive. It will only work on primitive types without any
-    /// intermediate references, raw pointers and trait objects may or may not work.
+    /// This check will only work on primitive types without any intermediate
+    /// references: raw pointers and trait objects may or may not work.
     ///
     /// ### Example
     /// ```no_run
@@ -211,17 +212,17 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts, using `as` or `pointer::cast`,
-    /// from a less-strictly-aligned pointer to a more-strictly-aligned pointer
+    /// Checks for casts, using `as` or `pointer::cast`, from a
+    /// less strictly aligned pointer to a more strictly aligned pointer.
     ///
     /// ### Why is this bad?
-    /// Dereferencing the resulting pointer may be undefined
-    /// behavior.
+    /// Dereferencing the resulting pointer may be undefined behavior.
     ///
     /// ### Known problems
-    /// Using `std::ptr::read_unaligned` and `std::ptr::write_unaligned` or similar
-    /// on the resulting pointer is fine. Is over-zealous: Casts with manual alignment checks or casts like
-    /// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis.
+    /// Using [`std::ptr::read_unaligned`](https://doc.rust-lang.org/std/ptr/fn.read_unaligned.html) and [`std::ptr::write_unaligned`](https://doc.rust-lang.org/std/ptr/fn.write_unaligned.html) or
+    /// similar on the resulting pointer is fine. Is over-zealous: casts with
+    /// manual alignment checks or casts like `u64` -> `u8` -> `u16` can be
+    /// fine. Miri is able to do a more in-depth analysis.
     ///
     /// ### Example
     /// ```no_run
@@ -234,20 +235,21 @@ declare_clippy_lint! {
     #[clippy::version = "pre 1.29.0"]
     pub CAST_PTR_ALIGNMENT,
     pedantic,
-    "cast from a pointer to a more-strictly-aligned pointer"
+    "cast from a pointer to a more strictly aligned pointer"
 }
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts of function pointers to something other than usize
+    /// Checks for casts of function pointers to something other than `usize`.
     ///
     /// ### Why is this bad?
-    /// Casting a function pointer to anything other than usize/isize is not portable across
-    /// architectures, because you end up losing bits if the target type is too small or end up with a
-    /// bunch of extra bits that waste space and add more instructions to the final binary than
-    /// strictly necessary for the problem
+    /// Casting a function pointer to anything other than `usize`/`isize` is
+    /// not portable across architectures. If the target type is too small the
+    /// address would be truncated, and target types larger than `usize` are
+    /// unnecessary.
     ///
-    /// Casting to isize also doesn't make sense since there are no signed addresses.
+    /// Casting to `isize` also doesn't make sense, since addresses are never
+    /// signed.
     ///
     /// ### Example
     /// ```no_run
@@ -263,17 +265,17 @@ declare_clippy_lint! {
     #[clippy::version = "pre 1.29.0"]
     pub FN_TO_NUMERIC_CAST,
     style,
-    "casting a function pointer to a numeric type other than usize"
+    "casting a function pointer to a numeric type other than `usize`"
 }
 
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for casts of a function pointer to a numeric type not wide enough to
-    /// store address.
+    /// store an address.
     ///
     /// ### Why is this bad?
     /// Such a cast discards some bits of the function's address. If this is intended, it would be more
-    /// clearly expressed by casting to usize first, then casting the usize to the intended type (with
+    /// clearly expressed by casting to `usize` first, then casting the `usize` to the intended type (with
     /// a comment) to perform the truncation.
     ///
     /// ### Example
@@ -306,7 +308,7 @@ declare_clippy_lint! {
     /// ### Why restrict this?
     /// Casting a function pointer to an integer can have surprising results and can occur
     /// accidentally if parentheses are omitted from a function call. If you aren't doing anything
-    /// low-level with function pointers then you can opt-out of casting functions to integers in
+    /// low-level with function pointers then you can opt out of casting functions to integers in
     /// order to avoid mistakes. Alternatively, you can use this lint to audit all uses of function
     /// pointer casts in your code.
     ///
@@ -349,8 +351,8 @@ declare_clippy_lint! {
     /// ### Why is this bad?
     /// In general, casting values to smaller types is
     /// error-prone and should be avoided where possible. In the particular case of
-    /// converting a character literal to u8, it is easy to avoid by just using a
-    /// byte literal instead. As an added bonus, `b'a'` is even slightly shorter
+    /// converting a character literal to `u8`, it is easy to avoid by just using a
+    /// byte literal instead. As an added bonus, `b'a'` is also slightly shorter
     /// than `'a' as u8`.
     ///
     /// ### Example
@@ -371,12 +373,13 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for `as` casts between raw pointers without changing its mutability,
-    /// namely `*const T` to `*const U` and `*mut T` to `*mut U`.
+    /// Checks for `as` casts between raw pointers that don't change their
+    /// constness, namely `*const T` to `*const U` and `*mut T` to `*mut U`.
     ///
     /// ### Why is this bad?
-    /// Though `as` casts between raw pointers are not terrible, `pointer::cast` is safer because
-    /// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`.
+    /// Though `as` casts between raw pointers are not terrible,
+    /// `pointer::cast` is safer because it cannot accidentally change the
+    /// pointer's mutability, nor cast the pointer to other types like `usize`.
     ///
     /// ### Example
     /// ```no_run
@@ -395,12 +398,12 @@ declare_clippy_lint! {
     #[clippy::version = "1.51.0"]
     pub PTR_AS_PTR,
     pedantic,
-    "casting using `as` from and to raw pointers that doesn't change its mutability, where `pointer::cast` could take the place of `as`"
+    "casting using `as` between raw pointers that doesn't change their constness, where `pointer::cast` could take the place of `as`"
 }
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for `as` casts between raw pointers which change its constness, namely `*const T` to
+    /// Checks for `as` casts between raw pointers that change their constness, namely `*const T` to
     /// `*mut T` and `*mut T` to `*const T`.
     ///
     /// ### Why is this bad?
@@ -423,12 +426,12 @@ declare_clippy_lint! {
     #[clippy::version = "1.72.0"]
     pub PTR_CAST_CONSTNESS,
     pedantic,
-    "casting using `as` from and to raw pointers to change constness when specialized methods apply"
+    "casting using `as` on raw pointers to change constness when specialized methods apply"
 }
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for casts from an enum type to an integral type which will definitely truncate the
+    /// Checks for casts from an enum type to an integral type that will definitely truncate the
     /// value.
     ///
     /// ### Why is this bad?
@@ -442,7 +445,7 @@ declare_clippy_lint! {
     #[clippy::version = "1.61.0"]
     pub CAST_ENUM_TRUNCATION,
     suspicious,
-    "casts from an enum type to an integral type which will truncate the value"
+    "casts from an enum type to an integral type that will truncate the value"
 }
 
 declare_clippy_lint! {
@@ -621,7 +624,7 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer
+    /// Checks for the result of a `&self`-taking `as_ptr` being cast to a mutable pointer.
     ///
     /// ### Why is this bad?
     /// Since `as_ptr` takes a `&self`, the pointer won't have write permissions unless interior
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
index 2c168405ee2..86c5f6b9f0b 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
@@ -92,7 +92,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: &Msrv) {
             cx,
             PTR_AS_PTR,
             expr.span,
-            "`as` casting between raw pointers without changing its mutability",
+            "`as` casting between raw pointers without changing their constness",
             help,
             final_suggestion,
             app,
diff --git a/src/tools/clippy/clippy_lints/src/cfg_not_test.rs b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs
new file mode 100644
index 00000000000..b54f392bf2f
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/cfg_not_test.rs
@@ -0,0 +1,60 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_ast::NestedMetaItem;
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_session::declare_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `cfg` that excludes code from `test` builds. (i.e., `#{cfg(not(test))]`)
+    ///
+    /// ### Why is this bad?
+    /// This may give the false impression that a codebase has 100% coverage, yet actually has untested code.
+    /// Enabling this also guards against excessive mockery as well, which is an anti-pattern.
+    ///
+    /// ### Example
+    /// ```rust
+    /// # fn important_check() {}
+    /// #[cfg(not(test))]
+    /// important_check(); // I'm not actually tested, but not including me will falsely increase coverage!
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// # fn important_check() {}
+    /// important_check();
+    /// ```
+    #[clippy::version = "1.73.0"]
+    pub CFG_NOT_TEST,
+    restriction,
+    "enforce against excluding code from test builds"
+}
+
+declare_lint_pass!(CfgNotTest => [CFG_NOT_TEST]);
+
+impl EarlyLintPass for CfgNotTest {
+    fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &rustc_ast::Attribute) {
+        if attr.has_name(rustc_span::sym::cfg) && contains_not_test(attr.meta_item_list().as_deref(), false) {
+            span_lint_and_then(
+                cx,
+                CFG_NOT_TEST,
+                attr.span,
+                "code is excluded from test builds",
+                |diag| {
+                    diag.help("consider not excluding any code from test builds");
+                    diag.note_once("this could increase code coverage despite not actually being tested");
+                },
+            );
+        }
+    }
+}
+
+fn contains_not_test(list: Option<&[NestedMetaItem]>, not: bool) -> bool {
+    list.is_some_and(|list| {
+        list.iter().any(|item| {
+            item.ident().is_some_and(|ident| match ident.name {
+                rustc_span::sym::not => contains_not_test(item.meta_item_list(), !not),
+                rustc_span::sym::test => not,
+                _ => contains_not_test(item.meta_item_list(), not),
+            })
+        })
+    })
+}
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 638de5e818c..eabc67601a2 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -8,8 +8,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     #[cfg(feature = "internal")]
     crate::utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS_INFO,
     #[cfg(feature = "internal")]
-    crate::utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS_INFO,
-    #[cfg(feature = "internal")]
     crate::utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL_INFO,
     #[cfg(feature = "internal")]
     crate::utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR_INFO,
@@ -73,6 +71,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::booleans::OVERLY_COMPLEX_BOOL_EXPR_INFO,
     crate::borrow_deref_ref::BORROW_DEREF_REF_INFO,
     crate::box_default::BOX_DEFAULT_INFO,
+    crate::byte_char_slices::BYTE_CHAR_SLICES_INFO,
     crate::cargo::CARGO_COMMON_METADATA_INFO,
     crate::cargo::LINT_GROUPS_PRIORITY_INFO,
     crate::cargo::MULTIPLE_CRATE_VERSIONS_INFO,
@@ -103,6 +102,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::casts::REF_AS_PTR_INFO,
     crate::casts::UNNECESSARY_CAST_INFO,
     crate::casts::ZERO_PTR_INFO,
+    crate::cfg_not_test::CFG_NOT_TEST_INFO,
     crate::checked_conversions::CHECKED_CONVERSIONS_INFO,
     crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO,
     crate::collapsible_if::COLLAPSIBLE_ELSE_IF_INFO,
@@ -313,6 +313,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::manual_range_patterns::MANUAL_RANGE_PATTERNS_INFO,
     crate::manual_rem_euclid::MANUAL_REM_EUCLID_INFO,
     crate::manual_retain::MANUAL_RETAIN_INFO,
+    crate::manual_rotate::MANUAL_ROTATE_INFO,
     crate::manual_slice_size_calculation::MANUAL_SLICE_SIZE_CALCULATION_INFO,
     crate::manual_string_new::MANUAL_STRING_NEW_INFO,
     crate::manual_strip::MANUAL_STRIP_INFO,
@@ -503,6 +504,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::missing_assert_message::MISSING_ASSERT_MESSAGE_INFO,
     crate::missing_asserts_for_indexing::MISSING_ASSERTS_FOR_INDEXING_INFO,
     crate::missing_const_for_fn::MISSING_CONST_FOR_FN_INFO,
+    crate::missing_const_for_thread_local::MISSING_CONST_FOR_THREAD_LOCAL_INFO,
     crate::missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS_INFO,
     crate::missing_enforced_import_rename::MISSING_ENFORCED_IMPORT_RENAMES_INFO,
     crate::missing_fields_in_debug::MISSING_FIELDS_IN_DEBUG_INFO,
@@ -585,12 +587,12 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::operators::VERBOSE_BIT_MASK_INFO,
     crate::option_env_unwrap::OPTION_ENV_UNWRAP_INFO,
     crate::option_if_let_else::OPTION_IF_LET_ELSE_INFO,
-    crate::overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL_INFO,
     crate::panic_in_result_fn::PANIC_IN_RESULT_FN_INFO,
     crate::panic_unimplemented::PANIC_INFO,
     crate::panic_unimplemented::TODO_INFO,
     crate::panic_unimplemented::UNIMPLEMENTED_INFO,
     crate::panic_unimplemented::UNREACHABLE_INFO,
+    crate::panicking_overflow_checks::PANICKING_OVERFLOW_CHECKS_INFO,
     crate::partial_pub_fields::PARTIAL_PUB_FIELDS_INFO,
     crate::partialeq_ne_impl::PARTIALEQ_NE_IMPL_INFO,
     crate::partialeq_to_none::PARTIALEQ_TO_NONE_INFO,
@@ -644,6 +646,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::semicolon_block::SEMICOLON_OUTSIDE_BLOCK_INFO,
     crate::semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED_INFO,
     crate::serde_api::SERDE_API_MISUSE_INFO,
+    crate::set_contains_or_insert::SET_CONTAINS_OR_INSERT_INFO,
     crate::shadow::SHADOW_REUSE_INFO,
     crate::shadow::SHADOW_SAME_INFO,
     crate::shadow::SHADOW_UNRELATED_INFO,
@@ -679,7 +682,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
     crate::tabs_in_doc_comments::TABS_IN_DOC_COMMENTS_INFO,
     crate::temporary_assignment::TEMPORARY_ASSIGNMENT_INFO,
     crate::tests_outside_test_module::TESTS_OUTSIDE_TEST_MODULE_INFO,
-    crate::thread_local_initializer_can_be_made_const::THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST_INFO,
     crate::to_digit_is_some::TO_DIGIT_IS_SOME_INFO,
     crate::to_string_trait_impl::TO_STRING_TRAIT_IMPL_INFO,
     crate::trailing_empty_array::TRAILING_EMPTY_ARRAY_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index 2b3f4854255..72fa05be3cc 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{has_drop, is_copy};
-use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro};
+use clippy_utils::{contains_name, get_parent_expr, in_automatically_derived, is_from_proc_macro};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
             // Avoid cases already linted by `field_reassign_with_default`
             && !self.reassigned_linted.contains(&expr.span)
             && let ExprKind::Call(path, ..) = expr.kind
-            && !any_parent_is_automatically_derived(cx.tcx, expr.hir_id)
+            && !in_automatically_derived(cx.tcx, expr.hir_id)
             && let ExprKind::Path(ref qpath) = path.kind
             && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
             && cx.tcx.is_diagnostic_item(sym::default_fn, def_id)
@@ -113,9 +113,9 @@ impl<'tcx> LateLintPass<'tcx> for Default {
         // start from the `let mut _ = _::default();` and look at all the following
         // statements, see if they re-assign the fields of the binding
         let stmts_head = match block.stmts {
+            [] | [_] => return,
             // Skip the last statement since there cannot possibly be any following statements that re-assign fields.
-            [head @ .., _] if !head.is_empty() => head,
-            _ => return,
+            [head @ .., _] => head,
         };
         for (stmt_idx, stmt) in stmts_head.iter().enumerate() {
             // find all binding statements like `let mut _ = T::default()` where `T::default()` is the
@@ -124,7 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
             let (local, variant, binding_name, binding_type, span) = if let StmtKind::Let(local) = stmt.kind
                 // only take `let ...` statements
                 && let Some(expr) = local.init
-                && !any_parent_is_automatically_derived(cx.tcx, expr.hir_id)
+                && !in_automatically_derived(cx.tcx, expr.hir_id)
                 && !expr.span.from_expansion()
                 // only take bindings to identifiers
                 && let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index ff631909bcb..9af73db6849 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -50,6 +50,8 @@ declare_lint_pass!(DefaultNumericFallback => [DEFAULT_NUMERIC_FALLBACK]);
 impl<'tcx> LateLintPass<'tcx> for DefaultNumericFallback {
     fn check_body(&mut self, cx: &LateContext<'tcx>, body: &Body<'tcx>) {
         let hir = cx.tcx.hir();
+        // NOTE: this is different from `clippy_utils::is_inside_always_const_context`.
+        // Inline const supports type inference.
         let is_parent_const = matches!(
             hir.body_const_context(hir.body_owner_def_id(body.id())),
             Some(ConstContext::Const { inline: false } | ConstContext::Static(_))
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index a115f8d0631..253f9959e13 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -3,7 +3,8 @@ use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use clippy_utils::sugg::has_enclosing_paren;
 use clippy_utils::ty::{implements_trait, is_manually_drop, peel_mid_ty_refs};
 use clippy_utils::{
-    expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, DefinedTy, ExprUseNode,
+    expr_use_ctxt, get_parent_expr, is_block_like, is_lint_allowed, path_to_local, peel_middle_ty_refs, DefinedTy,
+    ExprUseNode,
 };
 use core::mem;
 use rustc_ast::util::parser::{PREC_PREFIX, PREC_UNAMBIGUOUS};
@@ -175,6 +176,7 @@ struct StateData<'tcx> {
     adjusted_ty: Ty<'tcx>,
 }
 
+#[derive(Debug)]
 struct DerefedBorrow {
     count: usize,
     msg: &'static str,
@@ -182,6 +184,7 @@ struct DerefedBorrow {
     for_field_access: Option<Symbol>,
 }
 
+#[derive(Debug)]
 enum State {
     // Any number of deref method calls.
     DerefMethod {
@@ -744,7 +747,7 @@ fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> boo
     }
 }
 
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
 enum TyCoercionStability {
     Deref,
     Reborrow,
@@ -1042,16 +1045,28 @@ fn report<'tcx>(
                 return;
             }
 
-            let (prefix, precedence) = if let Some(mutability) = mutability
-                && !typeck.expr_ty(expr).is_ref()
+            let ty = typeck.expr_ty(expr);
+
+            // `&&[T; N]`, or `&&..&[T; N]` (src) cannot coerce to `&[T]` (dst).
+            if let ty::Ref(_, dst, _) = data.adjusted_ty.kind()
+                && dst.is_slice()
             {
-                let prefix = match mutability {
-                    Mutability::Not => "&",
-                    Mutability::Mut => "&mut ",
-                };
-                (prefix, PREC_PREFIX)
-            } else {
-                ("", 0)
+                let (src, n_src_refs) = peel_middle_ty_refs(ty);
+                if n_src_refs >= 2 && src.is_array() {
+                    return;
+                }
+            }
+
+            let (prefix, precedence) = match mutability {
+                Some(mutability) if !ty.is_ref() => {
+                    let prefix = match mutability {
+                        Mutability::Not => "&",
+                        Mutability::Mut => "&mut ",
+                    };
+                    (prefix, PREC_PREFIX)
+                },
+                None if !ty.is_ref() && data.adjusted_ty.is_ref() => ("&", 0),
+                _ => ("", 0),
             };
             span_lint_hir_and_then(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
index 9de879604e2..38fe687f7cc 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
@@ -1,6 +1,6 @@
 use clippy_config::types::DisallowedPath;
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::{fn_def_id, get_parent_expr, path_def_id};
+use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefIdMap;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -83,26 +83,26 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        let uncalled_path = if let Some(parent) = get_parent_expr(cx, expr)
-            && let ExprKind::Call(receiver, _) = parent.kind
-            && receiver.hir_id == expr.hir_id
-        {
-            None
-        } else {
-            path_def_id(cx, expr)
+        let (id, span) = match &expr.kind {
+            ExprKind::Path(path)
+                if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) =
+                    cx.qpath_res(path, expr.hir_id) =>
+            {
+                (id, expr.span)
+            },
+            ExprKind::MethodCall(name, ..) if let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => {
+                (id, name.ident.span)
+            },
+            _ => return,
         };
-        let Some(def_id) = uncalled_path.or_else(|| fn_def_id(cx, expr)) else {
-            return;
-        };
-        let conf = match self.disallowed.get(&def_id) {
-            Some(&index) => &self.conf_disallowed[index],
-            None => return,
-        };
-        let msg = format!("use of a disallowed method `{}`", conf.path());
-        span_lint_and_then(cx, DISALLOWED_METHODS, expr.span, msg, |diag| {
-            if let Some(reason) = conf.reason() {
-                diag.note(reason);
-            }
-        });
+        if let Some(&index) = self.disallowed.get(&id) {
+            let conf = &self.conf_disallowed[index];
+            let msg = format!("use of a disallowed method `{}`", conf.path());
+            span_lint_and_then(cx, DISALLOWED_METHODS, span, msg, |diag| {
+                if let Some(reason) = conf.reason() {
+                    diag.note(reason);
+                }
+            });
+        }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_names.rs b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
index 2afbf184117..58809604c37 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_names.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::is_test_module_or_function;
+use clippy_utils::is_in_test;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::{Item, Pat, PatKind};
+use rustc_hir::{Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
 
@@ -27,52 +27,30 @@ declare_clippy_lint! {
 #[derive(Clone, Debug)]
 pub struct DisallowedNames {
     disallow: FxHashSet<String>,
-    test_modules_deep: u32,
 }
 
 impl DisallowedNames {
     pub fn new(disallowed_names: &[String]) -> Self {
         Self {
             disallow: disallowed_names.iter().cloned().collect(),
-            test_modules_deep: 0,
         }
     }
-
-    fn in_test_module(&self) -> bool {
-        self.test_modules_deep != 0
-    }
 }
 
 impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]);
 
 impl<'tcx> LateLintPass<'tcx> for DisallowedNames {
-    fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
-        if is_test_module_or_function(cx.tcx, item) {
-            self.test_modules_deep = self.test_modules_deep.saturating_add(1);
-        }
-    }
-
     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
-        // Check whether we are under the `test` attribute.
-        if self.in_test_module() {
-            return;
-        }
-
-        if let PatKind::Binding(.., ident, _) = pat.kind {
-            if self.disallow.contains(&ident.name.to_string()) {
-                span_lint(
-                    cx,
-                    DISALLOWED_NAMES,
-                    ident.span,
-                    format!("use of a disallowed/placeholder name `{}`", ident.name),
-                );
-            }
-        }
-    }
-
-    fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
-        if is_test_module_or_function(cx.tcx, item) {
-            self.test_modules_deep = self.test_modules_deep.saturating_sub(1);
+        if let PatKind::Binding(.., ident, _) = pat.kind
+            && self.disallow.contains(&ident.name.to_string())
+            && !is_in_test(cx.tcx, pat.hir_id)
+        {
+            span_lint(
+                cx,
+                DISALLOWED_NAMES,
+                ident.span,
+                format!("use of a disallowed/placeholder name `{}`", ident.name),
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
index a995f06fb73..5ce11900adf 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
@@ -82,30 +82,25 @@ impl EarlyLintPass for DisallowedScriptIdents {
             // Note: `symbol.as_str()` is an expensive operation, thus should not be called
             // more than once for a single symbol.
             let symbol_str = symbol.as_str();
-            if symbol_str.is_ascii() {
-                continue;
-            }
 
-            for c in symbol_str.chars() {
-                // We want to iterate through all the scripts associated with this character
-                // and check whether at least of one scripts is in the whitelist.
-                let forbidden_script = c
-                    .script_extension()
-                    .iter()
-                    .find(|script| !self.whitelist.contains(script));
-                if let Some(script) = forbidden_script {
-                    span_lint(
-                        cx,
-                        DISALLOWED_SCRIPT_IDENTS,
-                        span,
-                        format!(
-                            "identifier `{symbol_str}` has a Unicode script that is not allowed by configuration: {}",
-                            script.full_name()
-                        ),
-                    );
-                    // We don't want to spawn warning multiple times over a single identifier.
-                    break;
-                }
+            // Check if any character in the symbol is not part of any allowed script.
+            // Fast path for ascii-only idents.
+            if !symbol_str.is_ascii()
+                && let Some(script) = symbol_str.chars().find_map(|c| {
+                    c.script_extension()
+                        .iter()
+                        .find(|script| !self.whitelist.contains(script))
+                })
+            {
+                span_lint(
+                    cx,
+                    DISALLOWED_SCRIPT_IDENTS,
+                    span,
+                    format!(
+                        "identifier `{symbol_str}` has a Unicode script that is not allowed by configuration: {}",
+                        script.full_name()
+                    ),
+                );
             }
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs
index 38bc58a5501..bd1cc46e185 100644
--- a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs
@@ -22,6 +22,7 @@ pub(super) fn check(
     range: Range<usize>,
     mut span: Span,
     containers: &[super::Container],
+    line_break_span: Span,
 ) {
     if doc[range.clone()].contains('\t') {
         // We don't do tab stops correctly.
@@ -46,11 +47,35 @@ pub(super) fn check(
         .sum();
     if ccount < blockquote_level || lcount < list_indentation {
         let msg = if ccount < blockquote_level {
-            "doc quote missing `>` marker"
+            "doc quote line without `>` marker"
         } else {
-            "doc list item missing indentation"
+            "doc list item without indentation"
         };
         span_lint_and_then(cx, DOC_LAZY_CONTINUATION, span, msg, |diag| {
+            let snippet = clippy_utils::source::snippet(cx, line_break_span, "");
+            if snippet.chars().filter(|&c| c == '\n').count() > 1
+                && let Some(doc_comment_start) = snippet.rfind('\n')
+                && let doc_comment = snippet[doc_comment_start..].trim()
+                && (doc_comment == "///" || doc_comment == "//!")
+            {
+                // suggest filling in a blank line
+                diag.span_suggestion_with_style(
+                    line_break_span.shrink_to_lo(),
+                    "if this should be its own paragraph, add a blank doc comment line",
+                    format!("\n{doc_comment}"),
+                    Applicability::MaybeIncorrect,
+                    SuggestionStyle::ShowAlways,
+                );
+                if ccount > 0 || blockquote_level > 0 {
+                    diag.help("if this not intended to be a quote at all, escape it with `\\>`");
+                } else {
+                    let indent = list_indentation - lcount;
+                    diag.help(format!(
+                        "if this is intended to be part of the list, indent {indent} spaces"
+                    ));
+                }
+                return;
+            }
             if ccount == 0 && blockquote_level == 0 {
                 // simpler suggestion style for indentation
                 let indent = list_indentation - lcount;
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 3e210fd153b..a2a1a51920f 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -6,7 +6,8 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::Visitable;
 use clippy_utils::{in_constant, is_entrypoint_fn, is_trait_impl_item, method_chain_args};
 use pulldown_cmark::Event::{
-    Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start, TaskListMarker, Text,
+    Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start,
+    TaskListMarker, Text,
 };
 use pulldown_cmark::Tag::{BlockQuote, CodeBlock, FootnoteDefinition, Heading, Item, Link, Paragraph};
 use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options, TagEnd};
@@ -747,7 +748,8 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
             },
             Start(FootnoteDefinition(..)) => in_footnote_definition = true,
             End(TagEnd::FootnoteDefinition) => in_footnote_definition = false,
-            Start(_) | End(_) => (), // We don't care about other tags
+            Start(_) | End(_)  // We don't care about other tags
+            | TaskListMarker(_) | Code(_) | Rule | InlineMath(..) | DisplayMath(..) => (),
             SoftBreak | HardBreak => {
                 if !containers.is_empty()
                     && let Some((next_event, next_range)) = events.peek()
@@ -762,13 +764,24 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                         range.end..next_range.start,
                         Span::new(span.hi(), next_span.lo(), span.ctxt(), span.parent()),
                         &containers[..],
+                        span,
                     );
                 }
             },
-            TaskListMarker(_) | Code(_) | Rule | InlineMath(..) | DisplayMath(..) => (),
             FootnoteReference(text) | Text(text) => {
                 paragraph_range.end = range.end;
-                ticks_unbalanced |= text.contains('`') && !in_code;
+                let range_ = range.clone();
+                ticks_unbalanced |= text.contains('`')
+                    && !in_code
+                    && doc[range.clone()].bytes().enumerate().any(|(i, c)| {
+                        // scan the markdown source code bytes for backquotes that aren't preceded by backslashes
+                        // - use bytes, instead of chars, to avoid utf8 decoding overhead (special chars are ascii)
+                        // - relevant backquotes are within doc[range], but backslashes are not, because they're not
+                        //   actually part of the rendered text (pulldown-cmark doesn't emit any events for escapes)
+                        // - if `range_.start + i == 0`, then `range_.start + i - 1 == -1`, and since we're working in
+                        //   usize, that would underflow and maybe panic
+                        c == b'`' && (range_.start + i == 0 || doc.as_bytes().get(range_.start + i - 1) != Some(&b'\\'))
+                    });
                 if Some(&text) == in_link.as_ref() || ticks_unbalanced {
                     // Probably a link of the form `<http://example.com>`
                     // Which are represented as a link to "http://example.com" with
diff --git a/src/tools/clippy/clippy_lints/src/endian_bytes.rs b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
index bb766e96338..99328e3e643 100644
--- a/src/tools/clippy/clippy_lints/src/endian_bytes.rs
+++ b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
@@ -33,7 +33,7 @@ declare_clippy_lint! {
     /// Checks for the usage of the `to_le_bytes` method and/or the function `from_le_bytes`.
     ///
     /// ### Why restrict this?
-    /// To ensure use of big endian or the target’s endianness rather than little endian.
+    /// To ensure use of big-endian or the target’s endianness rather than little-endian.
     ///
     /// ### Example
     /// ```rust,ignore
@@ -51,7 +51,7 @@ declare_clippy_lint! {
     /// Checks for the usage of the `to_be_bytes` method and/or the function `from_be_bytes`.
     ///
     /// ### Why restrict this?
-    /// To ensure use of little endian or the target’s endianness rather than big endian.
+    /// To ensure use of little-endian or the target’s endianness rather than big-endian.
     ///
     /// ### Example
     /// ```rust,ignore
diff --git a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
index 6fb38a0d6dd..cf85c74e688 100644
--- a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_in_test_function;
+use clippy_utils::is_in_test;
 
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
@@ -41,7 +41,7 @@ fn report(cx: &LateContext<'_>, param: &GenericParam<'_>, generics: &Generics<'_
 pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) {
     if let FnKind::ItemFn(_, generics, _) = kind
         && cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public()
-        && !is_in_test_function(cx.tcx, hir_id)
+        && !is_in_test(cx.tcx, hir_id)
     {
         for param in generics.params {
             if param.is_impl_trait() {
@@ -59,7 +59,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
         && of_trait.is_none()
         && let body = cx.tcx.hir().body(body_id)
         && cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public()
-        && !is_in_test_function(cx.tcx, impl_item.hir_id())
+        && !is_in_test(cx.tcx, impl_item.hir_id())
     {
         for param in impl_item.generics.params {
             if param.is_impl_trait() {
@@ -75,7 +75,7 @@ pub(super) fn check_trait_item(cx: &LateContext<'_>, trait_item: &TraitItem<'_>,
         && let hir::Node::Item(item) = cx.tcx.parent_hir_node(trait_item.hir_id())
         // ^^ (Will always be a trait)
         && !item.vis_span.is_empty() // Is public
-        && !is_in_test_function(cx.tcx, trait_item.hir_id())
+        && !is_in_test(cx.tcx, trait_item.hir_id())
     {
         for param in trait_item.generics.params {
             if param.is_impl_trait() {
diff --git a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
index 35b4481bfee..5c63d48adaf 100644
--- a/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
+++ b/src/tools/clippy/clippy_lints/src/incompatible_msrv.rs
@@ -1,6 +1,6 @@
 use clippy_config::msrvs::Msrv;
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::is_in_test_function;
+use clippy_utils::is_in_test;
 use rustc_attr::{StabilityLevel, StableSince};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::{Expr, ExprKind, HirId};
@@ -88,7 +88,7 @@ impl IncompatibleMsrv {
             return;
         }
         let version = self.get_def_id_version(cx.tcx, def_id);
-        if self.msrv.meets(version) || is_in_test_function(cx.tcx, node) {
+        if self.msrv.meets(version) || is_in_test(cx.tcx, node) {
             return;
         }
         if let ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) = span.ctxt().outer_expn_data().kind {
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index 9aedf5ec7e8..ec6174bc030 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -91,10 +91,6 @@ declare_lint_pass!(InherentToString => [INHERENT_TO_STRING, INHERENT_TO_STRING_S
 
 impl<'tcx> LateLintPass<'tcx> for InherentToString {
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
-        if impl_item.span.from_expansion() {
-            return;
-        }
-
         // Check if item is a method called `to_string` and has a parameter 'self'
         if let ImplItemKind::Fn(ref signature, _) = impl_item.kind
             // #11201
@@ -106,6 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for InherentToString {
             && decl.implicit_self.has_implicit_self()
             && decl.inputs.len() == 1
             && impl_item.generics.params.iter().all(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+            && !impl_item.span.from_expansion()
             // Check if return type is String
             && is_type_lang_item(cx, return_ty(cx, impl_item.owner_id), LangItem::String)
             // Filters instances of to_string which are required by a trait
diff --git a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
index 1c8fd0a27f9..7f183bb601e 100644
--- a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
+++ b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
@@ -1,13 +1,12 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
+use rustc_span::SyntaxContext;
 use std::borrow::Cow;
-use std::cmp::Reverse;
-use std::collections::BinaryHeap;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -44,38 +43,56 @@ declare_lint_pass!(NumberedFields => [INIT_NUMBERED_FIELDS]);
 
 impl<'tcx> LateLintPass<'tcx> for NumberedFields {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
-        if let ExprKind::Struct(path, fields, None) = e.kind {
-            if !fields.is_empty()
-                && !e.span.from_expansion()
-                && fields
-                    .iter()
-                    .all(|f| f.ident.as_str().as_bytes().iter().all(u8::is_ascii_digit))
-                && !matches!(cx.qpath_res(path, e.hir_id), Res::Def(DefKind::TyAlias, ..))
-            {
-                let expr_spans = fields
-                    .iter()
-                    .map(|f| (Reverse(f.ident.as_str().parse::<usize>().unwrap()), f.expr.span))
-                    .collect::<BinaryHeap<_>>();
-                let mut appl = Applicability::MachineApplicable;
-                let snippet = format!(
-                    "{}({})",
-                    snippet_with_applicability(cx, path.span(), "..", &mut appl),
-                    expr_spans
-                        .into_iter_sorted()
-                        .map(|(_, span)| snippet_with_context(cx, span, path.span().ctxt(), "..", &mut appl).0)
-                        .intersperse(Cow::Borrowed(", "))
-                        .collect::<String>()
-                );
-                span_lint_and_sugg(
-                    cx,
-                    INIT_NUMBERED_FIELDS,
-                    e.span,
-                    "used a field initializer for a tuple struct",
-                    "try",
-                    snippet,
-                    appl,
-                );
-            }
+        if let ExprKind::Struct(path, fields @ [field, ..], None) = e.kind
+            // If the first character of any field is a digit it has to be a tuple.
+            && field.ident.as_str().as_bytes().first().is_some_and(u8::is_ascii_digit)
+            // Type aliases can't be used as functions.
+            && !matches!(
+                cx.qpath_res(path, e.hir_id),
+                Res::Def(DefKind::TyAlias | DefKind::AssocTy, _)
+            )
+            // This is the only syntax macros can use that works for all struct types.
+            && !e.span.from_expansion()
+            && let mut has_side_effects = false
+            && let Ok(mut expr_spans) = fields
+                .iter()
+                .map(|f| {
+                    has_side_effects |= f.expr.can_have_side_effects();
+                    f.ident.as_str().parse::<usize>().map(|x| (x, f.expr.span))
+                })
+                .collect::<Result<Vec<_>, _>>()
+            // We can only reorder the expressions if there are no side effects.
+            && (!has_side_effects || expr_spans.is_sorted_by_key(|&(idx, _)| idx))
+        {
+            span_lint_and_then(
+                cx,
+                INIT_NUMBERED_FIELDS,
+                e.span,
+                "used a field initializer for a tuple struct",
+                |diag| {
+                    if !has_side_effects {
+                        // We already checked the order if there are side effects.
+                        expr_spans.sort_by_key(|&(idx, _)| idx);
+                    }
+                    let mut app = Applicability::MachineApplicable;
+                    diag.span_suggestion(
+                        e.span,
+                        "use tuple initialization",
+                        format!(
+                            "{}({})",
+                            snippet_with_applicability(cx, path.span(), "..", &mut app),
+                            expr_spans
+                                .into_iter()
+                                .map(
+                                    |(_, span)| snippet_with_context(cx, span, SyntaxContext::root(), "..", &mut app).0
+                                )
+                                .intersperse(Cow::Borrowed(", "))
+                                .collect::<String>()
+                        ),
+                        app,
+                    );
+                },
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
index 860258fd030..5657c58bb0a 100644
--- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
+++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
@@ -2,12 +2,11 @@
 
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::sugg::DiagExt;
-use rustc_ast::ast::Attribute;
 use rustc_errors::Applicability;
 use rustc_hir::{TraitFn, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::{sym, Symbol};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -34,27 +33,23 @@ declare_lint_pass!(InlineFnWithoutBody => [INLINE_FN_WITHOUT_BODY]);
 
 impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody {
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
-        if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind {
-            let attrs = cx.tcx.hir().attrs(item.hir_id());
-            check_attrs(cx, item.ident.name, attrs);
+        if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind
+            && let Some(attr) = cx
+                .tcx
+                .hir()
+                .attrs(item.hir_id())
+                .iter()
+                .find(|a| a.has_name(sym::inline))
+        {
+            span_lint_and_then(
+                cx,
+                INLINE_FN_WITHOUT_BODY,
+                attr.span,
+                format!("use of `#[inline]` on trait method `{}` which has no body", item.ident),
+                |diag| {
+                    diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable);
+                },
+            );
         }
     }
 }
-
-fn check_attrs(cx: &LateContext<'_>, name: Symbol, attrs: &[Attribute]) {
-    for attr in attrs {
-        if !attr.has_name(sym::inline) {
-            continue;
-        }
-
-        span_lint_and_then(
-            cx,
-            INLINE_FN_WITHOUT_BODY,
-            attr.span,
-            format!("use of `#[inline]` on trait method `{name}` which has no body"),
-            |diag| {
-                diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable);
-            },
-        );
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
index 10b00f632bb..5fe152d1e30 100644
--- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
+++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
@@ -85,16 +85,19 @@ impl LateLintPass<'_> for InstantSubtraction {
             lhs,
             rhs,
         ) = expr.kind
+            && let typeck = cx.typeck_results()
+            && ty::is_type_diagnostic_item(cx, typeck.expr_ty(lhs), sym::Instant)
         {
+            let rhs_ty = typeck.expr_ty(rhs);
+
             if is_instant_now_call(cx, lhs)
-                && is_an_instant(cx, rhs)
+                && ty::is_type_diagnostic_item(cx, rhs_ty, sym::Instant)
                 && let Some(sugg) = Sugg::hir_opt(cx, rhs)
             {
                 print_manual_instant_elapsed_sugg(cx, expr, sugg);
-            } else if !expr.span.from_expansion()
+            } else if ty::is_type_diagnostic_item(cx, rhs_ty, sym::Duration)
+                && !expr.span.from_expansion()
                 && self.msrv.meets(msrvs::TRY_FROM)
-                && is_an_instant(cx, lhs)
-                && is_a_duration(cx, rhs)
             {
                 print_unchecked_duration_subtraction_sugg(cx, lhs, rhs, expr);
             }
@@ -115,16 +118,6 @@ fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool {
     }
 }
 
-fn is_an_instant(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let expr_ty = cx.typeck_results().expr_ty(expr);
-    ty::is_type_diagnostic_item(cx, expr_ty, sym::Instant)
-}
-
-fn is_a_duration(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let expr_ty = cx.typeck_results().expr_ty(expr);
-    ty::is_type_diagnostic_item(cx, expr_ty, sym::Duration)
-}
-
 fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, sugg: Sugg<'_>) {
     span_lint_and_sugg(
         cx,
diff --git a/src/tools/clippy/clippy_lints/src/items_after_statements.rs b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
index 39223c20470..a88d8e24fda 100644
--- a/src/tools/clippy/clippy_lints/src/items_after_statements.rs
+++ b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
@@ -54,36 +54,35 @@ declare_lint_pass!(ItemsAfterStatements => [ITEMS_AFTER_STATEMENTS]);
 
 impl LateLintPass<'_> for ItemsAfterStatements {
     fn check_block(&mut self, cx: &LateContext<'_>, block: &Block<'_>) {
-        if in_external_macro(cx.sess(), block.span) {
-            return;
-        }
-
-        // skip initial items
-        let stmts = block
-            .stmts
-            .iter()
-            .skip_while(|stmt| matches!(stmt.kind, StmtKind::Item(..)));
-
-        // lint on all further items
-        for stmt in stmts {
-            if let StmtKind::Item(item_id) = stmt.kind {
-                let item = cx.tcx.hir().item(item_id);
-                if in_external_macro(cx.sess(), item.span) || !item.span.eq_ctxt(block.span) {
-                    return;
-                }
-                if let ItemKind::Macro(..) = item.kind {
-                    // do not lint `macro_rules`, but continue processing further statements
-                    continue;
-                }
-                span_lint_hir(
-                    cx,
-                    ITEMS_AFTER_STATEMENTS,
-                    item.hir_id(),
-                    item.span,
-                    "adding items after statements is confusing, since items exist from the \
-                     start of the scope",
-                );
-            }
+        if block.stmts.len() > 1 {
+            let ctxt = block.span.ctxt();
+            let mut in_external = None;
+            block
+                .stmts
+                .iter()
+                .skip_while(|stmt| matches!(stmt.kind, StmtKind::Item(..)))
+                .filter_map(|stmt| match stmt.kind {
+                    StmtKind::Item(id) => Some(cx.tcx.hir().item(id)),
+                    _ => None,
+                })
+                // Ignore macros since they can only see previously defined locals.
+                .filter(|item| !matches!(item.kind, ItemKind::Macro(..)))
+                // Stop linting if macros define items.
+                .take_while(|item| item.span.ctxt() == ctxt)
+                // Don't use `next` due to the complex filter chain.
+                .for_each(|item| {
+                    // Only do the macro check once, but delay it until it's needed.
+                    if !*in_external.get_or_insert_with(|| in_external_macro(cx.sess(), block.span)) {
+                        span_lint_hir(
+                            cx,
+                            ITEMS_AFTER_STATEMENTS,
+                            item.hir_id(),
+                            item.span,
+                            "adding items after statements is confusing, since items exist from the \
+                                start of the scope",
+                        );
+                    }
+                });
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
index 1b5f1b49947..ba0cd5d6eb3 100644
--- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
@@ -4,7 +4,7 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{FnSig, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::symbol::sym;
+use rustc_span::{sym, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -43,30 +43,27 @@ declare_lint_pass!(IterNotReturningIterator => [ITER_NOT_RETURNING_ITERATOR]);
 
 impl<'tcx> LateLintPass<'tcx> for IterNotReturningIterator {
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
-        let name = item.ident.name.as_str();
-        if matches!(name, "iter" | "iter_mut") {
-            if let TraitItemKind::Fn(fn_sig, _) = &item.kind {
-                check_sig(cx, name, fn_sig, item.owner_id.def_id);
-            }
+        if let TraitItemKind::Fn(fn_sig, _) = &item.kind
+            && matches!(item.ident.name, sym::iter | sym::iter_mut)
+        {
+            check_sig(cx, item.ident.name, fn_sig, item.owner_id.def_id);
         }
     }
 
     fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'tcx>) {
-        let name = item.ident.name.as_str();
-        if matches!(name, "iter" | "iter_mut")
+        if let ImplItemKind::Fn(fn_sig, _) = &item.kind
+            && matches!(item.ident.name, sym::iter | sym::iter_mut)
             && !matches!(
                 cx.tcx.parent_hir_node(item.hir_id()),
                 Node::Item(Item { kind: ItemKind::Impl(i), .. }) if i.of_trait.is_some()
             )
         {
-            if let ImplItemKind::Fn(fn_sig, _) = &item.kind {
-                check_sig(cx, name, fn_sig, item.owner_id.def_id);
-            }
+            check_sig(cx, item.ident.name, fn_sig, item.owner_id.def_id);
         }
     }
 }
 
-fn check_sig(cx: &LateContext<'_>, name: &str, sig: &FnSig<'_>, fn_id: LocalDefId) {
+fn check_sig(cx: &LateContext<'_>, name: Symbol, sig: &FnSig<'_>, fn_id: LocalDefId) {
     if sig.decl.implicit_self.has_implicit_self() {
         let ret_ty = cx
             .tcx
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index 6b03f2597b0..1e6404190d3 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -125,13 +125,13 @@ fn is_ty_exported(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
 
 impl LateLintPass<'_> for IterWithoutIntoIter {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
-        if !in_external_macro(cx.sess(), item.span)
-            && let ItemKind::Impl(imp) = item.kind
+        if let ItemKind::Impl(imp) = item.kind
             && let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind
             && let Some(trait_ref) = imp.of_trait
             && trait_ref
                 .trait_def_id()
                 .is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did))
+            && !in_external_macro(cx.sess(), item.span)
             && let &ty::Ref(_, ty, mtbl) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind()
             && let expected_method_name = match mtbl {
                 Mutability::Mut => sym::iter_mut,
diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
index 7f8197c0cc0..b18ab625e60 100644
--- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
@@ -46,12 +46,12 @@ impl_lint_pass!(LargeConstArrays => [LARGE_CONST_ARRAYS]);
 
 impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if !item.span.from_expansion()
-            && let ItemKind::Const(_, generics, _) = &item.kind
+        if let ItemKind::Const(_, generics, _) = &item.kind
             // Since static items may not have generics, skip generic const items.
             // FIXME(generic_const_items): I don't think checking `generics.hwcp` suffices as it
             // doesn't account for empty where-clauses that only consist of keyword `where` IINM.
             && generics.params.is_empty() && !generics.has_where_clause_predicates
+            && !item.span.from_expansion()
             && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
             && let ty::Array(element_type, cst) = ty.kind()
             && let ConstKind::Value(_, ty::ValTree::Leaf(element_count)) = cst.kind()
diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
index 0bf7389ef9c..85daadcc537 100644
--- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
+++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
@@ -77,17 +77,12 @@ impl_lint_pass!(LargeEnumVariant => [LARGE_ENUM_VARIANT]);
 
 impl<'tcx> LateLintPass<'tcx> for LargeEnumVariant {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &Item<'tcx>) {
-        if in_external_macro(cx.tcx.sess, item.span) {
-            return;
-        }
-        if let ItemKind::Enum(ref def, _) = item.kind {
-            let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
-            let ty::Adt(adt, subst) = ty.kind() else {
-                panic!("already checked whether this is an enum")
-            };
-            if adt.variants().len() <= 1 {
-                return;
-            }
+        if let ItemKind::Enum(ref def, _) = item.kind
+            && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
+            && let ty::Adt(adt, subst) = ty.kind()
+            && adt.variants().len() > 1
+            && !in_external_macro(cx.tcx.sess, item.span)
+        {
             let variants_size = AdtVariantInfo::new(cx, *adt, subst);
 
             let mut difference = variants_size[0].size - variants_size[1].size;
diff --git a/src/tools/clippy/clippy_lints/src/large_futures.rs b/src/tools/clippy/clippy_lints/src/large_futures.rs
index 07488a512a3..602227e4249 100644
--- a/src/tools/clippy/clippy_lints/src/large_futures.rs
+++ b/src/tools/clippy/clippy_lints/src/large_futures.rs
@@ -54,29 +54,26 @@ impl_lint_pass!(LargeFuture => [LARGE_FUTURES]);
 
 impl<'tcx> LateLintPass<'tcx> for LargeFuture {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if matches!(expr.span.ctxt().outer_expn_data().kind, rustc_span::ExpnKind::Macro(..)) {
-            return;
-        }
-        if let ExprKind::Match(expr, _, MatchSource::AwaitDesugar) = expr.kind {
-            if let ExprKind::Call(func, [expr, ..]) = expr.kind
-                && let ExprKind::Path(QPath::LangItem(LangItem::IntoFutureIntoFuture, ..)) = func.kind
-                && let ty = cx.typeck_results().expr_ty(expr)
-                && let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait()
-                && implements_trait(cx, ty, future_trait_def_id, &[])
-                && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty))
-                && let size = layout.layout.size()
-                && size >= Size::from_bytes(self.future_size_threshold)
-            {
-                span_lint_and_sugg(
-                    cx,
-                    LARGE_FUTURES,
-                    expr.span,
-                    format!("large future with a size of {} bytes", size.bytes()),
-                    "consider `Box::pin` on it",
-                    format!("Box::pin({})", snippet(cx, expr.span, "..")),
-                    Applicability::Unspecified,
-                );
-            }
+        if let ExprKind::Match(scrutinee, _, MatchSource::AwaitDesugar) = expr.kind
+            && let ExprKind::Call(func, [arg, ..]) = scrutinee.kind
+            && let ExprKind::Path(QPath::LangItem(LangItem::IntoFutureIntoFuture, ..)) = func.kind
+            && !expr.span.from_expansion()
+            && let ty = cx.typeck_results().expr_ty(arg)
+            && let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait()
+            && implements_trait(cx, ty, future_trait_def_id, &[])
+            && let Ok(layout) = cx.tcx.layout_of(cx.param_env.and(ty))
+            && let size = layout.layout.size()
+            && size >= Size::from_bytes(self.future_size_threshold)
+        {
+            span_lint_and_sugg(
+                cx,
+                LARGE_FUTURES,
+                arg.span,
+                format!("large future with a size of {} bytes", size.bytes()),
+                "consider `Box::pin` on it",
+                format!("Box::pin({})", snippet(cx, arg.span, "..")),
+                Applicability::Unspecified,
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs
index 07efee159aa..2688283a6ce 100644
--- a/src/tools/clippy/clippy_lints/src/large_include_file.rs
+++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs
@@ -1,5 +1,4 @@
 use clippy_utils::diagnostics::span_lint_and_note;
-use clippy_utils::is_lint_allowed;
 use clippy_utils::macros::root_macro_call_first_node;
 use rustc_ast::LitKind;
 use rustc_hir::{Expr, ExprKind};
@@ -52,24 +51,19 @@ impl_lint_pass!(LargeIncludeFile => [LARGE_INCLUDE_FILE]);
 
 impl LateLintPass<'_> for LargeIncludeFile {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
-        if let Some(macro_call) = root_macro_call_first_node(cx, expr)
-            && !is_lint_allowed(cx, LARGE_INCLUDE_FILE, expr.hir_id)
-            && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id)
-                || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id))
-            && let ExprKind::Lit(lit) = &expr.kind
-        {
-            let len = match &lit.node {
+        if let ExprKind::Lit(lit) = &expr.kind
+            && let len = match &lit.node {
                 // include_bytes
                 LitKind::ByteStr(bstr, _) => bstr.len(),
                 // include_str
                 LitKind::Str(sym, _) => sym.as_str().len(),
                 _ => return,
-            };
-
-            if len as u64 <= self.max_file_size {
-                return;
             }
-
+            && len as u64 > self.max_file_size
+            && let Some(macro_call) = root_macro_call_first_node(cx, expr)
+            && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id)
+                || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id))
+        {
             span_lint_and_note(
                 cx,
                 LARGE_INCLUDE_FILE,
diff --git a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
index eadfeb6e341..a08b40bef37 100644
--- a/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/legacy_numeric_constants.rs
@@ -48,15 +48,11 @@ impl_lint_pass!(LegacyNumericConstants => [LEGACY_NUMERIC_CONSTANTS]);
 
 impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
-        let Self { msrv } = self;
-
-        if !msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) || in_external_macro(cx.sess(), item.span) {
-            return;
-        }
-
         // Integer modules are "TBD" deprecated, and the contents are too,
         // so lint on the `use` statement directly.
         if let ItemKind::Use(path, kind @ (UseKind::Single | UseKind::Glob)) = item.kind
+            && self.msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS)
+            && !in_external_macro(cx.sess(), item.span)
             && let Some(def_id) = path.res[0].opt_def_id()
         {
             let module = if is_integer_module(cx, def_id) {
@@ -103,12 +99,7 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
-        let Self { msrv } = self;
-
-        if !msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS) || in_external_macro(cx.sess(), expr.span) {
-            return;
-        }
-        let ExprKind::Path(qpath) = expr.kind else {
+        let ExprKind::Path(qpath) = &expr.kind else {
             return;
         };
 
@@ -129,10 +120,10 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
             )
         // `<integer>::xxx_value` check
         } else if let QPath::TypeRelative(_, last_segment) = qpath
-            && let Some(def_id) = cx.qpath_res(&qpath, expr.hir_id).opt_def_id()
-            && is_integer_method(cx, def_id)
+            && let Some(def_id) = cx.qpath_res(qpath, expr.hir_id).opt_def_id()
             && let Some(par_expr) = get_parent_expr(cx, expr)
-            && let ExprKind::Call(_, _) = par_expr.kind
+            && let ExprKind::Call(_, []) = par_expr.kind
+            && is_integer_method(cx, def_id)
         {
             let name = last_segment.ident.name.as_str();
 
@@ -145,19 +136,20 @@ impl<'tcx> LateLintPass<'tcx> for LegacyNumericConstants {
             return;
         };
 
-        if is_from_proc_macro(cx, expr) {
-            return;
+        if self.msrv.meets(NUMERIC_ASSOCIATED_CONSTANTS)
+            && !in_external_macro(cx.sess(), expr.span)
+            && !is_from_proc_macro(cx, expr)
+        {
+            span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| {
+                diag.span_suggestion_with_style(
+                    span,
+                    "use the associated constant instead",
+                    sugg,
+                    Applicability::MaybeIncorrect,
+                    SuggestionStyle::ShowAlways,
+                );
+            });
         }
-
-        span_lint_hir_and_then(cx, LEGACY_NUMERIC_CONSTANTS, expr.hir_id, span, msg, |diag| {
-            diag.span_suggestion_with_style(
-                span,
-                "use the associated constant instead",
-                sugg,
-                Applicability::MaybeIncorrect,
-                SuggestionStyle::ShowAlways,
-            );
-        });
     }
 
     extract_msrv_attr!(LateContext);
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 57e0a7aa2c7..4c737371bd2 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -121,11 +121,9 @@ declare_lint_pass!(LenZero => [LEN_ZERO, LEN_WITHOUT_IS_EMPTY, COMPARISON_TO_EMP
 
 impl<'tcx> LateLintPass<'tcx> for LenZero {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if item.span.from_expansion() {
-            return;
-        }
-
-        if let ItemKind::Trait(_, _, _, _, trait_items) = item.kind {
+        if let ItemKind::Trait(_, _, _, _, trait_items) = item.kind
+            && !item.span.from_expansion()
+        {
             check_trait_items(cx, item, trait_items);
         }
     }
@@ -162,17 +160,14 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
     }
 
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if expr.span.from_expansion() {
-            return;
-        }
-
         if let ExprKind::Let(lt) = expr.kind
-            && has_is_empty(cx, lt.init)
             && match lt.pat.kind {
                 PatKind::Slice([], None, []) => true,
                 PatKind::Lit(lit) if is_empty_string(lit) => true,
                 _ => false,
             }
+            && !expr.span.from_expansion()
+            && has_is_empty(cx, lt.init)
         {
             let mut applicability = Applicability::MachineApplicable;
 
@@ -190,7 +185,9 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
             );
         }
 
-        if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind {
+        if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind
+            && !expr.span.from_expansion()
+        {
             // expr.span might contains parenthesis, see issue #10529
             let actual_span = span_without_enclosing_paren(cx, expr.span);
             match cmp {
diff --git a/src/tools/clippy/clippy_lints/src/let_if_seq.rs b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
index a65cb3f4dfb..0e488cee6b7 100644
--- a/src/tools/clippy/clippy_lints/src/let_if_seq.rs
+++ b/src/tools/clippy/clippy_lints/src/let_if_seq.rs
@@ -58,12 +58,10 @@ declare_lint_pass!(LetIfSeq => [USELESS_LET_IF_SEQ]);
 
 impl<'tcx> LateLintPass<'tcx> for LetIfSeq {
     fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
-        let mut it = block.stmts.iter().peekable();
-        while let Some(stmt) = it.next() {
-            if let Some(expr) = it.peek()
-                && let hir::StmtKind::Let(local) = stmt.kind
+        for [stmt, next] in block.stmts.array_windows::<2>() {
+            if let hir::StmtKind::Let(local) = stmt.kind
                 && let hir::PatKind::Binding(mode, canonical_id, ident, None) = local.pat.kind
-                && let hir::StmtKind::Expr(if_) = expr.kind
+                && let hir::StmtKind::Expr(if_) = next.kind
                 && let hir::ExprKind::If(
                     hir::Expr {
                         kind: hir::ExprKind::DropTemps(cond),
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index 9fd4f509aa4..8fa63f3e8fd 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -139,9 +139,9 @@ const SYNC_GUARD_PATHS: [&[&str]; 3] = [
 impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
     fn check_local(&mut self, cx: &LateContext<'tcx>, local: &LetStmt<'tcx>) {
         if matches!(local.source, LocalSource::Normal)
-            && !in_external_macro(cx.tcx.sess, local.span)
             && let PatKind::Wild = local.pat.kind
             && let Some(init) = local.init
+            && !in_external_macro(cx.tcx.sess, local.span)
         {
             let init_ty = cx.typeck_results().expr_ty(init);
             let contains_sync_guard = init_ty.walk().any(|inner| match inner.unpack() {
diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
index 593b29154b4..5a11702d7ce 100644
--- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::source::snippet;
+use clippy_utils::is_from_proc_macro;
 use rustc_hir::{LetStmt, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
@@ -25,19 +25,14 @@ declare_clippy_lint! {
 }
 declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]);
 
-impl LateLintPass<'_> for UnderscoreTyped {
-    fn check_local(&mut self, cx: &LateContext<'_>, local: &LetStmt<'_>) {
-        if !in_external_macro(cx.tcx.sess, local.span)
-            && let Some(ty) = local.ty // Ensure that it has a type defined
+impl<'tcx> LateLintPass<'tcx> for UnderscoreTyped {
+    fn check_local(&mut self, cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) {
+        if let Some(ty) = local.ty // Ensure that it has a type defined
             && let TyKind::Infer = &ty.kind // that type is '_'
             && local.span.eq_ctxt(ty.span)
+            && !in_external_macro(cx.tcx.sess, local.span)
+            && !is_from_proc_macro(cx, ty)
         {
-            // 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,
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 32fad0f02ce..c2dc26d6605 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -4,7 +4,9 @@
 #![feature(f128)]
 #![feature(f16)]
 #![feature(if_let_guard)]
+#![feature(is_sorted)]
 #![feature(iter_intersperse)]
+#![feature(iter_partition_in_place)]
 #![feature(let_chains)]
 #![cfg_attr(bootstrap, feature(lint_reasons))]
 #![feature(never_type)]
@@ -90,8 +92,10 @@ mod bool_to_int_with_if;
 mod booleans;
 mod borrow_deref_ref;
 mod box_default;
+mod byte_char_slices;
 mod cargo;
 mod casts;
+mod cfg_not_test;
 mod checked_conversions;
 mod cognitive_complexity;
 mod collapsible_if;
@@ -212,6 +216,7 @@ mod manual_non_exhaustive;
 mod manual_range_patterns;
 mod manual_rem_euclid;
 mod manual_retain;
+mod manual_rotate;
 mod manual_slice_size_calculation;
 mod manual_string_new;
 mod manual_strip;
@@ -229,6 +234,7 @@ mod mismatching_type_param_order;
 mod missing_assert_message;
 mod missing_asserts_for_indexing;
 mod missing_const_for_fn;
+mod missing_const_for_thread_local;
 mod missing_doc;
 mod missing_enforced_import_rename;
 mod missing_fields_in_debug;
@@ -275,9 +281,9 @@ mod only_used_in_recursion;
 mod operators;
 mod option_env_unwrap;
 mod option_if_let_else;
-mod overflow_check_conditional;
 mod panic_in_result_fn;
 mod panic_unimplemented;
+mod panicking_overflow_checks;
 mod partial_pub_fields;
 mod partialeq_ne_impl;
 mod partialeq_to_none;
@@ -318,6 +324,7 @@ mod self_named_constructors;
 mod semicolon_block;
 mod semicolon_if_nothing_returned;
 mod serde_api;
+mod set_contains_or_insert;
 mod shadow;
 mod significant_drop_tightening;
 mod single_call_fn;
@@ -339,7 +346,6 @@ mod swap_ptr_to_ref;
 mod tabs_in_doc_comments;
 mod temporary_assignment;
 mod tests_outside_test_module;
-mod thread_local_initializer_can_be_made_const;
 mod to_digit_is_some;
 mod to_string_trait_impl;
 mod trailing_empty_array;
@@ -639,9 +645,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
         });
         store.register_early_pass(|| Box::new(utils::internal_lints::produce_ice::ProduceIce));
         store.register_late_pass(|_| Box::new(utils::internal_lints::collapsible_calls::CollapsibleCalls));
-        store.register_late_pass(|_| {
-            Box::new(utils::internal_lints::compiler_lint_functions::CompilerLintFunctions::new())
-        });
         store.register_late_pass(|_| Box::new(utils::internal_lints::invalid_paths::InvalidPaths));
         store.register_late_pass(|_| {
             Box::<utils::internal_lints::interning_defined_symbol::InterningDefinedSymbol>::default()
@@ -788,7 +791,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     let format_args = format_args_storage.clone();
     store.register_late_pass(move |_| Box::new(format::UselessFormat::new(format_args.clone())));
     store.register_late_pass(|_| Box::new(swap::Swap));
-    store.register_late_pass(|_| Box::new(overflow_check_conditional::OverflowCheckConditional));
+    store.register_late_pass(|_| Box::new(panicking_overflow_checks::PanickingOverflowChecks));
     store.register_late_pass(|_| Box::<new_without_default::NewWithoutDefault>::default());
     store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(disallowed_names)));
     store.register_late_pass(move |_| {
@@ -1024,6 +1027,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(default_instead_of_iter_empty::DefaultIterEmpty));
     store.register_late_pass(move |_| Box::new(manual_rem_euclid::ManualRemEuclid::new(msrv())));
     store.register_late_pass(move |_| Box::new(manual_retain::ManualRetain::new(msrv())));
+    store.register_late_pass(move |_| Box::new(manual_rotate::ManualRotate));
     store.register_late_pass(move |_| {
         Box::new(operators::Operators::new(
             verbose_bit_mask_threshold,
@@ -1153,9 +1157,8 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
             behavior: pub_underscore_fields_behavior,
         })
     });
-    store.register_late_pass(move |_| {
-        Box::new(thread_local_initializer_can_be_made_const::ThreadLocalInitializerCanBeMadeConst::new(msrv()))
-    });
+    store
+        .register_late_pass(move |_| Box::new(missing_const_for_thread_local::MissingConstForThreadLocal::new(msrv())));
     store.register_late_pass(move |_| Box::new(incompatible_msrv::IncompatibleMsrv::new(msrv())));
     store.register_late_pass(|_| Box::new(to_string_trait_impl::ToStringTraitImpl));
     store.register_early_pass(|| Box::new(multiple_bound_locations::MultipleBoundLocations));
@@ -1171,6 +1174,9 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     });
     store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(msrv())));
     store.register_early_pass(|| Box::new(field_scoped_visibility_modifiers::FieldScopedVisibilityModifiers));
+    store.register_late_pass(|_| Box::new(set_contains_or_insert::HashsetInsertAfterContains));
+    store.register_early_pass(|| Box::new(byte_char_slices::ByteCharSlice));
+    store.register_early_pass(|| Box::new(cfg_not_test::CfgNotTest));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index d2a140a36a8..7481543941a 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -233,11 +233,9 @@ impl_lint_pass!(LiteralDigitGrouping => [
 
 impl EarlyLintPass for LiteralDigitGrouping {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if in_external_macro(cx.sess(), expr.span) {
-            return;
-        }
-
-        if let ExprKind::Lit(lit) = expr.kind {
+        if let ExprKind::Lit(lit) = expr.kind
+            && !in_external_macro(cx.sess(), expr.span)
+        {
             self.check_lit(cx, lit, expr.span);
         }
     }
@@ -448,11 +446,9 @@ impl_lint_pass!(DecimalLiteralRepresentation => [DECIMAL_LITERAL_REPRESENTATION]
 
 impl EarlyLintPass for DecimalLiteralRepresentation {
     fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
-        if in_external_macro(cx.sess(), expr.span) {
-            return;
-        }
-
-        if let ExprKind::Lit(lit) = expr.kind {
+        if let ExprKind::Lit(lit) = expr.kind
+            && !in_external_macro(cx.sess(), expr.span)
+        {
             self.check_lit(cx, lit, expr.span);
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs
index 24fc2b4faea..d9f6be6dc2b 100644
--- a/src/tools/clippy/clippy_lints/src/manual_bits.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs
@@ -50,13 +50,10 @@ impl_lint_pass!(ManualBits => [MANUAL_BITS]);
 
 impl<'tcx> LateLintPass<'tcx> for ManualBits {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !self.msrv.meets(msrvs::MANUAL_BITS) {
-            return;
-        }
-
         if let ExprKind::Binary(bin_op, left_expr, right_expr) = expr.kind
             && let BinOpKind::Mul = &bin_op.node
             && !in_external_macro(cx.sess(), expr.span)
+            && self.msrv.meets(msrvs::MANUAL_BITS)
             && let ctxt = expr.span.ctxt()
             && left_expr.span.ctxt() == ctxt
             && right_expr.span.ctxt() == ctxt
diff --git a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
index 89eea0b4456..03416ba96de 100644
--- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
@@ -82,29 +82,26 @@ impl Variant {
 
 impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if !in_external_macro(cx.sess(), expr.span)
-            && (
-                matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst)
-                    || cx.tcx.features().declared(sym!(const_float_classify))
-            ) && let ExprKind::Binary(kind, lhs, rhs) = expr.kind
+        if let ExprKind::Binary(kind, lhs, rhs) = expr.kind
             && let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind
             && let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind
             // Checking all possible scenarios using a function would be a hopeless task, as we have
             // 16 possible alignments of constants/operands. For now, let's use `partition`.
-            && let (operands, constants) = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs]
-                .into_iter()
-                .partition::<Vec<&Expr<'_>>, _>(|i| path_to_local(i).is_some())
-            && let [first, second] = &*operands
-            && let Some([const_1, const_2]) = constants
-                .into_iter()
-                .map(|i| constant(cx, cx.typeck_results(), i))
-                .collect::<Option<Vec<_>>>()
-                .as_deref()
+            && let mut exprs = [lhs_lhs, lhs_rhs, rhs_lhs, rhs_rhs]
+            && exprs.iter_mut().partition_in_place(|i| path_to_local(i).is_some()) == 2
+            && !in_external_macro(cx.sess(), expr.span)
+            && (
+                matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst)
+                    || cx.tcx.features().declared(sym!(const_float_classify))
+            )
+            && let [first, second, const_1, const_2] = exprs
+            && let Some(const_1) = constant(cx, cx.typeck_results(), const_1)
+            && let Some(const_2) = constant(cx, cx.typeck_results(), const_2)
             && path_to_local(first).is_some_and(|f| path_to_local(second).is_some_and(|s| f == s))
             // The actual infinity check, we also allow `NEG_INFINITY` before` INFINITY` just in
             // case somebody does that for some reason
-            && (is_infinity(const_1) && is_neg_infinity(const_2)
-                || is_neg_infinity(const_1) && is_infinity(const_2))
+            && (is_infinity(&const_1) && is_neg_infinity(&const_2)
+                || is_neg_infinity(&const_1) && is_infinity(&const_2))
             && let Some(local_snippet) = snippet_opt(cx, first.span)
         {
             let variant = match (kind.node, lhs_kind.node, rhs_kind.node) {
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index 03e4d668dd8..ebebdf679a8 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -49,16 +49,14 @@ declare_clippy_lint! {
 
 impl<'tcx> QuestionMark {
     pub(crate) fn check_manual_let_else(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'tcx>) {
-        if !self.msrv.meets(msrvs::LET_ELSE) || in_external_macro(cx.sess(), stmt.span) {
-            return;
-        }
-
         if let StmtKind::Let(local) = stmt.kind
             && let Some(init) = local.init
             && local.els.is_none()
             && local.ty.is_none()
             && init.span.eq_ctxt(stmt.span)
             && let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init)
+            && self.msrv.meets(msrvs::LET_ELSE)
+            && !in_external_macro(cx.sess(), stmt.span)
         {
             match if_let_or_match {
                 IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else, ..) => {
diff --git a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs
index 5732bdda7f2..8e8cdc3fb07 100644
--- a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs
@@ -47,13 +47,13 @@ impl_lint_pass!(ManualMainSeparatorStr => [MANUAL_MAIN_SEPARATOR_STR]);
 
 impl LateLintPass<'_> for ManualMainSeparatorStr {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        if self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR)
-            && let (target, _) = peel_hir_expr_refs(expr)
-            && is_trait_method(cx, target, sym::ToString)
-            && let ExprKind::MethodCall(path, receiver, &[], _) = target.kind
+        let (target, _) = peel_hir_expr_refs(expr);
+        if let ExprKind::MethodCall(path, receiver, &[], _) = target.kind
             && path.ident.name == sym::to_string
             && let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind
             && let Res::Def(DefKind::Const, receiver_def_id) = path.res
+            && is_trait_method(cx, target, sym::ToString)
+            && self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR)
             && match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR)
             && let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind()
             && ty.is_str()
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index d2ac0ad8363..73a505fd73f 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -97,19 +97,15 @@ impl_lint_pass!(ManualNonExhaustiveEnum => [MANUAL_NON_EXHAUSTIVE]);
 
 impl EarlyLintPass for ManualNonExhaustiveStruct {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
-        if !self.msrv.meets(msrvs::NON_EXHAUSTIVE) {
-            return;
-        }
-
-        if let ast::ItemKind::Struct(variant_data, _) = &item.kind {
-            let (fields, delimiter) = match variant_data {
+        if let ast::ItemKind::Struct(variant_data, _) = &item.kind
+            && let (fields, delimiter) = match variant_data {
                 ast::VariantData::Struct { fields, .. } => (&**fields, '{'),
                 ast::VariantData::Tuple(fields, _) => (&**fields, '('),
                 ast::VariantData::Unit(_) => return,
-            };
-            if fields.len() <= 1 {
-                return;
             }
+            && fields.len() > 1
+            && self.msrv.meets(msrvs::NON_EXHAUSTIVE)
+        {
             let mut iter = fields.iter().filter_map(|f| match f.vis.kind {
                 VisibilityKind::Public => None,
                 VisibilityKind::Inherited => Some(Ok(f)),
diff --git a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
index ec60de92c4b..07d4abbf5cd 100644
--- a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
@@ -76,14 +76,11 @@ impl Num {
 
 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
         // or at least one range
         if let PatKind::Or(pats) = pat.kind
             && (pats.len() >= 3 || pats.iter().any(|p| matches!(p.kind, PatKind::Range(..))))
+            && !in_external_macro(cx.sess(), pat.span)
         {
             let mut min = Num::dummy(i128::MAX);
             let mut max = Num::dummy(i128::MIN);
diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
index ab9bca170cf..b518dc26937 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
@@ -48,35 +48,30 @@ impl_lint_pass!(ManualRemEuclid => [MANUAL_REM_EUCLID]);
 
 impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !self.msrv.meets(msrvs::REM_EUCLID) {
-            return;
-        }
-
-        if in_constant(cx, expr.hir_id) && !self.msrv.meets(msrvs::REM_EUCLID_CONST) {
-            return;
-        }
-
-        if in_external_macro(cx.sess(), expr.span) {
-            return;
-        }
-
         // (x % c + c) % c
-        if let ExprKind::Binary(op1, expr1, right) = expr.kind
-            && op1.node == BinOpKind::Rem
+        if let ExprKind::Binary(rem_op, rem_lhs, rem_rhs) = expr.kind
+            && rem_op.node == BinOpKind::Rem
+            && let ExprKind::Binary(add_op, add_lhs, add_rhs) = rem_lhs.kind
+            && add_op.node == BinOpKind::Add
             && let ctxt = expr.span.ctxt()
-            && expr1.span.ctxt() == ctxt
-            && let Some(const1) = check_for_unsigned_int_constant(cx, right)
-            && let ExprKind::Binary(op2, left, right) = expr1.kind
-            && op2.node == BinOpKind::Add
-            && let Some((const2, expr2)) = check_for_either_unsigned_int_constant(cx, left, right)
-            && expr2.span.ctxt() == ctxt
-            && let ExprKind::Binary(op3, expr3, right) = expr2.kind
-            && op3.node == BinOpKind::Rem
-            && let Some(const3) = check_for_unsigned_int_constant(cx, right)
+            && rem_lhs.span.ctxt() == ctxt
+            && rem_rhs.span.ctxt() == ctxt
+            && add_lhs.span.ctxt() == ctxt
+            && add_rhs.span.ctxt() == ctxt
+            && !in_external_macro(cx.sess(), expr.span)
+            && self.msrv.meets(msrvs::REM_EUCLID)
+            && (self.msrv.meets(msrvs::REM_EUCLID_CONST) || !in_constant(cx, expr.hir_id))
+            && let Some(const1) = check_for_unsigned_int_constant(cx, rem_rhs)
+            && let Some((const2, add_other)) = check_for_either_unsigned_int_constant(cx, add_lhs, add_rhs)
+            && let ExprKind::Binary(rem2_op, rem2_lhs, rem2_rhs) = add_other.kind
+            && rem2_op.node == BinOpKind::Rem
+            && const1 == const2
+            && let Some(hir_id) = path_to_local(rem2_lhs)
+            && let Some(const3) = check_for_unsigned_int_constant(cx, rem2_rhs)
             // Also ensures the const is nonzero since zero can't be a divisor
-            && const1 == const2 && const2 == const3
-            && let Some(hir_id) = path_to_local(expr3)
-            && let Node::Pat(_) = cx.tcx.hir_node(hir_id)
+            && const2 == const3
+            && rem2_lhs.span.ctxt() == ctxt
+            && rem2_rhs.span.ctxt() == ctxt
         {
             // Apply only to params or locals with annotated types
             match cx.tcx.parent_hir_node(hir_id) {
@@ -91,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
             };
 
             let mut app = Applicability::MachineApplicable;
-            let rem_of = snippet_with_context(cx, expr3.span, ctxt, "_", &mut app).0;
+            let rem_of = snippet_with_context(cx, rem2_lhs.span, ctxt, "_", &mut app).0;
             span_lint_and_sugg(
                 cx,
                 MANUAL_REM_EUCLID,
diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs
index 3ddb06a1e08..8f7b8abd0c3 100644
--- a/src/tools/clippy/clippy_lints/src/manual_retain.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs
@@ -70,9 +70,8 @@ impl_lint_pass!(ManualRetain => [MANUAL_RETAIN]);
 impl<'tcx> LateLintPass<'tcx> for ManualRetain {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
         if let Assign(left_expr, collect_expr, _) = &expr.kind
-            && let hir::ExprKind::MethodCall(seg, ..) = &collect_expr.kind
+            && let hir::ExprKind::MethodCall(seg, target_expr, [], _) = &collect_expr.kind
             && seg.args.is_none()
-            && let hir::ExprKind::MethodCall(_, target_expr, [], _) = &collect_expr.kind
             && let Some(collect_def_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id)
             && cx.tcx.is_diagnostic_item(sym::iterator_collect_fn, collect_def_id)
         {
diff --git a/src/tools/clippy/clippy_lints/src/manual_rotate.rs b/src/tools/clippy/clippy_lints/src/manual_rotate.rs
new file mode 100644
index 00000000000..a517a4d5075
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/manual_rotate.rs
@@ -0,0 +1,117 @@
+use std::fmt::Display;
+
+use clippy_utils::consts::{constant, Constant};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::sugg;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
+use rustc_session::declare_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// It detects manual bit rotations that could be rewritten using standard
+    /// functions `rotate_left` or `rotate_right`.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// Calling the function better conveys the intent.
+    ///
+    /// ### Known issues
+    ///
+    /// Currently, the lint only catches shifts by constant amount.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let x = 12345678_u32;
+    /// let _ = (x >> 8) | (x << 24);
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// let x = 12345678_u32;
+    /// let _ = x.rotate_right(8);
+    /// ```
+    #[clippy::version = "1.81.0"]
+    pub MANUAL_ROTATE,
+    style,
+    "using bit shifts to rotate integers"
+}
+
+declare_lint_pass!(ManualRotate => [MANUAL_ROTATE]);
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+enum ShiftDirection {
+    Left,
+    Right,
+}
+
+impl Display for ShiftDirection {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.write_str(match self {
+            Self::Left => "rotate_left",
+            Self::Right => "rotate_right",
+        })
+    }
+}
+
+fn parse_shift<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+) -> Option<(ShiftDirection, u128, &'tcx Expr<'tcx>)> {
+    if let ExprKind::Binary(op, l, r) = expr.kind {
+        let dir = match op.node {
+            BinOpKind::Shl => ShiftDirection::Left,
+            BinOpKind::Shr => ShiftDirection::Right,
+            _ => return None,
+        };
+        let const_expr = constant(cx, cx.typeck_results(), r)?;
+        if let Constant::Int(shift) = const_expr {
+            return Some((dir, shift, l));
+        }
+    }
+    None
+}
+
+impl LateLintPass<'_> for ManualRotate {
+    fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
+        if let ExprKind::Binary(op, l, r) = expr.kind
+            && let BinOpKind::Add | BinOpKind::BitOr = op.node
+            && let Some((l_shift_dir, l_amount, l_expr)) = parse_shift(cx, l)
+            && let Some((r_shift_dir, r_amount, r_expr)) = parse_shift(cx, r)
+        {
+            if l_shift_dir == r_shift_dir {
+                return;
+            }
+            if !clippy_utils::eq_expr_value(cx, l_expr, r_expr) {
+                return;
+            }
+            let Some(bit_width) = (match cx.typeck_results().expr_ty(expr).kind() {
+                ty::Int(itype) => itype.bit_width(),
+                ty::Uint(itype) => itype.bit_width(),
+                _ => return,
+            }) else {
+                return;
+            };
+            if l_amount + r_amount == u128::from(bit_width) {
+                let (shift_function, amount) = if l_amount < r_amount {
+                    (l_shift_dir, l_amount)
+                } else {
+                    (r_shift_dir, r_amount)
+                };
+                let mut applicability = Applicability::MachineApplicable;
+                let expr_sugg = sugg::Sugg::hir_with_applicability(cx, l_expr, "_", &mut applicability).maybe_par();
+                span_lint_and_sugg(
+                    cx,
+                    MANUAL_ROTATE,
+                    expr.span,
+                    "there is no need to manually implement bit rotation",
+                    "this expression can be rewritten as",
+                    format!("{expr_sugg}.{shift_function}({amount})"),
+                    Applicability::MachineApplicable,
+                );
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
index 1de686dbcb5..429ee2637c2 100644
--- a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
@@ -40,11 +40,11 @@ declare_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION]
 
 impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        // Does not apply inside const because size_of_val is not cost in stable.
-        if !in_constant(cx, expr.hir_id)
-            && let ExprKind::Binary(ref op, left, right) = expr.kind
+        if let ExprKind::Binary(ref op, left, right) = expr.kind
             && BinOpKind::Mul == op.node
             && !expr.span.from_expansion()
+            // Does not apply inside const because size_of_val is not cost in stable.
+            && !in_constant(cx, expr.hir_id)
             && let Some(receiver) = simplify(cx, left, right)
         {
             let ctxt = expr.span.ctxt();
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index 45af9f07718..6a523ad1564 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -66,14 +66,11 @@ enum StripKind {
 
 impl<'tcx> LateLintPass<'tcx> for ManualStrip {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if !self.msrv.meets(msrvs::STR_STRIP_PREFIX) {
-            return;
-        }
-
         if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr)
             && let ExprKind::MethodCall(_, target_arg, [pattern], _) = cond.kind
-            && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id)
             && let ExprKind::Path(target_path) = &target_arg.kind
+            && self.msrv.meets(msrvs::STR_STRIP_PREFIX)
+            && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(cond.hir_id)
         {
             let strip_kind = if match_def_path(cx, method_def_id, &paths::STR_STARTS_WITH) {
                 StripKind::Prefix
diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
index 58b2ebebbf0..f1acc4b2174 100644
--- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
@@ -172,11 +172,10 @@ fn handle<'tcx>(cx: &LateContext<'tcx>, if_let_or_match: IfLetOrMatch<'tcx>, exp
 
 impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
-        if expr.span.from_expansion() || in_constant(cx, expr.hir_id) {
-            return;
-        }
-        // Call handle only if the expression is `if let` or `match`
-        if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr) {
+        if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr)
+            && !expr.span.from_expansion()
+            && !in_constant(cx, expr.hir_id)
+        {
             handle(cx, if_let_or_match, expr);
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index 9db04b615be..2db71b1f7a3 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -253,14 +253,11 @@ fn lint_map_unit_fn(
 
 impl<'tcx> LateLintPass<'tcx> for MapUnit {
     fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &hir::Stmt<'_>) {
-        if stmt.span.from_expansion() {
-            return;
-        }
-
-        if let hir::StmtKind::Semi(expr) = stmt.kind {
-            if let Some(arglists) = method_chain_args(expr, &["map"]) {
-                lint_map_unit_fn(cx, stmt, expr, arglists[0]);
-            }
+        if let hir::StmtKind::Semi(expr) = stmt.kind
+            && !stmt.span.from_expansion()
+            && let Some(arglists) = method_chain_args(expr, &["map"])
+        {
+            lint_map_unit_fn(cx, stmt, expr, arglists[0]);
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index bf7156cc53e..22a299ae3d8 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -1019,6 +1019,7 @@ impl_lint_pass!(Matches => [
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Matches {
+    #[expect(clippy::too_many_lines)]
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if is_direct_expn_of(expr.span, "matches").is_none() && in_external_macro(cx.sess(), expr.span) {
             return;
@@ -1037,7 +1038,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                 return;
             }
             if matches!(source, MatchSource::Normal | MatchSource::ForLoopDesugar) {
-                significant_drop_in_scrutinee::check(cx, expr, ex, arms, source);
+                significant_drop_in_scrutinee::check_match(cx, expr, ex, arms, source);
             }
 
             collapsible_match::check_match(cx, arms, &self.msrv);
@@ -1084,6 +1085,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
             }
         } else if let Some(if_let) = higher::IfLet::hir(cx, expr) {
             collapsible_match::check_if_let(cx, if_let.let_pat, if_let.if_then, if_let.if_else, &self.msrv);
+            significant_drop_in_scrutinee::check_if_let(cx, expr, if_let.let_expr, if_let.if_then, if_let.if_else);
             if !from_expansion {
                 if let Some(else_expr) = if_let.if_else {
                     if self.msrv.meets(msrvs::MATCHES_MACRO) {
@@ -1126,8 +1128,13 @@ impl<'tcx> LateLintPass<'tcx> for Matches {
                 );
                 needless_match::check_if_let(cx, expr, &if_let);
             }
-        } else if !from_expansion {
-            redundant_pattern_match::check(cx, expr);
+        } else {
+            if let Some(while_let) = higher::WhileLet::hir(expr) {
+                significant_drop_in_scrutinee::check_while_let(cx, expr, while_let.let_expr, while_let.if_then);
+            }
+            if !from_expansion {
+                redundant_pattern_match::check(cx, expr);
+            }
         }
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index 2f72e59834f..9047c9627d9 100644
--- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -16,7 +16,7 @@ use rustc_span::Span;
 
 use super::SIGNIFICANT_DROP_IN_SCRUTINEE;
 
-pub(super) fn check<'tcx>(
+pub(super) fn check_match<'tcx>(
     cx: &LateContext<'tcx>,
     expr: &'tcx Expr<'tcx>,
     scrutinee: &'tcx Expr<'_>,
@@ -27,10 +27,89 @@ pub(super) fn check<'tcx>(
         return;
     }
 
-    let (suggestions, message) = has_significant_drop_in_scrutinee(cx, scrutinee, source);
+    let scrutinee = match (source, &scrutinee.kind) {
+        (MatchSource::ForLoopDesugar, ExprKind::Call(_, [e])) => e,
+        _ => scrutinee,
+    };
+
+    let message = if source == MatchSource::Normal {
+        "temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression"
+    } else {
+        "temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression"
+    };
+
+    let arms = arms.iter().map(|arm| arm.body).collect::<Vec<_>>();
+
+    check(cx, expr, scrutinee, &arms, message, Suggestion::Emit);
+}
+
+pub(super) fn check_if_let<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    scrutinee: &'tcx Expr<'_>,
+    if_then: &'tcx Expr<'_>,
+    if_else: Option<&'tcx Expr<'_>>,
+) {
+    if is_lint_allowed(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, expr.hir_id) {
+        return;
+    }
+
+    let message =
+        "temporary with significant `Drop` in `if let` scrutinee will live until the end of the `if let` expression";
+
+    if let Some(if_else) = if_else {
+        check(cx, expr, scrutinee, &[if_then, if_else], message, Suggestion::Emit);
+    } else {
+        check(cx, expr, scrutinee, &[if_then], message, Suggestion::Emit);
+    }
+}
+
+pub(super) fn check_while_let<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    scrutinee: &'tcx Expr<'_>,
+    body: &'tcx Expr<'_>,
+) {
+    if is_lint_allowed(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, expr.hir_id) {
+        return;
+    }
+
+    check(
+        cx,
+        expr,
+        scrutinee,
+        &[body],
+        "temporary with significant `Drop` in `while let` scrutinee will live until the end of the `while let` expression",
+        // Don't emit wrong suggestions: We cannot fix the significant drop in the `while let` scrutinee by simply
+        // moving it out. We need to change the `while` to a `loop` instead.
+        Suggestion::DontEmit,
+    );
+}
+
+#[derive(Copy, Clone, Debug)]
+enum Suggestion {
+    Emit,
+    DontEmit,
+}
+
+fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+    scrutinee: &'tcx Expr<'_>,
+    arms: &[&'tcx Expr<'_>],
+    message: &'static str,
+    sugg: Suggestion,
+) {
+    let mut helper = SigDropHelper::new(cx);
+    let suggestions = helper.find_sig_drop(scrutinee);
+
     for found in suggestions {
         span_lint_and_then(cx, SIGNIFICANT_DROP_IN_SCRUTINEE, found.found_span, message, |diag| {
-            set_diagnostic(diag, cx, expr, found);
+            match sugg {
+                Suggestion::Emit => set_suggestion(diag, cx, expr, found),
+                Suggestion::DontEmit => (),
+            }
+
             let s = Span::new(expr.span.hi(), expr.span.hi(), expr.span.ctxt(), None);
             diag.span_label(s, "temporary lives until here");
             for span in has_significant_drop_in_arms(cx, arms) {
@@ -41,7 +120,7 @@ pub(super) fn check<'tcx>(
     }
 }
 
-fn set_diagnostic<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, found: FoundSigDrop) {
+fn set_suggestion<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, found: FoundSigDrop) {
     let original = snippet(cx, found.found_span, "..");
     let trailing_indent = " ".repeat(indent_of(cx, found.found_span).unwrap_or(0));
 
@@ -79,26 +158,6 @@ fn set_diagnostic<'tcx>(diag: &mut Diag<'_, ()>, cx: &LateContext<'tcx>, expr: &
     );
 }
 
-/// If the expression is an `ExprKind::Match`, check if the scrutinee has a significant drop that
-/// may have a surprising lifetime.
-fn has_significant_drop_in_scrutinee<'tcx>(
-    cx: &LateContext<'tcx>,
-    scrutinee: &'tcx Expr<'tcx>,
-    source: MatchSource,
-) -> (Vec<FoundSigDrop>, &'static str) {
-    let mut helper = SigDropHelper::new(cx);
-    let scrutinee = match (source, &scrutinee.kind) {
-        (MatchSource::ForLoopDesugar, ExprKind::Call(_, [e])) => e,
-        _ => scrutinee,
-    };
-    let message = if source == MatchSource::Normal {
-        "temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression"
-    } else {
-        "temporary with significant `Drop` in `for` loop condition will live until the end of the `for` expression"
-    };
-    (helper.find_sig_drop(scrutinee), message)
-}
-
 struct SigDropChecker<'a, 'tcx> {
     seen_types: FxHashSet<Ty<'tcx>>,
     cx: &'a LateContext<'tcx>,
@@ -428,10 +487,10 @@ impl<'a, 'tcx> ArmSigDropHelper<'a, 'tcx> {
     }
 }
 
-fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) -> FxHashSet<Span> {
+fn has_significant_drop_in_arms<'tcx>(cx: &LateContext<'tcx>, arms: &[&'tcx Expr<'_>]) -> FxHashSet<Span> {
     let mut helper = ArmSigDropHelper::new(cx);
     for arm in arms {
-        helper.visit_expr(arm.body);
+        helper.visit_expr(arm);
     }
     helper.found_sig_drop_spans
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
index e3ce64c246a..cac2e11f591 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_inspect.rs
@@ -167,14 +167,12 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
             } else {
                 edits.extend(addr_of_edits);
             }
-            edits.push((
-                name_span,
-                String::from(match name {
-                    "map" => "inspect",
-                    "map_err" => "inspect_err",
-                    _ => return,
-                }),
-            ));
+            let edit = match name {
+                "map" => "inspect",
+                "map_err" => "inspect_err",
+                _ => return,
+            };
+            edits.push((name_span, edit.to_string()));
             edits.push((
                 final_expr
                     .span
@@ -187,9 +185,15 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arg: &Expr<'_>, name:
             } else {
                 Applicability::MachineApplicable
             };
-            span_lint_and_then(cx, MANUAL_INSPECT, name_span, "", |diag| {
-                diag.multipart_suggestion("try", edits, app);
-            });
+            span_lint_and_then(
+                cx,
+                MANUAL_INSPECT,
+                name_span,
+                format!("using `{name}` over `{edit}`"),
+                |diag| {
+                    diag.multipart_suggestion("try", edits, app);
+                },
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 1408f454820..a846552cddf 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -628,12 +628,11 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))` or
-    /// `_.or_else(|x| Err(y))`.
+    /// Checks for usage of `_.and_then(|x| Some(y))`, `_.and_then(|x| Ok(y))`
+    /// or `_.or_else(|x| Err(y))`.
     ///
     /// ### Why is this bad?
-    /// Readability, this can be written more concisely as
-    /// `_.map(|x| y)` or `_.map_err(|x| y)`.
+    /// This can be written more concisely as `_.map(|x| y)` or `_.map_err(|x| y)`.
     ///
     /// ### Example
     /// ```no_run
@@ -4121,7 +4120,7 @@ declare_clippy_lint! {
     /// ```no_run
     /// let x = Some(0).inspect(|x| println!("{x}"));
     /// ```
-    #[clippy::version = "1.78.0"]
+    #[clippy::version = "1.81.0"]
     pub MANUAL_INSPECT,
     complexity,
     "use of `map` returning the original item"
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index ae9aa83efd6..5d899415d77 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -1,13 +1,15 @@
 use super::implicit_clone::is_clone_like;
 use super::unnecessary_iter_cloned::{self, is_into_iter};
 use clippy_config::msrvs::{self, Msrv};
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_opt;
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::source::{snippet, snippet_opt};
 use clippy_utils::ty::{
     get_iterator_item_ty, implements_trait, is_copy, is_type_diagnostic_item, is_type_lang_item, peel_mid_ty_refs,
 };
 use clippy_utils::visitors::find_all_ret_expressions;
-use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty};
+use clippy_utils::{
+    fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, match_def_path, paths, return_ty,
+};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -52,6 +54,9 @@ pub fn check<'tcx>(
             if check_into_iter_call_arg(cx, expr, method_name, receiver, msrv) {
                 return;
             }
+            if check_string_from_utf8(cx, expr, receiver) {
+                return;
+            }
             check_other_call_arg(cx, expr, method_name, receiver);
         }
     } else {
@@ -240,6 +245,65 @@ fn check_into_iter_call_arg(
     false
 }
 
+/// Checks for `&String::from_utf8(bytes.{to_vec,to_owned,...}()).unwrap()` coercing to `&str`,
+/// which can be written as just `std::str::from_utf8(bytes).unwrap()`.
+fn check_string_from_utf8<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, receiver: &'tcx Expr<'tcx>) -> bool {
+    if let Some((call, arg)) = skip_addr_of_ancestors(cx, expr)
+        && !arg.span.from_expansion()
+        && let ExprKind::Call(callee, _) = call.kind
+        && fn_def_id(cx, call).is_some_and(|did| match_def_path(cx, did, &paths::STRING_FROM_UTF8))
+        && let Some(unwrap_call) = get_parent_expr(cx, call)
+        && let ExprKind::MethodCall(unwrap_method_name, ..) = unwrap_call.kind
+        && matches!(unwrap_method_name.ident.name, sym::unwrap | sym::expect)
+        && let Some(ref_string) = get_parent_expr(cx, unwrap_call)
+        && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, _) = ref_string.kind
+        && let adjusted_ty = cx.typeck_results().expr_ty_adjusted(ref_string)
+        // `&...` creates a `&String`, so only actually lint if this coerces to a `&str`
+        && matches!(adjusted_ty.kind(), ty::Ref(_, ty, _) if ty.is_str())
+    {
+        span_lint_and_then(
+            cx,
+            UNNECESSARY_TO_OWNED,
+            ref_string.span,
+            "allocating a new `String` only to create a temporary `&str` from it",
+            |diag| {
+                let arg_suggestion = format!(
+                    "{borrow}{recv_snippet}",
+                    recv_snippet = snippet(cx, receiver.span.source_callsite(), ".."),
+                    borrow = if cx.typeck_results().expr_ty(receiver).is_ref() {
+                        ""
+                    } else {
+                        // If not already a reference, prefix with a borrow so that it can coerce to one
+                        "&"
+                    }
+                );
+
+                diag.multipart_suggestion(
+                    "convert from `&[u8]` to `&str` directly",
+                    vec![
+                        // `&String::from_utf8(bytes.to_vec()).unwrap()`
+                        //   ^^^^^^^^^^^^^^^^^
+                        (callee.span, "core::str::from_utf8".into()),
+                        // `&String::from_utf8(bytes.to_vec()).unwrap()`
+                        //  ^
+                        (
+                            ref_string.span.shrink_to_lo().to(unwrap_call.span.shrink_to_lo()),
+                            String::new(),
+                        ),
+                        // `&String::from_utf8(bytes.to_vec()).unwrap()`
+                        //                     ^^^^^^^^^^^^^^
+                        (arg.span, arg_suggestion),
+                    ],
+                    Applicability::MachineApplicable,
+                );
+            },
+        );
+        true
+    } else {
+        false
+    }
+}
+
 /// Checks whether `expr` is an argument in an `into_iter` call and, if so, determines whether its
 /// call of a `to_owned`-like function is unnecessary.
 fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, receiver: &Expr<'_>) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs
index 516b8984ad7..5b0bd0f716a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_expect_used.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::{is_never_like, is_type_diagnostic_item};
-use clippy_utils::{is_in_cfg_test, is_in_test_function, is_lint_allowed};
+use clippy_utils::{is_in_test, is_lint_allowed};
 use rustc_hir::Expr;
 use rustc_lint::{LateContext, Lint};
 use rustc_middle::ty;
@@ -61,7 +61,7 @@ pub(super) fn check(
 
     let method_suffix = if is_err { "_err" } else { "" };
 
-    if allow_unwrap_in_tests && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id)) {
+    if allow_unwrap_in_tests && is_in_test(cx.tcx, expr.hir_id) {
         return;
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs
index fca626fa5c3..c3fbca1d560 100644
--- a/src/tools/clippy/clippy_lints/src/minmax.rs
+++ b/src/tools/clippy/clippy_lints/src/minmax.rs
@@ -5,7 +5,7 @@ use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
-use std::cmp::Ordering;
+use std::cmp::Ordering::{Equal, Greater, Less};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -36,26 +36,21 @@ declare_lint_pass!(MinMaxPass => [MIN_MAX]);
 
 impl<'tcx> LateLintPass<'tcx> for MinMaxPass {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let Some((outer_max, outer_c, oe)) = min_max(cx, expr) {
-            if let Some((inner_max, inner_c, ie)) = min_max(cx, oe) {
-                if outer_max == inner_max {
-                    return;
-                }
-                match (
-                    outer_max,
-                    Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(ie), &outer_c, &inner_c),
-                ) {
-                    (_, None) | (MinMax::Max, Some(Ordering::Less)) | (MinMax::Min, Some(Ordering::Greater)) => (),
-                    _ => {
-                        span_lint(
-                            cx,
-                            MIN_MAX,
-                            expr.span,
-                            "this `min`/`max` combination leads to constant result",
-                        );
-                    },
-                }
-            }
+        if let Some((outer_max, outer_c, oe)) = min_max(cx, expr)
+            && let Some((inner_max, inner_c, ie)) = min_max(cx, oe)
+            && outer_max != inner_max
+            && let Some(ord) = Constant::partial_cmp(cx.tcx, cx.typeck_results().expr_ty(ie), &outer_c, &inner_c)
+            && matches!(
+                (outer_max, ord),
+                (MinMax::Max, Equal | Greater) | (MinMax::Min, Equal | Less)
+            )
+        {
+            span_lint(
+                cx,
+                MIN_MAX,
+                expr.span,
+                "this `min`/`max` combination leads to constant result",
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index f3f9bf11a61..32c8731c537 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -2,8 +2,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then, span_lint_hir_and
 use clippy_utils::source::{snippet, snippet_with_context};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::{
-    any_parent_is_automatically_derived, fulfill_or_allowed, get_parent_expr, is_lint_allowed, iter_input_pats,
-    last_path_segment, SpanlessEq,
+    fulfill_or_allowed, get_parent_expr, in_automatically_derived, is_lint_allowed, iter_input_pats, last_path_segment,
+    SpanlessEq,
 };
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -206,7 +206,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if in_external_macro(cx.sess(), expr.span)
             || expr.span.desugaring_kind().is_some()
-            || any_parent_is_automatically_derived(cx.tcx, expr.hir_id)
+            || in_automatically_derived(cx.tcx, expr.hir_id)
         {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
index dd98352da86..935ed48dacc 100644
--- a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::is_in_test;
 use clippy_utils::macros::{find_assert_args, find_assert_eq_args, root_macro_call_first_node, PanicExpn};
-use clippy_utils::{is_in_cfg_test, is_in_test_function};
 use rustc_hir::Expr;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingAssertMessage {
         };
 
         // This lint would be very noisy in tests, so just ignore if we're in test context
-        if is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id) {
+        if is_in_test(cx.tcx, expr.hir_id) {
             return;
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index bb0d714a31f..ed5f46ddc8d 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -8,9 +8,11 @@ use rustc_hir::intravisit::FnKind;
 use rustc_hir::{self as hir, Body, Constness, FnDecl, GenericParamKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::Span;
+use rustc_target::spec::abi::Abi;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -115,7 +117,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
                     .iter()
                     .any(|param| matches!(param.kind, GenericParamKind::Const { .. }));
 
-                if already_const(header) || has_const_generic_params {
+                if already_const(header)
+                    || has_const_generic_params
+                    || !could_be_const_with_abi(cx, &self.msrv, header.abi)
+                {
                     return;
                 }
             },
@@ -127,6 +132,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
             FnKind::Closure => return,
         }
 
+        if fn_inputs_has_impl_trait_ty(cx, def_id) {
+            return;
+        }
+
         let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
 
         // Const fns are not allowed as methods in a trait.
@@ -171,3 +180,25 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
 fn already_const(header: hir::FnHeader) -> bool {
     header.constness == Constness::Const
 }
+
+fn could_be_const_with_abi(cx: &LateContext<'_>, msrv: &Msrv, abi: Abi) -> bool {
+    match abi {
+        Abi::Rust => true,
+        // `const extern "C"` was stablized after 1.62.0
+        Abi::C { unwind: false } => msrv.meets(msrvs::CONST_EXTERN_FN),
+        // Rest ABIs are still unstable and need the `const_extern_fn` feature enabled.
+        _ => cx.tcx.features().const_extern_fn,
+    }
+}
+
+/// Return `true` when the given `def_id` is a function that has `impl Trait` ty as one of
+/// its parameter types.
+fn fn_inputs_has_impl_trait_ty(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
+    let inputs = cx.tcx.fn_sig(def_id).instantiate_identity().inputs().skip_binder();
+    inputs.iter().any(|input| {
+        matches!(
+            input.kind(),
+            ty::Alias(ty::AliasTyKind::Weak, alias_ty) if cx.tcx.type_of(alias_ty.def_id).skip_binder().is_impl_trait()
+        )
+    })
+}
diff --git a/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_thread_local.rs
index 4af3ee74d0e..ab1b4aa3dee 100644
--- a/src/tools/clippy/clippy_lints/src/thread_local_initializer_can_be_made_const.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_thread_local.rs
@@ -39,23 +39,23 @@ declare_clippy_lint! {
     /// }
     /// ```
     #[clippy::version = "1.77.0"]
-    pub THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST,
+    pub MISSING_CONST_FOR_THREAD_LOCAL,
     perf,
     "suggest using `const` in `thread_local!` macro"
 }
 
-pub struct ThreadLocalInitializerCanBeMadeConst {
+pub struct MissingConstForThreadLocal {
     msrv: Msrv,
 }
 
-impl ThreadLocalInitializerCanBeMadeConst {
+impl MissingConstForThreadLocal {
     #[must_use]
     pub fn new(msrv: Msrv) -> Self {
         Self { msrv }
     }
 }
 
-impl_lint_pass!(ThreadLocalInitializerCanBeMadeConst => [THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST]);
+impl_lint_pass!(MissingConstForThreadLocal => [MISSING_CONST_FOR_THREAD_LOCAL]);
 
 #[inline]
 fn is_thread_local_initializer(
@@ -102,7 +102,7 @@ fn initializer_can_be_made_const(cx: &LateContext<'_>, defid: rustc_span::def_id
     false
 }
 
-impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst {
+impl<'tcx> LateLintPass<'tcx> for MissingConstForThreadLocal {
     fn check_fn(
         &mut self,
         cx: &LateContext<'tcx>,
@@ -113,7 +113,7 @@ impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst {
         local_defid: rustc_span::def_id::LocalDefId,
     ) {
         let defid = local_defid.to_def_id();
-        if self.msrv.meets(msrvs::THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST)
+        if self.msrv.meets(msrvs::THREAD_LOCAL_CONST_INIT)
             && is_thread_local_initializer(cx, fn_kind, span).unwrap_or(false)
             // Some implementations of `thread_local!` include an initializer fn.
             // In the case of a const initializer, the init fn is also const,
@@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for ThreadLocalInitializerCanBeMadeConst {
         {
             span_lint_and_sugg(
                 cx,
-                THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST,
+                MISSING_CONST_FOR_THREAD_LOCAL,
                 unpeeled.span,
                 "initializer for `thread_local` value can be made `const`",
                 "replace with",
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
index 57ba0da5331..5ffd41d78e0 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -27,7 +27,7 @@ declare_clippy_lint! {
     /// Check if a `&mut` function argument is actually used mutably.
     ///
     /// Be careful if the function is publicly reexported as it would break compatibility with
-    /// users of this function.
+    /// users of this function, when the users pass this function as an argument.
     ///
     /// ### Why is this bad?
     /// Less `mut` means less fights with the borrow checker. It can also lead to more
@@ -138,6 +138,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
             return;
         }
 
+        if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(fn_def_id) {
+            return;
+        }
+
         let hir_id = cx.tcx.local_def_id_to_hir_id(fn_def_id);
         let is_async = match kind {
             FnKind::ItemFn(.., header) => {
@@ -262,9 +266,6 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
             .iter()
             .filter(|(def_id, _)| !self.used_fn_def_ids.contains(def_id))
         {
-            let show_semver_warning =
-                self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(*fn_def_id);
-
             let mut is_cfged = None;
             for input in unused {
                 // If the argument is never used mutably, we emit the warning.
@@ -284,7 +285,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
                                 format!("&{}", snippet(cx, cx.tcx.hir().span(inner_ty.ty.hir_id), "_"),),
                                 Applicability::Unspecified,
                             );
-                            if show_semver_warning {
+                            if cx.effective_visibilities.is_exported(*fn_def_id) {
                                 diag.warn("changing this function will impact semver compatibility");
                             }
                             if *is_cfged {
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 87f886b1128..0ecfa7baa72 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -1,7 +1,9 @@
 use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::has_drop;
-use clippy_utils::{any_parent_is_automatically_derived, is_lint_allowed, path_to_local, peel_blocks};
+use clippy_utils::{
+    in_automatically_derived, is_inside_always_const_context, is_lint_allowed, path_to_local, peel_blocks,
+};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{
@@ -185,7 +187,7 @@ impl NoEffect {
                 && has_no_effect(cx, init)
                 && let PatKind::Binding(_, hir_id, ident, _) = local.pat.kind
                 && ident.name.to_ident_string().starts_with('_')
-                && !any_parent_is_automatically_derived(cx.tcx, local.hir_id)
+                && !in_automatically_derived(cx.tcx, local.hir_id)
             {
                 if let Some(l) = self.local_bindings.last_mut() {
                     l.push(hir_id);
@@ -258,13 +260,16 @@ fn has_no_effect(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 
 fn check_unnecessary_operation(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
     if let StmtKind::Semi(expr) = stmt.kind
+        && !in_external_macro(cx.sess(), stmt.span)
         && let ctxt = stmt.span.ctxt()
         && expr.span.ctxt() == ctxt
         && let Some(reduced) = reduce_expression(cx, expr)
-        && !in_external_macro(cx.sess(), stmt.span)
         && reduced.iter().all(|e| e.span.ctxt() == ctxt)
     {
         if let ExprKind::Index(..) = &expr.kind {
+            if is_inside_always_const_context(cx.tcx, expr.hir_id) {
+                return;
+            }
             let snippet =
                 if let (Some(arr), Some(func)) = (snippet_opt(cx, reduced[0].span), snippet_opt(cx, reduced[1].span)) {
                     format!("assert!({}.len() > {});", &arr, &func)
diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
index faab79de9d3..0e5b440c50f 100644
--- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs
@@ -57,7 +57,6 @@ pub(crate) fn check<'tcx>(
                     Applicability::HasPlaceholders, // snippet
                 );
             }
-            diag.note("`f32::EPSILON` and `f64::EPSILON` are available for the `error_margin`");
         });
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs
index 48a442705b2..59834781a58 100644
--- a/src/tools/clippy/clippy_lints/src/operators/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs
@@ -242,6 +242,13 @@ declare_clippy_lint! {
     /// # let x = 1;
     /// if (x | 1 > 3) {  }
     /// ```
+    ///
+    /// Use instead:
+    ///
+    /// ```no_run
+    /// # let x = 1;
+    /// if (x >= 2) {  }
+    /// ```
     #[clippy::version = "pre 1.29.0"]
     pub INEFFECTIVE_BIT_MASK,
     correctness,
@@ -265,6 +272,13 @@ declare_clippy_lint! {
     /// # let x = 1;
     /// if x & 0b1111 == 0 { }
     /// ```
+    ///
+    /// Use instead:
+    ///
+    /// ```no_run
+    /// # let x: i32 = 1;
+    /// if x.trailing_zeros() > 4 { }
+    /// ```
     #[clippy::version = "pre 1.29.0"]
     pub VERBOSE_BIT_MASK,
     pedantic,
@@ -560,74 +574,128 @@ declare_clippy_lint! {
     /// implement equality for a type involving floats).
     ///
     /// ### Why is this bad?
-    /// Floating point calculations are usually imprecise, so
-    /// asking if two values are *exactly* equal is asking for trouble. For a good
-    /// guide on what to do, see [the floating point
-    /// guide](http://www.floating-point-gui.de/errors/comparison).
+    /// Floating point calculations are usually imprecise, so asking if two values are *exactly*
+    /// equal is asking for trouble because arriving at the same logical result via different
+    /// routes (e.g. calculation versus constant) may yield different values.
     ///
     /// ### Example
+    ///
     /// ```no_run
-    /// let x = 1.2331f64;
-    /// let y = 1.2332f64;
+    /// let a: f64 = 1000.1;
+    /// let b: f64 = 0.2;
+    /// let x = a + b;
+    /// let y = 1000.3; // Expected value.
     ///
-    /// if y == 1.23f64 { }
-    /// if y != x {} // where both are floats
+    /// // Actual value: 1000.3000000000001
+    /// println!("{x}");
+    ///
+    /// let are_equal = x == y;
+    /// println!("{are_equal}"); // false
     /// ```
     ///
-    /// Use instead:
+    /// The correct way to compare floating point numbers is to define an allowed error margin. This
+    /// may be challenging if there is no "natural" error margin to permit. Broadly speaking, there
+    /// are two cases:
+    ///
+    /// 1. If your values are in a known range and you can define a threshold for "close enough to
+    ///    be equal", it may be appropriate to define an absolute error margin. For example, if your
+    ///    data is "length of vehicle in centimeters", you may consider 0.1 cm to be "close enough".
+    /// 1. If your code is more general and you do not know the range of values, you should use a
+    ///    relative error margin, accepting e.g. 0.1% of error regardless of specific values.
+    ///
+    /// For the scenario where you can define a meaningful absolute error margin, consider using:
+    ///
     /// ```no_run
-    /// # let x = 1.2331f64;
-    /// # let y = 1.2332f64;
-    /// let error_margin = f64::EPSILON; // Use an epsilon for comparison
-    /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
-    /// // let error_margin = std::f64::EPSILON;
-    /// if (y - 1.23f64).abs() < error_margin { }
-    /// if (y - x).abs() > error_margin { }
+    /// let a: f64 = 1000.1;
+    /// let b: f64 = 0.2;
+    /// let x = a + b;
+    /// let y = 1000.3; // Expected value.
+    ///
+    /// const ALLOWED_ERROR_VEHICLE_LENGTH_CM: f64 = 0.1;
+    /// let within_tolerance = (x - y).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM;
+    /// println!("{within_tolerance}"); // true
     /// ```
+    ///
+    /// NB! Do not use `f64::EPSILON` - while the error margin is often called "epsilon", this is
+    /// a different use of the term that is not suitable for floating point equality comparison.
+    /// Indeed, for the example above using `f64::EPSILON` as the allowed error would return `false`.
+    ///
+    /// For the scenario where no meaningful absolute error can be defined, refer to
+    /// [the floating point guide](https://www.floating-point-gui.de/errors/comparison)
+    /// for a reference implementation of relative error based comparison of floating point values.
+    /// `MIN_NORMAL` in the reference implementation is equivalent to `MIN_POSITIVE` in Rust.
     #[clippy::version = "pre 1.29.0"]
     pub FLOAT_CMP,
     pedantic,
-    "using `==` or `!=` on float values instead of comparing difference with an epsilon"
+    "using `==` or `!=` on float values instead of comparing difference with an allowed error"
 }
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for (in-)equality comparisons on floating-point
-    /// value and constant, except in functions called `*eq*` (which probably
+    /// Checks for (in-)equality comparisons on constant floating-point
+    /// values (apart from zero), except in functions called `*eq*` (which probably
     /// implement equality for a type involving floats).
     ///
     /// ### Why restrict this?
-    /// Floating point calculations are usually imprecise, so
-    /// asking if two values are *exactly* equal is asking for trouble. For a good
-    /// guide on what to do, see [the floating point
-    /// guide](http://www.floating-point-gui.de/errors/comparison).
+    /// Floating point calculations are usually imprecise, so asking if two values are *exactly*
+    /// equal is asking for trouble because arriving at the same logical result via different
+    /// routes (e.g. calculation versus constant) may yield different values.
     ///
     /// ### Example
+    ///
     /// ```no_run
-    /// let x: f64 = 1.0;
-    /// const ONE: f64 = 1.00;
+    /// let a: f64 = 1000.1;
+    /// let b: f64 = 0.2;
+    /// let x = a + b;
+    /// const Y: f64 = 1000.3; // Expected value.
+    ///
+    /// // Actual value: 1000.3000000000001
+    /// println!("{x}");
     ///
-    /// if x == ONE { } // where both are floats
+    /// let are_equal = x == Y;
+    /// println!("{are_equal}"); // false
     /// ```
     ///
-    /// Use instead:
+    /// The correct way to compare floating point numbers is to define an allowed error margin. This
+    /// may be challenging if there is no "natural" error margin to permit. Broadly speaking, there
+    /// are two cases:
+    ///
+    /// 1. If your values are in a known range and you can define a threshold for "close enough to
+    ///    be equal", it may be appropriate to define an absolute error margin. For example, if your
+    ///    data is "length of vehicle in centimeters", you may consider 0.1 cm to be "close enough".
+    /// 1. If your code is more general and you do not know the range of values, you should use a
+    ///    relative error margin, accepting e.g. 0.1% of error regardless of specific values.
+    ///
+    /// For the scenario where you can define a meaningful absolute error margin, consider using:
+    ///
     /// ```no_run
-    /// # let x: f64 = 1.0;
-    /// # const ONE: f64 = 1.00;
-    /// let error_margin = f64::EPSILON; // Use an epsilon for comparison
-    /// // Or, if Rust <= 1.42, use `std::f64::EPSILON` constant instead.
-    /// // let error_margin = std::f64::EPSILON;
-    /// if (x - ONE).abs() < error_margin { }
+    /// let a: f64 = 1000.1;
+    /// let b: f64 = 0.2;
+    /// let x = a + b;
+    /// const Y: f64 = 1000.3; // Expected value.
+    ///
+    /// const ALLOWED_ERROR_VEHICLE_LENGTH_CM: f64 = 0.1;
+    /// let within_tolerance = (x - Y).abs() < ALLOWED_ERROR_VEHICLE_LENGTH_CM;
+    /// println!("{within_tolerance}"); // true
     /// ```
+    ///
+    /// NB! Do not use `f64::EPSILON` - while the error margin is often called "epsilon", this is
+    /// a different use of the term that is not suitable for floating point equality comparison.
+    /// Indeed, for the example above using `f64::EPSILON` as the allowed error would return `false`.
+    ///
+    /// For the scenario where no meaningful absolute error can be defined, refer to
+    /// [the floating point guide](https://www.floating-point-gui.de/errors/comparison)
+    /// for a reference implementation of relative error based comparison of floating point values.
+    /// `MIN_NORMAL` in the reference implementation is equivalent to `MIN_POSITIVE` in Rust.
     #[clippy::version = "pre 1.29.0"]
     pub FLOAT_CMP_CONST,
     restriction,
-    "using `==` or `!=` on float constants instead of comparing difference with an epsilon"
+    "using `==` or `!=` on float constants instead of comparing difference with an allowed error"
 }
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for getting the remainder of a division by one or minus
+    /// Checks for getting the remainder of integer division by one or minus
     /// one.
     ///
     /// ### Why is this bad?
@@ -646,7 +714,7 @@ declare_clippy_lint! {
     #[clippy::version = "pre 1.29.0"]
     pub MODULO_ONE,
     correctness,
-    "taking a number modulo +/-1, which can either panic/overflow or always returns 0"
+    "taking an integer modulo +/-1, which can either panic/overflow or always returns 0"
 }
 
 declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
deleted file mode 100644
index de789879331..00000000000
--- a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-use clippy_utils::diagnostics::span_lint;
-use clippy_utils::SpanlessEq;
-use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_lint_pass;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Detects classic underflow/overflow checks.
-    ///
-    /// ### Why is this bad?
-    /// Most classic C underflow/overflow checks will fail in
-    /// Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead.
-    ///
-    /// ### Example
-    /// ```no_run
-    /// # let a = 1;
-    /// # let b = 2;
-    /// a + b < a;
-    /// ```
-    #[clippy::version = "pre 1.29.0"]
-    pub OVERFLOW_CHECK_CONDITIONAL,
-    complexity,
-    "overflow checks inspired by C which are likely to panic"
-}
-
-declare_lint_pass!(OverflowCheckConditional => [OVERFLOW_CHECK_CONDITIONAL]);
-
-const OVERFLOW_MSG: &str = "you are trying to use classic C overflow conditions that will fail in Rust";
-const UNDERFLOW_MSG: &str = "you are trying to use classic C underflow conditions that will fail in Rust";
-
-impl<'tcx> LateLintPass<'tcx> for OverflowCheckConditional {
-    // a + b < a, a > a + b, a < a - b, a - b > a
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        let eq = |l, r| SpanlessEq::new(cx).eq_path_segment(l, r);
-        if let ExprKind::Binary(ref op, first, second) = expr.kind
-            && let ExprKind::Binary(ref op2, ident1, ident2) = first.kind
-            && let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind
-            && let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind
-            && let ExprKind::Path(QPath::Resolved(_, path3)) = second.kind
-            && (eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]))
-            && cx.typeck_results().expr_ty(ident1).is_integral()
-            && cx.typeck_results().expr_ty(ident2).is_integral()
-        {
-            if op.node == BinOpKind::Lt && op2.node == BinOpKind::Add {
-                span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG);
-            }
-            if op.node == BinOpKind::Gt && op2.node == BinOpKind::Sub {
-                span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG);
-            }
-        }
-
-        if let ExprKind::Binary(ref op, first, second) = expr.kind
-            && let ExprKind::Binary(ref op2, ident1, ident2) = second.kind
-            && let ExprKind::Path(QPath::Resolved(_, path1)) = ident1.kind
-            && let ExprKind::Path(QPath::Resolved(_, path2)) = ident2.kind
-            && let ExprKind::Path(QPath::Resolved(_, path3)) = first.kind
-            && (eq(&path1.segments[0], &path3.segments[0]) || eq(&path2.segments[0], &path3.segments[0]))
-            && cx.typeck_results().expr_ty(ident1).is_integral()
-            && cx.typeck_results().expr_ty(ident2).is_integral()
-        {
-            if op.node == BinOpKind::Gt && op2.node == BinOpKind::Add {
-                span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, OVERFLOW_MSG);
-            }
-            if op.node == BinOpKind::Lt && op2.node == BinOpKind::Sub {
-                span_lint(cx, OVERFLOW_CHECK_CONDITIONAL, expr.span, UNDERFLOW_MSG);
-            }
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs b/src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs
new file mode 100644
index 00000000000..7f100a746d5
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/panicking_overflow_checks.rs
@@ -0,0 +1,86 @@
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::eq_expr_value;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::lint::in_external_macro;
+use rustc_middle::ty;
+use rustc_session::declare_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Detects C-style underflow/overflow checks.
+    ///
+    /// ### Why is this bad?
+    /// These checks will, by default, panic in debug builds rather than check
+    /// whether the operation caused an overflow.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// # let a = 1i32;
+    /// # let b = 2i32;
+    /// if a + b < a {
+    ///     // handle overflow
+    /// }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```no_run
+    /// # let a = 1i32;
+    /// # let b = 2i32;
+    /// if a.checked_add(b).is_none() {
+    ///     // handle overflow
+    /// }
+    /// ```
+    ///
+    /// Or:
+    /// ```no_run
+    /// # let a = 1i32;
+    /// # let b = 2i32;
+    /// if a.overflowing_add(b).1 {
+    ///     // handle overflow
+    /// }
+    /// ```
+    #[clippy::version = "pre 1.29.0"]
+    pub PANICKING_OVERFLOW_CHECKS,
+    correctness,
+    "overflow checks which will panic in debug mode"
+}
+
+declare_lint_pass!(PanickingOverflowChecks => [PANICKING_OVERFLOW_CHECKS]);
+
+impl<'tcx> LateLintPass<'tcx> for PanickingOverflowChecks {
+    // a + b < a, a > a + b, a < a - b, a - b > a
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if let ExprKind::Binary(op, lhs, rhs) = expr.kind
+            && let (lt, gt) = match op.node {
+                BinOpKind::Lt => (lhs, rhs),
+                BinOpKind::Gt => (rhs, lhs),
+                _ => return,
+            }
+            && let ctxt = expr.span.ctxt()
+            && let (op_lhs, op_rhs, other, commutative) = match (&lt.kind, &gt.kind) {
+                (&ExprKind::Binary(op, lhs, rhs), _) if op.node == BinOpKind::Add && ctxt == lt.span.ctxt() => {
+                    (lhs, rhs, gt, true)
+                },
+                (_, &ExprKind::Binary(op, lhs, rhs)) if op.node == BinOpKind::Sub && ctxt == gt.span.ctxt() => {
+                    (lhs, rhs, lt, false)
+                },
+                _ => return,
+            }
+            && let typeck = cx.typeck_results()
+            && let ty = typeck.expr_ty(op_lhs)
+            && matches!(ty.kind(), ty::Uint(_))
+            && ty == typeck.expr_ty(op_rhs)
+            && ty == typeck.expr_ty(other)
+            && !in_external_macro(cx.tcx.sess, expr.span)
+            && (eq_expr_value(cx, op_lhs, other) || (commutative && eq_expr_value(cx, op_rhs, other)))
+        {
+            span_lint(
+                cx,
+                PANICKING_OVERFLOW_CHECKS,
+                expr.span,
+                "you are trying to use classic C overflow conditions that will fail in Rust",
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
index 85979903b58..8e999f3e89a 100644
--- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs
@@ -26,12 +26,14 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[
     ("clippy::option_map_unwrap_or", "clippy::map_unwrap_or"),
     ("clippy::option_map_unwrap_or_else", "clippy::map_unwrap_or"),
     ("clippy::option_unwrap_used", "clippy::unwrap_used"),
+    ("clippy::overflow_check_conditional", "clippy::panicking_overflow_checks"),
     ("clippy::ref_in_deref", "clippy::needless_borrow"),
     ("clippy::result_expect_used", "clippy::expect_used"),
     ("clippy::result_map_unwrap_or_else", "clippy::map_unwrap_or"),
     ("clippy::result_unwrap_used", "clippy::unwrap_used"),
     ("clippy::single_char_push_str", "clippy::single_char_add_str"),
     ("clippy::stutter", "clippy::module_name_repetitions"),
+    ("clippy::thread_local_initializer_can_be_made_const", "clippy::missing_const_for_thread_local"),
     ("clippy::to_string_in_display", "clippy::recursive_format_impl"),
     ("clippy::unwrap_or_else_default", "clippy::unwrap_or_default"),
     ("clippy::zero_width_space", "clippy::invisible_characters"),
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index c11da3147ef..8ced47b48a4 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -7,6 +7,7 @@ use clippy_utils::{
     path_to_local_id, span_contains_cfg, span_find_starting_semi,
 };
 use core::ops::ControlFlow;
+use rustc_ast::NestedMetaItem;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::LangItem::ResultErr;
@@ -14,13 +15,13 @@ use rustc_hir::{
     Block, Body, Expr, ExprKind, FnDecl, HirId, ItemKind, LangItem, MatchSource, Node, OwnerNode, PatKind, QPath, Stmt,
     StmtKind,
 };
-use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_lint::{LateContext, LateLintPass, Level, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::adjustment::Adjust;
 use rustc_middle::ty::{self, GenericArgKind, Ty};
 use rustc_session::declare_lint_pass;
 use rustc_span::def_id::LocalDefId;
-use rustc_span::{BytePos, Pos, Span};
+use rustc_span::{sym, BytePos, Pos, Span};
 use std::borrow::Cow;
 use std::fmt::Display;
 
@@ -80,6 +81,9 @@ declare_clippy_lint! {
     /// ```
     #[clippy::version = "pre 1.29.0"]
     pub NEEDLESS_RETURN,
+    // This lint requires some special handling in `check_final_expr` for `#[expect]`.
+    // This handling needs to be updated if the group gets changed. This should also
+    // be caught by tests.
     style,
     "using a return statement like `return expr;` where an expression would suffice"
 }
@@ -91,6 +95,9 @@ declare_clippy_lint! {
     /// ### Why is this bad?
     /// The `return` is unnecessary.
     ///
+    /// Returns may be used to add attributes to the return expression. Return
+    /// statements with attributes are therefore be accepted by this lint.
+    ///
     /// ### Example
     /// ```rust,ignore
     /// fn foo(x: usize) -> Result<(), Box<dyn Error>> {
@@ -377,13 +384,39 @@ fn check_final_expr<'tcx>(
                 }
             };
 
-            if !cx.tcx.hir().attrs(expr.hir_id).is_empty() {
-                return;
-            }
             let borrows = inner.map_or(false, |inner| last_statement_borrows(cx, inner));
             if borrows {
                 return;
             }
+            if ret_span.from_expansion() {
+                return;
+            }
+
+            // Returns may be used to turn an expression into a statement in rustc's AST.
+            // This allows the addition of attributes, like `#[allow]` (See: clippy#9361)
+            // `#[expect(clippy::needless_return)]` needs to be handled separatly to
+            // actually fullfil the expectation (clippy::#12998)
+            match cx.tcx.hir().attrs(expr.hir_id) {
+                [] => {},
+                [attr] => {
+                    if matches!(Level::from_attr(attr), Some(Level::Expect(_)))
+                        && let metas = attr.meta_item_list()
+                        && let Some(lst) = metas
+                        && let [NestedMetaItem::MetaItem(meta_item)] = lst.as_slice()
+                        && let [tool, lint_name] = meta_item.path.segments.as_slice()
+                        && tool.ident.name == sym::clippy
+                        && matches!(
+                            lint_name.ident.name.as_str(),
+                            "needless_return" | "style" | "all" | "warnings"
+                        )
+                    {
+                        // This is an expectation of the `needless_return` lint
+                    } else {
+                        return;
+                    }
+                },
+                _ => return,
+            }
 
             emit_return_lint(cx, ret_span, semi_spans, &replacement, expr.hir_id);
         },
@@ -415,10 +448,6 @@ fn emit_return_lint(
     replacement: &RetReplacement<'_>,
     at: HirId,
 ) {
-    if ret_span.from_expansion() {
-        return;
-    }
-
     span_lint_hir_and_then(
         cx,
         NEEDLESS_RETURN,
diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs
index 8fdd19c549f..508f3ae6def 100644
--- a/src/tools/clippy/clippy_lints/src/same_name_method.rs
+++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs
@@ -12,7 +12,7 @@ use std::collections::{BTreeMap, BTreeSet};
 declare_clippy_lint! {
     /// ### What it does
     /// It lints if a struct has two methods with the same name:
-    /// one from a trait, another not from trait.
+    /// one from a trait, another not from a trait.
     ///
     /// ### Why restrict this?
     /// Confusing.
diff --git a/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs b/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs
new file mode 100644
index 00000000000..5e65b9fa517
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs
@@ -0,0 +1,125 @@
+use std::ops::ControlFlow;
+
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::visitors::for_each_expr;
+use clippy_utils::{higher, peel_hir_expr_while, SpanlessEq};
+use rustc_hir::{Expr, ExprKind, UnOp};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+use rustc_span::symbol::Symbol;
+use rustc_span::{sym, Span};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for usage of `contains` to see if a value is not
+    /// present on `HashSet` followed by a `insert`.
+    ///
+    /// ### Why is this bad?
+    /// Using just `insert` and checking the returned `bool` is more efficient.
+    ///
+    /// ### Known problems
+    /// In case the value that wants to be inserted is borrowed and also expensive or impossible
+    /// to clone. In such a scenario, the developer might want to check with `contains` before inserting,
+    /// to avoid the clone. In this case, it will report a false positive.
+    ///
+    /// ### Example
+    /// ```rust
+    /// use std::collections::HashSet;
+    /// let mut set = HashSet::new();
+    /// let value = 5;
+    /// if !set.contains(&value) {
+    ///     set.insert(value);
+    ///     println!("inserted {value:?}");
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// use std::collections::HashSet;
+    /// let mut set = HashSet::new();
+    /// let value = 5;
+    /// if set.insert(&value) {
+    ///     println!("inserted {value:?}");
+    /// }
+    /// ```
+    #[clippy::version = "1.80.0"]
+    pub SET_CONTAINS_OR_INSERT,
+    nursery,
+    "call to `HashSet::contains` followed by `HashSet::insert`"
+}
+
+declare_lint_pass!(HashsetInsertAfterContains => [SET_CONTAINS_OR_INSERT]);
+
+impl<'tcx> LateLintPass<'tcx> for HashsetInsertAfterContains {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if !expr.span.from_expansion()
+            && let Some(higher::If {
+                cond: cond_expr,
+                then: then_expr,
+                ..
+            }) = higher::If::hir(expr)
+            && let Some(contains_expr) = try_parse_op_call(cx, cond_expr, sym!(contains))//try_parse_contains(cx, cond_expr)
+            && let Some(insert_expr) = find_insert_calls(cx, &contains_expr, then_expr)
+        {
+            span_lint(
+                cx,
+                SET_CONTAINS_OR_INSERT,
+                vec![contains_expr.span, insert_expr.span],
+                "usage of `HashSet::insert` after `HashSet::contains`",
+            );
+        }
+    }
+}
+
+struct OpExpr<'tcx> {
+    receiver: &'tcx Expr<'tcx>,
+    value: &'tcx Expr<'tcx>,
+    span: Span,
+}
+
+fn try_parse_op_call<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, symbol: Symbol) -> Option<OpExpr<'tcx>> {
+    let expr = peel_hir_expr_while(expr, |e| {
+        if let ExprKind::Unary(UnOp::Not, e) = e.kind {
+            Some(e)
+        } else {
+            None
+        }
+    });
+
+    if let ExprKind::MethodCall(path, receiver, [value], span) = expr.kind {
+        let value = value.peel_borrows();
+        let value = peel_hir_expr_while(value, |e| {
+            if let ExprKind::Unary(UnOp::Deref, e) = e.kind {
+                Some(e)
+            } else {
+                None
+            }
+        });
+        let receiver = receiver.peel_borrows();
+        let receiver_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
+        if value.span.eq_ctxt(expr.span)
+            && is_type_diagnostic_item(cx, receiver_ty, sym::HashSet)
+            && path.ident.name == symbol
+        {
+            return Some(OpExpr { receiver, value, span });
+        }
+    }
+    None
+}
+
+fn find_insert_calls<'tcx>(
+    cx: &LateContext<'tcx>,
+    contains_expr: &OpExpr<'tcx>,
+    expr: &'tcx Expr<'_>,
+) -> Option<OpExpr<'tcx>> {
+    for_each_expr(cx, expr, |e| {
+        if let Some(insert_expr) = try_parse_op_call(cx, e, sym!(insert))
+            && SpanlessEq::new(cx).eq_expr(contains_expr.receiver, insert_expr.receiver)
+            && SpanlessEq::new(cx).eq_expr(contains_expr.value, insert_expr.value)
+        {
+            ControlFlow::Break(insert_expr)
+        } else {
+            ControlFlow::Continue(())
+        }
+    })
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
index 877a77fd6d2..1d294c2944b 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
@@ -1,6 +1,5 @@
 pub mod almost_standard_lint_formulation;
 pub mod collapsible_calls;
-pub mod compiler_lint_functions;
 pub mod interning_defined_symbol;
 pub mod invalid_paths;
 pub mod lint_without_lint_pass;
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs
deleted file mode 100644
index 9b6b6871818..00000000000
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/compiler_lint_functions.rs
+++ /dev/null
@@ -1,73 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::match_type;
-use clippy_utils::{is_lint_allowed, paths};
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::{Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::impl_lint_pass;
-
-declare_clippy_lint! {
-    /// ### What it does
-    /// Checks for calls to `cx.span_lint*` and suggests to use the `utils::*`
-    /// variant of the function.
-    ///
-    /// ### Why is this bad?
-    /// The `utils::*` variants also add a link to the Clippy documentation to the
-    /// warning/error messages.
-    ///
-    /// ### Example
-    /// ```rust,ignore
-    /// cx.span_lint(LINT_NAME, "message");
-    /// ```
-    ///
-    /// Use instead:
-    /// ```rust,ignore
-    /// utils::span_lint(cx, LINT_NAME, "message");
-    /// ```
-    pub COMPILER_LINT_FUNCTIONS,
-    internal,
-    "usage of the lint functions of the compiler instead of the utils::* variant"
-}
-
-impl_lint_pass!(CompilerLintFunctions => [COMPILER_LINT_FUNCTIONS]);
-
-#[derive(Clone, Default)]
-pub struct CompilerLintFunctions {
-    map: FxHashMap<&'static str, &'static str>,
-}
-
-impl CompilerLintFunctions {
-    #[must_use]
-    pub fn new() -> Self {
-        let mut map = FxHashMap::default();
-        map.insert("span_lint", "utils::span_lint");
-        map.insert("lint", "utils::span_lint");
-        map.insert("span_lint_note", "utils::span_lint_and_note");
-        map.insert("span_lint_help", "utils::span_lint_and_help");
-        Self { map }
-    }
-}
-
-impl<'tcx> LateLintPass<'tcx> for CompilerLintFunctions {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if is_lint_allowed(cx, COMPILER_LINT_FUNCTIONS, expr.hir_id) {
-            return;
-        }
-
-        if let ExprKind::MethodCall(path, self_arg, _, _) = &expr.kind
-            && let fn_name = path.ident
-            && let Some(sugg) = self.map.get(fn_name.as_str())
-            && let ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
-            && (match_type(cx, ty, &paths::EARLY_CONTEXT) || match_type(cx, ty, &paths::LATE_CONTEXT))
-        {
-            span_lint_and_help(
-                cx,
-                COMPILER_LINT_FUNCTIONS,
-                path.ident.span,
-                "usage of a compiler lint function",
-                None,
-                format!("please use the Clippy variant of this function: `{sugg}`"),
-            );
-        }
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index 436f0cb79fb..a0a60ca8875 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_test_module_or_function;
+use clippy_utils::is_in_test;
 use clippy_utils::source::{snippet, snippet_with_applicability};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
@@ -100,7 +100,6 @@ declare_clippy_lint! {
 #[derive(Default)]
 pub struct WildcardImports {
     warn_on_all: bool,
-    test_modules_deep: u32,
     allowed_segments: FxHashSet<String>,
 }
 
@@ -108,7 +107,6 @@ impl WildcardImports {
     pub fn new(warn_on_all: bool, allowed_wildcard_imports: FxHashSet<String>) -> Self {
         Self {
             warn_on_all,
-            test_modules_deep: 0,
             allowed_segments: allowed_wildcard_imports,
         }
     }
@@ -122,15 +120,12 @@ impl LateLintPass<'_> for WildcardImports {
             return;
         }
 
-        if is_test_module_or_function(cx.tcx, item) {
-            self.test_modules_deep = self.test_modules_deep.saturating_add(1);
-        }
         let module = cx.tcx.parent_module_from_def_id(item.owner_id.def_id);
         if cx.tcx.visibility(item.owner_id.def_id) != ty::Visibility::Restricted(module.to_def_id()) {
             return;
         }
         if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind
-            && (self.warn_on_all || !self.check_exceptions(item, use_path.segments))
+            && (self.warn_on_all || !self.check_exceptions(cx, item, use_path.segments))
             && let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id)
             && !used_imports.is_empty() // Already handled by `unused_imports`
             && !used_imports.contains(&kw::Underscore)
@@ -180,20 +175,14 @@ impl LateLintPass<'_> for WildcardImports {
             span_lint_and_sugg(cx, lint, span, message, "try", sugg, applicability);
         }
     }
-
-    fn check_item_post(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
-        if is_test_module_or_function(cx.tcx, item) {
-            self.test_modules_deep = self.test_modules_deep.saturating_sub(1);
-        }
-    }
 }
 
 impl WildcardImports {
-    fn check_exceptions(&self, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool {
+    fn check_exceptions(&self, cx: &LateContext<'_>, item: &Item<'_>, segments: &[PathSegment<'_>]) -> bool {
         item.span.from_expansion()
             || is_prelude_import(segments)
-            || (is_super_only_import(segments) && self.test_modules_deep > 0)
             || is_allowed_via_config(segments, &self.allowed_segments)
+            || (is_super_only_import(segments) && is_in_test(cx.tcx, item.hir_id()))
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 652ce88bd95..96e53b7ef0b 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
+use clippy_utils::is_in_test;
 use clippy_utils::macros::{format_arg_removal_span, root_macro_call_first_node, FormatArgsStorage, MacroCall};
 use clippy_utils::source::{expand_past_previous_comma, snippet_opt};
-use clippy_utils::{is_in_cfg_test, is_in_test_function};
 use rustc_ast::token::LitKind;
 use rustc_ast::{
     FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder,
@@ -297,8 +297,7 @@ impl<'tcx> LateLintPass<'tcx> for Write {
             .as_ref()
             .map_or(false, |crate_name| crate_name == "build_script_build");
 
-        let allowed_in_tests = self.allow_print_in_tests
-            && (is_in_test_function(cx.tcx, expr.hir_id) || is_in_cfg_test(cx.tcx, expr.hir_id));
+        let allowed_in_tests = self.allow_print_in_tests && is_in_test(cx.tcx, expr.hir_id);
         match diag_name {
             sym::print_macro | sym::println_macro if !allowed_in_tests => {
                 if !is_build_script {