clang  9.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  };
117 
118  /// A class for tracking whether we're inside a VA_OPT during a
119  /// traversal of the tokens of a macro during macro expansion.
121 
122  Token SyntheticEOFToken;
123 
124  // The (spelling) location of the current __VA_OPT__ in the replacement list
125  // of the function-like macro being expanded.
126  SourceLocation VAOptLoc;
127 
128  // NumOfTokensPriorToVAOpt : when != -1, contains the index *of* the first
129  // token of the current VAOPT contents (so we know where to start eager
130  // token-pasting and stringification) *within* the substituted tokens of
131  // the function-like macro's new replacement list.
132  int NumOfTokensPriorToVAOpt = -1;
133 
134  unsigned LeadingSpaceForStringifiedToken : 1;
135 
136  unsigned StringifyBefore : 1;
137  unsigned CharifyBefore : 1;
138 
139 
140  bool hasStringifyBefore() const {
141  assert(!isReset() &&
142  "Must only be called if the state has not been reset");
143  return StringifyBefore;
144  }
145 
146  bool isReset() const {
147  return NumOfTokensPriorToVAOpt == -1 ||
148  VAOptLoc.isInvalid();
149  }
150 
151  public:
153  : VAOptDefinitionContext(PP), LeadingSpaceForStringifiedToken(false),
154  StringifyBefore(false), CharifyBefore(false) {
155  SyntheticEOFToken.startToken();
156  SyntheticEOFToken.setKind(tok::eof);
157  }
158 
159  void reset() {
160  VAOptLoc = SourceLocation();
161  NumOfTokensPriorToVAOpt = -1;
162  LeadingSpaceForStringifiedToken = false;
163  StringifyBefore = false;
164  CharifyBefore = false;
165  }
166 
167  const Token &getEOFTok() const { return SyntheticEOFToken; }
168 
169  void sawHashOrHashAtBefore(const bool HasLeadingSpace,
170  const bool IsHashAt) {
171 
172  StringifyBefore = !IsHashAt;
173  CharifyBefore = IsHashAt;
174  LeadingSpaceForStringifiedToken = HasLeadingSpace;
175  }
176 
177 
178 
179  bool hasCharifyBefore() const {
180  assert(!isReset() &&
181  "Must only be called if the state has not been reset");
182  return CharifyBefore;
183  }
185  return hasStringifyBefore() || hasCharifyBefore();
186  }
187 
188  unsigned int getNumberOfTokensPriorToVAOpt() const {
189  assert(!isReset() &&
190  "Must only be called if the state has not been reset");
191  return NumOfTokensPriorToVAOpt;
192  }
193 
195  assert(hasStringifyBefore() &&
196  "Must only be called if this has been marked for stringification");
197  return LeadingSpaceForStringifiedToken;
198  }
199 
201  const unsigned int NumPriorTokens) {
202  assert(VAOptLoc.isFileID() && "Must not come from a macro expansion");
203  assert(isReset() && "Must only be called if the state has been reset");
205  this->VAOptLoc = VAOptLoc;
206  NumOfTokensPriorToVAOpt = NumPriorTokens;
207  assert(NumOfTokensPriorToVAOpt > -1 &&
208  "Too many prior tokens");
209  }
210 
212  assert(!isReset() &&
213  "Must only be called if the state has not been reset");
214  assert(VAOptLoc.isValid() && "__VA_OPT__ location must be valid");
215  return VAOptLoc;
216  }
221 
222  };
223 } // end namespace clang
224 
225 #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:90
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:33
Encodes a location in the source.
IdentifierInfo * getIdentifierInfo() const
Definition: Token.h:176
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:168
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:124