https://github.com/kelbon updated https://github.com/llvm/llvm-project/pull/65851
>From d10ce5dd9e49fe85eac2e1f93a65cb27b511a71f Mon Sep 17 00:00:00 2001 From: Kelbon Nik <kelbon...@gmail.com> Date: Sat, 9 Sep 2023 17:51:15 +0400 Subject: [PATCH 01/17] add define2 pp directive --- clang/include/clang/Basic/TokenKinds.def | 1 + clang/include/clang/Lex/MacroInfo.h | 19 +++++++++---------- clang/include/clang/Lex/Preprocessor.h | 2 +- clang/lib/Basic/IdentifierTable.cpp | 2 ++ clang/lib/Format/WhitespaceManager.cpp | 2 +- clang/lib/Lex/MacroInfo.cpp | 3 ++- clang/lib/Lex/PPDirectives.cpp | 16 +++++++++++----- 7 files changed, 27 insertions(+), 18 deletions(-) diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 72e8df8c793a7b6..b227a6a5632f496 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -115,6 +115,7 @@ PPKEYWORD(__include_macros) // C99 6.10.3 - Macro Replacement. PPKEYWORD(define) +PPKEYWORD(define2) PPKEYWORD(undef) // C99 6.10.4 - Line Control. diff --git a/clang/include/clang/Lex/MacroInfo.h b/clang/include/clang/Lex/MacroInfo.h index 00c1c3866bbd9ca..4f0c8e987610e50 100644 --- a/clang/include/clang/Lex/MacroInfo.h +++ b/clang/include/clang/Lex/MacroInfo.h @@ -102,6 +102,10 @@ class MacroInfo { /// like \#define A A. bool IsDisabled : 1; + // True if 'define2' used, + // ignores 'IsDisabled' and enables expansion anyway + bool AllowRecurse : 1; + /// True if this macro is either defined in the main file and has /// been used, or if it is not defined in the main file. /// @@ -278,18 +282,13 @@ class MacroInfo { /// Return true if this macro is enabled. /// /// In other words, that we are not currently in an expansion of this macro. - bool isEnabled() const { return !IsDisabled; } - - void EnableMacro() { - assert(IsDisabled && "Cannot enable an already-enabled macro!"); - IsDisabled = false; - } + bool isEnabled() const { return AllowRecurse || !IsDisabled; } + void setAllowRecursive(bool Allow) { AllowRecurse = Allow; } + bool isAllowRecurse() const { return AllowRecurse; } - void DisableMacro() { - assert(!IsDisabled && "Cannot disable an already-disabled macro!"); - IsDisabled = true; - } + void EnableMacro() { IsDisabled = false; } + void DisableMacro() { IsDisabled = true; } /// Determine whether this macro was used for a header guard. bool isUsedForHeaderGuard() const { return UsedForHeaderGuard; } diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 575d08b83fd3a02..01eac0939fe9e21 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -2754,7 +2754,7 @@ class Preprocessor { void replayPreambleConditionalStack(); // Macro handling. - void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterHeaderGuard); + void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterHeaderGuard, bool AllowRecurse); void HandleUndefDirective(); // Conditional Inclusion. diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index e5599d545541085..7300825ff6b826a 100644 --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -431,6 +431,8 @@ tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const { unsigned Len = getLength(); if (Len < 2) return tok::pp_not_keyword; const char *Name = getNameStart(); + if (std::string_view(Name, Len) == "define2") + return tok::pp_define2; switch (HASH(Len, Name[0], Name[2])) { default: return tok::pp_not_keyword; CASE( 2, 'i', '\0', if); diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index b7bd8d27dc976b1..d8ab76d6761553e 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -743,7 +743,7 @@ void WhitespaceManager::alignConsecutiveMacros() { if (!Current || Current->isNot(tok::identifier)) return false; - if (!Current->Previous || Current->Previous->isNot(tok::pp_define)) + if (!Current->Previous || !Current->Previous->isOneOf(tok::pp_define, tok::pp_define2)) return false; // For a macro function, 0 spaces are required between the diff --git a/clang/lib/Lex/MacroInfo.cpp b/clang/lib/Lex/MacroInfo.cpp index 39bb0f44eff25ba..9c3619c7c909304 100644 --- a/clang/lib/Lex/MacroInfo.cpp +++ b/clang/lib/Lex/MacroInfo.cpp @@ -50,7 +50,7 @@ static_assert(MacroInfoSizeChecker<sizeof(void *)>::AsExpected, MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc), IsDefinitionLengthCached(false), IsFunctionLike(false), IsC99Varargs(false), IsGNUVarargs(false), IsBuiltinMacro(false), - HasCommaPasting(false), IsDisabled(false), IsUsed(false), + HasCommaPasting(false), IsDisabled(false), AllowRecurse(false), IsUsed(false), IsAllowRedefinitionsWithoutWarning(false), IsWarnIfUnused(false), UsedForHeaderGuard(false) {} @@ -157,6 +157,7 @@ LLVM_DUMP_METHOD void MacroInfo::dump() const { if (IsBuiltinMacro) Out << " builtin"; if (IsDisabled) Out << " disabled"; if (IsUsed) Out << " used"; + if (AllowRecurse) Out << " allow_recurse"; if (IsAllowRedefinitionsWithoutWarning) Out << " allow_redefinitions_without_warning"; if (IsWarnIfUnused) Out << " warn_if_unused"; diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 7edcb0577c2b25a..01b77a39437a30d 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -1111,7 +1111,11 @@ void Preprocessor::HandleSkippedDirectiveWhileUsingPCH(Token &Result, if (const IdentifierInfo *II = Result.getIdentifierInfo()) { if (II->getPPKeywordID() == tok::pp_define) { return HandleDefineDirective(Result, - /*ImmediatelyAfterHeaderGuard=*/false); + /*ImmediatelyAfterHeaderGuard=*/false, /*AllowRecurse=*/false); + } + if (II->getPPKeywordID() == tok::pp_define2) { + return HandleDefineDirective(Result, + /*ImmediatelyAfterHeaderGuard=*/false, /*AllowRecurse=*/true); } if (SkippingUntilPCHThroughHeader && II->getPPKeywordID() == tok::pp_include) { @@ -1250,7 +1254,9 @@ void Preprocessor::HandleDirective(Token &Result) { // C99 6.10.3 - Macro Replacement. case tok::pp_define: - return HandleDefineDirective(Result, ImmediatelyAfterTopLevelIfndef); + return HandleDefineDirective(Result, ImmediatelyAfterTopLevelIfndef, false); + case tok::pp_define2: + return HandleDefineDirective(Result, ImmediatelyAfterTopLevelIfndef, true); case tok::pp_undef: return HandleUndefDirective(); @@ -3036,10 +3042,10 @@ static bool isObjCProtectedMacro(const IdentifierInfo *II) { II->isStr("__unsafe_unretained") || II->isStr("__autoreleasing"); } -/// HandleDefineDirective - Implements \#define. This consumes the entire macro +/// HandleDefineDirective - Implements \#define and define2. This consumes the entire macro /// line then lets the caller lex the next real token. void Preprocessor::HandleDefineDirective( - Token &DefineTok, const bool ImmediatelyAfterHeaderGuard) { + Token &DefineTok, const bool ImmediatelyAfterHeaderGuard, bool AllowRecurse) { ++NumDefined; Token MacroNameTok; @@ -3064,7 +3070,7 @@ void Preprocessor::HandleDefineDirective( MacroNameTok, ImmediatelyAfterHeaderGuard); if (!MI) return; - + MI->setAllowRecursive(AllowRecurse); if (MacroShadowsKeyword && !isConfigurationPattern(MacroNameTok, MI, getLangOpts())) { Diag(MacroNameTok, diag::warn_pp_macro_hides_keyword); >From 4e175402aa82403ee5281c5cd60250cb3c1536fc Mon Sep 17 00:00:00 2001 From: Kelbon Nik <kelbon...@gmail.com> Date: Sun, 10 Sep 2023 16:00:45 +0400 Subject: [PATCH 02/17] add recursion depth limit and tests --- .../include/clang/Basic/DiagnosticLexKinds.td | 2 ++ clang/include/clang/Lex/MacroInfo.h | 33 ++++++++++++------- clang/lib/Lex/MacroInfo.cpp | 4 +-- clang/lib/Lex/TokenLexer.cpp | 3 +- .../test/Preprocessor/macro_vaopt_expand.cpp | 20 +++++++++++ clang/test/Preprocessor/recursive_macro.cpp | 13 ++++++++ 6 files changed, 60 insertions(+), 15 deletions(-) create mode 100644 clang/test/Preprocessor/recursive_macro.cpp diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td index 940cca67368492f..f940fa01a3d2f38 100644 --- a/clang/include/clang/Basic/DiagnosticLexKinds.td +++ b/clang/include/clang/Basic/DiagnosticLexKinds.td @@ -440,6 +440,8 @@ def err_pp_missing_lparen_in_vaopt_use : Error< def err_pp_vaopt_nested_use : Error< "__VA_OPT__ cannot be nested within its own replacement tokens">; +def err_pp_macro_recursion_depth_limit_exceeded : Error< + "macro recursion depth limit exceeded">; def err_vaopt_paste_at_start : Error< "'##' cannot appear at start of __VA_OPT__ argument">; diff --git a/clang/include/clang/Lex/MacroInfo.h b/clang/include/clang/Lex/MacroInfo.h index 4f0c8e987610e50..267292083058645 100644 --- a/clang/include/clang/Lex/MacroInfo.h +++ b/clang/include/clang/Lex/MacroInfo.h @@ -65,6 +65,12 @@ class MacroInfo { /// Length in characters of the macro definition. mutable unsigned DefinitionLength; + + enum : uint16_t { recursion_depth_limit = 16'000 }; + /// recursion depth, + /// > 0 if we have started an expansion of this macro already. + /// for 'define' max is 1, for 'define2' max is depth limit + uint16_t Depth = 0; mutable bool IsDefinitionLengthCached : 1; /// True if this macro is function-like, false if it is object-like. @@ -96,14 +102,7 @@ class MacroInfo { //===--------------------------------------------------------------------===// // State that changes as the macro is used. - /// True if we have started an expansion of this macro already. - /// - /// This disables recursive expansion, which would be quite bad for things - /// like \#define A A. - bool IsDisabled : 1; - - // True if 'define2' used, - // ignores 'IsDisabled' and enables expansion anyway + // True if 'define2' used, enables expansion anyway bool AllowRecurse : 1; /// True if this macro is either defined in the main file and has @@ -282,13 +281,23 @@ class MacroInfo { /// Return true if this macro is enabled. /// /// In other words, that we are not currently in an expansion of this macro. - bool isEnabled() const { return AllowRecurse || !IsDisabled; } + bool isEnabled() const { + // macro disabled if depth exceeds and stops infinite recursion + if (AllowRecurse) + return Depth < recursion_depth_limit; + return Depth == 0; + } void setAllowRecursive(bool Allow) { AllowRecurse = Allow; } bool isAllowRecurse() const { return AllowRecurse; } - void EnableMacro() { IsDisabled = false; } - - void DisableMacro() { IsDisabled = true; } + void EnableMacro() { + assert(Depth != 0 && "Cannot enable not disabled macro"); + --Depth; + } + // returns false if max recursion depth exceeded + [[nodiscard]] bool TryDisableMacro() { + return ++Depth < recursion_depth_limit; + } /// Determine whether this macro was used for a header guard. bool isUsedForHeaderGuard() const { return UsedForHeaderGuard; } diff --git a/clang/lib/Lex/MacroInfo.cpp b/clang/lib/Lex/MacroInfo.cpp index 9c3619c7c909304..110e3232b66dc14 100644 --- a/clang/lib/Lex/MacroInfo.cpp +++ b/clang/lib/Lex/MacroInfo.cpp @@ -50,7 +50,7 @@ static_assert(MacroInfoSizeChecker<sizeof(void *)>::AsExpected, MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc), IsDefinitionLengthCached(false), IsFunctionLike(false), IsC99Varargs(false), IsGNUVarargs(false), IsBuiltinMacro(false), - HasCommaPasting(false), IsDisabled(false), AllowRecurse(false), IsUsed(false), + HasCommaPasting(false), AllowRecurse(false), IsUsed(false), IsAllowRedefinitionsWithoutWarning(false), IsWarnIfUnused(false), UsedForHeaderGuard(false) {} @@ -155,7 +155,7 @@ LLVM_DUMP_METHOD void MacroInfo::dump() const { // FIXME: Dump locations. Out << "MacroInfo " << this; if (IsBuiltinMacro) Out << " builtin"; - if (IsDisabled) Out << " disabled"; + if (!isEnabled()) Out << " disabled"; if (IsUsed) Out << " used"; if (AllowRecurse) Out << " allow_recurse"; if (IsAllowRedefinitionsWithoutWarning) diff --git a/clang/lib/Lex/TokenLexer.cpp b/clang/lib/Lex/TokenLexer.cpp index 856d5682727fe3d..c51aec4fc17110d 100644 --- a/clang/lib/Lex/TokenLexer.cpp +++ b/clang/lib/Lex/TokenLexer.cpp @@ -88,7 +88,8 @@ void TokenLexer::Init(Token &Tok, SourceLocation ELEnd, MacroInfo *MI, // Mark the macro as currently disabled, so that it is not recursively // expanded. The macro must be disabled only after argument pre-expansion of // function-like macro arguments occurs. - Macro->DisableMacro(); + if (!Macro->TryDisableMacro()) + PP.Diag(Tok, diag::err_pp_macro_recursion_depth_limit_exceeded); } /// Create a TokenLexer for the specified token stream. This does not diff --git a/clang/test/Preprocessor/macro_vaopt_expand.cpp b/clang/test/Preprocessor/macro_vaopt_expand.cpp index 5eb0facb83f7364..9766b081516fd09 100644 --- a/clang/test/Preprocessor/macro_vaopt_expand.cpp +++ b/clang/test/Preprocessor/macro_vaopt_expand.cpp @@ -148,3 +148,23 @@ #undef F #undef G + +#define merge_all_expand2(a, b) a ## b +#define merge_all_expand(a, b) merge_all_expand2(a, b) +#define2 concat_all(head, ...) merge_all_expand(head, __VA_OPT__(concat_all(__VA_ARGS__))) +29: concat_all(aa, bb, cc) +30: [concat_all()] +// CHECK: 29: aabbcc +// CHECK: 30: [] + +#undef merge_all_expand +#undef merge_all_expand2 +#undef concat_all + +#define2 reverse(head, ...) __VA_OPT__(reverse(__VA_ARGS__) , ) head + +31: reverse(1, 2, 3) + +// CHECK: 31: 3, 2, 1 + +#undef reverse diff --git a/clang/test/Preprocessor/recursive_macro.cpp b/clang/test/Preprocessor/recursive_macro.cpp new file mode 100644 index 000000000000000..0fee436bf4d9ce0 --- /dev/null +++ b/clang/test/Preprocessor/recursive_macro.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 %s -Eonly -std=c++11 -pedantic -verify + +#define2 A A + +A //expected-error {{macro recursion depth limit exceeded}} + +#undef A + +#define2 boom(x) boom(x) + +boom(5) //expected-error {{macro recursion depth limit exceeded}} + +#undef boom >From 6ab7f4eba17c8174e09a50fedfcd3e1a22d44d80 Mon Sep 17 00:00:00 2001 From: Kelbon Nik <kelbon...@gmail.com> Date: Mon, 11 Sep 2023 12:03:36 +0400 Subject: [PATCH 03/17] rewrite Lexer recursion to loop --- clang/lib/Lex/Lexer.cpp | 32 +++++++++---------- clang/lib/Lex/PPMacroExpansion.cpp | 2 ++ .../test/Preprocessor/macro_vaopt_expand.cpp | 4 +-- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index 37c3e4175d4736e..178bcc08a72e208 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -847,26 +847,26 @@ bool Lexer::isAtEndOfMacroExpansion(SourceLocation loc, const SourceManager &SM, const LangOptions &LangOpts, SourceLocation *MacroEnd) { - assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc"); + for(SourceLocation expansionLoc; true;loc = expansionLoc) { + assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc"); - SourceLocation spellLoc = SM.getSpellingLoc(loc); - unsigned tokLen = MeasureTokenLength(spellLoc, SM, LangOpts); - if (tokLen == 0) - return false; + SourceLocation spellLoc = SM.getSpellingLoc(loc); + unsigned tokLen = MeasureTokenLength(spellLoc, SM, LangOpts); + if (tokLen == 0) + return false; - SourceLocation afterLoc = loc.getLocWithOffset(tokLen); - SourceLocation expansionLoc; - if (!SM.isAtEndOfImmediateMacroExpansion(afterLoc, &expansionLoc)) - return false; + SourceLocation afterLoc = loc.getLocWithOffset(tokLen); + if (!SM.isAtEndOfImmediateMacroExpansion(afterLoc, &expansionLoc)) + return false; - if (expansionLoc.isFileID()) { - // No other macro expansions. - if (MacroEnd) - *MacroEnd = expansionLoc; - return true; + if (expansionLoc.isFileID()) { + // No other macro expansions. + if (MacroEnd) + *MacroEnd = expansionLoc; + return true; + } } - - return isAtEndOfMacroExpansion(expansionLoc, SM, LangOpts, MacroEnd); + llvm_unreachable(""); } static CharSourceRange makeRangeFromFileLocs(CharSourceRange Range, diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index ec6a084f228f32d..313475cfd0e113c 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -614,6 +614,8 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, if (IdentifierInfo *NewII = Identifier.getIdentifierInfo()) { if (MacroInfo *NewMI = getMacroInfo(NewII)) if (!NewMI->isEnabled() || NewMI == MI) { + if (NewMI->isAllowRecurse() && NewMI == MI) + Diag(Identifier, diag::err_pp_macro_recursion_depth_limit_exceeded); Identifier.setFlag(Token::DisableExpand); // Don't warn for "#define X X" like "#define bool bool" from // stdbool.h. diff --git a/clang/test/Preprocessor/macro_vaopt_expand.cpp b/clang/test/Preprocessor/macro_vaopt_expand.cpp index 9766b081516fd09..17be324fdd71392 100644 --- a/clang/test/Preprocessor/macro_vaopt_expand.cpp +++ b/clang/test/Preprocessor/macro_vaopt_expand.cpp @@ -163,8 +163,8 @@ #define2 reverse(head, ...) __VA_OPT__(reverse(__VA_ARGS__) , ) head -31: reverse(1, 2, 3) +31: reverse(1,2,3) -// CHECK: 31: 3, 2, 1 +// CHECK: 31: 3,2,1 #undef reverse >From 6c126e8d6cb1fc97059d57b86e908465a2128873 Mon Sep 17 00:00:00 2001 From: Kelbon Nik <kelbon...@gmail.com> Date: Mon, 11 Sep 2023 13:54:55 +0400 Subject: [PATCH 04/17] more tests --- .../test/Preprocessor/macro_vaopt_expand.cpp | 20 ------------------- clang/test/Preprocessor/recursive_macro.cpp | 13 ------------ 2 files changed, 33 deletions(-) delete mode 100644 clang/test/Preprocessor/recursive_macro.cpp diff --git a/clang/test/Preprocessor/macro_vaopt_expand.cpp b/clang/test/Preprocessor/macro_vaopt_expand.cpp index 17be324fdd71392..5eb0facb83f7364 100644 --- a/clang/test/Preprocessor/macro_vaopt_expand.cpp +++ b/clang/test/Preprocessor/macro_vaopt_expand.cpp @@ -148,23 +148,3 @@ #undef F #undef G - -#define merge_all_expand2(a, b) a ## b -#define merge_all_expand(a, b) merge_all_expand2(a, b) -#define2 concat_all(head, ...) merge_all_expand(head, __VA_OPT__(concat_all(__VA_ARGS__))) -29: concat_all(aa, bb, cc) -30: [concat_all()] -// CHECK: 29: aabbcc -// CHECK: 30: [] - -#undef merge_all_expand -#undef merge_all_expand2 -#undef concat_all - -#define2 reverse(head, ...) __VA_OPT__(reverse(__VA_ARGS__) , ) head - -31: reverse(1,2,3) - -// CHECK: 31: 3,2,1 - -#undef reverse diff --git a/clang/test/Preprocessor/recursive_macro.cpp b/clang/test/Preprocessor/recursive_macro.cpp deleted file mode 100644 index 0fee436bf4d9ce0..000000000000000 --- a/clang/test/Preprocessor/recursive_macro.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// RUN: %clang_cc1 %s -Eonly -std=c++11 -pedantic -verify - -#define2 A A - -A //expected-error {{macro recursion depth limit exceeded}} - -#undef A - -#define2 boom(x) boom(x) - -boom(5) //expected-error {{macro recursion depth limit exceeded}} - -#undef boom >From fe01de795a9db1ff3c6bfde827b893e4059e24d5 Mon Sep 17 00:00:00 2001 From: Kelbon Nik <kelbon...@gmail.com> Date: Mon, 11 Sep 2023 13:55:51 +0400 Subject: [PATCH 05/17] test files --- .../Preprocessor/macro_infinite_recursion.cpp | 13 +++++++++ clang/test/Preprocessor/macro_recursion.cpp | 28 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 clang/test/Preprocessor/macro_infinite_recursion.cpp create mode 100644 clang/test/Preprocessor/macro_recursion.cpp diff --git a/clang/test/Preprocessor/macro_infinite_recursion.cpp b/clang/test/Preprocessor/macro_infinite_recursion.cpp new file mode 100644 index 000000000000000..cac8e7abbec5af3 --- /dev/null +++ b/clang/test/Preprocessor/macro_infinite_recursion.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 %s -Eonly -std=c++11 -pedantic -verify + +#define2 A A + +A //expected-error {{macro recursion depth limit exceeded}} + +#undef A + +#define2 A(x) A(x) + +A(5) //expected-error {{macro recursion depth limit exceeded}} + +#undef A diff --git a/clang/test/Preprocessor/macro_recursion.cpp b/clang/test/Preprocessor/macro_recursion.cpp new file mode 100644 index 000000000000000..da3e6157efc0f60 --- /dev/null +++ b/clang/test/Preprocessor/macro_recursion.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -E %s -std=c++20 | FileCheck %s + +#define merge_all_expand2(a, b) a ## b +#define merge_all_expand(a, b) merge_all_expand2(a, b) +#define2 concat_all(head, ...) merge_all_expand(head, __VA_OPT__(concat_all(__VA_ARGS__))) +0: concat_all(aa, bb, cc) +1: [concat_all()] +// CHECK: 0: aabbcc +// CHECK: 1: [] + +#undef merge_all_expand +#undef merge_all_expand2 +#undef concat_all + +#define2 reverse(head, ...) __VA_OPT__(reverse(__VA_ARGS__) , ) head + +2: reverse(1,2,3) + +// CHECK: 2: 3,2,1 + +#undef reverse + +#define2 fold_left(op, head, ...) ( __VA_OPT__(fold_left(op, __VA_ARGS__) op) head ) + +3: fold_left(+, 1, 2, 3, 4) +// CHECK: 3: ((((4) + 3) + 2) + 1) + +#undef fold_left >From abe0bd0489f6dce25431dccdeafac8063a239f8f Mon Sep 17 00:00:00 2001 From: Kelbon Nik <kelbon...@gmail.com> Date: Mon, 11 Sep 2023 14:23:17 +0400 Subject: [PATCH 06/17] whitespaces --- clang/test/Preprocessor/macro_recursion.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Preprocessor/macro_recursion.cpp b/clang/test/Preprocessor/macro_recursion.cpp index da3e6157efc0f60..a7a69e4ba08b146 100644 --- a/clang/test/Preprocessor/macro_recursion.cpp +++ b/clang/test/Preprocessor/macro_recursion.cpp @@ -16,7 +16,7 @@ 2: reverse(1,2,3) -// CHECK: 2: 3,2,1 +// CHECK: 2: 3 , 2 , 1 #undef reverse >From a28be970bf5c440bbecf7146d27e51dca42ba4cd Mon Sep 17 00:00:00 2001 From: Kelbon Nik <kelbon...@gmail.com> Date: Mon, 11 Sep 2023 16:10:20 +0400 Subject: [PATCH 07/17] whitespaces in tests --- clang/test/Preprocessor/macro_recursion.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/test/Preprocessor/macro_recursion.cpp b/clang/test/Preprocessor/macro_recursion.cpp index a7a69e4ba08b146..cd415ce1a95e463 100644 --- a/clang/test/Preprocessor/macro_recursion.cpp +++ b/clang/test/Preprocessor/macro_recursion.cpp @@ -2,7 +2,7 @@ #define merge_all_expand2(a, b) a ## b #define merge_all_expand(a, b) merge_all_expand2(a, b) -#define2 concat_all(head, ...) merge_all_expand(head, __VA_OPT__(concat_all(__VA_ARGS__))) +#define2 concat_all(head, ...)merge_all_expand(head,__VA_OPT__(concat_all(__VA_ARGS__))) 0: concat_all(aa, bb, cc) 1: [concat_all()] // CHECK: 0: aabbcc @@ -12,17 +12,17 @@ #undef merge_all_expand2 #undef concat_all -#define2 reverse(head, ...) __VA_OPT__(reverse(__VA_ARGS__) , ) head +#define2 reverse(head, ...)__VA_OPT__(reverse(__VA_ARGS__),)head 2: reverse(1,2,3) -// CHECK: 2: 3 , 2 , 1 +// CHECK: 2: 3,2,1 #undef reverse -#define2 fold_left(op, head, ...) ( __VA_OPT__(fold_left(op, __VA_ARGS__) op) head ) +#define2 fold_left(op, head, ...)(__VA_OPT__(fold_left(op,__VA_ARGS__)op)head) 3: fold_left(+, 1, 2, 3, 4) -// CHECK: 3: ((((4) + 3) + 2) + 1) +// CHECK: 3: ((((4)+3)+2)+1) #undef fold_left >From 8555660c576eac3f34537bf0233aefbfcb6828a2 Mon Sep 17 00:00:00 2001 From: Kelbon Nik <kelbon...@gmail.com> Date: Tue, 12 Sep 2023 01:53:45 +0400 Subject: [PATCH 08/17] remove redundant HandleDefineDirective argument --- clang/include/clang/Lex/MacroInfo.h | 23 ++++++++++++----------- clang/include/clang/Lex/Preprocessor.h | 2 +- clang/lib/Lex/PPDirectives.cpp | 15 +++++---------- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/clang/include/clang/Lex/MacroInfo.h b/clang/include/clang/Lex/MacroInfo.h index 267292083058645..54b1d7193dbe613 100644 --- a/clang/include/clang/Lex/MacroInfo.h +++ b/clang/include/clang/Lex/MacroInfo.h @@ -66,11 +66,9 @@ class MacroInfo { /// Length in characters of the macro definition. mutable unsigned DefinitionLength; - enum : uint16_t { recursion_depth_limit = 16'000 }; - /// recursion depth, - /// > 0 if we have started an expansion of this macro already. - /// for 'define' max is 1, for 'define2' max is depth limit - uint16_t Depth = 0; + /// True if 'define2' used, enables expansion anyway + bool AllowRecurse : 1; + mutable bool IsDefinitionLengthCached : 1; /// True if this macro is function-like, false if it is object-like. @@ -102,9 +100,6 @@ class MacroInfo { //===--------------------------------------------------------------------===// // State that changes as the macro is used. - // True if 'define2' used, enables expansion anyway - bool AllowRecurse : 1; - /// True if this macro is either defined in the main file and has /// been used, or if it is not defined in the main file. /// @@ -120,6 +115,12 @@ class MacroInfo { /// Whether this macro was used as header guard. bool UsedForHeaderGuard : 1; + enum : uint16_t { recursion_depth_limit = 16'000 }; + /// recursion depth, + /// > 0 if we have started an expansion of this macro already. + /// for 'define' max is 1, for 'define2' max is depth limit + uint16_t Depth = 0; + // Only the Preprocessor gets to create these. MacroInfo(SourceLocation DefLoc); @@ -283,9 +284,7 @@ class MacroInfo { /// In other words, that we are not currently in an expansion of this macro. bool isEnabled() const { // macro disabled if depth exceeds and stops infinite recursion - if (AllowRecurse) - return Depth < recursion_depth_limit; - return Depth == 0; + return AllowRecurse ? Depth < recursion_depth_limit : Depth == 0; } void setAllowRecursive(bool Allow) { AllowRecurse = Allow; } bool isAllowRecurse() const { return AllowRecurse; } @@ -296,8 +295,10 @@ class MacroInfo { } // returns false if max recursion depth exceeded [[nodiscard]] bool TryDisableMacro() { + assert((AllowRecurse || Depth == 0) && "Cannot disable an already-disabled macro!"); return ++Depth < recursion_depth_limit; } + /// Determine whether this macro was used for a header guard. bool isUsedForHeaderGuard() const { return UsedForHeaderGuard; } diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 01eac0939fe9e21..575d08b83fd3a02 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -2754,7 +2754,7 @@ class Preprocessor { void replayPreambleConditionalStack(); // Macro handling. - void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterHeaderGuard, bool AllowRecurse); + void HandleDefineDirective(Token &Tok, bool ImmediatelyAfterHeaderGuard); void HandleUndefDirective(); // Conditional Inclusion. diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 01b77a39437a30d..06b81985749aa25 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -1109,13 +1109,9 @@ class Preprocessor::ResetMacroExpansionHelper { void Preprocessor::HandleSkippedDirectiveWhileUsingPCH(Token &Result, SourceLocation HashLoc) { if (const IdentifierInfo *II = Result.getIdentifierInfo()) { - if (II->getPPKeywordID() == tok::pp_define) { + if (II->getPPKeywordID() == tok::pp_define || II->getPPKeywordID() == tok::pp_define2) { return HandleDefineDirective(Result, - /*ImmediatelyAfterHeaderGuard=*/false, /*AllowRecurse=*/false); - } - if (II->getPPKeywordID() == tok::pp_define2) { - return HandleDefineDirective(Result, - /*ImmediatelyAfterHeaderGuard=*/false, /*AllowRecurse=*/true); + /*ImmediatelyAfterHeaderGuard=*/false); } if (SkippingUntilPCHThroughHeader && II->getPPKeywordID() == tok::pp_include) { @@ -1254,9 +1250,8 @@ void Preprocessor::HandleDirective(Token &Result) { // C99 6.10.3 - Macro Replacement. case tok::pp_define: - return HandleDefineDirective(Result, ImmediatelyAfterTopLevelIfndef, false); case tok::pp_define2: - return HandleDefineDirective(Result, ImmediatelyAfterTopLevelIfndef, true); + return HandleDefineDirective(Result, ImmediatelyAfterTopLevelIfndef); case tok::pp_undef: return HandleUndefDirective(); @@ -3045,7 +3040,7 @@ static bool isObjCProtectedMacro(const IdentifierInfo *II) { /// HandleDefineDirective - Implements \#define and define2. This consumes the entire macro /// line then lets the caller lex the next real token. void Preprocessor::HandleDefineDirective( - Token &DefineTok, const bool ImmediatelyAfterHeaderGuard, bool AllowRecurse) { + Token &DefineTok, const bool ImmediatelyAfterHeaderGuard) { ++NumDefined; Token MacroNameTok; @@ -3070,7 +3065,7 @@ void Preprocessor::HandleDefineDirective( MacroNameTok, ImmediatelyAfterHeaderGuard); if (!MI) return; - MI->setAllowRecursive(AllowRecurse); + MI->setAllowRecursive(DefineTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_define2); if (MacroShadowsKeyword && !isConfigurationPattern(MacroNameTok, MI, getLangOpts())) { Diag(MacroNameTok, diag::warn_pp_macro_hides_keyword); >From 49d7fa2e638f3903375f6f1de8443c63ff909a5d Mon Sep 17 00:00:00 2001 From: Kelbon Nik <kelbon...@gmail.com> Date: Sun, 24 Sep 2023 13:42:56 +0400 Subject: [PATCH 09/17] __THIS_MACRO__ --- clang/include/clang/Lex/MacroInfo.h | 18 ++++++++---- clang/include/clang/Lex/Preprocessor.h | 6 ++++ clang/lib/Lex/PPMacroExpansion.cpp | 29 +++++++++++++++++++ clang/lib/Lex/Preprocessor.cpp | 1 + .../Preprocessor/macro_infinite_recursion.cpp | 6 ++-- clang/test/Preprocessor/macro_recursion.cpp | 6 ++-- 6 files changed, 55 insertions(+), 11 deletions(-) diff --git a/clang/include/clang/Lex/MacroInfo.h b/clang/include/clang/Lex/MacroInfo.h index 54b1d7193dbe613..8b91d33e971b752 100644 --- a/clang/include/clang/Lex/MacroInfo.h +++ b/clang/include/clang/Lex/MacroInfo.h @@ -55,7 +55,7 @@ class MacroInfo { IdentifierInfo **ParameterList = nullptr; /// This is the list of tokens that the macro is defined to. - const Token *ReplacementTokens = nullptr; + Token *ReplacementTokens = nullptr; /// \see ParameterList unsigned NumParameters = 0; @@ -186,8 +186,11 @@ class MacroInfo { param_iterator param_begin() const { return ParameterList; } param_iterator param_end() const { return ParameterList + NumParameters; } unsigned getNumParams() const { return NumParameters; } + ArrayRef<IdentifierInfo *> params() { + return ArrayRef<IdentifierInfo *>(ParameterList, NumParameters); + } ArrayRef<const IdentifierInfo *> params() const { - return ArrayRef<const IdentifierInfo *>(ParameterList, NumParameters); + return const_cast<MacroInfo*>(this)->params(); } /// Return the parameter number of the specified identifier, @@ -250,6 +253,9 @@ class MacroInfo { return ReplacementTokens + NumReplacementTokens; } bool tokens_empty() const { return NumReplacementTokens == 0; } + MutableArrayRef<Token> tokens() { + return llvm::MutableArrayRef(ReplacementTokens, NumReplacementTokens); + } ArrayRef<Token> tokens() const { return llvm::ArrayRef(ReplacementTokens, NumReplacementTokens); } @@ -293,10 +299,12 @@ class MacroInfo { assert(Depth != 0 && "Cannot enable not disabled macro"); --Depth; } - // returns false if max recursion depth exceeded - [[nodiscard]] bool TryDisableMacro() { + enum : uint16_t { macro_recursion_depth_limit = 16'000 }; + + [[nodiscard("infinite recursion check ignored")]] + bool TryDisableMacro() { assert((AllowRecurse || Depth == 0) && "Cannot disable an already-disabled macro!"); - return ++Depth < recursion_depth_limit; + return ++Depth < macro_recursion_depth_limit; } /// Determine whether this macro was used for a header guard. diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 575d08b83fd3a02..356be1d3b45cac9 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -160,6 +160,7 @@ class Preprocessor { IdentifierInfo *Ident__identifier; // __identifier IdentifierInfo *Ident__VA_ARGS__; // __VA_ARGS__ IdentifierInfo *Ident__VA_OPT__; // __VA_OPT__ + IdentifierInfo *Ident__THIS_MACRO__; // __THIS_MACRO__ IdentifierInfo *Ident__has_feature; // __has_feature IdentifierInfo *Ident__has_extension; // __has_extension IdentifierInfo *Ident__has_builtin; // __has_builtin @@ -2425,6 +2426,11 @@ class Preprocessor { private: friend void TokenLexer::ExpandFunctionArguments(); + /// If macro definition containts __THIS_MACRO__ creates impl-only recursive + /// version of macro, and replaces all __THIS_MACRO__ tokens + /// with new created recusive version + void appendRecursiveVersionIfRequired(IdentifierInfo*, MacroInfo*); + void PushIncludeMacroStack() { assert(CurLexerKind != CLK_CachingLexer && "cannot push a caching lexer"); IncludeMacroStack.emplace_back(CurLexerKind, CurLexerSubmodule, diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 313475cfd0e113c..ca1f78280bfcb24 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -59,6 +59,34 @@ using namespace clang; +void Preprocessor::appendRecursiveVersionIfRequired(IdentifierInfo* II, MacroInfo* MI) { + if (!MI->isFunctionLike()) + return; + auto is_this_macro_tok = [&] (const Token& t) { + return t.getKind() == tok::identifier && t.getIdentifierInfo() == Ident__THIS_MACRO__; + }; + if (llvm::none_of(MI->tokens(), is_this_macro_tok)) + return; + IdentifierInfo* ImplMacroII = [&] { + std::string ImplMacroName = "__THIS_MACRO__"; + ImplMacroName += II->getName(); + return getIdentifierInfo(ImplMacroName); + }(); + MacroInfo* NewMI = AllocateMacroInfo(MI->getDefinitionLoc()); + NewMI->setIsFunctionLike(); + NewMI->setParameterList(MI->params(), getPreprocessorAllocator()); + NewMI->setDefinitionEndLoc(MI->getDefinitionEndLoc()); + if (MI->isC99Varargs()) NewMI->setIsC99Varargs(); + if (MI->isGNUVarargs()) NewMI->setIsGNUVarargs(); + for (auto& t : MI->tokens()) { + if (is_this_macro_tok(t)) + t.setIdentifierInfo(ImplMacroII); + } + NewMI->setTokens(MI->tokens(), getPreprocessorAllocator()); + NewMI->setAllowRecursive(true); + appendDefMacroDirective(ImplMacroII, NewMI); +} + MacroDirective * Preprocessor::getLocalMacroDirectiveHistory(const IdentifierInfo *II) const { if (!II->hadMacroDefinition()) @@ -91,6 +119,7 @@ void Preprocessor::appendMacroDirective(IdentifierInfo *II, MacroDirective *MD){ II->setHasMacroDefinition(false); if (II->isFromAST()) II->setChangedSinceDeserialization(); + appendRecursiveVersionIfRequired(II, MD->getMacroInfo()); } void Preprocessor::setLoadedMacroDirective(IdentifierInfo *II, diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index f0381c18a8b6f77..4e6c0ce112d488e 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -121,6 +121,7 @@ Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts, SetPoisonReason(Ident__VA_ARGS__,diag::ext_pp_bad_vaargs_use); (Ident__VA_OPT__ = getIdentifierInfo("__VA_OPT__"))->setIsPoisoned(); SetPoisonReason(Ident__VA_OPT__,diag::ext_pp_bad_vaopt_use); + Ident__THIS_MACRO__ = getIdentifierInfo("__THIS_MACRO__"); // Initialize the pragma handlers. RegisterBuiltinPragmas(); diff --git a/clang/test/Preprocessor/macro_infinite_recursion.cpp b/clang/test/Preprocessor/macro_infinite_recursion.cpp index cac8e7abbec5af3..3306f468543bcb9 100644 --- a/clang/test/Preprocessor/macro_infinite_recursion.cpp +++ b/clang/test/Preprocessor/macro_infinite_recursion.cpp @@ -1,12 +1,12 @@ // RUN: %clang_cc1 %s -Eonly -std=c++11 -pedantic -verify -#define2 A A +#define A() __THIS_MACRO__() -A //expected-error {{macro recursion depth limit exceeded}} +A() //expected-error {{macro recursion depth limit exceeded}} #undef A -#define2 A(x) A(x) +#define A(x) __THIS_MACRO__(x) A(5) //expected-error {{macro recursion depth limit exceeded}} diff --git a/clang/test/Preprocessor/macro_recursion.cpp b/clang/test/Preprocessor/macro_recursion.cpp index cd415ce1a95e463..fc2c2ffd21eadd6 100644 --- a/clang/test/Preprocessor/macro_recursion.cpp +++ b/clang/test/Preprocessor/macro_recursion.cpp @@ -2,7 +2,7 @@ #define merge_all_expand2(a, b) a ## b #define merge_all_expand(a, b) merge_all_expand2(a, b) -#define2 concat_all(head, ...)merge_all_expand(head,__VA_OPT__(concat_all(__VA_ARGS__))) +#define concat_all(head, ...)merge_all_expand(head,__VA_OPT__(__THIS_MACRO__(__VA_ARGS__))) 0: concat_all(aa, bb, cc) 1: [concat_all()] // CHECK: 0: aabbcc @@ -12,7 +12,7 @@ #undef merge_all_expand2 #undef concat_all -#define2 reverse(head, ...)__VA_OPT__(reverse(__VA_ARGS__),)head +#define reverse(head, ...)__VA_OPT__(__THIS_MACRO__(__VA_ARGS__),)head 2: reverse(1,2,3) @@ -20,7 +20,7 @@ #undef reverse -#define2 fold_left(op, head, ...)(__VA_OPT__(fold_left(op,__VA_ARGS__)op)head) +#define fold_left(op, head, ...)(__VA_OPT__(__THIS_MACRO__(op,__VA_ARGS__)op)head) 3: fold_left(+, 1, 2, 3, 4) // CHECK: 3: ((((4)+3)+2)+1) >From 1add34ebecc2fa45ed48c7a2156d8d080afcd8bf Mon Sep 17 00:00:00 2001 From: Kelbon Nik <kelbon...@gmail.com> Date: Sun, 24 Sep 2023 14:49:26 +0400 Subject: [PATCH 10/17] rm define2 --- clang/include/clang/Basic/TokenKinds.def | 1 - clang/include/clang/Lex/MacroInfo.h | 4 ++-- clang/lib/Basic/IdentifierTable.cpp | 2 -- clang/lib/Format/WhitespaceManager.cpp | 2 +- clang/lib/Lex/PPDirectives.cpp | 7 +++---- 5 files changed, 6 insertions(+), 10 deletions(-) diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index b227a6a5632f496..72e8df8c793a7b6 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -115,7 +115,6 @@ PPKEYWORD(__include_macros) // C99 6.10.3 - Macro Replacement. PPKEYWORD(define) -PPKEYWORD(define2) PPKEYWORD(undef) // C99 6.10.4 - Line Control. diff --git a/clang/include/clang/Lex/MacroInfo.h b/clang/include/clang/Lex/MacroInfo.h index 8b91d33e971b752..49cbacf6df1acda 100644 --- a/clang/include/clang/Lex/MacroInfo.h +++ b/clang/include/clang/Lex/MacroInfo.h @@ -66,7 +66,7 @@ class MacroInfo { /// Length in characters of the macro definition. mutable unsigned DefinitionLength; - /// True if 'define2' used, enables expansion anyway + /// True only for inner-impl '__THIS_MACRO__', enables expansion anyway bool AllowRecurse : 1; mutable bool IsDefinitionLengthCached : 1; @@ -118,7 +118,7 @@ class MacroInfo { enum : uint16_t { recursion_depth_limit = 16'000 }; /// recursion depth, /// > 0 if we have started an expansion of this macro already. - /// for 'define' max is 1, for 'define2' max is depth limit + /// if !AllowRecurse max is 1, else max is recursion depth limit uint16_t Depth = 0; // Only the Preprocessor gets to create these. diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index 7300825ff6b826a..e5599d545541085 100644 --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -431,8 +431,6 @@ tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const { unsigned Len = getLength(); if (Len < 2) return tok::pp_not_keyword; const char *Name = getNameStart(); - if (std::string_view(Name, Len) == "define2") - return tok::pp_define2; switch (HASH(Len, Name[0], Name[2])) { default: return tok::pp_not_keyword; CASE( 2, 'i', '\0', if); diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index d8ab76d6761553e..b7bd8d27dc976b1 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -743,7 +743,7 @@ void WhitespaceManager::alignConsecutiveMacros() { if (!Current || Current->isNot(tok::identifier)) return false; - if (!Current->Previous || !Current->Previous->isOneOf(tok::pp_define, tok::pp_define2)) + if (!Current->Previous || Current->Previous->isNot(tok::pp_define)) return false; // For a macro function, 0 spaces are required between the diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 06b81985749aa25..9e4ce13bb9c32a9 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -1109,7 +1109,7 @@ class Preprocessor::ResetMacroExpansionHelper { void Preprocessor::HandleSkippedDirectiveWhileUsingPCH(Token &Result, SourceLocation HashLoc) { if (const IdentifierInfo *II = Result.getIdentifierInfo()) { - if (II->getPPKeywordID() == tok::pp_define || II->getPPKeywordID() == tok::pp_define2) { + if (II->getPPKeywordID() == tok::pp_define) { return HandleDefineDirective(Result, /*ImmediatelyAfterHeaderGuard=*/false); } @@ -1250,7 +1250,6 @@ void Preprocessor::HandleDirective(Token &Result) { // C99 6.10.3 - Macro Replacement. case tok::pp_define: - case tok::pp_define2: return HandleDefineDirective(Result, ImmediatelyAfterTopLevelIfndef); case tok::pp_undef: return HandleUndefDirective(); @@ -3037,7 +3036,7 @@ static bool isObjCProtectedMacro(const IdentifierInfo *II) { II->isStr("__unsafe_unretained") || II->isStr("__autoreleasing"); } -/// HandleDefineDirective - Implements \#define and define2. This consumes the entire macro +/// HandleDefineDirective - Implements \#define. This consumes the entire macro /// line then lets the caller lex the next real token. void Preprocessor::HandleDefineDirective( Token &DefineTok, const bool ImmediatelyAfterHeaderGuard) { @@ -3065,7 +3064,7 @@ void Preprocessor::HandleDefineDirective( MacroNameTok, ImmediatelyAfterHeaderGuard); if (!MI) return; - MI->setAllowRecursive(DefineTok.getIdentifierInfo()->getPPKeywordID() == tok::pp_define2); + if (MacroShadowsKeyword && !isConfigurationPattern(MacroNameTok, MI, getLangOpts())) { Diag(MacroNameTok, diag::warn_pp_macro_hides_keyword); >From c879ca056bf9eb16fad28ad1d324bad829bfb7ca Mon Sep 17 00:00:00 2001 From: Kelbon Nik <kelbon...@gmail.com> Date: Sun, 24 Sep 2023 14:52:58 +0400 Subject: [PATCH 11/17] rm enum --- clang/include/clang/Lex/MacroInfo.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/Lex/MacroInfo.h b/clang/include/clang/Lex/MacroInfo.h index 49cbacf6df1acda..e5b996115a96c2b 100644 --- a/clang/include/clang/Lex/MacroInfo.h +++ b/clang/include/clang/Lex/MacroInfo.h @@ -115,7 +115,7 @@ class MacroInfo { /// Whether this macro was used as header guard. bool UsedForHeaderGuard : 1; - enum : uint16_t { recursion_depth_limit = 16'000 }; + enum : uint16_t { macro_recursion_depth_limit = 16'000 }; /// recursion depth, /// > 0 if we have started an expansion of this macro already. /// if !AllowRecurse max is 1, else max is recursion depth limit @@ -290,7 +290,7 @@ class MacroInfo { /// In other words, that we are not currently in an expansion of this macro. bool isEnabled() const { // macro disabled if depth exceeds and stops infinite recursion - return AllowRecurse ? Depth < recursion_depth_limit : Depth == 0; + return AllowRecurse ? Depth < macro_recursion_depth_limit : Depth == 0; } void setAllowRecursive(bool Allow) { AllowRecurse = Allow; } bool isAllowRecurse() const { return AllowRecurse; } @@ -299,7 +299,6 @@ class MacroInfo { assert(Depth != 0 && "Cannot enable not disabled macro"); --Depth; } - enum : uint16_t { macro_recursion_depth_limit = 16'000 }; [[nodiscard("infinite recursion check ignored")]] bool TryDisableMacro() { >From 998bf1306c0cc9c1f76a3e3eb6370036de2f7c18 Mon Sep 17 00:00:00 2001 From: Kelbon Nik <kelbon...@gmail.com> Date: Sun, 24 Sep 2023 15:08:31 +0400 Subject: [PATCH 12/17] comment fixes --- clang/include/clang/Lex/Preprocessor.h | 2 +- clang/lib/Lex/PPDirectives.cpp | 2 +- clang/lib/Lex/PPMacroExpansion.cpp | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 356be1d3b45cac9..3a5bcac1de77427 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -2426,7 +2426,7 @@ class Preprocessor { private: friend void TokenLexer::ExpandFunctionArguments(); - /// If macro definition containts __THIS_MACRO__ creates impl-only recursive + /// If macro definition contains __THIS_MACRO__ creates impl-only recursive /// version of macro, and replaces all __THIS_MACRO__ tokens /// with new created recusive version void appendRecursiveVersionIfRequired(IdentifierInfo*, MacroInfo*); diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 9e4ce13bb9c32a9..7edcb0577c2b25a 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -3036,7 +3036,7 @@ static bool isObjCProtectedMacro(const IdentifierInfo *II) { II->isStr("__unsafe_unretained") || II->isStr("__autoreleasing"); } -/// HandleDefineDirective - Implements \#define. This consumes the entire macro +/// HandleDefineDirective - Implements \#define. This consumes the entire macro /// line then lets the caller lex the next real token. void Preprocessor::HandleDefineDirective( Token &DefineTok, const bool ImmediatelyAfterHeaderGuard) { diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index ca1f78280bfcb24..6fbe08e3baa569a 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -643,8 +643,6 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, if (IdentifierInfo *NewII = Identifier.getIdentifierInfo()) { if (MacroInfo *NewMI = getMacroInfo(NewII)) if (!NewMI->isEnabled() || NewMI == MI) { - if (NewMI->isAllowRecurse() && NewMI == MI) - Diag(Identifier, diag::err_pp_macro_recursion_depth_limit_exceeded); Identifier.setFlag(Token::DisableExpand); // Don't warn for "#define X X" like "#define bool bool" from // stdbool.h. >From cab7a4a019af133cc84c465cc8edbed2205880ca Mon Sep 17 00:00:00 2001 From: Kelbon Nik <kelbon...@gmail.com> Date: Sun, 24 Sep 2023 15:16:55 +0400 Subject: [PATCH 13/17] format --- clang/include/clang/Lex/MacroInfo.h | 8 ++++---- clang/include/clang/Lex/Preprocessor.h | 2 +- clang/lib/Lex/Lexer.cpp | 2 +- clang/lib/Lex/MacroInfo.cpp | 6 ++++-- clang/lib/Lex/PPMacroExpansion.cpp | 18 +++++++++++------- 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/clang/include/clang/Lex/MacroInfo.h b/clang/include/clang/Lex/MacroInfo.h index e5b996115a96c2b..b1df66961dd853d 100644 --- a/clang/include/clang/Lex/MacroInfo.h +++ b/clang/include/clang/Lex/MacroInfo.h @@ -190,7 +190,7 @@ class MacroInfo { return ArrayRef<IdentifierInfo *>(ParameterList, NumParameters); } ArrayRef<const IdentifierInfo *> params() const { - return const_cast<MacroInfo*>(this)->params(); + return const_cast<MacroInfo *>(this)->params(); } /// Return the parameter number of the specified identifier, @@ -300,9 +300,9 @@ class MacroInfo { --Depth; } - [[nodiscard("infinite recursion check ignored")]] - bool TryDisableMacro() { - assert((AllowRecurse || Depth == 0) && "Cannot disable an already-disabled macro!"); + [[nodiscard("infinite recursion check ignored")]] bool TryDisableMacro() { + assert((AllowRecurse || Depth == 0) && + "Cannot disable an already-disabled macro!"); return ++Depth < macro_recursion_depth_limit; } diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 3a5bcac1de77427..fb128d8c0e77334 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -2429,7 +2429,7 @@ class Preprocessor { /// If macro definition contains __THIS_MACRO__ creates impl-only recursive /// version of macro, and replaces all __THIS_MACRO__ tokens /// with new created recusive version - void appendRecursiveVersionIfRequired(IdentifierInfo*, MacroInfo*); + void appendRecursiveVersionIfRequired(IdentifierInfo *, MacroInfo *); void PushIncludeMacroStack() { assert(CurLexerKind != CLK_CachingLexer && "cannot push a caching lexer"); diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index 178bcc08a72e208..70ba8f4f9c84fd6 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -847,7 +847,7 @@ bool Lexer::isAtEndOfMacroExpansion(SourceLocation loc, const SourceManager &SM, const LangOptions &LangOpts, SourceLocation *MacroEnd) { - for(SourceLocation expansionLoc; true;loc = expansionLoc) { + for (SourceLocation expansionLoc; true; loc = expansionLoc) { assert(loc.isValid() && loc.isMacroID() && "Expected a valid macro loc"); SourceLocation spellLoc = SM.getSpellingLoc(loc); diff --git a/clang/lib/Lex/MacroInfo.cpp b/clang/lib/Lex/MacroInfo.cpp index 110e3232b66dc14..e042dd38a026311 100644 --- a/clang/lib/Lex/MacroInfo.cpp +++ b/clang/lib/Lex/MacroInfo.cpp @@ -155,9 +155,11 @@ LLVM_DUMP_METHOD void MacroInfo::dump() const { // FIXME: Dump locations. Out << "MacroInfo " << this; if (IsBuiltinMacro) Out << " builtin"; - if (!isEnabled()) Out << " disabled"; + if (!isEnabled()) + Out << " disabled"; if (IsUsed) Out << " used"; - if (AllowRecurse) Out << " allow_recurse"; + if (AllowRecurse) + Out << " allow_recurse"; if (IsAllowRedefinitionsWithoutWarning) Out << " allow_redefinitions_without_warning"; if (IsWarnIfUnused) Out << " warn_if_unused"; diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 6fbe08e3baa569a..b02eedea137e800 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -59,26 +59,30 @@ using namespace clang; -void Preprocessor::appendRecursiveVersionIfRequired(IdentifierInfo* II, MacroInfo* MI) { +void Preprocessor::appendRecursiveVersionIfRequired(IdentifierInfo *II, + MacroInfo *MI) { if (!MI->isFunctionLike()) return; auto is_this_macro_tok = [&] (const Token& t) { - return t.getKind() == tok::identifier && t.getIdentifierInfo() == Ident__THIS_MACRO__; + return t.getKind() == tok::identifier && + t.getIdentifierInfo() == Ident__THIS_MACRO__; }; if (llvm::none_of(MI->tokens(), is_this_macro_tok)) return; - IdentifierInfo* ImplMacroII = [&] { + IdentifierInfo *ImplMacroII = [&] { std::string ImplMacroName = "__THIS_MACRO__"; ImplMacroName += II->getName(); return getIdentifierInfo(ImplMacroName); }(); - MacroInfo* NewMI = AllocateMacroInfo(MI->getDefinitionLoc()); + MacroInfo *NewMI = AllocateMacroInfo(MI->getDefinitionLoc()); NewMI->setIsFunctionLike(); NewMI->setParameterList(MI->params(), getPreprocessorAllocator()); NewMI->setDefinitionEndLoc(MI->getDefinitionEndLoc()); - if (MI->isC99Varargs()) NewMI->setIsC99Varargs(); - if (MI->isGNUVarargs()) NewMI->setIsGNUVarargs(); - for (auto& t : MI->tokens()) { + if (MI->isC99Varargs()) + NewMI->setIsC99Varargs(); + if (MI->isGNUVarargs()) + NewMI->setIsGNUVarargs(); + for (auto &t : MI->tokens()) { if (is_this_macro_tok(t)) t.setIdentifierInfo(ImplMacroII); } >From 49b60855eed5657f386bc058c31457aa9bd78466 Mon Sep 17 00:00:00 2001 From: Kelbon Nik <kelbon...@gmail.com> Date: Sun, 24 Sep 2023 15:37:30 +0400 Subject: [PATCH 14/17] format again --- clang/include/clang/Lex/MacroInfo.h | 4 ++-- clang/lib/Lex/PPMacroExpansion.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/Lex/MacroInfo.h b/clang/include/clang/Lex/MacroInfo.h index b1df66961dd853d..904efe83ca12fe5 100644 --- a/clang/include/clang/Lex/MacroInfo.h +++ b/clang/include/clang/Lex/MacroInfo.h @@ -299,10 +299,10 @@ class MacroInfo { assert(Depth != 0 && "Cannot enable not disabled macro"); --Depth; } - + [[nodiscard("infinite recursion check ignored")]] bool TryDisableMacro() { assert((AllowRecurse || Depth == 0) && - "Cannot disable an already-disabled macro!"); + "Cannot disable an already-disabled macro!"); return ++Depth < macro_recursion_depth_limit; } diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index b02eedea137e800..fbd26a60adb53c4 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -63,7 +63,7 @@ void Preprocessor::appendRecursiveVersionIfRequired(IdentifierInfo *II, MacroInfo *MI) { if (!MI->isFunctionLike()) return; - auto is_this_macro_tok = [&] (const Token& t) { + auto is_this_macro_tok = [&](const Token& t) { return t.getKind() == tok::identifier && t.getIdentifierInfo() == Ident__THIS_MACRO__; }; >From de5a85225b695a444f9ff938902ad3abd36ed39b Mon Sep 17 00:00:00 2001 From: Kelbon Nik <kelbon...@gmail.com> Date: Sun, 24 Sep 2023 15:58:21 +0400 Subject: [PATCH 15/17] format 3 --- clang/include/clang/Lex/MacroInfo.h | 2 +- clang/lib/Lex/PPMacroExpansion.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/Lex/MacroInfo.h b/clang/include/clang/Lex/MacroInfo.h index 904efe83ca12fe5..81fd1574747127a 100644 --- a/clang/include/clang/Lex/MacroInfo.h +++ b/clang/include/clang/Lex/MacroInfo.h @@ -302,7 +302,7 @@ class MacroInfo { [[nodiscard("infinite recursion check ignored")]] bool TryDisableMacro() { assert((AllowRecurse || Depth == 0) && - "Cannot disable an already-disabled macro!"); + "Cannot disable an already-disabled macro!"); return ++Depth < macro_recursion_depth_limit; } diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index fbd26a60adb53c4..d78476349855d7a 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -63,7 +63,7 @@ void Preprocessor::appendRecursiveVersionIfRequired(IdentifierInfo *II, MacroInfo *MI) { if (!MI->isFunctionLike()) return; - auto is_this_macro_tok = [&](const Token& t) { + auto is_this_macro_tok = [&](const Token &t) { return t.getKind() == tok::identifier && t.getIdentifierInfo() == Ident__THIS_MACRO__; }; >From 10ec673196e9def900ecd17fb830f4f8d9a6099f Mon Sep 17 00:00:00 2001 From: Kelbon Nik <kelbon...@gmail.com> Date: Sun, 24 Sep 2023 17:23:39 +0400 Subject: [PATCH 16/17] undef implemented with define... --- clang/include/clang/Lex/Preprocessor.h | 2 +- clang/lib/Lex/PPMacroExpansion.cpp | 37 +++++++++++++------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index fb128d8c0e77334..4e75f4a269ac35f 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -2429,7 +2429,7 @@ class Preprocessor { /// If macro definition contains __THIS_MACRO__ creates impl-only recursive /// version of macro, and replaces all __THIS_MACRO__ tokens /// with new created recusive version - void appendRecursiveVersionIfRequired(IdentifierInfo *, MacroInfo *); + void appendRecursiveVersionIfRequired(const IdentifierInfo &, MacroInfo &); void PushIncludeMacroStack() { assert(CurLexerKind != CLK_CachingLexer && "cannot push a caching lexer"); diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index d78476349855d7a..de14dbe109d7e8d 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -59,36 +59,36 @@ using namespace clang; -void Preprocessor::appendRecursiveVersionIfRequired(IdentifierInfo *II, - MacroInfo *MI) { - if (!MI->isFunctionLike()) +void Preprocessor::appendRecursiveVersionIfRequired(const IdentifierInfo &II, + MacroInfo &MI) { + if (!MI.isFunctionLike()) return; auto is_this_macro_tok = [&](const Token &t) { return t.getKind() == tok::identifier && t.getIdentifierInfo() == Ident__THIS_MACRO__; }; - if (llvm::none_of(MI->tokens(), is_this_macro_tok)) + if (llvm::none_of(MI.tokens(), is_this_macro_tok)) return; IdentifierInfo *ImplMacroII = [&] { std::string ImplMacroName = "__THIS_MACRO__"; - ImplMacroName += II->getName(); + ImplMacroName += II.getName(); return getIdentifierInfo(ImplMacroName); }(); - MacroInfo *NewMI = AllocateMacroInfo(MI->getDefinitionLoc()); - NewMI->setIsFunctionLike(); - NewMI->setParameterList(MI->params(), getPreprocessorAllocator()); - NewMI->setDefinitionEndLoc(MI->getDefinitionEndLoc()); - if (MI->isC99Varargs()) - NewMI->setIsC99Varargs(); - if (MI->isGNUVarargs()) - NewMI->setIsGNUVarargs(); - for (auto &t : MI->tokens()) { + MacroInfo &NewMI = *AllocateMacroInfo(MI.getDefinitionLoc()); + NewMI.setIsFunctionLike(); + NewMI.setParameterList(MI.params(), getPreprocessorAllocator()); + NewMI.setDefinitionEndLoc(MI.getDefinitionEndLoc()); + if (MI.isC99Varargs()) + NewMI.setIsC99Varargs(); + if (MI.isGNUVarargs()) + NewMI.setIsGNUVarargs(); + for (auto &t : MI.tokens()) { if (is_this_macro_tok(t)) t.setIdentifierInfo(ImplMacroII); } - NewMI->setTokens(MI->tokens(), getPreprocessorAllocator()); - NewMI->setAllowRecursive(true); - appendDefMacroDirective(ImplMacroII, NewMI); + NewMI.setTokens(MI.tokens(), getPreprocessorAllocator()); + NewMI.setAllowRecursive(true); + appendDefMacroDirective(ImplMacroII, &NewMI); } MacroDirective * @@ -123,7 +123,8 @@ void Preprocessor::appendMacroDirective(IdentifierInfo *II, MacroDirective *MD){ II->setHasMacroDefinition(false); if (II->isFromAST()) II->setChangedSinceDeserialization(); - appendRecursiveVersionIfRequired(II, MD->getMacroInfo()); + if (MacroInfo *MI = MD->getMacroInfo()) + appendRecursiveVersionIfRequired(*II, *MI); } void Preprocessor::setLoadedMacroDirective(IdentifierInfo *II, >From c21a0203b8440bfc809ffeb16bc797cad5cc022d Mon Sep 17 00:00:00 2001 From: Kelbon Nik <kelbon...@gmail.com> Date: Tue, 3 Oct 2023 16:23:03 +0400 Subject: [PATCH 17/17] allow recurse for all functional macros with __THIS_MACRO__ token --- clang/include/clang/Lex/Preprocessor.h | 5 --- clang/lib/Lex/PPMacroExpansion.cpp | 48 ++++++--------------- clang/test/Preprocessor/macro_recursion.cpp | 11 +++++ 3 files changed, 25 insertions(+), 39 deletions(-) diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 4e75f4a269ac35f..e7e7bd5d47397b4 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -2426,11 +2426,6 @@ class Preprocessor { private: friend void TokenLexer::ExpandFunctionArguments(); - /// If macro definition contains __THIS_MACRO__ creates impl-only recursive - /// version of macro, and replaces all __THIS_MACRO__ tokens - /// with new created recusive version - void appendRecursiveVersionIfRequired(const IdentifierInfo &, MacroInfo &); - void PushIncludeMacroStack() { assert(CurLexerKind != CLK_CachingLexer && "cannot push a caching lexer"); IncludeMacroStack.emplace_back(CurLexerKind, CurLexerSubmodule, diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index de14dbe109d7e8d..31adf7d37bce363 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -59,38 +59,6 @@ using namespace clang; -void Preprocessor::appendRecursiveVersionIfRequired(const IdentifierInfo &II, - MacroInfo &MI) { - if (!MI.isFunctionLike()) - return; - auto is_this_macro_tok = [&](const Token &t) { - return t.getKind() == tok::identifier && - t.getIdentifierInfo() == Ident__THIS_MACRO__; - }; - if (llvm::none_of(MI.tokens(), is_this_macro_tok)) - return; - IdentifierInfo *ImplMacroII = [&] { - std::string ImplMacroName = "__THIS_MACRO__"; - ImplMacroName += II.getName(); - return getIdentifierInfo(ImplMacroName); - }(); - MacroInfo &NewMI = *AllocateMacroInfo(MI.getDefinitionLoc()); - NewMI.setIsFunctionLike(); - NewMI.setParameterList(MI.params(), getPreprocessorAllocator()); - NewMI.setDefinitionEndLoc(MI.getDefinitionEndLoc()); - if (MI.isC99Varargs()) - NewMI.setIsC99Varargs(); - if (MI.isGNUVarargs()) - NewMI.setIsGNUVarargs(); - for (auto &t : MI.tokens()) { - if (is_this_macro_tok(t)) - t.setIdentifierInfo(ImplMacroII); - } - NewMI.setTokens(MI.tokens(), getPreprocessorAllocator()); - NewMI.setAllowRecursive(true); - appendDefMacroDirective(ImplMacroII, &NewMI); -} - MacroDirective * Preprocessor::getLocalMacroDirectiveHistory(const IdentifierInfo *II) const { if (!II->hadMacroDefinition()) @@ -123,8 +91,20 @@ void Preprocessor::appendMacroDirective(IdentifierInfo *II, MacroDirective *MD){ II->setHasMacroDefinition(false); if (II->isFromAST()) II->setChangedSinceDeserialization(); - if (MacroInfo *MI = MD->getMacroInfo()) - appendRecursiveVersionIfRequired(*II, *MI); + // handle __THIS_MACRO__ if presented + MacroInfo *MI = MD->getMacroInfo(); + if (!MI || !MI->isFunctionLike()) + return; + auto is_this_macro = [&](const Token &t) { + return t.is(tok::identifier) && + t.getIdentifierInfo() == Ident__THIS_MACRO__; + }; + if (llvm::none_of(MI->tokens(), is_this_macro)) + return; + MI->setAllowRecursive(true); + for (auto &t : MI->tokens()) + if (is_this_macro(t)) + t.setIdentifierInfo(II); } void Preprocessor::setLoadedMacroDirective(IdentifierInfo *II, diff --git a/clang/test/Preprocessor/macro_recursion.cpp b/clang/test/Preprocessor/macro_recursion.cpp index fc2c2ffd21eadd6..5fd379680645fa4 100644 --- a/clang/test/Preprocessor/macro_recursion.cpp +++ b/clang/test/Preprocessor/macro_recursion.cpp @@ -26,3 +26,14 @@ // CHECK: 3: ((((4)+3)+2)+1) #undef fold_left + +#define PROCESS_ELEM(X)X +#define PROCESS_LIST(...)__VA_OPT__({PROCESS(__VA_ARGS__)}) +#define PROCESS(X, ...)PROCESS_##X __VA_OPT__(,__THIS_MACRO__(__VA_ARGS__)) + +4: PROCESS(ELEM(0),LIST(ELEM(1),ELEM(2)),ELEM(3)) +// CHECK: 4: 0 ,{1, 2}, 3 + +#undef PROCESS_LIST +#undef PROCESS_ELEM +#undef PROCESS _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits