public inbox for linux-sparse@vger.kernel.org
 help / color / mirror / Atom feed
From: Al Viro <viro@zeniv.linux.org.uk>
To: linux-sparse@vger.kernel.org
Cc: chriscli@google.com, torvalds@linux-foundation.org,
	zxh@xh-zhang.com, ben.dooks@codethink.co.uk,
	dan.carpenter@linaro.org, rf@opensource.cirrus.com
Subject: [PATCH 05/21] simplify collect_arguments() and fix error handling there
Date: Mon, 16 Mar 2026 07:03:59 +0000	[thread overview]
Message-ID: <20260316070415.768839-5-viro@zeniv.linux.org.uk> (raw)
In-Reply-To: <20260316070415.768839-1-viro@zeniv.linux.org.uk>

The current logics is too convoluted.  We use collect_arg() to carve
an argument out; it takes a pointer to previous token (either opening
parenthesis or comma), finds how far does the argument extend, cuts the
list at its end and returns the token that follows it (normally either
closing parenthesis or the comma).  collect_arg() is told whether we
want a vararg argument or not - the difference is that normal arguments
terminate on commas.

When macro has N non-vararg arguments and V (0 or 1) vararg ones, we want
	* N calls of collect_arg() asking for non-vararg arguments;
all but the last one must be followed by commas.  The last one may be
followed either by comma or by closing parenthesis.
	* If we have seen exactly N commas, call collect_arg() asking
to collect everything until the closing parenthesis.  That will get us
to the end of arguments.

The only potential gotcha is that there is a case when "exactly N commas"
for non-vararg macro does _not_ mean excessive arguments - N = V = 0.
Not hard to account for - in that case we must look at the chunk carved
out by the last (and only) call of collect_arg(); that would be everything
between the parentheses.  If it's empty, we are fine, otherwise we've
excessive arguments.

Rather than trying to fold all of that into a single loop, separate
the handling of non-vararg arguments from the rest; the logics becomes
simpler that way, especially around the error recovery.

As a side benefit the 'vararg' bit in struct argcount becomes unused
and can be removed.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
 pre-process.c | 104 ++++++++++++++++++++++----------------------------
 token.h       |   1 -
 2 files changed, 46 insertions(+), 59 deletions(-)

diff --git a/pre-process.c b/pre-process.c
index d591a183..25990dfa 100644
--- a/pre-process.c
+++ b/pre-process.c
@@ -255,7 +255,7 @@ static void expand_list(struct token **list)
 
 static void preprocessor_line(struct stream *stream, struct token **line);
 
