1 /* $NetBSD: msg_130.c,v 1.14 2021/05/25 19:04:07 rillig Exp $ */ 2 # 3 "msg_130.c" 3 4 // Test for message: enum type mismatch: '%s' '%s' '%s' [130] 5 6 /* See also msg_241.c, which covers unusual operators on enums. */ 7 8 enum color { 9 RED = 1 << 0, 10 GREEN = 1 << 1, 11 BLUE = 1 << 2 12 }; 13 14 enum size { 15 SMALL, 16 MEDIUM, 17 LARGE 18 }; 19 20 enum daytime { 21 NIGHT, MORNING, NOON, EVENING 22 }; 23 24 void sink(_Bool); 25 26 void 27 example(_Bool cond, enum color c, enum size s) 28 { 29 sink(cond ? GREEN : MORNING); /* expect: 130 */ 30 31 sink(c != s); /* expect: 130 */ 32 sink(c == s); /* expect: 130 */ 33 sink((c & MEDIUM) != 0); /* might be useful to warn about */ 34 sink((c | MEDIUM) != 0); /* might be useful to warn about */ 35 36 c |= MEDIUM; /* might be useful to warn about */ 37 c &= MEDIUM; /* might be useful to warn about */ 38 39 /* The cast to unsigned is required by GCC at WARNS=6. */ 40 c &= ~(unsigned)MEDIUM; /* might be useful to warn about */ 41 } 42 43 void 44 switch_example(enum color c) 45 { 46 switch (c) { 47 case EVENING: /* maybe someday expect: 130 */ 48 case LARGE: /* maybe someday expect: 130 */ 49 case 0: /* maybe someday expect: 130 */ 50 sink(1 == 1); 51 break; 52 default: 53 break; 54 } 55 } 56 57 /* 58 * Unnamed enum types can be used as a container for constants, especially 59 * since in C90 and C99, even after the declaration 'static const int x = 3', 60 * 'x' is not a constant expression. 61 */ 62 enum { 63 sizeof_int = sizeof(int), 64 sizeof_short = sizeof(short) 65 }; 66 67 enum { 68 sizeof_uint = sizeof(unsigned int) 69 }; 70 71 int 72 enum_constant_from_unnamed_type(int x) 73 { 74 /* using an enum constant as constant-expression */ 75 switch (x) { 76 case sizeof_int: 77 return 1; 78 case sizeof_short: 79 return 2; 80 default: 81 break; 82 } 83 84 if (x == sizeof_int) 85 return 4; 86 if (x > sizeof_int) 87 return 5; 88 89 if (sizeof_int == sizeof_uint) /* expect: 130 *//* FIXME */ 90 return 6; 91 92 return 0; /* expect: statement not reached */ 93 } 94 95 /* 96 * A typical legitimate use case for an anonymous enum type that should not 97 * be mixed with other types is a state machine. 98 * 99 * This example demonstrates that the type of the 'switch' expression can be 100 * an anonymous enum. 101 */ 102 void 103 state_machine(const char *str) 104 { 105 enum { 106 begin, 107 seen_letter, 108 seen_letter_digit, 109 error 110 } state = begin; 111 112 for (const char *p = str; *p != '\0'; p++) { 113 switch (state) { 114 case begin: 115 state = *p == 'A' ? seen_letter : error; 116 break; 117 case seen_letter: 118 state = *p == '1' ? seen_letter_digit : error; 119 break; 120 default: 121 state = error; 122 } 123 } 124 125 if (state == 2) /* might be worth a warning */ 126 return; 127 if (state == sizeof_int) /* expect: 130 */ 128 return; 129 } 130 131 /* 132 * For check_case_label_enum, a warning only makes sense if the type of the 133 * enum can actually be specified somehow, either explicitly by using a tag 134 * name or a typedef name, or implicitly by using a variable in a switch 135 * expression. 136 */ 137 138 typedef enum { 139 has_typedef = 1001 140 } typedef_name; 141 142 enum tag_name { 143 has_tag = 1002 144 }; 145 146 enum { 147 has_variable = 1003 148 } variable; 149 150 enum { 151 inaccessible = 1004 152 }; 153 154 /* 155 * This check is already done by Clang, so it may not be necessary to add it 156 * to lint as well. Except if there are some cases that Clang didn't 157 * implement. 158 */ 159 void 160 test_check_case_label_enum(enum color color) 161 { 162 switch (color) 163 { 164 case has_typedef: 165 case has_tag: 166 case has_variable: 167 case inaccessible: 168 return; 169 } 170 } 171