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:
parent
d736a27c95
commit
5c34ad8f3f
|
@ -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`.
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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 *);
|
||||
|
||||
/*
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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" },
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue