Module Name:    src
Committed By:   rillig
Date:           Mon Nov  1 11:46:50 UTC 2021

Modified Files:
        src/tests/usr.bin/xlint/lint1: msg_348.c msg_348.exp
        src/usr.bin/xlint/lint1: tree.c

Log Message:
lint: in the check for array[enum], allow enum constant NUM

When an enum type defines a constant NUM_VALUES, this constant is
usually not part of the enum values available to the application but
rather a handy place for defining the number of other enum values. Don't
warn about this case.

Seen in openpam_impl.h and several other places.


To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.3 src/tests/usr.bin/xlint/lint1/msg_348.c \
    src/tests/usr.bin/xlint/lint1/msg_348.exp
cvs rdiff -u -r1.388 -r1.389 src/usr.bin/xlint/lint1/tree.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/tests/usr.bin/xlint/lint1/msg_348.c
diff -u src/tests/usr.bin/xlint/lint1/msg_348.c:1.2 src/tests/usr.bin/xlint/lint1/msg_348.c:1.3
--- src/tests/usr.bin/xlint/lint1/msg_348.c:1.2	Sun Oct 31 23:15:44 2021
+++ src/tests/usr.bin/xlint/lint1/msg_348.c	Mon Nov  1 11:46:50 2021
@@ -1,11 +1,16 @@
-/*	$NetBSD: msg_348.c,v 1.2 2021/10/31 23:15:44 rillig Exp $	*/
+/*	$NetBSD: msg_348.c,v 1.3 2021/11/01 11:46:50 rillig Exp $	*/
 # 3 "msg_348.c"
 
 // Test for message 348: maximum value %d of '%s' does not match maximum array index %d [348]
 
+/* lint1-extra-flags: -r */
+
 enum color {
 	red,
 	green,
+	/* expect+3: previous declaration of blue [260] */
+	/* expect+2: previous declaration of blue [260] */
+	/* expect+1: previous declaration of blue [260] */
 	blue
 };
 
@@ -115,3 +120,46 @@ large_name(enum large large)
 	/* No warning since at least 1 enum constant is outside of INT. */
 	return name[large];
 }
+
+enum color_with_count {
+	cc_red,
+	cc_green,
+	cc_blue,
+	cc_num_values
+};
+
+const char *
+color_with_count_name(enum color_with_count color)
+{
+	static const char *const name[] = { "red", "green", "blue" };
+	/* No warning since the maximum enum constant is a count. */
+	return name[color];
+}
+
+/*
+ * If the last enum constant contains "num" in its name, it is not
+ * necessarily the count of the other enum values, it may also be a
+ * legitimate application value, therefore don't warn in this case.
+ */
+const char *
+color_with_num(enum color_with_count color)
+{
+	static const char *const name[] = { "r", "g", "b", "num" };
+	/* No warning since the maximum values already match. */
+	return name[color];
+}
+
+enum color_with_uc_count {
+	CC_RED,
+	CC_GREEN,
+	CC_BLUE,
+	CC_NUM_VALUES
+};
+
+const char *
+color_with_uc_count_name(enum color_with_uc_count color)
+{
+	static const char *const name[] = { "red", "green", "blue" };
+	/* No warning since the maximum enum constant is a count. */
+	return name[color];
+}
Index: src/tests/usr.bin/xlint/lint1/msg_348.exp
diff -u src/tests/usr.bin/xlint/lint1/msg_348.exp:1.2 src/tests/usr.bin/xlint/lint1/msg_348.exp:1.3
--- src/tests/usr.bin/xlint/lint1/msg_348.exp:1.2	Sun Oct 31 23:15:44 2021
+++ src/tests/usr.bin/xlint/lint1/msg_348.exp	Mon Nov  1 11:46:50 2021
@@ -1,5 +1,8 @@
-msg_348.c(32): warning: maximum value 2 of 'enum color' does not match maximum array index 1 [348]
-msg_348.c(45): warning: maximum value 2 of 'enum color' does not match maximum array index 3 [348]
-msg_348.c(82): warning: maximum value 2 of 'enum color' does not match maximum array index 1 [348]
-msg_348.c(103): warning: integral constant too large [56]
-msg_348.c(105): warning: integral constant too large [56]
+msg_348.c(37): warning: maximum value 2 of 'enum color' does not match maximum array index 1 [348]
+msg_348.c(14): previous declaration of blue [260]
+msg_348.c(50): warning: maximum value 2 of 'enum color' does not match maximum array index 3 [348]
+msg_348.c(14): previous declaration of blue [260]
+msg_348.c(87): warning: maximum value 2 of 'enum color' does not match maximum array index 1 [348]
+msg_348.c(14): previous declaration of blue [260]
+msg_348.c(108): warning: integral constant too large [56]
+msg_348.c(110): warning: integral constant too large [56]

