xref: /netbsd-src/tests/usr.bin/xlint/lint1/msg_130.c (revision 7d62b00eb9ad855ffcd7da46b41e23feb5476fac)
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