about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJason Newcomb <jsnewcomb@pm.me>2024-08-03 00:29:23 -0400
committerJason Newcomb <jsnewcomb@pm.me>2025-05-16 06:08:35 -0400
commit57782e0ff1e9833e121187f1c33b72bec6a8a61a (patch)
tree8d05a5d3f4678f6635191403c2dcf414ceadf14e
parent95d7eda0b44cc883516b9198dce3b05db3a581f9 (diff)
downloadrust-57782e0ff1e9833e121187f1c33b72bec6a8a61a.tar.gz
rust-57782e0ff1e9833e121187f1c33b72bec6a8a61a.zip
Rewrite `non_copy_const`
-rw-r--r--clippy_lints/src/non_copy_const.rs1063
-rw-r--r--clippy_utils/src/ty/mod.rs11
-rw-r--r--tests/ui/borrow_interior_mutable_const/enums.rs18
-rw-r--r--tests/ui/borrow_interior_mutable_const/enums.stderr50
-rw-r--r--tests/ui/borrow_interior_mutable_const/others.rs44
-rw-r--r--tests/ui/borrow_interior_mutable_const/others.stderr63
-rw-r--r--tests/ui/borrow_interior_mutable_const/projections.stderr16
-rw-r--r--tests/ui/borrow_interior_mutable_const/traits.rs51
-rw-r--r--tests/ui/borrow_interior_mutable_const/traits.stderr66
-rw-r--r--tests/ui/crashes/ice-12979.1.fixed2
-rw-r--r--tests/ui/crashes/ice-12979.2.fixed3
-rw-r--r--tests/ui/crashes/ice-12979.rs3
-rw-r--r--tests/ui/crashes/ice-12979.stderr19
-rw-r--r--tests/ui/crashes/ice-9445.rs4
-rw-r--r--tests/ui/crashes/ice-9445.stderr12
-rw-r--r--tests/ui/declare_interior_mutable_const/enums.rs29
-rw-r--r--tests/ui/declare_interior_mutable_const/enums.stderr71
-rw-r--r--tests/ui/declare_interior_mutable_const/others.rs9
-rw-r--r--tests/ui/declare_interior_mutable_const/others.stderr26
-rw-r--r--tests/ui/declare_interior_mutable_const/traits.rs33
-rw-r--r--tests/ui/declare_interior_mutable_const/traits.stderr65
21 files changed, 981 insertions, 677 deletions
diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs
index 6d3e77b6b6e..f57ab0e6781 100644
--- a/clippy_lints/src/non_copy_const.rs
+++ b/clippy_lints/src/non_copy_const.rs
@@ -1,25 +1,46 @@
-use std::ptr;
+// Implementation for lints detecting interior mutability in constants.
+//
+// For `declare_interior_mutable_const` there are three strategies used to
+// determine if a value has interior mutability:
+// * A type-based check. This is the least accurate, but can always run.
+// * A const-eval based check. This is the most accurate, but this requires that the value is
+//   defined and does not work with generics.
+// * A HIR-tree based check. This is less accurate than const-eval, but it can be applied to generic
+//   values.
+//
+// For `borrow_interior_mutable_const` the same three strategies are applied
+// when checking a constant's value, but field and array index projections at
+// the borrow site are taken into account as well. As an example: `FOO.bar` may
+// have interior mutability, but `FOO.baz` may not. When borrowing `FOO.baz` no
+// warning will be issued.
+//
+// No matter the lint or strategy, a warning should only be issued if a value
+// definitely contains interior mutability.
 
 use clippy_config::Conf;
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
 use clippy_utils::is_in_const_context;
 use clippy_utils::macros::macro_backtrace;
-use clippy_utils::ty::{InteriorMut, implements_trait};
-use rustc_abi::VariantIdx;
+use clippy_utils::paths::{PathNS, lookup_path_str};
+use clippy_utils::ty::{get_field_idx_by_name, implements_trait};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_hir::{
-    BodyId, Expr, ExprKind, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind, UnOp,
+    Expr, ExprKind, ImplItem, ImplItemKind, Item, ItemKind, Node, StructTailExpr, TraitItem, TraitItemKind, UnOp,
+};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::mir::{ConstValue, UnevaluatedConst};
+use rustc_middle::ty::adjustment::{Adjust, Adjustment};
+use rustc_middle::ty::{
+    self, AliasTyKind, EarlyBinder, GenericArgs, GenericArgsRef, Instance, Ty, TyCtxt, TypeFolder, TypeSuperFoldable,
+    TypeckResults, TypingEnv,
 };
-use rustc_lint::{LateContext, LateLintPass, Lint};
-use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId, ReportedErrorInfo};
-use rustc_middle::ty::adjustment::Adjust;
-use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::impl_lint_pass;
-use rustc_span::{DUMMY_SP, Span, sym};
+use rustc_span::{DUMMY_SP, sym};
+use std::collections::hash_map::Entry;
 
-// FIXME: this is a correctness problem but there's no suitable
-// warn-by-default category.
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for declaration of `const` items which is interior
@@ -74,8 +95,6 @@ declare_clippy_lint! {
     "declaring `const` with interior mutability"
 }
 
