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