xref: /llvm-project/clang/test/Analysis/enum-cast-out-of-range.cpp (revision 4b7d4008e21e9da9a189523ff90389a044b37ea4)
1 // RUN: %clang_analyze_cc1 \
2 // RUN:   -analyzer-checker=core,optin.core.EnumCastOutOfRange \
3 // RUN:   -std=c++11 -verify %s
4 
5 // expected-note@+1 + {{enum declared here}}
6 enum unscoped_unspecified_t {
7   unscoped_unspecified_0 = -4,
8   unscoped_unspecified_1,
9   unscoped_unspecified_2 = 1,
10   unscoped_unspecified_3,
11   unscoped_unspecified_4 = 4
12 };
13 
14 // expected-note@+1 + {{enum declared here}}
15 enum unscoped_specified_t : int {
16   unscoped_specified_0 = -4,
17   unscoped_specified_1,
18   unscoped_specified_2 = 1,
19   unscoped_specified_3,
20   unscoped_specified_4 = 4
21 };
22 
23 // expected-note@+1 + {{enum declared here}}
24 enum class scoped_unspecified_t {
25   scoped_unspecified_0 = -4,
26   scoped_unspecified_1,
27   scoped_unspecified_2 = 1,
28   scoped_unspecified_3,
29   scoped_unspecified_4 = 4
30 };
31 
32 // expected-note@+1 + {{enum declared here}}
33 enum class scoped_specified_t : int {
34   scoped_specified_0 = -4,
35   scoped_specified_1,
36   scoped_specified_2 = 1,
37   scoped_specified_3,
38   scoped_specified_4 = 4
39 };
40 
41 struct S {
42   unscoped_unspecified_t E : 5;
43 };
44 
unscopedUnspecified()45 void unscopedUnspecified() {
46   unscoped_unspecified_t InvalidBeforeRangeBegin = static_cast<unscoped_unspecified_t>(-5); // expected-warning {{The value '-5' provided to the cast expression is not in the valid range of values for 'unscoped_unspecified_t'}}
47   unscoped_unspecified_t ValidNegativeValue1 = static_cast<unscoped_unspecified_t>(-4); // OK.
48   unscoped_unspecified_t ValidNegativeValue2 = static_cast<unscoped_unspecified_t>(-3); // OK.
49   unscoped_unspecified_t InvalidInsideRange1 = static_cast<unscoped_unspecified_t>(-2); // expected-warning {{The value '-2' provided to the cast expression is not in the valid range of values for 'unscoped_unspecified_t'}}
50   unscoped_unspecified_t InvalidInsideRange2 = static_cast<unscoped_unspecified_t>(-1); // expected-warning {{The value '-1' provided to the cast expression is not in the valid range of values for 'unscoped_unspecified_t'}}
51   unscoped_unspecified_t InvalidInsideRange3 = static_cast<unscoped_unspecified_t>(0); // expected-warning {{The value '0' provided to the cast expression is not in the valid range of values for 'unscoped_unspecified_t'}}
52   unscoped_unspecified_t ValidPositiveValue1 = static_cast<unscoped_unspecified_t>(1); // OK.
53   unscoped_unspecified_t ValidPositiveValue2 = static_cast<unscoped_unspecified_t>(2); // OK.
54   unscoped_unspecified_t InvalidInsideRange4 = static_cast<unscoped_unspecified_t>(3); // expected-warning {{The value '3' provided to the cast expression is not in the valid range of values for 'unscoped_unspecified_t'}}
55   unscoped_unspecified_t ValidPositiveValue3 = static_cast<unscoped_unspecified_t>(4); // OK.
56   unscoped_unspecified_t InvalidAfterRangeEnd = static_cast<unscoped_unspecified_t>(5); // expected-warning {{The value '5' provided to the cast expression is not in the valid range of values for 'unscoped_unspecified_t'}}
57 }
58 
unscopedSpecified()59 void unscopedSpecified() {
60   unscoped_specified_t InvalidBeforeRangeBegin = static_cast<unscoped_specified_t>(-5); // expected-warning {{The value '-5' provided to the cast expression is not in the valid range of values for 'unscoped_specified_t'}}
61   unscoped_specified_t ValidNegativeValue1 = static_cast<unscoped_specified_t>(-4); // OK.
62   unscoped_specified_t ValidNegativeValue2 = static_cast<unscoped_specified_t>(-3); // OK.
63   unscoped_specified_t InvalidInsideRange1 = static_cast<unscoped_specified_t>(-2); // expected-warning {{The value '-2' provided to the cast expression is not in the valid range of values for 'unscoped_specified_t'}}
64   unscoped_specified_t InvalidInsideRange2 = static_cast<unscoped_specified_t>(-1); // expected-warning {{The value '-1' provided to the cast expression is not in the valid range of values for 'unscoped_specified_t'}}
65   unscoped_specified_t InvalidInsideRange3 = static_cast<unscoped_specified_t>(0); // expected-warning {{The value '0' provided to the cast expression is not in the valid range of values for 'unscoped_specified_t'}}
66   unscoped_specified_t ValidPositiveValue1 = static_cast<unscoped_specified_t>(1); // OK.
67   unscoped_specified_t ValidPositiveValue2 = static_cast<unscoped_specified_t>(2); // OK.
68   unscoped_specified_t InvalidInsideRange4 = static_cast<unscoped_specified_t>(3); // expected-warning {{The value '3' provided to the cast expression is not in the valid range of values for 'unscoped_specified_t'}}
69   unscoped_specified_t ValidPositiveValue3 = static_cast<unscoped_specified_t>(4); // OK.
70   unscoped_specified_t InvalidAfterRangeEnd = static_cast<unscoped_specified_t>(5); // expected-warning {{The value '5' provided to the cast expression is not in the valid range of values for 'unscoped_specified_t'}}
71 }
72 
scopedUnspecified()73 void scopedUnspecified() {
74   scoped_unspecified_t InvalidBeforeRangeBegin = static_cast<scoped_unspecified_t>(-5); // expected-warning{{The value '-5' provided to the cast expression is not in the valid range of values for 'scoped_unspecified_t'}}
75   scoped_unspecified_t ValidNegativeValue1 = static_cast<scoped_unspecified_t>(-4); // OK.
76   scoped_unspecified_t ValidNegativeValue2 = static_cast<scoped_unspecified_t>(-3); // OK.
77   scoped_unspecified_t InvalidInsideRange1 = static_cast<scoped_unspecified_t>(-2); // expected-warning {{The value '-2' provided to the cast expression is not in the valid range of values for 'scoped_unspecified_t'}}
78   scoped_unspecified_t InvalidInsideRange2 = static_cast<scoped_unspecified_t>(-1); // expected-warning {{The value '-1' provided to the cast expression is not in the valid range of values for 'scoped_unspecified_t'}}
79   scoped_unspecified_t InvalidInsideRange3 = static_cast<scoped_unspecified_t>(0); // expected-warning {{The value '0' provided to the cast expression is not in the valid range of values for 'scoped_unspecified_t'}}
80   scoped_unspecified_t ValidPositiveValue1 = static_cast<scoped_unspecified_t>(1); // OK.
81   scoped_unspecified_t ValidPositiveValue2 = static_cast<scoped_unspecified_t>(2); // OK.
82   scoped_unspecified_t InvalidInsideRange4 = static_cast<scoped_unspecified_t>(3); // expected-warning {{The value '3' provided to the cast expression is not in the valid range of values for 'scoped_unspecified_t'}}
83   scoped_unspecified_t ValidPositiveValue3 = static_cast<scoped_unspecified_t>(4); // OK.
84   scoped_unspecified_t InvalidAfterRangeEnd = static_cast<scoped_unspecified_t>(5); // expected-warning {{The value '5' provided to the cast expression is not in the valid range of values for 'scoped_unspecified_t'}}
85 }
86 
scopedSpecified()87 void scopedSpecified() {
88   scoped_specified_t InvalidBeforeRangeBegin = static_cast<scoped_specified_t>(-5); // expected-warning {{The value '-5' provided to the cast expression is not in the valid range of values for 'scoped_specified_t'}}
89   scoped_specified_t ValidNegativeValue1 = static_cast<scoped_specified_t>(-4); // OK.
90   scoped_specified_t ValidNegativeValue2 = static_cast<scoped_specified_t>(-3); // OK.
91   scoped_specified_t InvalidInsideRange1 = static_cast<scoped_specified_t>(-2); // expected-warning {{The value '-2' provided to the cast expression is not in the valid range of values for 'scoped_specified_t'}}
92   scoped_specified_t InvalidInsideRange2 = static_cast<scoped_specified_t>(-1); // expected-warning {{The value '-1' provided to the cast expression is not in the valid range of values for 'scoped_specified_t'}}
93   scoped_specified_t InvalidInsideRange3 = static_cast<scoped_specified_t>(0); // expected-warning {{The value '0' provided to the cast expression is not in the valid range of values for 'scoped_specified_t'}}
94   scoped_specified_t ValidPositiveValue1 = static_cast<scoped_specified_t>(1); // OK.
95   scoped_specified_t ValidPositiveValue2 = static_cast<scoped_specified_t>(2); // OK.
96   scoped_specified_t InvalidInsideRange4 = static_cast<scoped_specified_t>(3); // expected-warning {{The value '3' provided to the cast expression is not in the valid range of values for 'scoped_specified_t'}}
97   scoped_specified_t ValidPositiveValue3 = static_cast<scoped_specified_t>(4); // OK.
98   scoped_specified_t InvalidAfterRangeEnd = static_cast<scoped_specified_t>(5); // expected-warning {{The value '5' provided to the cast expression is not in the valid range of values for 'scoped_specified_t'}}
99 }
100 
unscopedUnspecifiedCStyle()101 void unscopedUnspecifiedCStyle() {
102   unscoped_unspecified_t InvalidBeforeRangeBegin = (unscoped_unspecified_t)(-5); // expected-warning {{The value '-5' provided to the cast expression is not in the valid range of values for 'unscoped_unspecified_t'}}
103   unscoped_unspecified_t ValidNegativeValue1 = (unscoped_unspecified_t)(-4); // OK.
104   unscoped_unspecified_t ValidNegativeValue2 = (unscoped_unspecified_t)(-3); // OK.
105   unscoped_unspecified_t InvalidInsideRange1 = (unscoped_unspecified_t)(-2); // expected-warning {{The value '-2' provided to the cast expression is not in the valid range of values for 'unscoped_unspecified_t'}}
106   unscoped_unspecified_t InvalidInsideRange2 = (unscoped_unspecified_t)(-1); // expected-warning {{The value '-1' provided to the cast expression is not in the valid range of values for 'unscoped_unspecified_t'}}
107   unscoped_unspecified_t InvalidInsideRange3 = (unscoped_unspecified_t)(0); // expected-warning {{The value '0' provided to the cast expression is not in the valid range of values for 'unscoped_unspecified_t'}}
108   unscoped_unspecified_t ValidPositiveValue1 = (unscoped_unspecified_t)(1); // OK.
109   unscoped_unspecified_t ValidPositiveValue2 = (unscoped_unspecified_t)(2); // OK.
110   unscoped_unspecified_t InvalidInsideRange4 = (unscoped_unspecified_t)(3); // expected-warning {{The value '3' provided to the cast expression is not in the valid range of values for 'unscoped_unspecified_t'}}
111   unscoped_unspecified_t ValidPositiveValue3 = (unscoped_unspecified_t)(4); // OK.
112   unscoped_unspecified_t InvalidAfterRangeEnd = (unscoped_unspecified_t)(5); // expected-warning {{The value '5' provided to the cast expression is not in the valid range of values for 'unscoped_unspecified_t'}}
113 }
114 
unscopedSpecifiedCStyle()115 void unscopedSpecifiedCStyle() {
116   unscoped_specified_t InvalidBeforeRangeBegin = (unscoped_specified_t)(-5); // expected-warning {{The value '-5' provided to the cast expression is not in the valid range of values for 'unscoped_specified_t'}}
117   unscoped_specified_t ValidNegativeValue1 = (unscoped_specified_t)(-4); // OK.
118   unscoped_specified_t ValidNegativeValue2 = (unscoped_specified_t)(-3); // OK.
119   unscoped_specified_t InvalidInsideRange1 = (unscoped_specified_t)(-2); // expected-warning {{The value '-2' provided to the cast expression is not in the valid range of values for 'unscoped_specified_t'}}
120   unscoped_specified_t InvalidInsideRange2 = (unscoped_specified_t)(-1); // expected-warning {{The value '-1' provided to the cast expression is not in the valid range of values for 'unscoped_specified_t'}}
121   unscoped_specified_t InvalidInsideRange3 = (unscoped_specified_t)(0); // expected-warning {{The value '0' provided to the cast expression is not in the valid range of values for 'unscoped_specified_t'}}
122   unscoped_specified_t ValidPositiveValue1 = (unscoped_specified_t)(1); // OK.
123   unscoped_specified_t ValidPositiveValue2 = (unscoped_specified_t)(2); // OK.
124   unscoped_specified_t InvalidInsideRange4 = (unscoped_specified_t)(3); // expected-warning {{The value '3' provided to the cast expression is not in the valid range of values for 'unscoped_specified_t'}}
125   unscoped_specified_t ValidPositiveValue3 = (unscoped_specified_t)(4); // OK.
126   unscoped_specified_t InvalidAfterRangeEnd = (unscoped_specified_t)(5); // expected-warning {{The value '5' provided to the cast expression is not in the valid range of values for 'unscoped_specified_t'}}
127 }
128 
scopedUnspecifiedCStyle()129 void scopedUnspecifiedCStyle() {
130   scoped_unspecified_t InvalidBeforeRangeBegin = (scoped_unspecified_t)(-5); // expected-warning{{The value '-5' provided to the cast expression is not in the valid range of values for 'scoped_unspecified_t'}}
131   scoped_unspecified_t ValidNegativeValue1 = (scoped_unspecified_t)(-4); // OK.
132   scoped_unspecified_t ValidNegativeValue2 = (scoped_unspecified_t)(-3); // OK.
133   scoped_unspecified_t InvalidInsideRange1 = (scoped_unspecified_t)(-2); // expected-warning {{The value '-2' provided to the cast expression is not in the valid range of values for 'scoped_unspecified_t'}}
134   scoped_unspecified_t InvalidInsideRange2 = (scoped_unspecified_t)(-1); // expected-warning {{The value '-1' provided to the cast expression is not in the valid range of values for 'scoped_unspecified_t'}}
135   scoped_unspecified_t InvalidInsideRange3 = (scoped_unspecified_t)(0); // expected-warning {{The value '0' provided to the cast expression is not in the valid range of values for 'scoped_unspecified_t'}}
136   scoped_unspecified_t ValidPositiveValue1 = (scoped_unspecified_t)(1); // OK.
137   scoped_unspecified_t ValidPositiveValue2 = (scoped_unspecified_t)(2); // OK.
138   scoped_unspecified_t InvalidInsideRange4 = (scoped_unspecified_t)(3); // expected-warning {{The value '3' provided to the cast expression is not in the valid range of values for 'scoped_unspecified_t'}}
139   scoped_unspecified_t ValidPositiveValue3 = (scoped_unspecified_t)(4); // OK.
140   scoped_unspecified_t InvalidAfterRangeEnd = (scoped_unspecified_t)(5); // expected-warning {{The value '5' provided to the cast expression is not in the valid range of values for 'scoped_unspecified_t'}}
141 }
142 
scopedSpecifiedCStyle()143 void scopedSpecifiedCStyle() {
144   scoped_specified_t InvalidBeforeRangeBegin = (scoped_specified_t)(-5); // expected-warning {{The value '-5' provided to the cast expression is not in the valid range of values for 'scoped_specified_t'}}
145   scoped_specified_t ValidNegativeValue1 = (scoped_specified_t)(-4); // OK.
146   scoped_specified_t ValidNegativeValue2 = (scoped_specified_t)(-3); // OK.
147   scoped_specified_t InvalidInsideRange1 = (scoped_specified_t)(-2); // expected-warning {{The value '-2' provided to the cast expression is not in the valid range of values for 'scoped_specified_t'}}
148   scoped_specified_t InvalidInsideRange2 = (scoped_specified_t)(-1); // expected-warning {{The value '-1' provided to the cast expression is not in the valid range of values for 'scoped_specified_t'}}
149   scoped_specified_t InvalidInsideRange3 = (scoped_specified_t)(0); // expected-warning {{The value '0' provided to the cast expression is not in the valid range of values for 'scoped_specified_t'}}
150   scoped_specified_t ValidPositiveValue1 = (scoped_specified_t)(1); // OK.
151   scoped_specified_t ValidPositiveValue2 = (scoped_specified_t)(2); // OK.
152   scoped_specified_t InvalidInsideRange4 = (scoped_specified_t)(3); // expected-warning {{The value '3' provided to the cast expression is not in the valid range of values for 'scoped_specified_t'}}
153   scoped_specified_t ValidPositiveValue3 = (scoped_specified_t)(4); // OK.
154   scoped_specified_t InvalidAfterRangeEnd = (scoped_specified_t)(5); // expected-warning {{The value '5' provided to the cast expression is not in the valid range of values for 'scoped_specified_t'}}
155 }
156 
157 unscoped_unspecified_t unused;
unusedExpr()158 void unusedExpr() {
159   // following line is not something that EnumCastOutOfRangeChecker should evaluate.  checker should either ignore this line
160   // or process it without producing any warnings.  However, compilation will (and should) still generate a warning having
161   // nothing to do with this checker.
162   unused; // expected-warning {{expression result unused}}
163 }
164 
rangeConstrained1(int input)165 void rangeConstrained1(int input) {
166   if (input > -5 && input < 5)
167     auto value = static_cast<scoped_specified_t>(input); // OK. Being conservative, this is a possibly good value.
168 }
169 
rangeConstrained2(int input)170 void rangeConstrained2(int input) {
171   if (input < -5)
172     auto value = static_cast<scoped_specified_t>(input); // expected-warning {{The value provided to the cast expression is not in the valid range of values for 'scoped_specified_t'}}
173 }
174 
rangeConstrained3(int input)175 void rangeConstrained3(int input) {
176   if (input >= -2 && input <= -1)
177     auto value = static_cast<scoped_specified_t>(input); // expected-warning {{The value provided to the cast expression is not in the valid range of values for 'scoped_specified_t'}}
178 }
179 
rangeConstrained4(int input)180 void rangeConstrained4(int input) {
181   if (input >= -2 && input <= 1)
182     auto value = static_cast<scoped_specified_t>(input); // OK. Possibly 1.
183 }
184 
rangeConstrained5(int input)185 void rangeConstrained5(int input) {
186   if (input >= 1 && input <= 2)
187     auto value = static_cast<scoped_specified_t>(input); // OK. Strict inner matching.
188 }
189 
rangeConstrained6(int input)190 void rangeConstrained6(int input) {
191   if (input >= 2 && input <= 4)
192     auto value = static_cast<scoped_specified_t>(input); // OK. The value is possibly 2 or 4, dont warn.
193 }
194 
rangeConstrained7(int input)195 void rangeConstrained7(int input) {
196   if (input >= 3 && input <= 3)
197     auto value = static_cast<scoped_specified_t>(input); // expected-warning {{The value '3' provided to the cast expression is not in the valid range of values for 'scoped_specified_t'}}
198 }
199 
enumBitFieldAssignment()200 void enumBitFieldAssignment() {
201   S s;
202   s.E = static_cast<unscoped_unspecified_t>(4); // OK.
203   s.E = static_cast<unscoped_unspecified_t>(5); // expected-warning {{The value '5' provided to the cast expression is not in the valid range of values for 'unscoped_unspecified_t'}}
204 }
205 
206 
207 enum class empty_unspecified {};
208 
209 enum class empty_specified: char {};
210 
211 enum class empty_specified_unsigned: unsigned char {};
212 
213 void ignore_unused(...);
214 
empty_enums_init_with_zero_should_not_warn()215 void empty_enums_init_with_zero_should_not_warn() {
216   auto eu = static_cast<empty_unspecified>(0); //should always be OK to zero initialize any enum
217   auto ef = static_cast<empty_specified>(0);
218   auto efu = static_cast<empty_specified_unsigned>(0);
219 
220   ignore_unused(eu, ef, efu);
221 }
222 
223 //Test the example from checkers.rst:
224 enum WidgetKind { A=1, B, C, X=99 }; // expected-note {{enum declared here}}
225 
foo()226 void foo() {
227   WidgetKind c = static_cast<WidgetKind>(3);  // OK
228   WidgetKind x = static_cast<WidgetKind>(99); // OK
229   WidgetKind d = static_cast<WidgetKind>(4);  // expected-warning {{The value '4' provided to the cast expression is not in the valid range of values for 'WidgetKind'}}
230 
231   ignore_unused(c, x, d);
232 }
233