https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120600
Bug ID: 120600
Summary: Inconsistent header name parsing in __has_include
Product: gcc
Version: 16.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: preprocessor
Assignee: unassigned at gcc dot gnu.org
Reporter: luigighiron at gmail dot com
Target Milestone: ---
The following code demonstrates how __has_include inconsistently parses header
names:
#define X stdio.h
#define Y (
#define Z __has_include(
int a=
#if __has_include Y<X>)
1
#else
0
#endif
;
int b=
#if Z<X>)
1
#else
0
#endif
;
#include<stdio.h>
int main(){
printf("%i %i\n",a,b);
}
Assuming a file named X doesn't exist, 1 0 is printed by GCC. Furthermore, if
the opening parenthesis in the definition of Z is replaced by Y then 1 1 is
printed. That is, GCC only parses header names if the __has_include and opening
parenthesis are not separated. Interestingly, 0 1 is printed when using Clang
instead. MSVC prints 0 0 (with and without /Zc:preprocessor), and from my
testing will always attempt to parse a header name in __has_include. Parsing
header names inconsistently here seems like a bug, I don't see any reason for
the behavior to be this way.
Also, there is a divergence between compilers about uses of #include such as:
#define X stdio.h
#define NONE
#include NONE<X>
GCC has this include stdio.h, while Clang and MSVC (with and without
/Zc:preprocessor) have this include X. Though all compilers accept this as
including X:
#define X stdio.h
#define NONE
#include<X>NONE
The divergence of parsing header names when an empty macro is placed before the
header name is also reflected in __has_include. I think the sentence "The
identifiers __has_include, __has_embed, and __has_c_attribute shall not appear
in any context not mentioned in this subclause." from C23 could be interpreted
as making these cases undefined behavior, though macro expansion is described
as happening first so that is not how I interpreted it. Moreover, it would be
strange to support these uses at all if it is undefined.