msg_130.c revision 1.15
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 8enum color { 9 RED = 1 << 0, 10 GREEN = 1 << 1, 11 BLUE = 1 << 2 12}; 13 14enum size { 15 SMALL, 16 MEDIUM, 17 LARGE 18}; 19 20enum daytime { 21 NIGHT, MORNING, NOON, EVENING 22}; 23 24void sink(_Bool); 25 26void 27example(_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 45void 46switch_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 */ 64enum { 65 sizeof_int = sizeof(int), 66 sizeof_short = sizeof(short) 67}; 68 69enum { 70 sizeof_uint = sizeof(unsigned int) 71}; 72 73int 74enum_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 */ 107void 108state_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 144typedef enum { 145 has_typedef = 1001 146} typedef_name; 147 148enum tag_name { 149 has_tag = 1002 150}; 151 152enum { 153 has_variable = 1003 154} variable; 155 156enum { 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 */ 165void 166test_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