Issue 1071: Header names, __has_include, and __has_embed

Authors: Jay Ghiron
Date: 2026-06-02
Submitted against: C23
Status: Open

For this issue, assume the following macros are always defined:

#define E
#define S <
#define C(A,B)A##B
#define H __has_include
#define G __has_include(
#define L (
#define X Y
#define Z <X>

Additionally, assume that the implementation has the header name <X> identify a file named X and has the three preprocessing tokens <, Y, and > with no whitespace between identify a file named Y when used in place of a header name. GCC, Clang, MSVC, and EDG all agree on the behavior of the following:

#include<X>
#include Z

Which includes a file named X and then a file named Y. <X> in the first #include directive forms a header name, but the second #include directive does not since the <X> is not present in the #include directive. Since the second #include directive does not form a header name the X inside of the angle brackets gets expanded to become Y. The macro X here is used to test if a header name is formed which contains X. Header name formation is also visible with sequences of characters that can form preprocessing tokens other than < and > punctuators:

#include<->
#define HYPHEN <->
#include HYPHEN

The first #include directive can be valid, but the second #include directive is not valid because HYPHEN gets lexed as two preprocessing tokens < and -> rather than three preprocessing tokens <, -, and >. Implementations sometimes do not reject using preprocessing tokens other than < and > at the beginning and ending respectively, but the intent seems clear enough that other punctuator preprocessing tokens cannot be used. In C++ CWG 3015 and C++ CWG 3078 the parsing of header names has been clarified there, but no compilers seem to actually implement those defect reports yet. Most of the following questions will be using #include and __has_include, but the same issues exist for #embed and __has_embed as well. In the following questions, assume that any included file exists and is valid.

Question 1

#include<X>E

Is this valid? That is, if an #include directive does not include just a header name can the preprocessing tokens inside of it expand to a header name? GCC, Clang, MSVC, and EDG all accept this as including a file named X. All further questions assume that this is valid.

Question 2

#include E<X>

Does this include a file named X or a file named Y? GCC and EDG include a file named Y, Clang and MSVC include a file named X. The wording "within #include and #embed preprocessing directives, in __has_include and __has_embed expressions" (C23 6.4.1 paragraph 4) is not clear about whether this counts as within the preprocessing directive. This also applies to __has_include:

#if __has_include(E<X>)
1
#else
0
#endif

Does this test for the existence of a file named X or a file named Y? GCC and EDG test for the existence of a file named Y, Clang and MSVC test for the existence of a file named X.

Question 3

#include S<X>

If the answer to question two is that #include E<X> includes a file named X, is this valid or invalid and does it expand X? If a header name is formed, it appears that the result would be invalid. GCC, Clang, and EDG all accept this as valid and do expand X. MSVC with its old preprocessor accepts this as valid and does not expand X. MSVC with its new preprocessor rejects this as invalid. This also applies to __has_include:

#if __has_include(S<X>)
1
#else
0
#endif

If the answer to question two is that __has_include(E<X>) tests for the existence of a file named X, is this valid or invalid and does it expand X? If a header name is formed, it appears that the result would be invalid. GCC, Clang, and EDG all accept this as valid and do expand X. MSVC with its old preprocessor accepts this as valid and does not expand X. MSVC with its new preprocessor rejects this as invalid.

Question 4

Can token concatenation form header names? For example:

#include C(<=,>)

Does this form the header name <=> in token concatenation? GCC, Clang, MSVC, and EDG all do not allow this but the wording in the standard does not clearly forbid it. If it is possible, the following is an exhaustive list of all possible header names that could be formed from concatenation: <->, <:>, <%>, <=>, <=->, <=:>, <=%>, <<>, <<->, <<:>, <<%>, <<=>, <<=->, <<=:>, <<=%>, <:->, <::>, <:%>, <%->, <%:>, and <%%>.

Question 5

Can __has_include, __has_embed, and __has_c_attribute expressions be the result of macro expansions?

The identifiers __has_include, __has_embed, and __has_c_attribute shall not appear in any context not mentioned in this subclause.

(C23 6.10.2 "Conditional inclusion" paragraph 11.)

