clang 10.0.0git

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