-// FIXME: this is a correctness problem but there's no suitable
-// warn-by-default category.
 declare_clippy_lint! {
     /// ### What it does
     /// Checks if `const` items which is interior mutable (e.g.,
@@ -113,60 +132,96 @@ declare_clippy_lint! {
     "referencing `const` with interior mutability"
 }
 
-#[derive(Copy, Clone)]
-enum Source<'tcx> {
-    Item { item: Span, ty: Ty<'tcx> },
-    Assoc { item: Span },
-    Expr { expr: Span },
+#[derive(Clone, Copy)]
+enum IsFreeze {
+    /// The type and all possible values are `Freeze`
+    Yes,
+    /// The type itself is non-`Freeze`, but not all values are.
+    Maybe,
+    /// The type and all possible values are non-`Freeze`
+    No,
 }
+impl IsFreeze {
+    /// Merges the variants of a sum type (i.e. an enum).
+    fn from_variants(iter: impl Iterator<Item = Self>) -> Self {
+        iter.fold(Self::Yes, |x, y| match (x, y) {
+            (Self::Maybe, _) | (_, Self::Maybe) | (Self::No, Self::Yes) | (Self::Yes, Self::No) => Self::Maybe,
+            (Self::No, Self::No) => Self::No,
+            (Self::Yes, Self::Yes) => Self::Yes,
+        })
+    }
+
+    /// Merges the fields of a product type (e.g. a struct or tuple).
+    fn from_fields(mut iter: impl Iterator<Item = Self>) -> Self {
+        iter.try_fold(Self::Yes, |x, y| match (x, y) {
+            (Self::No, _) | (_, Self::No) => None,
+            (Self::Maybe, _) | (_, Self::Maybe) => Some(Self::Maybe),
+            (Self::Yes, Self::Yes) => Some(Self::Yes),
+        })
+        .unwrap_or(Self::No)
+    }
+
+    /// Checks if this is definitely `Freeze`.
+    fn is_freeze(self) -> bool {
+        matches!(self, Self::Yes)
+    }
 
-impl Source<'_> {
-    #[must_use]
-    fn lint(&self) -> (&'static Lint, &'static str, Span) {
+    /// Checks if this is definitely not `Freeze`.
+    fn is_not_freeze(self) -> bool {
+        matches!(self, Self::No)
+    }
+}
+
+/// What operation caused a borrow to occur.
+#[derive(Clone, Copy)]
+enum BorrowCause {
+    Borrow,
+    Deref,
+    Index,
+    AutoDeref,
+    AutoBorrow,
+}
+impl BorrowCause {
+    fn note(self) -> Option<&'static str> {
         match self {
-            Self::Item { item, .. } | Self::Assoc { item, .. } => (
-                DECLARE_INTERIOR_MUTABLE_CONST,
-                "a `const` item should not be interior mutable",
-                *item,
-            ),
-            Self::Expr { expr } => (
-                BORROW_INTERIOR_MUTABLE_CONST,
-                "a `const` item with interior mutability should not be borrowed",
-                *expr,
-            ),
+            Self::Borrow => None,
+            Self::Deref => Some("this deref expression is a call to `Deref::deref`"),
+            Self::Index => Some("this index expression is a call to `Index::index`"),
+            Self::AutoDeref => Some("there is a compiler inserted call to `Deref::deref` here"),
+            Self::AutoBorrow => Some("there is a compiler inserted borrow here"),
         }
     }
 }
 
-fn lint<'tcx>(cx: &LateContext<'tcx>, source: Source<'tcx>) {
-    let (lint, msg, span) = source.lint();
-    span_lint_and_then(cx, lint, span, msg, |diag| {
-        if span.from_expansion() {
-            return; // Don't give suggestions into macros.
-        }
-        match source {
-            Source::Item { ty, .. } => {
-                let Some(sync_trait) = cx.tcx.lang_items().sync_trait() else {
-                    return;
-                };
-                if implements_trait(cx, ty, sync_trait, &[]) {
-                    diag.help("consider making this a static item");
-                } else {
-                    diag.help(
-                        "consider making this `Sync` so that it can go in a static item or using a `thread_local`",
-                    );
-                }
-            },
-            Source::Assoc { .. } => (),
-            Source::Expr { .. } => {
-                diag.help("assign this const to a local or static variable, and use the variable here");
-            },
-        }
-    });
+/// The source of a borrow. Both what caused it and where.
+struct BorrowSource<'tcx> {
+    expr: &'tcx Expr<'tcx>,
+    cause: BorrowCause,
+}
+impl<'tcx> BorrowSource<'tcx> {
+    fn new(tcx: TyCtxt<'tcx>, expr: &'tcx Expr<'tcx>, cause: BorrowCause) -> Self {
+        // Custom deref and index impls will always have an auto-borrow inserted since we
+        // never work with reference types.
+        let (expr, cause) = if matches!(cause, BorrowCause::AutoBorrow)
+            && let Node::Expr(parent) = tcx.parent_hir_node(expr.hir_id)
+        {
+            match parent.kind {
+                ExprKind::Unary(UnOp::Deref, _) => (parent, BorrowCause::Deref),
+                ExprKind::Index(..) => (parent, BorrowCause::Index),
+                _ => (expr, cause),
+            }
+        } else {
+            (expr, cause)
+        };
+        Self { expr, cause }
+    }
 }
 
 pub struct NonCopyConst<'tcx> {
-    interior_mut: InteriorMut<'tcx>,
+    ignore_tys: DefIdSet,
+    // Cache checked types. We can recurse through a type multiple times so this
+    // can be hit quite frequently.
+    freeze_tys: FxHashMap<Ty<'tcx>, IsFreeze>,
 }
 
 impl_lint_pass!(NonCopyConst<'_> => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]);
@@ -174,332 +229,631 @@ impl_lint_pass!(NonCopyConst<'_> => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTE
 impl<'tcx> NonCopyConst<'tcx> {
     pub fn new(tcx: TyCtxt<'tcx>, conf: &'static Conf) -> Self {
         Self {
-            interior_mut: InteriorMut::without_pointers(tcx, &conf.ignore_interior_mutability),
+            ignore_tys: conf
+                .ignore_interior_mutability
+                .iter()
+                .flat_map(|ignored_ty| lookup_path_str(tcx, PathNS::Type, ignored_ty))
+                .collect(),
+            freeze_tys: FxHashMap::default(),
         }
     }
 
-    fn is_value_unfrozen_raw_inner(cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool {
-        // No branch that we check (yet) should continue if val isn't a branch
-        let Some(branched_val) = val.try_to_branch() else {
-            return false;
-        };
-        match *ty.kind() {
-            // the fact that we have to dig into every structs to search enums
-            // leads us to the point checking `UnsafeCell` directly is the only option.
-            ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true,
-            // As of 2022-09-08 miri doesn't track which union field is active so there's no safe way to check the
-            // contained value.
-            ty::Adt(def, ..) if def.is_union() => false,
-            ty::Array(ty, _) => branched_val
-                .iter()
-                .any(|field| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
-            ty::Adt(def, args) if def.is_enum() => {
-                let Some((&variant_valtree, fields)) = branched_val.split_first() else {
-                    return false;
-                };
-                let variant_index = variant_valtree.unwrap_leaf();
-                let variant_index = VariantIdx::from_u32(variant_index.to_u32());
-                fields
-                    .iter()
-                    .copied()
-                    .zip(
-                        def.variants()[variant_index]
+    /// Checks if a value of the given type is `Freeze`, or may be depending on the value.
+    fn is_ty_freeze(&mut self, tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>, ty: Ty<'tcx>) -> IsFreeze {
+        let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+        match self.freeze_tys.entry(ty) {
+            Entry::Occupied(e) => *e.get(),
+            Entry::Vacant(e) => {
+                let e = e.insert(IsFreeze::Yes);
+                if ty.is_freeze(tcx, typing_env) {
+                    return IsFreeze::Yes;
+                }
+                let is_freeze = match *ty.kind() {
+                    ty::Adt(adt, _) if adt.is_unsafe_cell() => {
+                        *e = IsFreeze::No;
+                        return IsFreeze::No;
+                    },
+                    ty::Adt(adt, _) if self.ignore_tys.contains(&adt.did()) => return IsFreeze::Yes,
+                    ty::Adt(adt, args) if adt.is_enum() => IsFreeze::from_variants(adt.variants().iter().map(|v| {
+                        IsFreeze::from_fields(
+                            v.fields
+                                .iter()
+                                .map(|f| self.is_ty_freeze(tcx, typing_env, f.ty(tcx, args))),
+                        )
+                    })),
+                    // Workaround for `ManuallyDrop`-like unions.
+                    ty::Adt(adt, args)
+                        if adt.is_union()
+                            && adt.non_enum_variant().fields.iter().any(|f| {
+                                tcx.layout_of(typing_env.as_query_input(f.ty(tcx, args)))
+                                    .is_ok_and(|l| l.layout.size().bytes() == 0)
+                            }) =>
+                    {
+                        return IsFreeze::Yes;
+                    },
+                    // Rust doesn't have the concept of an active union field so we have
+                    // to treat all fields as active.
+                    ty::Adt(adt, args) => IsFreeze::from_fields(
+                        adt.non_enum_variant()
                             .fields
                             .iter()
-                            .map(|field| field.ty(cx.tcx, args)),
-                    )
-                    .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, field, ty))
-            },
-            ty::Adt(def, args) => branched_val
-                .iter()
-                .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args)))
-                .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
-            ty::Tuple(tys) => branched_val
-                .iter()
-                .zip(tys)
-                .any(|(field, ty)| Self::is_value_unfrozen_raw_inner(cx, *field, ty)),
-            ty::Alias(ty::Projection, _) => match cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) {
-                Ok(normalized_ty) if ty != normalized_ty => Self::is_value_unfrozen_raw_inner(cx, val, normalized_ty),
-                _ => false,
+                            .map(|f| self.is_ty_freeze(tcx, typing_env, f.ty(tcx, args))),
+                    ),
+                    ty::Array(ty, _) | ty::Pat(ty, _) => self.is_ty_freeze(tcx, typing_env, ty),
+                    ty::Tuple(tys) => {
+                        IsFreeze::from_fields(tys.iter().map(|ty| self.is_ty_freeze(tcx, typing_env, ty)))
+                    },
+                    // Treat type parameters as though they were `Freeze`.
+                    ty::Param(_) | ty::Alias(..) => return IsFreeze::Yes,
+                    // TODO: check other types.
+                    _ => {
+                        *e = IsFreeze::No;
+                        return IsFreeze::No;
+                    },
+                };
+                if !is_freeze.is_freeze() {
+                    self.freeze_tys.insert(ty, is_freeze);
+                }
+                is_freeze
             },
-            _ => false,
         }
     }
 
-    fn is_value_unfrozen_raw(
-        cx: &LateContext<'tcx>,
-        result: Result<Result<ty::ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>,
+    /// Checks if the given constant value is `Freeze`. Returns `Err` if the constant
+    /// cannot be read, but the result depends on the value.
+    fn is_value_freeze(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        typing_env: TypingEnv<'tcx>,
         ty: Ty<'tcx>,
-    ) -> bool {
-        result.map_or_else(
-            |err| {
-                // Consider `TooGeneric` cases as being unfrozen.
-                // This causes a false positive where an assoc const whose type is unfrozen
-                // have a value that is a frozen variant with a generic param (an example is
-                // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::GENERIC_VARIANT`).
-                // However, it prevents a number of false negatives that is, I think, important:
-                // 1. assoc consts in trait defs referring to consts of themselves (an example is
-                //    `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`).
-                // 2. a path expr referring to assoc consts whose type is doesn't have any frozen variants in trait
-                //    defs (i.e. without substitute for `Self`). (e.g. borrowing
-                //    `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`)
-                // 3. similar to the false positive above; but the value is an unfrozen variant, or the type has no
-                //    enums. (An example is
-                //    `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT` and
-                //    `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`).
-                // One might be able to prevent these FNs correctly, and replace this with `false`;
-                // e.g. implementing `has_frozen_variant` described above, and not running this function
-                // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd
-                // case (that actually removes another suboptimal behavior (I won't say 'false positive') where,
-                // similar to 2., but with a frozen variant) (e.g. borrowing
-                // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`).
-                // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none).
-                matches!(err, ErrorHandled::TooGeneric(..))
+        val: ConstValue<'tcx>,
+    ) -> Result<bool, ()> {
+        let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+        match self.is_ty_freeze(tcx, typing_env, ty) {
+            IsFreeze::Yes => Ok(true),
+            IsFreeze::Maybe if matches!(ty.kind(), ty::Adt(..) | ty::Array(..) | ty::Tuple(..)) => {
+                for &(val, ty) in tcx
+                    .try_destructure_mir_constant_for_user_output(val, ty)
+                    .ok_or(())?
+                    .fields
+                {
+                    if !self.is_value_freeze(tcx, typing_env, ty, val)? {
+                        return Ok(false);
+                    }
+                }
+                Ok(true)
             },
-            |val| val.map_or(true, |val| Self::is_value_unfrozen_raw_inner(cx, val, ty)),
-        )
-    }
-
-    fn is_value_unfrozen_poly(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool {
-        let def_id = body_id.hir_id.owner.to_def_id();
-        let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id);
-        let instance = ty::Instance::new_raw(def_id, args);
-        let cid = GlobalId {
-            instance,
-            promoted: None,
-        };
-        let typing_env = ty::TypingEnv::post_analysis(cx.tcx, def_id);
-        let result = cx.tcx.const_eval_global_id_for_typeck(typing_env, cid, DUMMY_SP);
-        Self::is_value_unfrozen_raw(cx, result, ty)
-    }
-
-    fn is_value_unfrozen_expr(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool {
-        let args = cx.typeck_results().node_args(hir_id);
-
-        let result = Self::const_eval_resolve(
-            cx.tcx,
-            cx.typing_env(),
-            ty::UnevaluatedConst::new(def_id, args),
-            DUMMY_SP,
-        );
-        Self::is_value_unfrozen_raw(cx, result, ty)
+            IsFreeze::Maybe | IsFreeze::No => Ok(false),
+        }
     }
 
-    pub fn const_eval_resolve(
+    /// Checks if the given expression creates a value which is `Freeze`.
+    ///
+    /// This will return `true` if the type is maybe `Freeze`, but it cannot be
+    /// determined for certain from the value.
+    ///
+    /// `typing_env` and `gen_args` are from the constant's use site.
+    /// `typeck` and `e` are from the constant's definition site.
+    fn is_init_expr_freeze(
+        &mut self,
         tcx: TyCtxt<'tcx>,
-        typing_env: ty::TypingEnv<'tcx>,
-        ct: ty::UnevaluatedConst<'tcx>,
-        span: Span,
-    ) -> EvalToValTreeResult<'tcx> {
-        match ty::Instance::try_resolve(tcx, typing_env, ct.def, ct.args) {
-            Ok(Some(instance)) => {
-                let cid = GlobalId {
-                    instance,
-                    promoted: None,
-                };
-                tcx.const_eval_global_id_for_typeck(typing_env, cid, span)
+        typing_env: TypingEnv<'tcx>,
+        typeck: &'tcx TypeckResults<'tcx>,
+        gen_args: GenericArgsRef<'tcx>,
+        e: &'tcx Expr<'tcx>,
+    ) -> bool {
+        // Make sure to instantiate all types coming from `typeck` with `gen_args`.
+        let ty = EarlyBinder::bind(typeck.expr_ty(e)).instantiate(tcx, gen_args);
+        let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+        match self.is_ty_freeze(tcx, typing_env, ty) {
+            IsFreeze::Yes => true,
+            IsFreeze::No => false,
+            IsFreeze::Maybe => match e.kind {
+                ExprKind::Block(b, _)
+                    if !b.targeted_by_break
+                        && b.stmts.is_empty()
+                        && let Some(e) = b.expr =>
+                {
+                    self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, e)
+                },
+                ExprKind::Path(ref p) => {
+                    let res = typeck.qpath_res(p, e.hir_id);
+                    let gen_args = EarlyBinder::bind(typeck.node_args(e.hir_id)).instantiate(tcx, gen_args);
+                    match res {
+                        Res::Def(DefKind::Const | DefKind::AssocConst, did)
+                            if let Ok(val) =
+                                tcx.const_eval_resolve(typing_env, UnevaluatedConst::new(did, gen_args), DUMMY_SP)
+                                && let Ok(is_freeze) = self.is_value_freeze(tcx, typing_env, ty, val) =>
+                        {
+                            is_freeze
+                        },
+                        Res::Def(DefKind::Const | DefKind::AssocConst, did)
+                            if let Some((typeck, init)) = get_const_hir_value(tcx, typing_env, did, gen_args) =>
+                        {
+                            self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, init)
+                        },
+                        // Either this is a unit constructor, or some unknown value.
+                        // In either case we consider the value to be `Freeze`.
+                        _ => true,
+                    }
+                },
+                ExprKind::Call(callee, args)
+                    if let ExprKind::Path(p) = &callee.kind
+                        && let res = typeck.qpath_res(p, callee.hir_id)
+                        && matches!(res, Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(_)) =>
+                {
+                    args.iter()
+                        .all(|e| self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, e))
+                },
+                ExprKind::Struct(_, fields, StructTailExpr::None) => fields
+                    .iter()
+                    .all(|f| self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, f.expr)),
+                ExprKind::Tup(exprs) | ExprKind::Array(exprs) => exprs
+                    .iter()
+                    .all(|e| self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, e)),
+                ExprKind::Repeat(e, _) => self.is_init_expr_freeze(tcx, typing_env, typeck, gen_args, e),
+                _ => true,
             },
-            Ok(None) => Err(ErrorHandled::TooGeneric(span)),
-            Err(err) => Err(ErrorHandled::Reported(
-                ReportedErrorInfo::non_const_eval_error(err),
-                span,
-            )),
         }
     }
-}
 
-impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
-    fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) {
-        if let ItemKind::Const(.., body_id) = it.kind {
-            let ty = cx.tcx.type_of(it.owner_id).instantiate_identity();
-            if !ignored_macro(cx, it)
-                && self.interior_mut.is_interior_mut_ty(cx, ty)
-                && Self::is_value_unfrozen_poly(cx, body_id, ty)
-            {
-                lint(cx, Source::Item { item: it.span, ty });
+    /// Checks if the given expression (or a local projection of it) is both borrowed and
+    /// definitely a non-`Freeze` type.
+    fn is_non_freeze_expr_borrowed(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        typing_env: TypingEnv<'tcx>,
+        typeck: &'tcx TypeckResults<'tcx>,
+        mut src_expr: &'tcx Expr<'tcx>,
+    ) -> Option<BorrowSource<'tcx>> {
+        let mut parents = tcx.hir_parent_iter(src_expr.hir_id);
+        loop {
+            let ty = typeck.expr_ty(src_expr);
+            // Normalized as we need to check if this is an array later.
+            let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+            let is_freeze = self.is_ty_freeze(tcx, typing_env, ty);
+            if is_freeze.is_freeze() {
+                return None;
             }
-        }
-    }
-
-    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'_>) {
-        if let TraitItemKind::Const(_, body_id_opt) = &trait_item.kind {
-            let ty = cx.tcx.type_of(trait_item.owner_id).instantiate_identity();
-
-            // Normalize assoc types because ones originated from generic params
-            // bounded other traits could have their bound.
-            let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
-            if self.interior_mut.is_interior_mut_ty(cx, normalized)
-                // When there's no default value, lint it only according to its type;
-                // in other words, lint consts whose value *could* be unfrozen, not definitely is.
-                // This feels inconsistent with how the lint treats generic types,
-                // which avoids linting types which potentially become unfrozen.
-                // One could check whether an unfrozen type have a *frozen variant*
-                // (like `body_id_opt.map_or_else(|| !has_frozen_variant(...), ...)`),
-                // and do the same as the case of generic types at impl items.
-                // Note that it isn't sufficient to check if it has an enum
-                // since all of that enum's variants can be unfrozen:
-                // i.e. having an enum doesn't necessary mean a type has a frozen variant.
-                // And, implementing it isn't a trivial task; it'll probably end up
-                // re-implementing the trait predicate evaluation specific to `Freeze`.
-                && body_id_opt.is_none_or(|body_id| Self::is_value_unfrozen_poly(cx, body_id, normalized))
-            {
-                lint(cx, Source::Assoc { item: trait_item.span });
+            if let [adjust, ..] = typeck.expr_adjustments(src_expr) {
+                return does_adjust_borrow(adjust)
+                    .filter(|_| is_freeze.is_not_freeze())
+                    .map(|cause| BorrowSource::new(tcx, src_expr, cause));
             }
+            let Some((_, Node::Expr(use_expr))) = parents.next() else {
+                return None;
+            };
+            match use_expr.kind {
+                ExprKind::Field(..) => {},
+                ExprKind::Index(..) if ty.is_array() => {},
+                ExprKind::AddrOf(..) if is_freeze.is_not_freeze() => {
+                    return Some(BorrowSource::new(tcx, use_expr, BorrowCause::Borrow));
+                },
+                // All other expressions use the value.
+                _ => return None,
+            }
+            src_expr = use_expr;
         }
     }
 
-    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
-        if let ImplItemKind::Const(_, body_id) = &impl_item.kind {
-            let item_def_id = cx.tcx.hir_get_parent_item(impl_item.hir_id()).def_id;
-            let item = cx.tcx.hir_expect_item(item_def_id);
-
-            match &item.kind {
-                ItemKind::Impl(Impl {
-                    of_trait: Some(of_trait_ref),
-                    ..
-                }) => {
-                    if let Some(of_trait_def_id) = of_trait_ref.trait_def_id()
-                        // Lint a trait impl item only when the definition is a generic type,
-                        // assuming an assoc const is not meant to be an interior mutable type.
-                        && let Some(of_assoc_item) = cx
-                            .tcx
-                            .associated_item(impl_item.owner_id)
-                            .trait_item_def_id
-                        && cx
-                            .tcx
-                            .layout_of(ty::TypingEnv::post_analysis(cx.tcx, of_trait_def_id).as_query_input(
-                                // Normalize assoc types because ones originated from generic params
-                                // bounded other traits could have their bound at the trait defs;
-                                // and, in that case, the definition is *not* generic.
-                                cx.tcx.normalize_erasing_regions(
-                                    ty::TypingEnv::post_analysis(cx.tcx, of_trait_def_id),
-                                    cx.tcx.type_of(of_assoc_item).instantiate_identity(),
-                                ),
-                            ))
-                            .is_err()
-                            // If there were a function like `has_frozen_variant` described above,
-                            // we should use here as a frozen variant is a potential to be frozen
-                            // similar to unknown layouts.
-                            // e.g. `layout_of(...).is_err() || has_frozen_variant(...);`
-                        && let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity()
-                        && let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty)
-                        && self.interior_mut.is_interior_mut_ty(cx, normalized)
-                        && Self::is_value_unfrozen_poly(cx, *body_id, normalized)
-                    {
-                        lint(cx, Source::Assoc { item: impl_item.span });
+    /// Checks if the given value (or a local projection of it) is both borrowed and
+    /// definitely non-`Freeze`. Returns `Err` if the constant cannot be read, but the
+    /// result depends on the value.
+    fn is_non_freeze_val_borrowed(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        typing_env: TypingEnv<'tcx>,
+        typeck: &'tcx TypeckResults<'tcx>,
+        mut src_expr: &'tcx Expr<'tcx>,
+        mut val: ConstValue<'tcx>,
+    ) -> Result<Option<BorrowSource<'tcx>>, ()> {
+        let mut parents = tcx.hir_parent_iter(src_expr.hir_id);
+        let mut ty = typeck.expr_ty(src_expr);
+        loop {
+            // Normalized as we need to check if this is an array later.
+            ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+            if let [adjust, ..] = typeck.expr_adjustments(src_expr) {
+                let res = if let Some(cause) = does_adjust_borrow(adjust)
+                    && !self.is_value_freeze(tcx, typing_env, ty, val)?
+                {
+                    Some(BorrowSource::new(tcx, src_expr, cause))
+                } else {
+                    None
+                };
+                return Ok(res);
+            }
+            // Check only the type here as the result gets cached for each type.
+            if self.is_ty_freeze(tcx, typing_env, ty).is_freeze() {
+                return Ok(None);
+            }
+            let Some((_, Node::Expr(use_expr))) = parents.next() else {
+                return Ok(None);
+            };
+            let next_val = match use_expr.kind {
+                ExprKind::Field(_, name) => {
+                    if let Some(idx) = get_field_idx_by_name(ty, name.name) {
+                        tcx.try_destructure_mir_constant_for_user_output(val, ty)
+                            .ok_or(())?
+                            .fields
+                            .get(idx)
+                    } else {
+                        return Ok(None);
                     }
                 },
-                ItemKind::Impl(Impl { of_trait: None, .. }) => {
-                    let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity();
-                    // Normalize assoc types originated from generic params.
-                    let normalized = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
-
-                    if self.interior_mut.is_interior_mut_ty(cx, normalized)
-                        && Self::is_value_unfrozen_poly(cx, *body_id, normalized)
-                    {
-                        lint(cx, Source::Assoc { item: impl_item.span });
+                ExprKind::Index(_, idx, _) if ty.is_array() => {
+                    let val = tcx.try_destructure_mir_constant_for_user_output(val, ty).ok_or(())?;
+                    if let Some(Constant::Int(idx)) = ConstEvalCtxt::with_env(tcx, typing_env, typeck).eval(idx) {
+                        val.fields.get(idx as usize)
+                    } else {
+                        // It's some value in the array so check all of them.
+                        for &(val, _) in val.fields {
+                            if let Some(src) =
+                                self.is_non_freeze_val_borrowed(tcx, typing_env, typeck, use_expr, val)?
+                            {
+                                return Ok(Some(src));
+                            }
+                        }
+                        return Ok(None);
                     }
                 },
-                _ => (),
+                ExprKind::AddrOf(..) if !self.is_value_freeze(tcx, typing_env, ty, val)? => {
+                    return Ok(Some(BorrowSource::new(tcx, use_expr, BorrowCause::Borrow)));
+                },
+                // All other expressions use the value.
+                _ => return Ok(None),
+            };
+            src_expr = use_expr;
+            if let Some(&(next_val, next_ty)) = next_val {
+                ty = next_ty;
+                val = next_val;
+            } else {
+                return Ok(None);
             }
         }
     }
 
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
-        if let ExprKind::Path(qpath) = &expr.kind {
-            // Only lint if we use the const item inside a function.
-            if is_in_const_context(cx) {
-                return;
+    /// Checks if the given value (or a local projection of it) is both borrowed and
+    /// definitely non-`Freeze`.
+    ///
+    /// `typing_env` and `init_args` are from the constant's use site.
+    /// `init_typeck` and `init_expr` are from the constant's definition site.
+    #[expect(clippy::too_many_arguments, clippy::too_many_lines)]
+    fn is_non_freeze_init_borrowed(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        typing_env: TypingEnv<'tcx>,
+        typeck: &'tcx TypeckResults<'tcx>,
+        mut src_expr: &'tcx Expr<'tcx>,
+        mut init_typeck: &'tcx TypeckResults<'tcx>,
+        mut init_args: GenericArgsRef<'tcx>,
+        mut init_expr: &'tcx Expr<'tcx>,
+    ) -> Option<BorrowSource<'tcx>> {
+        // Make sure to instantiate all types coming from `init_typeck` with `init_args`.
+        let mut parents = tcx.hir_parent_iter(src_expr.hir_id);
+        loop {
+            // First handle any adjustments since they are cheap to check.
+            if let [adjust, ..] = typeck.expr_adjustments(src_expr) {
+                return does_adjust_borrow(adjust)
+                    .filter(|_| !self.is_init_expr_freeze(tcx, typing_env, init_typeck, init_args, init_expr))
+                    .map(|cause| BorrowSource::new(tcx, src_expr, cause));
             }
 
-            // Make sure it is a const item.
-            let Res::Def(DefKind::Const | DefKind::AssocConst, item_def_id) = cx.qpath_res(qpath, expr.hir_id) else {
-                return;
-            };
-
-            // Climb up to resolve any field access and explicit referencing.
-            let mut cur_expr = expr;
-            let mut dereferenced_expr = expr;
-            let mut needs_check_adjustment = true;
+            // Then read through constants and blocks on the init expression before
+            // applying the next use expression.
             loop {
-                let parent_id = cx.tcx.parent_hir_id(cur_expr.hir_id);
-                if parent_id == cur_expr.hir_id {
-                    break;
+                match init_expr.kind {
+                    ExprKind::Block(b, _)
+                        if !b.targeted_by_break
+                            && b.stmts.is_empty()
+                            && let Some(next_init) = b.expr =>
+                    {
+                        init_expr = next_init;
+                    },
+                    ExprKind::Path(ref init_path) => {
+                        let next_init_args =
+                            EarlyBinder::bind(init_typeck.node_args(init_expr.hir_id)).instantiate(tcx, init_args);
+                        match init_typeck.qpath_res(init_path, init_expr.hir_id) {
+                            Res::Def(DefKind::Ctor(..), _) => return None,
+                            Res::Def(DefKind::Const | DefKind::AssocConst, did)
+                                if let Ok(val) = tcx.const_eval_resolve(
+                                    typing_env,
+                                    UnevaluatedConst::new(did, next_init_args),
+                                    DUMMY_SP,
+                                ) && let Ok(res) =
+                                    self.is_non_freeze_val_borrowed(tcx, typing_env, init_typeck, src_expr, val) =>
+                            {
+                                return res;
+                            },
+                            Res::Def(DefKind::Const | DefKind::AssocConst, did)
+                                if let Some((next_typeck, value)) =
+                                    get_const_hir_value(tcx, typing_env, did, next_init_args) =>
+                            {
+                                init_typeck = next_typeck;
+                                init_args = next_init_args;
+                                init_expr = value;
+                            },
+                            // There's no more that we can read from the init expression. Switch to a
+                            // type based check.
+                            _ => {
+                                return self.is_non_freeze_expr_borrowed(tcx, typing_env, typeck, src_expr);
+                            },
+                        }
+                    },
+                    _ => break,
                 }
-                if let Node::Expr(parent_expr) = cx.tcx.hir_node(parent_id) {
-                    match &parent_expr.kind {
-                        ExprKind::AddrOf(..) => {
-                            // `&e` => `e` must be referenced.
-                            needs_check_adjustment = false;
-                        },
-                        ExprKind::Field(..) => {
-                            needs_check_adjustment = true;
+            }
 
-                            // Check whether implicit dereferences happened;
-                            // if so, no need to go further up
-                            // because of the same reason as the `ExprKind::Unary` case.
-                            if cx
-                                .typeck_results()
-                                .expr_adjustments(dereferenced_expr)
-                                .iter()
-                                .any(|adj| matches!(adj.kind, Adjust::Deref(_)))
-                            {
-                                break;
-                            }
+            // Then a type check. Note we only check the type here as the result
+            // gets cached.
+            let ty = EarlyBinder::bind(typeck.expr_ty(src_expr)).instantiate(tcx, init_args);
+            // Normalized as we need to check if this is an array later.
+            let ty = tcx.try_normalize_erasing_regions(typing_env, ty).unwrap_or(ty);
+            if self.is_ty_freeze(tcx, typing_env, ty).is_freeze() {
+                return None;
+            }
 
-                            dereferenced_expr = parent_expr;
-                        },
-                        ExprKind::Index(e, _, _) if ptr::eq(&raw const **e, cur_expr) => {
-                            // `e[i]` => desugared to `*Index::index(&e, i)`,
-                            // meaning `e` must be referenced.
-                            // no need to go further up since a method call is involved now.
-                            needs_check_adjustment = false;
-                            break;
-                        },
-                        ExprKind::Unary(UnOp::Deref, _) => {
-                            // `*e` => desugared to `*Deref::deref(&e)`,
-                            // meaning `e` must be referenced.
-                            // no need to go further up since a method call is involved now.
-                            needs_check_adjustment = false;
-                            break;
+            // Finally reduce the init expression using the next use expression.
+            let Some((_, Node::Expr(use_expr))) = parents.next() else {
+                return None;
+            };
+            init_expr = match &use_expr.kind {
+                ExprKind::Field(_, name) => match init_expr.kind {
+                    ExprKind::Struct(_, fields, _)
+                        if let Some(field) = fields.iter().find(|f| f.ident.name == name.name) =>
+                    {
+                        field.expr
+                    },
+                    ExprKind::Tup(fields)
+                        if let Ok(idx) = name.as_str().parse::<usize>()
+                            && let Some(field) = fields.get(idx) =>
+                    {
+                        field
+                    },
+                    ExprKind::Call(callee, args)
+                        if let ExprKind::Path(callee_path) = &callee.kind
+                            && matches!(
+                                init_typeck.qpath_res(callee_path, callee.hir_id),
+                                Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(_)
+                            )
+                            && let Ok(idx) = name.as_str().parse::<usize>()
+                            && let Some(arg) = args.get(idx) =>
+                    {
+                        arg
+                    },
+                    // Revert to a type based check as we don't know the field's value.
+                    _ => return self.is_non_freeze_expr_borrowed(tcx, typing_env, typeck, use_expr),
+                },
+                ExprKind::Index(_, idx, _) if ty.is_array() => match init_expr.kind {
+                    ExprKind::Array(fields) => {
+                        if let Some(Constant::Int(idx)) = ConstEvalCtxt::with_env(tcx, typing_env, typeck).eval(idx) {
+                            // If the index is out of bounds it means the code
+                            // unconditionally panics. In that case there is no borrow.
+                            fields.get(idx as usize)?
+                        } else {
+                            // Unknown index, just run the check for all values.
+                            return fields.iter().find_map(|f| {
+                                self.is_non_freeze_init_borrowed(
+                                    tcx,
+                                    typing_env,
+                                    typeck,
+                                    use_expr,
+                                    init_typeck,
+                                    init_args,
+                                    f,
+                                )
+                            });
+                        }
+                    },
+                    // Just assume the index expression doesn't panic here.
+                    ExprKind::Repeat(field, _) => field,
+                    _ => return self.is_non_freeze_expr_borrowed(tcx, typing_env, typeck, use_expr),
+                },
+                ExprKind::AddrOf(..)
+                    if !self.is_init_expr_freeze(tcx, typing_env, init_typeck, init_args, init_expr) =>
+                {
+                    return Some(BorrowSource::new(tcx, use_expr, BorrowCause::Borrow));
+                },
+                // All other expressions use the value.
+                _ => return None,
+            };
+            src_expr = use_expr;
+        }
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
+        if let ItemKind::Const(ident, .., body_id) = item.kind
+            && !ident.is_special()
+            && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
+            && match self.is_ty_freeze(cx.tcx, cx.typing_env(), ty) {
+                IsFreeze::No => true,
+                IsFreeze::Yes => false,
+                IsFreeze::Maybe => match cx.tcx.const_eval_poly(item.owner_id.to_def_id()) {
+                    Ok(val) if let Ok(is_freeze) = self.is_value_freeze(cx.tcx, cx.typing_env(), ty, val) => !is_freeze,
+                    _ => !self.is_init_expr_freeze(
+                        cx.tcx,
+                        cx.typing_env(),
+                        cx.tcx.typeck(item.owner_id),
+                        GenericArgs::identity_for_item(cx.tcx, item.owner_id),
+                        cx.tcx.hir_body(body_id).value,
+                    ),
+                },
+            }
+            && !item.span.in_external_macro(cx.sess().source_map())
+            // Only needed when compiling `std`
+            && !is_thread_local(cx, item)
+        {
+            span_lint_and_then(
+                cx,
+                DECLARE_INTERIOR_MUTABLE_CONST,
+                ident.span,
+                "a `const` item should not be interior mutable",
+                |diag| {
+                    let Some(sync_trait) = cx.tcx.lang_items().sync_trait() else {
+                        return;
+                    };
+                    if implements_trait(cx, ty, sync_trait, &[]) {
+                        diag.help("consider making this a static item");
+                    } else {
+                        diag.help(
+                            "consider making this `Sync` so that it can go in a static item or using a `thread_local`",
+                        );
+                    }
+                },
+            );
+        }
+    }
+
+    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
+        if let TraitItemKind::Const(_, body_id_opt) = item.kind
+            && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
+            && match self.is_ty_freeze(cx.tcx, cx.typing_env(), ty) {
+                IsFreeze::No => true,
+                IsFreeze::Maybe if let Some(body_id) = body_id_opt => {
+                    match cx.tcx.const_eval_poly(item.owner_id.to_def_id()) {
+                        Ok(val) if let Ok(is_freeze) = self.is_value_freeze(cx.tcx, cx.typing_env(), ty, val) => {
+                            !is_freeze
                         },
-                        _ => break,
+                        _ => !self.is_init_expr_freeze(
+                            cx.tcx,
+                            cx.typing_env(),
+                            cx.tcx.typeck(item.owner_id),
+                            GenericArgs::identity_for_item(cx.tcx, item.owner_id),
+                            cx.tcx.hir_body(body_id).value,
+                        ),
                     }
-                    cur_expr = parent_expr;
-                } else {
-                    break;
-                }
+                },
+                IsFreeze::Yes | IsFreeze::Maybe => false,
             }
+            && !item.span.in_external_macro(cx.sess().source_map())
+        {
+            span_lint(
+                cx,
+                DECLARE_INTERIOR_MUTABLE_CONST,
+                item.ident.span,
+                "a `const` item should not be interior mutable",
+            );
+        }
+    }
 
-            let ty = if needs_check_adjustment {
-                let adjustments = cx.typeck_results().expr_adjustments(dereferenced_expr);
-                if let Some(i) = adjustments
-                    .iter()
-                    .position(|adj| matches!(adj.kind, Adjust::Borrow(_) | Adjust::Deref(_)))
-                {
-                    if i == 0 {
-                        cx.typeck_results().expr_ty(dereferenced_expr)
+    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
+        if let ImplItemKind::Const(_, body_id) = item.kind
+            && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
+            && match self.is_ty_freeze(cx.tcx, cx.typing_env(), ty) {
+                IsFreeze::Yes => false,
+                IsFreeze::No => {
+                    // If this is a trait impl, check if the trait definition is the source
+                    // of the cell.
+                    if let Node::Item(parent_item) = cx.tcx.parent_hir_node(item.hir_id())
+                        && let ItemKind::Impl(impl_block) = parent_item.kind
+                        && let Some(of_trait) = impl_block.of_trait
+                        && let Some(trait_id) = of_trait.trait_def_id()
+                    {
+                        // Replace all instances of `<Self as Trait>::AssocType` with the
+                        // unit type and check again. If the result is the same then the
+                        // trait definition is the cause.
+                        let ty = (ReplaceAssocFolder {
+                            tcx: cx.tcx,
+                            trait_id,
+                            self_ty: cx.tcx.type_of(parent_item.owner_id).instantiate_identity(),
+                        })
+                        .fold_ty(cx.tcx.type_of(item.owner_id).instantiate_identity());
+                        // `ty` may not be normalizable, but that should be fine.
+                        !self.is_ty_freeze(cx.tcx, cx.typing_env(), ty).is_not_freeze()
                     } else {
-                        adjustments[i - 1].target
+                        true
                     }
+                },
+                // Even if this is from a trait, there are values which don't have
+                // interior mutability.
+                IsFreeze::Maybe => match cx.tcx.const_eval_poly(item.owner_id.to_def_id()) {
+                    Ok(val) if let Ok(is_freeze) = self.is_value_freeze(cx.tcx, cx.typing_env(), ty, val) => !is_freeze,
+                    _ => !self.is_init_expr_freeze(
+                        cx.tcx,
+                        cx.typing_env(),
+                        cx.tcx.typeck(item.owner_id),
+                        GenericArgs::identity_for_item(cx.tcx, item.owner_id),
+                        cx.tcx.hir_body(body_id).value,
+                    ),
+                },
+            }
+            && !item.span.in_external_macro(cx.sess().source_map())
+        {
+            span_lint(
+                cx,
+                DECLARE_INTERIOR_MUTABLE_CONST,
+                item.ident.span,
+                "a `const` item should not be interior mutable",
+            );
+        }
+    }
+
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
+        if let ExprKind::Path(qpath) = &e.kind
+            && let typeck = cx.typeck_results()
+            && let Res::Def(DefKind::Const | DefKind::AssocConst, did) = typeck.qpath_res(qpath, e.hir_id)
+            // As of `1.80` constant contexts can't borrow any type with interior mutability
+            && !is_in_const_context(cx)
+            && !self.is_ty_freeze(cx.tcx, cx.typing_env(), typeck.expr_ty(e)).is_freeze()
+            && let Some(borrow_src) = {
+                // The extra block helps formatting a lot.
+                if let Ok(val) = cx.tcx.const_eval_resolve(
+                    cx.typing_env(),
+                    UnevaluatedConst::new(did, typeck.node_args(e.hir_id)),
+                    DUMMY_SP,
+                ) && let Ok(src) = self.is_non_freeze_val_borrowed(cx.tcx, cx.typing_env(), typeck, e, val)
+                {
+                    src
+                } else if let init_args = typeck.node_args(e.hir_id)
+                    && let Some((init_typeck, init)) = get_const_hir_value(cx.tcx, cx.typing_env(), did, init_args)
+                {
+                    self.is_non_freeze_init_borrowed(cx.tcx, cx.typing_env(), typeck, e, init_typeck, init_args, init)
                 } else {
-                    // No borrow adjustments means the entire const is moved.
-                    return;
+                    self.is_non_freeze_expr_borrowed(cx.tcx, cx.typing_env(), typeck, e)
                 }
-            } else {
-                cx.typeck_results().expr_ty(dereferenced_expr)
-            };
-
-            if self.interior_mut.is_interior_mut_ty(cx, ty)
-                && Self::is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty)
-            {
-                lint(cx, Source::Expr { expr: expr.span });
             }
+            && !borrow_src.expr.span.in_external_macro(cx.sess().source_map())
+        {
+            span_lint_and_then(
+                cx,
+                BORROW_INTERIOR_MUTABLE_CONST,
+                borrow_src.expr.span,
+                "a `const` item with interior mutability should not be borrowed",
+                |diag| {
+                    if let Some(msg) = borrow_src.cause.note() {
+                        diag.note(msg);
+                    }
+                    diag.help("assign this const to a local or static variable, and use the variable here");
+                },
+            );
         }
     }
 }
 
-fn ignored_macro(cx: &LateContext<'_>, it: &Item<'_>) -> bool {
+struct ReplaceAssocFolder<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    trait_id: DefId,
+    self_ty: Ty<'tcx>,
+}
+impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceAssocFolder<'tcx> {
+    fn cx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        if let ty::Alias(AliasTyKind::Projection, ty) = ty.kind()
+            && ty.trait_def_id(self.tcx) == self.trait_id
+            && ty.self_ty() == self.self_ty
+        {
+            self.tcx.types.unit
+        } else {
+            ty.super_fold_with(self)
+        }
+    }
+}
+
+fn is_thread_local(cx: &LateContext<'_>, it: &Item<'_>) -> bool {
     macro_backtrace(it.span).any(|macro_call| {
         matches!(
             cx.tcx.get_diagnostic_name(macro_call.def_id),
@@ -507,3 +861,42 @@ fn ignored_macro(cx: &LateContext<'_>, it: &Item<'_>) -> bool {
         )
     })
 }
+
+/// Checks if the adjustment causes a borrow of the original value. Returns
+/// `None` if the value is consumed instead of borrowed.
+fn does_adjust_borrow(adjust: &Adjustment<'_>) -> Option<BorrowCause> {
+    match adjust.kind {
+        Adjust::Borrow(_) => Some(BorrowCause::AutoBorrow),
+        // Custom deref calls `<T as Deref>::deref(&x)` resulting in a borrow.
+        Adjust::Deref(Some(_)) => Some(BorrowCause::AutoDeref),
+        // All other adjustments read the value.
+        _ => None,
+    }
+}
+
+/// Attempts to get the value of a constant as a HIR expression. Also gets the
+/// `TypeckResults` associated with the constant's body.
+fn get_const_hir_value<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    typing_env: TypingEnv<'tcx>,
+    did: DefId,
+    args: GenericArgsRef<'tcx>,
+) -> Option<(&'tcx TypeckResults<'tcx>, &'tcx Expr<'tcx>)> {
+    let did = did.as_local()?;
+    let (did, body_id) = match tcx.hir_node(tcx.local_def_id_to_hir_id(did)) {
+        Node::Item(item) if let ItemKind::Const(.., body_id) = item.kind => (did, body_id),
+        Node::ImplItem(item) if let ImplItemKind::Const(.., body_id) = item.kind => (did, body_id),
+        Node::TraitItem(_)
+            if let Ok(Some(inst)) = Instance::try_resolve(tcx, typing_env, did.into(), args)
+                && let Some(did) = inst.def_id().as_local() =>
+        {
+            match tcx.hir_node(tcx.local_def_id_to_hir_id(did)) {
+                Node::ImplItem(item) if let ImplItemKind::Const(.., body_id) = item.kind => (did, body_id),
+                Node::TraitItem(item) if let TraitItemKind::Const(.., Some(body_id)) = item.kind => (did, body_id),
+                _ => return None,
+            }
+        },
+        _ => return None,
+    };
+    Some((tcx.typeck(did), tcx.hir_body(body_id).value))
+}
diff --git a/clippy_utils/src/ty/mod.rs b/clippy_utils/src/ty/mod.rs
index 26d41cfb497..c50ad17bfad 100644
--- a/clippy_utils/src/ty/mod.rs
+++ b/clippy_utils/src/ty/mod.rs
@@ -1361,3 +1361,14 @@ pub fn is_slice_like<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         || ty.is_array()
         || matches!(ty.kind(), ty::Adt(adt_def, _) if cx.tcx.is_diagnostic_item(sym::Vec, adt_def.did()))
 }
+
+/// Gets the index of a field by name.
+pub fn get_field_idx_by_name(ty: Ty<'_>, name: Symbol) -> Option<usize> {
+    match *ty.kind() {
+        ty::Adt(def, _) if def.is_union() || def.is_struct() => {
+            def.non_enum_variant().fields.iter().position(|f| f.name == name)
+        },
+        ty::Tuple(_) => name.as_str().parse::<usize>().ok(),
+        _ => None,
+    }
+}
diff --git a/tests/ui/borrow_interior_mutable_const/enums.rs b/tests/ui/borrow_interior_mutable_const/enums.rs
index da940a4cfb5..ea47e588858 100644
--- a/tests/ui/borrow_interior_mutable_const/enums.rs
+++ b/tests/ui/borrow_interior_mutable_const/enums.rs
@@ -19,7 +19,7 @@ const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true));
 const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
 
 fn borrow_optional_cell() {
-    let _ = &UNFROZEN_VARIANT; //~ ERROR: interior mutability
+    let _ = &UNFROZEN_VARIANT; //~ borrow_interior_mutable_const
     let _ = &FROZEN_VARIANT;
 }
 
@@ -34,11 +34,11 @@ trait AssocConsts {
         // This is the "suboptimal behavior" mentioned in `is_value_unfrozen`
         // caused by a similar reason to unfrozen types without any default values
         // get linted even if it has frozen variants'.
-        let _ = &Self::TO_BE_FROZEN_VARIANT; //~ ERROR: interior mutability
+        let _ = &Self::TO_BE_FROZEN_VARIANT;
 
         // The lint ignores default values because an impl of this trait can set
         // an unfrozen variant to `DEFAULTED_ON_FROZEN_VARIANT` and use the default impl for `function`.
-        let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; //~ ERROR: interior mutability
+        let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT;
     }
 }
 
@@ -47,9 +47,9 @@ impl AssocConsts for u64 {
     const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
 
     fn function() {
-        let _ = &<Self as AssocConsts>::TO_BE_UNFROZEN_VARIANT; //~ ERROR: interior mutability
+        let _ = &<Self as AssocConsts>::TO_BE_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const
         let _ = &<Self as AssocConsts>::TO_BE_FROZEN_VARIANT;
-        let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ ERROR: interior mutability
+        let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const
         let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT;
     }
 }
@@ -71,7 +71,7 @@ impl AssocTypes for u64 {
     const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen> = None;
 
     fn function() {
-        let _ = &<Self as AssocTypes>::TO_BE_UNFROZEN_VARIANT; //~ ERROR: interior mutability
+        let _ = &<Self as AssocTypes>::TO_BE_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const
         let _ = &<Self as AssocTypes>::TO_BE_FROZEN_VARIANT;
     }
 }
@@ -88,14 +88,14 @@ impl<T> BothOfCellAndGeneric<T> {
     const FROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Frozen(5);
 
     fn function() {
-        let _ = &Self::UNFROZEN_VARIANT; //~ ERROR: interior mutability
-        let _ = &Self::GENERIC_VARIANT; //~ ERROR: interior mutability
+        let _ = &Self::UNFROZEN_VARIANT; //~ borrow_interior_mutable_const
+        let _ = &Self::GENERIC_VARIANT;
         let _ = &Self::FROZEN_VARIANT;
     }
 }
 
 fn main() {
     // constants defined in foreign crates
-    let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ ERROR: interior mutability
+    let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const
     let _ = &helper::WRAPPED_PRIVATE_FROZEN_VARIANT;
 }
diff --git a/tests/ui/borrow_interior_mutable_const/enums.stderr b/tests/ui/borrow_interior_mutable_const/enums.stderr
index 43850384b90..7a3cb7d6aa9 100644
--- a/tests/ui/borrow_interior_mutable_const/enums.stderr
+++ b/tests/ui/borrow_interior_mutable_const/enums.stderr
@@ -1,8 +1,8 @@
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:22:14
+  --> tests/ui/borrow_interior_mutable_const/enums.rs:22:13
    |
 LL |     let _ = &UNFROZEN_VARIANT;
-   |              ^^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 note: the lint level is defined here
@@ -12,68 +12,44 @@ LL | #![deny(clippy::borrow_interior_mutable_const)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:37:18
-   |
-LL |         let _ = &Self::TO_BE_FROZEN_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:41:18
-   |
-LL |         let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:50:18
+  --> tests/ui/borrow_interior_mutable_const/enums.rs:50:17
    |
 LL |         let _ = &<Self as AssocConsts>::TO_BE_UNFROZEN_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:52:18
+  --> tests/ui/borrow_interior_mutable_const/enums.rs:52:17
    |
 LL |         let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:74:18
+  --> tests/ui/borrow_interior_mutable_const/enums.rs:74:17
    |
 LL |         let _ = &<Self as AssocTypes>::TO_BE_UNFROZEN_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:91:18
+  --> tests/ui/borrow_interior_mutable_const/enums.rs:91:17
    |
 LL |         let _ = &Self::UNFROZEN_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: assign this const to a local or static variable, and use the variable here
-
-error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:92:18
-   |
-LL |         let _ = &Self::GENERIC_VARIANT;
-   |                  ^^^^^^^^^^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/enums.rs:99:14
+  --> tests/ui/borrow_interior_mutable_const/enums.rs:99:13
    |
 LL |     let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT;
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
-error: aborting due to 9 previous errors
+error: aborting due to 6 previous errors
 
diff --git a/tests/ui/borrow_interior_mutable_const/others.rs b/tests/ui/borrow_interior_mutable_const/others.rs
index fa729b62d7f..720f88326d7 100644
--- a/tests/ui/borrow_interior_mutable_const/others.rs
+++ b/tests/ui/borrow_interior_mutable_const/others.rs
@@ -62,20 +62,14 @@ mod issue12979 {
 const CELL_REF: StaticRef<(UnsafeCell<u32>,)> = unsafe { StaticRef::new(std::ptr::null()) };
 
 fn main() {
-    ATOMIC.store(1, Ordering::SeqCst);
-    //~^ borrow_interior_mutable_const
-    assert_eq!(ATOMIC.load(Ordering::SeqCst), 5);
-    //~^ borrow_interior_mutable_const
+    ATOMIC.store(1, Ordering::SeqCst); //~ borrow_interior_mutable_const
+    assert_eq!(ATOMIC.load(Ordering::SeqCst), 5); //~ borrow_interior_mutable_const
 
     let _once = ONCE_INIT;
-    let _once_ref = &ONCE_INIT;
-    //~^ borrow_interior_mutable_const
-    let _once_ref_2 = &&ONCE_INIT;
-    //~^ borrow_interior_mutable_const
-    let _once_ref_4 = &&&&ONCE_INIT;
-    //~^ borrow_interior_mutable_const
-    let _once_mut = &mut ONCE_INIT;
-    //~^ borrow_interior_mutable_const
+    let _once_ref = &ONCE_INIT; //~ borrow_interior_mutable_const
+    let _once_ref_2 = &&ONCE_INIT; //~ borrow_interior_mutable_const
+    let _once_ref_4 = &&&&ONCE_INIT; //~ borrow_interior_mutable_const
+    let _once_mut = &mut ONCE_INIT; //~ borrow_interior_mutable_const
     let _atomic_into_inner = ATOMIC.into_inner();
     // these should be all fine.
     let _twice = (ONCE_INIT, ONCE_INIT);
@@ -86,30 +80,22 @@ fn main() {
     let _ref_array_once = &[ONCE_INIT, ONCE_INIT][0];
 
     // referencing projection is still bad.
-    let _ = &ATOMIC_TUPLE;
-    //~^ borrow_interior_mutable_const
-    let _ = &ATOMIC_TUPLE.0;
-    //~^ borrow_interior_mutable_const
-    let _ = &(&&&&ATOMIC_TUPLE).0;
-    //~^ borrow_interior_mutable_const
-    let _ = &ATOMIC_TUPLE.0[0];
-    //~^ borrow_interior_mutable_const
-    let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst);
-    //~^ borrow_interior_mutable_const
+    let _ = &ATOMIC_TUPLE; //~ borrow_interior_mutable_const
+    let _ = &ATOMIC_TUPLE.0; //~ borrow_interior_mutable_const
+    let _ = &(&&&&ATOMIC_TUPLE).0; //~ borrow_interior_mutable_const
+    let _ = &ATOMIC_TUPLE.0[0]; //~ borrow_interior_mutable_const
+    let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst); //~ borrow_interior_mutable_const
     let _ = &ATOMIC_TUPLE.2;
-    let _ = (&&&&ATOMIC_TUPLE).0;
-    let _ = (&&&&ATOMIC_TUPLE).2;
+    let _ = (&&&&ATOMIC_TUPLE).0; //~ borrow_interior_mutable_const
+    let _ = (&&&&ATOMIC_TUPLE).2; //~ borrow_interior_mutable_const
     let _ = ATOMIC_TUPLE.0;
     let _ = ATOMIC_TUPLE.0[0];
-    //~^ borrow_interior_mutable_const
     let _ = ATOMIC_TUPLE.1.into_iter();
     let _ = ATOMIC_TUPLE.2;
     let _ = &{ ATOMIC_TUPLE };
 
-    CELL.set(2);
-    //~^ borrow_interior_mutable_const
-    assert_eq!(CELL.get(), 6);
-    //~^ borrow_interior_mutable_const
+    CELL.set(2); //~ borrow_interior_mutable_const
+    assert_eq!(CELL.get(), 6); //~ borrow_interior_mutable_const
 
     assert_eq!(INTEGER, 8);
     assert!(STRING.is_empty());
diff --git a/tests/ui/borrow_interior_mutable_const/others.stderr b/tests/ui/borrow_interior_mutable_const/others.stderr
index decea153f71..6e887406dcd 100644
--- a/tests/ui/borrow_interior_mutable_const/others.stderr
+++ b/tests/ui/borrow_interior_mutable_const/others.stderr
@@ -4,6 +4,7 @@ error: a `const` item with interior mutability should not be borrowed
 LL |     ATOMIC.store(1, Ordering::SeqCst);
    |     ^^^^^^
    |
+   = note: there is a compiler inserted borrow here
    = help: assign this const to a local or static variable, and use the variable here
 note: the lint level is defined here
   --> tests/ui/borrow_interior_mutable_const/others.rs:1:9
@@ -12,108 +13,120 @@ LL | #![deny(clippy::borrow_interior_mutable_const)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:67:16
+  --> tests/ui/borrow_interior_mutable_const/others.rs:66:16
    |
 LL |     assert_eq!(ATOMIC.load(Ordering::SeqCst), 5);
    |                ^^^^^^
    |
+   = note: there is a compiler inserted borrow here
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:71:22
+  --> tests/ui/borrow_interior_mutable_const/others.rs:69:21
    |
 LL |     let _once_ref = &ONCE_INIT;
-   |                      ^^^^^^^^^
+   |                     ^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:73:25
+  --> tests/ui/borrow_interior_mutable_const/others.rs:70:24
    |
 LL |     let _once_ref_2 = &&ONCE_INIT;
-   |                         ^^^^^^^^^
+   |                        ^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:75:27
+  --> tests/ui/borrow_interior_mutable_const/others.rs:71:26
    |
 LL |     let _once_ref_4 = &&&&ONCE_INIT;
-   |                           ^^^^^^^^^
+   |                          ^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:77:26
+  --> tests/ui/borrow_interior_mutable_const/others.rs:72:21
    |
 LL |     let _once_mut = &mut ONCE_INIT;
-   |                          ^^^^^^^^^
+   |                     ^^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:89:14
+  --> tests/ui/borrow_interior_mutable_const/others.rs:83:13
    |
 LL |     let _ = &ATOMIC_TUPLE;
-   |              ^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:91:14
+  --> tests/ui/borrow_interior_mutable_const/others.rs:84:13
    |
 LL |     let _ = &ATOMIC_TUPLE.0;
-   |              ^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:93:19
+  --> tests/ui/borrow_interior_mutable_const/others.rs:85:18
    |
 LL |     let _ = &(&&&&ATOMIC_TUPLE).0;
-   |                   ^^^^^^^^^^^^
+   |                  ^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:95:14
+  --> tests/ui/borrow_interior_mutable_const/others.rs:86:13
    |
 LL |     let _ = &ATOMIC_TUPLE.0[0];
-   |              ^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:97:13
+  --> tests/ui/borrow_interior_mutable_const/others.rs:87:13
    |
 LL |     let _ = ATOMIC_TUPLE.0[0].load(Ordering::SeqCst);
-   |             ^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^^^
    |
+   = note: there is a compiler inserted borrow here
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:103:13
+  --> tests/ui/borrow_interior_mutable_const/others.rs:89:17
    |
-LL |     let _ = ATOMIC_TUPLE.0[0];
-   |             ^^^^^^^^^^^^
+LL |     let _ = (&&&&ATOMIC_TUPLE).0;
+   |                 ^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:109:5
+  --> tests/ui/borrow_interior_mutable_const/others.rs:90:17
+   |
+LL |     let _ = (&&&&ATOMIC_TUPLE).2;
+   |                 ^^^^^^^^^^^^^
+   |
+   = help: assign this const to a local or static variable, and use the variable here
+
+error: a `const` item with interior mutability should not be borrowed
+  --> tests/ui/borrow_interior_mutable_const/others.rs:97:5
    |
 LL |     CELL.set(2);
    |     ^^^^
    |
+   = note: there is a compiler inserted borrow here
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/others.rs:111:16
+  --> tests/ui/borrow_interior_mutable_const/others.rs:98:16
    |
 LL |     assert_eq!(CELL.get(), 6);
    |                ^^^^
    |
+   = note: there is a compiler inserted borrow here
    = help: assign this const to a local or static variable, and use the variable here
 
-error: aborting due to 14 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/tests/ui/borrow_interior_mutable_const/projections.stderr b/tests/ui/borrow_interior_mutable_const/projections.stderr
index eabaf66560a..b0e1883f8bf 100644
--- a/tests/ui/borrow_interior_mutable_const/projections.stderr
+++ b/tests/ui/borrow_interior_mutable_const/projections.stderr
@@ -1,8 +1,8 @@
 error: a `const` item should not be interior mutable
-  --> tests/ui/borrow_interior_mutable_const/projections.rs:27:1
+  --> tests/ui/borrow_interior_mutable_const/projections.rs:27:7
    |
 LL | const CELL: Assoc<u8> = UnsafeCell::new(0);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |       ^^^^
    |
    = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
 note: the lint level is defined here
@@ -12,18 +12,18 @@ LL | #![deny(clippy::declare_interior_mutable_const)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/borrow_interior_mutable_const/projections.rs:29:1
+  --> tests/ui/borrow_interior_mutable_const/projections.rs:29:7
    |
 LL | const MUTABLE: MaybeMutable = MaybeMutable::Mutable(CELL);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |       ^^^^^^^
    |
    = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/projections.rs:38:16
+  --> tests/ui/borrow_interior_mutable_const/projections.rs:38:15
    |
 LL |     print_ref(&CELL);
-   |                ^^^^
+   |               ^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 note: the lint level is defined here
@@ -33,10 +33,10 @@ LL | #![deny(clippy::borrow_interior_mutable_const)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/projections.rs:40:16
+  --> tests/ui/borrow_interior_mutable_const/projections.rs:40:15
    |
 LL |     print_ref(&MUTABLE);
-   |                ^^^^^^^
+   |               ^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
diff --git a/tests/ui/borrow_interior_mutable_const/traits.rs b/tests/ui/borrow_interior_mutable_const/traits.rs
index c4878dbe57b..34a758efa2c 100644
--- a/tests/ui/borrow_interior_mutable_const/traits.rs
+++ b/tests/ui/borrow_interior_mutable_const/traits.rs
@@ -12,8 +12,7 @@ trait ConcreteTypes {
     const STRING: String;
 
     fn function() {
-        let _ = &Self::ATOMIC;
-        //~^ borrow_interior_mutable_const
+        let _ = &Self::ATOMIC; //~ borrow_interior_mutable_const
         let _ = &Self::STRING;
     }
 }
@@ -24,8 +23,7 @@ impl ConcreteTypes for u64 {
 
     fn function() {
         // Lint this again since implementers can choose not to borrow it.
-        let _ = &Self::ATOMIC;
-        //~^ borrow_interior_mutable_const
+        let _ = &Self::ATOMIC; //~ borrow_interior_mutable_const
         let _ = &Self::STRING;
     }
 }
@@ -50,8 +48,7 @@ impl<T: ConstDefault> GenericTypes<T, AtomicUsize> for Vec<T> {
 
     fn function() {
         let _ = &Self::TO_REMAIN_GENERIC;
-        let _ = &Self::TO_BE_CONCRETE;
-        //~^ borrow_interior_mutable_const
+        let _ = &Self::TO_BE_CONCRETE; //~ borrow_interior_mutable_const
     }
 }
 
@@ -86,10 +83,8 @@ impl<T: ConstDefault> AssocTypes for Vec<T> {
 
     fn function() {
         let _ = &Self::TO_BE_FROZEN;
-        let _ = &Self::TO_BE_UNFROZEN;
-        //~^ borrow_interior_mutable_const
-        let _ = &Self::WRAPPED_TO_BE_UNFROZEN;
-        //~^ borrow_interior_mutable_const
+        let _ = &Self::TO_BE_UNFROZEN; //~ borrow_interior_mutable_const
+        let _ = &Self::WRAPPED_TO_BE_UNFROZEN; //~ borrow_interior_mutable_const
         let _ = &Self::WRAPPED_TO_BE_GENERIC_PARAM;
     }
 }
@@ -111,8 +106,7 @@ where
 
     fn function() {
         let _ = &Self::NOT_BOUNDED;
-        let _ = &Self::BOUNDED;
-        //~^ borrow_interior_mutable_const
+        let _ = &Self::BOUNDED; //~ borrow_interior_mutable_const
     }
 }
 
@@ -125,8 +119,7 @@ where
 
     fn function() {
         let _ = &Self::NOT_BOUNDED;
-        let _ = &Self::BOUNDED;
-        //~^ borrow_interior_mutable_const
+        let _ = &Self::BOUNDED; //~ borrow_interior_mutable_const
     }
 }
 
@@ -155,10 +148,8 @@ impl SelfType for AtomicUsize {
     const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21));
 
     fn function() {
-        let _ = &Self::SELF;
-        //~^ borrow_interior_mutable_const
-        let _ = &Self::WRAPPED_SELF;
-        //~^ borrow_interior_mutable_const
+        let _ = &Self::SELF; //~ borrow_interior_mutable_const
+        let _ = &Self::WRAPPED_SELF; //~ borrow_interior_mutable_const
     }
 }
 