Index: src/usr.bin/xlint/lint1/tree.c
diff -u src/usr.bin/xlint/lint1/tree.c:1.388 src/usr.bin/xlint/lint1/tree.c:1.389
--- src/usr.bin/xlint/lint1/tree.c:1.388	Sun Oct 31 23:15:44 2021
+++ src/usr.bin/xlint/lint1/tree.c	Mon Nov  1 11:46:50 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: tree.c,v 1.388 2021/10/31 23:15:44 rillig Exp $	*/
+/*	$NetBSD: tree.c,v 1.389 2021/11/01 11:46:50 rillig Exp $	*/
 
 /*
  * Copyright (c) 1994, 1995 Jochen Pohl
@@ -37,7 +37,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID) && !defined(lint)
-__RCSID("$NetBSD: tree.c,v 1.388 2021/10/31 23:15:44 rillig Exp $");
+__RCSID("$NetBSD: tree.c,v 1.389 2021/11/01 11:46:50 rillig Exp $");
 #endif
 
 #include <float.h>
@@ -1776,8 +1776,9 @@ check_enum_int_mismatch(op_t op, int arg
 static void
 check_enum_array_index(const tnode_t *ln, const tnode_t *rn)
 {
-	int max_enum_value, max_array_index;
-	const struct sym *ec;
+	int max_array_index;
+	int64_t max_enum_value;
+	const struct sym *ec, *max_ec;
 
 	if (ln->tn_op != ADDR)
 		return;
@@ -1794,22 +1795,34 @@ check_enum_array_index(const tnode_t *ln
 	if (rn->tn_left->tn_type->t_tspec != ENUM)
 		return;
 
-	max_enum_value = INT_MIN;
 	ec = rn->tn_left->tn_type->t_enum->en_first_enumerator;
-	for (; ec != NULL; ec = ec->s_next) {
-		int64_t ev = ec->s_value.v_quad;
-		lint_assert(INT_MIN <= ev && ev <= INT_MAX);
-		if (ev > max_enum_value)
-			max_enum_value = (int)ev;
-	}
+	max_ec = ec;
+	lint_assert(ec != NULL);
+	for (ec = ec->s_next; ec != NULL; ec = ec->s_next)
+		if (ec->s_value.v_quad > max_ec->s_value.v_quad)
+			max_ec = ec;
+
+	max_enum_value = max_ec->s_value.v_quad;
+	lint_assert(INT_MIN <= max_enum_value && max_enum_value <= INT_MAX);
 
 	max_array_index = ln->tn_left->tn_type->t_dim - 1;
 	if (max_enum_value == max_array_index)
 		return;
 
+	/*
+	 * If the largest enum constant is named '*_NUM_*', it is typically
+	 * not part of the allowed enum values but a marker for the number
+	 * of actual enum values.
+	 */
+	if (max_enum_value == max_array_index + 1 &&
+	    (strstr(max_ec->s_name, "NUM") != NULL ||
+	     strstr(max_ec->s_name, "num") != NULL))
+		return;
+
 	/* maximum value %d of '%s' does not match maximum array index %d */
-	warning(348, max_enum_value, type_name(rn->tn_left->tn_type),
+	warning(348, (int)max_enum_value, type_name(rn->tn_left->tn_type),
 	    max_array_index);
+	print_previous_declaration(-1, max_ec);
 }
 
 /*

Reply via email to