summaryrefslogtreecommitdiffstats
path: root/src/tools/clippy/tests/ui/declare_interior_mutable_const/enums.rs
blob: f44518694b89c309bc4ae14326f112367a878ac5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#![warn(clippy::declare_interior_mutable_const)]

use std::cell::Cell;
use std::sync::atomic::AtomicUsize;

enum OptionalCell {
    Unfrozen(Cell<bool>),
    Frozen,
}

// a constant with enums should be linted only when the used variant is unfrozen (#3962).
const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(true)); //~ ERROR interior mutable
const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;

const fn unfrozen_variant() -> OptionalCell {
    OptionalCell::Unfrozen(Cell::new(false))
}

const fn frozen_variant() -> OptionalCell {
    OptionalCell::Frozen
}

const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant(); //~ ERROR interior mutable
const FROZEN_VARIANT_FROM_FN: OptionalCell = frozen_variant();

enum NestedInnermost {
    Unfrozen(AtomicUsize),
    Frozen,
}

struct NestedInner {
    inner: NestedInnermost,
}

enum NestedOuter {
    NestedInner(NestedInner),
    NotNested(usize),
}

struct NestedOutermost {
    outer: NestedOuter,
}

// a constant with enums should be linted according to its value, no matter how structs involve.
const NESTED_UNFROZEN_VARIANT: NestedOutermost = NestedOutermost {
    outer: NestedOuter::NestedInner(NestedInner {
        inner: NestedInnermost::Unfrozen(AtomicUsize::new(2)),
    }),
}; //~ ERROR interior mutable
const NESTED_FROZEN_VARIANT: NestedOutermost = NestedOutermost {
    outer: NestedOuter::NestedInner(NestedInner {
        inner: NestedInnermost::Frozen,
    }),
};

trait AssocConsts {
    // When there's no default value, lint it only according to its type.
    // Further details are on the corresponding code (`NonCopyConst::check_trait_item`).
    const TO_BE_UNFROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable
    const TO_BE_FROZEN_VARIANT: OptionalCell; //~ ERROR interior mutable

    // Lint default values accordingly.
    const DEFAULTED_ON_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false)); //~ ERROR interior mutable
    const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
}

// The lint doesn't trigger for an assoc constant in a trait impl with an unfrozen type even if it
// has enums. Further details are on the corresponding code in 'NonCopyConst::check_impl_item'.
impl AssocConsts for u64 {
    const TO_BE_UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
    const TO_BE_FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;

    // even if this sets an unfrozen variant, the lint ignores it.
    const DEFAULTED_ON_FROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Cell::new(false));
}

// At first, I thought I'd need to check every patterns in `trait.rs`; but, what matters
// here are values; and I think substituted generics at definitions won't appear in MIR.
trait AssocTypes {
    type ToBeUnfrozen;

    const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen>;
    const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen>;
}

impl AssocTypes for u64 {
    type ToBeUnfrozen = AtomicUsize;

    const TO_BE_UNFROZEN_VARIANT: Option<Self::ToBeUnfrozen> = Some(Self::ToBeUnfrozen::new(4)); //~ ERROR interior mutable
    const TO_BE_FROZEN_VARIANT: Option<Self::ToBeUnfrozen> = None;
}

// Use raw pointers since direct generics have a false negative at the type level.
enum BothOfCellAndGeneric<T> {
    Unfrozen(Cell<*const T>),
    Generic(*const T),
    Frozen(usize),
}

impl<T> BothOfCellAndGeneric<T> {
    const UNFROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable

    // This is a false positive. The argument about this is on `is_value_unfrozen_raw`
    const GENERIC_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable

    const FROZEN_VARIANT: BothOfCellAndGeneric<T> = BothOfCellAndGeneric::Frozen(5);

    // This is what is likely to be a false negative when one tries to fix
    // the `GENERIC_VARIANT` false positive.
    const NO_ENUM: Cell<*const T> = Cell::new(std::ptr::null()); //~ ERROR interior mutable
}

// associated types here is basically the same as the one above.
trait BothOfCellAndGenericWithAssocType {
    type AssocType;

    const UNFROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> =
        BothOfCellAndGeneric::Unfrozen(Cell::new(std::ptr::null())); //~ ERROR interior mutable
    const GENERIC_VARIANT: BothOfCellAndGeneric<Self::AssocType> = BothOfCellAndGeneric::Generic(std::ptr::null()); //~ ERROR interior mutable
    const FROZEN_VARIANT: BothOfCellAndGeneric<Self::AssocType> = BothOfCellAndGeneric::Frozen(5);
}

fn main() {}