200 lines
6.5 KiB
Rust
200 lines
6.5 KiB
Rust
#![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<u32> = Cell::new(0);
|
|
const UNSAFE_CELL: UnsafeCell<u32> = UnsafeCell::new(0); //~ declare_interior_mutable_const
|
|
const REF_CELL: RefCell<u32> = RefCell::new(0); //~ declare_interior_mutable_const
|
|
const CELL: Cell<u32> = 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<u32> {
|
|
ptr::null()
|
|
}
|
|
const PTR: *const Cell<u32> = make_ptr();
|
|
|
|
const fn casted_to_cell_ptr() -> *const Cell<u32> {
|
|
const VALUE: u32 = 0;
|
|
&VALUE as *const _ as *const Cell<u32>
|
|
}
|
|
const TRANSMUTED_PTR: *const Cell<u32> = casted_to_cell_ptr();
|
|
|
|
const CELL_TUPLE: (bool, Cell<u32>) = (true, Cell::new(0)); //~ declare_interior_mutable_const
|
|
const CELL_ARRAY: [Cell<u32>; 2] = [Cell::new(0), Cell::new(0)]; //~ declare_interior_mutable_const
|
|
|
|
const UNINIT_CELL: MaybeUninit<Cell<&'static ()>> = MaybeUninit::uninit();
|
|
|
|
struct CellStruct {
|
|
x: u32,
|
|
cell: Cell<u32>,
|
|
}
|
|
//~v declare_interior_mutable_const
|
|
const CELL_STRUCT: CellStruct = CellStruct {
|
|
x: 0,
|
|
cell: Cell::new(0),
|
|
};
|
|
|
|
enum CellEnum {
|
|
Cell(Cell<u32>),
|
|
}
|
|
const CELL_ENUM: CellEnum = CellEnum::Cell(Cell::new(0)); //~ declare_interior_mutable_const
|
|
|
|
const NONE_CELL: Option<Cell<u32>> = None;
|
|
const SOME_CELL: Option<Cell<u32>> = Some(Cell::new(0)); //~ declare_interior_mutable_const
|
|
|
|
struct NestedCell([(Option<Cell<u32>>,); 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<Cell<u32>>,
|
|
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<u32> = Cell::new(0); //~ declare_interior_mutable_const
|
|
}
|
|
|
|
struct AssocCell(Cell<u32>);
|
|
impl AssocCell {
|
|
const SELF: Self = Self(Cell::new(0)); //~ declare_interior_mutable_const
|
|
const NONE_SELF: Option<Self> = None;
|
|
const SOME_SELF: Option<Self> = 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<T: ConstDefault> ConstDefault for Cell<T> {
|
|
// Interior mutability is forced by the trait.
|
|
const DEFAULT: Self = Cell::new(T::DEFAULT);
|
|
}
|
|
impl<T: ConstDefault> ConstDefault for Option<Cell<T>> {
|
|
// Could have been `None`
|
|
const DEFAULT: Self = Some(Cell::new(T::DEFAULT)); //~ declare_interior_mutable_const
|
|
}
|
|
|
|
enum GenericEnumCell<T> {
|
|
Cell(Cell<T>),
|
|
Other(T),
|
|
}
|
|
impl<T: ConstDefault> ConstDefault for GenericEnumCell<T> {
|
|
const DEFAULT: Self = Self::Cell(Cell::new(T::DEFAULT)); //~ declare_interior_mutable_const
|
|
}
|
|
impl<T: ConstDefault> GenericEnumCell<T> {
|
|
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<T> {
|
|
GenericEnumCell(GenericEnumCell<T>),
|
|
EnumCell(GenericEnumCell<u32>),
|
|
Other(T),
|
|
}
|
|
impl<T: ConstDefault> GenericNestedEnumCell<T> {
|
|
const GENERIC_OTHER: Self = Self::GenericEnumCell(GenericEnumCell::<T>::FROM_OTHER);
|
|
const GENERIC_CELL: Self = Self::GenericEnumCell(GenericEnumCell::<T>::CELL); //~ declare_interior_mutable_const
|
|
const ENUM_OTHER: Self = Self::EnumCell(GenericEnumCell::<u32>::FROM_OTHER);
|
|
const ENUM_CELL: Self = Self::EnumCell(GenericEnumCell::<u32>::CELL); //~ declare_interior_mutable_const
|
|
}
|
|
|
|
trait CellTrait: ConstDefault + Sized {
|
|
// Must be non-`Freeze` due to the type
|
|
const CELL: Cell<Self>; //~ declare_interior_mutable_const
|
|
// May be non-`Freeze`, but may not be
|
|
const OPTION_CELL: Option<Cell<Self>>;
|
|
// May get redefined by the impl, but the default is non-`Freeze`.
|
|
const SOME_CELL: Option<Cell<Self>> = Some(Cell::new(Self::DEFAULT)); //~ declare_interior_mutable_const
|
|
// May get redefined by the impl, but the default is `Freeze`.
|
|
const NONE_CELL: Option<Cell<Self>> = None;
|
|
}
|
|
|
|
trait CellWithAssoc {
|
|
type T;
|
|
const DEFAULT: Self::T;
|
|
// Must be non-`Freeze` due to the type
|
|
const CELL: Cell<Self::T>; //~ declare_interior_mutable_const
|
|
// May be non-`Freeze`, but may not be
|
|
const OPTION_CELL: Option<Cell<Self::T>>;
|
|
// May get redefined by the impl, but the default is non-`Freeze`.
|
|
const SOME_CELL: Option<Cell<Self::T>> = Some(Cell::new(Self::DEFAULT)); //~ declare_interior_mutable_const
|
|
// May get redefined by the impl, but the default is `Freeze`.
|
|
const NONE_CELL: Option<Cell<Self::T>> = None;
|
|
}
|
|
|
|
impl CellWithAssoc for () {
|
|
type T = u32;
|
|
const DEFAULT: Self::T = 0;
|
|
const CELL: Cell<Self::T> = Cell::new(0);
|
|
const OPTION_CELL: Option<Cell<Self::T>> = None;
|
|
}
|
|
|
|
trait WithAssoc {
|
|
type T;
|
|
const VALUE: Self::T;
|
|
}
|
|
|
|
impl WithAssoc for u32 {
|
|
type T = Cell<u32>;
|
|
// 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: <Self::T as WithAssoc>::T;
|
|
}
|
|
|
|
impl WithLayeredAssoc for u32 {
|
|
type T = u32;
|
|
// The cell comes from the impl block, not the trait.
|
|
const VALUE: <Self::T as WithAssoc>::T = Cell::new(0); //~ declare_interior_mutable_const
|
|
}
|
|
|
|
trait WithGenericAssoc {
|
|
type T<U>;
|
|
const VALUE: Self::T<u32>;
|
|
}
|
|
|
|
impl WithGenericAssoc for u32 {
|
|
type T<U> = Cell<U>;
|
|
const VALUE: Self::T<u32> = Cell::new(0); //~ declare_interior_mutable_const
|
|
}
|
|
|
|
trait WithGenericAssocCell {
|
|
type T<U>;
|
|
const VALUE: Self::T<Cell<u32>>;
|
|
}
|
|
|
|
impl WithGenericAssocCell for u32 {
|
|
type T<U> = Option<U>;
|
|
const VALUE: Self::T<Cell<u32>> = None;
|
|
}
|
|
|
|
impl WithGenericAssocCell for i32 {
|
|
type T<U> = Option<U>;
|
|
const VALUE: Self::T<Cell<u32>> = Some(Cell::new(0)); //~ declare_interior_mutable_const
|
|
}
|
|
|
|
thread_local!(static THREAD_LOCAL_CELL: Cell<u32> = const { Cell::new(0) });
|
|
thread_local!(static THREAD_LOCAL_CELL2: Cell<u32> = Cell::new(0));
|