@@ -167,10 +158,8 @@ trait BothOfCellAndGeneric<T> {
     const INDIRECT: Cell<*const T>;
 
     fn function() {
-        let _ = &Self::DIRECT;
-        //~^ borrow_interior_mutable_const
-        let _ = &Self::INDIRECT;
-        //~^ borrow_interior_mutable_const
+        let _ = &Self::DIRECT; //~ borrow_interior_mutable_const
+        let _ = &Self::INDIRECT; //~ borrow_interior_mutable_const
     }
 }
 
@@ -179,10 +168,8 @@ impl<T: ConstDefault> BothOfCellAndGeneric<T> for Vec<T> {
     const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null());
 
     fn function() {
-        let _ = &Self::DIRECT;
-        //~^ borrow_interior_mutable_const
-        let _ = &Self::INDIRECT;
-        //~^ borrow_interior_mutable_const
+        let _ = &Self::DIRECT; //~ borrow_interior_mutable_const
+        let _ = &Self::INDIRECT; //~ borrow_interior_mutable_const
     }
 }
 
@@ -201,19 +188,15 @@ where
     const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19);
 
     fn function() {
-        let _ = &Self::ATOMIC;
-        //~^ borrow_interior_mutable_const
+        let _ = &Self::ATOMIC; //~ borrow_interior_mutable_const
         let _ = &Self::COW;
         let _ = &Self::GENERIC_TYPE;
         let _ = &Self::ASSOC_TYPE;
-        let _ = &Self::BOUNDED_ASSOC_TYPE;
-        //~^ borrow_interior_mutable_const
+        let _ = &Self::BOUNDED_ASSOC_TYPE; //~ borrow_interior_mutable_const
     }
 }
 
 fn main() {
-    u64::ATOMIC.store(5, Ordering::SeqCst);
-    //~^ borrow_interior_mutable_const
-    assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9);
-    //~^ borrow_interior_mutable_const
+    u64::ATOMIC.store(5, Ordering::SeqCst); //~ borrow_interior_mutable_const
+    assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9); //~ borrow_interior_mutable_const
 }
