[clang] Extension: allow recursive macros (PR #65851)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Sep 24 06:23:55 PDT 2023
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 <kelbonage at gmail.com>
Date: Sat, 9 Sep 2023 17:51:15 +0400
Subject: [PATCH 01/16] 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 <kelbonage at gmail.com>
Date: Sun, 10 Sep 2023 16:00:45 +0400
Subject: [PATCH 02/16] 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 <kelbonage at gmail.com>
Date: Mon, 11 Sep 2023 12:03:36 +0400
Subject: [PATCH 03/16] 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 <kelbonage at gmail.com>
Date: Mon, 11 Sep 2023 13:54:55 +0400
Subject: [PATCH 04/16] 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 <kelbonage at gmail.com>
Date: Mon, 11 Sep 2023 13:55:51 +0400
Subject: [PATCH 05/16] 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 <kelbonage at gmail.com>
Date: Mon, 11 Sep 2023 14:23:17 +0400
Subject: [PATCH 06/16] 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 <kelbonage at gmail.com>
Date: Mon, 11 Sep 2023 16:10:20 +0400
Subject: [PATCH 07/16] 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 <kelbonage at gmail.com>
Date: Tue, 12 Sep 2023 01:53:45 +0400
Subject: [PATCH 08/16] 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 <kelbonage at gmail.com>
Date: Sun, 24 Sep 2023 13:42:56 +0400
Subject: [PATCH 09/16] __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 <kelbonage at gmail.com>
Date: Sun, 24 Sep 2023 14:49:26 +0400
Subject: [PATCH 10/16] 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 <kelbonage at gmail.com>
Date: Sun, 24 Sep 2023 14:52:58 +0400
Subject: [PATCH 11/16] 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 <kelbonage at gmail.com>
Date: Sun, 24 Sep 2023 15:08:31 +0400
Subject: [PATCH 12/16] 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 <kelbonage at gmail.com>
Date: Sun, 24 Sep 2023 15:16:55 +0400
Subject: [PATCH 13/16] 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 <kelbonage at gmail.com>
Date: Sun, 24 Sep 2023 15:37:30 +0400
Subject: [PATCH 14/16] 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 <kelbonage at gmail.com>
Date: Sun, 24 Sep 2023 15:58:21 +0400
Subject: [PATCH 15/16] 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 <kelbonage at gmail.com>
Date: Sun, 24 Sep 2023 17:23:39 +0400
Subject: [PATCH 16/16] 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,
More information about the cfe-commits
mailing list