From 58d483409705aa4063eec5edbe6bb020adcacb59 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Sat, 1 Feb 2025 02:30:50 +0300 Subject: [PATCH] Resolve projections during internal mutability analysis --- clippy_lints/src/non_copy_const.rs | 6 +++ clippy_utils/src/ty/mod.rs | 4 ++ .../projections.rs | 42 ++++++++++++++++++ .../projections.stderr | 44 +++++++++++++++++++ 4 files changed, 96 insertions(+) create mode 100644 tests/ui/borrow_interior_mutable_const/projections.rs create mode 100644 tests/ui/borrow_interior_mutable_const/projections.stderr diff --git a/clippy_lints/src/non_copy_const.rs b/clippy_lints/src/non_copy_const.rs index 147654675ec9..0d89b4e85350 100644 --- a/clippy_lints/src/non_copy_const.rs +++ b/clippy_lints/src/non_copy_const.rs @@ -215,6 +215,12 @@ impl<'tcx> NonCopyConst<'tcx> { .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, ty::ValTree::Branch(val), normalized_ty) + }, + _ => false, + }, _ => false, } } diff --git a/clippy_utils/src/ty/mod.rs b/clippy_utils/src/ty/mod.rs index f2bbdda70585..5201036d84d3 100644 --- a/clippy_utils/src/ty/mod.rs +++ b/clippy_utils/src/ty/mod.rs @@ -1227,6 +1227,10 @@ impl<'tcx> InteriorMut<'tcx> { .find_map(|f| self.interior_mut_ty_chain(cx, f.ty(cx.tcx, args))) } }, + ty::Alias(ty::Projection, _) => match cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) { + Ok(normalized_ty) if ty != normalized_ty => self.interior_mut_ty_chain(cx, normalized_ty), + _ => None, + }, _ => None, }; diff --git a/tests/ui/borrow_interior_mutable_const/projections.rs b/tests/ui/borrow_interior_mutable_const/projections.rs new file mode 100644 index 000000000000..bbe5538fbe12 --- /dev/null +++ b/tests/ui/borrow_interior_mutable_const/projections.rs @@ -0,0 +1,42 @@ +#![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 new file mode 100644 index 000000000000..eabaf66560ad --- /dev/null +++ b/tests/ui/borrow_interior_mutable_const/projections.stderr @@ -0,0 +1,44 @@ +error: a `const` item should not be interior mutable + --> tests/ui/borrow_interior_mutable_const/projections.rs:27:1 + | +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 + --> 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 + --> tests/ui/borrow_interior_mutable_const/projections.rs:29:1 + | +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 + | +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 + --> 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 + --> tests/ui/borrow_interior_mutable_const/projections.rs:40:16 + | +LL | print_ref(&MUTABLE); + | ^^^^^^^ + | + = help: assign this const to a local or static variable, and use the variable here + +error: aborting due to 4 previous errors +