diff --git a/tests/ui/borrow_interior_mutable_const/traits.stderr b/tests/ui/borrow_interior_mutable_const/traits.stderr
index cad68ca9260..233ec6dad67 100644
--- a/tests/ui/borrow_interior_mutable_const/traits.stderr
+++ b/tests/ui/borrow_interior_mutable_const/traits.stderr
@@ -1,8 +1,8 @@
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:15:18
+  --> tests/ui/borrow_interior_mutable_const/traits.rs:15:17
    |
 LL |         let _ = &Self::ATOMIC;
-   |                  ^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 note: the lint level is defined here
@@ -12,131 +12,133 @@ LL | #![deny(clippy::borrow_interior_mutable_const)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:27:18
+  --> tests/ui/borrow_interior_mutable_const/traits.rs:26:17
    |
 LL |         let _ = &Self::ATOMIC;
-   |                  ^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:53:18
+  --> tests/ui/borrow_interior_mutable_const/traits.rs:51:17
    |
 LL |         let _ = &Self::TO_BE_CONCRETE;
-   |                  ^^^^^^^^^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:89:18
+  --> tests/ui/borrow_interior_mutable_const/traits.rs:86:17
    |
 LL |         let _ = &Self::TO_BE_UNFROZEN;
-   |                  ^^^^^^^^^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:91:18
+  --> tests/ui/borrow_interior_mutable_const/traits.rs:87:17
    |
 LL |         let _ = &Self::WRAPPED_TO_BE_UNFROZEN;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:114:18
