Module Name:    src
Committed By:   rillig
Date:           Sat May 15 19:12:15 UTC 2021

Modified Files:
        src/tests/usr.bin/xlint/lint1: Makefile expr_range.c
        src/usr.bin/xlint/lint1: func.c lint1.h

Log Message:
lint: warn about unreachable case labels for '&&'

See octeon_gmxreg.h 1.2 from 2020-06-18 for an example, where
RXN_RX_INBND_SPEED was cleaned up without adjusting the corresponding
code in octeon_gmx.c.


To generate a diff of this commit:
cvs rdiff -u -r1.56 -r1.57 src/tests/usr.bin/xlint/lint1/Makefile
cvs rdiff -u -r1.1 -r1.2 src/tests/usr.bin/xlint/lint1/expr_range.c
cvs rdiff -u -r1.107 -r1.108 src/usr.bin/xlint/lint1/func.c
cvs rdiff -u -r1.100 -r1.101 src/usr.bin/xlint/lint1/lint1.h

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/Makefile
diff -u src/tests/usr.bin/xlint/lint1/Makefile:1.56 src/tests/usr.bin/xlint/lint1/Makefile:1.57
--- src/tests/usr.bin/xlint/lint1/Makefile:1.56	Fri May 14 21:14:55 2021
+++ src/tests/usr.bin/xlint/lint1/Makefile	Sat May 15 19:12:14 2021
@@ -1,4 +1,4 @@
-# $NetBSD: Makefile,v 1.56 2021/05/14 21:14:55 rillig Exp $
+# $NetBSD: Makefile,v 1.57 2021/05/15 19:12:14 rillig Exp $
 
 NOMAN=		# defined
 MAX_MESSAGE=	343		# see lint1/err.c
@@ -104,6 +104,7 @@ FILES+=		emit.c
 FILES+=		emit.exp
 FILES+=		emit.ln
 FILES+=		expr_range.c
+FILES+=		expr_range.exp
 FILES+=		feat_stacktrace.c
 FILES+=		feat_stacktrace.exp
 FILES+=		gcc_attribute.c

Index: src/tests/usr.bin/xlint/lint1/expr_range.c
diff -u src/tests/usr.bin/xlint/lint1/expr_range.c:1.1 src/tests/usr.bin/xlint/lint1/expr_range.c:1.2
--- src/tests/usr.bin/xlint/lint1/expr_range.c:1.1	Fri May 14 21:14:55 2021
+++ src/tests/usr.bin/xlint/lint1/expr_range.c	Sat May 15 19:12:14 2021
@@ -1,37 +1,43 @@
-/*	$NetBSD: expr_range.c,v 1.1 2021/05/14 21:14:55 rillig Exp $	*/
+/*	$NetBSD: expr_range.c,v 1.2 2021/05/15 19:12:14 rillig Exp $	*/
 # 3 "expr_range.c"
 
 /*
- * Test whether lint can detect switch branches that are impossible to reach.
- * As of 2021-05-14, it cannot.  To do this, it would need to keep track of
- * the possible values of each variable or expression.  To do this reliably,
- * it would also need accurate control flow analysis, which as of 2021-05-14
- * works only for functions without 'goto'.
+ * In a switch statement that has (expr & constant) as the controlling
+ * expression, complain if one of the case branches is unreachable because
+ * the case label does can never match the controlling expression.
  *
- * GCC 10 does not complain the unreachable branch.  It knows that the branch
- * is unreachable though since it doesn't generate any code for it.  GCC once
- * had the option -Wunreachable-code, but that option was made a no-op in
- * 2011.
+ * GCC 10 does not complain about the unreachable branch.  It knows that the
+ * branch is unreachable though since it doesn't generate any code for it.
+ * GCC once had the option -Wunreachable-code, but that option was made a
+ * no-op in 2011.
  *
  * Clang 10 does not complain about this either, and just like GCC it doesn't
  * generate any code for this branch.  The code for tracking an expression's
  * possible values may be related to RangeConstraintManager, just guessing.
- *
- * There should be at least one static analysis tool that warns about this.
  */
 
 /* lint1-extra-flags: -chap */
 
