lint: in strict bool mode, allow do-while-0

Even though 0 is not a boolean constant, allow this common idiom, to
help in those cases where the C preprocessor used by lint does not mark
tokens as coming from system headers (Clang).
This commit is contained in:
rillig 2024-05-12 12:28:34 +00:00
parent 805a7e0567
commit 681c37d9da
5 changed files with 34 additions and 33 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: d_c99_bool_strict.c,v 1.49 2024/05/12 11:46:14 rillig Exp $ */
/* $NetBSD: d_c99_bool_strict.c,v 1.50 2024/05/12 12:28:35 rillig Exp $ */
# 3 "d_c99_bool_strict.c"
/*
@ -476,7 +476,6 @@ strict_bool_controlling_expression(bool b, int i, double d, const void *p)
// or nowhere.
/* expect+1: warning: loop not entered at top [207] */
do {
/* expect+1: error: controlling expression must be bool, not 'int' [333] */
} while (0);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: d_c99_bool_strict_syshdr.c,v 1.23 2024/05/12 11:46:14 rillig Exp $ */
/* $NetBSD: d_c99_bool_strict_syshdr.c,v 1.24 2024/05/12 12:28:35 rillig Exp $ */
# 3 "d_c99_bool_strict_syshdr.c"
/*
@ -17,33 +17,33 @@ extern const unsigned short *ctype_table;
extern void println(const char *);
/*
* On NetBSD 8, <sys/select.h> defines FD_ISSET by enclosing the statements
* in the well-known 'do { ... } while (CONSTCOND 0)' loop. The 0 in the
* controlling expression has type INT but should be allowed nevertheless
* since that header does not have a way to distinguish between bool and int.
* It just follows the C99 standard, unlike the lint-provided stdbool.h,
* which redefines 'false' to '__lint_false'.
* No matter whether the code is from a system header or not, the idiom
* 'do { ... } while (0)' is well known, and using the integer constant 0
* instead of the boolean constant 'false' neither creates any type confusion
* nor does its value take place in any conversions, as its scope is limited
* to the controlling expression of the loop.
*/
void
strict_bool_system_header_statement_macro(void)
statement_macro(void)
{
do {
println("nothing");
} while (/*CONSTCOND*/0);
/* expect-1: error: controlling expression must be bool, not 'int' [333] */
# 38 "d_c99_bool_strict_syshdr.c" 3 4
do {
println("nothing");
} while (/*CONSTCOND*/0); /* ok */
# 43 "d_c99_bool_strict_syshdr.c"
# 39 "d_c99_bool_strict_syshdr.c" 3 4
do {
println("nothing");
} while (/*CONSTCOND*/0);
# 44 "d_c99_bool_strict_syshdr.c"
do {
println("nothing");
} while (/*CONSTCOND*/0);
/* expect-1: error: controlling expression must be bool, not 'int' [333] */
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: ckbool.c,v 1.30 2024/03/09 13:54:47 rillig Exp $ */
/* $NetBSD: ckbool.c,v 1.31 2024/05/12 12:28:34 rillig Exp $ */
/*-
* Copyright (c) 2021 The NetBSD Foundation, Inc.
@ -36,7 +36,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID)
__RCSID("$NetBSD: ckbool.c,v 1.30 2024/03/09 13:54:47 rillig Exp $");
__RCSID("$NetBSD: ckbool.c,v 1.31 2024/05/12 12:28:34 rillig Exp $");
#endif
#include <string.h>
@ -149,7 +149,7 @@ typeok_scalar_strict_bool(op_t op, const mod_t *mp, int arg,
if (mp->m_compares_with_zero) {
bool binary = mp->m_binary;
bool lbool = is_typeok_bool_compares_with_zero(ln);
bool lbool = is_typeok_bool_compares_with_zero(ln, false);
bool ok = true;
if (!binary && !lbool) {
@ -163,7 +163,7 @@ typeok_scalar_strict_bool(op_t op, const mod_t *mp, int arg,
ok = false;
}
if (binary && op != QUEST &&
!is_typeok_bool_compares_with_zero(rn)) {
!is_typeok_bool_compares_with_zero(rn, false)) {
/* right operand of '%s' must be bool, not '%s' */
error(332, op_name(op), tspec_name(rt));
ok = false;
@ -198,7 +198,7 @@ typeok_scalar_strict_bool(op_t op, const mod_t *mp, int arg,
}
bool
is_typeok_bool_compares_with_zero(const tnode_t *tn)
is_typeok_bool_compares_with_zero(const tnode_t *tn, bool is_do_while)
{
while (tn->tn_op == COMMA)
tn = tn->u.ops.right;
@ -206,6 +206,7 @@ is_typeok_bool_compares_with_zero(const tnode_t *tn)
return tn->tn_type->t_tspec == BOOL
|| tn->tn_op == BITAND
|| (is_do_while && is_int_constant_zero(tn, tn->tn_type->t_tspec))
|| (tn->tn_sys && is_scalar(tn->tn_type->t_tspec));
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: externs1.h,v 1.227 2024/05/12 08:48:36 rillig Exp $ */
/* $NetBSD: externs1.h,v 1.228 2024/05/12 12:28:34 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@ -288,7 +288,7 @@ tnode_t *build_binary(tnode_t *, op_t, bool, tnode_t *);
tnode_t *build_unary(op_t, bool, tnode_t *);
tnode_t *build_member_access(tnode_t *, op_t, bool, sbuf_t *);
tnode_t *cconv(tnode_t *);
bool is_typeok_bool_compares_with_zero(const tnode_t *);
bool is_typeok_bool_compares_with_zero(const tnode_t *, bool);
bool typeok(op_t, int, const tnode_t *, const tnode_t *);
tnode_t *promote(op_t, bool, tnode_t *);
tnode_t *convert(op_t, int, type_t *, tnode_t *);

View File

@ -1,4 +1,4 @@
/* $NetBSD: func.c,v 1.186 2024/03/29 08:35:32 rillig Exp $ */
/* $NetBSD: func.c,v 1.187 2024/05/12 12:28:34 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@ -37,7 +37,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID)
__RCSID("$NetBSD: func.c,v 1.186 2024/03/29 08:35:32 rillig Exp $");
__RCSID("$NetBSD: func.c,v 1.187 2024/05/12 12:28:34 rillig Exp $");
#endif
#include <stdlib.h>
@ -548,7 +548,7 @@ default_label(void)
}
static tnode_t *
check_controlling_expression(tnode_t *tn)
check_controlling_expression(tnode_t *tn, bool is_do_while)
{
tn = cconv(tn);
if (tn != NULL)
@ -563,7 +563,8 @@ check_controlling_expression(tnode_t *tn)
return NULL;
}
if (tn != NULL && Tflag && !is_typeok_bool_compares_with_zero(tn)) {
if (tn != NULL && Tflag
&& !is_typeok_bool_compares_with_zero(tn, is_do_while)) {
/* controlling expression must be bool, not '%s' */
error(333, tn->tn_type->t_is_enum ? type_name(tn->tn_type)
: tspec_name(tn->tn_type->t_tspec));
@ -576,7 +577,7 @@ void
stmt_if_expr(tnode_t *tn)
{
if (tn != NULL)
tn = check_controlling_expression(tn);
tn = check_controlling_expression(tn, false);
if (tn != NULL)
expr(tn, false, true, false, false);
begin_control_statement(CS_IF);
@ -721,7 +722,7 @@ stmt_while_expr(tnode_t *tn)
}
if (tn != NULL)
tn = check_controlling_expression(tn);
tn = check_controlling_expression(tn, false);
begin_control_statement(CS_WHILE);
cstmt->c_loop = true;
@ -762,7 +763,7 @@ stmt_do_while_expr(tnode_t *tn)
set_reached(true);
if (tn != NULL)
tn = check_controlling_expression(tn);
tn = check_controlling_expression(tn, true);
if (tn != NULL && tn->tn_op == CON) {
cstmt->c_maybe_endless = constant_is_nonzero(tn);
@ -811,7 +812,7 @@ stmt_for_exprs(tnode_t *tn1, tnode_t *tn2, tnode_t *tn3)
expr(tn1, false, false, true, false);
if (tn2 != NULL)
tn2 = check_controlling_expression(tn2);
tn2 = check_controlling_expression(tn2, false);
if (tn2 != NULL)
expr(tn2, false, true, true, false);