+  --> tests/ui/borrow_interior_mutable_const/traits.rs:109:17
    |
 LL |         let _ = &Self::BOUNDED;
-   |                  ^^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:128:18
+  --> tests/ui/borrow_interior_mutable_const/traits.rs:122:17
    |
 LL |         let _ = &Self::BOUNDED;
-   |                  ^^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:158:18
+  --> tests/ui/borrow_interior_mutable_const/traits.rs:151:17
    |
 LL |         let _ = &Self::SELF;
-   |                  ^^^^^^^^^^
+   |                 ^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:160:18
+  --> tests/ui/borrow_interior_mutable_const/traits.rs:152:17
    |
 LL |         let _ = &Self::WRAPPED_SELF;
-   |                  ^^^^^^^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:170:18
+  --> tests/ui/borrow_interior_mutable_const/traits.rs:161:17
    |
 LL |         let _ = &Self::DIRECT;
-   |                  ^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:172:18
+  --> tests/ui/borrow_interior_mutable_const/traits.rs:162:17
    |
 LL |         let _ = &Self::INDIRECT;
-   |                  ^^^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:182:18
+  --> tests/ui/borrow_interior_mutable_const/traits.rs:171:17
    |
 LL |         let _ = &Self::DIRECT;
-   |                  ^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:184:18
+  --> tests/ui/borrow_interior_mutable_const/traits.rs:172:17
    |
 LL |         let _ = &Self::INDIRECT;
