https://github.com/a-tarasyuk created https://github.com/llvm/llvm-project/pull/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 >From 56330fcdf146021a0146a47c56b4a0a8f35b0aec Mon Sep 17 00:00:00 2001 From: Oleksandr Tarasiuk <[email protected]> Date: Mon, 2 Feb 2026 01:25:30 +0200 Subject: [PATCH] [clang] avoid reentering header-name lexing on nested macro expansion --- clang/docs/ReleaseNotes.rst | 1 + clang/lib/Lex/Preprocessor.cpp | 12 +++++++++--- .../Preprocessor/embed___has_embed_parsing_errors.c | 11 +++++++++++ clang/test/Preprocessor/has_include.c | 10 ++++++++++ 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 2e7a9fff3161b..4f75f744089ef 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -221,6 +221,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) Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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@+2 {{expected value in expression}} #if __has_embed("" limit #endif + +// expected-error@+2 {{missing '(' after '__has_include'}} +// expected-error@+1 {{expected "FILENAME" or <FILENAME>}} +#if __has_embed(__has_include) +#endif + +// expected-error@+3 {{missing '(' after '__has_embed'}} +// expected-error@+2 {{expected value in expression}} +// expected-error@+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@+2 {{missing '(' after '__has_include'}} +// expected-error@+1 {{expected "FILENAME" or <FILENAME>}} +#if __has_include(__has_include) +#endif + +// expected-error@+2 {{missing '(' after '__has_embed'}} +// expected-error@+1 {{expected "FILENAME" or <FILENAME>}} +#if __has_include(__has_embed) +#endif + // expected-error@+1 {{'__has_include' must be used within a preprocessing directive}} __has_include _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
