Module Name:    src
Committed By:   rillig
Date:           Mon Feb  5 23:11:23 UTC 2024

Modified Files:
        src/usr.bin/xlint/lint1: README.md cgram.y ckctype.c ckgetopt.c debug.c
            emit1.c externs1.h lint1.h op.h oper.c tree.c

Log Message:
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.


To generate a diff of this commit:
cvs rdiff -u -r1.14 -r1.15 src/usr.bin/xlint/lint1/README.md \
    src/usr.bin/xlint/lint1/oper.c
cvs rdiff -u -r1.486 -r1.487 src/usr.bin/xlint/lint1/cgram.y
cvs rdiff -u -r1.9 -r1.10 src/usr.bin/xlint/lint1/ckctype.c
cvs rdiff -u -r1.22 -r1.23 src/usr.bin/xlint/lint1/ckgetopt.c
cvs rdiff -u -r1.70 -r1.71 src/usr.bin/xlint/lint1/debug.c
cvs rdiff -u -r1.85 -r1.86 src/usr.bin/xlint/lint1/emit1.c
cvs rdiff -u -r1.215 -r1.216 src/usr.bin/xlint/lint1/externs1.h
cvs rdiff -u -r1.213 -r1.214 src/usr.bin/xlint/lint1/lint1.h
cvs rdiff -u -r1.26 -r1.27 src/usr.bin/xlint/lint1/op.h
cvs rdiff -u -r1.602 -r1.603 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/usr.bin/xlint/lint1/README.md
diff -u src/usr.bin/xlint/lint1/README.md:1.14 src/usr.bin/xlint/lint1/README.md:1.15
--- src/usr.bin/xlint/lint1/README.md:1.14	Thu Sep 14 21:08:12 2023
+++ src/usr.bin/xlint/lint1/README.md	Mon Feb  5 23:11:22 2024
@@ -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`.
 
Index: src/usr.bin/xlint/lint1/oper.c
diff -u src/usr.bin/xlint/lint1/oper.c:1.14 src/usr.bin/xlint/lint1/oper.c:1.15
--- src/usr.bin/xlint/lint1/oper.c:1.14	Thu Sep 14 22:20:08 2023
+++ src/usr.bin/xlint/lint1/oper.c	Mon Feb  5 23:11:22 2024
@@ -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" },

Index: src/usr.bin/xlint/lint1/cgram.y
diff -u src/usr.bin/xlint/lint1/cgram.y:1.486 src/usr.bin/xlint/lint1/cgram.y:1.487
--- src/usr.bin/xlint/lint1/cgram.y:1.486	Fri Feb  2 16:05:37 2024
+++ src/usr.bin/xlint/lint1/cgram.y	Mon Feb  5 23:11:22 2024
@@ -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, 
 	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, 
 %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
 /* 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);
 	}
 ;
 

Index: src/usr.bin/xlint/lint1/ckctype.c
diff -u src/usr.bin/xlint/lint1/ckctype.c:1.9 src/usr.bin/xlint/lint1/ckctype.c:1.10
--- src/usr.bin/xlint/lint1/ckctype.c:1.9	Sun Dec  3 13:12:40 2023
+++ src/usr.bin/xlint/lint1/ckctype.c	Mon Feb  5 23:11:22 2024
@@ -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 
 }
 
 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

Index: src/usr.bin/xlint/lint1/ckgetopt.c
diff -u src/usr.bin/xlint/lint1/ckgetopt.c:1.22 src/usr.bin/xlint/lint1/ckgetopt.c:1.23
--- src/usr.bin/xlint/lint1/ckgetopt.c:1.22	Sat Feb  3 19:25:16 2024
+++ src/usr.bin/xlint/lint1/ckgetopt.c	Mon Feb  5 23:11:22 2024
@@ -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
-
-	    && call->tn_right->tn_op == PUSH
+	    && 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
 
-	    && (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) {

Index: src/usr.bin/xlint/lint1/debug.c
diff -u src/usr.bin/xlint/lint1/debug.c:1.70 src/usr.bin/xlint/lint1/debug.c:1.71
--- src/usr.bin/xlint/lint1/debug.c:1.70	Sat Feb  3 19:25:16 2024
+++ src/usr.bin/xlint/lint1/debug.c	Mon Feb  5 23:11:22 2024
@@ -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(
 		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(
 		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);

Index: src/usr.bin/xlint/lint1/emit1.c
diff -u src/usr.bin/xlint/lint1/emit1.c:1.85 src/usr.bin/xlint/lint1/emit1.c:1.86
--- src/usr.bin/xlint/lint1/emit1.c:1.85	Sat Feb  3 19:25:16 2024
+++ src/usr.bin/xlint/lint1/emit1.c	Mon Feb  5 23:11:22 2024
@@ -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 *
 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_u
 	 * 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_u
 					/* 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_u
 
 			/* 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');

Index: src/usr.bin/xlint/lint1/externs1.h
diff -u src/usr.bin/xlint/lint1/externs1.h:1.215 src/usr.bin/xlint/lint1/externs1.h:1.216
--- src/usr.bin/xlint/lint1/externs1.h:1.215	Sat Feb  3 19:25:16 2024
+++ src/usr.bin/xlint/lint1/externs1.h	Mon Feb  5 23:11:22 2024
@@ -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 *);
 
 /*

Index: src/usr.bin/xlint/lint1/lint1.h
diff -u src/usr.bin/xlint/lint1/lint1.h:1.213 src/usr.bin/xlint/lint1/lint1.h:1.214
--- src/usr.bin/xlint/lint1/lint1.h:1.213	Sat Feb  3 19:37:02 2024
+++ src/usr.bin/xlint/lint1/lint1.h	Mon Feb  5 23:11:22 2024
@@ -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 */

Index: src/usr.bin/xlint/lint1/op.h
diff -u src/usr.bin/xlint/lint1/op.h:1.26 src/usr.bin/xlint/lint1/op.h:1.27
--- src/usr.bin/xlint/lint1/op.h:1.26	Sun Dec  3 18:17:41 2023
+++ src/usr.bin/xlint/lint1/op.h	Mon Feb  5 23:11:22 2024
@@ -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,

Index: src/usr.bin/xlint/lint1/tree.c
diff -u src/usr.bin/xlint/lint1/tree.c:1.602 src/usr.bin/xlint/lint1/tree.c:1.603
--- src/usr.bin/xlint/lint1/tree.c:1.602	Sat Feb  3 19:25:16 2024
+++ src/usr.bin/xlint/lint1/tree.c	Mon Feb  5 23:11:22 2024
@@ -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, t
 	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, tn
 	}
 
 	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 
 	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 
 		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
 }
 
 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
 	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
 	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 
 	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 
 	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);

Reply via email to