clang  10.0.0svn
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).
31  const Preprocessor &PP;
32  IdentifierInfo *const Ident__VA_ARGS__;
33  IdentifierInfo *const Ident__VA_OPT__;
34 
35  public:
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 
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.
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:
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 '('.
91  assert(!isInVAOpt() && "Must NOT be within VAOPT context to call this");
92  UnmatchedOpeningParens.push_back(LParenLoc);
93 
94  }
95 
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.
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.
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:
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; }
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  }
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 
217  assert(hasStringifyBefore() &&
218  "Must only be called if this has been marked for stringification");
219  return LeadingSpaceForStringifiedToken;
220  }
221 
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");
227  this->VAOptLoc = VAOptLoc;
228  NumOfTokensPriorToVAOpt = NumPriorTokens;
229  assert(NumOfTokensPriorToVAOpt > -1 &&
230  "Too many prior tokens");
231  }
232 
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  }
243 
244  };
245 } // end namespace clang
246 
247 #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:34
void setKind(tok::TokenKind K)
Definition: Token.h:93
void exitScope()
Client code should call this function as soon as the Preprocessor has either completed lexing the mac...
VAOptDefinitionContext(Preprocessor &PP)
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:17
Encodes a location in the source.
IdentifierInfo * getIdentifierInfo() const
Definition: Token.h:179
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)
bool isAtTopLevel() const
Are we at the top level within the VA_OPT?
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:171
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:125