-   |                  ^^^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:204:18
+  --> tests/ui/borrow_interior_mutable_const/traits.rs:191:17
    |
 LL |         let _ = &Self::ATOMIC;
-   |                  ^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:209:18
+  --> tests/ui/borrow_interior_mutable_const/traits.rs:195:17
    |
 LL |         let _ = &Self::BOUNDED_ASSOC_TYPE;
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:215:5
+  --> tests/ui/borrow_interior_mutable_const/traits.rs:200:5
    |
 LL |     u64::ATOMIC.store(5, Ordering::SeqCst);
    |     ^^^^^^^^^^^
    |
+   = note: there is a compiler inserted borrow here
    = help: assign this const to a local or static variable, and use the variable here
 
 error: a `const` item with interior mutability should not be borrowed
-  --> tests/ui/borrow_interior_mutable_const/traits.rs:217:16
+  --> tests/ui/borrow_interior_mutable_const/traits.rs:201:16
    |
 LL |     assert_eq!(u64::ATOMIC.load(Ordering::SeqCst), 9);
    |                ^^^^^^^^^^^
    |
+   = note: there is a compiler inserted borrow here
    = help: assign this const to a local or static variable, and use the variable here
 
 error: aborting due to 17 previous errors
diff --git a/tests/ui/crashes/ice-12979.1.fixed b/tests/ui/crashes/ice-12979.1.fixed
new file mode 100644
index 00000000000..e68f1c20a8e
--- /dev/null
+++ b/tests/ui/crashes/ice-12979.1.fixed
@@ -0,0 +1,2 @@
+#[deny(clippy::declare_interior_mutable_const)] //~ empty_line_after_outer_attr
+const FOO: u8 = 0;
diff --git a/tests/ui/crashes/ice-12979.2.fixed b/tests/ui/crashes/ice-12979.2.fixed
new file mode 100644
index 00000000000..e89fa636d4b
--- /dev/null
+++ b/tests/ui/crashes/ice-12979.2.fixed
@@ -0,0 +1,3 @@
+#![deny(clippy::declare_interior_mutable_const)] //~ empty_line_after_outer_attr
+
+const FOO: u8 = 0;
diff --git a/tests/ui/crashes/ice-12979.rs b/tests/ui/crashes/ice-12979.rs
new file mode 100644
index 00000000000..a2787291d9e
--- /dev/null
+++ b/tests/ui/crashes/ice-12979.rs
@@ -0,0 +1,3 @@
+#[deny(clippy::declare_interior_mutable_const)] //~ empty_line_after_outer_attr
+
+const FOO: u8 = 0;
diff --git a/tests/ui/crashes/ice-12979.stderr b/tests/ui/crashes/ice-12979.stderr
new file mode 100644
index 00000000000..5e760816164
--- /dev/null
+++ b/tests/ui/crashes/ice-12979.stderr
@@ -0,0 +1,19 @@
+error: empty line after outer attribute
+  --> tests/ui/crashes/ice-12979.rs:1:1
+   |
+LL | / #[deny(clippy::declare_interior_mutable_const)]
+LL | |
+   | |_^
+LL |   const FOO: u8 = 0;
+   |   --------- the attribute applies to this constant item
+   |
+   = note: `-D clippy::empty-line-after-outer-attr` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::empty_line_after_outer_attr)]`
+   = help: if the empty line is unintentional, remove it
+help: if the attribute should apply to the crate use an inner attribute
+   |
+LL | #![deny(clippy::declare_interior_mutable_const)]
+   |  +
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/crashes/ice-9445.rs b/tests/ui/crashes/ice-9445.rs
deleted file mode 100644
index 232b8e4a795..00000000000
--- a/tests/ui/crashes/ice-9445.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-const UNINIT: core::mem::MaybeUninit<core::cell::Cell<&'static ()>> = core::mem::MaybeUninit::uninit();
-//~^ declare_interior_mutable_const
-
-fn main() {}
diff --git a/tests/ui/crashes/ice-9445.stderr b/tests/ui/crashes/ice-9445.stderr
deleted file mode 100644
index 76689cd6f5c..00000000000
--- a/tests/ui/crashes/ice-9445.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error: a `const` item should not be interior mutable
-  --> tests/ui/crashes/ice-9445.rs:1:1
-   |
-LL | const UNINIT: core::mem::MaybeUninit<core::cell::Cell<&'static ()>> = core::mem::MaybeUninit::uninit();
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
-   = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]`
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/declare_interior_mutable_const/enums.rs b/tests/ui/declare_interior_mutable_const/enums.rs
index c87468277fb..2ca6b7bc303 100644
--- a/tests/ui/declare_interior_mutable_const/enums.rs
+++ b/tests/ui/declare_interior_mutable_const/enums.rs
@@ -9,8 +9,7 @@ enum OptionalCell {
 }
 
 // a constant with enums should be linted only when the used variant is unfrozen (#3962).
