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
19#include "llvm/ADT/SmallVector.h"
20
21namespace 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.
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
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:22