Skip to content

Rewrite non_copy_const #13207

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,157 changes: 791 additions & 366 deletions clippy_lints/src/non_copy_const.rs

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions clippy_utils/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<usize> {
match *ty.kind() {
ty::Adt(def, _) if def.is_union() || def.is_struct() => {
def.non_enum_variant().fields.iter().position(|f| f.name == name)
},
ty::Tuple(_) => name.as_str().parse::<usize>().ok(),
_ => None,
}
}
221 changes: 221 additions & 0 deletions tests/ui/borrow_interior_mutable_const.rs
Original file line number Diff line number Diff line change
@@ -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<T: ConstDefault> ConstDefault for Cell<T> {
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<u32> = 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<u32> = 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<u32>,); 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<u32>);
impl S {
const C: Self = Self(Cell::new(0));
}
impl Deref for S {
type Target = Cell<u32>;
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<u32>),
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<T> {
cell: (Cell<T>, u32),
other: Option<T>,
}
impl<T: ConstDefault + Copy> S<T> {
const C: Self = Self {
cell: (Cell::<T>::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<Cell<u32>> = Some(Cell::new(0));
}
impl T for u32 {}
impl T for i32 {
const VALUE: Option<Cell<u32>> = None;
}

let _ = &u32::VALUE; //~ borrow_interior_mutable_const
let _ = &i32::VALUE;
}
{
trait Trait<T: ConstDefault> {
type T<U: ConstDefault>: ConstDefault;
const VALUE: Option<Self::T<T>> = Some(Self::T::<T>::DEFAULT);
}
impl<T: ConstDefault> Trait<T> for u32 {
type T<U: ConstDefault> = Cell<U>;
}
impl<T: ConstDefault> Trait<T> for i32 {
type T<U: ConstDefault> = Cell<U>;
const VALUE: Option<Cell<T>> = None;
}

fn f<T: ConstDefault>() {
let _ = &<u32 as Trait<T>>::VALUE; //~ borrow_interior_mutable_const
let _ = &<i32 as Trait<T>>::VALUE;
}
}
{
trait Trait {
const UNFROZEN: Option<Cell<u32>> = Some(Cell::new(0));
const FROZEN: Option<Cell<u32>> = None;
const NON_FREEZE: u32 = 0;
}
fn f<T: Trait>() {
// 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<Cell<u32>>; 2]);
impl Index<usize> for S {
type Output = Option<Cell<u32>>;
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<Cell<u32>>; 2] = [None, None];
let _ = &C[0];
let _ = &C[1];
let _ = &C[2];

fn f(i: usize) {
let _ = &C[i];
}
}
{
const C: [Option<Cell<u32>>; 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<T> = Cell<T>;
type MyCell = Cell2<u32>;
struct S(Option<MyCell>);
trait T {
type Assoc;
}
struct S2<T>(T, T, u32);
impl T for S {
type Assoc = S2<Self>;
}
type Assoc<X> = <X as T>::Assoc;
impl S {
const VALUE: Assoc<Self> = 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;
}
}
Loading