clang  19.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  LLVM_PREFERRED_TYPE(bool)
133  unsigned LeadingSpaceForStringifiedToken : 1;
134 
135  LLVM_PREFERRED_TYPE(bool)
136  unsigned StringifyBefore : 1;
137  LLVM_PREFERRED_TYPE(bool)
138  unsigned CharifyBefore : 1;
139  LLVM_PREFERRED_TYPE(bool)
140  unsigned BeginsWithPlaceholder : 1;
141  LLVM_PREFERRED_TYPE(bool)
142  unsigned EndsWithPlaceholder : 1;
143 
144  bool hasStringifyBefore() const {
145  assert(!isReset() &&
146  "Must only be called if the state has not been reset");
147  return StringifyBefore;
148  }
149 
150  bool isReset() const {
151  return NumOfTokensPriorToVAOpt == -1 ||
152  VAOptLoc.isInvalid();
153  }
154 
155  public:
157  : VAOptDefinitionContext(PP), LeadingSpaceForStringifiedToken(false),
158  StringifyBefore(false), CharifyBefore(false),
159  BeginsWithPlaceholder(false), EndsWithPlaceholder(false) {
160  SyntheticEOFToken.startToken();
161  SyntheticEOFToken.setKind(tok::eof);
162  }
163 
164  void reset() {
165  VAOptLoc = SourceLocation();
166  NumOfTokensPriorToVAOpt = -1;
167  LeadingSpaceForStringifiedToken = false;
168  StringifyBefore = false;
169  CharifyBefore = false;
170  BeginsWithPlaceholder = false;
171  EndsWithPlaceholder = false;
172  }
173 
174  const Token &getEOFTok() const { return SyntheticEOFToken; }
175 
176  void sawHashOrHashAtBefore(const bool HasLeadingSpace,
177  const bool IsHashAt) {
178 
179  StringifyBefore = !IsHashAt;
180  CharifyBefore = IsHashAt;
181  LeadingSpaceForStringifiedToken = HasLeadingSpace;
182  }
183 
184  void hasPlaceholderAfterHashhashAtStart() { BeginsWithPlaceholder = true; }
186  if (isAtTopLevel())
187  EndsWithPlaceholder = true;
188  }
189 
190 
191  bool beginsWithPlaceholder() const {
192  assert(!isReset() &&
193  "Must only be called if the state has not been reset");
194  return BeginsWithPlaceholder;
195  }
196  bool endsWithPlaceholder() const {
197  assert(!isReset() &&
198  "Must only be called if the state has not been reset");
199  return EndsWithPlaceholder;
200  }
201 
202  bool hasCharifyBefore() const {
203  assert(!isReset() &&
204  "Must only be called if the state has not been reset");
205  return CharifyBefore;
206  }
208  return hasStringifyBefore() || hasCharifyBefore();
209  }
210 
211  unsigned int getNumberOfTokensPriorToVAOpt() const {
212  assert(!isReset() &&
213  "Must only be called if the state has not been reset");
214  return NumOfTokensPriorToVAOpt;
215  }
216 
218  assert(hasStringifyBefore() &&
219  "Must only be called if this has been marked for stringification");
220  return LeadingSpaceForStringifiedToken;
221  }
222 
224  const unsigned int NumPriorTokens) {
225  assert(VAOptLoc.isFileID() && "Must not come from a macro expansion");
226  assert(isReset() && "Must only be called if the state has been reset");
228  this->VAOptLoc = VAOptLoc;
229  NumOfTokensPriorToVAOpt = NumPriorTokens;
230  assert(NumOfTokensPriorToVAOpt > -1 &&
231  "Too many prior tokens");
232  }
233 
235  assert(!isReset() &&
236  "Must only be called if the state has not been reset");
237  assert(VAOptLoc.isValid() && "__VA_OPT__ location must be valid");
238  return VAOptLoc;
239  }
244 
245  };
246 } // end namespace clang
247 
248 #endif
StringRef P
Defines the clang::Preprocessor interface.
One of these records is kept for each identifier that is lexed.
void setIsPoisoned(bool Value=true)
setIsPoisoned - Mark this identifier as poisoned.
bool isPoisoned() const
Return true if this token has been poisoned.
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
Definition: Preprocessor.h:128
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
Token - This structure provides full information about a lexed token.
Definition: Token.h:36
void setKind(tok::TokenKind K)
Definition: Token.h:95
void startToken()
Reset all flags to cleared.
Definition: Token.h:177
A class for tracking whether we're inside a VA_OPT during a traversal of the tokens of a variadic mac...
VAOptDefinitionContext(Preprocessor &PP)
SourceLocation getUnmatchedOpeningParenLoc() const
bool isInVAOpt() const
Returns true if we have seen the VA_OPT and '(' but before having seen the matching ')'.
bool isVAOptToken(const Token &T) const
void sawOpeningParen(SourceLocation LParenLoc)
Call this function each time an lparen is seen.
bool isAtTopLevel() const
Are we at the top level within the VA_OPT?
bool sawClosingParen()
Call this function each time an rparen is seen.
void sawVAOptFollowedByOpeningParens(const SourceLocation LParenLoc)
Call this function as soon as you see VA_OPT and '('.
A class for tracking whether we're inside a VA_OPT during a traversal of the tokens of a macro during...
void sawHashOrHashAtBefore(const bool HasLeadingSpace, const bool IsHashAt)
SourceLocation getVAOptLoc() const
unsigned int getNumberOfTokensPriorToVAOpt() const
void sawVAOptFollowedByOpeningParens(const SourceLocation VAOptLoc, const unsigned int NumPriorTokens)
An RAII class that tracks when the Preprocessor starts and stops lexing the definition of a (ISO C/C+...
void exitScope()
Client code should call this function as soon as the Preprocessor has either completed lexing the mac...
void enterScope()
Client code should call this function just before the Preprocessor is about to Lex tokens from the de...
VariadicMacroScopeGuard(const Preprocessor &P)
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
#define false
Definition: stdbool.h:26