## __VA_ARGS__ in binutils-gdb?
Nick Alcock
nick.alcock@oracle.com
Sun Nov 23 13:01:52 GMT 2025
More information about the Binutils mailing list
Sun Nov 23 13:01:52 GMT 2025
- Previous message (by thread): ## __VA_ARGS__ in binutils-gdb?
- Next message (by thread): ## __VA_ARGS__ in binutils-gdb?
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
On 21 Nov 2025, Jan Beulich said:
> On 20.11.2025 17:18, Nick Alcock via Binutils wrote:
>> I'm trying to do this while keeping the number of translatable strings
>> down, ideally by keeping the strings the same for the same errors coming
>> from different functions, but including the name of the function that
>> failed in the output, so I can say (e.g. in ctf_add_decl_tag()):
>>
>> ctf_err_type (fp, type, ECTF_RANGE,
>> _("component index %i greater than member count %lu"),
>> component_idx, ctf_member_count (fp, type));
>>
>> and have it emit this into the err/warning stream:
>>
>> ctf_add_decl_tag (".BTF", 0x402): component index 42 greater than member count 6: argument out of range
>>
>> or, for something in which no extra info is needed, we can eschew the
>> translatable string entirely and simplify right down, e.g. this from
>> ctf_add_member_bitfield():
>>
>> ctf_err_type (fp, type, ECTF_INCOMPLETE, NULL);
>>
>> which emits (for a type in a child dict derived from foo/bar.c):
>>
>> ctf_add_member_bitfield ("foo/bar.c", 0x392): type is not a complete type
>>
>> (where "type is not a complete type" is what ctf_errmsg() returns for
>> ECTF_INCOMPLETE).
>>
>> Now obviously the key here is the function name, and I really don't want
>> to have to type __func__ in everywhere. So that means a variadic macro.
>> But ## __VA_ARGS__ is a GCC-specific compiler extension, and all
>> hackarounds for its absence are either horrifying (HAS_COMMA) or too new
>> to rely on (__VA_OPT__).
>
> Without you actually showing the intended macro, it's not quite clear to
> me whether the extension really needs using. In particular I don't see
It clearly doesn't: I thought of a better way.
> why the function name would be the culprit. The need to use ## is generally
> tied to __VA_ARGS__ expanding to nothing, where the extra comma would get
> in the way. (Which effectively means it's less the macro itself that's of
> interest, but the overall set of use sites: Are there any which pass no
> extra arguments at all for the variadic part?)
That happens here -- this is basically a printf() with extra arguments
on the front, one of which I'd like to be a __func__. printf() can
handle zero variadic args: so should this.
But there is a way to do this with only *slightly* extra weirdness while
remaining standards-compliant, I think.
>> So I was surprised to find ## __VA_ARGS__ in use in binutils-gdb with no
>> configure tests or ifdeffery guarding it; mostly in GDB but also in some
>> arch-dependent parts of BFD. So I'm wondering... is ## __VA_ARGS__
>> widely enough available that I can use it in libctf? People using
>> strange compilers without this GCC extension can always disable libctf,
>> but if such compilers are actually still commonplace this would make me
>> rather queasy. (I suspect they're rare as anything.)
>
> I'm puzzled here, too: I can find uses of __VA_ARGS__ in bfd/, but none of
> ## __VA_ARGS__.
I typoed -- I originally missed off the ##, then reported on the output
of the wrong grep :(
> I can spot
> - one in binutils/objcopy.c,
> - one in gas/gen-sframe.h (with exactly one use site),
> - two in include/opcode/aarch64.h (guarded by DEBUG_AARCH64),
> - two in libsframe/testsuite/sframe-test.h,
> - one in opcodes/bfin-dis.c (where the ## could easily be dropped).
>
> The likely reason this has gone through so far is imo a lack of testing in
> uncommon environments, possibly together with people not being aware that
Yeah, this is probably simply stuff that crept in unnoticed, which is
why I asked if using it was really OK (and, more generally, how archaic
a compiler we support -- standard C99, yes, do we know if we still
actually compile on compilers with no GNU C extensions at all? Are there
even any left? HP-UX's bundled C compiler was the old hideous monster
that caused everyone pain, but that wasn't even ANSI and is long dead.)
> they're using an extension. Imo the uses (perhaps with the exception of
> debugging-only ones) would better be dropped (and no new ones permitted in).
Agreed.
> Since you mention configure-time testing of the feature: How would you see
> a fallback look like if the extension is found unavailable? Without a
> pretty generally usable fallback, checking this in configure looks somewhat
> pointless to me.
Yeah, that was my other big worry -- if I could have just thrown a
fallback in, I'd have done that and not worried about it.
Still... my fundamental problem was that I was trying to combine a macro
(for automatically supplying __func__ in the right function), and a
stdargs function -- and while both are needed, there's no reason for the
two to be in the same function call. In trivial testing the below seems
to work, and doesn't require anything nonstandard, though I'd better
make sure that inline doesn't produce ugly code and just non-inline it
if it does, it's just on an error path after all:
typedef struct ctf_err_locus
{
ctf_dict_t *fp;
ctf_id_t type;
const char *func;
} ctf_err_locus_t;
__attribute__((__format__(printf, 3, 4)))
void ctf_err_type (ctf_err_locus_t l, ctf_error_t err, const char *format, ...);
ctf_err_locus_t
err_locus_internal (ctf_dict_t *fp, ctf_id_t type, const char *func)
{
ctf_err_locus_t l;
l.fp = fp;
l.type = type;
l.func = func;
return l;
}
#define err_locus(fp, type) err_locus_internal (fp, type, __func__)
void
foo (ctf_dict_t *fp, ctf_id_t type, int16_t component_idx)
{
ctf_err_type (err_locus (fp, type), ECTF_BADCOMPONENT,
"component index %i greater than member count %lu",
component_idx, ctf_member_count (fp, type));
ctf_err_type (err_locus (fp, type), ECTF_BADCOMPONENT,
"foo no format string");
ctf_err_type (err_locus (fp, type), ECTF_INCOMPLETE, NULL);
}
(and all three test cases compile fine: NULL, no variadic args,
variadic args.)
(all totally internal to libctf, of course, nothing outside can see any
of this.)
--
NULL && (void)
- Previous message (by thread): ## __VA_ARGS__ in binutils-gdb?
- Next message (by thread): ## __VA_ARGS__ in binutils-gdb?
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
More information about the Binutils mailing list