msg_130.c revision 1.15
11.15Srillig/*	$NetBSD: msg_130.c,v 1.15 2022/06/16 16:58:36 rillig Exp $	*/
21.1Srillig# 3 "msg_130.c"
31.1Srillig
41.5Srillig// Test for message: enum type mismatch: '%s' '%s' '%s' [130]
51.1Srillig
61.7Srillig/* See also msg_241.c, which covers unusual operators on enums. */
71.7Srillig
81.2Srilligenum color {
91.4Srillig	RED	= 1 << 0,
101.4Srillig	GREEN	= 1 << 1,
111.4Srillig	BLUE	= 1 << 2
121.4Srillig};
131.4Srillig
141.4Srilligenum size {
151.4Srillig	SMALL,
161.4Srillig	MEDIUM,
171.4Srillig	LARGE
181.2Srillig};
191.2Srillig
201.2Srilligenum daytime {
211.2Srillig	NIGHT, MORNING, NOON, EVENING
221.2Srillig};
231.2Srillig
241.4Srilligvoid sink(_Bool);
251.4Srillig
261.4Srilligvoid
271.4Srilligexample(_Bool cond, enum color c, enum size s)
281.2Srillig{
291.15Srillig	/* expect+1: warning: enum type mismatch: 'enum color' ':' 'enum daytime' [130] */
301.15Srillig	sink(cond ? GREEN : MORNING);
311.15Srillig	/* expect+1: warning: enum type mismatch: 'enum color' '!=' 'enum size' [130] */
321.15Srillig	sink(c != s);
331.15Srillig	/* expect+1: warning: enum type mismatch: 'enum color' '==' 'enum size' [130] */
341.15Srillig	sink(c == s);
351.4Srillig	sink((c & MEDIUM) != 0);	/* might be useful to warn about */
361.4Srillig	sink((c | MEDIUM) != 0);	/* might be useful to warn about */
371.4Srillig
381.4Srillig	c |= MEDIUM;			/* might be useful to warn about */
391.4Srillig	c &= MEDIUM;			/* might be useful to warn about */
401.4Srillig
411.4Srillig	/* The cast to unsigned is required by GCC at WARNS=6. */
421.4Srillig	c &= ~(unsigned)MEDIUM;		/* might be useful to warn about */
431.2Srillig}
441.6Srillig
451.6Srilligvoid
461.6Srilligswitch_example(enum color c)
471.6Srillig{
481.6Srillig	switch (c) {
491.11Srillig	case EVENING:			/* maybe someday expect: 130 */
501.11Srillig	case LARGE:			/* maybe someday expect: 130 */
511.11Srillig	case 0:				/* maybe someday expect: 130 */
521.6Srillig		sink(1 == 1);
531.6Srillig		break;
541.6Srillig	default:
551.6Srillig		break;
561.6Srillig	}
571.6Srillig}
581.9Srillig
591.9Srillig/*
601.9Srillig * Unnamed enum types can be used as a container for constants, especially
611.9Srillig * since in C90 and C99, even after the declaration 'static const int x = 3',
621.9Srillig * 'x' is not a constant expression.
631.9Srillig */
641.9Srilligenum {
651.9Srillig	sizeof_int = sizeof(int),
661.14Srillig	sizeof_short = sizeof(short)
671.9Srillig};
681.9Srillig
691.9Srilligenum {
701.9Srillig	sizeof_uint = sizeof(unsigned int)
711.9Srillig};
721.9Srillig
731.9Srilligint
741.9Srilligenum_constant_from_unnamed_type(int x)
751.9Srillig{
761.11Srillig	/* using an enum constant as constant-expression */
771.9Srillig	switch (x) {
781.11Srillig	case sizeof_int:
791.9Srillig		return 1;
801.14Srillig	case sizeof_short:
811.9Srillig		return 2;
821.9Srillig	default:
831.9Srillig		break;
841.9Srillig	}
851.9Srillig
861.9Srillig	if (x == sizeof_int)
871.9Srillig		return 4;
881.9Srillig	if (x > sizeof_int)
891.9Srillig		return 5;
901.9Srillig
911.15Srillig	/* FIXME */
921.15Srillig	/* expect+1: warning: enum type mismatch: 'enum <unnamed>' '==' 'enum <unnamed>' [130] */
931.15Srillig	if (sizeof_int == sizeof_uint)
941.9Srillig		return 6;
951.9Srillig
961.15Srillig	/* expect+1: warning: statement not reached [193] */
971.15Srillig	return 0;
981.9Srillig}
991.10Srillig
1001.10Srillig/*
1011.10Srillig * A typical legitimate use case for an anonymous enum type that should not
1021.10Srillig * be mixed with other types is a state machine.
1031.10Srillig *
1041.10Srillig * This example demonstrates that the type of the 'switch' expression can be
1051.10Srillig * an anonymous enum.
1061.10Srillig */
1071.10Srilligvoid
1081.10Srilligstate_machine(const char *str)
1091.10Srillig{
1101.10Srillig	enum {
1111.10Srillig		begin,
1121.10Srillig		seen_letter,
1131.10Srillig		seen_letter_digit,
1141.10Srillig		error
1151.10Srillig	} state = begin;
1161.10Srillig
1171.10Srillig	for (const char *p = str; *p != '\0'; p++) {
1181.10Srillig		switch (state) {
1191.10Srillig		case begin:
1201.10Srillig			state = *p == 'A' ? seen_letter : error;
1211.10Srillig			break;
1221.10Srillig		case seen_letter:
1231.10Srillig			state = *p == '1' ? seen_letter_digit : error;
1241.10Srillig			break;
1251.10Srillig		default:
1261.10Srillig			state = error;
1271.10Srillig		}
1281.10Srillig	}
1291.10Srillig
1301.10Srillig	if (state == 2)			/* might be worth a warning */
1311.10Srillig		return;
1321.15Srillig	/* expect+1: warning: enum type mismatch: 'enum <unnamed>' '==' 'enum <unnamed>' [130] */
1331.15Srillig	if (state == sizeof_int)
1341.10Srillig		return;
1351.10Srillig}
1361.13Srillig
1371.13Srillig/*
1381.13Srillig * For check_case_label_enum, a warning only makes sense if the type of the
1391.13Srillig * enum can actually be specified somehow, either explicitly by using a tag
1401.13Srillig * name or a typedef name, or implicitly by using a variable in a switch
1411.13Srillig * expression.
1421.13Srillig */
1431.13Srillig
1441.13Srilligtypedef enum {
1451.13Srillig	has_typedef = 1001
1461.13Srillig} typedef_name;
1471.13Srillig
1481.13Srilligenum tag_name {
1491.13Srillig	has_tag = 1002
1501.13Srillig};
1511.13Srillig
1521.13Srilligenum {
1531.13Srillig	has_variable = 1003
1541.13Srillig} variable;
1551.13Srillig
1561.13Srilligenum {
1571.13Srillig	inaccessible = 1004
1581.13Srillig};
1591.13Srillig
1601.13Srillig/*
1611.13Srillig * This check is already done by Clang, so it may not be necessary to add it
1621.13Srillig * to lint as well.  Except if there are some cases that Clang didn't
1631.13Srillig * implement.
1641.13Srillig */
1651.13Srilligvoid
1661.13Srilligtest_check_case_label_enum(enum color color)
1671.13Srillig{
1681.13Srillig	switch (color)
1691.13Srillig	{
1701.13Srillig	case has_typedef:
1711.13Srillig	case has_tag:
1721.13Srillig	case has_variable:
1731.13Srillig	case inaccessible:
1741.13Srillig		return;
1751.13Srillig	}
1761.13Srillig}
177