11.17Srillig/*	$NetBSD: msg_130.c,v 1.17 2024/11/13 04:32:49 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.16Srillig/* lint1-extra-flags: -X 351 */
91.16Srillig
101.2Srilligenum color {
111.4Srillig	RED	= 1 << 0,
121.4Srillig	GREEN	= 1 << 1,
131.4Srillig	BLUE	= 1 << 2
141.4Srillig};
151.4Srillig
161.4Srilligenum size {
171.4Srillig	SMALL,
181.4Srillig	MEDIUM,
191.4Srillig	LARGE
201.2Srillig};
211.2Srillig
221.2Srilligenum daytime {
231.2Srillig	NIGHT, MORNING, NOON, EVENING
241.2Srillig};
251.2Srillig
261.4Srilligvoid sink(_Bool);
271.4Srillig
281.4Srilligvoid
291.4Srilligexample(_Bool cond, enum color c, enum size s)
301.2Srillig{
311.15Srillig	/* expect+1: warning: enum type mismatch: 'enum color' ':' 'enum daytime' [130] */
321.15Srillig	sink(cond ? GREEN : MORNING);
331.15Srillig	/* expect+1: warning: enum type mismatch: 'enum color' '!=' 'enum size' [130] */
341.15Srillig	sink(c != s);
351.15Srillig	/* expect+1: warning: enum type mismatch: 'enum color' '==' 'enum size' [130] */
361.15Srillig	sink(c == s);
371.4Srillig	sink((c & MEDIUM) != 0);	/* might be useful to warn about */
381.4Srillig	sink((c | MEDIUM) != 0);	/* might be useful to warn about */
391.4Srillig
401.4Srillig	c |= MEDIUM;			/* might be useful to warn about */
411.4Srillig	c &= MEDIUM;			/* might be useful to warn about */
421.4Srillig
431.4Srillig	/* The cast to unsigned is required by GCC at WARNS=6. */
441.4Srillig	c &= ~(unsigned)MEDIUM;		/* might be useful to warn about */
451.2Srillig}
461.6Srillig
471.6Srilligvoid
481.6Srilligswitch_example(enum color c)
491.6Srillig{
501.6Srillig	switch (c) {
511.11Srillig	case EVENING:			/* maybe someday expect: 130 */
521.11Srillig	case LARGE:			/* maybe someday expect: 130 */
531.11Srillig	case 0:				/* maybe someday expect: 130 */
541.6Srillig		sink(1 == 1);
551.6Srillig		break;
561.6Srillig	default:
571.6Srillig		break;
581.6Srillig	}
591.6Srillig}
601.9Srillig
611.9Srillig/*
621.9Srillig * Unnamed enum types can be used as a container for constants, especially
631.9Srillig * since in C90 and C99, even after the declaration 'static const int x = 3',
641.9Srillig * 'x' is not a constant expression.
651.9Srillig */
661.9Srilligenum {
671.9Srillig	sizeof_int = sizeof(int),
681.14Srillig	sizeof_short = sizeof(short)
691.9Srillig};
701.9Srillig
711.9Srilligenum {
721.9Srillig	sizeof_uint = sizeof(unsigned int)
731.9Srillig};
741.9Srillig
751.9Srilligint
761.9Srilligenum_constant_from_unnamed_type(int x)
771.9Srillig{
781.11Srillig	/* using an enum constant as constant-expression */
791.9Srillig	switch (x) {
801.11Srillig	case sizeof_int:
811.9Srillig		return 1;
821.14Srillig	case sizeof_short:
831.9Srillig		return 2;
841.9Srillig	default:
851.9Srillig		break;
861.9Srillig	}
871.9Srillig
881.9Srillig	if (x == sizeof_int)
891.9Srillig		return 4;
901.9Srillig	if (x > sizeof_int)
911.9Srillig		return 5;
921.9Srillig
931.15Srillig	/* FIXME */
941.15Srillig	/* expect+1: warning: enum type mismatch: 'enum <unnamed>' '==' 'enum <unnamed>' [130] */
951.15Srillig	if (sizeof_int == sizeof_uint)
961.9Srillig		return 6;
971.9Srillig
981.17Srillig	/* expect+1: warning: 'return' statement not reached [193] */
991.15Srillig	return 0;
1001.9Srillig}
1011.10Srillig
1021.10Srillig/*
1031.10Srillig * A typical legitimate use case for an anonymous enum type that should not
1041.10Srillig * be mixed with other types is a state machine.
1051.10Srillig *
1061.10Srillig * This example demonstrates that the type of the 'switch' expression can be
1071.10Srillig * an anonymous enum.
1081.10Srillig */
1091.10Srilligvoid
1101.10Srilligstate_machine(const char *str)
1111.10Srillig{
1121.10Srillig	enum {
1131.10Srillig		begin,
1141.10Srillig		seen_letter,
1151.10Srillig		seen_letter_digit,
1161.10Srillig		error
1171.10Srillig	} state = begin;
1181.10Srillig
1191.10Srillig	for (const char *p = str; *p != '\0'; p++) {
1201.10Srillig		switch (state) {
1211.10Srillig		case begin:
1221.10Srillig			state = *p == 'A' ? seen_letter : error;
1231.10Srillig			break;
1241.10Srillig		case seen_letter:
1251.10Srillig			state = *p == '1' ? seen_letter_digit : error;
1261.10Srillig			break;
1271.10Srillig		default:
1281.10Srillig			state = error;
1291.10Srillig		}
1301.10Srillig	}
1311.10Srillig
1321.10Srillig	if (state == 2)			/* might be worth a warning */
1331.10Srillig		return;
1341.15Srillig	/* expect+1: warning: enum type mismatch: 'enum <unnamed>' '==' 'enum <unnamed>' [130] */
1351.15Srillig	if (state == sizeof_int)
1361.10Srillig		return;
1371.10Srillig}
1381.13Srillig
1391.13Srillig/*
1401.13Srillig * For check_case_label_enum, a warning only makes sense if the type of the
1411.13Srillig * enum can actually be specified somehow, either explicitly by using a tag
1421.13Srillig * name or a typedef name, or implicitly by using a variable in a switch
1431.13Srillig * expression.
1441.13Srillig */
1451.13Srillig
1461.13Srilligtypedef enum {
1471.13Srillig	has_typedef = 1001
1481.13Srillig} typedef_name;
1491.13Srillig
1501.13Srilligenum tag_name {
1511.13Srillig	has_tag = 1002
1521.13Srillig};
1531.13Srillig
1541.13Srilligenum {
1551.13Srillig	has_variable = 1003
1561.13Srillig} variable;
1571.13Srillig
1581.13Srilligenum {
1591.13Srillig	inaccessible = 1004
1601.13Srillig};
1611.13Srillig
1621.13Srillig/*
1631.13Srillig * This check is already done by Clang, so it may not be necessary to add it
1641.13Srillig * to lint as well.  Except if there are some cases that Clang didn't
1651.13Srillig * implement.
1661.13Srillig */
1671.13Srilligvoid
1681.13Srilligtest_check_case_label_enum(enum color color)
1691.13Srillig{
1701.13Srillig	switch (color)
1711.13Srillig	{
1721.13Srillig	case has_typedef:
1731.13Srillig	case has_tag:
1741.13Srillig	case has_variable:
1751.13Srillig	case inaccessible:
1761.13Srillig		return;
1771.13Srillig	}
1781.13Srillig}
179