NetBSD/tests/usr.bin/xlint/lint1/msg_130.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;
}
}