xref: /netbsd-src/tests/usr.bin/xlint/lint1/msg_130.c (revision 6937eff333b197fb14840f0e58df0f7a0edfd51a)
1 /*	$NetBSD: msg_130.c,v 1.17 2024/11/13 04:32:49 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 
10 enum color {
11 	RED	= 1 << 0,
12 	GREEN	= 1 << 1,
13 	BLUE	= 1 << 2
14 };
15 
16 enum size {
17 	SMALL,
18 	MEDIUM,
19 	LARGE
20 };
21 
22 enum daytime {
23 	NIGHT, MORNING, NOON, EVENING
24 };
25 
26 void sink(_Bool);
27 
28 void
29 example(_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 
47 void
48 switch_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  */
66 enum {
67 	sizeof_int = sizeof(int),
68 	sizeof_short = sizeof(short)
69 };
70 
71 enum {
72 	sizeof_uint = sizeof(unsigned int)
73 };
74 
75 int
76 enum_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: 'return' 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  */
109 void
110 state_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 
146 typedef enum {
147 	has_typedef = 1001
148 } typedef_name;
149 
150 enum tag_name {
151 	has_tag = 1002
152 };
153 
154 enum {
155 	has_variable = 1003
156 } variable;
157 
158 enum {
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  */
167 void
168 test_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