-const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true));
-//~^ declare_interior_mutable_const
+const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); //~ declare_interior_mutable_const
 const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
 
 const fn unfrozen_variant() -> OptionalCell {
@@ -21,8 +20,7 @@ const fn frozen_variant() -> OptionalCell {
     OptionalCell::Frozen
 }
 
-const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant();
-//~^ declare_interior_mutable_const
+const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); //~ declare_interior_mutable_const
 const FROZEN_VARIANT_FROM_FN: OptionalCell = frozen_variant();
 
 enum NestedInnermost {
@@ -60,24 +58,21 @@ trait AssocConsts {
     // When there's no default value, lint it only according to its type.
     // Further details are on the corresponding code (`NonCopyConst::check_trait_item`).
     const TO_BE_UNFROZEN_VARIANT: OptionalCell;
-    //~^ declare_interior_mutable_const
     const TO_BE_FROZEN_VARIANT: OptionalCell;
-    //~^ declare_interior_mutable_const
 
     // Lint default values accordingly.
-    const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
-    //~^ declare_interior_mutable_const
+    const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ declare_interior_mutable_const
     const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
 }
 
 // The lint doesn't trigger for an assoc constant in a trait impl with an unfrozen type even if it
 // has enums. Further details are on the corresponding code in 'NonCopyConst::check_impl_item'.
 impl AssocConsts for u64 {
-    const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
+    const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ declare_interior_mutable_const
     const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
 
     // even if this sets an unfrozen variant, the lint ignores it.
-    const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
+    const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ declare_interior_mutable_const
 }
 
 // At first, I thought I'd need to check every patterns in `trait.rs`; but, what matters
@@ -92,8 +87,7 @@ trait AssocTypes {
 impl AssocTypes for u64 {
     type ToBeUnfrozen = AtomicUsize;
 
-    const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen> = Some(Self::ToBeUnfrozen::new(4));
-    //~^ declare_interior_mutable_const
+    const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen> = Some(Self::ToBeUnfrozen::new(4)); //~ declare_interior_mutable_const
     const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen> = None;
 }
 
@@ -105,30 +99,25 @@ enum BothOfCellAndGeneric<T> {
 }
 
 impl<T> BothOfCellAndGeneric<T> {
-    const UNFROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null()));
-    //~^ declare_interior_mutable_const
+    const UNFROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ declare_interior_mutable_const
 
     // This is a false positive. The argument about this is on `is_value_unfrozen_raw`
     const GENERIC_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Generic(std::ptr::null());
-    //~^ declare_interior_mutable_const
 
     const FROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Frozen(5);
 
     // This is what is likely to be a false negative when one tries to fix
     // the `GENERIC_VARIANT` false positive.
-    const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null());
-    //~^ declare_interior_mutable_const
+    const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); //~ declare_interior_mutable_const
 }
 
 // associated types here is basically the same as the one above.
 trait BothOfCellAndGenericWithAssocType {
     type AssocType;
 
-    const UNFROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> =
-        //~^ declare_interior_mutable_const
+    const UNFROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> = //~ declare_interior_mutable_const
         BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null()));
     const GENERIC_VARIANT: BothOfCellAndGeneric<Self::AssocType> = BothOfCellAndGeneric::Generic(std::ptr::null());
-    //~^ declare_interior_mutable_const
     const FROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> = BothOfCellAndGeneric::Frozen(5);
 }
 
