1 #![warn(clippy::declare_interior_mutable_const)]
2 
3 use std::cell::Cell;
4 use std::sync::atomic::AtomicUsize;
5 
6 enum OptionalCell {
7     Unfrozen(Cell<bool>),
8     Frozen,
9 }
10 
11 // a constant with enums should be linted only when the used variant is unfrozen (#3962).
12 const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); //~ ERROR interior mutable
13 const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
14 
unfrozen_variant() -> OptionalCell15 const fn unfrozen_variant() -> OptionalCell {
16     OptionalCell::Unfrozen(Cell::new(false))
17 }
18 
frozen_variant() -> OptionalCell19 const fn frozen_variant() -> OptionalCell {
20     OptionalCell::Frozen
21 }
22 
23 const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); //~ ERROR interior mutable
24 const FROZEN_VARIANT_FROM_FN: OptionalCell = frozen_variant();
25 
26 enum NestedInnermost {
27     Unfrozen(AtomicUsize),
28     Frozen,
29 }
30 
31 struct NestedInner {
32     inner: NestedInnermost,
33 }
34 
35 enum NestedOuter {
36     NestedInner(NestedInner),
37     NotNested(usize),
38 }
39 
40 struct NestedOutermost {
41     outer: NestedOuter,
42 }
43 
44 // a constant with enums should be linted according to its value, no matter how structs involve.
45 const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost {
46     outer: NestedOuter::NestedInner(NestedInner {
47         inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)),
48     }),
49 }; //~ ERROR interior mutable
50 const NESTED_FROZEN_VARIANT: NestedOutermost = NestedOutermost {
51     outer: NestedOuter::NestedInner(NestedInner {
52         inner: NestedInnermost::Frozen,
53     }),
54 };
55 
56 trait AssocConsts {
57     // When there's no default value, lint it only according to its type.
58     // Further details are on the corresponding code (`NonCopyConst::check_trait_item`).
59     const TO_BE_UNFROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable
60     const TO_BE_FROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable
61 
62     // Lint default values accordingly.
63     const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ ERROR interior mutable
64     const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
65 }
66 
67 // The lint doesn't trigger for an assoc constant in a trait impl with an unfrozen type even if it
68 // has enums. Further details are on the corresponding code in 'NonCopyConst::check_impl_item'.
69 impl AssocConsts for u64 {
70     const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
71     const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
72 
73     // even if this sets an unfrozen variant, the lint ignores it.
74     const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
75 }
76 
77 // At first, I thought I'd need to check every patterns in `trait.rs`; but, what matters
78 // here are values; and I think substituted generics at definitions won't appear in MIR.
79 trait AssocTypes {
80     type ToBeUnfrozen;
81 
82     const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen>;
83     const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen>;
84 }
85 
86 impl AssocTypes for u64 {
87     type ToBeUnfrozen = AtomicUsize;
88 
89     const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen> = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR interior mutable
90     const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen> = None;
91 }
92 
93 // Use raw pointers since direct generics have a false negative at the type level.
94 enum BothOfCellAndGeneric<T> {
95     Unfrozen(Cell<*const T>),
96     Generic(*const T),
97     Frozen(usize),
98 }
99 
100 impl<T> BothOfCellAndGeneric<T> {
101     const UNFROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable
102 
103     // This is a false positive. The argument about this is on `is_value_unfrozen_raw`
104     const GENERIC_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable
105 
106     const FROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Frozen(5);
107 
108     // This is what is likely to be a false negative when one tries to fix
109     // the `GENERIC_VARIANT` false positive.
110     const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); //~ ERROR interior mutable
111 }
112 
113 // associated types here is basically the same as the one above.
114 trait BothOfCellAndGenericWithAssocType {
115     type AssocType;
116 
117     const UNFROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> =
118         BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable
119     const GENERIC_VARIANT: BothOfCellAndGeneric<Self::AssocType> = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable
120     const FROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> = BothOfCellAndGeneric::Frozen(5);
121 }
122 
main()123 fn main() {}
124