Note: This is not important for the question
I have some macros that act as slightly more general version of attributes, that I attach to functions. Depending on the compiler and compiler version, they will either expand to an attribute (e.g. __attribute__((nonnull))
), or a warning (e.g. _Pragma("message \"nonnull attribute unavailable\"")
). Since the attribute macros can be in any order, this can lead to them being intermixed (e.g. warning attribute attribute warning warning).
The result is that I can have code like the following:
#pragma message "one"
__attribute__((cold))
#pragma message "two"
__attribute__((noreturn))
#pragma message "three"
void test(void);
Running clang
, this sample code compiles perfectly fine, printing the three messages as expected.
input.c:1:9: warning: one [-W#pragma-messages]
#pragma message "one"
^
input.c:3:9: warning: two [-W#pragma-messages]
#pragma message "two"
^
input.c:5:9: warning: three [-W#pragma-messages]
#pragma message "three"
^
Running gcc
however, gives me an error on the second #pragma
. If I comment that out, I get an error on the third #pragma
.
input.c:1:9: note: ‘#pragma message: one’
1 | #pragma message "one"
| ^~~~~~~
input.c:3:9: error: expected identifier or ‘(’ before ‘#pragma’
3 | #pragma message "two"
| ^~~~~~~
input.c:1:9: note: ‘#pragma message: one’
1 | #pragma message "one"
| ^~~~~~~
input.c:5:9: error: expected identifier or ‘(’ before ‘#pragma’
5 | #pragma message "three"
| ^~~~~~~
With experimentation, it seems that gcc
does not accept any #pragma
directives after an __attribute__
.
Uncommenting the #pragma
causes a reproducible error on GCC v11.4.0
__attribute__((nonnull))
// #pragma message "this is an error"
void test(void);
Is there any fix or solution to allow me to intermingle the #pragma
and __attribute__
directives on gcc
, just like clang
allows?
I've tried a number of different combinations and they all produce the results you're seeing.
This could be due to the different ways that gcc
and clang
do parsing. clang
has the preprocessor fully integrated. For gcc
, it's a separate pass/program.
So, AFAICT, no direct solution.
I have some macros that act as slightly more general version of attributes, that I attach to functions. Depending on the compiler and compiler version, they will either expand to an attribute (e.g.
__attribute__((nonnull))
), or a warning (e.g._Pragma("message \"nonnull attribute unavailable\"")
).
You didn't specify how the macros are conditionally generated, but I'll take a guess. You have something similar to autoconf
that probes the system and generates (e.g. config.h
).
There may be a workaround, if you [just] want to warn/error on an unsupported attribute.
This is a bit of a hack, but ...
#if HAVE_INLINE
#define always_inline always_inline
#else
#define always_inline always_inline_not_supported
#endif
__attribute__ ((cold))
__attribute__ ((noreturn))
__attribute__ ((always_inline))
void
test(void *);
Compiling with -DHAVE_INLINE
compiles cleanly.
Compiling without -DHAVE_INLINE
produces:
x.c:11:1: warning: ‘always_inline_not_supported’ attribute directive ignored [-Wattributes]
test(void *);
^~~~
It can be even simpler:
#if !HAVE_INLINE
#define always_inline always_inline_not_supported
#endif
__attribute__ ((cold))
__attribute__ ((noreturn))
__attribute__ ((always_inline))
void
test(void *);