Fri Mar 5 17:10:06 2021 UTC ()
lint: warn about enum/enum or enum/int type mismatch in switch

This is something that neither GCC 10 nor Clang 8 do, even though it
seems useful.  Lint didn't do it up to now, but that was probably an
oversight since it is easy to miss the implicit '==' operator in the
switch statement.


(rillig)
diff -r1.7 -r1.8 src/tests/usr.bin/xlint/lint1/msg_130.c
diff -r1.5 -r1.6 src/tests/usr.bin/xlint/lint1/msg_130.exp
diff -r1.74 -r1.75 src/usr.bin/xlint/lint1/func.c

cvs diff -r1.7 -r1.8 src/tests/usr.bin/xlint/lint1/msg_130.c (expand / switch to unified diff)

--- src/tests/usr.bin/xlint/lint1/msg_130.c 2021/03/05 16:35:52 1.7
+++ src/tests/usr.bin/xlint/lint1/msg_130.c 2021/03/05 17:10:06 1.8
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: msg_130.c,v 1.7 2021/03/05 16:35:52 rillig Exp $ */ 1/* $NetBSD: msg_130.c,v 1.8 2021/03/05 17:10:06 rillig Exp $ */
2# 3 "msg_130.c" 2# 3 "msg_130.c"
3 3
4// Test for message: enum type mismatch: '%s' '%s' '%s' [130] 4// Test for message: enum type mismatch: '%s' '%s' '%s' [130]
5 5
6/* See also msg_241.c, which covers unusual operators on enums. */ 6/* See also msg_241.c, which covers unusual operators on enums. */
7 7
8enum color { 8enum color {
9 RED = 1 << 0, 9 RED = 1 << 0,
10 GREEN = 1 << 1, 10 GREEN = 1 << 1,
11 BLUE = 1 << 2 11 BLUE = 1 << 2
12}; 12};
13 13
14enum size { 14enum size {
@@ -34,21 +34,22 @@ example(_Bool cond, enum color c, enum s @@ -34,21 +34,22 @@ example(_Bool cond, enum color c, enum s
34 sink((c | MEDIUM) != 0); /* might be useful to warn about */ 34 sink((c | MEDIUM) != 0); /* might be useful to warn about */
35 35
36 c |= MEDIUM; /* might be useful to warn about */ 36 c |= MEDIUM; /* might be useful to warn about */
37 c &= MEDIUM; /* might be useful to warn about */ 37 c &= MEDIUM; /* might be useful to warn about */
38 38
39 /* The cast to unsigned is required by GCC at WARNS=6. */ 39 /* The cast to unsigned is required by GCC at WARNS=6. */
40 c &= ~(unsigned)MEDIUM; /* might be useful to warn about */ 40 c &= ~(unsigned)MEDIUM; /* might be useful to warn about */
41} 41}
42 42
43void 43void
44switch_example(enum color c) 44switch_example(enum color c)
45{ 45{
46 switch (c) { 46 switch (c) {
47 case EVENING: /* TODO: 130 */ 47 case EVENING: /* expect: 130 */
48 case LARGE: /* TODO: 130 */ 48 case LARGE: /* expect: 130 */
 49 case 0: /* expect: 130 */
49 sink(1 == 1); 50 sink(1 == 1);
50 break; 51 break;
51 default: 52 default:
52 break; 53 break;
53 } 54 }
54} 55}

cvs diff -r1.5 -r1.6 src/tests/usr.bin/xlint/lint1/Attic/msg_130.exp (expand / switch to unified diff)

--- src/tests/usr.bin/xlint/lint1/Attic/msg_130.exp 2021/03/05 16:35:52 1.5
+++ src/tests/usr.bin/xlint/lint1/Attic/msg_130.exp 2021/03/05 17:10:06 1.6
@@ -1,3 +1,6 @@ @@ -1,3 +1,6 @@
1msg_130.c(29): warning: enum type mismatch: 'enum color' ':' 'enum daytime' [130] 1msg_130.c(29): warning: enum type mismatch: 'enum color' ':' 'enum daytime' [130]
2msg_130.c(31): warning: enum type mismatch: 'enum color' '!=' 'enum size' [130] 2msg_130.c(31): warning: enum type mismatch: 'enum color' '!=' 'enum size' [130]
3msg_130.c(32): warning: enum type mismatch: 'enum color' '==' 'enum size' [130] 3msg_130.c(32): warning: enum type mismatch: 'enum color' '==' 'enum size' [130]
 4msg_130.c(47): warning: enum type mismatch: 'enum color' '==' 'enum daytime' [130]
 5msg_130.c(48): warning: enum type mismatch: 'enum color' '==' 'enum size' [130]
 6msg_130.c(49): warning: enum type mismatch: 'enum color' '==' 'int' [130]

cvs diff -r1.74 -r1.75 src/usr.bin/xlint/lint1/func.c (expand / switch to unified diff)

--- src/usr.bin/xlint/lint1/func.c 2021/02/28 19:16:05 1.74
+++ src/usr.bin/xlint/lint1/func.c 2021/03/05 17:10:05 1.75
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: func.c,v 1.74 2021/02/28 19:16:05 rillig Exp $ */ 1/* $NetBSD: func.c,v 1.75 2021/03/05 17:10:05 rillig Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1994, 1995 Jochen Pohl 4 * Copyright (c) 1994, 1995 Jochen Pohl
5 * All Rights Reserved. 5 * All Rights Reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -27,27 +27,27 @@ @@ -27,27 +27,27 @@
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */ 32 */
33 33
34#if HAVE_NBTOOL_CONFIG_H 34#if HAVE_NBTOOL_CONFIG_H
35#include "nbtool_config.h" 35#include "nbtool_config.h"
36#endif 36#endif
37 37
38#include <sys/cdefs.h> 38#include <sys/cdefs.h>
39#if defined(__RCSID) && !defined(lint) 39#if defined(__RCSID) && !defined(lint)
40__RCSID("$NetBSD: func.c,v 1.74 2021/02/28 19:16:05 rillig Exp $"); 40__RCSID("$NetBSD: func.c,v 1.75 2021/03/05 17:10:05 rillig Exp $");
41#endif 41#endif
42 42
43#include <stdlib.h> 43#include <stdlib.h>
44#include <string.h> 44#include <string.h>
45 45
46#include "lint1.h" 46#include "lint1.h"
47#include "cgram.h" 47#include "cgram.h"
48 48
49/* 49/*
50 * Contains a pointer to the symbol table entry of the current function 50 * Contains a pointer to the symbol table entry of the current function
51 * definition. 51 * definition.
52 */ 52 */
53sym_t *funcsym; 53sym_t *funcsym;
@@ -417,51 +417,69 @@ named_label(sym_t *sym) @@ -417,51 +417,69 @@ named_label(sym_t *sym)
417{ 417{
418 418
419 if (sym->s_set) { 419 if (sym->s_set) {
420 /* label %s redefined */ 420 /* label %s redefined */
421 error(194, sym->s_name); 421 error(194, sym->s_name);
422 } else { 422 } else {
423 mark_as_set(sym); 423 mark_as_set(sym);
424 } 424 }
425 425
426 reached = true; 426 reached = true;
427} 427}
428 428
429static void 429static void
 430check_case_label_enum(const tnode_t *tn, const cstk_t *ci)
 431{
 432 /* similar to typeok_enum in tree.c */
 433
 434 if (!(tn->tn_type->t_is_enum || ci->c_swtype->t_is_enum))
 435 return;
 436 if (tn->tn_type->t_is_enum && ci->c_swtype->t_is_enum &&
 437 tn->tn_type->t_enum == ci->c_swtype->t_enum)
 438 return;
 439
 440 /* enum type mismatch: '%s' '%s' '%s' */
 441 warning(130, type_name(ci->c_swtype), getopname(EQ),
 442 type_name(tn->tn_type));
 443}
 444
 445static void
430check_case_label(tnode_t *tn, cstk_t *ci) 446check_case_label(tnode_t *tn, cstk_t *ci)
431{ 447{
432 clst_t *cl; 448 clst_t *cl;
433 val_t *v; 449 val_t *v;
434 val_t nv; 450 val_t nv;
435 tspec_t t; 451 tspec_t t;
436 452
437 if (ci == NULL) { 453 if (ci == NULL) {
438 /* case not in switch */ 454 /* case not in switch */
439 error(195); 455 error(195);
440 return; 456 return;
441 } 457 }
442 458
443 if (tn != NULL && tn->tn_op != CON) { 459 if (tn != NULL && tn->tn_op != CON) {
444 /* non-constant case expression */ 460 /* non-constant case expression */
445 error(197); 461 error(197);
446 return; 462 return;
447 } 463 }
448 464
449 if (tn != NULL && !is_integer(tn->tn_type->t_tspec)) { 465 if (tn != NULL && !is_integer(tn->tn_type->t_tspec)) {
450 /* non-integral case expression */ 466 /* non-integral case expression */
451 error(198); 467 error(198);
452 return; 468 return;
453 } 469 }
454 470
 471 check_case_label_enum(tn, ci);
 472
455 lint_assert(ci->c_swtype != NULL); 473 lint_assert(ci->c_swtype != NULL);
456 474
457 if (reached && !ftflg) { 475 if (reached && !ftflg) {
458 if (hflag) 476 if (hflag)
459 /* fallthrough on case statement */ 477 /* fallthrough on case statement */
460 warning(220); 478 warning(220);
461 } 479 }
462 480
463 t = tn->tn_type->t_tspec; 481 t = tn->tn_type->t_tspec;
464 if (t == LONG || t == ULONG || 482 if (t == LONG || t == ULONG ||
465 t == QUAD || t == UQUAD) { 483 t == QUAD || t == UQUAD) {
466 if (tflag) 484 if (tflag)
467 /* case label must be of type `int' in traditional C */ 485 /* case label must be of type `int' in traditional C */