+void println(const char *);
+
 void
 example(unsigned x)
 {
 	switch (x & 6) {
-	case 1:
-		/* This branch is unreachable. */
-		printf("one\n");
+	case 0:
+		println("0 is reachable");
+		break;
+	case 1:			/* expect: statement not reached */
+		println("1 is not reachable");
 		break;
 	case 2:
-		printf("two\n");
+		println("2 is reachable");
+		break;
+	case 6:
+		println("6 is reachable");
+		break;
+	case 7:			/* expect: statement not reached */
+		println("7 is not reachable");
 		break;
 	}
 }

Index: src/usr.bin/xlint/lint1/func.c
diff -u src/usr.bin/xlint/lint1/func.c:1.107 src/usr.bin/xlint/lint1/func.c:1.108
--- src/usr.bin/xlint/lint1/func.c:1.107	Mon May  3 07:08:54 2021
+++ src/usr.bin/xlint/lint1/func.c	Sat May 15 19:12:14 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: func.c,v 1.107 2021/05/03 07:08:54 rillig Exp $	*/
+/*	$NetBSD: func.c,v 1.108 2021/05/15 19:12:14 rillig Exp $	*/
 
 /*
  * Copyright (c) 1994, 1995 Jochen Pohl
@@ -37,7 +37,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID) && !defined(lint)
-__RCSID("$NetBSD: func.c,v 1.107 2021/05/03 07:08:54 rillig Exp $");
+__RCSID("$NetBSD: func.c,v 1.108 2021/05/15 19:12:14 rillig Exp $");
 #endif
 
 #include <stdlib.h>
@@ -440,6 +440,25 @@ named_label(sym_t *sym)
 }
 
 static void
+check_case_label_bitand(const tnode_t *case_expr, const tnode_t *switch_expr)
+{
+	uint64_t case_value, mask;
+
+	if (switch_expr->tn_op != BITAND ||
+	    switch_expr->tn_right->tn_op != CON)
+		return;
+
+	lint_assert(case_expr->tn_op == CON);
+	case_value = case_expr->tn_val->v_quad;
+	mask = switch_expr->tn_right->tn_val->v_quad;
+
+	if ((case_value & ~mask) != 0) {
+		/* statement not reached */
+		warning(193);
+	}
+}
+
+static void
 check_case_label_enum(const tnode_t *tn, const cstk_t *ci)
 {
 	/* similar to typeok_enum in tree.c */
@@ -483,6 +502,7 @@ check_case_label(tnode_t *tn, cstk_t *ci
 		return;
 	}
 
+	check_case_label_bitand(tn, ci->c_switch_expr);
 	check_case_label_enum(tn, ci);
 
 	lint_assert(ci->c_switch_type != NULL);
@@ -694,12 +714,16 @@ switch1(tnode_t *tn)
 		tp->t_tspec = INT;
 	}
 
+	/* leak the memory, for check_case_label_bitand */
+	expr_save_memory();
+
 	check_getopt_begin_switch();
-	expr(tn, true, false, true, false);
+	expr(tn, true, false, false, false);
 
 	begin_control_statement(CS_SWITCH);
 	cstmt->c_switch = true;
 	cstmt->c_switch_type = tp;
+	cstmt->c_switch_expr = tn;
 
 	set_reached(false);
 	seen_fallthrough = true;

Index: src/usr.bin/xlint/lint1/lint1.h
diff -u src/usr.bin/xlint/lint1/lint1.h:1.100 src/usr.bin/xlint/lint1/lint1.h:1.101
--- src/usr.bin/xlint/lint1/lint1.h:1.100	Sun Apr 18 17:47:32 2021
+++ src/usr.bin/xlint/lint1/lint1.h	Sat May 15 19:12:14 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: lint1.h,v 1.100 2021/04/18 17:47:32 rillig Exp $ */
+/* $NetBSD: lint1.h,v 1.101 2021/05/15 19:12:14 rillig Exp $ */
 
 /*
  * Copyright (c) 1996 Christopher G. Demetriou.  All Rights Reserved.
@@ -416,6 +416,7 @@ typedef struct control_statement {
 	bool	c_had_return_value : 1;	/* had "return expr;" */
 
 	type_t	*c_switch_type;		/* type of switch expression */
+	tnode_t	*c_switch_expr;
 	case_label_t *c_case_labels;	/* list of case values */
 
 	struct	memory_block *c_for_expr3_mem; /* saved memory for end of loop

Reply via email to