-static struct token *collect_arg(struct token *prev, int vararg, const struct position *pos)
+static struct token *collect_arg(struct token *prev, bool vararg, const struct position *pos)
 {
 	struct stream *stream = input_streams + prev->pos.stream;
 	struct token **p = &prev->next;
@@ -314,76 +314,66 @@ struct arg {
 
 static int collect_arguments(struct token *start, struct symbol *sym, struct arg *args, struct token *what)
 {
+	int fixed = sym->fixed_args;
+	bool vararg = sym->vararg;
 	struct token *arglist = sym->arglist;
-	int wanted = sym->fixed_args + sym->vararg;
-	struct token *next = NULL;
-	int count = 0;
+	struct argcount *p;
+	struct token *next = NULL, *v = NULL;
+	const char *err;
+	int commas;
 
 	arglist = arglist->next;	/* skip counter */
 
-	if (!wanted) {
-		next = collect_arg(start, 0, &what->pos);
-		if (eof_token(next))
+	for (commas = 0; commas < fixed; commas++) {
+		next = collect_arg(start, false, &what->pos);
+		if (token_type(next) != TOKEN_SPECIAL)
 			goto Eclosing;
-		if (!eof_token(start->next) || !match_op(next, ')')) {
-			count++;
-			goto Emany;
-		}
-	} else {
-		for (count = 0; count < wanted; count++) {
-			struct argcount *p = &arglist->next->count;
-			next = collect_arg(start, p->vararg, &what->pos);
-			if (eof_token(next))
-				goto Eclosing;
-			if (p->vararg && wanted == 1 && eof_token(start->next))
-				break;
-			arglist = arglist->next->next;
-			args[count].arg = start->next;
-			args[count].n_normal = p->normal;
-			args[count].n_quoted = p->quoted;
-			args[count].n_str = p->str;
-			if (match_op(next, ')')) {
-				count++;
-				break;
-			}
-			start = next;
-		}
-		if (count == wanted && !match_op(next, ')'))
-			goto Emany;
-		if (count == wanted - 1) {
-			struct argcount *p = &arglist->next->count;
-			if (!p->vararg)
+		p = &arglist->next->count;
+		arglist = arglist->next->next;
+		args[commas].arg = start->next;
+		args[commas].n_normal = p->normal;
+		args[commas].n_quoted = p->quoted;
+		args[commas].n_str = p->str;
+		if (!match_op(next, ',')) {
+			if (commas < fixed - 1)
 				goto Efew;
-			args[count].arg = NULL;
-			args[count].n_normal = p->normal;
-			args[count].n_quoted = p->quoted;
-			args[count].n_str = p->str;
+			break;
 		}
-		if (count < wanted - 1)
-			goto Efew;
+		start = next;
+	}
+	if (commas == fixed) {
+		next = collect_arg(start, true, &what->pos);
+		if (token_type(next) != TOKEN_SPECIAL)
+			goto Eclosing;
+		v = start->next;
+		if (fixed == 0 && eof_token(v))
+			v = NULL;
+	}
+	if (v && !vararg)
+		goto Eexcess;
+	if (vararg) {
+		p = &arglist->next->count;
+		args[fixed].arg = v;
+		args[fixed].n_normal = p->normal;
+		args[fixed].n_quoted = p->quoted;
+		args[fixed].n_str = p->str;
 	}
 	what->next = next->next;
 	return 1;
 
 Efew:
-	sparse_error(what->pos, "macro \"%s\" requires %d arguments, but only %d given",
-		show_token(what), wanted, count);
+	err = "too few arguments provided to";
+	next = next->next;
 	goto out;
-Emany:
-	while (match_op(next, ',')) {
-		next = collect_arg(next, 0, &what->pos);
-		count++;
-	}
-	if (eof_token(next))
-		goto Eclosing;
-	sparse_error(what->pos, "macro \"%s\" passed %d arguments, but takes just %d",
-		show_token(what), count, wanted);
+Eexcess:
+	err = "too many arguments provided to";
+	next = next->next;
 	goto out;
 Eclosing:
-	sparse_error(what->pos, "unterminated argument list invoking macro \"%s\"",
-		show_token(what));
+	err = "unterminated argument list invoking";
 out:
-	what->next = next->next;
+	sparse_error(what->pos, "%s macro \"%s\"", err, show_ident(sym->ident));
+	what->next = next;
 	return 0;
 }
 
@@ -1107,7 +1097,7 @@ static inline void set_arg_count(struct token *token)
 {
 	token_type(token) = TOKEN_ARG_COUNT;
 	token->count.normal = token->count.quoted =
-	token->count.str = token->count.vararg = 0;
+	token->count.str = 0;
 }
 
 static struct token *parse_arguments(struct token *list)
@@ -1148,7 +1138,6 @@ static struct token *parse_arguments(struct token *list)
 			if (match_op(next->next, ')')) {
 				set_arg_count(next);
 				macro_vararg = macro_nargs - 1;
-				next->count.vararg = 1;
 				next = next->next;
 				arg->next->next = &eof_token_entry;
 				return next->next;
@@ -1176,7 +1165,6 @@ static struct token *parse_arguments(struct token *list)
 			return NULL;
 		set_arg_count(next);
 		macro_vararg = macro_nargs - 1;
-		next->count.vararg = 1;
 		next = next->next;
 		arg->next->next = &eof_token_entry;
 		return next;
diff --git a/token.h b/token.h
index 9000e0cb..5dcd8594 100644
--- a/token.h
+++ b/token.h
@@ -175,7 +175,6 @@ struct argcount {
 	unsigned normal:10;
 	unsigned quoted:10;
 	unsigned str:10;
-	unsigned vararg:1;
 };
 
 /*
-- 
2.47.3


  parent reply	other threads:[~2026-03-16  7:01 UTC|newest]

Thread overview: 42+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <cover.1771930766.git.dan.carpenter@linaro.org>
2026-02-24 11:07 ` [PATCH] sparse: add support for __VA_OPT__ Dan Carpenter
2026-02-24 11:16   ` Ben Dooks
2026-02-24 11:56     ` Dan Carpenter
2026-02-24 12:42       ` Richard Fitzgerald
2026-02-24 13:15         ` Ben Dooks
2026-02-25  2:39   ` Chris Li
2026-02-25  3:36     ` Al Viro
2026-02-25  5:29       ` [RFC PATCH] pre-process: add __VA_OPT__ support Eric Zhang
2026-02-25  6:40         ` Al Viro
2026-02-25  7:27           ` Al Viro
2026-02-25  8:14             ` Eric Zhang
2026-02-25 22:18               ` Al Viro
2026-02-26  7:29                 ` Al Viro
2026-03-16  6:56                   ` Al Viro
2026-03-16  7:03                     ` [PATCH 01/21] split copy() into "need to copy" and "can move in place" cases Al Viro
2026-03-16  7:03                       ` [PATCH 02/21] expand and simplify the call of dup_token() in copy() Al Viro
2026-03-16  7:03                       ` [PATCH 03/21] more dup_token() optimizations Al Viro
2026-03-16  7:03                       ` [PATCH 04/21] parsing #define: saner handling of argument count, part 1 Al Viro
2026-03-16  7:03                       ` Al Viro [this message]
2026-03-16  7:04                       ` [PATCH 06/21] try_arg(): don't use arglist for argument name lookups Al Viro
2026-03-16  7:04                       ` [PATCH 07/21] make expand_has_...() responsible for expanding its argument Al Viro
2026-03-16  7:04                       ` [PATCH 08/21] preparing to change argument number encoding for TOKEN_..._ARGUMENT Al Viro
2026-03-16  7:04                       ` [PATCH 09/21] steal 2 bits from argnum for argument kind Al Viro
2026-03-16  7:04                       ` [PATCH 10/21] on-demand argument expansion Al Viro
2026-03-16  7:04                       ` [PATCH 11/21] kill create_arglist() Al Viro
2026-03-16  7:04                       ` [PATCH 12/21] stop mangling arglist, get rid of TOKEN_ARG_COUNT Al Viro
2026-03-16  7:04                       ` [PATCH 13/21] deal with ## on arguments separately Al Viro
2026-03-16  7:04                       ` [PATCH 14/21] preparations for __VA_OPT__ support: reshuffle argument slot assignments Al Viro
2026-03-16  7:04                       ` [PATCH 15/21] pre-process.c: split try_arg() Al Viro
2026-03-16  7:04                       ` [PATCH 16/21] __VA_OPT__: parsing Al Viro
2026-03-16  7:04                       ` [PATCH 17/21] expansion-time va_opt handling Al Viro
2026-03-16  7:04                       ` [PATCH 18/21] merge(): saner handling of ->noexpand Al Viro
2026-03-16  7:04                       ` [PATCH 19/21] simplify the calling conventions of collect_arguments() Al Viro
2026-03-16  7:04                       ` [PATCH 20/21] make expand_one_symbol() inline Al Viro
2026-03-16  7:04                       ` [PATCH 21/21] substitute(): convert switch() into cascade of ifs Al Viro
2026-03-16 16:42                     ` [RFC PATCH] pre-process: add __VA_OPT__ support Linus Torvalds
2026-03-19  3:53                       ` Al Viro
2026-03-19  4:07                         ` Linus Torvalds
2026-03-19  5:34                           ` Al Viro
2026-03-17  7:41                     ` Chris Li
2026-03-18  6:35                     ` Eric Zhang
2026-02-25  7:05       ` [PATCH] sparse: add support for __VA_OPT__ Chris Li

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260316070415.768839-5-viro@zeniv.linux.org.uk \
    --to=viro@zeniv.linux.org.uk \
    --cc=ben.dooks@codethink.co.uk \
    --cc=chriscli@google.com \
    --cc=dan.carpenter@linaro.org \
    --cc=linux-sparse@vger.kernel.org \
    --cc=rf@opensource.cirrus.com \
    --cc=torvalds@linux-foundation.org \
    --cc=zxh@xh-zhang.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox