244 lines · cpp
1// RUN: %clang_analyze_cc1 \2// RUN: -analyzer-checker=core,optin.core.EnumCastOutOfRange \3// RUN: -std=c++11 -verify %s4 5// expected-note@+1 + {{enum declared here}}6enum 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 = 412};13 14// expected-note@+1 + {{enum declared here}}15enum 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 = 421};22 23// expected-note@+1 + {{enum declared here}}24enum 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 = 430};31 32// expected-note@+1 + {{enum declared here}}33enum 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 = 439};40 41struct S {42 unscoped_unspecified_t E : 5;43};44 45void 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 59void 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 73void 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 87void 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 101void 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 115void 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 129void 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 143void 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 157unscoped_unspecified_t unused;158void unusedExpr() {159 // following line is not something that EnumCastOutOfRangeChecker should evaluate. checker should either ignore this line160 // or process it without producing any warnings. However, compilation will (and should) still generate a warning having161 // nothing to do with this checker.162 unused; // expected-warning {{expression result unused}}163}164 165void 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 170void 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 175void 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 180void rangeConstrained4(int input) {181 if (input >= -2 && input <= 1)182 auto value = static_cast<scoped_specified_t>(input); // OK. Possibly 1.183}184 185void rangeConstrained5(int input) {186 if (input >= 1 && input <= 2)187 auto value = static_cast<scoped_specified_t>(input); // OK. Strict inner matching.188}189 190void 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 195void 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 200void 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 207enum class empty_unspecified {};208 209enum class empty_specified: char {};210 211enum class empty_specified_unsigned: unsigned char {};212 213void ignore_unused(...);214 215void empty_enums_init_with_zero_should_not_warn() {216 auto eu = static_cast<empty_unspecified>(0); //should always be OK to zero initialize any enum217 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:224enum WidgetKind { A=1, B, C, X=99 }; // expected-note {{enum declared here}}225 226void foo() {227 WidgetKind c = static_cast<WidgetKind>(3); // OK228 WidgetKind x = static_cast<WidgetKind>(99); // OK229 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 234enum [[clang::flag_enum]] FlagEnum {235 FE_BIT_1 = 1 << 0,236 FE_BIT_2 = 1 << 1,237 FE_BIT_3 = 1 << 2,238};239 240void testFlagEnum_gh_76208(void) {241 FlagEnum First2BitsSet = (FlagEnum)(FE_BIT_1 | FE_BIT_2); // no-warning: Enums with the attribute 'flag_enum' are not checked242 (void)First2BitsSet;243}244