[PATCH 13/21] deal with ## on arguments separately

Al Viro <[email protected]> Mon, 16 Mar 2026 07:04:07 +0000
Newsgroups org.kernel.vger.linux-sparse
Message-ID <[email protected]>
Adding/concatenating the chunks to growing expansion is done in the end
of loop body in substitute(); preceding switch leaves the data for it in
two variables - 'added' is the first token of the next chunk and 'tail'
points to the forward pointer in the last token of that chunk.

The only case when we might be adding more than one token is macro
argument; forcing it to use the same path as everything else complicates
things for no good reason, especially when it comes to concatenation.

Let the TOKEN_MACRO_ARGUMENT case deal with that stuff on its own.
In case of concatenation let it merge the first token before
copying/inserting the rest; that simplifies the common case and it
simplifies the data flow for everyone since we don't need to bother with
'tail' anymore.

As a side benefit, merge() is no longer inlined, which reduces the spills.

That chunk could go after __VA_OPT__ handling, but having it done first
simplifies the things for __VA_OPT__ (and especially for #__VA_OPT__()),
so let's put that one first.

Signed-off-by: Al Viro <[email protected]>
---
 pre-process.c | 38 +++++++++++++++++++++++---------------
 1 file changed, 23 insertions(+), 15 deletions(-)

diff --git a/pre-process.c b/pre-process.c
index a60ad687..16cec8e1 100644
--- a/pre-process.c
+++ b/pre-process.c
@@ -650,7 +650,7 @@ static struct token **substitute(struct token **list, const struct token *body,
 
 	for (; !eof_token(body); body = body->next) {
 		struct token *added, *arg;
-		struct token **tail;
+		struct token **inserted_at;
 		const struct token *t;
 
 		switch (token_type(body)) {
@@ -674,7 +674,6 @@ static struct token **substitute(struct token **list, const struct token *body,
 			}
 			added = dup_token(t, base_pos);
 			token_type(added) = TOKEN_SPECIAL;
-			tail = &added->next;
 			break;
 
 		case TOKEN_MACRO_ARGUMENT:
@@ -686,13 +685,28 @@ static struct token **substitute(struct token **list, const struct token *body,
 					state = Placeholder;
 				continue;
 			}
+			if (state == Concat && merge(containing_token(list), arg)) {
+				arg = arg->next;
+				if (eof_token(arg)) {
+					// merged the sole token in
+					state = Normal;
+					continue;
+				}
+				inserted_at = NULL;
+			} else {
+				inserted_at = list;
+			}
 			if (body->argnum & (1 << ARGNUM_CONSUME))
-				tail = move_into(&added, arg);
+				list = move_into(list, arg);
 			else
-				tail = copy(&added, arg);
-			added->pos.newline = body->pos.newline;
-			added->pos.whitespace = body->pos.whitespace;
-			break;
+				list = copy(list, arg);
+			if (inserted_at) {
+				struct token *p = *inserted_at;
+				p->pos.whitespace = body->pos.whitespace;
+				p->pos.newline = 0;
+			}
+			state = Normal;
+			continue;
 
 		case TOKEN_CONCAT:
 			if (state == Placeholder)
@@ -703,7 +717,6 @@ static struct token **substitute(struct token **list, const struct token *body,
 
 		default:
 			added = dup_token(body, base_pos);
-			tail = &added->next;
 			break;
 		}
 
@@ -711,17 +724,12 @@ static struct token **substitute(struct token **list, const struct token *body,
 		 * if we got to doing real concatenation, we already have
 		 * added something into the list, so containing_token() is OK.
 		 */
-		if (state == Concat && merge(containing_token(list), added)) {
-			*list = added->next;
-			if (tail != &added->next)
-				list = tail;
-		} else {
+		if (state != Concat || !merge(containing_token(list), added)) {
 			*list = added;
-			list = tail;
+			list = &added->next;
 		}
 		state = Normal;
 	}
-	*list = &eof_token_entry;
 	return list;
 }
 
-- 
2.47.3