Module Name: src
Committed By: rillig
Date: Tue Jan 12 20:42:01 UTC 2021
Modified Files:
src/tests/usr.bin/xlint/lint1: d_c99_bool_strict.c
d_c99_bool_strict.exp
src/usr.bin/xlint/common: externs.h
src/usr.bin/xlint/lint1: cgram.y err.c externs1.h func.c main1.c op.h
oper.c ops.def tree.c
src/usr.bin/xlint/lint2: main2.c
src/usr.bin/xlint/xlint: lint.1 xlint.c
Added Files:
src/tests/usr.bin/xlint: check-expect.lua
Log Message:
lint: add new check for strict bool mode
In strict bool mode, bool is considered incompatible with all other
scalar types, just as in Java, C#, Pascal.
The controlling expressions in if statements, while loops, for loops and
the '?:' operator must be of type bool. The logical operators work on
bool instead of int, the bitwise operators accept both integer and bool.
The arithmetic operators don't accept bool.
Since <stdbool.h> implements bool using C preprocessor macros instead of
predefining the identifiers "true" and "false", the integer constants 0
and 1 may be used in all contexts that require a bool expression.
Except from these, no implicit conversion between bool and scalar types
is allowed.
See usr.bin/tests/xlint/lint1/d_c99_bool_strict.c for more details.
The command line option -T has been chosen because all obvious choices
(-b or -B for bool, -s or -S for strict) are already in use. The -T may
stand for "types are checked strictly".
The default behavior of lint doesn't change. The strict bool check is
purely optional.
An example program for strict bool mode is usr.bin/make, which has been
using explicit comparisons such as p != NULL, ch != '\0' or n > 0 in
most places for a long time now, even before the refactoring in 2020.
To generate a diff of this commit:
cvs rdiff -u -r0 -r1.1 src/tests/usr.bin/xlint/check-expect.lua
cvs rdiff -u -r1.3 -r1.4 src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c
cvs rdiff -u -r1.2 -r1.3 src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.exp
cvs rdiff -u -r1.12 -r1.13 src/usr.bin/xlint/common/externs.h
cvs rdiff -u -r1.138 -r1.139 src/usr.bin/xlint/lint1/cgram.y
cvs rdiff -u -r1.65 -r1.66 src/usr.bin/xlint/lint1/err.c
cvs rdiff -u -r1.54 -r1.55 src/usr.bin/xlint/lint1/externs1.h
cvs rdiff -u -r1.56 -r1.57 src/usr.bin/xlint/lint1/func.c
cvs rdiff -u -r1.33 -r1.34 src/usr.bin/xlint/lint1/main1.c
cvs rdiff -u -r1.11 -r1.12 src/usr.bin/xlint/lint1/op.h
cvs rdiff -u -r1.2 -r1.3 src/usr.bin/xlint/lint1/oper.c
cvs rdiff -u -r1.9 -r1.10 src/usr.bin/xlint/lint1/ops.def
cvs rdiff -u -r1.150 -r1.151 src/usr.bin/xlint/lint1/tree.c
cvs rdiff -u -r1.10 -r1.11 src/usr.bin/xlint/lint2/main2.c
cvs rdiff -u -r1.41 -r1.42 src/usr.bin/xlint/xlint/lint.1
cvs rdiff -u -r1.52 -r1.53 src/usr.bin/xlint/xlint/xlint.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/d_c99_bool_strict.c
diff -u src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c:1.3 src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c:1.4
--- src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c:1.3 Mon Jan 11 00:28:28 2021
+++ src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c Tue Jan 12 20:42:01 2021
@@ -1,9 +1,9 @@
-/* $NetBSD: d_c99_bool_strict.c,v 1.3 2021/01/11 00:28:28 rillig Exp $ */
+/* $NetBSD: d_c99_bool_strict.c,v 1.4 2021/01/12 20:42:01 rillig Exp $ */
# 3 "d_c99_bool_strict.c"
/*
- * Experimental feature: allow to treat _Bool as incompatible with all
- * scalar types. This means:
+ * The option -T treats _Bool as incompatible with all other scalar types.
+ * This means:
*
* SB001: Controlling expressions in 'if', 'while', 'for', '?:' must be of
* type _Bool instead of scalar.
@@ -18,9 +18,9 @@
*
* SB005: There is no implicit conversion from _Bool to any other type.
*
- * SB006: A constant integer expression is compatible with type _Bool if
- * it is an integer constant with value 0 or 1, or if the result type of
- * its main operator is _Bool.
+ * SB006: An expression is compatible with type _Bool if its main operator
+ * returns type _Bool, or if the expression is an integer constant expression
+ * with value 0 or 1.
*
* SB007: Expressions like "flags & FLAG" are compatible with _Bool if
* they appear in a context where they are immediately compared to zero.
@@ -32,7 +32,7 @@
* typically have type _Bool:1 and can be converted to _Bool and back.
*/
-// Not yet implemented: /* lint1-extra-flags: -T */
+/* lint1-extra-flags: -T */
/*
* The header <stdbool.h> defines the macros bool = _Bool, false = 0 and
@@ -61,23 +61,23 @@ SB001_controlling_expression(bool b, int
return;
/* Not allowed: 2 is not a boolean expression. */
- if (/*CONSTCOND*/2)
+ if (/*CONSTCOND*/2) /* expect: 333 */
return;
/* Not allowed: There is no implicit conversion from scalar to bool. */
- if (i)
+ if (i) /* expect: 333 */
return;
if (i != 0)
return;
/* Not allowed: There is no implicit conversion from scalar to bool. */
- if (d)
+ if (d) /* expect: 333 */
return;
if (d != 0.0)
return;
/* Not allowed: There is no implicit conversion from scalar to bool. */
- if (p)
+ if (p) /* expect: 333 */
return;
if (p != (void *)0)
return;
@@ -88,15 +88,15 @@ SB001_controlling_expression(bool b, int
}
void
-SB002_operator_result(bool b)
+SB002_operator_result_type(bool b)
{
b = b;
- char c = b;
- int i = b;
- double d = b;
- void *p = b;
+ char c = b; /* expect: 107 */
+ int i = b; /* expect: 107 */
+ double d = b; /* expect: 107 */
+ void *p = b; /* expect: 107 */
- /* These assignments are all ok. */
+ /* The right-hand sides of these assignments are all ok. */
b = !b;
b = i == i;
b = i != i;
@@ -108,59 +108,70 @@ SB002_operator_result(bool b)
b = b || b;
/*
- * These assignments are not ok, they implicitly convert from bool
- * to int.
+ * The right-hand sides of these assignments are not ok, they
+ * implicitly convert from bool to int.
*/
- i = !b;
- i = i == i;
- i = i != i;
- i = i < i;
- i = i <= i;
- i = i >= i;
- i = i > i;
- i = b && b;
- i = b || b;
+ i = !b; /* expect: 107 */
+ i = i == i; /* expect: 107 */
+ i = i != i; /* expect: 107 */
+ i = i < i; /* expect: 107 */
+ i = i <= i; /* expect: 107 */
+ i = i >= i; /* expect: 107 */
+ i = i > i; /* expect: 107 */
+ i = b && b; /* expect: 107 */
+ i = b || b; /* expect: 107 */
}
-void
+int
SB003_operands(bool b, int i)
{
- /* These assignments are ok. */
+ /* The right-hand sides of these assignments are ok. */
b = !b;
b = b && b;
b = b || b;
- /* These assignments implicitly convert from scalar to bool. */
- b = !i;
- b = i && i;
- b = i || i;
+ /*
+ * The right-hand sides of these assignments implicitly convert from
+ * scalar to bool.
+ */
+ b = !i; /* expect: 330 */
+ b = i && i; /* expect: 331, 332 */
+ b = i || i; /* expect: 331, 332 */
+
+ b = b && 0;
+ b = 0 && b;
+ b = b || 0;
+ b = 0 || b;
+
+ return i;
}
+/*ARGSUSED*/
void
-SB004_non_bool_operands(bool b, unsigned u)
+SB004_operators_and_bool_operands(bool b, unsigned u)
{
b = !b; /* ok */
- b = ~b; /* not ok */
- ++b; /* not ok */
- --b; /* not ok */
- b++; /* not ok */
- b--; /* not ok */
- b = +b; /* not ok */
- b = -b; /* not ok */
-
- b = b * b; /* not ok */
- b = b / b; /* not ok */
- b = b % b; /* not ok */
- b = b + b; /* not ok */
- b = b - b; /* not ok */
- b = b << b; /* not ok */
- b = b >> b; /* not ok */
-
- b = b < b; /* not ok */
- b = b <= b; /* not ok */
- b = b > b; /* not ok */
- b = b >= b; /* not ok */
+ b = ~b; /* expect: 335 */
+ ++b; /* expect: 335 */
+ --b; /* expect: 335 */
+ b++; /* expect: 335 */
+ b--; /* expect: 335 */
+ b = +b; /* expect: 335 */
+ b = -b; /* expect: 335 */
+
+ b = b * b; /* expect: 336, 337 */
+ b = b / b; /* expect: 336, 337 */
+ b = b % b; /* expect: 336, 337 */
+ b = b + b; /* expect: 336, 337 */
+ b = b - b; /* expect: 336, 337 */
+ b = b << b; /* expect: 336, 337 */
+ b = b >> b; /* expect: 336, 337 */
+
+ b = b < b; /* expect: 336, 337 */
+ b = b <= b; /* expect: 336, 337 */
+ b = b > b; /* expect: 336, 337 */
+ b = b >= b; /* expect: 336, 337 */
b = b == b; /* ok */
b = b != b; /* ok */
@@ -172,37 +183,38 @@ SB004_non_bool_operands(bool b, unsigned
b = b ? b : b; /* ok */
b = b; /* ok */
- b *= b; /* not ok */
- b /= b; /* not ok */
- b %= b; /* not ok */
- b += b; /* not ok */
- b -= b; /* not ok */
- b <<= b; /* not ok */
- b >>= b; /* not ok */
+ b *= b; /* expect: 336, 337 */
+ b /= b; /* expect: 336, 337 */
+ b %= b; /* expect: 336, 337 */
+ b += b; /* expect: 336, 337 */
+ b -= b; /* expect: 336, 337 */
+ b <<= b; /* expect: 336, 337 */
+ b >>= b; /* expect: 336, 337 */
b &= b; /* ok */
b ^= b; /* ok */
b |= b; /* ok */
/* Operations with mixed types. */
- u = b * u; /* not ok */
- u = u * b; /* not ok */
- u = b / u; /* not ok */
- u = u / b; /* not ok */
- u = b % u; /* not ok */
- u = u % b; /* not ok */
- u = b + u; /* not ok */
- u = u + b; /* not ok */
- u = b - u; /* not ok */
- u = u - b; /* not ok */
- u = b << u; /* not ok */
- u = u << b; /* not ok */
- u = b >> u; /* not ok */
- u = u >> b; /* not ok */
+ u = b * u; /* expect: 336 */
+ u = u * b; /* expect: 337 */
+ u = b / u; /* expect: 336 */
+ u = u / b; /* expect: 337 */
+ u = b % u; /* expect: 336 */
+ u = u % b; /* expect: 337 */
+ u = b + u; /* expect: 336 */
+ u = u + b; /* expect: 337 */
+ u = b - u; /* expect: 336 */
+ u = u - b; /* expect: 337 */
+ u = b << u; /* expect: 336 */
+ u = u << b; /* expect: 337 */
+ u = b >> u; /* expect: 336 */
+ u = u >> b; /* expect: 337 */
u = b ? u : u; /* ok */
- u = b ? b : u; /* not ok */
- u = b ? u : b; /* not ok */
+ u = b ? b : u; /* expect: 107 */
+ u = b ? u : b; /* expect: 107 */
}
+/*ARGSUSED*/
void
SB005_convert_from_bool_to_scalar(bool b)
{
@@ -211,10 +223,10 @@ SB005_convert_from_bool_to_scalar(bool b
double d;
void *p;
- i = b; /* not ok */
- u = b; /* not ok */
- d = b; /* not ok */
- p = b; /* not ok */
+ i = b; /* expect: 107 */
+ u = b; /* expect: 107 */
+ d = b; /* expect: 107 */
+ p = b; /* expect: 107 */
}
enum SB006_bool_constant_expression {
@@ -225,27 +237,32 @@ enum SB006_bool_constant_expression {
INT1 = 1 ? 100 : 101,
/* Not ok: 2 is not a boolean constant (neither 0 nor 1). */
- INT2 = 2 ? 100 : 101,
+ INT2 = 2 ? 100 : 101, /* expect: 331 */
/*
- * Not ok: the intermediate expression "2 - 2" has return type
- * scalar, not bool. It is irrelevant that the final result
- * is 0, which would be a boolean constant.
+ * The intermediate expression "2" has type int, which is not
+ * compatible with _Bool. The expression "2 - 2" is an integer
+ * constant expression with value 0 and is thus a bool constant
+ * expression. This particular case probably does not occur in
+ * practice.
*/
ARITH = (2 - 2) ? 100 : 101,
/*
- * Ok: The 13 and 12 are not boolean expressions, but they
- * are not in the calculation path that leads to the final
- * result. The important point is that the operator '>' has
- * return type bool.
+ * These two variants of an expression can occur when a preprocessor
+ * macro is either defined to 1 or left empty, as in lint1/ops.def.
*/
+ BINARY_PLUS = (1 + 0) ? 100 : 101,
+ UNARY_PLUS = (+0) ? 100 : 101,
+
+ /* The main operator '>' has return type bool. */
Q1 = (13 > 12) ? 100 : 101,
/*
- * Not ok: The 7 is irrelevant for the final result of the
- * expression, yet it turns the result type of the operator
- * '?:' to be int, not bool.
+ * The 7 is part of the integer constant expression, but it is
+ * irrelevant for the final result. The expression in parentheses
+ * is an integer constant expression with value 1 and thus is a
+ * bool constant expression.
*/
Q2 = (13 > 12 ? 1 : 7) ? 100 : 101,
@@ -277,7 +294,8 @@ enum Flags {
* The usual way to query one of the flags is demonstrated below.
*/
-extern void println(const char *);
+extern void
+println(const char *);
void
query_flag_from_enum_bit_set(enum Flags flags)
@@ -291,6 +309,7 @@ query_flag_from_enum_bit_set(enum Flags
if ((flags & (FLAG0 | FLAG1)) == (FLAG0 | FLAG1))
println("FLAG0 and FLAG1 are both set");
+
if (flags & FLAG0 && flags & FLAG1)
println("FLAG0 and FLAG1 are both set");
@@ -306,52 +325,53 @@ query_flag_from_enum_bit_set(enum Flags
* calls them), the result of the operator '&' is compared against 0. This
* makes this pattern work, no matter whether the bits are in the low-value
* range or in the high-value range (such as FLAG28, which has the value
- * 1073741824, which is more than what fits into an unsigned char). Even
- * if an enum could be extended to larger types than int, this pattern
+ * 1073741824, which is more than what would fit into an unsigned char).
+ * Even if an enum could be extended to larger types than int, this pattern
* would work.
*/
/*
* There is a crucial difference between a _Bool variable and an ordinary
- * integer variable though. C99 6.3.1.2 defines a conversion from an
- * arbitrary scalar type to _Bool as (value != 0 ? 1 : 0). This means that
- * even if _Bool is implemented as an 8-bit unsigned integer, assigning 256
- * to it would still result in the value 1 being stored. Storing 256 in an
- * ordinary 8-bit unsigned integer would result in the value 0 being stored.
- * See the test d_c99_bool.c for more details.
+ * integer variable. C99 6.3.1.2 defines a conversion from an arbitrary
+ * scalar value to _Bool as equivalent to (value != 0 ? 1 : 0). This means
+ * that even if _Bool is implemented as an 8-bit unsigned integer, assigning
+ * 256 to it would still result in the value 1 being stored. Storing 256 in
+ * an ordinary 8-bit unsigned integer would result in the value 0 being
+ * stored. See the test d_c99_bool.c for more details.
*
* Because of this, expressions like (flags & FLAG28) are only allowed in
* bool context if they are guaranteed not to be truncated, even if the
* result were to be stored in a plain unsigned integer.
*/
+/*ARGSUSED*/
void
SB007_allow_flag_test_on_bit_set_enums(enum Flags flags)
{
bool b;
/*
- * FLAG0 has the value 1 and can therefore be stored in a bool
- * variable without truncation. Nevertheless this special case
- * is not allowed because it would be too confusing if FLAG0 would
- * work and all the other flags wouldn't.
+ * FLAG0 has the value 1 and thus can be stored in a bool variable
+ * without truncation. Nevertheless this special case is not allowed
+ * because it would be too confusing if FLAG0 would work and all the
+ * other flags wouldn't.
*/
- b = flags & FLAG0;
+ b = flags & FLAG0; /* expect: 107 */
/*
* Assuming that FLAG1 is set in flags, a _Bool variable stores this
- * as 1, as defined by C99 6.3.1.2. An unsigned char variable would
- * store it as 2, as that is the integer value of FLAG1. Since FLAG1
- * fits in an unsigned char, no truncation takes place.
+ * as 1, as defined by C99 6.3.1.2. A uint8_t variable would store
+ * it as 2, as that is the integer value of FLAG1. Since FLAG1 fits
+ * in a uint8_t, no truncation takes place.
*/
- b = flags & FLAG1;
+ b = flags & FLAG1; /* expect: 107 */
/*
- * In a _Bool variable, FLAG28 is stored as 1, as above. In an
- * unsigned char, the stored value would be 0 since bit 28 is out of
- * range for an unsigned char, which usually has 8 significant bits.
+ * In a _Bool variable, FLAG28 is stored as 1, since it is unequal to
+ * zero. In a uint8_t, the stored value would be 0 since bit 28 is
+ * out of range for a uint8_t and thus gets truncated.
*/
- b = flags & FLAG28;
+ b = flags & FLAG28; /* expect: 107 */
}
/* A bool bit field is compatible with bool. Other bit fields are not. */
@@ -361,40 +381,64 @@ struct flags {
unsigned uint_flag: 1;
};
+/*ARGSUSED*/
void
-SB008_flags_from_bit_fields(const struct flags *flags)
+SB008_bit_fields(const struct flags *flags)
{
bool b;
b = flags->bool_flag; /* ok */
- b = flags->uint_flag; /* not ok */
+ b = flags->uint_flag; /* expect: 107 */
+ flags->bool_flag = b;
+ flags->uint_flag = b; /* expect: 107 */
}
/* Test implicit conversion when returning a value from a function. */
+/*ARGSUSED*/
bool
returning_bool(bool b, int i, const char *p)
{
if (i > 0)
return b; /* ok */
if (i < 0)
- return i; /* not ok */
- return p; /* not ok */
+ return i; /* expect: 211 */
+ return p; /* expect: 211 */
}
+/*ARGSUSED*/
char
returning_char(bool b, int i, const char *p)
{
if (i > 0)
- return b; /* not ok */
+ return b; /* expect: 211 */
if (i < 0)
- return i; /* not ok, but not related to bool */
- return p; /* not ok */
+ return i; /* XXX: narrowing conversion */
+ return p; /* expect: 183 */
+}
+
+bool
+return_constant_false(void)
+{
+ return 0;
+}
+
+bool
+return_constant_true(void)
+{
+ return 1;
+}
+
+bool
+return_invalid_integer(void)
+{
+ return 2; /* expect: 211 */
}
/* Test passing arguments to a function. */
-extern void taking_arguments(bool, int, const char *, ...);
+extern void
+taking_arguments(bool, int, const char *, ...);
void
passing_arguments(bool b, int i, const char *p)
@@ -403,14 +447,77 @@ passing_arguments(bool b, int i, const c
taking_arguments(b, i, p);
/* Implicitly converting bool to other scalar types. */
- taking_arguments(b, b, b);
+ taking_arguments(b, b, b); /* expect: 334, 334 */
/* Implicitly converting int to bool (arg #1). */
- taking_arguments(i, i, i);
+ taking_arguments(i, i, i); /* expect: 334, 154 */
/* Implicitly converting pointer to bool (arg #1). */
- taking_arguments(p, p, p);
+ taking_arguments(p, p, p); /* expect: 334, 154 */
/* Passing bool as vararg. */
- taking_arguments(b, i, p, b, i, p);
+ taking_arguments(b, i, p, b, i, p); /* expect: arg#4 */ // TODO
+
+ /* Passing a bool constant. */
+ taking_arguments(0, i, p);
+
+ /* Passing a bool constant. */
+ taking_arguments(1, i, p);
+
+ /* Trying to pass an invalid integer. */
+ taking_arguments(2, i, p); /* expect: 334 */
+}
+
+/*
+ * This is just normal access to a bool member of a struct, to ensure that
+ * these produce no errors.
+ */
+void
+struct_access_operators(void)
+{
+ struct bool_struct {
+ bool b;
+ };
+
+ /* Initialize and assign using boolean constants. */
+ bool b = 0;
+ b = 1;
+
+ /* Access a struct member using the '.' operator. */
+ struct bool_struct bs = { 1 };
+ b = bs.b;
+ bs.b = b;
+ bs.b = 0;
+
+ /* Access a struct member using the '->' operator. */
+ struct bool_struct *bsp = &bs;
+ b = bsp->b;
+ bsp->b = b;
+ bsp->b = 0;
+
+ /* Taking the address of a bool lvalue. */
+ bool *bp;
+ bp = &b;
+ *bp = b;
+ b = *bp;
+}
+
+/*
+ * Comparing a _Bool expression to 0 or 1 is redundant. It may come from
+ * an earlier version of the code, before it got migrated to using _Bool.
+ * Usually, bool expressions are used directly as control expressions or
+ * as argument to the boolean operators such as '!', '&&', '||'.
+ *
+ * Since lint steps in after the C preprocessor, it has no chance of seeing
+ * the original source code, which may well have been "b == false" instead
+ * of "b == 0".
+ */
+bool
+compare_var_with_constant(bool b)
+{
+ bool t1 = b == 0;
+ bool t2 = t1 != 0;
+ bool t3 = t2 == 1;
+ bool t4 = t3 != 1;
+ return t4 ^ t3;
}
Index: src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.exp
diff -u src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.exp:1.2 src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.exp:1.3
--- src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.exp:1.2 Mon Jan 11 00:28:28 2021
+++ src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.exp Tue Jan 12 20:42:01 2021
@@ -1,6 +1,103 @@
-d_c99_bool_strict.c(97): warning: illegal combination of pointer (pointer to void) and integer (_Bool), op = [123]
-d_c99_bool_strict.c(217): warning: illegal combination of pointer (pointer to void) and integer (_Bool), op = [123]
-d_c99_bool_strict.c(392): warning: illegal combination of integer (char) and pointer (pointer to const char) [183]
-d_c99_bool_strict.c(406): warning: illegal combination of pointer (pointer to const char) and integer (_Bool), arg #3 [154]
-d_c99_bool_strict.c(409): warning: illegal combination of pointer (pointer to const char) and integer (int), arg #3 [154]
-d_c99_bool_strict.c(412): warning: illegal combination of integer (int) and pointer (pointer to const char), arg #2 [154]
+d_c99_bool_strict.c(64): controlling expression must be bool, not 'int' [333]
+d_c99_bool_strict.c(68): controlling expression must be bool, not 'int' [333]
+d_c99_bool_strict.c(74): controlling expression must be bool, not 'double' [333]
+d_c99_bool_strict.c(80): controlling expression must be bool, not 'pointer' [333]
+d_c99_bool_strict.c(94): operands of '=' have incompatible types (char != _Bool) [107]
+d_c99_bool_strict.c(95): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(96): operands of '=' have incompatible types (double != _Bool) [107]
+d_c99_bool_strict.c(97): operands of '=' have incompatible types (pointer != _Bool) [107]
+d_c99_bool_strict.c(114): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(115): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(116): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(117): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(118): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(119): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(120): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(121): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(122): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(138): operand of '!' must be bool, not 'int' [330]
+d_c99_bool_strict.c(139): left operand of '&&' must be bool, not 'int' [331]
+d_c99_bool_strict.c(139): right operand of '&&' must be bool, not 'int' [332]
+d_c99_bool_strict.c(140): left operand of '||' must be bool, not 'int' [331]
+d_c99_bool_strict.c(140): right operand of '||' must be bool, not 'int' [332]
+d_c99_bool_strict.c(155): operand of '~' must not be bool [335]
+d_c99_bool_strict.c(156): operand of '++x' must not be bool [335]
+d_c99_bool_strict.c(157): operand of '--x' must not be bool [335]
+d_c99_bool_strict.c(158): operand of 'x++' must not be bool [335]
+d_c99_bool_strict.c(159): operand of 'x--' must not be bool [335]
+d_c99_bool_strict.c(160): operand of '+' must not be bool [335]
+d_c99_bool_strict.c(161): operand of '-' must not be bool [335]
+d_c99_bool_strict.c(163): left operand of '*' must not be bool [336]
+d_c99_bool_strict.c(163): right operand of '*' must not be bool [337]
+d_c99_bool_strict.c(164): left operand of '/' must not be bool [336]
+d_c99_bool_strict.c(164): right operand of '/' must not be bool [337]
+d_c99_bool_strict.c(165): left operand of '%' must not be bool [336]
+d_c99_bool_strict.c(165): right operand of '%' must not be bool [337]
+d_c99_bool_strict.c(166): left operand of '+' must not be bool [336]
+d_c99_bool_strict.c(166): right operand of '+' must not be bool [337]
+d_c99_bool_strict.c(167): left operand of '-' must not be bool [336]
+d_c99_bool_strict.c(167): right operand of '-' must not be bool [337]
+d_c99_bool_strict.c(168): left operand of '<<' must not be bool [336]
+d_c99_bool_strict.c(168): right operand of '<<' must not be bool [337]
+d_c99_bool_strict.c(169): left operand of '>>' must not be bool [336]
+d_c99_bool_strict.c(169): right operand of '>>' must not be bool [337]
+d_c99_bool_strict.c(171): left operand of '<' must not be bool [336]
+d_c99_bool_strict.c(171): right operand of '<' must not be bool [337]
+d_c99_bool_strict.c(172): left operand of '<=' must not be bool [336]
+d_c99_bool_strict.c(172): right operand of '<=' must not be bool [337]
+d_c99_bool_strict.c(173): left operand of '>' must not be bool [336]
+d_c99_bool_strict.c(173): right operand of '>' must not be bool [337]
+d_c99_bool_strict.c(174): left operand of '>=' must not be bool [336]
+d_c99_bool_strict.c(174): right operand of '>=' must not be bool [337]
+d_c99_bool_strict.c(186): left operand of '*=' must not be bool [336]
+d_c99_bool_strict.c(186): right operand of '*=' must not be bool [337]
+d_c99_bool_strict.c(187): left operand of '/=' must not be bool [336]
+d_c99_bool_strict.c(187): right operand of '/=' must not be bool [337]
+d_c99_bool_strict.c(188): left operand of '%=' must not be bool [336]
+d_c99_bool_strict.c(188): right operand of '%=' must not be bool [337]
+d_c99_bool_strict.c(189): left operand of '+=' must not be bool [336]
+d_c99_bool_strict.c(189): right operand of '+=' must not be bool [337]
+d_c99_bool_strict.c(190): left operand of '-=' must not be bool [336]
+d_c99_bool_strict.c(190): right operand of '-=' must not be bool [337]
+d_c99_bool_strict.c(191): left operand of '<<=' must not be bool [336]
+d_c99_bool_strict.c(191): right operand of '<<=' must not be bool [337]
+d_c99_bool_strict.c(192): left operand of '>>=' must not be bool [336]
+d_c99_bool_strict.c(192): right operand of '>>=' must not be bool [337]
+d_c99_bool_strict.c(198): left operand of '*' must not be bool [336]
+d_c99_bool_strict.c(199): right operand of '*' must not be bool [337]
+d_c99_bool_strict.c(200): left operand of '/' must not be bool [336]
+d_c99_bool_strict.c(201): right operand of '/' must not be bool [337]
+d_c99_bool_strict.c(202): left operand of '%' must not be bool [336]
+d_c99_bool_strict.c(203): right operand of '%' must not be bool [337]
+d_c99_bool_strict.c(204): left operand of '+' must not be bool [336]
+d_c99_bool_strict.c(205): right operand of '+' must not be bool [337]
+d_c99_bool_strict.c(206): left operand of '-' must not be bool [336]
+d_c99_bool_strict.c(207): right operand of '-' must not be bool [337]
+d_c99_bool_strict.c(208): left operand of '<<' must not be bool [336]
+d_c99_bool_strict.c(209): right operand of '<<' must not be bool [337]
+d_c99_bool_strict.c(210): left operand of '>>' must not be bool [336]
+d_c99_bool_strict.c(211): right operand of '>>' must not be bool [337]
+d_c99_bool_strict.c(213): operands of ':' have incompatible types (_Bool != unsigned int) [107]
+d_c99_bool_strict.c(214): operands of ':' have incompatible types (unsigned int != _Bool) [107]
+d_c99_bool_strict.c(226): operands of '=' have incompatible types (int != _Bool) [107]
+d_c99_bool_strict.c(227): operands of '=' have incompatible types (unsigned int != _Bool) [107]
+d_c99_bool_strict.c(228): operands of '=' have incompatible types (double != _Bool) [107]
+d_c99_bool_strict.c(229): operands of '=' have incompatible types (pointer != _Bool) [107]
+d_c99_bool_strict.c(240): left operand of '?' must be bool, not 'int' [331]
+d_c99_bool_strict.c(359): operands of '=' have incompatible types (_Bool != int) [107]
+d_c99_bool_strict.c(367): operands of '=' have incompatible types (_Bool != int) [107]
+d_c99_bool_strict.c(374): operands of '=' have incompatible types (_Bool != int) [107]
+d_c99_bool_strict.c(391): operands of '=' have incompatible types (_Bool != unsigned int) [107]
+d_c99_bool_strict.c(393): operands of '=' have incompatible types (unsigned int != _Bool) [107]
+d_c99_bool_strict.c(405): return value type mismatch (_Bool) and (int) [211]
+d_c99_bool_strict.c(406): return value type mismatch (_Bool) and (pointer to const char) [211]
+d_c99_bool_strict.c(414): return value type mismatch (char) and (_Bool) [211]
+d_c99_bool_strict.c(417): warning: illegal combination of integer (char) and pointer (pointer to const char) [183]
+d_c99_bool_strict.c(435): return value type mismatch (_Bool) and (int) [211]
+d_c99_bool_strict.c(450): argument #2 expects 'int', gets passed '_Bool' [334]
+d_c99_bool_strict.c(450): argument #3 expects 'pointer', gets passed '_Bool' [334]
+d_c99_bool_strict.c(453): argument #1 expects '_Bool', gets passed 'int' [334]
+d_c99_bool_strict.c(453): warning: illegal combination of pointer (pointer to const char) and integer (int), arg #3 [154]
+d_c99_bool_strict.c(456): argument #1 expects '_Bool', gets passed 'pointer' [334]
+d_c99_bool_strict.c(456): warning: illegal combination of integer (int) and pointer (pointer to const char), arg #2 [154]
+d_c99_bool_strict.c(468): argument #1 expects '_Bool', gets passed 'int' [334]
Index: src/usr.bin/xlint/common/externs.h
diff -u src/usr.bin/xlint/common/externs.h:1.12 src/usr.bin/xlint/common/externs.h:1.13
--- src/usr.bin/xlint/common/externs.h:1.12 Mon Jan 4 01:12:20 2021
+++ src/usr.bin/xlint/common/externs.h Tue Jan 12 20:42:00 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: externs.h,v 1.12 2021/01/04 01:12:20 rillig Exp $ */
+/* $NetBSD: externs.h,v 1.13 2021/01/12 20:42:00 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@@ -35,6 +35,8 @@
* main[12].c
*/
extern int pflag;
+/* Treat _Bool as incompatible to all other scalar types. */
+extern bool Tflag;
/*
* inittyp.c
Index: src/usr.bin/xlint/lint1/cgram.y
diff -u src/usr.bin/xlint/lint1/cgram.y:1.138 src/usr.bin/xlint/lint1/cgram.y:1.139
--- src/usr.bin/xlint/lint1/cgram.y:1.138 Sun Jan 10 14:07:34 2021
+++ src/usr.bin/xlint/lint1/cgram.y Tue Jan 12 20:42:01 2021
@@ -1,5 +1,5 @@
%{
-/* $NetBSD: cgram.y,v 1.138 2021/01/10 14:07:34 rillig Exp $ */
+/* $NetBSD: cgram.y,v 1.139 2021/01/12 20:42:01 rillig Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
@@ -35,7 +35,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(lint)
-__RCSID("$NetBSD: cgram.y,v 1.138 2021/01/10 14:07:34 rillig Exp $");
+__RCSID("$NetBSD: cgram.y,v 1.139 2021/01/12 20:42:01 rillig Exp $");
#endif
#include <limits.h>
@@ -2097,6 +2097,11 @@ toicon(tnode_t *tn, int required)
v = constant(tn, required);
+ if (tn == NULL) {
+ i = 1;
+ goto done;
+ }
+
/*
* Abstract declarations are used inside expression. To free
* the memory would be a fatal error.
@@ -2126,6 +2131,8 @@ toicon(tnode_t *tn, int required)
}
}
}
+
+done:
free(v);
return i;
}
Index: src/usr.bin/xlint/lint1/err.c
diff -u src/usr.bin/xlint/lint1/err.c:1.65 src/usr.bin/xlint/lint1/err.c:1.66
--- src/usr.bin/xlint/lint1/err.c:1.65 Sat Jan 9 17:21:33 2021
+++ src/usr.bin/xlint/lint1/err.c Tue Jan 12 20:42:01 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: err.c,v 1.65 2021/01/09 17:21:33 rillig Exp $ */
+/* $NetBSD: err.c,v 1.66 2021/01/12 20:42:01 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@@ -37,7 +37,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(lint)
-__RCSID("$NetBSD: err.c,v 1.65 2021/01/09 17:21:33 rillig Exp $");
+__RCSID("$NetBSD: err.c,v 1.66 2021/01/12 20:42:01 rillig Exp $");
#endif
#include <sys/types.h>
@@ -389,6 +389,14 @@ const char *msgs[] = {
"declarations after statements is a C9X feature", /* 327 */
"union cast is a C9X feature", /* 328 */
"type '%s' is not a member of '%s'", /* 329 */
+ "operand of '%s' must be bool, not '%s'", /* 330 */
+ "left operand of '%s' must be bool, not '%s'", /* 331 */
+ "right operand of '%s' must be bool, not '%s'", /* 332 */
+ "controlling expression must be bool, not '%s'", /* 333 */
+ "argument #%d expects '%s', gets passed '%s'", /* 334 */
+ "operand of '%s' must not be bool", /* 335 */
+ "left operand of '%s' must not be bool", /* 336 */
+ "right operand of '%s' must not be bool", /* 337 */
};
/*
Index: src/usr.bin/xlint/lint1/externs1.h
diff -u src/usr.bin/xlint/lint1/externs1.h:1.54 src/usr.bin/xlint/lint1/externs1.h:1.55
--- src/usr.bin/xlint/lint1/externs1.h:1.54 Mon Jan 11 19:29:49 2021
+++ src/usr.bin/xlint/lint1/externs1.h Tue Jan 12 20:42:01 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: externs1.h,v 1.54 2021/01/11 19:29:49 rillig Exp $ */
+/* $NetBSD: externs1.h,v 1.55 2021/01/12 20:42:01 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@@ -204,6 +204,7 @@ extern tnode_t *new_string_node(strg_t *
extern sym_t *struct_or_union_member(tnode_t *, op_t, sym_t *);
extern tnode_t *build(op_t, tnode_t *, tnode_t *);
extern tnode_t *cconv(tnode_t *);
+extern bool is_strict_bool(const tnode_t *);
extern bool typeok(op_t, int, const tnode_t *, const tnode_t *);
extern tnode_t *promote(op_t, int, tnode_t *);
extern tnode_t *convert(op_t, int, type_t *, tnode_t *);
Index: src/usr.bin/xlint/lint1/func.c
diff -u src/usr.bin/xlint/lint1/func.c:1.56 src/usr.bin/xlint/lint1/func.c:1.57
--- src/usr.bin/xlint/lint1/func.c:1.56 Sun Jan 10 11:17:53 2021
+++ src/usr.bin/xlint/lint1/func.c Tue Jan 12 20:42:01 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: func.c,v 1.56 2021/01/10 11:17:53 rillig Exp $ */
+/* $NetBSD: func.c,v 1.57 2021/01/12 20:42:01 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.56 2021/01/10 11:17:53 rillig Exp $");
+__RCSID("$NetBSD: func.c,v 1.57 2021/01/12 20:42:01 rillig Exp $");
#endif
#include <stdlib.h>
@@ -552,6 +552,12 @@ check_controlling_expression(tnode_t *tn
return NULL;
}
+ if (tn != NULL && Tflag && !is_strict_bool(tn)) {
+ /* controlling expression must be bool, not '%s' */
+ error(333, tspec_name(tn->tn_type->t_tspec));
+ return NULL;
+ }
+
return tn;
}
Index: src/usr.bin/xlint/lint1/main1.c
diff -u src/usr.bin/xlint/lint1/main1.c:1.33 src/usr.bin/xlint/lint1/main1.c:1.34
--- src/usr.bin/xlint/lint1/main1.c:1.33 Sun Jan 10 14:12:48 2021
+++ src/usr.bin/xlint/lint1/main1.c Tue Jan 12 20:42:01 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: main1.c,v 1.33 2021/01/10 14:12:48 rillig Exp $ */
+/* $NetBSD: main1.c,v 1.34 2021/01/12 20:42:01 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@@ -37,7 +37,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(lint)
-__RCSID("$NetBSD: main1.c,v 1.33 2021/01/10 14:12:48 rillig Exp $");
+__RCSID("$NetBSD: main1.c,v 1.34 2021/01/12 20:42:01 rillig Exp $");
#endif
#include <sys/types.h>
@@ -101,6 +101,8 @@ int rflag;
/* Strict ANSI C mode. */
int sflag;
+bool Tflag;
+
/* Traditional C mode. */
int tflag;
@@ -176,7 +178,7 @@ main(int argc, char *argv[])
setprogname(argv[0]);
ERR_ZERO(&msgset);
- while ((c = getopt(argc, argv, "abcdeghmprstuvwyzFPR:SX:")) != -1) {
+ while ((c = getopt(argc, argv, "abcdeghmprstuvwyzFPR:STX:")) != -1) {
switch (c) {
case 'a': aflag++; break;
case 'b': bflag = 1; break;
@@ -191,6 +193,7 @@ main(int argc, char *argv[])
case 'r': rflag = 1; break;
case 's': sflag = 1; break;
case 'S': Sflag = 1; break;
+ case 'T': Tflag = true; break;
case 't': tflag = 1; break;
case 'u': uflag = 0; break;
case 'w': wflag = 1; break;
Index: src/usr.bin/xlint/lint1/op.h
diff -u src/usr.bin/xlint/lint1/op.h:1.11 src/usr.bin/xlint/lint1/op.h:1.12
--- src/usr.bin/xlint/lint1/op.h:1.11 Sat Jan 9 17:36:10 2021
+++ src/usr.bin/xlint/lint1/op.h Tue Jan 12 20:42:01 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: op.h,v 1.11 2021/01/09 17:36:10 rillig Exp $ */
+/* $NetBSD: op.h,v 1.12 2021/01/12 20:42:01 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@@ -38,7 +38,9 @@
*/
typedef struct {
bool m_binary : 1; /* binary operator */
- bool m_logical : 1; /* logical operator, result is int */
+ bool m_returns_bool : 1; /* logical operator, result is 0 or 1 */
+ bool m_takes_bool : 1; /* only in strict bool mode */
+ bool m_takes_only_bool : 1; /* only in strict bool mode */
bool m_requires_integer : 1;
bool m_requires_integer_or_complex : 1;
bool m_requires_arith : 1;
@@ -62,7 +64,7 @@ extern mod_t modtab[];
#define begin_ops() typedef enum {
#define op(name, repr, \
- bi, lo, in, sc, ar, fo, va, ts, ba, se, \
+ bi, lo, tb, to, in, sc, ar, fo, va, ts, ba, se, \
lu, ru, pc, cm, ve, de, ew, ic, active) \
name,
#define end_ops() } op_t;
Index: src/usr.bin/xlint/lint1/oper.c
diff -u src/usr.bin/xlint/lint1/oper.c:1.2 src/usr.bin/xlint/lint1/oper.c:1.3
--- src/usr.bin/xlint/lint1/oper.c:1.2 Sat Jan 9 22:19:11 2021
+++ src/usr.bin/xlint/lint1/oper.c Tue Jan 12 20:42:01 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: oper.c,v 1.2 2021/01/09 22:19:11 rillig Exp $ */
+/* $NetBSD: oper.c,v 1.3 2021/01/12 20:42:01 rillig Exp $ */
/*-
* Copyright (c) 2021 The NetBSD Foundation, Inc.
@@ -41,9 +41,9 @@ static const struct {
} imods[] =
#define begin_ops() {
#define op(name, repr, \
- bi, lo, in, sc, ar, fo, va, ts, ba, se, \
+ bi, lo, tb, to, in, sc, ar, fo, va, ts, ba, se, \
lu, ru, pc, cm, ve, de, ew, ic, active) \
- { { bi + 0, lo + 0, in + 0, sc + 0, ar + 0, \
+ { { bi + 0, lo + 0, tb + 0, to + 0, in + 0, sc + 0, ar + 0, \
fo + 0, va + 0, ts + 0, ba + 0, se + 0, \
lu + 0, ru + 0, pc + 0, cm + 0, ve + 0, \
de + 0, ew + 0, ic + 0, repr }, active },
Index: src/usr.bin/xlint/lint1/ops.def
diff -u src/usr.bin/xlint/lint1/ops.def:1.9 src/usr.bin/xlint/lint1/ops.def:1.10
--- src/usr.bin/xlint/lint1/ops.def:1.9 Sat Jan 9 22:19:11 2021
+++ src/usr.bin/xlint/lint1/ops.def Tue Jan 12 20:42:01 2021
@@ -1,85 +1,85 @@
-/* $NetBSD: ops.def,v 1.9 2021/01/09 22:19:11 rillig Exp $ */
+/* $NetBSD: ops.def,v 1.10 2021/01/12 20:42:01 rillig Exp $ */
begin_ops()
/* See mod_t in op.h for the definition of the table columns. */
-/* name repr b l i c a s f v t b s l r p c e e = act */
-op( NOOP, "no-op", , , , , , , , , , , , , , , , , , , 0)
-op( ARROW, "->", 1, , , , , , ,1, , , , , , , , , , , 1)
-op( POINT, ".", 1, , , , , , , , , , , , , , , , , , 1)
-op( NOT, "!", ,1, , , ,1,1, ,1, , , , , , , ,1, , 1)
-op( COMPL, "~", , , ,1, , ,1,1, , , , , , , , ,1,1, 1)
-op( INC, "++", , , , , , , , , , , , , , , , , , , 0)
-op( DEC, "--", , , , , , , , , , , , , , , , , , , 0)
-op( INCBEF, "++x", , , , , ,1, , , , ,1, , , , , ,1, , 1)
-op( DECBEF, "--x", , , , , ,1, , , , ,1, , , , , ,1, , 1)
-op( INCAFT, "x++", , , , , ,1, , , , ,1, , , , , ,1, , 1)
-op( DECAFT, "x--", , , , , ,1, , , , ,1, , , , , ,1, , 1)
-op( UPLUS, "+", , , , ,1, ,1,1, , , , , , , , ,1,1, 1)
-op( UMINUS, "-", , , , ,1, ,1,1, , , ,1, , , , ,1,1, 1)
-op( STAR, "*", , , , , , , ,1, , , , , , , , , , , 1)
-op( AMPER, "&", , , , , , , , , , , , , , , , , , , 1)
-
-/* name repr b l i c a s f v t b s l r p c e e = act */
-op( MULT, "*", 1, , , ,1, ,1,1, ,1, , ,1, , , ,1,1, 1)
-op( DIV, "/", 1, , , ,1, ,1,1, ,1, ,1,1, , , ,1,1, 1)
-op( MOD, "%", 1, ,1, , , ,1,1, ,1, ,1,1, , , ,1,1, 1)
-op( PLUS, "+", 1, , , , ,1,1,1, ,1, , , , , , ,1, , 1)
-op( MINUS, "-", 1, , , , ,1,1,1, ,1, , , , , , ,1, , 1)
-op( SHL, "<<", 1, ,1, , , ,1,1, , , , , ,1, , ,1,1, 1)
-op( SHR, ">>", 1, ,1, , , ,1,1, , , ,1, ,1, , ,1,1, 1)
-
-/* name repr b l i c a s f v t b s l r p c e e = act */
-op( LT, "<", 1,1, , , ,1,1,1, ,1, ,1,1, ,1,1, ,1, 1)
-op( LE, "<=", 1,1, , , ,1,1,1, ,1, ,1,1, ,1,1, ,1, 1)
-op( GT, ">", 1,1, , , ,1,1,1, ,1, ,1,1, ,1,1, ,1, 1)
-op( GE, ">=", 1,1, , , ,1,1,1, ,1, ,1,1, ,1,1, ,1, 1)
-op( EQ, "==", 1,1, , , ,1,1,1, ,1, , , , ,1,1, ,1, 1)
-op( NE, "!=", 1,1, , , ,1,1,1, ,1, , , , ,1,1, ,1, 1)
-
-/* name repr b l i c a s f v t b s l r p c e e = act */
-op( AND, "&", 1, ,1, , , ,1,1, ,1, , , ,1, , ,1, , 1)
-op( XOR, "^", 1, ,1, , , ,1,1, ,1, , , ,1, , ,1, , 1)
-op( OR, "|", 1, ,1, , , ,1,1, ,1, , , ,1, , ,1, , 1)
-op( LOGAND, "&&", 1,1, , , ,1,1, ,1, , , , , , , ,1, , 1)
-op( LOGOR, "||", 1,1, , , ,1,1, ,1, , , , ,1, , ,1, , 1)
-op( QUEST, "?", 1, , , , , ,1, ,1, , , , , , , , , , 1)
-op( COLON, ":", 1, , , , , , ,1, ,1, , , , , ,1, , , 1)
-
-/* name repr b l i c a s f v t b s l r p c e e = act */
-op( ASSIGN, "=", 1, , , , , , , , , ,1, , , , ,1, , , 1)
-op( MULASS, "*=", 1, , , ,1, , , , , ,1, , , , , ,1, , 1)
-op( DIVASS, "/=", 1, , , ,1, , , , , ,1, ,1, , , ,1, , 1)
-op( MODASS, "%=", 1, ,1, , , , , , , ,1, ,1, , , ,1, , 1)
-op( ADDASS, "+=", 1, , , , ,1, , , , ,1, , , , , ,1, , 1)
-op( SUBASS, "-=", 1, , , , ,1, , , , ,1, , , , , ,1, , 1)
-op( SHLASS, "<<=", 1, ,1, , , , , , , ,1, , , , , ,1, , 1)
-op( SHRASS, ">>=", 1, ,1, , , , , , , ,1, , , , , ,1, , 1)
-op( ANDASS, "&=", 1, ,1, , , , , , , ,1, , , , , ,1, , 1)
-op( XORASS, "^=", 1, ,1, , , , , , , ,1, , , , , ,1, , 1)
-op( ORASS, "|=", 1, ,1, , , , , , , ,1, , , , , ,1, , 1)
-
-/* name repr b l i c a s f v t b s l r p c e e = act */
-op( NAME, "name", , , , , , , , , , , , , , , , , , , 1)
-op( CON, "const", , , , , , , , , , , , , , , , , , , 1)
-op( STRING, "string", , , , , , , , , , , , , , , , , , , 1)
-op( FSEL, "fsel", , , , , , , , , , , , , , , , , , , 1)
-op( CALL, "call", 1, , , , , , , , , ,1, , , , , , , , 1)
-op( COMMA, ",", 1, , , , , , , , , , , , , , , , ,1, 1)
-op( CVT, "convert", , , , , , , ,1, , , , , , , , , , , 1)
-op( ICALL, "icall", 1, , , , , , , , , ,1, , , , , , , , 1)
-op( LOAD, "load", , , , , , , , , , , , , , , , , , , 1)
-op( PUSH, "push", , , , , , , ,1, , , , , , , , , , , 1)
-op( RETURN, "return", 1, , , , , , , , , ,1, , , , ,1, , , 1)
-op( REAL, "real", , , , , , , , , , , , , , , , , , , 0)
-op( IMAG, "imag", , , , , , , , , , , , , , , , , , , 0)
+/* name repr b l b o i c a s f v t b s l r p c e e = act */
+op( NOOP, "no-op", , , , , , , , , , , , , , , , , , , , ,0)
+op( ARROW, "->", 1, ,1, , , , , , ,1, , , , , , , , , , ,1)
+op( POINT, ".", 1, ,1, , , , , , , , , , , , , , , , , ,1)
+op( NOT, "!", ,1,1,1, , , ,1,1, ,1, , , , , , , ,1, ,1)
+op( COMPL, "~", , , , , ,1, , ,1,1, , , , , , , , ,1,1,1)
+op( INC, "++", , , , , , , , , , , , , , , , , , , , ,0)
+op( DEC, "--", , , , , , , , , , , , , , , , , , , , ,0)
+op( INCBEF, "++x", , , , , , , ,1, , , , ,1, , , , , ,1, ,1)
+op( DECBEF, "--x", , , , , , , ,1, , , , ,1, , , , , ,1, ,1)
+op( INCAFT, "x++", , , , , , , ,1, , , , ,1, , , , , ,1, ,1)
+op( DECAFT, "x--", , , , , , , ,1, , , , ,1, , , , , ,1, ,1)
+op( UPLUS, "+", , , , , , ,1, ,1,1, , , , , , , , ,1,1,1)
+op( UMINUS, "-", , , , , , ,1, ,1,1, , , ,1, , , , ,1,1,1)
+op( STAR, "*", , , , , , , , , ,1, , , , , , , , , , ,1)
+op( AMPER, "&", , ,1, , , , , , , , , , , , , , , , , ,1)
+
+/* name repr b l b o i c a s f v t b s l r p c e e = act */
+op( MULT, "*", 1, , , , , ,1, ,1,1, ,1, , ,1, , , ,1,1,1)
+op( DIV, "/", 1, , , , , ,1, ,1,1, ,1, ,1,1, , , ,1,1,1)
+op( MOD, "%", 1, , , ,1, , , ,1,1, ,1, ,1,1, , , ,1,1,1)
+op( PLUS, "+", 1, , , , , , ,1,1,1, ,1, , , , , , ,1, ,1)
+op( MINUS, "-", 1, , , , , , ,1,1,1, ,1, , , , , , ,1, ,1)
+op( SHL, "<<", 1, , , ,1, , , ,1,1, , , , , ,1, , ,1,1,1)
+op( SHR, ">>", 1, , , ,1, , , ,1,1, , , ,1, ,1, , ,1,1,1)
+
+/* name repr b l b o i c a s f v t b s l r p c e e = act */
+op( LT, "<", 1,1, , , , , ,1,1,1, ,1, ,1,1, ,1,1, ,1,1)
+op( LE, "<=", 1,1, , , , , ,1,1,1, ,1, ,1,1, ,1,1, ,1,1)
+op( GT, ">", 1,1, , , , , ,1,1,1, ,1, ,1,1, ,1,1, ,1,1)
+op( GE, ">=", 1,1, , , , , ,1,1,1, ,1, ,1,1, ,1,1, ,1,1)
+op( EQ, "==", 1,1,1, , , , ,1,1,1, ,1, , , , ,1,1, ,1,1)
+op( NE, "!=", 1,1,1, , , , ,1,1,1, ,1, , , , ,1,1, ,1,1)
+
+/* name repr b l b o i c a s f v t b s l r p c e e = act */
+op( AND, "&", 1, ,1, ,1, , , ,1,1, ,1, , , ,1, , ,1, ,1)
+op( XOR, "^", 1, ,1, ,1, , , ,1,1, ,1, , , ,1, , ,1, ,1)
+op( OR, "|", 1, ,1, ,1, , , ,1,1, ,1, , , ,1, , ,1, ,1)
+op( LOGAND, "&&", 1,1,1,1, , , ,1,1, ,1, , , , , , , ,1, ,1)
+op( LOGOR, "||", 1,1,1,1, , , ,1,1, ,1, , , , ,1, , ,1, ,1)
+op( QUEST, "?", 1, , , , , , , ,1, ,1, , , , , , , , , ,1)
+op( COLON, ":", 1, ,1, , , , , , ,1, ,1, , , , , ,1, , ,1)
+
+/* name repr b l b o i c a s f v t b s l r p c e e = act */
+op( ASSIGN, "=", 1, ,1, , , , , , , , , ,1, , , , ,1, , ,1)
+op( MULASS, "*=", 1, , , , , ,1, , , , , ,1, , , , , ,1, ,1)
+op( DIVASS, "/=", 1, , , , , ,1, , , , , ,1, ,1, , , ,1, ,1)
+op( MODASS, "%=", 1, , , ,1, , , , , , , ,1, ,1, , , ,1, ,1)
+op( ADDASS, "+=", 1, , , , , , ,1, , , , ,1, , , , , ,1, ,1)
+op( SUBASS, "-=", 1, , , , , , ,1, , , , ,1, , , , , ,1, ,1)
+op( SHLASS, "<<=", 1, , , ,1, , , , , , , ,1, , , , , ,1, ,1)
+op( SHRASS, ">>=", 1, , , ,1, , , , , , , ,1, , , , , ,1, ,1)
+op( ANDASS, "&=", 1, ,1, ,1, , , , , , , ,1, , , , , ,1, ,1)
+op( XORASS, "^=", 1, ,1, ,1, , , , , , , ,1, , , , , ,1, ,1)
+op( ORASS, "|=", 1, ,1, ,1, , , , , , , ,1, , , , , ,1, ,1)
+
+/* name repr b l b o i c a s f v t b s l r p c e e = act */
+op( NAME, "name", , , , , , , , , , , , , , , , , , , , ,1)
+op( CON, "const", , , , , , , , , , , , , , , , , , , , ,1)
+op( STRING, "string", , , , , , , , , , , , , , , , , , , , ,1)
+op( FSEL, "fsel", , , , , , , , , , , , , , , , , , , , ,1)
+op( CALL, "call", 1, , , , , , , , , , , ,1, , , , , , , ,1)
+op( COMMA, ",", 1, , , , , , , , , , , , , , , , , , ,1,1)
+op( CVT, "convert", , , , , , , , , ,1, , , , , , , , , , ,1)
+op( ICALL, "icall", 1, , , , , , , , , , , ,1, , , , , , , ,1)
+op( LOAD, "load", , , , , , , , , , , , , , , , , , , , ,1)
+op( PUSH, "push", , , , , , , , , ,1, , , , , , , , , , ,1)
+op( RETURN, "return", 1, , , , , , , , , , , ,1, , , , ,1, , ,1)
+op( REAL, "real", , , , , , , , , , , , , , , , , , , , ,0)
+op( IMAG, "imag", , , , , , , , , , , , , , , , , , , , ,0)
/* INIT, CASE and FARG are pseudo operators that don't appear in the tree. */
-/* name repr b l i c a s f v t b s l r p c e e = act */
-op( INIT, "init", 1, , , , , , , , , , , , , , ,1, , , 1)
-op( CASE, "case", , , , , , , , , , , , , , , , , , , 0)
-op( FARG, "farg", 1, , , , , , , , , , , , , , ,1, , , 1)
+/* name repr b l b o i c a s f v t b s l r p c e e = act */
+op( INIT, "init", 1, ,1, , , , , , , , , , , , , , ,1, , ,1)
+op( CASE, "case", , , , , , , , , , , , , , , , , , , , ,0)
+op( FARG, "farg", 1, , , , , , , , , , , , , , , , ,1, , ,1)
end_ops()
Index: src/usr.bin/xlint/lint1/tree.c
diff -u src/usr.bin/xlint/lint1/tree.c:1.150 src/usr.bin/xlint/lint1/tree.c:1.151
--- src/usr.bin/xlint/lint1/tree.c:1.150 Mon Jan 11 20:04:01 2021
+++ src/usr.bin/xlint/lint1/tree.c Tue Jan 12 20:42:01 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: tree.c,v 1.150 2021/01/11 20:04:01 rillig Exp $ */
+/* $NetBSD: tree.c,v 1.151 2021/01/12 20:42:01 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.150 2021/01/11 20:04:01 rillig Exp $");
+__RCSID("$NetBSD: tree.c,v 1.151 2021/01/12 20:42:01 rillig Exp $");
#endif
#include <float.h>
@@ -603,7 +603,8 @@ build(op_t op, tnode_t *ln, tnode_t *rn)
ntn = build_real_imag(op, ln);
break;
default:
- rtp = mp->m_logical ? gettyp(INT) : ln->tn_type;
+ rtp = mp->m_returns_bool
+ ? gettyp(Tflag ? BOOL : INT) : ln->tn_type;
lint_assert(mp->m_binary || rn == NULL);
ntn = new_tnode(op, rtp, ln, rn);
break;
@@ -692,6 +693,61 @@ cconv(tnode_t *tn)
return tn;
}
+static const tnode_t *
+before_conversion(const tnode_t *tn)
+{
+ while (tn->tn_op == CVT && !tn->tn_cast)
+ tn = tn->tn_left;
+ return tn;
+}
+
+static bool
+is_strict_bool_constant(const tnode_t *tn)
+{
+ tspec_t t;
+
+ tn = before_conversion(tn);
+ t = tn->tn_type->t_tspec;
+
+ if (t == BOOL)
+ return true;
+
+ return t == INT && tn->tn_op == CON &&
+ (tn->tn_val->v_quad == 0 || tn->tn_val->v_quad == 1);
+}
+
+/* In strict bool mode, see if the node's type is compatible with bool. */
+bool
+is_strict_bool(const tnode_t *tn)
+{
+ tspec_t t;
+
+ tn = before_conversion(tn);
+ t = tn->tn_type->t_tspec;
+
+ if (t == BOOL)
+ return true;
+
+ if (t == INT && tn->tn_op == CON &&
+ (tn->tn_val->v_quad == 0 || tn->tn_val->v_quad == 1))
+ return true;
+
+ /* For enums that are used as bit sets, allow "flags & FLAG". */
+ if (tn->tn_op == AND &&
+ tn->tn_left->tn_op == CVT &&
+ tn->tn_left->tn_type->t_tspec == INT && !tn->tn_left->tn_cast &&
+ tn->tn_left->tn_left->tn_type->t_tspec == ENUM &&
+ /*
+ * XXX: Somehow the type information got lost here. The type
+ * of the enum constant on the right-hand side should still be
+ * ENUM, but is INT.
+ */
+ tn->tn_right->tn_type->t_tspec == INT)
+ return true;
+
+ return false;
+}
+
static bool
typeok_incdec(const mod_t *mp, const tnode_t *tn, const type_t *tp)
{
@@ -796,14 +852,6 @@ typeok_minus(op_t op,
return true;
}
-static const tnode_t *
-before_promotion_and_balancing(const tnode_t *tn)
-{
- while (tn->tn_op == CVT && !tn->tn_cast)
- tn = tn->tn_left;
- return tn;
-}
-
static void
typeok_shr(const mod_t *mp,
const tnode_t *ln, tspec_t lt,
@@ -811,8 +859,8 @@ typeok_shr(const mod_t *mp,
{
tspec_t olt, ort;
- olt = before_promotion_and_balancing(ln)->tn_type->t_tspec;
- ort = before_promotion_and_balancing(rn)->tn_type->t_tspec;
+ olt = before_conversion(ln)->tn_type->t_tspec;
+ ort = before_conversion(rn)->tn_type->t_tspec;
/* operands have integer types (checked above) */
if (pflag && !is_uinteger(lt)) {
@@ -1037,9 +1085,125 @@ typeok_assign(const mod_t *mp, const tno
return true;
}
+/*
+ * For assignment operators in strict bool mode, the type check is stricter
+ * than for operators that compare to 0. Code that passes this strict check
+ * can be compiled in a pre-C99 environment that doesn't implement the
+ * special rule C99 6.3.1.2, without silent change in behavior.
+ */
+static bool
+typeok_strict_bool_assign(op_t op, int arg,
+ const tnode_t *ln, tspec_t lt,
+ const tnode_t *rn, tspec_t rt)
+{
+ if ((lt == BOOL) == (rt == BOOL))
+ return true;
+
+ if (lt == BOOL && is_strict_bool_constant(rn))
+ return true;
+
+ if (op == FARG) {
+ /* argument #%d expects '%s', gets passed '%s' */
+ error(334,
+ arg,
+ tspec_name(ln->tn_type->t_tspec),
+ tspec_name(rn->tn_type->t_tspec));
+ } else if (op == RETURN) {
+ /* return value type mismatch (%s) and (%s) */
+ error(211,
+ type_name(ln->tn_type),
+ type_name(rn->tn_type));
+ return false;
+ } else {
+ /* operands of '%s' have incompatible types (%s != %s) */
+ error(107,
+ getopname(op),
+ tspec_name(ln->tn_type->t_tspec),
+ tspec_name(rn->tn_type->t_tspec));
+ }
+
+ return false;
+}
+
+/*
+ * In strict bool mode, check whether the types of the operands match the
+ * operator.
+ */
+static bool
+typeok_scalar_strict_bool(op_t op, const mod_t *mp, int arg,
+ const tnode_t *ln,
+ const tnode_t *rn)
+
+{
+ tspec_t lt, rt;
+
+ ln = before_conversion(ln);
+ lt = ln->tn_type->t_tspec;
+
+ if (rn != NULL) {
+ rn = before_conversion(rn);
+ rt = rn->tn_type->t_tspec;
+ } else {
+ rt = NOTSPEC;
+ }
+
+ if (op == ASSIGN || op == FARG || op == RETURN || op == COLON)
+ return typeok_strict_bool_assign(op, arg, ln, lt, rn, rt);
+
+ if (mp->m_takes_only_bool || op == QUEST) {
+ bool binary = mp->m_binary;
+ bool lbool = is_strict_bool(ln);
+ bool ok = true;
+
+ if (!binary && !lbool) {
+ /* operand of '%s' must be bool, not '%s' */
+ error(330, getopname(op), tspec_name(lt));
+ ok = false;
+ }
+ if (binary && !lbool) {
+ /* left operand of '%s' must be bool, not '%s' */
+ error(331, getopname(op), tspec_name(lt));
+ ok = false;
+ }
+ if (binary && op != QUEST && !is_strict_bool(rn)) {
+ /* right operand of '%s' must be bool, not '%s' */
+ error(332, getopname(op), tspec_name(rt));
+ ok = false;
+ }
+ return ok;
+ }
+
+ if (!mp->m_takes_bool) {
+ bool binary = mp->m_binary;
+ bool lbool = before_conversion(ln)->tn_type->t_tspec == BOOL;
+ bool ok = true;
+
+ if (!binary && lbool) {
+ /* operand of '%s' must not be bool */
+ error(335, getopname(op));
+ ok = false;
+ }
+ if (binary && lbool) {
+ /* left operand of '%s' must not be bool */
+ error(336, getopname(op));
+ ok = false;
+ }
+ if (binary && before_conversion(rn)->tn_type->t_tspec == BOOL) {
+ /* right operand of '%s' must not be bool */
+ error(337, getopname(op));
+ ok = false;
+ }
+ return ok;
+ }
+
+ return true;
+}
+
/* Check the types using the information from modtab[]. */
static bool
-typeok_scalar(op_t op, const mod_t *mp, tspec_t lt, tspec_t rt)
+typeok_scalar(op_t op, const mod_t *mp,
+ const tnode_t *ln, tspec_t lt,
+ const tnode_t *rn, tspec_t rt)
{
if (mp->m_requires_integer) {
if (!is_integer(lt) || (mp->m_binary && !is_integer(rt))) {
@@ -1265,7 +1429,9 @@ typeok(op_t op, int arg, const tnode_t *
rt = NOTSPEC;
}
- if (!typeok_scalar(op, mp, lt, rt))
+ if (Tflag && !typeok_scalar_strict_bool(op, mp, arg, ln, rn))
+ return false;
+ if (!typeok_scalar(op, mp, ln, lt, rn, rt))
return false;
if (!typeok_op(op, mp, arg, ln, ltp, lt, rn, rtp, rt))
@@ -2980,7 +3146,7 @@ fold_test(tnode_t *tn)
v = xcalloc(1, sizeof (val_t));
v->v_tspec = tn->tn_type->t_tspec;
- lint_assert(tn->tn_type->t_tspec == INT);
+ lint_assert(v->v_tspec == INT || (Tflag && v->v_tspec == BOOL));
if (is_floating(tn->tn_left->tn_type->t_tspec)) {
l = tn->tn_left->tn_val->v_ldbl != 0.0;
@@ -3522,6 +3688,8 @@ constant(tnode_t *tn, int required)
if (tn == NULL) {
lint_assert(nerr != 0);
+ if (dflag)
+ printf("constant node is null; returning 1 instead\n");
v->v_tspec = INT;
v->v_quad = 1;
return v;
Index: src/usr.bin/xlint/lint2/main2.c
diff -u src/usr.bin/xlint/lint2/main2.c:1.10 src/usr.bin/xlint/lint2/main2.c:1.11
--- src/usr.bin/xlint/lint2/main2.c:1.10 Mon Jan 4 22:26:51 2021
+++ src/usr.bin/xlint/lint2/main2.c Tue Jan 12 20:42:01 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: main2.c,v 1.10 2021/01/04 22:26:51 rillig Exp $ */
+/* $NetBSD: main2.c,v 1.11 2021/01/12 20:42:01 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@@ -37,7 +37,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(lint)
-__RCSID("$NetBSD: main2.c,v 1.10 2021/01/04 22:26:51 rillig Exp $");
+__RCSID("$NetBSD: main2.c,v 1.11 2021/01/12 20:42:01 rillig Exp $");
#endif
#include <stdio.h>
@@ -68,6 +68,7 @@ int pflag;
*/
int sflag;
+bool Tflag;
int tflag;
/*
@@ -100,11 +101,14 @@ main(int argc, char *argv[])
libs = xcalloc(1, sizeof (char *));
opterr = 0;
- while ((c = getopt(argc, argv, "hpstxuC:HFl:")) != -1) {
+ while ((c = getopt(argc, argv, "hpstxuC:HTFl:")) != -1) {
switch (c) {
case 's':
sflag = 1;
break;
+ case 'T':
+ Tflag = true;
+ break;
case 't':
tflag = 1;
break;
Index: src/usr.bin/xlint/xlint/lint.1
diff -u src/usr.bin/xlint/xlint/lint.1:1.41 src/usr.bin/xlint/xlint/lint.1:1.42
--- src/usr.bin/xlint/xlint/lint.1:1.41 Sun May 24 09:55:43 2020
+++ src/usr.bin/xlint/xlint/lint.1 Tue Jan 12 20:42:01 2021
@@ -1,4 +1,4 @@
-.\" $NetBSD: lint.1,v 1.41 2020/05/24 09:55:43 wiz Exp $
+.\" $NetBSD: lint.1,v 1.42 2021/01/12 20:42:01 rillig Exp $
.\"
.\" Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
.\" Copyright (c) 1994, 1995 Jochen Pohl
@@ -30,7 +30,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd May 23, 2020
+.Dd Jan 12, 2021
.Dt LINT 1
.Os
.Sh NAME
@@ -38,7 +38,7 @@
.Nd a C program verifier
.Sh SYNOPSIS
.Nm
-.Op Fl abceFgHhPprVvwxz
+.Op Fl abceFgHhPprTVvwxz
.Op Fl i | Fl nu
.Op Fl S | Fl s | Fl t
.Op Fl B Ar directory
@@ -54,7 +54,7 @@
.Op Fl Z Ar cpparg
.Ar
.Nm lint
-.Op Fl abceFgHhprVvwz
+.Op Fl abceFgHhprTVvwz
.Op Fl S | Fl s | Fl t
.Fl C Ar library
.Op Fl B Ar directory
@@ -369,6 +369,10 @@ With the
flag,
.Li __STRICT_ANSI__
is a predefined preprocessor macro.
+.It Fl T
+Treat
+.Sy _Bool
+as a data type that is incompatible with all other scalar types.
.It Fl t
Traditional C mode.
.Li __STDC__
Index: src/usr.bin/xlint/xlint/xlint.c
diff -u src/usr.bin/xlint/xlint/xlint.c:1.52 src/usr.bin/xlint/xlint/xlint.c:1.53
--- src/usr.bin/xlint/xlint/xlint.c:1.52 Mon Jan 4 22:26:51 2021
+++ src/usr.bin/xlint/xlint/xlint.c Tue Jan 12 20:42:01 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: xlint.c,v 1.52 2021/01/04 22:26:51 rillig Exp $ */
+/* $NetBSD: xlint.c,v 1.53 2021/01/12 20:42:01 rillig Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
@@ -38,7 +38,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(lint)
-__RCSID("$NetBSD: xlint.c,v 1.52 2021/01/04 22:26:51 rillig Exp $");
+__RCSID("$NetBSD: xlint.c,v 1.53 2021/01/12 20:42:01 rillig Exp $");
#endif
#include <sys/param.h>
@@ -290,13 +290,13 @@ usage(void)
{
(void)fprintf(stderr,
- "Usage: %s [-abceghprvwxzHFS] [-s|-t] [-i|-nu] [-Dname[=def]]"
+ "Usage: %s [-abceghprvwxzHFST] [-s|-t] [-i|-nu] [-Dname[=def]]"
" [-Uname] [-X <id>[,<id>]... [-Z <cpparg>]\n", getprogname());
(void)fprintf(stderr,
"\t[-Idirectory] [-Ldirectory] [-llibrary] [-ooutputfile]"
" file...\n");
(void)fprintf(stderr,
- " %s [-abceghprvwzHFS] [|-s|-t] -Clibrary [-Dname[=def]]\n"
+ " %s [-abceghprvwzHFST] [|-s|-t] -Clibrary [-Dname[=def]]\n"
" [-X <id>[,<id>]... [-Z <cpparg>]\n", getprogname());
(void)fprintf(stderr, "\t[-Idirectory] [-Uname] [-Bpath] [-R old=new]"
" file ...\n");
@@ -370,7 +370,8 @@ main(int argc, char *argv[])
(void)signal(SIGINT, terminate);
(void)signal(SIGQUIT, terminate);
(void)signal(SIGTERM, terminate);
- while ((c = getopt(argc, argv, "abcd:eghil:no:prstuvwxzB:C:D:FHI:L:M:PR:SU:VX:Z:")) != -1) {
+ while ((c = getopt(argc, argv,
+ "abcd:eghil:no:prstuvwxzB:C:D:FHI:L:M:PR:STU:VX:Z:")) != -1) {
switch (c) {
case 'a':
@@ -391,6 +392,7 @@ main(int argc, char *argv[])
/* FALLTHROUGH */
case 'u':
case 'h':
+ case 'T':
(void)sprintf(flgbuf, "-%c", c);
appcstrg(&l1flags, flgbuf);
appcstrg(&l2flags, flgbuf);
Added files:
Index: src/tests/usr.bin/xlint/check-expect.lua
diff -u /dev/null src/tests/usr.bin/xlint/check-expect.lua:1.1
--- /dev/null Tue Jan 12 20:42:01 2021
+++ src/tests/usr.bin/xlint/check-expect.lua Tue Jan 12 20:42:01 2021
@@ -0,0 +1,135 @@
+#! /usr/bin/lua
+-- $NetBSD: check-expect.lua,v 1.1 2021/01/12 20:42:01 rillig Exp $
+
+--[[
+
+usage: lua ./check-expect.lua *.c
+
+Check that the /* expect: ... */ comments in the .c source files match the
+actual messages found in the corresponding .exp files.
+
+]]
+
+
+local function load_lines(fname)
+ local lines = {}
+
+ local f = io.open(fname, "r")
+ if f == nil then return nil end
+
+ for line in f:lines() do
+ table.insert(lines, line)
+ end
+ f:close()
+
+ return lines
+end
+
+local function load_expect_comments_from_c(fname)
+
+ local lines = load_lines(fname)
+ if lines == nil then return nil end
+
+ local comments_by_line = {}
+ local seen_comment = false
+ for lineno, line in ipairs(lines) do
+ local comments_in_line = {}
+ for comments in line:gmatch("/%* expect: (.-) %*/$") do
+ for comment in comments:gmatch("[^,]+") do
+ table.insert(comments_in_line, comment:match("^%s*(.-)%s*$"))
+ seen_comment = true
+ end
+ end
+ comments_by_line[lineno] = comments_in_line
+ end
+
+ if seen_comment then return comments_by_line else return nil end
+end
+
+
+local function load_actual_messages_from_exp(fname)
+
+ local lines = load_lines(fname)
+ if lines == nil then return nil end
+
+ local messages = {}
+ for lineno, line in ipairs(lines) do
+ for c_lineno, message in line:gmatch("%S+%((%d+)%): (.+)$") do
+ table.insert(messages, {
+ exp_lineno = lineno,
+ c_lineno = tonumber(c_lineno),
+ msg = message
+ })
+ end
+ end
+
+ return messages
+end
+
+
+local function check_test(c_fname, errors)
+ local exp_fname = c_fname:gsub("%.c$", ".exp")
+ local comments = load_expect_comments_from_c(c_fname)
+ if comments == nil or #comments == 0 then return end
+ local messages = load_actual_messages_from_exp(exp_fname)
+ if messages == nil then return end
+
+ local remaining = 0
+ for lineno, exps in ipairs(comments) do
+ for _, msg in ipairs(exps) do
+ -- print("comment", lineno, msg)
+ remaining = remaining + 1
+ end
+ end
+
+ for _, act in ipairs(messages) do
+ -- print("messages", act.exp_lineno, act.c_lineno, act.msg)
+
+ local exp = comments[act.c_lineno] or {}
+
+ local found = false
+ for i, msg in ipairs(exp) do
+ if msg ~= "" and act.msg:find(msg, 1, true) then
+ exp[i] = ""
+ found = true
+ remaining = remaining - 1
+ -- print("found", act.c_lineno, act.msg, msg, remaining)
+ break
+ end
+ end
+
+ if not found then
+ errors:add("error: %s:%d: message \"%s\" is not declared in %s:%d",
+ exp_fname, act.exp_lineno, act.msg, c_fname, act.c_lineno)
+ end
+ end
+
+ for lineno, exps in ipairs(comments) do
+ for _, msg in ipairs(exps) do
+ if msg ~= "" then
+ errors:add("error: %s:%d: declared message \"%s\" is not in the actual output",
+ c_fname, lineno, msg)
+ end
+ end
+ end
+end
+
+
+local function main(args)
+ local errors = {}
+ errors.add = function(self, fmt, ...)
+ table.insert(self, string.format(fmt, ...))
+ end
+
+ for _, name in ipairs(args) do
+ check_test(name, errors)
+ end
+
+ for _, error in ipairs(errors) do
+ print(error)
+ end
+
+ return #errors == 0
+end
+
+os.exit(main(arg))