[PATCH 12/21] stop mangling arglist, get rid of TOKEN_ARG_COUNT

Al Viro <[email protected]> Mon, 16 Mar 2026 07:04:06 +0000
Newsgroups org.kernel.vger.linux-sparse
Message-ID <[email protected]>
Now it can be done - we no longer store the counters in arglist, so
there's no reason to mangle it.  Just have it return the pointer to
closing ) on success and let the caller split the list at that point.
Simplifies both the parse_arguments() and dump_macro() and fixes
a bug in the latter - pre-C99 gcc vararg macros used to lose ... in
-dM output.  They did work correctly, but dump_macro() output had
produced #define A(X,Y) instead of correct #define A(X,Y...)
Testcase added.

Signed-off-by: Al Viro <[email protected]>
---
 pre-process.c                        | 47 +++++++---------------------
 token.h                              |  9 ------
 tokenize.c                           |  4 ---
 validation/preprocessor/dump-macro.c |  4 ++-
 4 files changed, 15 insertions(+), 49 deletions(-)

diff --git a/pre-process.c b/pre-process.c
index aaf60293..a60ad687 100644
--- a/pre-process.c
+++ b/pre-process.c
@@ -1000,7 +1000,6 @@ static int token_different(struct token *t1, struct token *t2)
 	case TOKEN_IDENT:
 		different = t1->ident != t2->ident;
 		break;
-	case TOKEN_ARG_COUNT:
 	case TOKEN_UNTAINT:
 	case TOKEN_CONCAT:
 	case TOKEN_GNU_KLUDGE:
@@ -1077,22 +1076,12 @@ Eargs:
 	return false;
 }
 
-static inline void set_arg_count(struct token *token)
-{
-	token_type(token) = TOKEN_ARG_COUNT;
-}
-
 static struct token *parse_arguments(struct token *list)
 {
 	struct token *arg = list->next, *next = list;
 
-	set_arg_count(list);
-
-	if (match_op(arg, ')')) {
-		next = arg->next;
-		list->next = &eof_token_entry;
-		return next;
-	}
+	if (match_op(arg, ')'))
+		return arg;
 
 	while (token_type(arg) == TOKEN_IDENT) {
 		if (arg->ident == &__VA_ARGS___ident)
@@ -1102,26 +1091,18 @@ static struct token *parse_arguments(struct token *list)
 
 		next = arg->next;
 		if (match_op(next, ',')) {
-			set_arg_count(next);
 			arg = next->next;
 			continue;
 		}
 
-		if (match_op(next, ')')) {
-			set_arg_count(next);
-			next = next->next;
-			arg->next->next = &eof_token_entry;
+		if (match_op(next, ')'))
 			return next;
-		}
 
 		/* normal cases are finished here */
 
 		if (match_op(next, SPECIAL_ELLIPSIS)) {
 			if (match_op(next->next, ')')) {
-				set_arg_count(next);
 				macro_vararg = macro_nargs - 1;
-				next = next->next;
-				arg->next->next = &eof_token_entry;
 				return next->next;
 			}
 
@@ -1143,10 +1124,7 @@ static struct token *parse_arguments(struct token *list)
 			goto Enotclosed;
 		if (!macro_add_arg(arg->pos, &__VA_ARGS___ident))
 			return NULL;
-		set_arg_count(next);
 		macro_vararg = macro_nargs - 1;
-		next = next->next;
-		arg->next->next = &eof_token_entry;
 		return next;
 	}
 
@@ -1483,14 +1461,19 @@ static int do_handle_define(struct stream *stream, struct token **line, struct t
 	expansion = left->next;
 	if (!expansion->pos.whitespace) {
 		if (match_op(expansion, '(')) {
-			arglist = expansion;
-			expansion = parse_arguments(expansion);
-			if (!expansion) {
+			struct token *last = parse_arguments(expansion);
+			if (!last) {
 				macro_nargs = 0;
 				macro_vararg = -1;
 				return 1;
 			}
+			// last points to ) at the end of arguments,
+			// expansion starts right after that,
+			// everything up to that point is arglist.
 			macro_funclike = true;
+			arglist = expansion;
+			expansion = last->next;
+			last->next = &eof_token_entry;
 		} else if (!eof_token(expansion)) {
 			warning(expansion->pos,
 				"no whitespace before object-like macro body");
@@ -2281,20 +2264,14 @@ static void dump_macro(struct symbol *sym)
 	printf("#define %s", show_ident(sym->ident));
 	token = sym->arglist;
 	if (token) {
-		const char *sep = "";
 		int narg = 0;
-		putchar('(');
 		for (; !eof_token(token); token = token->next) {
-			if (token_type(token) == TOKEN_ARG_COUNT)
-				continue;
-			printf("%s%s", sep, show_token(token));
+			printf("%s", show_token(token));
 			if (token_type(token) == TOKEN_IDENT)
 				args[narg++] = token->ident;
-			sep = ",";
 		}
 		if (narg < nargs)
 			args[narg] = &__VA_ARGS___ident;
-		putchar(')');
 	}
 
 	token = sym->expansion;
diff --git a/token.h b/token.h
index b28ac2ca..e469e02d 100644
--- a/token.h
+++ b/token.h
@@ -103,7 +103,6 @@ enum token_type {
 	TOKEN_CONCAT,
 	TOKEN_GNU_KLUDGE,
 	TOKEN_UNTAINT,
-	TOKEN_ARG_COUNT,
 	TOKEN_IF,
 	TOKEN_SKIP_GROUPS,
 	TOKEN_ELSE,
@@ -168,13 +167,6 @@ struct string {
 	char data[];
 };
 
-/* will fit into 32 bits */
-struct argcount {
-	unsigned normal:10;
-	unsigned quoted:10;
-	unsigned str:10;
-};
-
 enum arg_kind {
 	ARG_QUOTED = 0,
 	ARG_NORMAL = 1,
@@ -207,7 +199,6 @@ struct token {
 		unsigned int special;
 		struct string *string;
 		int argnum;
-		struct argcount count;
 		char embedded[4];
 	};
 };
diff --git a/tokenize.c b/tokenize.c
index 54ea348c..85bc3f49 100644
--- a/tokenize.c
+++ b/tokenize.c
@@ -241,10 +241,6 @@ const char *show_token(const struct token *token)
 		sprintf(buffer, "<untaint>");
 		return buffer;
 
-	case TOKEN_ARG_COUNT:
-		sprintf(buffer, "<argcnt>");
-		return buffer;
-
 	default:
 		sprintf(buffer, "unhandled token type '%d' ", token_type(token));
 		return buffer;
diff --git a/validation/preprocessor/dump-macro.c b/validation/preprocessor/dump-macro.c
index 46d70b34..710c1027 100644
--- a/validation/preprocessor/dump-macro.c
+++ b/validation/preprocessor/dump-macro.c
@@ -1,9 +1,11 @@
 #define A(X,Y,...) __VA_ARGS__,Y,X
+#define B(X,Y...) Y
 /*
  * check-name: -dM handling of varargs
- * check-command: sparse -E -dM $file | tail -1
+ * check-command: sparse -E -dM $file | tail -2
  *
  * check-output-start
 #define A(X,Y,...) __VA_ARGS__,Y,X
+#define B(X,Y...) Y
  * check-output-end
  */
-- 
2.47.3