clang  6.0.0svn
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).
32  const Preprocessor &PP;
33  IdentifierInfo *const Ident__VA_ARGS__;
34  IdentifierInfo *const Ident__VA_OPT__;
35 
36  public:
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  /// occured 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 
67  };
68 
69  /// \brief A class for tracking whether we're inside a VA_OPT during a
70  /// traversal of the tokens of a variadic macro definition.
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:
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 '('.
92  assert(!isInVAOpt() && "Must NOT be within VAOPT context to call this");
93  UnmatchedOpeningParens.push_back(LParenLoc);
94 
95  }
96 
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.
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  /// \brief A class for tracking whether we're inside a VA_OPT during a
120  /// traversal of the tokens of a macro during macro expansion.
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:
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  }
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 
196  assert(hasStringifyBefore() &&
197  "Must only be called if this has been marked for stringification");
198  return LeadingSpaceForStringifiedToken;
199  }
200 
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");
206  this->VAOptLoc = VAOptLoc;
207  NumOfTokensPriorToVAOpt = NumPriorTokens;
208  assert(NumOfTokensPriorToVAOpt > -1 &&
209  "Too many prior tokens");
210  }
211 
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  }
222 
223  };
224 } // end namespace clang
225 
226 #endif
void sawOpeningParen(SourceLocation LParenLoc)
Call this function each time an lparen is seen.
bool sawClosingParen()
Call this function each time an rparen is seen.
StringRef P
A class for tracking whether we&#39;re inside a VA_OPT during a traversal of the tokens of a macro during...
One of these records is kept for each identifier that is lexed.
void sawVAOptFollowedByOpeningParens(const SourceLocation VAOptLoc, const unsigned int NumPriorTokens)
Token - This structure provides full information about a lexed token.
Definition: Token.h:35
void setKind(tok::TokenKind K)
Definition: Token.h:91
void exitScope()
Client code should call this function as soon as the Preprocessor has either completed lexing the mac...
VAOptDefinitionContext(Preprocessor &PP)
const FunctionProtoType * T
SourceLocation getVAOptLoc() const
A class for tracking whether we&#39;re inside a VA_OPT during a traversal of the tokens of a variadic mac...
Defines the clang::Preprocessor interface.
void setIsPoisoned(bool Value=true)
setIsPoisoned - Mark this identifier as poisoned.
void enterScope()
Client code should call this function just before the Preprocessor is about to Lex tokens from the de...
SourceLocation getUnmatchedOpeningParenLoc() const
bool isVAOptToken(const Token &T) const
#define false
Definition: stdbool.h:33
Encodes a location in the source.
IdentifierInfo * getIdentifierInfo() const
Definition: Token.h:177
bool isInVAOpt() const
Returns true if we have seen the VA_OPT and &#39;(&#39; but before having seen the matching &#39;)&#39;...
bool isPoisoned() const
Return true if this token has been poisoned.
Dataflow Directional Tag Classes.
bool isValid() const
Return true if this is a valid SourceLocation object.
VariadicMacroScopeGuard(const Preprocessor &P)
void sawHashOrHashAtBefore(const bool HasLeadingSpace, const bool IsHashAt)
unsigned int getNumberOfTokensPriorToVAOpt() const
void sawVAOptFollowedByOpeningParens(const SourceLocation LParenLoc)
Call this function as soon as you see VA_OPT and &#39;(&#39;.
void startToken()
Reset all flags to cleared.
Definition: Token.h:169
An RAII class that tracks when the Preprocessor starts and stops lexing the definition of a (ISO C/C+...
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:98