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