diff --git a/tests/ui/declare_interior_mutable_const/enums.stderr b/tests/ui/declare_interior_mutable_const/enums.stderr
index 32839d14f0e..25f39f243e0 100644
--- a/tests/ui/declare_interior_mutable_const/enums.stderr
+++ b/tests/ui/declare_interior_mutable_const/enums.stderr
@@ -1,89 +1,70 @@
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:12:1
+  --> tests/ui/declare_interior_mutable_const/enums.rs:12:7
    |
 LL | const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true));
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |       ^^^^^^^^^^^^^^^^
    |
    = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
    = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]`
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:24:1
+  --> tests/ui/declare_interior_mutable_const/enums.rs:23:7
    |
 LL | const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant();
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |       ^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:47:1
+  --> tests/ui/declare_interior_mutable_const/enums.rs:45:7
    |
-LL | / const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost {
-LL | |
-LL | |     outer: NestedOuter::NestedInner(NestedInner {
-LL | |         inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)),
-LL | |     }),
-LL | | };
-   | |__^
+LL | const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost {
+   |       ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider making this a static item
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:62:5
+  --> tests/ui/declare_interior_mutable_const/enums.rs:64:11
    |
-LL |     const TO_BE_UNFROZEN_VARIANT: OptionalCell;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:64:5
+  --> tests/ui/declare_interior_mutable_const/enums.rs:71:11
    |
-LL |     const TO_BE_FROZEN_VARIANT: OptionalCell;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
+   |           ^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:68:5
+  --> tests/ui/declare_interior_mutable_const/enums.rs:75:11
    |
-LL |     const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:95:5
+  --> tests/ui/declare_interior_mutable_const/enums.rs:90:11
    |
 LL |     const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen> = Some(Self::ToBeUnfrozen::new(4));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           ^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:108:5
+  --> tests/ui/declare_interior_mutable_const/enums.rs:102:11
    |
 LL |     const UNFROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null()));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:112:5
-   |
-LL |     const GENERIC_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Generic(std::ptr::null());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           ^^^^^^^^^^^^^^^^
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:119:5
+  --> tests/ui/declare_interior_mutable_const/enums.rs:111:11
    |
 LL |     const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:127:5
-   |
-LL | /     const UNFROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> =
-LL | |
-LL | |         BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null()));
-   | |____________________________________________________________________^
+   |           ^^^^^^^
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/enums.rs:130:5
+  --> tests/ui/declare_interior_mutable_const/enums.rs:118:11
    |
-LL |     const GENERIC_VARIANT: BothOfCellAndGeneric<Self::AssocType> = BothOfCellAndGeneric::Generic(std::ptr::null());
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     const UNFROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> =
+   |           ^^^^^^^^^^^^^^^^
 
-error: aborting due to 12 previous errors
+error: aborting due to 10 previous errors
 
diff --git a/tests/ui/declare_interior_mutable_const/others.rs b/tests/ui/declare_interior_mutable_const/others.rs
index 7ce04a3f2c3..362f28b8c53 100644
--- a/tests/ui/declare_interior_mutable_const/others.rs
+++ b/tests/ui/declare_interior_mutable_const/others.rs
@@ -7,20 +7,17 @@ use std::ptr;
 use std::sync::Once;
 use std::sync::atomic::AtomicUsize;
 
-const ATOMIC: AtomicUsize = AtomicUsize::new(5);
-//~^ declare_interior_mutable_const
-const CELL: Cell<usize> = Cell::new(6);
-//~^ declare_interior_mutable_const
+const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ declare_interior_mutable_const
+const CELL: Cell<usize> = Cell::new(6); //~ declare_interior_mutable_const
 const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
 //~^ declare_interior_mutable_const
 
 macro_rules! declare_const {
     ($name:ident: $ty:ty = $e:expr) => {
         const $name: $ty = $e;
-        //~^ declare_interior_mutable_const
     };
 }
-declare_const!(_ONCE: Once = Once::new());
+declare_const!(_ONCE: Once = Once::new()); //~ declare_interior_mutable_const
 
 // const ATOMIC_REF: &AtomicUsize = &AtomicUsize::new(7); // This will simply trigger E0492.
 
diff --git a/tests/ui/declare_interior_mutable_const/others.stderr b/tests/ui/declare_interior_mutable_const/others.stderr
index 09299b29041..243c6b0cc5f 100644
--- a/tests/ui/declare_interior_mutable_const/others.stderr
+++ b/tests/ui/declare_interior_mutable_const/others.stderr
@@ -1,49 +1,47 @@
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/others.rs:10:1
+  --> tests/ui/declare_interior_mutable_const/others.rs:10:7
    |
 LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |       ^^^^^^
    |
    = help: consider making this a static item
    = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]`
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/others.rs:12:1
+  --> tests/ui/declare_interior_mutable_const/others.rs:11:7
    |
 LL | const CELL: Cell<usize> = Cell::new(6);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |       ^^^^
    |
    = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/others.rs:14:1
+  --> tests/ui/declare_interior_mutable_const/others.rs:12:7
    |
 LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec<AtomicUsize>, u8) = ([ATOMIC], Vec::new(), 7);
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |       ^^^^^^^^^^^^
    |
    = help: consider making this a static item
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/others.rs:19:9
+  --> tests/ui/declare_interior_mutable_const/others.rs:20:16
    |
-LL |         const $name: $ty = $e;
-   |         ^^^^^^^^^^^^^^^^^^^^^^
-...
 LL | declare_const!(_ONCE: Once = Once::new());
-   | ----------------------------------------- in this macro invocation
+   |                ^^^^^
    |
-   = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info)
+   = help: consider making this a static item
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/others.rs:47:13
+  --> tests/ui/declare_interior_mutable_const/others.rs:44:19
    |
 LL |             const _BAZ: Cell<usize> = Cell::new(0);
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                   ^^^^
 ...
 LL |     issue_8493!();
    |     ------------- in this macro invocation
    |
+   = help: consider making this `Sync` so that it can go in a static item or using a `thread_local`
    = note: this error originates in the macro `issue_8493` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 5 previous errors
diff --git a/tests/ui/declare_interior_mutable_const/traits.rs b/tests/ui/declare_interior_mutable_const/traits.rs
index d3139be6859..f4916e1b4cf 100644
--- a/tests/ui/declare_interior_mutable_const/traits.rs
+++ b/tests/ui/declare_interior_mutable_const/traits.rs
@@ -7,17 +7,15 @@ use std::sync::atomic::AtomicUsize;
 macro_rules! declare_const {
     ($name:ident: $ty:ty = $e:expr) => {
         const $name: $ty = $e;
-        //~^ declare_interior_mutable_const
     };
 }
 
 // a constant whose type is a concrete type should be linted at the definition site.
 trait ConcreteTypes {
-    const ATOMIC: AtomicUsize;
-    //~^ declare_interior_mutable_const
+    const ATOMIC: AtomicUsize; //~ declare_interior_mutable_const
     const INTEGER: u64;
     const STRING: String;
-    declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC);
+    declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ declare_interior_mutable_const
 }
 
 impl ConcreteTypes for u64 {
@@ -43,7 +41,6 @@ trait GenericTypes<T, U> {
 impl<T: ConstDefault> GenericTypes<T, AtomicUsize> for u64 {
     const TO_REMAIN_GENERIC: T = T::DEFAULT;
     const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11);
-    //~^ declare_interior_mutable_const
 }
 
 // a helper type used below
@@ -68,10 +65,8 @@ impl<T: ConstDefault> AssocTypes for Vec<T> {
     type ToBeGenericParam = T;
 
     const TO_BE_FROZEN: Self::ToBeFrozen = 12;
-    const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13);
-    //~^ declare_interior_mutable_const
-    const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14));
-    //~^ declare_interior_mutable_const
+    const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); //~ declare_interior_mutable_const
+    const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14)); //~ declare_interior_mutable_const
     const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper<Self::ToBeGenericParam> = Wrapper(T::DEFAULT);
 }
 
@@ -90,8 +85,7 @@ where
     T: AssocTypesHelper<ToBeBounded = AtomicUsize>,
 {
     const NOT_BOUNDED: T::NotToBeBounded;
-    const BOUNDED: T::ToBeBounded;
-    //~^ declare_interior_mutable_const
+    const BOUNDED: T::ToBeBounded; //~ declare_interior_mutable_const
 }
 
 impl<T> AssocTypesFromGenericParam<T> for u64
@@ -120,23 +114,18 @@ impl SelfType for AtomicUsize {
     // this (interior mutable `Self` const) exists in `parking_lot`.
     // `const_trait_impl` will replace it in the future, hopefully.
     const SELF: Self = AtomicUsize::new(17);
-    //~^ declare_interior_mutable_const
-    const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21));
-    //~^ declare_interior_mutable_const
+    const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21)); //~ declare_interior_mutable_const
 }
 
 // Even though a constant contains a generic type, if it also have an interior mutable type,
 // it should be linted at the definition site.
 trait BothOfCellAndGeneric<T> {
-    const DIRECT: Cell<T>;
-    //~^ declare_interior_mutable_const
-    const INDIRECT: Cell<*const T>;
-    //~^ declare_interior_mutable_const
+    const DIRECT: Cell<T>; //~ declare_interior_mutable_const
+    const INDIRECT: Cell<*const T>; //~ declare_interior_mutable_const
 }
 
 impl<T: ConstDefault> BothOfCellAndGeneric<T> for u64 {
     const DIRECT: Cell<T> = Cell::new(T::DEFAULT);
-    //~^ declare_interior_mutable_const
     const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null());
 }
 
@@ -148,15 +137,13 @@ impl<T> Local<T>
 where
     T: ConstDefault + AssocTypesHelper<ToBeBounded = AtomicUsize>,
 {
-    const ATOMIC: AtomicUsize = AtomicUsize::new(18);
-    //~^ declare_interior_mutable_const
+    const ATOMIC: AtomicUsize = AtomicUsize::new(18); //~ declare_interior_mutable_const
     const COW: Cow<'static, str> = Cow::Borrowed("tuvwxy");
 
     const GENERIC_TYPE: T = T::DEFAULT;
 
     const ASSOC_TYPE: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED;
-    const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19);
-    //~^ declare_interior_mutable_const
+    const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); //~ declare_interior_mutable_const
 }
 
 fn main() {}
diff --git a/tests/ui/declare_interior_mutable_const/traits.stderr b/tests/ui/declare_interior_mutable_const/traits.stderr
index b03dd7a0840..9b9d9ddeef9 100644
--- a/tests/ui/declare_interior_mutable_const/traits.stderr
+++ b/tests/ui/declare_interior_mutable_const/traits.stderr
@@ -1,88 +1,65 @@
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:16:5
+  --> tests/ui/declare_interior_mutable_const/traits.rs:15:11
    |
 LL |     const ATOMIC: AtomicUsize;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           ^^^^^^
    |
    = note: `-D clippy::declare-interior-mutable-const` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::declare_interior_mutable_const)]`
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:9:9
+  --> tests/ui/declare_interior_mutable_const/traits.rs:18:20
    |
-LL |         const $name: $ty = $e;
-   |         ^^^^^^^^^^^^^^^^^^^^^^
-...
 LL |     declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC);
-   |     ---------------------------------------------------------- in this macro invocation
-   |
-   = note: this error originates in the macro `declare_const` (in Nightly builds, run with -Z macro-backtrace for more info)
+   |                    ^^^^^^^^^^^^^^
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:45:5
-   |
-LL |     const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:71:5
+  --> tests/ui/declare_interior_mutable_const/traits.rs:68:11
    |
 LL |     const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           ^^^^^^^^^^^^^^
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:73:5
+  --> tests/ui/declare_interior_mutable_const/traits.rs:69:11
    |
 LL |     const WRAPPED_TO_BE_UNFROZEN: Wrapper<Self::ToBeUnfrozen> = Wrapper(AtomicUsize::new(14));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           ^^^^^^^^^^^^^^^^^^^^^^
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:93:5
+  --> tests/ui/declare_interior_mutable_const/traits.rs:88:11
    |
 LL |     const BOUNDED: T::ToBeBounded;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:122:5
-   |
-LL |     const SELF: Self = AtomicUsize::new(17);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           ^^^^^^^
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:124:5
+  --> tests/ui/declare_interior_mutable_const/traits.rs:117:11
    |
 LL |     const WRAPPED_SELF: Option<Self> = Some(AtomicUsize::new(21));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           ^^^^^^^^^^^^
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:131:5
+  --> tests/ui/declare_interior_mutable_const/traits.rs:123:11
    |
 LL |     const DIRECT: Cell<T>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^
+   |           ^^^^^^
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:133:5
+  --> tests/ui/declare_interior_mutable_const/traits.rs:124:11
    |
 LL |     const INDIRECT: Cell<*const T>;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:138:5
-   |
-LL |     const DIRECT: Cell<T> = Cell::new(T::DEFAULT);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           ^^^^^^^^
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:151:5
+  --> tests/ui/declare_interior_mutable_const/traits.rs:140:11
    |
 LL |     const ATOMIC: AtomicUsize = AtomicUsize::new(18);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           ^^^^^^
 
 error: a `const` item should not be interior mutable
-  --> tests/ui/declare_interior_mutable_const/traits.rs:158:5
+  --> tests/ui/declare_interior_mutable_const/traits.rs:146:11
    |
 LL |     const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           ^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 13 previous errors
+error: aborting due to 10 previous errors