Module Name: src Committed By: rillig Date: Tue Nov 16 21:01:06 UTC 2021
Modified Files: src/tests/usr.bin/xlint/lint1: d_c99_bool_strict.c d_c99_bool_strict.exp src/usr.bin/xlint/lint1: cgram.y ckbool.c debug.c externs1.h func.c init.c lint1.h mem1.c tree.c Log Message: lint: fix check for function calls in strict bool mode Previously, if a function call occurred in the controlling expression, its return type could be any scalar, not just bool. This was against the goal of strict bool mode, which makes bool a separate and incompabile type to all other types. For example, it would allow controlling expressions like 'strcmp(a, b)' without the usual '!= 0', but only if at least one of 'a' and 'b' came from a macro definition from a system header. The fix is that the decision of whether the type of the controlling expression may be scalar is no longer based on the operand types but on the main operator of the controlling expression. To generate a diff of this commit: cvs rdiff -u -r1.33 -r1.34 src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c cvs rdiff -u -r1.31 -r1.32 \ src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.exp cvs rdiff -u -r1.369 -r1.370 src/usr.bin/xlint/lint1/cgram.y cvs rdiff -u -r1.8 -r1.9 src/usr.bin/xlint/lint1/ckbool.c cvs rdiff -u -r1.4 -r1.5 src/usr.bin/xlint/lint1/debug.c cvs rdiff -u -r1.139 -r1.140 src/usr.bin/xlint/lint1/externs1.h cvs rdiff -u -r1.125 -r1.126 src/usr.bin/xlint/lint1/func.c cvs rdiff -u -r1.209 -r1.210 src/usr.bin/xlint/lint1/init.c cvs rdiff -u -r1.130 -r1.131 src/usr.bin/xlint/lint1/lint1.h cvs rdiff -u -r1.54 -r1.55 src/usr.bin/xlint/lint1/mem1.c cvs rdiff -u -r1.394 -r1.395 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/d_c99_bool_strict.c diff -u src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c:1.33 src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c:1.34 --- src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c:1.33 Tue Nov 16 18:27:04 2021 +++ src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.c Tue Nov 16 21:01:06 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: d_c99_bool_strict.c,v 1.33 2021/11/16 18:27:04 rillig Exp $ */ +/* $NetBSD: d_c99_bool_strict.c,v 1.34 2021/11/16 21:01:06 rillig Exp $ */ # 3 "d_c99_bool_strict.c" /* @@ -783,8 +783,8 @@ initialization(void) * though they are not strictly boolean. * * This shouldn't apply to function call expressions though since one of the - * goals of strict bool mode is to normalize all expressions like 'strcmp' to - * be 'strcmp(a, b) == 0' instead of '!strcmp(a, b)'. + * goals of strict bool mode is to normalize all expressions calling 'strcmp' + * to be of the form 'strcmp(a, b) == 0' instead of '!strcmp(a, b)'. */ # 1 "stdio.h" 1 3 4 typedef struct stdio_file { @@ -815,68 +815,83 @@ controlling_expression(FILE *f, const ch return; /* - * No warning below since the expression 'stdio_stdin' comes from a - * system header (typically via a macro), and this property is passed - * up to the expression 'ferror(stdio_stdin)'. + * Before tree.c 1.395 from 2021-11-16, the expression below didn't + * produce a warning since the expression 'stdio_stdin' didn't come + * from a system header (typically via a macro), and this property + * was passed up to the expression 'ferror(stdio_stdin)'. * - * That is wrong though since the above rule would allow a plain - * 'strcmp' without a following '== 0', as long as one of its - * arguments comes from a system header. + * That was wrong though since the type of a function call expression + * only depends on the function itself but not its arguments types. + * The old rule had allowed a raw condition 'strcmp(a, b)' without + * the comparison '!= 0', as long as one of its arguments came from a + * system header. * * Seen in bin/echo/echo.c, function main, call to ferror. */ - /* - * TODO: In a function call expression, tn->tn_relaxed should only be - * derived from the function itself, not from its arguments. - */ - /* TODO: Warn about type mismatch [333]. */ + /* expect+5: error: controlling expression must be bool, not 'int' [333] */ if (ferror( -# 835 "d_c99_bool_strict.c" 3 4 +# 834 "d_c99_bool_strict.c" 3 4 &stdio_files[1] -# 837 "d_c99_bool_strict.c" +# 836 "d_c99_bool_strict.c" )) return; /* * Before cgram.y 1.369 from 2021-11-16, at the end of parsing the * name 'stdio_stdout', the parser already looked ahead to the next - * token, to see whether it was the '(' of a function call. At that - * point, the parser was no longer in a system header, therefore - * 'stdio_stdout' was not tn_relaxed, and this information was pushed - * down to the whole function call expression (which was another bug - * at that time). + * token, to see whether it was the '(' of a function call. + * + * At that point, the parser was no longer in a system header, + * therefore 'stdio_stdout' had tn_sys == false, and this information + * was pushed down to the whole function call expression (which was + * another bug that got fixed in tree.c 1.395 from 2021-11-16). */ + /* expect+5: error: controlling expression must be bool, not 'int' [333] */ if (ferror( -# 851 "d_c99_bool_strict.c" 3 4 +# 852 "d_c99_bool_strict.c" 3 4 stdio_stdout -# 853 "d_c99_bool_strict.c" +# 854 "d_c99_bool_strict.c" )) return; /* - * In this variant, there is a token ')' after the name - * 'stdio_stdout', which has the effect that at the end of parsing - * the name, the parser is still in the system header, thus setting - * tn_relaxed to true. + * In this variant of the pattern, there is a token ')' after the + * name 'stdio_stdout', which even before tree.c 1.395 from + * 2021-11-16 had the effect that at the end of parsing the name, the + * parser was still in the system header, thus setting tn_sys (or + * rather tn_relaxed at that time) to true. */ + /* expect+5: error: controlling expression must be bool, not 'int' [333] */ if (ferror( -# 864 "d_c99_bool_strict.c" 3 4 +# 867 "d_c99_bool_strict.c" 3 4 (stdio_stdout) -# 866 "d_c99_bool_strict.c" +# 869 "d_c99_bool_strict.c" )) return; /* * Before cgram.y 1.369 from 2021-11-16, the comment following * 'stdio_stdout' did not prevent the search for '('. At the point - * where build_name calls expr_zalloc_tnode, the parser was already + * where build_name called expr_zalloc_tnode, the parser was already * in the main file again, thus treating 'stdio_stdout' as not coming * from a system header. + * + * This has been fixed in tree.c 1.395 from 2021-11-16. Before that, + * an expression had come from a system header if its operands came + * from a system header, but that was only close to the truth. In a + * case where both operands come from a system header but the + * operator comes from the main translation unit, the main + * translation unit still has control over the whole expression. So + * the correct approach is to focus on the operator, not the + * operands. There are a few corner cases where the operator is + * invisible (for implicit conversions) or synthetic (for translating + * 'arr[index]' to '*(arr + index)', but these are handled as well. */ + /* expect+5: error: controlling expression must be bool, not 'int' [333] */ if (ferror( -# 878 "d_c99_bool_strict.c" 3 4 +# 893 "d_c99_bool_strict.c" 3 4 stdio_stdout /* comment */ -# 880 "d_c99_bool_strict.c" +# 895 "d_c99_bool_strict.c" )) return; } 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.31 src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.exp:1.32 --- src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.exp:1.31 Tue Nov 16 18:27:04 2021 +++ src/tests/usr.bin/xlint/lint1/d_c99_bool_strict.exp Tue Nov 16 21:01:06 2021 @@ -171,3 +171,7 @@ d_c99_bool_strict.c(805): error: control d_c99_bool_strict.c(808): error: controlling expression must be bool, not 'int' [333] d_c99_bool_strict.c(811): error: operand of '!' must be bool, not 'int' [330] d_c99_bool_strict.c(814): error: operand of '!' must be bool, not 'int' [330] +d_c99_bool_strict.c(836): error: controlling expression must be bool, not 'int' [333] +d_c99_bool_strict.c(854): error: controlling expression must be bool, not 'int' [333] +d_c99_bool_strict.c(869): error: controlling expression must be bool, not 'int' [333] +d_c99_bool_strict.c(895): error: controlling expression must be bool, not 'int' [333] Index: src/usr.bin/xlint/lint1/cgram.y diff -u src/usr.bin/xlint/lint1/cgram.y:1.369 src/usr.bin/xlint/lint1/cgram.y:1.370 --- src/usr.bin/xlint/lint1/cgram.y:1.369 Tue Nov 16 18:27:04 2021 +++ src/usr.bin/xlint/lint1/cgram.y Tue Nov 16 21:01:05 2021 @@ -1,5 +1,5 @@ %{ -/* $NetBSD: cgram.y,v 1.369 2021/11/16 18:27:04 rillig Exp $ */ +/* $NetBSD: cgram.y,v 1.370 2021/11/16 21:01:05 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.369 2021/11/16 18:27:04 rillig Exp $"); +__RCSID("$NetBSD: cgram.y,v 1.370 2021/11/16 21:01:05 rillig Exp $"); #endif #include <limits.h> @@ -144,6 +144,7 @@ anonymize(sym_t *s) bool y_seen_statement; struct generic_association *y_generic; struct array_size y_array_size; + bool y_in_system_header; }; %token T_LBRACE T_RBRACE T_LBRACK T_RBRACK T_LPAREN T_RPAREN @@ -355,6 +356,7 @@ anonymize(sym_t *s) %type <y_seen_statement> block_item %type <y_tnode> do_while_expr %type <y_sym> func_declarator +%type <y_in_system_header> sys %{ #if defined(YYDEBUG) && defined(YYBISON) @@ -484,20 +486,20 @@ generic_association: /* K&R 7.1, C90 ???, C99 6.5.2, C11 6.5.2 */ postfix_expression: primary_expression - | postfix_expression T_LBRACK expression T_RBRACK { - $$ = build_unary(INDIR, build_binary($1, PLUS, $3)); + | postfix_expression T_LBRACK sys expression T_RBRACK { + $$ = build_unary(INDIR, $3, build_binary($1, PLUS, $3, $4)); } - | postfix_expression T_LPAREN T_RPAREN { - $$ = build_function_call($1, NULL); + | postfix_expression T_LPAREN sys T_RPAREN { + $$ = build_function_call($1, $3, NULL); } - | postfix_expression T_LPAREN argument_expression_list T_RPAREN { - $$ = build_function_call($1, $3); + | postfix_expression T_LPAREN sys argument_expression_list T_RPAREN { + $$ = build_function_call($1, $3, $4); } - | postfix_expression point_or_arrow T_NAME { - $$ = build_member_access($1, $2, $3); + | postfix_expression point_or_arrow sys T_NAME { + $$ = build_member_access($1, $2, $3, $4); } - | postfix_expression T_INCDEC { - $$ = build_unary($2 == INC ? INCAFT : DECAFT, $1); + | postfix_expression T_INCDEC sys { + $$ = build_unary($2 == INC ? INCAFT : DECAFT, $3, $1); } | T_LPAREN type_name T_RPAREN { /* C99 6.5.2.5 "Compound literals" */ sym_t *tmp = mktempsym($2); @@ -589,33 +591,33 @@ argument_expression_list: /* K&R 7.2, C90 ???, C99 6.5.3, C11 6.5.3 */ unary_expression: postfix_expression - | T_INCDEC unary_expression { - $$ = build_unary($1 == INC ? INCBEF : DECBEF, $2); + | T_INCDEC sys unary_expression { + $$ = build_unary($1 == INC ? INCBEF : DECBEF, $2, $3); } - | T_AMPER cast_expression { - $$ = build_unary(ADDR, $2); + | T_AMPER sys cast_expression { + $$ = build_unary(ADDR, $2, $3); } - | T_ASTERISK cast_expression { - $$ = build_unary(INDIR, $2); + | T_ASTERISK sys cast_expression { + $$ = build_unary(INDIR, $2, $3); } - | T_ADDITIVE cast_expression { + | T_ADDITIVE sys cast_expression { if (tflag && $1 == PLUS) { /* unary + is illegal in traditional C */ warning(100); } - $$ = build_unary($1 == PLUS ? UPLUS : UMINUS, $2); + $$ = build_unary($1 == PLUS ? UPLUS : UMINUS, $2, $3); } - | T_COMPLEMENT cast_expression { - $$ = build_unary(COMPL, $2); + | T_COMPLEMENT sys cast_expression { + $$ = build_unary(COMPL, $2, $3); } - | T_LOGNOT cast_expression { - $$ = build_unary(NOT, $2); + | T_LOGNOT sys cast_expression { + $$ = build_unary(NOT, $2, $3); } - | T_REAL cast_expression { /* GCC c_parser_unary_expression */ - $$ = build_unary(REAL, $2); + | T_REAL sys cast_expression { /* GCC c_parser_unary_expression */ + $$ = build_unary(REAL, $2, $3); } - | T_IMAG cast_expression { /* GCC c_parser_unary_expression */ - $$ = build_unary(IMAG, $2); + | T_IMAG sys cast_expression { /* GCC c_parser_unary_expression */ + $$ = build_unary(IMAG, $2, $3); } | T_EXTENSION cast_expression { /* GCC c_parser_unary_expression */ $$ = $2; @@ -666,61 +668,62 @@ expression_opt: /* K&R ???, C90 ???, C99 6.5.5 to 6.5.15, C11 6.5.5 to 6.5.15 */ conditional_expression: cast_expression - | conditional_expression T_ASTERISK conditional_expression { - $$ = build_binary($1, MULT, $3); + | conditional_expression T_ASTERISK sys conditional_expression { + $$ = build_binary($1, MULT, $3, $4); } - | conditional_expression T_MULTIPLICATIVE conditional_expression { - $$ = build_binary($1, $2, $3); + | conditional_expression T_MULTIPLICATIVE sys conditional_expression { + $$ = build_binary($1, $2, $3, $4); } - | conditional_expression T_ADDITIVE conditional_expression { - $$ = build_binary($1, $2, $3); + | conditional_expression T_ADDITIVE sys conditional_expression { + $$ = build_binary($1, $2, $3, $4); } - | conditional_expression T_SHIFT conditional_expression { - $$ = build_binary($1, $2, $3); + | conditional_expression T_SHIFT sys conditional_expression { + $$ = build_binary($1, $2, $3, $4); } - | conditional_expression T_RELATIONAL conditional_expression { - $$ = build_binary($1, $2, $3); + | conditional_expression T_RELATIONAL sys conditional_expression { + $$ = build_binary($1, $2, $3, $4); } - | conditional_expression T_EQUALITY conditional_expression { - $$ = build_binary($1, $2, $3); + | conditional_expression T_EQUALITY sys conditional_expression { + $$ = build_binary($1, $2, $3, $4); } - | conditional_expression T_AMPER conditional_expression { - $$ = build_binary($1, BITAND, $3); + | conditional_expression T_AMPER sys conditional_expression { + $$ = build_binary($1, BITAND, $3, $4); } - | conditional_expression T_BITXOR conditional_expression { - $$ = build_binary($1, BITXOR, $3); + | conditional_expression T_BITXOR sys conditional_expression { + $$ = build_binary($1, BITXOR, $3, $4); } - | conditional_expression T_BITOR conditional_expression { - $$ = build_binary($1, BITOR, $3); + | conditional_expression T_BITOR sys conditional_expression { + $$ = build_binary($1, BITOR, $3, $4); } - | conditional_expression T_LOGAND conditional_expression { - $$ = build_binary($1, LOGAND, $3); + | conditional_expression T_LOGAND sys conditional_expression { + $$ = build_binary($1, LOGAND, $3, $4); } - | conditional_expression T_LOGOR conditional_expression { - $$ = build_binary($1, LOGOR, $3); + | conditional_expression T_LOGOR sys conditional_expression { + $$ = build_binary($1, LOGOR, $3, $4); } - | conditional_expression T_QUEST expression - T_COLON conditional_expression { - $$ = build_binary($1, QUEST, build_binary($3, COLON, $5)); + | conditional_expression T_QUEST sys + expression T_COLON sys conditional_expression { + $$ = build_binary($1, QUEST, $3, + build_binary($4, COLON, $6, $7)); } ; /* K&R ???, C90 ???, C99 6.5.16, C11 6.5.16 */ assignment_expression: conditional_expression - | unary_expression T_ASSIGN assignment_expression { - $$ = build_binary($1, ASSIGN, $3); + | unary_expression T_ASSIGN sys assignment_expression { + $$ = build_binary($1, ASSIGN, $3, $4); } - | unary_expression T_OPASSIGN assignment_expression { - $$ = build_binary($1, $2, $3); + | unary_expression T_OPASSIGN sys assignment_expression { + $$ = build_binary($1, $2, $3, $4); } ; /* K&R ???, C90 ???, C99 6.5.17, C11 6.5.17 */ expression: assignment_expression - | expression T_COMMA assignment_expression { - $$ = build_binary($1, COMMA, $3); + | expression T_COMMA sys assignment_expression { + $$ = build_binary($1, COMMA, $3, $4); } ; @@ -1855,11 +1858,11 @@ jump_statement: /* C99 6.8.6 */ | T_BREAK T_SEMI { do_break(); } - | T_RETURN T_SEMI { - do_return(NULL); + | T_RETURN sys T_SEMI { + do_return($2, NULL); } - | T_RETURN expression T_SEMI { - do_return($2); + | T_RETURN sys expression T_SEMI { + do_return($2, $3); } ; @@ -2127,6 +2130,12 @@ gcc_attribute_format: | T_AT_FORMAT_SYSLOG ; +sys: + /* empty */ { + $$ = in_system_header; + } + ; + %% /* ARGSUSED */ Index: src/usr.bin/xlint/lint1/ckbool.c diff -u src/usr.bin/xlint/lint1/ckbool.c:1.8 src/usr.bin/xlint/lint1/ckbool.c:1.9 --- src/usr.bin/xlint/lint1/ckbool.c:1.8 Mon Jul 26 16:22:24 2021 +++ src/usr.bin/xlint/lint1/ckbool.c Tue Nov 16 21:01:05 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: ckbool.c,v 1.8 2021/07/26 16:22:24 rillig Exp $ */ +/* $NetBSD: ckbool.c,v 1.9 2021/11/16 21:01:05 rillig Exp $ */ /*- * Copyright (c) 2021 The NetBSD Foundation, Inc. @@ -36,7 +36,7 @@ #include <sys/cdefs.h> #if defined(__RCSID) && !defined(lint) -__RCSID("$NetBSD: ckbool.c,v 1.8 2021/07/26 16:22:24 rillig Exp $"); +__RCSID("$NetBSD: ckbool.c,v 1.9 2021/11/16 21:01:05 rillig Exp $"); #endif #include <string.h> @@ -89,13 +89,12 @@ is_typeok_strict_bool_binary(op_t op, if ((lt == BOOL) == (rt == BOOL)) return true; - if ((ln->tn_relaxed || rn->tn_relaxed) && + if ((ln->tn_sys || rn->tn_sys) && (is_int_constant_zero(ln, lt) || is_int_constant_zero(rn, rt))) return true; - if (is_assignment_bool_or_other(op)) { - return lt != BOOL && (ln->tn_relaxed || rn->tn_relaxed); - } + if (is_assignment_bool_or_other(op)) + return lt != BOOL && (ln->tn_sys || rn->tn_sys); return !is_symmetric_bool_or_other(op); } @@ -222,7 +221,7 @@ is_typeok_bool_operand(const tnode_t *tn if (t == BOOL) return true; - if (tn->tn_relaxed && is_scalar(t)) + if (tn->tn_sys && is_scalar(t)) return true; /* For enums that are used as bit sets, allow "flags & FLAG". */ Index: src/usr.bin/xlint/lint1/debug.c diff -u src/usr.bin/xlint/lint1/debug.c:1.4 src/usr.bin/xlint/lint1/debug.c:1.5 --- src/usr.bin/xlint/lint1/debug.c:1.4 Tue Nov 16 06:55:03 2021 +++ src/usr.bin/xlint/lint1/debug.c Tue Nov 16 21:01:05 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: debug.c,v 1.4 2021/11/16 06:55:03 rillig Exp $ */ +/* $NetBSD: debug.c,v 1.5 2021/11/16 21:01:05 rillig Exp $ */ /*- * Copyright (c) 2021 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ #include <sys/cdefs.h> #if defined(__RCSID) && !defined(lint) -__RCSID("$NetBSD: debug.c,v 1.4 2021/11/16 06:55:03 rillig Exp $"); +__RCSID("$NetBSD: debug.c,v 1.5 2021/11/16 21:01:05 rillig Exp $"); #endif #include <stdlib.h> @@ -121,7 +121,7 @@ debug_node(const tnode_t *tn) op == CVT && !tn->tn_cast ? "convert" : modtab[op].m_name, type_name(tn->tn_type), tn->tn_lvalue ? ", lvalue" : "", tn->tn_parenthesized ? ", parenthesized" : "", - tn->tn_relaxed ? ", relaxed" : ""); + tn->tn_sys ? ", sys" : ""); if (op == NAME) debug_printf(" %s %s\n", tn->tn_sym->s_name, Index: src/usr.bin/xlint/lint1/externs1.h diff -u src/usr.bin/xlint/lint1/externs1.h:1.139 src/usr.bin/xlint/lint1/externs1.h:1.140 --- src/usr.bin/xlint/lint1/externs1.h:1.139 Tue Nov 16 17:41:23 2021 +++ src/usr.bin/xlint/lint1/externs1.h Tue Nov 16 21:01:05 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: externs1.h,v 1.139 2021/11/16 17:41:23 rillig Exp $ */ +/* $NetBSD: externs1.h,v 1.140 2021/11/16 21:01:05 rillig Exp $ */ /* * Copyright (c) 1994, 1995 Jochen Pohl @@ -241,9 +241,9 @@ extern sym_t *struct_or_union_member(tno extern tnode_t *build_generic_selection(const tnode_t *, struct generic_association *); -extern tnode_t *build_binary(tnode_t *, op_t, tnode_t *); -extern tnode_t *build_unary(op_t, tnode_t *); -extern tnode_t *build_member_access(tnode_t *, op_t, sbuf_t *); +extern tnode_t *build_binary(tnode_t *, op_t, bool, tnode_t *); +extern tnode_t *build_unary(op_t, bool, tnode_t *); +extern tnode_t *build_member_access(tnode_t *, op_t, bool, sbuf_t *); extern tnode_t *cconv(tnode_t *); extern bool is_typeok_bool_operand(const tnode_t *); extern bool typeok(op_t, int, const tnode_t *, const tnode_t *); @@ -255,7 +255,7 @@ extern tnode_t *build_offsetof(const typ extern tnode_t *build_alignof(const type_t *); extern tnode_t *cast(tnode_t *, type_t *); extern tnode_t *build_function_argument(tnode_t *, tnode_t *); -extern tnode_t *build_function_call(tnode_t *, tnode_t *); +extern tnode_t *build_function_call(tnode_t *, bool, tnode_t *); extern val_t *constant(tnode_t *, bool); extern void expr(tnode_t *, bool, bool, bool, bool); extern void check_expr_misc(const tnode_t *, bool, bool, bool, @@ -308,7 +308,7 @@ extern void for2(void); extern void do_goto(sym_t *); extern void do_continue(void); extern void do_break(void); -extern void do_return(tnode_t *); +extern void do_return(bool, tnode_t *); extern void global_clean_up_decl(bool); extern void argsused(int); extern void constcond(int); Index: src/usr.bin/xlint/lint1/func.c diff -u src/usr.bin/xlint/lint1/func.c:1.125 src/usr.bin/xlint/lint1/func.c:1.126 --- src/usr.bin/xlint/lint1/func.c:1.125 Tue Nov 16 17:41:23 2021 +++ src/usr.bin/xlint/lint1/func.c Tue Nov 16 21:01:05 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: func.c,v 1.125 2021/11/16 17:41:23 rillig Exp $ */ +/* $NetBSD: func.c,v 1.126 2021/11/16 21:01:05 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.125 2021/11/16 17:41:23 rillig Exp $"); +__RCSID("$NetBSD: func.c,v 1.126 2021/11/16 21:01:05 rillig Exp $"); #endif #include <stdlib.h> @@ -1047,7 +1047,7 @@ do_continue(void) * T_RETURN expr T_SEMI */ void -do_return(tnode_t *tn) +do_return(bool sys, tnode_t *tn) { tnode_t *ln, *rn; control_statement *cs; @@ -1092,7 +1092,7 @@ do_return(tnode_t *tn) ln->tn_lvalue = true; ln->tn_sym = funcsym; /* better than nothing */ - tn = build_binary(ln, RETURN, tn); + tn = build_binary(ln, RETURN, sys, tn); if (tn != NULL) { rn = tn->tn_right; Index: src/usr.bin/xlint/lint1/init.c diff -u src/usr.bin/xlint/lint1/init.c:1.209 src/usr.bin/xlint/lint1/init.c:1.210 --- src/usr.bin/xlint/lint1/init.c:1.209 Sat Sep 4 12:30:46 2021 +++ src/usr.bin/xlint/lint1/init.c Tue Nov 16 21:01:05 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: init.c,v 1.209 2021/09/04 12:30:46 rillig Exp $ */ +/* $NetBSD: init.c,v 1.210 2021/11/16 21:01:05 rillig Exp $ */ /* * Copyright (c) 1994, 1995 Jochen Pohl @@ -38,7 +38,7 @@ #include <sys/cdefs.h> #if defined(__RCSID) && !defined(lint) -__RCSID("$NetBSD: init.c,v 1.209 2021/09/04 12:30:46 rillig Exp $"); +__RCSID("$NetBSD: init.c,v 1.210 2021/11/16 21:01:05 rillig Exp $"); #endif #include <stdlib.h> @@ -832,7 +832,7 @@ initialization_expr_using_op(struct init ln = build_name(in->in_sym, 0); ln->tn_type = expr_unqualified_type(ln->tn_type); - tn = build_binary(ln, INIT, rn); + tn = build_binary(ln, INIT, false /* XXX */, rn); expr(tn, false, false, false, false); return true; Index: src/usr.bin/xlint/lint1/lint1.h diff -u src/usr.bin/xlint/lint1/lint1.h:1.130 src/usr.bin/xlint/lint1/lint1.h:1.131 --- src/usr.bin/xlint/lint1/lint1.h:1.130 Mon Nov 1 19:48:51 2021 +++ src/usr.bin/xlint/lint1/lint1.h Tue Nov 16 21:01:05 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: lint1.h,v 1.130 2021/11/01 19:48:51 rillig Exp $ */ +/* $NetBSD: lint1.h,v 1.131 2021/11/16 21:01:05 rillig Exp $ */ /* * Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved. @@ -307,9 +307,10 @@ typedef struct tnode { bool tn_lvalue : 1; /* node is lvalue */ bool tn_cast : 1; /* if tn_op == CVT, it's an explicit cast */ bool tn_parenthesized : 1; - bool tn_relaxed : 1; /* in strict bool mode, allow mixture between - * bool and scalar, for backwards - * compatibility + bool tn_sys : 1; /* in strict bool mode, allow mixture between + * bool and scalar, for code from system + * headers that may be a mixture between + * scalar types and bool */ bool tn_system_dependent : 1; /* depends on sizeof or offsetof */ union { Index: src/usr.bin/xlint/lint1/mem1.c diff -u src/usr.bin/xlint/lint1/mem1.c:1.54 src/usr.bin/xlint/lint1/mem1.c:1.55 --- src/usr.bin/xlint/lint1/mem1.c:1.54 Tue Nov 16 18:37:24 2021 +++ src/usr.bin/xlint/lint1/mem1.c Tue Nov 16 21:01:05 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: mem1.c,v 1.54 2021/11/16 18:37:24 rillig Exp $ */ +/* $NetBSD: mem1.c,v 1.55 2021/11/16 21:01:05 rillig Exp $ */ /* * Copyright (c) 1994, 1995 Jochen Pohl @@ -37,7 +37,7 @@ #include <sys/cdefs.h> #if defined(__RCSID) && !defined(lint) -__RCSID("$NetBSD: mem1.c,v 1.54 2021/11/16 18:37:24 rillig Exp $"); +__RCSID("$NetBSD: mem1.c,v 1.55 2021/11/16 21:01:05 rillig Exp $"); #endif #include <sys/param.h> @@ -364,9 +364,9 @@ expr_zalloc_tnode(void) * typically contain generated code that cannot be influenced, such * as a flex lexer or a yacc parser. */ - tn->tn_relaxed = in_system_header || - (curr_pos.p_file != csrc_pos.p_file && - str_endswith(curr_pos.p_file, ".c")); + tn->tn_sys = in_system_header || + (curr_pos.p_file != csrc_pos.p_file && + str_endswith(curr_pos.p_file, ".c")); return tn; } Index: src/usr.bin/xlint/lint1/tree.c diff -u src/usr.bin/xlint/lint1/tree.c:1.394 src/usr.bin/xlint/lint1/tree.c:1.395 --- src/usr.bin/xlint/lint1/tree.c:1.394 Tue Nov 16 06:55:03 2021 +++ src/usr.bin/xlint/lint1/tree.c Tue Nov 16 21:01:05 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: tree.c,v 1.394 2021/11/16 06:55:03 rillig Exp $ */ +/* $NetBSD: tree.c,v 1.395 2021/11/16 21:01:05 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.394 2021/11/16 06:55:03 rillig Exp $"); +__RCSID("$NetBSD: tree.c,v 1.395 2021/11/16 21:01:05 rillig Exp $"); #endif #include <float.h> @@ -61,7 +61,7 @@ static void check_enum_type_mismatch(op_ const tnode_t *, const tnode_t *); static void check_enum_int_mismatch(op_t, int, const tnode_t *, const tnode_t *); -static tnode_t *new_tnode(op_t, type_t *, tnode_t *, tnode_t *); +static tnode_t *new_tnode(op_t, bool, type_t *, tnode_t *, tnode_t *); static void balance(op_t, tnode_t **, tnode_t **); static void warn_incompatible_types(op_t, const type_t *, tspec_t, const type_t *, tspec_t); @@ -75,14 +75,14 @@ static void check_integer_conversion(op_ static void check_pointer_integer_conversion(op_t, tspec_t, type_t *, tnode_t *); static void check_pointer_conversion(tnode_t *, type_t *); -static tnode_t *build_struct_access(op_t, tnode_t *, tnode_t *); -static tnode_t *build_prepost_incdec(op_t, tnode_t *); -static tnode_t *build_real_imag(op_t, tnode_t *); -static tnode_t *build_address(tnode_t *, bool); -static tnode_t *build_plus_minus(op_t, tnode_t *, tnode_t *); -static tnode_t *build_bit_shift(op_t, tnode_t *, tnode_t *); -static tnode_t *build_colon(tnode_t *, tnode_t *); -static tnode_t *build_assignment(op_t, tnode_t *, tnode_t *); +static tnode_t *build_struct_access(op_t, bool, tnode_t *, tnode_t *); +static tnode_t *build_prepost_incdec(op_t, bool, tnode_t *); +static tnode_t *build_real_imag(op_t, bool, tnode_t *); +static tnode_t *build_address(bool, tnode_t *, bool); +static tnode_t *build_plus_minus(op_t, bool, tnode_t *, tnode_t *); +static tnode_t *build_bit_shift(op_t, bool, tnode_t *, tnode_t *); +static tnode_t *build_colon(bool, tnode_t *, tnode_t *); +static tnode_t *build_assignment(op_t, bool, tnode_t *, tnode_t *); static tnode_t *plength(type_t *); static tnode_t *fold(tnode_t *); static tnode_t *fold_test(tnode_t *); @@ -509,15 +509,13 @@ build_generic_selection(const tnode_t *e } /* - * Create a tree node. Called for most operands except function calls, - * sizeof and casts. + * Create a tree node for a binary operator and its two operands. Also called + * for unary operators; in that case rn is NULL. * - * op operator - * ln left operand - * rn if not NULL, right operand + * Function calls, sizeof and casts are handled elsewhere. */ tnode_t * -build_binary(tnode_t *ln, op_t op, tnode_t *rn) +build_binary(tnode_t *ln, op_t op, bool sys, tnode_t *rn) { const mod_t *mp; tnode_t *ntn; @@ -599,30 +597,30 @@ build_binary(tnode_t *ln, op_t op, tnode switch (op) { case POINT: case ARROW: - ntn = build_struct_access(op, ln, rn); + ntn = build_struct_access(op, sys, ln, rn); break; case INCAFT: case DECAFT: case INCBEF: case DECBEF: - ntn = build_prepost_incdec(op, ln); + ntn = build_prepost_incdec(op, sys, ln); break; case ADDR: - ntn = build_address(ln, false); + ntn = build_address(sys, ln, false); break; case INDIR: - ntn = new_tnode(INDIR, ln->tn_type->t_subt, ln, NULL); + ntn = new_tnode(INDIR, sys, ln->tn_type->t_subt, ln, NULL); break; case PLUS: case MINUS: - ntn = build_plus_minus(op, ln, rn); + ntn = build_plus_minus(op, sys, ln, rn); break; case SHL: case SHR: - ntn = build_bit_shift(op, ln, rn); + ntn = build_bit_shift(op, sys, ln, rn); break; case COLON: - ntn = build_colon(ln, rn); + ntn = build_colon(sys, ln, rn); break; case ASSIGN: case MULASS: @@ -637,21 +635,21 @@ build_binary(tnode_t *ln, op_t op, tnode case ORASS: case RETURN: case INIT: - ntn = build_assignment(op, ln, rn); + ntn = build_assignment(op, sys, ln, rn); break; case COMMA: case QUEST: - ntn = new_tnode(op, rn->tn_type, ln, rn); + ntn = new_tnode(op, sys, rn->tn_type, ln, rn); break; case REAL: case IMAG: - ntn = build_real_imag(op, ln); + ntn = build_real_imag(op, sys, ln); break; default: rettp = mp->m_returns_bool ? gettyp(Tflag ? BOOL : INT) : ln->tn_type; lint_assert(mp->m_binary || rn == NULL); - ntn = new_tnode(op, rettp, ln, rn); + ntn = new_tnode(op, sys, rettp, ln, rn); break; } @@ -697,13 +695,13 @@ build_binary(tnode_t *ln, op_t op, tnode } tnode_t * -build_unary(op_t op, tnode_t *tn) +build_unary(op_t op, bool sys, tnode_t *tn) { - return build_binary(tn, op, NULL); + return build_binary(tn, op, sys, NULL); } tnode_t * -build_member_access(tnode_t *ln, op_t op, sbuf_t *member) +build_member_access(tnode_t *ln, op_t op, bool sys, sbuf_t *member) { sym_t *msym; @@ -715,7 +713,7 @@ build_member_access(tnode_t *ln, op_t op ln = cconv(ln); } msym = struct_or_union_member(ln, op, getsym(member)); - return build_binary(ln, op, build_name(msym, 0)); + return build_binary(ln, op, sys, build_name(msym, 0)); } /* @@ -744,7 +742,7 @@ cconv(tnode_t *tn) /* %soperand of '%s' must be lvalue */ gnuism(114, "", op_name(ADDR)); } - tn = new_tnode(ADDR, + tn = new_tnode(ADDR, tn->tn_sys, expr_derive_type(tn->tn_type->t_subt, PTR), tn, NULL); } @@ -754,14 +752,14 @@ cconv(tnode_t *tn) * of type T) */ if (tn->tn_type->t_tspec == FUNC) - tn = build_address(tn, true); + tn = build_address(tn->tn_sys, tn, true); /* lvalue to rvalue */ if (tn->tn_lvalue) { tp = expr_dup_type(tn->tn_type); /* C99 6.3.2.1p2 sentence 2 says to remove the qualifiers. */ tp->t_const = tp->t_volatile = false; - tn = new_tnode(LOAD, tp, tn, NULL); + tn = new_tnode(LOAD, tn->tn_sys, tp, tn, NULL); } return tn; @@ -1831,7 +1829,7 @@ check_enum_array_index(const tnode_t *ln * Build and initialize a new node. */ static tnode_t * -new_tnode(op_t op, type_t *type, tnode_t *ln, tnode_t *rn) +new_tnode(op_t op, bool sys, type_t *type, tnode_t *ln, tnode_t *rn) { tnode_t *ntn; tspec_t t; @@ -1844,10 +1842,7 @@ new_tnode(op_t op, type_t *type, tnode_t ntn->tn_op = op; ntn->tn_type = type; - /* FIXME: For function call expressions (CALL/ICALL), ignore rn. */ - /* FIXME: For bit shift expressions, ignore rn. */ - /* TODO: Check all other operators for the exact combination rules. */ - ntn->tn_relaxed = ln->tn_relaxed || (rn != NULL && rn->tn_relaxed); + ntn->tn_sys = sys; ntn->tn_left = ln; ntn->tn_right = rn; @@ -2093,7 +2088,7 @@ convert(op_t op, int arg, type_t *tp, tn ntn->tn_op = CVT; ntn->tn_type = tp; ntn->tn_cast = op == CVT; - ntn->tn_relaxed |= tn->tn_relaxed; + ntn->tn_sys |= tn->tn_sys; ntn->tn_right = NULL; if (tn->tn_op != CON || nt == VOID) { ntn->tn_left = tn; @@ -2770,7 +2765,7 @@ has_constant_member(const type_t *tp) * Create a new node for one of the operators POINT and ARROW. */ static tnode_t * -build_struct_access(op_t op, tnode_t *ln, tnode_t *rn) +build_struct_access(op_t op, bool sys, tnode_t *ln, tnode_t *rn) { tnode_t *ntn, *ctn; bool nolval; @@ -2786,7 +2781,7 @@ build_struct_access(op_t op, tnode_t *ln nolval = op == POINT && !ln->tn_lvalue; if (op == POINT) { - ln = build_address(ln, true); + ln = build_address(sys, ln, true); } else if (ln->tn_type->t_tspec != PTR) { lint_assert(tflag); lint_assert(is_integer(ln->tn_type->t_tspec)); @@ -2796,14 +2791,15 @@ build_struct_access(op_t op, tnode_t *ln ctn = build_integer_constant(PTRDIFF_TSPEC, rn->tn_sym->s_value.v_quad / CHAR_SIZE); - ntn = new_tnode(PLUS, expr_derive_type(rn->tn_type, PTR), ln, ctn); + ntn = new_tnode(PLUS, sys, expr_derive_type(rn->tn_type, PTR), + ln, ctn); if (ln->tn_op == CON) ntn = fold(ntn); if (rn->tn_type->t_bitfield) { - ntn = new_tnode(FSEL, ntn->tn_type->t_subt, ntn, NULL); + ntn = new_tnode(FSEL, sys, ntn->tn_type->t_subt, ntn, NULL); } else { - ntn = new_tnode(INDIR, ntn->tn_type->t_subt, ntn, NULL); + ntn = new_tnode(INDIR, sys, ntn->tn_type->t_subt, ntn, NULL); } if (nolval) @@ -2816,7 +2812,7 @@ build_struct_access(op_t op, tnode_t *ln * Create a node for INCAFT, INCBEF, DECAFT and DECBEF. */ static tnode_t * -build_prepost_incdec(op_t op, tnode_t *ln) +build_prepost_incdec(op_t op, bool sys, tnode_t *ln) { tnode_t *cn, *ntn; @@ -2827,7 +2823,7 @@ build_prepost_incdec(op_t op, tnode_t *l } else { cn = build_integer_constant(INT, (int64_t)1); } - ntn = new_tnode(op, ln->tn_type, ln, cn); + ntn = new_tnode(op, sys, ln->tn_type, ln, cn); return ntn; } @@ -2836,7 +2832,7 @@ build_prepost_incdec(op_t op, tnode_t *l * Create a node for REAL, IMAG */ static tnode_t * -build_real_imag(op_t op, tnode_t *ln) +build_real_imag(op_t op, bool sys, tnode_t *ln) { tnode_t *cn, *ntn; @@ -2870,7 +2866,7 @@ build_real_imag(op_t op, tnode_t *ln) type_name(ln->tn_type)); return NULL; } - ntn = new_tnode(op, cn->tn_type, ln, cn); + ntn = new_tnode(op, sys, cn->tn_type, ln, cn); ntn->tn_lvalue = true; return ntn; @@ -2880,7 +2876,7 @@ build_real_imag(op_t op, tnode_t *ln) * Create a tree node for the unary & operator */ static tnode_t * -build_address(tnode_t *tn, bool noign) +build_address(bool sys, tnode_t *tn, bool noign) { tspec_t t; @@ -2898,14 +2894,15 @@ build_address(tnode_t *tn, bool noign) return tn->tn_left; } - return new_tnode(ADDR, expr_derive_type(tn->tn_type, PTR), tn, NULL); + return new_tnode(ADDR, sys, expr_derive_type(tn->tn_type, PTR), + tn, NULL); } /* * Create a node for operators PLUS and MINUS. */ static tnode_t * -build_plus_minus(op_t op, tnode_t *ln, tnode_t *rn) +build_plus_minus(op_t op, bool sys, tnode_t *ln, tnode_t *rn) { tnode_t *ntn, *ctn; type_t *tp; @@ -2926,26 +2923,26 @@ build_plus_minus(op_t op, tnode_t *ln, t ctn = plength(ln->tn_type); if (rn->tn_type->t_tspec != ctn->tn_type->t_tspec) rn = convert(NOOP, 0, ctn->tn_type, rn); - rn = new_tnode(MULT, rn->tn_type, rn, ctn); + rn = new_tnode(MULT, sys, rn->tn_type, rn, ctn); if (rn->tn_left->tn_op == CON) rn = fold(rn); - ntn = new_tnode(op, ln->tn_type, ln, rn); + ntn = new_tnode(op, sys, ln->tn_type, ln, rn); } else if (rn->tn_type->t_tspec == PTR) { lint_assert(ln->tn_type->t_tspec == PTR); lint_assert(op == MINUS); tp = gettyp(PTRDIFF_TSPEC); - ntn = new_tnode(op, tp, ln, rn); + ntn = new_tnode(op, sys, tp, ln, rn); if (ln->tn_op == CON && rn->tn_op == CON) ntn = fold(ntn); ctn = plength(ln->tn_type); balance(NOOP, &ntn, &ctn); - ntn = new_tnode(DIV, tp, ntn, ctn); + ntn = new_tnode(DIV, sys, tp, ntn, ctn); } else { - ntn = new_tnode(op, ln->tn_type, ln, rn); + ntn = new_tnode(op, sys, ln->tn_type, ln, rn); } return ntn; @@ -2955,14 +2952,14 @@ build_plus_minus(op_t op, tnode_t *ln, t * Create a node for operators SHL and SHR. */ static tnode_t * -build_bit_shift(op_t op, tnode_t *ln, tnode_t *rn) +build_bit_shift(op_t op, bool sys, tnode_t *ln, tnode_t *rn) { tspec_t t; tnode_t *ntn; if ((t = rn->tn_type->t_tspec) != INT && t != UINT) rn = convert(CVT, 0, gettyp(INT), rn); - ntn = new_tnode(op, ln->tn_type, ln, rn); + ntn = new_tnode(op, sys, ln->tn_type, ln, rn); return ntn; } @@ -2970,7 +2967,7 @@ build_bit_shift(op_t op, tnode_t *ln, tn * Create a node for COLON. */ static tnode_t * -build_colon(tnode_t *ln, tnode_t *rn) +build_colon(bool sys, tnode_t *ln, tnode_t *rn) { tspec_t lt, rt, pdt; type_t *tp; @@ -3026,7 +3023,7 @@ build_colon(tnode_t *ln, tnode_t *rn) tp = merge_qualifiers(ln->tn_type, rn->tn_type); } - ntn = new_tnode(COLON, tp, ln, rn); + ntn = new_tnode(COLON, sys, tp, ln, rn); return ntn; } @@ -3035,7 +3032,7 @@ build_colon(tnode_t *ln, tnode_t *rn) * Create a node for an assignment operator (both = and op= ). */ static tnode_t * -build_assignment(op_t op, tnode_t *ln, tnode_t *rn) +build_assignment(op_t op, bool sys, tnode_t *ln, tnode_t *rn) { tspec_t lt, rt; tnode_t *ntn, *ctn; @@ -3051,7 +3048,7 @@ build_assignment(op_t op, tnode_t *ln, t ctn = plength(ln->tn_type); if (rn->tn_type->t_tspec != ctn->tn_type->t_tspec) rn = convert(NOOP, 0, ctn->tn_type, rn); - rn = new_tnode(MULT, rn->tn_type, rn, ctn); + rn = new_tnode(MULT, sys, rn->tn_type, rn, ctn); if (rn->tn_left->tn_op == CON) rn = fold(rn); } @@ -3088,7 +3085,7 @@ build_assignment(op_t op, tnode_t *ln, t } } - ntn = new_tnode(op, ln->tn_type, ln, rn); + ntn = new_tnode(op, sys, ln->tn_type, ln, rn); return ntn; } @@ -3682,7 +3679,7 @@ build_function_argument(tnode_t *args, t if (arg == NULL) arg = build_integer_constant(INT, 0); - ntn = new_tnode(PUSH, arg->tn_type, arg, args); + ntn = new_tnode(PUSH, arg->tn_sys, arg->tn_type, arg, args); return ntn; } @@ -3692,7 +3689,7 @@ build_function_argument(tnode_t *args, t * function arguments and insert conversions, if necessary. */ tnode_t * -build_function_call(tnode_t *func, tnode_t *args) +build_function_call(tnode_t *func, bool sys, tnode_t *args) { tnode_t *ntn; op_t fcop; @@ -3723,7 +3720,7 @@ build_function_call(tnode_t *func, tnode args = check_function_arguments(func->tn_type->t_subt, args); - ntn = new_tnode(fcop, func->tn_type->t_subt->t_subt, func, args); + ntn = new_tnode(fcop, sys, func->tn_type->t_subt->t_subt, func, args); return ntn; }