clang 8.0.0

VariadicMacroSupport.h
Go to the documentation of this file.
1 //===- VariadicMacroSupport.h - state machines and scope guards -*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines support types to help with preprocessing variadic macro
11 // (i.e. macros that use: ellipses __VA_ARGS__ ) definitions and
12 // expansions.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #ifndef LLVM_CLANG_LEX_VARIADICMACROSUPPORT_H
17 #define LLVM_CLANG_LEX_VARIADICMACROSUPPORT_H
18
19 #include "clang/Lex/Preprocessor.h"
20 #include "llvm/ADT/SmallVector.h"
21
22 namespace clang {
23 class Preprocessor;
24
25 /// An RAII class that tracks when the Preprocessor starts and stops lexing
26 /// the definition of a (ISO C/C++) variadic macro. As an example, this is
27 /// useful for unpoisoning and repoisoning certain identifiers (such as
28 /// __VA_ARGS__) that are only allowed in this context. Also, being a friend
29 /// of the Preprocessor class allows it to access PP's cached identifiers
30 /// directly (as opposed to performing a lookup each time).
31 class VariadicMacroScopeGuard {
32 const Preprocessor &PP;
33 IdentifierInfo *const Ident__VA_ARGS__;
34 IdentifierInfo *const Ident__VA_OPT__;
35
36 public:
37 VariadicMacroScopeGuard(const Preprocessor &P)
38 : PP(P), Ident__VA_ARGS__(PP.Ident__VA_ARGS__),
39 Ident__VA_OPT__(PP.Ident__VA_OPT__) {
40 assert(Ident__VA_ARGS__->isPoisoned() && "__VA_ARGS__ should be poisoned "
41 "outside an ISO C/C++ variadic "
42 "macro definition!");
43 assert(
44 !Ident__VA_OPT__ ||
45 (Ident__VA_OPT__->isPoisoned() && "__VA_OPT__ should be poisoned!"));
46 }
47
48 /// Client code should call this function just before the Preprocessor is
49 /// about to Lex tokens from the definition of a variadic (ISO C/C++) macro.
50 void enterScope() {
51 Ident__VA_ARGS__->setIsPoisoned(false);
52 if (Ident__VA_OPT__)
53 Ident__VA_OPT__->setIsPoisoned(false);
54 }
55
56 /// Client code should call this function as soon as the Preprocessor has
57 /// either completed lexing the macro's definition tokens, or an error
58 /// occurred and the context is being exited. This function is idempotent
59 /// (might be explicitly called, and then reinvoked via the destructor).
60 void exitScope() {
61 Ident__VA_ARGS__->setIsPoisoned(true);
62 if (Ident__VA_OPT__)
63 Ident__VA_OPT__->setIsPoisoned(true);
64 }
65
66 ~VariadicMacroScopeGuard() { exitScope(); }
67 };
68
69 /// A class for tracking whether we're inside a VA_OPT during a
70 /// traversal of the tokens of a variadic macro definition.
71 class VAOptDefinitionContext {
72 /// Contains all the locations of so far unmatched lparens.
73 SmallVector<SourceLocation, 8> UnmatchedOpeningParens;
74
75 const IdentifierInfo *const Ident__VA_OPT__;
76
77
78 public:
79 VAOptDefinitionContext(Preprocessor &PP)
80 : Ident__VA_OPT__(PP.Ident__VA_OPT__) {}
81
82 bool isVAOptToken(const Token &T) const {
83 return Ident__VA_OPT__ && T.getIdentifierInfo() == Ident__VA_OPT__;
84 }
85
86 /// Returns true if we have seen the __VA_OPT__ and '(' but before having
87 /// seen the matching ')'.
88 bool isInVAOpt() const { return UnmatchedOpeningParens.size(); }
89
90 /// Call this function as soon as you see __VA_OPT__ and '('.
91 void sawVAOptFollowedByOpeningParens(const SourceLocation LParenLoc) {
92 assert(!isInVAOpt() && "Must NOT be within VAOPT context to call this");
93 UnmatchedOpeningParens.push_back(LParenLoc);
94
95 }
96
97 SourceLocation getUnmatchedOpeningParenLoc() const {
98 assert(isInVAOpt() && "Must be within VAOPT context to call this");
99 return UnmatchedOpeningParens.back();
100 }
101
102 /// Call this function each time an rparen is seen. It returns true only if
103 /// the rparen that was just seen was the eventual (non-nested) closing
104 /// paren for VAOPT, and ejects us out of the VAOPT context.
105 bool sawClosingParen() {
106 assert(isInVAOpt() && "Must be within VAOPT context to call this");
107 UnmatchedOpeningParens.pop_back();
108 return !UnmatchedOpeningParens.size();
109 }
110
111 /// Call this function each time an lparen is seen.
112 void sawOpeningParen(SourceLocation LParenLoc) {
113 assert(isInVAOpt() && "Must be within VAOPT context to call this");
114 UnmatchedOpeningParens.push_back(LParenLoc);
115 }
116
117 };
118
119 /// A class for tracking whether we're inside a VA_OPT during a
120 /// traversal of the tokens of a macro during macro expansion.
121 class VAOptExpansionContext : VAOptDefinitionContext {
122
123 Token SyntheticEOFToken;
124
125 // The (spelling) location of the current __VA_OPT__ in the replacement list
126 // of the function-like macro being expanded.
127 SourceLocation VAOptLoc;
128
129 // NumOfTokensPriorToVAOpt : when != -1, contains the index *of* the first
130 // token of the current VAOPT contents (so we know where to start eager
131 // token-pasting and stringification) *within* the substituted tokens of
132 // the function-like macro's new replacement list.
133 int NumOfTokensPriorToVAOpt = -1;
134
135 unsigned LeadingSpaceForStringifiedToken : 1;
136
137 unsigned StringifyBefore : 1;
138 unsigned CharifyBefore : 1;
139
140
141 bool hasStringifyBefore() const {
142 assert(!isReset() &&
143 "Must only be called if the state has not been reset");
144 return StringifyBefore;
145 }
146
147 bool isReset() const {
148 return NumOfTokensPriorToVAOpt == -1 ||
149 VAOptLoc.isInvalid();
150 }
151
152 public:
153 VAOptExpansionContext(Preprocessor &PP)
154 : VAOptDefinitionContext(PP), LeadingSpaceForStringifiedToken(false),
155 StringifyBefore(false), CharifyBefore(false) {
156 SyntheticEOFToken.startToken();
157 SyntheticEOFToken.setKind(tok::eof);
158 }
159
160 void reset() {
161 VAOptLoc = SourceLocation();
162 NumOfTokensPriorToVAOpt = -1;
163 LeadingSpaceForStringifiedToken = false;
164 StringifyBefore = false;
165 CharifyBefore = false;
166 }
167
168 const Token &getEOFTok() const { return SyntheticEOFToken; }
169
170 void sawHashOrHashAtBefore(const bool HasLeadingSpace,
171 const bool IsHashAt) {
172
173 StringifyBefore = !IsHashAt;
174 CharifyBefore = IsHashAt;
175 LeadingSpaceForStringifiedToken = HasLeadingSpace;
176 }
177
178
179
180 bool hasCharifyBefore() const {
181 assert(!isReset() &&
182 "Must only be called if the state has not been reset");
183 return CharifyBefore;
184 }
185 bool hasStringifyOrCharifyBefore() const {
186 return hasStringifyBefore() || hasCharifyBefore();
187 }
188
189 unsigned int getNumberOfTokensPriorToVAOpt() const {
190 assert(!isReset() &&
191 "Must only be called if the state has not been reset");
192 return NumOfTokensPriorToVAOpt;
193 }
194
195 bool getLeadingSpaceForStringifiedToken() const {
196 assert(hasStringifyBefore() &&
197 "Must only be called if this has been marked for stringification");
198 return LeadingSpaceForStringifiedToken;
199 }
200
201 void sawVAOptFollowedByOpeningParens(const SourceLocation VAOptLoc,
202 const unsigned int NumPriorTokens) {
203 assert(VAOptLoc.isFileID() && "Must not come from a macro expansion");
204 assert(isReset() && "Must only be called if the state has been reset");
205 VAOptDefinitionContext::sawVAOptFollowedByOpeningParens(SourceLocation());
206 this->VAOptLoc = VAOptLoc;
207 NumOfTokensPriorToVAOpt = NumPriorTokens;
208 assert(NumOfTokensPriorToVAOpt > -1 &&
209 "Too many prior tokens");
210 }
211
212 SourceLocation getVAOptLoc() const {
213 assert(!isReset() &&
214 "Must only be called if the state has not been reset");
215 assert(VAOptLoc.isValid() && "__VA_OPT__ location must be valid");
216 return VAOptLoc;
217 }
218 using VAOptDefinitionContext::isVAOptToken;
219 using VAOptDefinitionContext::isInVAOpt;
220 using VAOptDefinitionContext::sawClosingParen;
221 using VAOptDefinitionContext::sawOpeningParen;
222
223 };
224 } // end namespace clang
225
226 #endif
clang::VAOptDefinitionContext::sawOpeningParen
void sawOpeningParen(SourceLocation LParenLoc)
Call this function each time an lparen is seen.
Definition: VariadicMacroSupport.h:112
clang::VAOptDefinitionContext::sawClosingParen
bool sawClosingParen()
Call this function each time an rparen is seen.
Definition: VariadicMacroSupport.h:105
P
StringRef P
Definition: ASTMatchersInternal.cpp:439
clang::VAOptExpansionContext
A class for tracking whether we&#39;re inside a VA_OPT during a traversal of the tokens of a macro during...
Definition: VariadicMacroSupport.h:121
clang::VAOptExpansionContext::hasCharifyBefore
bool hasCharifyBefore() const
Definition: VariadicMacroSupport.h:180
clang::VAOptExpansionContext::getLeadingSpaceForStringifiedToken
bool getLeadingSpaceForStringifiedToken() const
Definition: VariadicMacroSupport.h:195
clang::VAOptExpansionContext::hasStringifyOrCharifyBefore
bool hasStringifyOrCharifyBefore() const
Definition: VariadicMacroSupport.h:185
clang::IdentifierInfo
One of these records is kept for each identifier that is lexed.
Definition: IdentifierTable.h:58
clang::VAOptExpansionContext::getEOFTok
const Token & getEOFTok() const
Definition: VariadicMacroSupport.h:168
clang::VAOptExpansionContext::sawVAOptFollowedByOpeningParens
void sawVAOptFollowedByOpeningParens(const SourceLocation VAOptLoc, const unsigned int NumPriorTokens)
Definition: VariadicMacroSupport.h:201
clang::Token
Token - This structure provides full information about a lexed token.
Definition: Token.h:35
clang::Token::setKind
void setKind(tok::TokenKind K)
Definition: Token.h:91
clang::VariadicMacroScopeGuard::exitScope
void exitScope()
Client code should call this function as soon as the Preprocessor has either completed lexing the mac...
Definition: VariadicMacroSupport.h:60
clang::VAOptExpansionContext::reset
void reset()
Definition: VariadicMacroSupport.h:160
clang::VAOptDefinitionContext::VAOptDefinitionContext
VAOptDefinitionContext(Preprocessor &PP)
Definition: VariadicMacroSupport.h:79
clang::SourceLocation::isFileID
bool isFileID() const
Definition: SourceLocation.h:100
clang::VariadicMacroScopeGuard::~VariadicMacroScopeGuard
~VariadicMacroScopeGuard()
Definition: VariadicMacroSupport.h:66
clang::VAOptExpansionContext::getVAOptLoc
SourceLocation getVAOptLoc() const
Definition: VariadicMacroSupport.h:212
clang::VAOptDefinitionContext
A class for tracking whether we&#39;re inside a VA_OPT during a traversal of the tokens of a variadic mac...
Definition: VariadicMacroSupport.h:71
Preprocessor.h
Defines the clang::Preprocessor interface.
clang::IdentifierInfo::setIsPoisoned
void setIsPoisoned(bool Value=true)
setIsPoisoned - Mark this identifier as poisoned.
Definition: IdentifierTable.h:282
clang::VariadicMacroScopeGuard::enterScope
void enterScope()
Client code should call this function just before the Preprocessor is about to Lex tokens from the de...
Definition: VariadicMacroSupport.h:50
clang::VAOptDefinitionContext::getUnmatchedOpeningParenLoc
SourceLocation getUnmatchedOpeningParenLoc() const
Definition: VariadicMacroSupport.h:97
clang::VAOptDefinitionContext::isVAOptToken
bool isVAOptToken(const Token &T) const
Definition: VariadicMacroSupport.h:82
false
#define false
Definition: stdbool.h:33
clang::SourceLocation
Encodes a location in the source.
Definition: SourceLocation.h:88
clang::Token::getIdentifierInfo
IdentifierInfo * getIdentifierInfo() const
Definition: Token.h:177
clang::VAOptDefinitionContext::isInVAOpt
bool isInVAOpt() const
Returns true if we have seen the VA_OPT and &#39;(&#39; but before having seen the matching &#39;)&#39;...
Definition: VariadicMacroSupport.h:88
clang::IdentifierInfo::isPoisoned
bool isPoisoned() const
Return true if this token has been poisoned.
Definition: IdentifierTable.h:291
llvm::SmallVector
Definition: LLVM.h:36
clang
Dataflow Directional Tag Classes.
Definition: CFGReachabilityAnalysis.h:22
clang::SourceLocation::isValid
bool isValid() const
Return true if this is a valid SourceLocation object.
Definition: SourceLocation.h:108
clang::VariadicMacroScopeGuard::VariadicMacroScopeGuard
VariadicMacroScopeGuard(const Preprocessor &P)
Definition: VariadicMacroSupport.h:37
clang::VAOptExpansionContext::sawHashOrHashAtBefore
void sawHashOrHashAtBefore(const bool HasLeadingSpace, const bool IsHashAt)
Definition: VariadicMacroSupport.h:170
clang::comments::tok::eof
Definition: CommentLexer.h:34
clang::VAOptExpansionContext::getNumberOfTokensPriorToVAOpt
unsigned int getNumberOfTokensPriorToVAOpt() const
Definition: VariadicMacroSupport.h:189
clang::SourceLocation::isInvalid
bool isInvalid() const
Definition: SourceLocation.h:109
clang::VAOptDefinitionContext::sawVAOptFollowedByOpeningParens
void sawVAOptFollowedByOpeningParens(const SourceLocation LParenLoc)
Call this function as soon as you see VA_OPT and &#39;(&#39;.
Definition: VariadicMacroSupport.h:91
clang::VAOptExpansionContext::VAOptExpansionContext
VAOptExpansionContext(Preprocessor &PP)
Definition: VariadicMacroSupport.h:153
clang::Token::startToken
void startToken()
Reset all flags to cleared.
Definition: Token.h:169
clang::VariadicMacroScopeGuard
An RAII class that tracks when the Preprocessor starts and stops lexing the definition of a (ISO C/C+...
Definition: VariadicMacroSupport.h:31
clang::Preprocessor
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:125