Skip to content

Commit

Permalink
__THIS_MACRO__
Browse files Browse the repository at this point in the history
  • Loading branch information
kelbon committed Sep 24, 2023
1 parent 8555660 commit 49d7fa2
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 11 deletions.
18 changes: 13 additions & 5 deletions clang/include/clang/Lex/MacroInfo.h
Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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.
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Lex/Preprocessor.h
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
29 changes: 29 additions & 0 deletions clang/lib/Lex/PPMacroExpansion.cpp
Expand Up @@ -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())
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Lex/Preprocessor.cpp
Expand Up @@ -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();
Expand Down
6 changes: 3 additions & 3 deletions 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}}

Expand Down
6 changes: 3 additions & 3 deletions clang/test/Preprocessor/macro_recursion.cpp
Expand Up @@ -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
Expand All @@ -12,15 +12,15 @@
#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)

// CHECK: 2: 3,2,1

#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)
Expand Down

0 comments on commit 49d7fa2

Please sign in to comment.