#![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));