179 lines
3.6 KiB
C
179 lines
3.6 KiB
C
/* $NetBSD: msg_130.c,v 1.16 2023/03/28 14:44:34 rillig Exp $ */
|
|
# 3 "msg_130.c"
|
|
|
|
// Test for message: enum type mismatch: '%s' '%s' '%s' [130]
|
|
|
|
/* See also msg_241.c, which covers unusual operators on enums. */
|
|
|
|
/* lint1-extra-flags: -X 351 */
|
|
|
|
enum color {
|
|
RED = 1 << 0,
|
|
GREEN = 1 << 1,
|
|
BLUE = 1 << 2
|
|
};
|
|
|
|
enum size {
|
|
SMALL,
|
|
MEDIUM,
|
|
LARGE
|
|
};
|
|
|
|
enum daytime {
|
|
NIGHT, MORNING, NOON, EVENING
|
|
};
|
|
|
|
void sink(_Bool);
|
|
|
|
void
|
|
example(_Bool cond, enum color c, enum size s)
|
|
{
|
|
/* expect+1: warning: enum type mismatch: 'enum color' ':' 'enum daytime' [130] */
|
|
sink(cond ? GREEN : MORNING);
|
|
/* expect+1: warning: enum type mismatch: 'enum color' '!=' 'enum size' [130] */
|
|
sink(c != s);
|
|
/* expect+1: warning: enum type mismatch: 'enum color' '==' 'enum size' [130] */
|
|
sink(c == s);
|
|
sink((c & MEDIUM) != 0); /* might be useful to warn about */
|
|
sink((c | MEDIUM) != 0); /* might be useful to warn about */
|
|
|
|
c |= MEDIUM; /* might be useful to warn about */
|
|
c &= MEDIUM; /* might be useful to warn about */
|
|
|
|
/* The cast to unsigned is required by GCC at WARNS=6. */
|
|
c &= ~(unsigned)MEDIUM; /* might be useful to warn about */
|
|
}
|
|
|
|
void
|
|
switch_example(enum color c)
|
|
{
|
|
switch (c) {
|
|
case EVENING: /* maybe someday expect: 130 */
|
|
case LARGE: /* maybe someday expect: 130 */
|
|
case 0: /* maybe someday expect: 130 */
|
|
sink(1 == 1);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Unnamed enum types can be used as a container for constants, especially
|
|
* since in C90 and C99, even after the declaration 'static const int x = 3',
|
|
* 'x' is not a constant expression.
|
|
*/
|
|
enum {
|
|
sizeof_int = sizeof(int),
|
|
sizeof_short = sizeof(short)
|
|
};
|
|
|
|
enum {
|
|
sizeof_uint = sizeof(unsigned int)
|
|
};
|
|
|
|
int
|
|
enum_constant_from_unnamed_type(int x)
|
|
{
|
|
/* using an enum constant as constant-expression */
|
|
switch (x) {
|
|
case sizeof_int:
|
|
return 1;
|
|
case sizeof_short:
|
|
return 2;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (x == sizeof_int)
|
|
return 4;
|
|
if (x > sizeof_int)
|
|
return 5;
|
|
|
|
/* FIXME */
|
|
/* expect+1: warning: enum type mismatch: 'enum <unnamed>' '==' 'enum <unnamed>' [130] */
|
|
if (sizeof_int == sizeof_uint)
|
|
return 6;
|
|
|
|
/* expect+1: warning: statement not reached [193] */
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* A typical legitimate use case for an anonymous enum type that should not
|
|
* be mixed with other types is a state machine.
|
|
*
|
|
* This example demonstrates that the type of the 'switch' expression can be
|
|
* an anonymous enum.
|
|
*/
|
|
void
|
|
state_machine(const char *str)
|
|
{
|
|
enum {
|
|
begin,
|
|
seen_letter,
|
|
seen_letter_digit,
|
|
error
|
|
} state = begin;
|
|
|
|
for (const char *p = str; *p != '\0'; p++) {
|
|
switch (state) {
|
|
case begin:
|
|
state = *p == 'A' ? seen_letter : error;
|
|
break;
|
|
case seen_letter:
|
|
state = *p == '1' ? seen_letter_digit : error;
|
|
break;
|
|
default:
|
|
state = error;
|
|
}
|
|
}
|
|
|
|
if (state == 2) /* might be worth a warning */
|
|
return;
|
|
/* expect+1: warning: enum type mismatch: 'enum <unnamed>' '==' 'enum <unnamed>' [130] */
|
|
if (state == sizeof_int)
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* For check_case_label_enum, a warning only makes sense if the type of the
|
|
* enum can actually be specified somehow, either explicitly by using a tag
|
|
* name or a typedef name, or implicitly by using a variable in a switch
|
|
* expression.
|
|
*/
|
|
|
|
typedef enum {
|
|
has_typedef = 1001
|
|
} typedef_name;
|
|
|
|
enum tag_name {
|
|
has_tag = 1002
|
|
};
|
|
|
|
enum {
|
|
has_variable = 1003
|
|
} variable;
|
|
|
|
enum {
|
|
inaccessible = 1004
|
|
};
|
|
|
|
/*
|
|
* This check is already done by Clang, so it may not be necessary to add it
|
|
* to lint as well. Except if there are some cases that Clang didn't
|
|
* implement.
|
|
*/
|
|
void
|
|
test_check_case_label_enum(enum color color)
|
|
{
|
|
switch (color)
|
|
{
|
|
case has_typedef:
|
|
case has_tag:
|
|
case has_variable:
|
|
case inaccessible:
|
|
return;
|
|
}
|
|
}
|