GCC, Clang, MSVC, and EDG all do not reject macros like H, though it seems like the above sentence can be construed as making H undefined. If it should be interpreted as making H undefined, then in C++ which uses the same wording it should be ill-formed there due to the different meaning of "shall". Note that there is a significant amount of code which does roughly the following:

#ifdef __has_include
#define MY_HAS_INCLUDE(...)__has_include(__VA_ARGS__)
#else
#define MY_HAS_INCLUDE(...)0
#endif

Question 6

#if H(<X>)
1
#else
0
#endif

If the answer to question five is that __has_include can be the result of macro expansions, does this test for the existence of a file named X or a file named Y? GCC, Clang, MSVC, and EDG all agree that this tests for the existence of a file named X, even though reaching such a result requires that translation phase three knows about macro expansion.

Question 7

#if G<X>)
1
#else
0
#endif

If the answer to question five is that __has_include can be the result of macro expansions, does this test for the existence of a file named X or a file named Y? GCC, MSVC, and EDG test for the existence of a file named X, Clang tests for the existence of a file named Y.

Question 8

#if __has_include L<X>)
1
#else
0
#endif

Does this test for the existence of a file named X or a file named Y? Clang, MSVC, and EDG test for the existence of a file named X, GCC tests for the existence of a file named Y.

Question 9

Depending upon how previous questions are answered, if lexing depends upon macro definitions then this creates awkward situations in skipped preprocessing directives:

#if 1
#elif __has_include("\"")
#elif H("\"")
#endif

Does the skipped __has_include("\"") attempt to form the invalid header name "\" and then the invalid incomplete string literal? The wording does not seem to make any distinction of lexing in skipped preprocessing directives, but GCC and Clang seem to try to form string literals here despite __has_include being used. MSVC and EDG will accept any sequence of characters inside of skipped preprocessing directives, even those that do not form valid preprocessing tokens. Since H cannot be expanded here, it seems like H("\"") must be lexed as containing a string literal "\"".

Question 10

Can __has_include, __has_embed, and __has_c_attribute expressions be passed as arguments to macros, and if they can are header names still formed in __has_include and __has_embed? If it is possible and header names are still formed, then those header names can be extracted:

#define HEADER__has_include(...)__VA_ARGS__
#define HEADER(...)HEADER##__VA_ARGS__
#if __has_include(HEADER(__has_include(<X>)))
1
#else
0
#endif

GCC, MSVC with its old preprocessor, and EDG test for the existence of a file named Y, Clang and MSVC with its new preprocessor test for the existence of a file named X. With the following slight variation:

#define HEADER__has_include
#define HEADER(...)HEADER##__VA_ARGS__
#if __has_include HEADER(__has_include(<X>))
1
#else
0
#endif

MSVC will test for a file named Y in both its old preprocessor and new preprocessor. GCC, Clang, and EDG all behave the same in this variation. If header names can be used in arguments to macros, then they can also be subject to stringization and concatenation. In C++ header names are conditionally allowed to contain backslashes and quotes, so stringization there mentions header names as needing escaping. It appears that quoted header names can be concatenated with an encoding prefix to form a string literal. Header name formation is also visible in this context with header names such as <)> or <,> since they would otherwise affect how the arguments to a function-like macro are identified.

Question 11

#if __has_embed("something"limit(defined __has_embed))
1
#else
0
#endif

Is this valid? That is, does the defined macro expression get replaced inside of the __has_embed expression considering it gets replaced first:

After all replacements due to macro expansion and evaluations of defined macro expressions, has_include expressions, has_embed expressions, and has_c_attribute expressions have been performed, all remaining identifiers other than true (including those lexically identical to keywords such as false) are replaced with the pp-number 0, true is replaced with pp-number 1, and then each preprocessing token is converted into a token.

(C23 6.10.2 "Conditional inclusion" paragraph 13.)

GCC and Clang reject this as invalid, MSVC and EDG do not support __has_embed yet. C++ explicitly disallows this and it seems like N3811 wants to disallow it. Though the wording in N3811 would not actually disallow it if defined macro expressions in __has_embed expressions get replaced before they are considered.