Re: [PATCH] sparse: add support for __VA_OPT__

Al Viro <[email protected]> Wed, 25 Feb 2026 03:36:39 +0000
Newsgroups org.kernel.vger.linux-sparse
Message-ID <20260225033639.GA2924820@ZenIV>
On Tue, Feb 24, 2026 at 06:39:57PM -0800, Chris Li wrote:

> > I guess if you wanted instead of a comma then you could have an empty
> > __VA_OPT__() or you could pass random things like __VA_OPT__(a b c).  I
> > don't know why you would do that.  In this case, "a" is a macro argument
> > so that has to be expanded out.

<sarcasm>
Then perhaps reading the standard might prove enlightening - possibly
due to examples that might be in there, or seeing the actual description
of semantics?  https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf
is there and searching for __VA_OPT__ would immediately get you this:

#define SDEF(sname, ...) S sname __VA_OPT__(= { __VA_ARGS__ })
SDEF(foo); // replaced by S foo;
SDEF(bar, 1, 2); // replaced by S bar = { 1, 2 };

Would that answer your question?
</sarcasm>

> One idea is to add an expand function expand___VA_OPT__, similar to
> expand_has_feature(). Register it in the dynamic expand macro array.
> That way you get the collect_arguments() for free and it behaves just
> like a builtin macro expansion. Just duplicate the collected arg list
> to the current token, if  there are extra arguments.

Sorry, no go; for one thing, #__VA_OPT__() won't be dealt with that way,
for another there's fun with foo ## __VA_OPT__(arg) (argument is expanded
*and* subjected to ## - yes, it's possible now).

I have something resembling a workable approach, but there's nasty corner
case when you mix it with the side effects; that's impossible in standard
C, but gcc has the sodding __COUNTER__ thing and _that_ makes life really
interesting.

If there's __VA_OPT__ in the body, we want to expand vararg whether it
occurs in the body or not.

We want to expand each argument that is present in the body.

Question: should we expand an argument that occurs *only* under __VA_OPT__?
Note that "expand and discard" is *not* a no-op - expansion of __COUNTER__
will have visible side effects.  What's more, gcc and clang diverge there.

Another kind of side effect is possible in standard C: argument substitution
might fail when attempted.  And gcc is arguably broken there - see
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=123325 for fun details.
clang handles that one sanely...

I got stalled waiting for gcc folks to respond, then sidetracked to other
stuff.  I'll resurrect that stuff later this week.