From 277b4adf08108abd1e08e2bd90a50e8e29cbfd41 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 3 Aug 2024 00:29:23 -0400 Subject: [PATCH 1/3] Rewrite `non_copy_const` --- clippy_lints/src/non_copy_const.rs | 1067 +++++++++++------ clippy_utils/src/ty/mod.rs | 11 + .../ui/borrow_interior_mutable_const/enums.rs | 18 +- .../enums.stderr | 50 +- .../borrow_interior_mutable_const/others.rs | 44 +- .../others.stderr | 63 +- .../projections.stderr | 16 +- .../borrow_interior_mutable_const/traits.rs | 51 +- .../traits.stderr | 66 +- tests/ui/crashes/ice-12979.1.fixed | 2 + tests/ui/crashes/ice-12979.2.fixed | 3 + tests/ui/crashes/ice-12979.rs | 3 + tests/ui/crashes/ice-12979.stderr | 19 + tests/ui/crashes/ice-9445.rs | 4 - tests/ui/crashes/ice-9445.stderr | 12 - .../declare_interior_mutable_const/enums.rs | 29 +- .../enums.stderr | 71 +- .../declare_interior_mutable_const/others.rs | 9 +- .../others.stderr | 26 +- .../declare_interior_mutable_const/traits.rs | 33 +- .../traits.stderr | 65 +- 21 files changed, 984 insertions(+), 678 deletions(-) create mode 100644 tests/ui/crashes/ice-12979.1.fixed create mode 100644 tests/ui/crashes/ice-12979.2.fixed create mode 100644 tests/ui/crashes/ice-12979.rs create mode 100644 tests/ui/crashes/ice-12979.stderr delete mode 100644 tests/ui/crashes/ice-9445.rs delete mode 100644 tests/ui/crashes/ice-9445.stderr diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 63859c0396e4..8df2db859f67 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -1,25 +1,45 @@ -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::is_in_const_context; +use clippy_utils::consts::{ConstEvalCtxt, Constant}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::macros::macro_backtrace; -use clippy_utils::ty::{InteriorMut, implements_trait}; -use rustc_abi::VariantIdx; +use clippy_utils::ty::{get_field_idx_by_name, implements_trait}; +use clippy_utils::{def_path_def_ids, is_in_const_context}; +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 +94,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 +131,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) -> 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) -> 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, IsFreeze>, } impl_lint_pass!(NonCopyConst<'_> => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]); @@ -174,332 +228,634 @@ 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| { + let path: Vec<&str> = ignored_ty.split("::").collect(); + def_path_def_ids(tcx, path.as_slice()) + }) + .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, 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 { + 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(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> { + 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>, ()> { + 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> { + // 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::() + && 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::() + && 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 `::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> 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 +863,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 { + match adjust.kind { + Adjust::Borrow(_) => Some(BorrowCause::AutoBorrow), + // Custom deref calls `::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 8db9cd593b33..0ae314419135 100644 --- a/clippy_utils/src/ty/mod.rs +++ b/clippy_utils/src/ty/mod.rs @@ -1422,3 +1422,14 @@ pub fn has_non_owning_mutable_access<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<' let mut phantoms = FxHashSet::default(); has_non_owning_mutable_access_inner(cx, &mut phantoms, iter_ty) } + +/// Gets the index of a field by name. +pub fn get_field_idx_by_name(ty: Ty<'_>, name: Symbol) -> Option { + 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::().ok(), + _ => None, + } +} diff --git a/tests/ui/borrow_interior_mutable_const/enums.rs b/tests/ui/borrow_interior_mutable_const/enums.rs index da940a4cfb50..ea47e588858f 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 _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR: interior mutability + let _ = &::TO_BE_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const let _ = &::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 = None; fn function() { - let _ = &::TO_BE_UNFROZEN_VARIANT; //~ ERROR: interior mutability + let _ = &::TO_BE_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const let _ = &::TO_BE_FROZEN_VARIANT; } } @@ -88,14 +88,14 @@ impl BothOfCellAndGeneric { const FROZEN_VARIANT: BothOfCellAndGeneric = 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 43850384b903..7a3cb7d6aa95 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 _ = &::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 _ = &::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 fa729b62d7f5..720f88326d7e 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,)> = 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 decea153f717..6e887406dcdb 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 eabaf66560ad..b0e1883f8bf7 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 = 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 c4878dbe57b2..34a758efa2c8 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 GenericTypes for Vec { 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 AssocTypes for Vec { 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 = 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 { 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 BothOfCellAndGeneric for Vec { 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 cad68ca9260c..233ec6dad670 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 000000000000..e68f1c20a8e7 --- /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 000000000000..e89fa636d4b2 --- /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 000000000000..a2787291d9e1 --- /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 000000000000..5e7608161646 --- /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 232b8e4a7959..000000000000 --- a/tests/ui/crashes/ice-9445.rs +++ /dev/null @@ -1,4 +0,0 @@ -const UNINIT: core::mem::MaybeUninit> = 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 76689cd6f5c2..000000000000 --- 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::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 c87468277fb3..2ca6b7bc303a 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 = Some(Self::ToBeUnfrozen::new(4)); - //~^ declare_interior_mutable_const + const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); //~ declare_interior_mutable_const const TO_BE_FROZEN_VARIANT: Option = None; } @@ -105,30 +99,25 @@ enum BothOfCellAndGeneric { } impl BothOfCellAndGeneric { - const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); - //~^ declare_interior_mutable_const + const UNFROZEN_VARIANT: BothOfCellAndGeneric = 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 = BothOfCellAndGeneric::Generic(std::ptr::null()); - //~^ declare_interior_mutable_const const FROZEN_VARIANT: BothOfCellAndGeneric = 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 = - //~^ declare_interior_mutable_const + const UNFROZEN_VARIANT: BothOfCellAndGeneric = //~ declare_interior_mutable_const BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); - //~^ declare_interior_mutable_const const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); } diff --git a/tests/ui/declare_interior_mutable_const/enums.stderr b/tests/ui/declare_interior_mutable_const/enums.stderr index 32839d14f0ed..25f39f243e01 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 = 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 = 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 = 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 = -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 = BothOfCellAndGeneric::Generic(std::ptr::null()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric = + | ^^^^^^^^^^^^^^^^ -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 7ce04a3f2c34..362f28b8c53b 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 = Cell::new(6); -//~^ declare_interior_mutable_const +const ATOMIC: AtomicUsize = AtomicUsize::new(5); //~ declare_interior_mutable_const +const CELL: Cell = Cell::new(6); //~ declare_interior_mutable_const const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, 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 09299b290416..243c6b0cc5f8 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 = 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, 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 = 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 d3139be6859f..f4916e1b4cf1 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 { impl GenericTypes 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 AssocTypes for Vec { 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 = 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 = Wrapper(AtomicUsize::new(14)); //~ declare_interior_mutable_const const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper = Wrapper(T::DEFAULT); } @@ -90,8 +85,7 @@ where T: AssocTypesHelper, { const NOT_BOUNDED: T::NotToBeBounded; - const BOUNDED: T::ToBeBounded; - //~^ declare_interior_mutable_const + const BOUNDED: T::ToBeBounded; //~ declare_interior_mutable_const } impl AssocTypesFromGenericParam 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 = Some(AtomicUsize::new(21)); - //~^ declare_interior_mutable_const + const WRAPPED_SELF: Option = 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 { - const DIRECT: Cell; - //~^ declare_interior_mutable_const - const INDIRECT: Cell<*const T>; - //~^ declare_interior_mutable_const + const DIRECT: Cell; //~ declare_interior_mutable_const + const INDIRECT: Cell<*const T>; //~ declare_interior_mutable_const } impl BothOfCellAndGeneric for u64 { const DIRECT: Cell = Cell::new(T::DEFAULT); - //~^ declare_interior_mutable_const const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null()); } @@ -148,15 +137,13 @@ impl Local where T: ConstDefault + AssocTypesHelper, { - 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 b03dd7a08403..9b9d9ddeef93 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 = 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 = 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; - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^ 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 = 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 From e809fd4bd73e8cf6ce5c483786d89fa41b7ee9fd Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Tue, 6 Aug 2024 21:02:36 -0400 Subject: [PATCH 2/3] Reword `declare_interior_mutable_const` and `borrow_interior_mutable_const` messages to be less assertive. Update documentation for both lints. --- clippy_lints/src/non_copy_const.rs | 112 +++++++++++------- .../enums.stderr | 24 ++-- .../others.stderr | 60 +++++----- .../projections.stderr | 16 +-- .../traits.stderr | 68 +++++------ .../enums.stderr | 26 ++-- .../others.stderr | 20 ++-- .../traits.stderr | 20 ++-- 8 files changed, 188 insertions(+), 158 deletions(-) diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 8df2db859f67..38be99294bea 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -42,35 +42,36 @@ use std::collections::hash_map::Entry; declare_clippy_lint! { /// ### What it does - /// Checks for declaration of `const` items which is interior - /// mutable (e.g., contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.). + /// Checks for the declaration of named constant which contain interior mutability. /// /// ### Why is this bad? - /// Consts are copied everywhere they are referenced, i.e., - /// every time you refer to the const a fresh instance of the `Cell` or `Mutex` - /// or `AtomicXxxx` will be created, which defeats the whole purpose of using - /// these types in the first place. + /// Named constants are copied at every use site which means any change to their value + /// will be lost after the newly created value is dropped. e.g. /// - /// The `const` should better be replaced by a `static` item if a global - /// variable is wanted, or replaced by a `const fn` if a constructor is wanted. + /// ```rust + /// use core::sync::atomic::{AtomicUsize, Ordering}; + /// const ATOMIC: AtomicUsize = AtomicUsize::new(0); + /// fn add_one() -> usize { + /// // This will always return `0` since `ATOMIC` is copied before it's used. + /// ATOMIC.fetch_add(1, Ordering::AcqRel) + /// } + /// ``` /// - /// ### Known problems - /// A "non-constant" const item is a legacy way to supply an - /// initialized value to downstream `static` items (e.g., the - /// `std::sync::ONCE_INIT` constant). In this case the use of `const` is legit, - /// and this lint should be suppressed. + /// If shared modification of the value is desired, a `static` item is needed instead. + /// If that is not desired, a `const fn` constructor should be used to make it obvious + /// at the use site that a new value is created. /// - /// Even though the lint avoids triggering on a constant whose type has enums that have variants - /// with interior mutability, and its value uses non interior mutable variants (see - /// [#3962](https://github.com/rust-lang/rust-clippy/issues/3962) and - /// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825) for examples); - /// it complains about associated constants without default values only based on its types; - /// which might not be preferable. - /// There're other enums plus associated constants cases that the lint cannot handle. + /// ### Known problems + /// Prior to `const fn` stabilization this was the only way to provide a value which + /// could initialize a `static` item (e.g. the `std::sync::ONCE_INIT` constant). In + /// this case the use of `const` is required and this lint should be suppressed. /// - /// Types that have underlying or potential interior mutability trigger the lint whether - /// the interior mutable field is used or not. See issue - /// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) + /// There also exists types which contain private fields with interior mutability, but + /// no way to both create a value as a constant and modify any mutable field using the + /// type's public interface (e.g. `bytes::Bytes`). As there is no reasonable way to + /// scan a crate's interface to see if this is the case, all such types will be linted. + /// If this happens use the `ignore-interior-mutability` configuration option to allow + /// the type. /// /// ### Example /// ```no_run @@ -96,16 +97,42 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks if `const` items which is interior mutable (e.g., - /// contains a `Cell`, `Mutex`, `AtomicXxxx`, etc.) has been borrowed directly. + /// Checks for a borrow of a named constant with interior mutability. /// /// ### Why is this bad? - /// Consts are copied everywhere they are referenced, i.e., - /// every time you refer to the const a fresh instance of the `Cell` or `Mutex` - /// or `AtomicXxxx` will be created, which defeats the whole purpose of using - /// these types in the first place. + /// Named constants are copied at every use site which means any change to their value + /// will be lost after the newly created value is dropped. e.g. + /// + /// ```rust + /// use core::sync::atomic::{AtomicUsize, Ordering}; + /// const ATOMIC: AtomicUsize = AtomicUsize::new(0); + /// fn add_one() -> usize { + /// // This will always return `0` since `ATOMIC` is copied before it's borrowed + /// // for use by `fetch_add`. + /// ATOMIC.fetch_add(1, Ordering::AcqRel) + /// } + /// ``` /// - /// The `const` value should be stored inside a `static` item. + /// ### Known problems + /// This lint does not, and cannot in general, determine if the borrow of the constant + /// is used in a way which causes a mutation. e.g. + /// + /// ```rust + /// use core::cell::Cell; + /// const CELL: Cell = Cell::new(0); + /// fn get_cell() -> Cell { + /// // This is fine. It borrows a copy of `CELL`, but never mutates it through the + /// // borrow. + /// CELL.clone() + /// } + /// ``` + /// + /// There also exists types which contain private fields with interior mutability, but + /// no way to both create a value as a constant and modify any mutable field using the + /// type's public interface (e.g. `bytes::Bytes`). As there is no reasonable way to + /// scan a crate's interface to see if this is the case, all such types will be linted. + /// If this happens use the `ignore-interior-mutability` configuration option to allow + /// the type. /// /// ### Example /// ```no_run @@ -179,6 +206,7 @@ enum BorrowCause { Index, AutoDeref, AutoBorrow, + AutoDerefField, } impl BorrowCause { fn note(self) -> Option<&'static str> { @@ -188,6 +216,9 @@ impl BorrowCause { 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"), + Self::AutoDerefField => { + Some("there is a compiler inserted call to `Deref::deref` when accessing this field") + }, } } } @@ -207,6 +238,7 @@ impl<'tcx> BorrowSource<'tcx> { match parent.kind { ExprKind::Unary(UnOp::Deref, _) => (parent, BorrowCause::Deref), ExprKind::Index(..) => (parent, BorrowCause::Index), + ExprKind::Field(..) => (parent, BorrowCause::AutoDerefField), _ => (expr, cause), } } else { @@ -690,17 +722,15 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { cx, DECLARE_INTERIOR_MUTABLE_CONST, ident.span, - "a `const` item should not be interior mutable", + "named constant with interior mutability", |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"); + diag.help("did you mean to make 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`", - ); + diag.help("did you mean to make this a `thread_local!` item"); } }, ); @@ -734,7 +764,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { cx, DECLARE_INTERIOR_MUTABLE_CONST, item.ident.span, - "a `const` item should not be interior mutable", + "named constant with interior mutability", ); } } @@ -786,7 +816,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { cx, DECLARE_INTERIOR_MUTABLE_CONST, item.ident.span, - "a `const` item should not be interior mutable", + "named constant with interior mutability", ); } } @@ -821,12 +851,12 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> { cx, BORROW_INTERIOR_MUTABLE_CONST, borrow_src.expr.span, - "a `const` item with interior mutability should not be borrowed", + "borrow of a named constant with interior mutability", |diag| { - if let Some(msg) = borrow_src.cause.note() { - diag.note(msg); + if let Some(note) = borrow_src.cause.note() { + diag.note(note); } - diag.help("assign this const to a local or static variable, and use the variable here"); + diag.help("this lint can be silenced by assigning the value to a local variable before borrowing"); }, ); } diff --git a/tests/ui/borrow_interior_mutable_const/enums.stderr b/tests/ui/borrow_interior_mutable_const/enums.stderr index 7a3cb7d6aa95..80c2deb4b3a5 100644 --- a/tests/ui/borrow_interior_mutable_const/enums.stderr +++ b/tests/ui/borrow_interior_mutable_const/enums.stderr @@ -1,55 +1,55 @@ -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing note: the lint level is defined here --> tests/ui/borrow_interior_mutable_const/enums.rs:3:9 | LL | #![deny(clippy::borrow_interior_mutable_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/enums.rs:50:17 | LL | let _ = &::TO_BE_UNFROZEN_VARIANT; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/enums.rs:74:17 | LL | let _ = &::TO_BE_UNFROZEN_VARIANT; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing error: aborting due to 6 previous errors diff --git a/tests/ui/borrow_interior_mutable_const/others.stderr b/tests/ui/borrow_interior_mutable_const/others.stderr index 6e887406dcdb..67b9907f8e38 100644 --- a/tests/ui/borrow_interior_mutable_const/others.stderr +++ b/tests/ui/borrow_interior_mutable_const/others.stderr @@ -1,132 +1,132 @@ -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/others.rs:65:5 | 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing note: the lint level is defined here --> tests/ui/borrow_interior_mutable_const/others.rs:1:9 | LL | #![deny(clippy::borrow_interior_mutable_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/others.rs:89:17 | LL | let _ = (&&&&ATOMIC_TUPLE).0; | ^^^^^^^^^^^^^ | - = help: assign this const to a local or static variable, and use the variable here + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing 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 b0e1883f8bf7..114fd66651af 100644 --- a/tests/ui/borrow_interior_mutable_const/projections.stderr +++ b/tests/ui/borrow_interior_mutable_const/projections.stderr @@ -1,44 +1,44 @@ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/borrow_interior_mutable_const/projections.rs:27:7 | LL | const CELL: Assoc = UnsafeCell::new(0); | ^^^^ | - = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` + = help: did you mean to make this a `thread_local!` item note: the lint level is defined here --> tests/ui/borrow_interior_mutable_const/projections.rs:2:9 | LL | #![deny(clippy::declare_interior_mutable_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> 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` + = help: did you mean to make this a `thread_local!` item -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing note: the lint level is defined here --> tests/ui/borrow_interior_mutable_const/projections.rs:1:9 | LL | #![deny(clippy::borrow_interior_mutable_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing error: aborting due to 4 previous errors diff --git a/tests/ui/borrow_interior_mutable_const/traits.stderr b/tests/ui/borrow_interior_mutable_const/traits.stderr index 233ec6dad670..1d84ebf2ac94 100644 --- a/tests/ui/borrow_interior_mutable_const/traits.stderr +++ b/tests/ui/borrow_interior_mutable_const/traits.stderr @@ -1,145 +1,145 @@ -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing note: the lint level is defined here --> tests/ui/borrow_interior_mutable_const/traits.rs:1:9 | LL | #![deny(clippy::borrow_interior_mutable_const)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing -error: a `const` item with interior mutability should not be borrowed +error: borrow of a named constant with interior mutability --> 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 + = help: this lint can be silenced by assigning the value to a local variable before borrowing error: aborting due to 17 previous errors diff --git a/tests/ui/declare_interior_mutable_const/enums.stderr b/tests/ui/declare_interior_mutable_const/enums.stderr index 25f39f243e01..4eca533e5ada 100644 --- a/tests/ui/declare_interior_mutable_const/enums.stderr +++ b/tests/ui/declare_interior_mutable_const/enums.stderr @@ -1,66 +1,66 @@ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> 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` + = help: did you mean to make this a `thread_local!` 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 +error: named constant with interior mutability --> 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` + = help: did you mean to make this a `thread_local!` item -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/enums.rs:45:7 | LL | const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { | ^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider making this a static item + = help: did you mean to make this a `static` item -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/enums.rs:64:11 | LL | const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/enums.rs:71:11 | LL | const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); | ^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/enums.rs:75:11 | LL | const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/enums.rs:90:11 | LL | const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); | ^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/enums.rs:102:11 | LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); | ^^^^^^^^^^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> 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 +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/enums.rs:118:11 | LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric = diff --git a/tests/ui/declare_interior_mutable_const/others.stderr b/tests/ui/declare_interior_mutable_const/others.stderr index 243c6b0cc5f8..67fb4d046a6b 100644 --- a/tests/ui/declare_interior_mutable_const/others.stderr +++ b/tests/ui/declare_interior_mutable_const/others.stderr @@ -1,38 +1,38 @@ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/others.rs:10:7 | LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); | ^^^^^^ | - = help: consider making this a static item + = help: did you mean to make 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 +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/others.rs:11:7 | LL | const CELL: Cell = Cell::new(6); | ^^^^ | - = help: consider making this `Sync` so that it can go in a static item or using a `thread_local` + = help: did you mean to make this a `thread_local!` item -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/others.rs:12:7 | LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); | ^^^^^^^^^^^^ | - = help: consider making this a static item + = help: did you mean to make this a `static` item -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/others.rs:20:16 | LL | declare_const!(_ONCE: Once = Once::new()); | ^^^^^ | - = help: consider making this a static item + = help: did you mean to make this a `static` item -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/others.rs:44:19 | LL | const _BAZ: Cell = Cell::new(0); @@ -41,7 +41,7 @@ LL | const _BAZ: Cell = 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` + = help: did you mean to make this a `thread_local!` item = 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.stderr b/tests/ui/declare_interior_mutable_const/traits.stderr index 9b9d9ddeef93..a5c08871ba77 100644 --- a/tests/ui/declare_interior_mutable_const/traits.stderr +++ b/tests/ui/declare_interior_mutable_const/traits.stderr @@ -1,4 +1,4 @@ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/traits.rs:15:11 | LL | const ATOMIC: AtomicUsize; @@ -7,55 +7,55 @@ 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 +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/traits.rs:18:20 | LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); | ^^^^^^^^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> 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 +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/traits.rs:69:11 | LL | const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); | ^^^^^^^^^^^^^^^^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/traits.rs:88:11 | LL | const BOUNDED: T::ToBeBounded; | ^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/traits.rs:117:11 | LL | const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); | ^^^^^^^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/traits.rs:123:11 | LL | const DIRECT: Cell; | ^^^^^^ -error: a `const` item should not be interior mutable +error: named constant with interior mutability --> 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 +error: named constant with interior mutability --> 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 +error: named constant with interior mutability --> tests/ui/declare_interior_mutable_const/traits.rs:146:11 | LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); From b896272bd3ea8ef4709bbc4bb54a85704cc06730 Mon Sep 17 00:00:00 2001 From: Jason Newcomb Date: Sat, 3 Aug 2024 14:53:02 -0400 Subject: [PATCH 3/3] Rewrite tests for `declare_interior_mutable_const` and `borrow_interior_mutable_const` to be more thorough on weird constructs --- .../interior_mutable_const.rs} | 0 tests/ui/borrow_interior_mutable_const.rs | 221 ++++++++++++++++ tests/ui/borrow_interior_mutable_const.stderr | 247 ++++++++++++++++++ .../ui/borrow_interior_mutable_const/enums.rs | 101 ------- .../enums.stderr | 55 ---- .../borrow_interior_mutable_const/others.rs | 114 -------- .../others.stderr | 132 ---------- .../projections.rs | 42 --- .../projections.stderr | 44 ---- .../borrow_interior_mutable_const/traits.rs | 202 -------------- .../traits.stderr | 145 ---------- tests/ui/declare_interior_mutable_const.rs | 200 ++++++++++++++ .../ui/declare_interior_mutable_const.stderr | 197 ++++++++++++++ .../declare_interior_mutable_const/enums.rs | 124 --------- .../enums.stderr | 70 ----- .../declare_interior_mutable_const/others.rs | 73 ------ .../others.stderr | 48 ---- .../declare_interior_mutable_const/traits.rs | 149 ----------- .../traits.stderr | 65 ----- 19 files changed, 865 insertions(+), 1364 deletions(-) rename tests/ui/{borrow_interior_mutable_const/auxiliary/helper.rs => auxiliary/interior_mutable_const.rs} (100%) create mode 100644 tests/ui/borrow_interior_mutable_const.rs create mode 100644 tests/ui/borrow_interior_mutable_const.stderr delete mode 100644 tests/ui/borrow_interior_mutable_const/enums.rs delete mode 100644 tests/ui/borrow_interior_mutable_const/enums.stderr delete mode 100644 tests/ui/borrow_interior_mutable_const/others.rs delete mode 100644 tests/ui/borrow_interior_mutable_const/others.stderr delete mode 100644 tests/ui/borrow_interior_mutable_const/projections.rs delete mode 100644 tests/ui/borrow_interior_mutable_const/projections.stderr delete mode 100644 tests/ui/borrow_interior_mutable_const/traits.rs delete mode 100644 tests/ui/borrow_interior_mutable_const/traits.stderr create mode 100644 tests/ui/declare_interior_mutable_const.rs create mode 100644 tests/ui/declare_interior_mutable_const.stderr delete mode 100644 tests/ui/declare_interior_mutable_const/enums.rs delete mode 100644 tests/ui/declare_interior_mutable_const/enums.stderr delete mode 100644 tests/ui/declare_interior_mutable_const/others.rs delete mode 100644 tests/ui/declare_interior_mutable_const/others.stderr delete mode 100644 tests/ui/declare_interior_mutable_const/traits.rs delete mode 100644 tests/ui/declare_interior_mutable_const/traits.stderr diff --git a/tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs b/tests/ui/auxiliary/interior_mutable_const.rs similarity index 100% rename from tests/ui/borrow_interior_mutable_const/auxiliary/helper.rs rename to tests/ui/auxiliary/interior_mutable_const.rs diff --git a/tests/ui/borrow_interior_mutable_const.rs b/tests/ui/borrow_interior_mutable_const.rs new file mode 100644 index 000000000000..0f439f789150 --- /dev/null +++ b/tests/ui/borrow_interior_mutable_const.rs @@ -0,0 +1,221 @@ +//@aux-build:interior_mutable_const.rs + +#![deny(clippy::borrow_interior_mutable_const)] +#![allow( + clippy::declare_interior_mutable_const, + clippy::out_of_bounds_indexing, + const_item_mutation, + unconditional_panic +)] + +use core::cell::{Cell, UnsafeCell}; +use core::ops::{Deref, Index}; + +trait ConstDefault { + const DEFAULT: Self; +} +impl ConstDefault for u32 { + const DEFAULT: Self = 0; +} +impl ConstDefault for Cell { + const DEFAULT: Self = Cell::new(T::DEFAULT); +} + +fn main() { + { + const C: String = String::new(); + let _ = C; + let _ = &C; + let _ = C.len(); + let _ = &*C; + } + { + const C: UnsafeCell = UnsafeCell::new(0); + let _ = C; + let _ = &C; //~ borrow_interior_mutable_const + let _ = C.into_inner(); + let _ = C.get(); //~ borrow_interior_mutable_const + } + { + const C: Cell = Cell::new(0); + let _ = C; + let _ = &C; //~ borrow_interior_mutable_const + let _ = &mut C; //~ borrow_interior_mutable_const + let _ = C.into_inner(); + + let local = C; + C.swap(&local) //~ borrow_interior_mutable_const + } + { + const C: [(Cell,); 1] = [(Cell::new(0),)]; + let _ = C; + let _ = &C; //~ borrow_interior_mutable_const + let _ = &C[0]; //~ borrow_interior_mutable_const + let _ = &C[0].0; //~ borrow_interior_mutable_const + C[0].0.set(1); //~ borrow_interior_mutable_const + } + { + struct S(Cell); + impl S { + const C: Self = Self(Cell::new(0)); + } + impl Deref for S { + type Target = Cell; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + let _ = S::C; + let _ = S::C.0; + let _ = &S::C; //~ borrow_interior_mutable_const + let _ = &S::C.0; //~ borrow_interior_mutable_const + S::C.set(1); //~ borrow_interior_mutable_const + let _ = &*S::C; //~ borrow_interior_mutable_const + (*S::C).set(1); //~ borrow_interior_mutable_const + } + { + enum E { + Cell(Cell), + Other, + } + const CELL: E = E::Cell(Cell::new(0)); + const OTHER: E = E::Other; + + let _ = CELL; + let _ = &CELL; //~ borrow_interior_mutable_const + let E::Cell(_) = CELL else { + return; + }; + + let _ = OTHER; + let _ = &OTHER; + let E::Cell(ref _x) = OTHER else { + return; + }; + } + { + struct S { + cell: (Cell, u32), + other: Option, + } + impl S { + const C: Self = Self { + cell: (Cell::::DEFAULT, 0), + other: Some(T::DEFAULT), + }; + + fn f() { + let _ = Self::C; + let _ = &Self::C; //~ borrow_interior_mutable_const + let _ = Self::C.other; + let _ = &Self::C.other; + let _ = &Self::C.cell; //~ borrow_interior_mutable_const + let _ = &Self::C.cell.0; //~ borrow_interior_mutable_const + Self::C.cell.0.set(T::DEFAULT); //~ borrow_interior_mutable_const + let _ = &Self::C.cell.1; + } + } + } + { + trait T { + const VALUE: Option> = Some(Cell::new(0)); + } + impl T for u32 {} + impl T for i32 { + const VALUE: Option> = None; + } + + let _ = &u32::VALUE; //~ borrow_interior_mutable_const + let _ = &i32::VALUE; + } + { + trait Trait { + type T: ConstDefault; + const VALUE: Option> = Some(Self::T::::DEFAULT); + } + impl Trait for u32 { + type T = Cell; + } + impl Trait for i32 { + type T = Cell; + const VALUE: Option> = None; + } + + fn f() { + let _ = &>::VALUE; //~ borrow_interior_mutable_const + let _ = &>::VALUE; + } + } + { + trait Trait { + const UNFROZEN: Option> = Some(Cell::new(0)); + const FROZEN: Option> = None; + const NON_FREEZE: u32 = 0; + } + fn f() { + // None of these are guaranteed to be frozen, so don't lint. + let _ = &T::UNFROZEN; + let _ = &T::FROZEN; + let _ = &T::NON_FREEZE; + } + } + { + struct S([Option>; 2]); + impl Index for S { + type Output = Option>; + fn index(&self, idx: usize) -> &Self::Output { + &self.0[idx] + } + } + + const C: S = S([Some(Cell::new(0)), None]); + let _ = &C; //~ borrow_interior_mutable_const + let _ = &C[0]; //~ borrow_interior_mutable_const + let _ = &C.0[0]; //~ borrow_interior_mutable_const + let _ = &C.0[1]; + } + { + const C: [Option>; 2] = [None, None]; + let _ = &C[0]; + let _ = &C[1]; + let _ = &C[2]; + + fn f(i: usize) { + let _ = &C[i]; + } + } + { + const C: [Option>; 2] = [None, Some(Cell::new(0))]; + let _ = &C[0]; + let _ = &C[1]; //~ borrow_interior_mutable_const + let _ = &C[2]; + + fn f(i: usize) { + let _ = &C[i]; //~ borrow_interior_mutable_const + } + } + { + let _ = &interior_mutable_const::WRAPPED_PRIVATE_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const + let _ = &interior_mutable_const::WRAPPED_PRIVATE_FROZEN_VARIANT; + } + { + type Cell2 = Cell; + type MyCell = Cell2; + struct S(Option); + trait T { + type Assoc; + } + struct S2(T, T, u32); + impl T for S { + type Assoc = S2; + } + type Assoc = ::Assoc; + impl S { + const VALUE: Assoc = S2(Self(None), Self(Some(Cell::new(0))), 0); + } + let _ = &S::VALUE; //~ borrow_interior_mutable_const + let _ = &S::VALUE.0; + let _ = &S::VALUE.1; //~ borrow_interior_mutable_const + let _ = &S::VALUE.2; + } +} diff --git a/tests/ui/borrow_interior_mutable_const.stderr b/tests/ui/borrow_interior_mutable_const.stderr new file mode 100644 index 000000000000..e7c3f879b05b --- /dev/null +++ b/tests/ui/borrow_interior_mutable_const.stderr @@ -0,0 +1,247 @@ +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:35:17 + | +LL | let _ = &C; + | ^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing +note: the lint level is defined here + --> tests/ui/borrow_interior_mutable_const.rs:3:9 + | +LL | #![deny(clippy::borrow_interior_mutable_const)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:37:17 + | +LL | let _ = C.get(); + | ^ + | + = note: there is a compiler inserted borrow here + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:42:17 + | +LL | let _ = &C; + | ^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:43:17 + | +LL | let _ = &mut C; + | ^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:47:9 + | +LL | C.swap(&local) + | ^ + | + = note: there is a compiler inserted borrow here + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:52:17 + | +LL | let _ = &C; + | ^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:53:17 + | +LL | let _ = &C[0]; + | ^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:54:17 + | +LL | let _ = &C[0].0; + | ^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:55:9 + | +LL | C[0].0.set(1); + | ^^^^^^ + | + = note: there is a compiler inserted borrow here + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:70:17 + | +LL | let _ = &S::C; + | ^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:71:17 + | +LL | let _ = &S::C.0; + | ^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:72:9 + | +LL | S::C.set(1); + | ^^^^ + | + = note: there is a compiler inserted call to `Deref::deref` here + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:73:18 + | +LL | let _ = &*S::C; + | ^^^^^ + | + = note: this deref expression is a call to `Deref::deref` + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:74:9 + | +LL | (*S::C).set(1); + | ^^^^^^^ + | + = note: this deref expression is a call to `Deref::deref` + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:85:17 + | +LL | let _ = &CELL; + | ^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:109:25 + | +LL | let _ = &Self::C; + | ^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:112:25 + | +LL | let _ = &Self::C.cell; + | ^^^^^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:113:25 + | +LL | let _ = &Self::C.cell.0; + | ^^^^^^^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:114:17 + | +LL | Self::C.cell.0.set(T::DEFAULT); + | ^^^^^^^^^^^^^^ + | + = note: there is a compiler inserted borrow here + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:128:17 + | +LL | let _ = &u32::VALUE; + | ^^^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:145:21 + | +LL | let _ = &>::VALUE; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:172:17 + | +LL | let _ = &C; + | ^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:173:18 + | +LL | let _ = &C[0]; + | ^^^^ + | + = note: this index expression is a call to `Index::index` + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:174:17 + | +LL | let _ = &C.0[0]; + | ^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:190:17 + | +LL | let _ = &C[1]; + | ^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:194:21 + | +LL | let _ = &C[i]; + | ^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:198:17 + | +LL | let _ = &interior_mutable_const::WRAPPED_PRIVATE_UNFROZEN_VARIANT; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:216:17 + | +LL | let _ = &S::VALUE; + | ^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: borrow of a named constant with interior mutability + --> tests/ui/borrow_interior_mutable_const.rs:218:17 + | +LL | let _ = &S::VALUE.1; + | ^^^^^^^^^^^ + | + = help: this lint can be silenced by assigning the value to a local variable before borrowing + +error: aborting due to 29 previous errors + diff --git a/tests/ui/borrow_interior_mutable_const/enums.rs b/tests/ui/borrow_interior_mutable_const/enums.rs deleted file mode 100644 index ea47e588858f..000000000000 --- a/tests/ui/borrow_interior_mutable_const/enums.rs +++ /dev/null @@ -1,101 +0,0 @@ -//@aux-build:helper.rs - -#![deny(clippy::borrow_interior_mutable_const)] -#![allow(clippy::declare_interior_mutable_const)] - -// this file (mostly) replicates its `declare` counterpart. Please see it for more discussions. - -extern crate helper; - -use std::cell::Cell; -use std::sync::atomic::AtomicUsize; - -enum OptionalCell { - Unfrozen(Cell), - Frozen, -} - -const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); -const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; - -fn borrow_optional_cell() { - let _ = &UNFROZEN_VARIANT; //~ borrow_interior_mutable_const - let _ = &FROZEN_VARIANT; -} - -trait AssocConsts { - const TO_BE_UNFROZEN_VARIANT: OptionalCell; - const TO_BE_FROZEN_VARIANT: OptionalCell; - - const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); - const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; - - fn function() { - // 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; - - // 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; - } -} - -impl AssocConsts for u64 { - const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); - const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; - - fn function() { - let _ = &::TO_BE_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const - let _ = &::TO_BE_FROZEN_VARIANT; - let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const - let _ = &Self::DEFAULTED_ON_FROZEN_VARIANT; - } -} - -trait AssocTypes { - type ToBeUnfrozen; - - const TO_BE_UNFROZEN_VARIANT: Option; - const TO_BE_FROZEN_VARIANT: Option; - - // there's no need to test here because it's the exactly same as `trait::AssocTypes` - fn function(); -} - -impl AssocTypes for u64 { - type ToBeUnfrozen = AtomicUsize; - - const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); - const TO_BE_FROZEN_VARIANT: Option = None; - - fn function() { - let _ = &::TO_BE_UNFROZEN_VARIANT; //~ borrow_interior_mutable_const - let _ = &::TO_BE_FROZEN_VARIANT; - } -} - -enum BothOfCellAndGeneric { - Unfrozen(Cell<*const T>), - Generic(*const T), - Frozen(usize), -} - -impl BothOfCellAndGeneric { - const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); - const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); - const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); - - fn function() { - 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; //~ 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 deleted file mode 100644 index 80c2deb4b3a5..000000000000 --- a/tests/ui/borrow_interior_mutable_const/enums.stderr +++ /dev/null @@ -1,55 +0,0 @@ -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/enums.rs:22:13 - | -LL | let _ = &UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing -note: the lint level is defined here - --> tests/ui/borrow_interior_mutable_const/enums.rs:3:9 - | -LL | #![deny(clippy::borrow_interior_mutable_const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/enums.rs:50:17 - | -LL | let _ = &::TO_BE_UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/enums.rs:52:17 - | -LL | let _ = &Self::DEFAULTED_ON_UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/enums.rs:74:17 - | -LL | let _ = &::TO_BE_UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/enums.rs:91:17 - | -LL | let _ = &Self::UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/enums.rs:99:13 - | -LL | let _ = &helper::WRAPPED_PRIVATE_UNFROZEN_VARIANT; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -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 deleted file mode 100644 index 720f88326d7e..000000000000 --- a/tests/ui/borrow_interior_mutable_const/others.rs +++ /dev/null @@ -1,114 +0,0 @@ -#![deny(clippy::borrow_interior_mutable_const)] -#![allow(clippy::declare_interior_mutable_const, clippy::needless_borrow)] -#![allow(const_item_mutation)] - -use std::borrow::Cow; -use std::cell::{Cell, UnsafeCell}; -use std::fmt::Display; -use std::sync::Once; -use std::sync::atomic::{AtomicUsize, Ordering}; - -const ATOMIC: AtomicUsize = AtomicUsize::new(5); -const CELL: Cell = Cell::new(6); -const ATOMIC_TUPLE: ([AtomicUsize; 1], Option>, u8) = ([ATOMIC], None, 7); -const INTEGER: u8 = 8; -const STRING: String = String::new(); -const STR: &str = "012345"; -const COW: Cow = Cow::Borrowed("abcdef"); -const NO_ANN: &dyn Display = &70; -static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); -const ONCE_INIT: Once = Once::new(); - -// This is just a pointer that can be safely dereferenced, -// it's semantically the same as `&'static T`; -// but it isn't allowed to make a static reference from an arbitrary integer value at the moment. -// For more information, please see the issue #5918. -pub struct StaticRef { - ptr: *const T, -} - -impl StaticRef { - /// Create a new `StaticRef` from a raw pointer - /// - /// ## Safety - /// - /// Callers must pass in a reference to statically allocated memory which - /// does not overlap with other values. - pub const unsafe fn new(ptr: *const T) -> StaticRef { - StaticRef { ptr } - } -} - -impl std::ops::Deref for StaticRef { - type Target = T; - - fn deref(&self) -> &T { - unsafe { &*self.ptr } - } -} - -// ICE regression test -mod issue12979 { - use std::cell::UnsafeCell; - - const ATOMIC_TUPLE: (Vec>, ()) = (Vec::new(), ()); - - fn main() { - let _x = &ATOMIC_TUPLE.0; - } -} - -// use a tuple to make sure referencing a field behind a pointer isn't linted. -const CELL_REF: StaticRef<(UnsafeCell,)> = 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 - - 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 _atomic_into_inner = ATOMIC.into_inner(); - // these should be all fine. - let _twice = (ONCE_INIT, ONCE_INIT); - let _ref_twice = &(ONCE_INIT, ONCE_INIT); - let _ref_once = &(ONCE_INIT, ONCE_INIT).0; - let _array_twice = [ONCE_INIT, ONCE_INIT]; - let _ref_array_twice = &[ONCE_INIT, ONCE_INIT]; - 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.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]; - 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 - - assert_eq!(INTEGER, 8); - assert!(STRING.is_empty()); - - let a = ATOMIC; - a.store(4, Ordering::SeqCst); - assert_eq!(a.load(Ordering::SeqCst), 4); - - STATIC_TUPLE.0.store(3, Ordering::SeqCst); - assert_eq!(STATIC_TUPLE.0.load(Ordering::SeqCst), 3); - assert!(STATIC_TUPLE.1.is_empty()); - - assert_eq!(NO_ANN.to_string(), "70"); // should never lint this. - - let _ = &CELL_REF.0; -} diff --git a/tests/ui/borrow_interior_mutable_const/others.stderr b/tests/ui/borrow_interior_mutable_const/others.stderr deleted file mode 100644 index 67b9907f8e38..000000000000 --- a/tests/ui/borrow_interior_mutable_const/others.stderr +++ /dev/null @@ -1,132 +0,0 @@ -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:65:5 - | -LL | ATOMIC.store(1, Ordering::SeqCst); - | ^^^^^^ - | - = note: there is a compiler inserted borrow here - = help: this lint can be silenced by assigning the value to a local variable before borrowing -note: the lint level is defined here - --> tests/ui/borrow_interior_mutable_const/others.rs:1:9 - | -LL | #![deny(clippy::borrow_interior_mutable_const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: borrow of a named constant with interior mutability - --> 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: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:69:21 - | -LL | let _once_ref = &ONCE_INIT; - | ^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:70:24 - | -LL | let _once_ref_2 = &&ONCE_INIT; - | ^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:71:26 - | -LL | let _once_ref_4 = &&&&ONCE_INIT; - | ^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:72:21 - | -LL | let _once_mut = &mut ONCE_INIT; - | ^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:83:13 - | -LL | let _ = &ATOMIC_TUPLE; - | ^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:84:13 - | -LL | let _ = &ATOMIC_TUPLE.0; - | ^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:85:18 - | -LL | let _ = &(&&&&ATOMIC_TUPLE).0; - | ^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:86:13 - | -LL | let _ = &ATOMIC_TUPLE.0[0]; - | ^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> 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: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:89:17 - | -LL | let _ = (&&&&ATOMIC_TUPLE).0; - | ^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:90:17 - | -LL | let _ = (&&&&ATOMIC_TUPLE).2; - | ^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/others.rs:97:5 - | -LL | CELL.set(2); - | ^^^^ - | - = note: there is a compiler inserted borrow here - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> 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: this lint can be silenced by assigning the value to a local variable before borrowing - -error: aborting due to 15 previous errors - diff --git a/tests/ui/borrow_interior_mutable_const/projections.rs b/tests/ui/borrow_interior_mutable_const/projections.rs deleted file mode 100644 index bbe5538fbe12..000000000000 --- a/tests/ui/borrow_interior_mutable_const/projections.rs +++ /dev/null @@ -1,42 +0,0 @@ -#![deny(clippy::borrow_interior_mutable_const)] -#![deny(clippy::declare_interior_mutable_const)] - -// Inspired by https://github.com/rust-lang/rust/pull/130543#issuecomment-2364828139 - -use std::cell::UnsafeCell; - -trait Trait { - type Assoc; -} - -type Assoc = ::Assoc; - -impl Trait for u8 { - type Assoc = UnsafeCell; -} - -impl Trait for () { - type Assoc = (); -} - -enum MaybeMutable { - Mutable(Assoc), - Immutable(Assoc<()>), -} - -const CELL: Assoc = UnsafeCell::new(0); //~ ERROR: interior mutable -const UNIT: Assoc<()> = (); -const MUTABLE: MaybeMutable = MaybeMutable::Mutable(CELL); //~ ERROR: interior mutable -const IMMUTABLE: MaybeMutable = MaybeMutable::Immutable(UNIT); - -fn print_ref(t: &T) { - let p: *const T = t; - println!("{p:p}") -} - -fn main() { - print_ref(&CELL); //~ ERROR: interior mutability - print_ref(&UNIT); - print_ref(&MUTABLE); //~ ERROR: interior mutability - print_ref(&IMMUTABLE); -} diff --git a/tests/ui/borrow_interior_mutable_const/projections.stderr b/tests/ui/borrow_interior_mutable_const/projections.stderr deleted file mode 100644 index 114fd66651af..000000000000 --- a/tests/ui/borrow_interior_mutable_const/projections.stderr +++ /dev/null @@ -1,44 +0,0 @@ -error: named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/projections.rs:27:7 - | -LL | const CELL: Assoc = UnsafeCell::new(0); - | ^^^^ - | - = help: did you mean to make this a `thread_local!` item -note: the lint level is defined here - --> tests/ui/borrow_interior_mutable_const/projections.rs:2:9 - | -LL | #![deny(clippy::declare_interior_mutable_const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/projections.rs:29:7 - | -LL | const MUTABLE: MaybeMutable = MaybeMutable::Mutable(CELL); - | ^^^^^^^ - | - = help: did you mean to make this a `thread_local!` item - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/projections.rs:38:15 - | -LL | print_ref(&CELL); - | ^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing -note: the lint level is defined here - --> tests/ui/borrow_interior_mutable_const/projections.rs:1:9 - | -LL | #![deny(clippy::borrow_interior_mutable_const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/projections.rs:40:15 - | -LL | print_ref(&MUTABLE); - | ^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: aborting due to 4 previous errors - diff --git a/tests/ui/borrow_interior_mutable_const/traits.rs b/tests/ui/borrow_interior_mutable_const/traits.rs deleted file mode 100644 index 34a758efa2c8..000000000000 --- a/tests/ui/borrow_interior_mutable_const/traits.rs +++ /dev/null @@ -1,202 +0,0 @@ -#![deny(clippy::borrow_interior_mutable_const)] -#![allow(clippy::declare_interior_mutable_const)] - -// this file replicates its `declare` counterpart. Please see it for more discussions. - -use std::borrow::Cow; -use std::cell::Cell; -use std::sync::atomic::{AtomicUsize, Ordering}; - -trait ConcreteTypes { - const ATOMIC: AtomicUsize; - const STRING: String; - - fn function() { - let _ = &Self::ATOMIC; //~ borrow_interior_mutable_const - let _ = &Self::STRING; - } -} - -impl ConcreteTypes for u64 { - const ATOMIC: AtomicUsize = AtomicUsize::new(9); - const STRING: String = String::new(); - - fn function() { - // Lint this again since implementers can choose not to borrow it. - let _ = &Self::ATOMIC; //~ borrow_interior_mutable_const - let _ = &Self::STRING; - } -} - -// a helper trait used below -trait ConstDefault { - const DEFAULT: Self; -} - -trait GenericTypes { - const TO_REMAIN_GENERIC: T; - const TO_BE_CONCRETE: U; - - fn function() { - let _ = &Self::TO_REMAIN_GENERIC; - } -} - -impl GenericTypes for Vec { - const TO_REMAIN_GENERIC: T = T::DEFAULT; - const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); - - fn function() { - let _ = &Self::TO_REMAIN_GENERIC; - let _ = &Self::TO_BE_CONCRETE; //~ borrow_interior_mutable_const - } -} - -// a helper type used below -pub struct Wrapper(T); - -trait AssocTypes { - type ToBeFrozen; - type ToBeUnfrozen; - type ToBeGenericParam; - - const TO_BE_FROZEN: Self::ToBeFrozen; - const TO_BE_UNFROZEN: Self::ToBeUnfrozen; - const WRAPPED_TO_BE_UNFROZEN: Wrapper; - const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper; - - fn function() { - let _ = &Self::TO_BE_FROZEN; - let _ = &Self::WRAPPED_TO_BE_UNFROZEN; - } -} - -impl AssocTypes for Vec { - type ToBeFrozen = u16; - type ToBeUnfrozen = AtomicUsize; - type ToBeGenericParam = T; - - const TO_BE_FROZEN: Self::ToBeFrozen = 12; - const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); - const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); - const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper = Wrapper(T::DEFAULT); - - 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::WRAPPED_TO_BE_GENERIC_PARAM; - } -} - -// a helper trait used below -trait AssocTypesHelper { - type NotToBeBounded; - type ToBeBounded; - - const NOT_TO_BE_BOUNDED: Self::NotToBeBounded; -} - -trait AssocTypesFromGenericParam -where - T: AssocTypesHelper, -{ - const NOT_BOUNDED: T::NotToBeBounded; - const BOUNDED: T::ToBeBounded; - - fn function() { - let _ = &Self::NOT_BOUNDED; - let _ = &Self::BOUNDED; //~ borrow_interior_mutable_const - } -} - -impl AssocTypesFromGenericParam for Vec -where - T: AssocTypesHelper, -{ - const NOT_BOUNDED: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED; - const BOUNDED: T::ToBeBounded = AtomicUsize::new(15); - - fn function() { - let _ = &Self::NOT_BOUNDED; - let _ = &Self::BOUNDED; //~ borrow_interior_mutable_const - } -} - -trait SelfType: Sized { - const SELF: Self; - const WRAPPED_SELF: Option; - - fn function() { - let _ = &Self::SELF; - let _ = &Self::WRAPPED_SELF; - } -} - -impl SelfType for u64 { - const SELF: Self = 16; - const WRAPPED_SELF: Option = Some(20); - - fn function() { - let _ = &Self::SELF; - let _ = &Self::WRAPPED_SELF; - } -} - -impl SelfType for AtomicUsize { - const SELF: Self = AtomicUsize::new(17); - const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); - - fn function() { - let _ = &Self::SELF; //~ borrow_interior_mutable_const - let _ = &Self::WRAPPED_SELF; //~ borrow_interior_mutable_const - } -} - -trait BothOfCellAndGeneric { - const DIRECT: Cell; - const INDIRECT: Cell<*const T>; - - fn function() { - let _ = &Self::DIRECT; //~ borrow_interior_mutable_const - let _ = &Self::INDIRECT; //~ borrow_interior_mutable_const - } -} - -impl BothOfCellAndGeneric for Vec { - const DIRECT: Cell = Cell::new(T::DEFAULT); - 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 - } -} - -struct Local(T); - -impl Local -where - T: ConstDefault + AssocTypesHelper, -{ - const ATOMIC: AtomicUsize = AtomicUsize::new(18); - 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); - - fn function() { - 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 - } -} - -fn main() { - 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 deleted file mode 100644 index 1d84ebf2ac94..000000000000 --- a/tests/ui/borrow_interior_mutable_const/traits.stderr +++ /dev/null @@ -1,145 +0,0 @@ -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:15:17 - | -LL | let _ = &Self::ATOMIC; - | ^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing -note: the lint level is defined here - --> tests/ui/borrow_interior_mutable_const/traits.rs:1:9 - | -LL | #![deny(clippy::borrow_interior_mutable_const)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:26:17 - | -LL | let _ = &Self::ATOMIC; - | ^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:51:17 - | -LL | let _ = &Self::TO_BE_CONCRETE; - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:86:17 - | -LL | let _ = &Self::TO_BE_UNFROZEN; - | ^^^^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:87:17 - | -LL | let _ = &Self::WRAPPED_TO_BE_UNFROZEN; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:109:17 - | -LL | let _ = &Self::BOUNDED; - | ^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:122:17 - | -LL | let _ = &Self::BOUNDED; - | ^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:151:17 - | -LL | let _ = &Self::SELF; - | ^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:152:17 - | -LL | let _ = &Self::WRAPPED_SELF; - | ^^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:161:17 - | -LL | let _ = &Self::DIRECT; - | ^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:162:17 - | -LL | let _ = &Self::INDIRECT; - | ^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:171:17 - | -LL | let _ = &Self::DIRECT; - | ^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:172:17 - | -LL | let _ = &Self::INDIRECT; - | ^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:191:17 - | -LL | let _ = &Self::ATOMIC; - | ^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> tests/ui/borrow_interior_mutable_const/traits.rs:195:17 - | -LL | let _ = &Self::BOUNDED_ASSOC_TYPE; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> 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: this lint can be silenced by assigning the value to a local variable before borrowing - -error: borrow of a named constant with interior mutability - --> 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: this lint can be silenced by assigning the value to a local variable before borrowing - -error: aborting due to 17 previous errors - diff --git a/tests/ui/declare_interior_mutable_const.rs b/tests/ui/declare_interior_mutable_const.rs new file mode 100644 index 000000000000..c65df275038d --- /dev/null +++ b/tests/ui/declare_interior_mutable_const.rs @@ -0,0 +1,200 @@ +#![deny(clippy::declare_interior_mutable_const)] +#![allow(clippy::missing_const_for_thread_local)] + +use core::cell::{Cell, RefCell, UnsafeCell}; +use core::mem::{ManuallyDrop, MaybeUninit}; +use core::ptr; +use core::sync::atomic::AtomicUsize; + +fn main() {} + +const _: Cell = Cell::new(0); +const UNSAFE_CELL: UnsafeCell = UnsafeCell::new(0); //~ declare_interior_mutable_const +const REF_CELL: RefCell = RefCell::new(0); //~ declare_interior_mutable_const +const CELL: Cell = Cell::new(0); //~ declare_interior_mutable_const + +// Constants can't contain pointers or references to type with interior mutability. +const fn make_ptr() -> *const Cell { + ptr::null() +} +const PTR: *const Cell = make_ptr(); + +const fn casted_to_cell_ptr() -> *const Cell { + const VALUE: u32 = 0; + &VALUE as *const _ as *const Cell +} +const TRANSMUTED_PTR: *const Cell = casted_to_cell_ptr(); + +const CELL_TUPLE: (bool, Cell) = (true, Cell::new(0)); //~ declare_interior_mutable_const +const CELL_ARRAY: [Cell; 2] = [Cell::new(0), Cell::new(0)]; //~ declare_interior_mutable_const + +const UNINIT_CELL: MaybeUninit> = MaybeUninit::uninit(); + +struct CellStruct { + x: u32, + cell: Cell, +} +//~v declare_interior_mutable_const +const CELL_STRUCT: CellStruct = CellStruct { + x: 0, + cell: Cell::new(0), +}; + +enum CellEnum { + Cell(Cell), +} +const CELL_ENUM: CellEnum = CellEnum::Cell(Cell::new(0)); //~ declare_interior_mutable_const + +const NONE_CELL: Option> = None; +const SOME_CELL: Option> = Some(Cell::new(0)); //~ declare_interior_mutable_const + +struct NestedCell([(Option>,); 1]); +const NONE_NESTED_CELL: NestedCell = NestedCell([(None,)]); +const SOME_NESTED_CELL: NestedCell = NestedCell([(Some(Cell::new(0)),)]); //~ declare_interior_mutable_const + +union UnionCell { + cell: ManuallyDrop>, + x: u32, +} +//~v declare_interior_mutable_const +const UNION_CELL: UnionCell = UnionCell { + cell: ManuallyDrop::new(Cell::new(0)), +}; +// Access to either union field is valid so we have to be conservative here. +const UNION_U32: UnionCell = UnionCell { x: 0 }; //~ declare_interior_mutable_const + +struct Assoc; +impl Assoc { + const SELF: Self = Self; + const CELL: Cell = Cell::new(0); //~ declare_interior_mutable_const +} + +struct AssocCell(Cell); +impl AssocCell { + const SELF: Self = Self(Cell::new(0)); //~ declare_interior_mutable_const + const NONE_SELF: Option = None; + const SOME_SELF: Option = Some(Self(Cell::new(0))); //~ declare_interior_mutable_const +} + +trait ConstDefault { + // May or may not be `Freeze` + const DEFAULT: Self; +} +impl ConstDefault for u32 { + const DEFAULT: Self = 0; +} +impl ConstDefault for Cell { + // Interior mutability is forced by the trait. + const DEFAULT: Self = Cell::new(T::DEFAULT); +} +impl ConstDefault for Option> { + // Could have been `None` + const DEFAULT: Self = Some(Cell::new(T::DEFAULT)); //~ declare_interior_mutable_const +} + +enum GenericEnumCell { + Cell(Cell), + Other(T), +} +impl ConstDefault for GenericEnumCell { + const DEFAULT: Self = Self::Cell(Cell::new(T::DEFAULT)); //~ declare_interior_mutable_const +} +impl GenericEnumCell { + const CELL: Self = Self::DEFAULT; //~ declare_interior_mutable_const + const CELL_BY_DEFAULT: Self = Self::Cell(Cell::DEFAULT); //~ declare_interior_mutable_const + const OTHER: Self = Self::Other(T::DEFAULT); + const FROM_OTHER: Self = Self::OTHER; +} + +enum GenericNestedEnumCell { + GenericEnumCell(GenericEnumCell), + EnumCell(GenericEnumCell), + Other(T), +} +impl GenericNestedEnumCell { + const GENERIC_OTHER: Self = Self::GenericEnumCell(GenericEnumCell::::FROM_OTHER); + const GENERIC_CELL: Self = Self::GenericEnumCell(GenericEnumCell::::CELL); //~ declare_interior_mutable_const + const ENUM_OTHER: Self = Self::EnumCell(GenericEnumCell::::FROM_OTHER); + const ENUM_CELL: Self = Self::EnumCell(GenericEnumCell::::CELL); //~ declare_interior_mutable_const +} + +trait CellTrait: ConstDefault + Sized { + // Must be non-`Freeze` due to the type + const CELL: Cell; //~ declare_interior_mutable_const + // May be non-`Freeze`, but may not be + const OPTION_CELL: Option>; + // May get redefined by the impl, but the default is non-`Freeze`. + const SOME_CELL: Option> = Some(Cell::new(Self::DEFAULT)); //~ declare_interior_mutable_const + // May get redefined by the impl, but the default is `Freeze`. + const NONE_CELL: Option> = None; +} + +trait CellWithAssoc { + type T; + const DEFAULT: Self::T; + // Must be non-`Freeze` due to the type + const CELL: Cell; //~ declare_interior_mutable_const + // May be non-`Freeze`, but may not be + const OPTION_CELL: Option>; + // May get redefined by the impl, but the default is non-`Freeze`. + const SOME_CELL: Option> = Some(Cell::new(Self::DEFAULT)); //~ declare_interior_mutable_const + // May get redefined by the impl, but the default is `Freeze`. + const NONE_CELL: Option> = None; +} + +impl CellWithAssoc for () { + type T = u32; + const DEFAULT: Self::T = 0; + const CELL: Cell = Cell::new(0); + const OPTION_CELL: Option> = None; +} + +trait WithAssoc { + type T; + const VALUE: Self::T; +} + +impl WithAssoc for u32 { + type T = Cell; + // The cell comes from the impl block, not the trait. + const VALUE: Self::T = Cell::new(0); //~ declare_interior_mutable_const +} + +trait WithLayeredAssoc { + type T: WithAssoc; + const VALUE: ::T; +} + +impl WithLayeredAssoc for u32 { + type T = u32; + // The cell comes from the impl block, not the trait. + const VALUE: ::T = Cell::new(0); //~ declare_interior_mutable_const +} + +trait WithGenericAssoc { + type T; + const VALUE: Self::T; +} + +impl WithGenericAssoc for u32 { + type T = Cell; + const VALUE: Self::T = Cell::new(0); //~ declare_interior_mutable_const +} + +trait WithGenericAssocCell { + type T; + const VALUE: Self::T>; +} + +impl WithGenericAssocCell for u32 { + type T = Option; + const VALUE: Self::T> = None; +} + +impl WithGenericAssocCell for i32 { + type T = Option; + const VALUE: Self::T> = Some(Cell::new(0)); //~ declare_interior_mutable_const +} + +thread_local!(static THREAD_LOCAL_CELL: Cell = const { Cell::new(0) }); +thread_local!(static THREAD_LOCAL_CELL2: Cell = Cell::new(0)); diff --git a/tests/ui/declare_interior_mutable_const.stderr b/tests/ui/declare_interior_mutable_const.stderr new file mode 100644 index 000000000000..9742c17486c5 --- /dev/null +++ b/tests/ui/declare_interior_mutable_const.stderr @@ -0,0 +1,197 @@ +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:12:7 + | +LL | const UNSAFE_CELL: UnsafeCell = UnsafeCell::new(0); + | ^^^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item +note: the lint level is defined here + --> tests/ui/declare_interior_mutable_const.rs:1:9 + | +LL | #![deny(clippy::declare_interior_mutable_const)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:13:7 + | +LL | const REF_CELL: RefCell = RefCell::new(0); + | ^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:14:7 + | +LL | const CELL: Cell = Cell::new(0); + | ^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:28:7 + | +LL | const CELL_TUPLE: (bool, Cell) = (true, Cell::new(0)); + | ^^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:29:7 + | +LL | const CELL_ARRAY: [Cell; 2] = [Cell::new(0), Cell::new(0)]; + | ^^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:38:7 + | +LL | const CELL_STRUCT: CellStruct = CellStruct { + | ^^^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:46:7 + | +LL | const CELL_ENUM: CellEnum = CellEnum::Cell(Cell::new(0)); + | ^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:49:7 + | +LL | const SOME_CELL: Option> = Some(Cell::new(0)); + | ^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:53:7 + | +LL | const SOME_NESTED_CELL: NestedCell = NestedCell([(Some(Cell::new(0)),)]); + | ^^^^^^^^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:60:7 + | +LL | const UNION_CELL: UnionCell = UnionCell { + | ^^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:64:7 + | +LL | const UNION_U32: UnionCell = UnionCell { x: 0 }; + | ^^^^^^^^^ + | + = help: did you mean to make this a `thread_local!` item + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:69:11 + | +LL | const CELL: Cell = Cell::new(0); + | ^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:74:11 + | +LL | const SELF: Self = Self(Cell::new(0)); + | ^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:76:11 + | +LL | const SOME_SELF: Option = Some(Self(Cell::new(0))); + | ^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:92:11 + | +LL | const DEFAULT: Self = Some(Cell::new(T::DEFAULT)); + | ^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:100:11 + | +LL | const DEFAULT: Self = Self::Cell(Cell::new(T::DEFAULT)); + | ^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:103:11 + | +LL | const CELL: Self = Self::DEFAULT; + | ^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:104:11 + | +LL | const CELL_BY_DEFAULT: Self = Self::Cell(Cell::DEFAULT); + | ^^^^^^^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:116:11 + | +LL | const GENERIC_CELL: Self = Self::GenericEnumCell(GenericEnumCell::::CELL); + | ^^^^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:118:11 + | +LL | const ENUM_CELL: Self = Self::EnumCell(GenericEnumCell::::CELL); + | ^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:123:11 + | +LL | const CELL: Cell; + | ^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:127:11 + | +LL | const SOME_CELL: Option> = Some(Cell::new(Self::DEFAULT)); + | ^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:136:11 + | +LL | const CELL: Cell; + | ^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:140:11 + | +LL | const SOME_CELL: Option> = Some(Cell::new(Self::DEFAULT)); + | ^^^^^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:160:11 + | +LL | const VALUE: Self::T = Cell::new(0); + | ^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:171:11 + | +LL | const VALUE: ::T = Cell::new(0); + | ^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:181:11 + | +LL | const VALUE: Self::T = Cell::new(0); + | ^^^^^ + +error: named constant with interior mutability + --> tests/ui/declare_interior_mutable_const.rs:196:11 + | +LL | const VALUE: Self::T> = Some(Cell::new(0)); + | ^^^^^ + +error: aborting due to 28 previous errors + diff --git a/tests/ui/declare_interior_mutable_const/enums.rs b/tests/ui/declare_interior_mutable_const/enums.rs deleted file mode 100644 index 2ca6b7bc303a..000000000000 --- a/tests/ui/declare_interior_mutable_const/enums.rs +++ /dev/null @@ -1,124 +0,0 @@ -#![warn(clippy::declare_interior_mutable_const)] - -use std::cell::Cell; -use std::sync::atomic::AtomicUsize; - -enum OptionalCell { - Unfrozen(Cell), - Frozen, -} - -// 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 FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen; - -const fn unfrozen_variant() -> OptionalCell { - OptionalCell::Unfrozen(Cell::new(false)) -} - -const fn frozen_variant() -> OptionalCell { - OptionalCell::Frozen -} - -const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); //~ declare_interior_mutable_const -const FROZEN_VARIANT_FROM_FN: OptionalCell = frozen_variant(); - -enum NestedInnermost { - Unfrozen(AtomicUsize), - Frozen, -} - -struct NestedInner { - inner: NestedInnermost, -} - -enum NestedOuter { - NestedInner(NestedInner), - NotNested(usize), -} - -struct NestedOutermost { - outer: NestedOuter, -} - -// a constant with enums should be linted according to its value, no matter how structs involve. -const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { - //~^ declare_interior_mutable_const - outer: NestedOuter::NestedInner(NestedInner { - inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)), - }), -}; -const NESTED_FROZEN_VARIANT: NestedOutermost = NestedOutermost { - outer: NestedOuter::NestedInner(NestedInner { - inner: NestedInnermost::Frozen, - }), -}; - -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; - const TO_BE_FROZEN_VARIANT: OptionalCell; - - // Lint default values accordingly. - 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)); //~ 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)); //~ declare_interior_mutable_const -} - -// At first, I thought I'd need to check every patterns in `trait.rs`; but, what matters -// here are values; and I think substituted generics at definitions won't appear in MIR. -trait AssocTypes { - type ToBeUnfrozen; - - const TO_BE_UNFROZEN_VARIANT: Option; - const TO_BE_FROZEN_VARIANT: Option; -} - -impl AssocTypes for u64 { - type ToBeUnfrozen = AtomicUsize; - - const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); //~ declare_interior_mutable_const - const TO_BE_FROZEN_VARIANT: Option = None; -} - -// Use raw pointers since direct generics have a false negative at the type level. -enum BothOfCellAndGeneric { - Unfrozen(Cell<*const T>), - Generic(*const T), - Frozen(usize), -} - -impl BothOfCellAndGeneric { - const UNFROZEN_VARIANT: BothOfCellAndGeneric = 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 = BothOfCellAndGeneric::Generic(std::ptr::null()); - - const FROZEN_VARIANT: BothOfCellAndGeneric = 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 -} - -// associated types here is basically the same as the one above. -trait BothOfCellAndGenericWithAssocType { - type AssocType; - - const UNFROZEN_VARIANT: BothOfCellAndGeneric = //~ declare_interior_mutable_const - BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); - const GENERIC_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Generic(std::ptr::null()); - const FROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Frozen(5); -} - -fn main() {} diff --git a/tests/ui/declare_interior_mutable_const/enums.stderr b/tests/ui/declare_interior_mutable_const/enums.stderr deleted file mode 100644 index 4eca533e5ada..000000000000 --- a/tests/ui/declare_interior_mutable_const/enums.stderr +++ /dev/null @@ -1,70 +0,0 @@ -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/enums.rs:12:7 - | -LL | const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); - | ^^^^^^^^^^^^^^^^ - | - = help: did you mean to make this a `thread_local!` 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: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/enums.rs:23:7 - | -LL | const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: did you mean to make this a `thread_local!` item - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/enums.rs:45:7 - | -LL | const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost { - | ^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: did you mean to make this a `static` item - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/enums.rs:64:11 - | -LL | const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/enums.rs:71:11 - | -LL | const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/enums.rs:75:11 - | -LL | const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/enums.rs:90:11 - | -LL | const TO_BE_UNFROZEN_VARIANT: Option = Some(Self::ToBeUnfrozen::new(4)); - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/enums.rs:102:11 - | -LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); - | ^^^^^^^^^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/enums.rs:111:11 - | -LL | const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); - | ^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/enums.rs:118:11 - | -LL | const UNFROZEN_VARIANT: BothOfCellAndGeneric = - | ^^^^^^^^^^^^^^^^ - -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 deleted file mode 100644 index 362f28b8c53b..000000000000 --- a/tests/ui/declare_interior_mutable_const/others.rs +++ /dev/null @@ -1,73 +0,0 @@ -#![warn(clippy::declare_interior_mutable_const)] - -use std::borrow::Cow; -use std::cell::Cell; -use std::fmt::Display; -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 = Cell::new(6); //~ declare_interior_mutable_const -const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); -//~^ declare_interior_mutable_const - -macro_rules! declare_const { - ($name:ident: $ty:ty = $e:expr) => { - const $name: $ty = $e; - }; -} -declare_const!(_ONCE: Once = Once::new()); //~ declare_interior_mutable_const - -// const ATOMIC_REF: &AtomicUsize = &AtomicUsize::new(7); // This will simply trigger E0492. - -const INTEGER: u8 = 8; -const STRING: String = String::new(); -const STR: &str = "012345"; -const COW: Cow = Cow::Borrowed("abcdef"); -// note: a const item of Cow is used in the `postgres` package. - -const NO_ANN: &dyn Display = &70; - -static STATIC_TUPLE: (AtomicUsize, String) = (ATOMIC, STRING); -// there should be no lints on the line above line - -mod issue_8493 { - use std::cell::Cell; - - thread_local! { - static _BAR: Cell = const { Cell::new(0) }; - } - - macro_rules! issue_8493 { - () => { - const _BAZ: Cell = Cell::new(0); - //~^ declare_interior_mutable_const - static _FOOBAR: () = { - thread_local! { - static _VAR: Cell = const { Cell::new(0) }; - } - }; - }; - } - - issue_8493!(); -} - -#[repr(C, align(8))] -struct NoAtomic(usize); -#[repr(C, align(8))] -struct WithAtomic(AtomicUsize); - -const fn with_non_null() -> *const WithAtomic { - const NO_ATOMIC: NoAtomic = NoAtomic(0); - (&NO_ATOMIC as *const NoAtomic).cast() -} -const WITH_ATOMIC: *const WithAtomic = with_non_null(); - -struct Generic(T); -impl Generic { - const RAW_POINTER: *const Cell = ptr::null(); -} - -fn main() {} diff --git a/tests/ui/declare_interior_mutable_const/others.stderr b/tests/ui/declare_interior_mutable_const/others.stderr deleted file mode 100644 index 67fb4d046a6b..000000000000 --- a/tests/ui/declare_interior_mutable_const/others.stderr +++ /dev/null @@ -1,48 +0,0 @@ -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/others.rs:10:7 - | -LL | const ATOMIC: AtomicUsize = AtomicUsize::new(5); - | ^^^^^^ - | - = help: did you mean to make 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: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/others.rs:11:7 - | -LL | const CELL: Cell = Cell::new(6); - | ^^^^ - | - = help: did you mean to make this a `thread_local!` item - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/others.rs:12:7 - | -LL | const ATOMIC_TUPLE: ([AtomicUsize; 1], Vec, u8) = ([ATOMIC], Vec::new(), 7); - | ^^^^^^^^^^^^ - | - = help: did you mean to make this a `static` item - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/others.rs:20:16 - | -LL | declare_const!(_ONCE: Once = Once::new()); - | ^^^^^ - | - = help: did you mean to make this a `static` item - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/others.rs:44:19 - | -LL | const _BAZ: Cell = Cell::new(0); - | ^^^^ -... -LL | issue_8493!(); - | ------------- in this macro invocation - | - = help: did you mean to make this a `thread_local!` item - = 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 deleted file mode 100644 index f4916e1b4cf1..000000000000 --- a/tests/ui/declare_interior_mutable_const/traits.rs +++ /dev/null @@ -1,149 +0,0 @@ -#![warn(clippy::declare_interior_mutable_const)] - -use std::borrow::Cow; -use std::cell::Cell; -use std::sync::atomic::AtomicUsize; - -macro_rules! declare_const { - ($name:ident: $ty:ty = $e:expr) => { - const $name: $ty = $e; - }; -} - -// 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 INTEGER: u64; - const STRING: String; - declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); //~ declare_interior_mutable_const -} - -impl ConcreteTypes for u64 { - const ATOMIC: AtomicUsize = AtomicUsize::new(9); - const INTEGER: u64 = 10; - const STRING: String = String::new(); -} - -// a helper trait used below -trait ConstDefault { - const DEFAULT: Self; -} - -// a constant whose type is a generic type should be linted at the implementation site. -trait GenericTypes { - const TO_REMAIN_GENERIC: T; - const TO_BE_CONCRETE: U; - - const HAVING_DEFAULT: T = Self::TO_REMAIN_GENERIC; - declare_const!(IN_MACRO: T = Self::TO_REMAIN_GENERIC); -} - -impl GenericTypes for u64 { - const TO_REMAIN_GENERIC: T = T::DEFAULT; - const TO_BE_CONCRETE: AtomicUsize = AtomicUsize::new(11); -} - -// a helper type used below -struct Wrapper(T); - -// a constant whose type is an associated type should be linted at the implementation site, too. -trait AssocTypes { - type ToBeFrozen; - type ToBeUnfrozen; - type ToBeGenericParam; - - const TO_BE_FROZEN: Self::ToBeFrozen; - const TO_BE_UNFROZEN: Self::ToBeUnfrozen; - const WRAPPED_TO_BE_UNFROZEN: Wrapper; - // to ensure it can handle things when a generic type remains after normalization. - const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper; -} - -impl AssocTypes for Vec { - type ToBeFrozen = u16; - type ToBeUnfrozen = AtomicUsize; - 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 = Wrapper(AtomicUsize::new(14)); //~ declare_interior_mutable_const - const WRAPPED_TO_BE_GENERIC_PARAM: Wrapper = Wrapper(T::DEFAULT); -} - -// a helper trait used below -trait AssocTypesHelper { - type NotToBeBounded; - type ToBeBounded; - - const NOT_TO_BE_BOUNDED: Self::NotToBeBounded; -} - -// a constant whose type is an assoc type originated from a generic param bounded at the definition -// site should be linted at there. -trait AssocTypesFromGenericParam -where - T: AssocTypesHelper, -{ - const NOT_BOUNDED: T::NotToBeBounded; - const BOUNDED: T::ToBeBounded; //~ declare_interior_mutable_const -} - -impl AssocTypesFromGenericParam for u64 -where - T: AssocTypesHelper, -{ - // an associated type could remain unknown in a trait impl. - const NOT_BOUNDED: T::NotToBeBounded = T::NOT_TO_BE_BOUNDED; - const BOUNDED: T::ToBeBounded = AtomicUsize::new(15); -} - -// a constant whose type is `Self` should be linted at the implementation site as well. -// (`Option` requires `Sized` bound.) -trait SelfType: Sized { - const SELF: Self; - // this was the one in the original issue (#5050). - const WRAPPED_SELF: Option; -} - -impl SelfType for u64 { - const SELF: Self = 16; - const WRAPPED_SELF: Option = Some(20); -} - -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); - const WRAPPED_SELF: Option = 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 { - const DIRECT: Cell; //~ declare_interior_mutable_const - const INDIRECT: Cell<*const T>; //~ declare_interior_mutable_const -} - -impl BothOfCellAndGeneric for u64 { - const DIRECT: Cell = Cell::new(T::DEFAULT); - const INDIRECT: Cell<*const T> = Cell::new(std::ptr::null()); -} - -struct Local(T); - -// a constant in an inherent impl are essentially the same as a normal const item -// except there can be a generic or associated type. -impl Local -where - T: ConstDefault + AssocTypesHelper, -{ - 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 -} - -fn main() {} diff --git a/tests/ui/declare_interior_mutable_const/traits.stderr b/tests/ui/declare_interior_mutable_const/traits.stderr deleted file mode 100644 index a5c08871ba77..000000000000 --- a/tests/ui/declare_interior_mutable_const/traits.stderr +++ /dev/null @@ -1,65 +0,0 @@ -error: named constant with interior mutability - --> 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: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/traits.rs:18:20 - | -LL | declare_const!(ANOTHER_ATOMIC: AtomicUsize = Self::ATOMIC); - | ^^^^^^^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/traits.rs:68:11 - | -LL | const TO_BE_UNFROZEN: Self::ToBeUnfrozen = AtomicUsize::new(13); - | ^^^^^^^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/traits.rs:69:11 - | -LL | const WRAPPED_TO_BE_UNFROZEN: Wrapper = Wrapper(AtomicUsize::new(14)); - | ^^^^^^^^^^^^^^^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/traits.rs:88:11 - | -LL | const BOUNDED: T::ToBeBounded; - | ^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/traits.rs:117:11 - | -LL | const WRAPPED_SELF: Option = Some(AtomicUsize::new(21)); - | ^^^^^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/traits.rs:123:11 - | -LL | const DIRECT: Cell; - | ^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/traits.rs:124:11 - | -LL | const INDIRECT: Cell<*const T>; - | ^^^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/traits.rs:140:11 - | -LL | const ATOMIC: AtomicUsize = AtomicUsize::new(18); - | ^^^^^^ - -error: named constant with interior mutability - --> tests/ui/declare_interior_mutable_const/traits.rs:146:11 - | -LL | const BOUNDED_ASSOC_TYPE: T::ToBeBounded = AtomicUsize::new(19); - | ^^^^^^^^^^^^^^^^^^ - -error: aborting due to 10 previous errors -