clang  14.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).
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(Ident__VA_OPT__->isPoisoned() && "__VA_OPT__ should be poisoned!");
43  }
44 
45  /// Client code should call this function just before the Preprocessor is
46  /// about to Lex tokens from the definition of a variadic (ISO C/C++) macro.
47  void enterScope() {
48  Ident__VA_ARGS__->setIsPoisoned(false);
49  Ident__VA_OPT__->setIsPoisoned(false);
50  }
51 
52  /// Client code should call this function as soon as the Preprocessor has
53  /// either completed lexing the macro's definition tokens, or an error
54  /// occurred and the context is being exited. This function is idempotent
55  /// (might be explicitly called, and then reinvoked via the destructor).
56  void exitScope() {
57  Ident__VA_ARGS__->setIsPoisoned(true);
58  Ident__VA_OPT__->setIsPoisoned(true);
59  }
60 
62  };
63 
64  /// A class for tracking whether we're inside a VA_OPT during a
65  /// traversal of the tokens of a variadic macro definition.
67  /// Contains all the locations of so far unmatched lparens.
68  SmallVector<SourceLocation, 8> UnmatchedOpeningParens;
69 
70  const IdentifierInfo *const Ident__VA_OPT__;
71 
72 
73  public:
75  : Ident__VA_OPT__(PP.Ident__VA_OPT__) {}
76 
77  bool isVAOptToken(const Token &T) const {
78  return Ident__VA_OPT__ && T.getIdentifierInfo() == Ident__VA_OPT__;
79  }
80 
81  /// Returns true if we have seen the __VA_OPT__ and '(' but before having
82  /// seen the matching ')'.
83  bool isInVAOpt() const { return UnmatchedOpeningParens.size(); }
84 
85  /// Call this function as soon as you see __VA_OPT__ and '('.
87  assert(!isInVAOpt() && "Must NOT be within VAOPT context to call this");
88  UnmatchedOpeningParens.push_back(LParenLoc);
89 
90  }
91 
93  assert(isInVAOpt() && "Must be within VAOPT context to call this");
94  return UnmatchedOpeningParens.back();
95  }
96 
97  /// Call this function each time an rparen is seen. It returns true only if
98  /// the rparen that was just seen was the eventual (non-nested) closing
99  /// paren for VAOPT, and ejects us out of the VAOPT context.
101  assert(isInVAOpt() && "Must be within VAOPT context to call this");
102  UnmatchedOpeningParens.pop_back();
103  return !UnmatchedOpeningParens.size();
104  }
105 
106  /// Call this function each time an lparen is seen.
107  void sawOpeningParen(SourceLocation LParenLoc) {
108  assert(isInVAOpt() && "Must be within VAOPT context to call this");
109  UnmatchedOpeningParens.push_back(LParenLoc);
110  }
111 
112  /// Are we at the top level within the __VA_OPT__?
113  bool isAtTopLevel() const { return UnmatchedOpeningParens.size() == 1; }
114  };
115 
116  /// A class for tracking whether we're inside a VA_OPT during a
117  /// traversal of the tokens of a macro during macro expansion.
119 
120  Token SyntheticEOFToken;
121 
122  // The (spelling) location of the current __VA_OPT__ in the replacement list
123  // of the function-like macro being expanded.
124  SourceLocation VAOptLoc;
125 
126  // NumOfTokensPriorToVAOpt : when != -1, contains the index *of* the first
127  // token of the current VAOPT contents (so we know where to start eager
128  // token-pasting and stringification) *within* the substituted tokens of
129  // the function-like macro's new replacement list.
130  int NumOfTokensPriorToVAOpt = -1;
131 
132  unsigned LeadingSpaceForStringifiedToken : 1;
133 
134  unsigned StringifyBefore : 1;
135  unsigned CharifyBefore : 1;
136  unsigned BeginsWithPlaceholder : 1;
137  unsigned EndsWithPlaceholder : 1;
138 
139  bool hasStringifyBefore() const {
140  assert(!isReset() &&
141  "Must only be called if the state has not been reset");
142  return StringifyBefore;
143  }
144 
145  bool isReset() const {
146  return NumOfTokensPriorToVAOpt == -1 ||
147  VAOptLoc.isInvalid();
148  }
149 
150  public:
152  : VAOptDefinitionContext(PP), LeadingSpaceForStringifiedToken(false),
153  StringifyBefore(false), CharifyBefore(false),
154  BeginsWithPlaceholder(false), EndsWithPlaceholder(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  BeginsWithPlaceholder = false;
166  EndsWithPlaceholder = false;
167  }
168 
169  const Token &getEOFTok() const { return SyntheticEOFToken; }
170 
171  void sawHashOrHashAtBefore(const bool HasLeadingSpace,
172  const bool IsHashAt) {
173 
174  StringifyBefore = !IsHashAt;
175  CharifyBefore = IsHashAt;
176  LeadingSpaceForStringifiedToken = HasLeadingSpace;
177  }
178 
179  void hasPlaceholderAfterHashhashAtStart() { BeginsWithPlaceholder = true; }
181  if (isAtTopLevel())
182  EndsWithPlaceholder = true;
183  }
184 
185 
186  bool beginsWithPlaceholder() const {
187  assert(!isReset() &&
188  "Must only be called if the state has not been reset");
189  return BeginsWithPlaceholder;
190  }
191  bool endsWithPlaceholder() const {
192  assert(!isReset() &&
193  "Must only be called if the state has not been reset");
194  return EndsWithPlaceholder;
195  }
196 
197  bool hasCharifyBefore() const {
198  assert(!isReset() &&
199  "Must only be called if the state has not been reset");
200  return CharifyBefore;
201  }
203  return hasStringifyBefore() || hasCharifyBefore();
204  }
205 
206  unsigned int getNumberOfTokensPriorToVAOpt() const {
207  assert(!isReset() &&
208  "Must only be called if the state has not been reset");
209  return NumOfTokensPriorToVAOpt;
210  }
211 
213  assert(hasStringifyBefore() &&
214  "Must only be called if this has been marked for stringification");
215  return LeadingSpaceForStringifiedToken;
216  }
217 
219  const unsigned int NumPriorTokens) {
220  assert(VAOptLoc.isFileID() && "Must not come from a macro expansion");
221  assert(isReset() && "Must only be called if the state has been reset");
223  this->VAOptLoc = VAOptLoc;
224  NumOfTokensPriorToVAOpt = NumPriorTokens;
225  assert(NumOfTokensPriorToVAOpt > -1 &&
226  "Too many prior tokens");
227  }
228 
230  assert(!isReset() &&
231  "Must only be called if the state has not been reset");
232  assert(VAOptLoc.isValid() && "__VA_OPT__ location must be valid");
233  return VAOptLoc;
234  }
239 
240  };
241 } // end namespace clang
242 
243 #endif
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::VAOptDefinitionContext::sawVAOptFollowedByOpeningParens
void sawVAOptFollowedByOpeningParens(const SourceLocation LParenLoc)
Call this function as soon as you see VA_OPT and '('.
Definition: VariadicMacroSupport.h:86
clang::VAOptExpansionContext::hasPlaceholderBeforeRParen
void hasPlaceholderBeforeRParen()
Definition: VariadicMacroSupport.h:180
clang::VAOptDefinitionContext::isInVAOpt
bool isInVAOpt() const
Returns true if we have seen the VA_OPT and '(' but before having seen the matching ')'.
Definition: VariadicMacroSupport.h:83
clang::VAOptExpansionContext::sawHashOrHashAtBefore
void sawHashOrHashAtBefore(const bool HasLeadingSpace, const bool IsHashAt)
Definition: VariadicMacroSupport.h:171
clang::VAOptExpansionContext::getNumberOfTokensPriorToVAOpt
unsigned int getNumberOfTokensPriorToVAOpt() const
Definition: VariadicMacroSupport.h:206
llvm::SmallVector
Definition: LLVM.h:38
clang::SourceLocation
Encodes a location in the source.
Definition: SourceLocation.h:88
clang::Token::getIdentifierInfo
IdentifierInfo * getIdentifierInfo() const
Definition: Token.h:179
clang::VAOptExpansionContext::beginsWithPlaceholder
bool beginsWithPlaceholder() const
Definition: VariadicMacroSupport.h:186
clang::VAOptExpansionContext
A class for tracking whether we're inside a VA_OPT during a traversal of the tokens of a macro during...
Definition: VariadicMacroSupport.h:118
clang::VAOptDefinitionContext::VAOptDefinitionContext
VAOptDefinitionContext(Preprocessor &PP)
Definition: VariadicMacroSupport.h:74
clang::Token
Token - This structure provides full information about a lexed token.
Definition: Token.h:34
Preprocessor.h
clang::VAOptExpansionContext::hasCharifyBefore
bool hasCharifyBefore() const
Definition: VariadicMacroSupport.h:197
clang::VAOptExpansionContext::getLeadingSpaceForStringifiedToken
bool getLeadingSpaceForStringifiedToken() const
Definition: VariadicMacroSupport.h:212
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:56
clang::IdentifierInfo::setIsPoisoned
void setIsPoisoned(bool Value=true)
setIsPoisoned - Mark this identifier as poisoned.
Definition: IdentifierTable.h:345
clang::VAOptExpansionContext::VAOptExpansionContext
VAOptExpansionContext(Preprocessor &PP)
Definition: VariadicMacroSupport.h:151
clang::VAOptDefinitionContext::isVAOptToken
bool isVAOptToken(const Token &T) const
Definition: VariadicMacroSupport.h:77
clang::VAOptExpansionContext::reset
void reset()
Definition: VariadicMacroSupport.h:159
clang::SourceLocation::isFileID
bool isFileID() const
Definition: SourceLocation.h:104
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:47
clang::VAOptExpansionContext::hasPlaceholderAfterHashhashAtStart
void hasPlaceholderAfterHashhashAtStart()
Definition: VariadicMacroSupport.h:179
clang::VariadicMacroScopeGuard::VariadicMacroScopeGuard
VariadicMacroScopeGuard(const Preprocessor &P)
Definition: VariadicMacroSupport.h:36
P
StringRef P
Definition: ASTMatchersInternal.cpp:563
clang::VAOptDefinitionContext::sawOpeningParen
void sawOpeningParen(SourceLocation LParenLoc)
Call this function each time an lparen is seen.
Definition: VariadicMacroSupport.h:107
false
#define false
Definition: stdbool.h:17
clang::VAOptExpansionContext::endsWithPlaceholder
bool endsWithPlaceholder() const
Definition: VariadicMacroSupport.h:191
clang::IdentifierInfo::isPoisoned
bool isPoisoned() const
Return true if this token has been poisoned.
Definition: IdentifierTable.h:354
clang::VAOptDefinitionContext
A class for tracking whether we're inside a VA_OPT during a traversal of the tokens of a variadic mac...
Definition: VariadicMacroSupport.h:66
clang::IdentifierInfo
One of these records is kept for each identifier that is lexed.
Definition: IdentifierTable.h:84
clang::VariadicMacroScopeGuard::~VariadicMacroScopeGuard
~VariadicMacroScopeGuard()
Definition: VariadicMacroSupport.h:61
clang::SourceLocation::isInvalid
bool isInvalid() const
Definition: SourceLocation.h:113
clang
Definition: CalledOnceCheck.h:17
clang::VAOptExpansionContext::getEOFTok
const Token & getEOFTok() const
Definition: VariadicMacroSupport.h:169
clang::VAOptExpansionContext::hasStringifyOrCharifyBefore
bool hasStringifyOrCharifyBefore() const
Definition: VariadicMacroSupport.h:202
clang::SourceLocation::isValid
bool isValid() const
Return true if this is a valid SourceLocation object.
Definition: SourceLocation.h:112
clang::VAOptDefinitionContext::getUnmatchedOpeningParenLoc
SourceLocation getUnmatchedOpeningParenLoc() const
Definition: VariadicMacroSupport.h:92
clang::Token::setKind
void setKind(tok::TokenKind K)
Definition: Token.h:93
clang::VAOptDefinitionContext::isAtTopLevel
bool isAtTopLevel() const
Are we at the top level within the VA_OPT?
Definition: VariadicMacroSupport.h:113
clang::VAOptExpansionContext::getVAOptLoc
SourceLocation getVAOptLoc() const
Definition: VariadicMacroSupport.h:229
clang::comments::tok::eof
@ eof
Definition: CommentLexer.h:33
clang::Preprocessor
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:130
clang::VAOptDefinitionContext::sawClosingParen
bool sawClosingParen()
Call this function each time an rparen is seen.
Definition: VariadicMacroSupport.h:100
clang::VAOptExpansionContext::sawVAOptFollowedByOpeningParens
void sawVAOptFollowedByOpeningParens(const SourceLocation VAOptLoc, const unsigned int NumPriorTokens)
Definition: VariadicMacroSupport.h:218