sleeptightAnsiC
sleeptightAnsiC

Reputation: 757

Is warning yielded by -Wc++-compat about identifiers not yet expanded by macro a false positive?

I've been compiling my C code against some very "non-default" warnings and found a potential GCC bug - a false positive caused by -Wc++-compat. Before explaining anything, it would probably be easier to introduce the code first:

main.c

#include <stdio.h>

#define X_KEYWORDS  \
        X(bool)     \
        X(not)      \
        X(and)      \
        X(or)       \
        X(xor)      \
        X(nullptr)  \
        X(true)     \
        X(false)

int main(void)
{
#       define X(keyword) puts(#keyword);
        X_KEYWORDS
#       undef X
        return 0;
}

And when compiled with -Wc++-compat, GCC prints following diagnostic:

$ gcc main.c -Wc++-compat
main.c:5:11: warning: identifier "not" is a special operator name in C++ [-Wc++-compat]
    5 |         X(not)      \
      |           ^
main.c:6:11: warning: identifier "and" is a special operator name in C++ [-Wc++-compat]
    6 |         X(and)      \
      |           ^
main.c:7:11: warning: identifier "or" is a special operator name in C++ [-Wc++-compat]
    7 |         X(or)       \
      |           ^
main.c:8:11: warning: identifier "xor" is a special operator name in C++ [-Wc++-compat]
    8 |         X(xor)      \
      |

As you can see, it warns me about constructs inside of a macro definition; these weren't expanded anywhere yet. The body of main is irrelevant here; it can be even empty - int main(void) {} - and the same warnings would appear anyway. I just wanted to show that this specific X-Macro has a valid use case.

Those warnings never appear in the actual expanded code. My snippet expands them into string literals which appear valid to me. I do not see how it would violate C++ dialect.

Those "faulty" identifiers are the same as the ones defined in libc <iso646.h> (?). Note that I also used other C++-specific keywords inside of the macro body, such as bool or nullptr, and the warning does not point at them.

Anyway, the mentioned behavior does not seem to occur with clang:

$ clang main.c -Wc++-compat

and compiles just fine as C++ with all compilers I have available at the moment:

$ mv main.c main.cpp
$ g++ main.cpp
$ cl main.cpp /nologo
main.cpp
$ clang++ main.cpp


(references)

$ uname -a
Linux MAL200424 6.11.6-arch1-1 #1 SMP PREEMPT_DYNAMIC Fri, 01 Nov 2024 03:30:41 +0000 x86_64 GNU/Linux

$ gcc --version
gcc (GCC) 14.2.1 20240910

$ clang --version
clang version 18.1.8

godbolt link: https://godbolt.org/z/8jo363EbP
GCC manual: https://gcc.gnu.org/onlinedocs/gcc-14.2.0/gcc/Warning-Options.html#index-Wc_002b_002b-compat
about <iso646.h>: https://en.cppreference.com/w/c/language/operator_alternative


EDIT: Got this reported here:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=117902

Upvotes: 5

Views: 143

Answers (2)

Lundin
Lundin

Reputation: 213809

Am I just safe to assume this is a GCC-specific bug?

Yes that seems likely since most optional diagnostics in gcc are quite broken since forever (I can reproduce the compiler bug down to gcc 5 and older yet).

As you say, it is senseless to warn against those reserved identifiers before they are actually used as identifiers in a C name space.

As it happens those identifiers are also reserved in C in some situations. C didn't include them as keywords like C++, but through iso646.h, which is a mandatory header for the compiler to implement.

According to C23 7.1.3 we may not declare identifiers at file scope which may collide with names of items in the standard library headers. But that is not the case here: you have not declared these as macros, but are rather using them as input arguments to macros which is fine.

A bunch of the things in the macro list is even C standard keywords now, as per C23. So it's buggy beyond just considering C++ compatibility... what about writing C code with C compatibility?


Or is there any case those diagnostics would be valid?

Only when those items from the X macro list are present as actual identifiers. Then it's not just a C++ compatibility issue but likely a C syntax error as well.


Why would it only warn about stuff from <iso646.h> ?

That does indeed not make any sense. The warning seems to be sloppily implemented.

Upvotes: 1

John Bollinger
John Bollinger

Reputation: 180201

  • Am I just safe to assume this is a GCC-specific bug?

As you observe yourself, the diagnostics flag the definition of macro X_KEYWORDS, not the location where it is expanded. At this point, the compiler does not know how that macro may be used, so it is probably best to characterize the behavior as GCC being exceedingly cautious, not buggy. I take it to be telling you that there might be ways you could use that macro that would be incompatible with C++. I anticipate that you would get additional diagnostics if you actually did use it in such a way (which you haven't).

So no, you should not take the diagnostics to be buggy, but neither should you take them as indicating that your overall program fails to be well-formed C++.

  • Or is there any case those diagnostics would be valid?

See above.

  • Why would it only warn about stuff from <iso646.h> ?

Of the particular preprocessing tokens under consideration, the ones GCC warns about are of type preprocessing-op-or-punc in C++, but of type identifier in C. The others are of type identifier in both languages. That appears to be what GCC means by calling those in the former group "special operator names". That's also the basis for potential incompatibilities.

Upvotes: 2

Related Questions