lint: make function call arguments directly accessible

Previously, the arguments of a function call expression were arranged in
a linear tree structure, from right to left.  To allow easier access to
the arguments, store them in an array instead.
This commit is contained in:
rillig 2024-02-05 23:11:22 +00:00
parent d736a27c95
commit 5c34ad8f3f
11 changed files with 185 additions and 175 deletions

View File

@ -1,4 +1,4 @@
[//]: # ($NetBSD: README.md,v 1.14 2023/09/14 21:08:12 rillig Exp $)
[//]: # ($NetBSD: README.md,v 1.15 2024/02/05 23:11:22 rillig Exp $)
# Introduction
@ -123,34 +123,31 @@ structure:
~~~text
1: 'call' type 'int'
2: '&' type 'pointer to function(pointer to const char, pointer to const char) returning int'
3: 'name' 'strcmp' with extern 'function(pointer to const char, pointer to const char) returning int'
4: 'push' type 'pointer to const char'
5: 'convert' type 'pointer to const char'
6: '&' type 'pointer to char'
7: 'string' type 'array[5] of char', lvalue, length 4, "name"
8: 'push' type 'pointer to const char'
9: 'load' type 'pointer to const char'
10: '*' type 'pointer to const char', lvalue
11: '+' type 'pointer to pointer to const char'
12: 'load' type 'pointer to pointer to const char'
13: 'name' 'names' with auto 'pointer to pointer to const char', lvalue
14: '*' type 'long'
15: 'convert' type 'long'
16: 'load' type 'int'
17: 'name' 'i' with auto 'int', lvalue
18: 'constant' type 'long', value 8
2: '&' type 'pointer to function(pointer to const char, pointer to const char) returning int'
3: 'name' 'strcmp' with extern 'function(pointer to const char, pointer to const char) returning int'
4: 'load' type 'pointer to const char'
5: '*' type 'pointer to const char', lvalue
6: '+' type 'pointer to pointer to const char'
7: 'load' type 'pointer to pointer to const char'
8: 'name' 'names' with auto 'pointer to pointer to const char', lvalue
9: '*' type 'long'
10: 'convert' type 'long'
11: 'load' type 'int'
12: 'name' 'i' with auto 'int', lvalue
13: 'constant' type 'long', value 8
14: 'convert' type 'pointer to const char'
15: '&' type 'pointer to char'
16: 'string' type 'array[5] of char', lvalue, "name"
~~~
| Lines | Notes |
|--------|------------------------------------------------------------------|
| 4, 8 | Each argument of the function call corresponds to a `PUSH` node. |
| 5, 9 | The left operand of a `PUSH` node is the actual argument. |
| 8 | The right operand is the `PUSH` node of the previous argument. |
| 5, 9 | The arguments of a call are ordered from right to left. |
| 10, 11 | Array access is represented as `*(left + right)`. |
| 14, 18 | Array and struct offsets are in premultiplied form. |
| 18 | The size of a pointer on this platform is 8 bytes. |
| Lines | Notes |
|------------|-------------------------------------------------------------|
| 1, 2, 4, 7 | A function call consists of the function and its arguments. |
| 4, 14 | The arguments of a call are ordered from left to right. |
| 5, 6 | Array access is represented as `*(left + right)`. |
| 9, 13 | Array and struct offsets are in premultiplied form. |
| 9 | The type `ptrdiff_t` on this platform is `long`, not `int`. |
| 13 | The size of a pointer on this platform is 8 bytes. |
See `debug_node` for how to interpret the members of `tnode_t`.

View File

@ -1,5 +1,5 @@
%{
/* $NetBSD: cgram.y,v 1.486 2024/02/02 16:05:37 rillig Exp $ */
/* $NetBSD: cgram.y,v 1.487 2024/02/05 23:11:22 rillig Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
@ -35,7 +35,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID)
__RCSID("$NetBSD: cgram.y,v 1.486 2024/02/02 16:05:37 rillig Exp $");
__RCSID("$NetBSD: cgram.y,v 1.487 2024/02/05 23:11:22 rillig Exp $");
#endif
#include <limits.h>
@ -145,6 +145,7 @@ is_either(const char *s, const char *a, const char *b)
type_qualifiers y_type_qualifiers;
function_specifier y_function_specifier;
struct parameter_list y_parameter_list;
function_call *y_arguments;
type_t *y_type;
tnode_t *y_tnode;
range_t y_range;
@ -298,7 +299,7 @@ is_either(const char *s, const char *a, const char *b)
%type <y_tnode> gcc_statement_expr_list
%type <y_tnode> gcc_statement_expr_item
%type <y_op> point_or_arrow
%type <y_tnode> argument_expression_list
%type <y_arguments> argument_expression_list
%type <y_tnode> unary_expression
%type <y_tnode> cast_expression
%type <y_tnode> expression_opt
@ -558,7 +559,9 @@ postfix_expression:
$$ = build_unary(INDIR, $3, build_binary($1, PLUS, $3, $4));
}
| postfix_expression T_LPAREN sys T_RPAREN {
$$ = build_function_call($1, $3, NULL);
function_call *call =
expr_zero_alloc(sizeof(*call), "function_call");
$$ = build_function_call($1, $3, call);
}
| postfix_expression T_LPAREN sys argument_expression_list T_RPAREN {
$$ = build_function_call($1, $3, $4);
@ -643,10 +646,11 @@ point_or_arrow: /* helper for 'postfix_expression' */
/* K&R 7.1, C90 ???, C99 6.5.2, C11 6.5.2 */
argument_expression_list:
assignment_expression {
$$ = build_function_argument(NULL, $1);
$$ = expr_zero_alloc(sizeof(*$$), "function_call");
add_function_argument($$, $1);
}
| argument_expression_list T_COMMA assignment_expression {
$$ = build_function_argument($1, $3);
add_function_argument($1, $3);
}
;

View File

@ -1,4 +1,4 @@
/* $NetBSD: ckctype.c,v 1.9 2023/12/03 13:12:40 rillig Exp $ */
/* $NetBSD: ckctype.c,v 1.10 2024/02/05 23:11:22 rillig Exp $ */
/*-
* Copyright (c) 2021 The NetBSD Foundation, Inc.
@ -36,7 +36,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID)
__RCSID("$NetBSD: ckctype.c,v 1.9 2023/12/03 13:12:40 rillig Exp $");
__RCSID("$NetBSD: ckctype.c,v 1.10 2024/02/05 23:11:22 rillig Exp $");
#endif
#include <string.h>
@ -120,15 +120,13 @@ check_ctype_arg(const char *func, const tnode_t *arg)
}
void
check_ctype_function_call(const tnode_t *func, const tnode_t *args)
check_ctype_function_call(const function_call *call)
{
if (func->tn_op == NAME &&
is_ctype_function(func->tn_sym->s_name) &&
args != NULL &&
tn_ck_left(args) != NULL &&
args->tn_right == NULL)
check_ctype_arg(func->tn_sym->s_name, args->tn_left);
if (call->args_len == 1 && call->args != NULL &&
call->func->tn_op == NAME &&
is_ctype_function(call->func->tn_sym->s_name))
check_ctype_arg(call->func->tn_sym->s_name, call->args[0]);
}
void

View File

@ -1,4 +1,4 @@
/* $NetBSD: ckgetopt.c,v 1.22 2024/02/03 19:25:16 rillig Exp $ */
/* $NetBSD: ckgetopt.c,v 1.23 2024/02/05 23:11:22 rillig Exp $ */
/*-
* Copyright (c) 2021 The NetBSD Foundation, Inc.
@ -35,7 +35,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID)
__RCSID("$NetBSD: ckgetopt.c,v 1.22 2024/02/03 19:25:16 rillig Exp $");
__RCSID("$NetBSD: ckgetopt.c,v 1.23 2024/02/05 23:11:22 rillig Exp $");
#endif
#include <stdbool.h>
@ -79,24 +79,27 @@ static struct {
static bool
is_getopt_condition(const tnode_t *tn, char **out_options)
{
const tnode_t *call, *last_arg;
const function_call *call;
const tnode_t *last_arg;
const buffer *str;
if (tn != NULL
&& tn->tn_op == NE
&& tn->tn_left->tn_op == ASSIGN
&& tn->tn_right->tn_op == CON
&& tn->tn_right->tn_u._tn_val.v_tspec == INT
&& tn->tn_right->tn_u._tn_val.u.integer == -1
&& (call = tn->tn_left->tn_right)->tn_op == CALL
&& call->tn_left->tn_op == ADDR
&& call->tn_left->tn_left->tn_op == NAME
&& strcmp(call->tn_left->tn_left->tn_sym->s_name, "getopt") == 0
&& tn->tn_left->tn_op == ASSIGN
&& tn->tn_left->tn_right->tn_op == CALL
&& (call = tn->tn_left->tn_right->tn_call)->func->tn_op == ADDR
&& call->func->tn_left->tn_op == NAME
&& strcmp(call->func->tn_left->tn_sym->s_name, "getopt") == 0
&& call->args_len == 3
&& call->args != NULL
&& call->tn_right->tn_op == PUSH
&& (last_arg = call->tn_right->tn_left)->tn_op == CVT
&& (last_arg = call->args[2]) != NULL
&& last_arg->tn_op == CVT
&& last_arg->tn_left->tn_op == ADDR
&& last_arg->tn_left->tn_left->tn_op == STRING
&& (str = last_arg->tn_left->tn_left->tn_string)->data != NULL) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: debug.c,v 1.70 2024/02/03 19:25:16 rillig Exp $ */
/* $NetBSD: debug.c,v 1.71 2024/02/05 23:11:22 rillig Exp $ */
/*-
* Copyright (c) 2021 The NetBSD Foundation, Inc.
@ -35,7 +35,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID)
__RCSID("$NetBSD: debug.c,v 1.70 2024/02/03 19:25:16 rillig Exp $");
__RCSID("$NetBSD: debug.c,v 1.71 2024/02/05 23:11:22 rillig Exp $");
#endif
#include <stdlib.h>
@ -240,6 +240,20 @@ debug_node(const tnode_t *tn) // NOLINT(misc-no-recursion)
else
debug_printf(", length %zu\n", tn->tn_string->len);
break;
case CALL:
case ICALL:
debug_printf("\n");
debug_indent_inc();
const function_call *call = tn->tn_call;
debug_node(call->func);
if (call->args != NULL) {
for (size_t i = 0; i < call->args_len; i++)
debug_node(call->args[i]);
} else
debug_step("error in arguments");
debug_indent_dec();
break;
default:
debug_printf("\n");
@ -249,7 +263,7 @@ debug_node(const tnode_t *tn) // NOLINT(misc-no-recursion)
debug_node(tn->tn_left);
if (op != INCBEF && op != INCAFT
&& op != DECBEF && op != DECAFT
&& op != CALL && op != ICALL && op != PUSH)
&& op != CALL && op != ICALL)
lint_assert(is_binary(tn) == (tn->tn_right != NULL));
if (tn->tn_right != NULL)
debug_node(tn->tn_right);

View File

@ -1,4 +1,4 @@
/* $NetBSD: emit1.c,v 1.85 2024/02/03 19:25:16 rillig Exp $ */
/* $NetBSD: emit1.c,v 1.86 2024/02/05 23:11:22 rillig Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
@ -38,7 +38,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID)
__RCSID("$NetBSD: emit1.c,v 1.85 2024/02/03 19:25:16 rillig Exp $");
__RCSID("$NetBSD: emit1.c,v 1.86 2024/02/05 23:11:22 rillig Exp $");
#endif
#include <stdlib.h>
@ -323,9 +323,6 @@ outfdef(const sym_t *fsym, const pos_t *posp, bool rval, bool osdef,
void
outcall(const tnode_t *tn, bool retval_used, bool retval_discarded)
{
tnode_t *args, *arg;
int narg, i;
outint(csrc_pos.p_line);
outchar('c'); /* function call */
outint(get_filename_id(curr_pos.p_file));
@ -336,16 +333,11 @@ outcall(const tnode_t *tn, bool retval_used, bool retval_discarded)
* flags; 'u' and 'i' must be last to make sure a letter is between the
* numeric argument of a flag and the name of the function
*/
narg = 0;
args = tn_ck_right(tn);
for (arg = args; arg != NULL; arg = tn_ck_right(arg))
narg++;
const function_call *call = tn->tn_call;
/* information about arguments */
for (int n = 1; n <= narg; n++) {
/* the last argument is the top one in the tree */
for (i = narg, arg = args; i > n; i--, arg = arg->tn_right)
continue;
arg = arg->tn_left;
for (size_t n = 1; call->args != NULL && n <= call->args_len; n++) {
const tnode_t *arg = call->args[n - 1];
if (arg->tn_op == CON) {
tspec_t t = arg->tn_type->t_tspec;
if (is_integer(t)) {
@ -364,7 +356,7 @@ outcall(const tnode_t *tn, bool retval_used, bool retval_discarded)
/* negative if cast to signed */
outchar('n');
}
outint(n);
outint((int)n);
}
} else if (arg->tn_op == ADDR &&
arg->tn_left->tn_op == STRING &&
@ -377,25 +369,20 @@ outcall(const tnode_t *tn, bool retval_used, bool retval_discarded)
/* string literal, write all format specifiers */
outchar('s');
outint(n);
outint((int)n);
outfstrg(buf.data);
free(buf.data);
}
}
outchar((char)(retval_discarded ? 'd' : retval_used ? 'u' : 'i'));
/* name of the called function */
outname(tn_ck_left(tn->tn_left)->tn_sym->s_name);
outname(call->func->tn_left->tn_sym->s_name);
/* types of arguments */
outchar('f');
outint(narg);
for (int n = 1; n <= narg; n++) {
/* the last argument is the top one in the tree */
for (i = narg, arg = args; i > n; i--, arg = arg->tn_right)
continue;
outtype(arg->tn_left->tn_type);
}
outint((int)call->args_len);
for (size_t i = 0; call->args != NULL && i < call->args_len; i++)
outtype(call->args[i]->tn_type);
/* expected type of return value */
outtype(tn->tn_type);
outchar('\n');

View File

@ -1,4 +1,4 @@
/* $NetBSD: externs1.h,v 1.215 2024/02/03 19:25:16 rillig Exp $ */
/* $NetBSD: externs1.h,v 1.216 2024/02/05 23:11:22 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@ -292,8 +292,8 @@ tnode_t *build_sizeof(const type_t *);
tnode_t *build_offsetof(const type_t *, designation);
tnode_t *build_alignof(const type_t *);
tnode_t *cast(tnode_t *, bool, type_t *);
tnode_t *build_function_argument(tnode_t *, tnode_t *);
tnode_t *build_function_call(tnode_t *, bool, tnode_t *);
void add_function_argument(function_call *, tnode_t *);
tnode_t *build_function_call(tnode_t *, bool, function_call *);
val_t *integer_constant(tnode_t *, bool);
void expr(tnode_t *, bool, bool, bool, bool);
void check_expr_misc(const tnode_t *, bool, bool, bool, bool, bool, bool);
@ -408,7 +408,7 @@ bool fallback_symbol_strict_bool(sym_t *);
/*
* ckctype.c
*/
void check_ctype_function_call(const tnode_t *, const tnode_t *);
void check_ctype_function_call(const function_call *);
void check_ctype_macro_invocation(const tnode_t *, const tnode_t *);
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: lint1.h,v 1.213 2024/02/03 19:37:02 rillig Exp $ */
/* $NetBSD: lint1.h,v 1.214 2024/02/05 23:11:22 rillig Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
@ -288,6 +288,13 @@ typedef struct sbuf {
} sbuf_t;
typedef struct {
struct tnode *func;
struct tnode **args;
size_t args_len;
size_t args_cap;
} function_call;
/*
* tree node
*/
@ -317,6 +324,7 @@ typedef struct tnode {
* wide strings, 'data' is NULL and
* 'len' is the number of resulting
* characters */
function_call *_tn_call;
} tn_u;
} tnode_t;
@ -325,6 +333,7 @@ typedef struct tnode {
#define tn_sym tn_u._tn_sym
#define tn_val tn_u._tn_val
#define tn_string tn_u._tn_string
#define tn_call tn_u._tn_call
struct generic_association {
type_t *ga_arg; /* NULL means default or error */

View File

@ -1,4 +1,4 @@
/* $NetBSD: op.h,v 1.26 2023/12/03 18:17:41 rillig Exp $ */
/* $NetBSD: op.h,v 1.27 2024/02/05 23:11:22 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@ -119,13 +119,6 @@ typedef enum {
CVT,
ICALL,
LOAD,
/*
* PUSH is a virtual node that is used to concatenate arguments in a
* function call expression. The PUSH nodes are ordered from right to
* left. For example, the function call f(17, 23) is represented as
* CALL(f, PUSH(23, PUSH(17, NULL))).
*/
PUSH,
RETURN,
REAL,
IMAG,

View File

@ -1,4 +1,4 @@
/* $NetBSD: oper.c,v 1.14 2023/09/14 22:20:08 rillig Exp $ */
/* $NetBSD: oper.c,v 1.15 2024/02/05 23:11:22 rillig Exp $ */
/*-
* Copyright (c) 2021 The NetBSD Foundation, Inc.
@ -121,12 +121,11 @@ const mod_t modtab[NOPS] = {
{_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, "constant" },
{_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_, "string" },
{_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,X, "fsel" },
{X,_,_,_,_,_,_,_,_,_,_,X,_,_,_,_,_,_,_,X, "call" },
{_,_,_,_,_,_,_,_,_,_,_,X,_,_,_,_,_,_,_,_, "call" },
{X,_,X,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,X,X, "," },
{_,_,_,_,_,_,_,_,_,X,_,_,_,_,_,_,_,_,_,X, "convert" },
{X,_,_,_,_,_,_,_,_,_,_,X,_,_,_,_,_,_,_,X, "icall" },
{_,_,_,_,_,_,_,_,_,_,_,X,_,_,_,_,_,_,_,_, "icall" },
{_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,X, "load" },
{_,_,_,_,_,_,_,_,_,X,_,_,_,_,_,_,_,_,_,X, "push" },
{X,_,X,_,_,_,_,_,_,_,_,X,_,_,_,_,X,_,_,X, "return" },
{_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,X, "real" },
{_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,X, "imag" },

View File

@ -1,4 +1,4 @@
/* $NetBSD: tree.c,v 1.602 2024/02/03 19:25:16 rillig Exp $ */
/* $NetBSD: tree.c,v 1.603 2024/02/05 23:11:22 rillig Exp $ */
/*
* Copyright (c) 1994, 1995 Jochen Pohl
@ -37,7 +37,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID)
__RCSID("$NetBSD: tree.c,v 1.602 2024/02/03 19:25:16 rillig Exp $");
__RCSID("$NetBSD: tree.c,v 1.603 2024/02/05 23:11:22 rillig Exp $");
#endif
#include <float.h>
@ -1629,10 +1629,17 @@ use(const tnode_t *tn)
case CON:
case STRING:
break;
case CALL:
case ICALL:;
const function_call *call = tn->tn_call;
if (call->args != NULL)
for (size_t i = 0, n = call->args_len; i < n; i++)
use(call->args[i]);
break;
default:
lint_assert(has_operands(tn));
use(tn->tn_left);
if (is_binary(tn) || tn->tn_op == PUSH)
if (is_binary(tn))
use(tn->tn_right);
}
}
@ -2574,13 +2581,13 @@ static bool
is_direct_function_call(const tnode_t *tn, const char **out_name)
{
if (!(tn->tn_op == CALL &&
tn->tn_left->tn_op == ADDR &&
tn->tn_left->tn_left->tn_op == NAME))
return false;
*out_name = tn->tn_left->tn_left->tn_sym->s_name;
return true;
if (tn->tn_op == CALL
&& tn->tn_call->func->tn_op == ADDR
&& tn->tn_call->func->tn_left->tn_op == NAME) {
*out_name = tn->tn_call->func->tn_left->tn_sym->s_name;
return true;
}
return false;
}
static bool
@ -2622,14 +2629,9 @@ is_const_char_pointer(const tnode_t *tn)
static bool
is_first_arg_const_char_pointer(const tnode_t *tn)
{
lint_assert(has_operands(tn));
const tnode_t *an = tn->tn_right;
if (an == NULL)
return false;
while (tn_ck_right(an) != NULL)
an = an->tn_right;
return is_const_char_pointer(an->tn_left);
return tn->tn_call->args != NULL
&& tn->tn_call->args_len >= 1
&& is_const_char_pointer(tn->tn_call->args[0]);
}
static bool
@ -2642,13 +2644,9 @@ is_const_pointer(const tnode_t *tn)
static bool
is_second_arg_const_pointer(const tnode_t *tn)
{
const tnode_t *an = tn_ck_right(tn);
if (an == NULL || tn_ck_right(an) == NULL)
return false;
while (tn_ck_right(an->tn_right) != NULL)
an = an->tn_right;
return is_const_pointer(an->tn_left);
return tn->tn_call->args_len >= 2
&& tn->tn_call->args != NULL
&& is_const_pointer(tn->tn_call->args[1]);
}
static void
@ -4110,14 +4108,8 @@ invalid_cast:
return NULL;
}
/*
* Create the node for a function argument.
* All necessary conversions and type checks are done in
* build_function_call because build_function_argument has no
* information about the expected parameter types.
*/
tnode_t *
build_function_argument(tnode_t *args, tnode_t *arg)
void
add_function_argument(function_call *call, tnode_t *arg)
{
/*
* If there was a serious error in the expression for the argument,
@ -4127,7 +4119,16 @@ build_function_argument(tnode_t *args, tnode_t *arg)
if (arg == NULL)
arg = build_integer_constant(INT, 0);
return build_op(PUSH, arg->tn_sys, arg->tn_type, arg, args);
if (call->args_len >= call->args_cap) {
call->args_cap += 8;
tnode_t **new_args = expr_zero_alloc(
call->args_cap * sizeof(*call->args),
"function_call.args");
memcpy(new_args, call->args,
call->args_len * sizeof(*call->args));
call->args = new_args;
}
call->args[call->args_len++] = arg;
}
/*
@ -4159,18 +4160,17 @@ check_prototype_argument(
* Check types of all function arguments and insert conversions,
* if necessary.
*/
static tnode_t *
check_function_arguments(type_t *ftp, tnode_t *args)
static bool
check_function_arguments(const function_call *call)
{
type_t *ftp = call->func->tn_type->t_subt;
/* get # of parameters in the prototype */
int npar = 0;
for (const sym_t *p = ftp->t_params; p != NULL; p = p->s_next)
npar++;
/* get # of arguments in the function call */
int narg = 0;
for (const tnode_t *arg = args; arg != NULL; arg = tn_ck_right(arg))
narg++;
int narg = (int)call->args_len;
const sym_t *param = ftp->t_params;
if (ftp->t_proto && npar != narg && !(ftp->t_vararg && npar < narg)) {
@ -4180,50 +4180,45 @@ check_function_arguments(type_t *ftp, tnode_t *args)
}
for (int n = 1; n <= narg; n++) {
// The rightmost argument starts the argument list.
tnode_t *arg = args;
for (int i = narg; i > n; i--, arg = arg->tn_right)
continue;
tnode_t *arg = call->args[n - 1];
/* some things which are always not allowed */
tspec_t at = arg->tn_left->tn_type->t_tspec;
tspec_t at = arg->tn_type->t_tspec;
if (at == VOID) {
/* void expressions may not be arguments, arg #%d */
error(151, n);
return NULL;
return false;
}
if (is_struct_or_union(at) &&
is_incomplete(arg->tn_left->tn_type)) {
is_incomplete(arg->tn_type)) {
/* argument cannot have unknown size, arg #%d */
error(152, n);
return NULL;
return false;
}
if (is_integer(at) &&
arg->tn_left->tn_type->t_is_enum &&
is_incomplete(arg->tn_left->tn_type)) {
arg->tn_type->t_is_enum &&
is_incomplete(arg->tn_type)) {
/* argument cannot have unknown size, arg #%d */
warning(152, n);
}
arg->tn_left = cconv(arg->tn_left);
arg = cconv(arg);
call->args[n - 1] = arg;
if (param != NULL) {
arg->tn_left = check_prototype_argument(
n, param->s_type, arg->tn_left);
} else
arg->tn_left = promote(NOOP, true, arg->tn_left);
arg->tn_type = arg->tn_left->tn_type;
arg = param != NULL
? check_prototype_argument(n, param->s_type, arg)
: promote(NOOP, true, arg);
call->args[n - 1] = arg;
if (param != NULL)
param = param->s_next;
}
return args;
return true;
}
tnode_t *
build_function_call(tnode_t *func, bool sys, tnode_t *args)
build_function_call(tnode_t *func, bool sys, function_call *call)
{
if (func == NULL)
@ -4232,9 +4227,11 @@ build_function_call(tnode_t *func, bool sys, tnode_t *args)
op_t fcop = func->tn_op == NAME && func->tn_type->t_tspec == FUNC
? CALL : ICALL;
check_ctype_function_call(func, args);
call->func = func;
check_ctype_function_call(call);
func = cconv(func);
call->func = func;
if (func->tn_type->t_tspec != PTR ||
func->tn_type->t_subt->t_tspec != FUNC) {
@ -4243,9 +4240,15 @@ build_function_call(tnode_t *func, bool sys, tnode_t *args)
return NULL;
}
args = check_function_arguments(func->tn_type->t_subt, args);
if (!check_function_arguments(call))
call->args = NULL;
return build_op(fcop, sys, func->tn_type->t_subt->t_subt, func, args);
tnode_t *ntn = expr_alloc_tnode();
ntn->tn_op = fcop;
ntn->tn_type = func->tn_type->t_subt->t_subt;
ntn->tn_sys = sys;
ntn->tn_call = call;
return ntn;
}
/*
@ -4482,9 +4485,7 @@ check_expr_call(const tnode_t *tn, const tnode_t *ln,
}
static void
check_expr_op(const tnode_t *tn, op_t op, const tnode_t *ln,
bool szof, bool fcall, bool vctx, bool cond,
bool retval_discarded, bool eqwarn)
check_expr_op(op_t op, const tnode_t *ln, bool szof, bool fcall, bool eqwarn)
{
switch (op) {
case ADDR:
@ -4493,7 +4494,6 @@ check_expr_op(const tnode_t *tn, op_t op, const tnode_t *ln,
case LOAD:
check_expr_load(ln);
/* FALLTHROUGH */
case PUSH:
case INCBEF:
case DECBEF:
case INCAFT:
@ -4515,9 +4515,6 @@ check_expr_op(const tnode_t *tn, op_t op, const tnode_t *ln,
case ASSIGN:
check_expr_assign(ln, szof);
break;
case CALL:
check_expr_call(tn, ln, szof, vctx, cond, retval_discarded);
break;
case EQ:
if (hflag && eqwarn)
/* operator '==' found where '=' was expected */
@ -4552,12 +4549,26 @@ check_expr_misc(const tnode_t *tn, bool vctx, bool cond,
op_t op = tn->tn_op;
if (op == NAME || op == CON || op == STRING)
return;
if (op == CALL || op == ICALL) {
const function_call *call = tn->tn_call;
if (op == CALL)
check_expr_call(tn, call->func,
szof, vctx, cond, retval_discarded);
bool discard = op == CVT && tn->tn_type->t_tspec == VOID;
check_expr_misc(call->func, false, false, false, op == CALL,
discard, szof);
if (call->args != NULL) {
for (size_t i = 0, n = call->args_len; i < n; i++)
check_expr_misc(call->args[i],
false, false, false, false, false, szof);
}
return;
}
lint_assert(has_operands(tn));
tnode_t *ln = tn->tn_left;
tnode_t *rn = tn->tn_right;
check_expr_op(tn, op, ln,
szof, fcall, vctx, cond, retval_discarded, eqwarn);
check_expr_op(op, ln, szof, fcall, eqwarn);
const mod_t *mp = &modtab[op];
bool cvctx = mp->m_value_context;
@ -4579,11 +4590,6 @@ check_expr_misc(const tnode_t *tn, bool vctx, bool cond,
check_expr_misc(ln, cvctx, ccond, eq, op == CALL, discard, szof);
switch (op) {
case PUSH:
if (rn != NULL)
check_expr_misc(rn, false, false, eq, false, false,
szof);
break;
case LOGAND:
case LOGOR:
check_expr_misc(rn, false, true, eq, false, false, szof);