[clang] 59553fa - [clang] avoid reentering header-name lexing on nested macro expansion (#179151)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Feb 13 08:58:55 PST 2026
Author: Oleksandr Tarasiuk
Date: 2026-02-13T18:58:50+02:00
New Revision: 59553fa27a52fd95d9f5386a4554e76f3a8e5c9a
URL: https://github.com/llvm/llvm-project/commit/59553fa27a52fd95d9f5386a4554e76f3a8e5c9a
DIFF: https://github.com/llvm/llvm-project/commit/59553fa27a52fd95d9f5386a4554e76f3a8e5c9a.diff
LOG: [clang] avoid reentering header-name lexing on nested macro expansion (#179151)
Fixes #178635
---
This PR addressed the issue when header-name _lexing_ reentered on
nested macro expansion.
`__has_include`/`__has_embed` lex a header name by calling
`LexHeaderName`, and neither expects nested expansion in that context.
If `__has_include` appears inside the header name expression (e.g.,
`__has_include(__has_include)`, or `__has_embed(__has_include)`)
https://github.com/llvm/llvm-project/blob/6a18039298174562a38f28ca06d12dcbf7f14f06/clang/lib/Lex/PPMacroExpansion.cpp#L1252
macro expansion reenters `LexHeaderName` and hits the assertion
https://github.com/llvm/llvm-project/blob/6a18039298174562a38f28ca06d12dcbf7f14f06/clang/lib/Lex/PPMacroExpansion.cpp#L1898
https://github.com/llvm/llvm-project/blob/6a18039298174562a38f28ca06d12dcbf7f14f06/clang/lib/Lex/PPMacroExpansion.cpp#L1156
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/lib/Lex/Preprocessor.cpp
clang/test/Preprocessor/embed___has_embed_parsing_errors.c
clang/test/Preprocessor/has_include.c
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 92731326ca1bf..2268622af0a0d 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -262,6 +262,7 @@ Bug Fixes in This Version
- Fix lifetime extension of temporaries in for-range-initializers in templates. (#GH165182)
- Fixed a preprocessor crash in ``__has_cpp_attribute`` on incomplete scoped attributes. (#GH178098)
- Fixes an assertion failure when evaluating ``__underlying_type`` on enum redeclarations. (#GH177943)
+- Fixed an assertion failure caused by nested macro expansion during header-name lexing (``__has_embed(__has_include)``). (#GH178635)
- Clang now outputs relative paths of embeds for dependency output. (#GH161950)
- Fixed an assertion failure when evaluating ``_Countof`` on invalid ``void``-typed operands. (#GH180893)
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 791a9644b6e85..6abcf37079798 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -1041,10 +1041,16 @@ void Preprocessor::LexTokensUntilEOF(std::vector<Token> *Tokens) {
bool Preprocessor::LexHeaderName(Token &FilenameTok, bool AllowMacroExpansion) {
// Lex using header-name tokenization rules if tokens are being lexed from
// a file. Just grab a token normally if we're in a macro expansion.
- if (CurPPLexer)
- CurPPLexer->LexIncludeFilename(FilenameTok);
- else
+ if (CurPPLexer) {
+ // Avoid nested header-name lexing when macro expansion recurses
+ // __has_include(__has_include))
+ if (CurPPLexer->ParsingFilename)
+ LexUnexpandedToken(FilenameTok);
+ else
+ CurPPLexer->LexIncludeFilename(FilenameTok);
+ } else {
Lex(FilenameTok);
+ }
// This could be a <foo/bar.h> file coming from a macro expansion. In this
// case, glue the tokens together into an angle_string_literal token.
diff --git a/clang/test/Preprocessor/embed___has_embed_parsing_errors.c b/clang/test/Preprocessor/embed___has_embed_parsing_errors.c
index 4c6b03069c518..d9f78fa82ecce 100644
--- a/clang/test/Preprocessor/embed___has_embed_parsing_errors.c
+++ b/clang/test/Preprocessor/embed___has_embed_parsing_errors.c
@@ -292,3 +292,14 @@ int a = __has_embed (__FILE__);
expected-error at +2 {{expected value in expression}}
#if __has_embed("" limit
#endif
+
+// expected-error at +2 {{missing '(' after '__has_include'}}
+// expected-error at +1 {{expected "FILENAME" or <FILENAME>}}
+#if __has_embed(__has_include)
+#endif
+
+// expected-error at +3 {{missing '(' after '__has_embed'}}
+// expected-error at +2 {{expected value in expression}}
+// expected-error at +1 {{expected "FILENAME" or <FILENAME>}}
+#if __has_embed(__has_embed)
+#endif
diff --git a/clang/test/Preprocessor/has_include.c b/clang/test/Preprocessor/has_include.c
index ff199bf23063f..13f9d99b3c080 100644
--- a/clang/test/Preprocessor/has_include.c
+++ b/clang/test/Preprocessor/has_include.c
@@ -148,6 +148,16 @@ MACRO1 // This should be fine because it is never actually reached
#if __has_include(stdint.h>)
#endif
+// expected-error at +2 {{missing '(' after '__has_include'}}
+// expected-error at +1 {{expected "FILENAME" or <FILENAME>}}
+#if __has_include(__has_include)
+#endif
+
+// expected-error at +2 {{missing '(' after '__has_embed'}}
+// expected-error at +1 {{expected "FILENAME" or <FILENAME>}}
+#if __has_include(__has_embed)
+#endif
+
// expected-error at +1 {{'__has_include' must be used within a preprocessing directive}}
__has_include
More information about the cfe-commits
mailing list