File indexing completed on 2026-05-10 08:36:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef LLVM_CLANG_LEX_VARIADICMACROSUPPORT_H
0016 #define LLVM_CLANG_LEX_VARIADICMACROSUPPORT_H
0017
0018 #include "clang/Lex/Preprocessor.h"
0019 #include "llvm/ADT/SmallVector.h"
0020
0021 namespace clang {
0022 class Preprocessor;
0023
0024
0025
0026
0027
0028
0029
0030 class VariadicMacroScopeGuard {
0031 const Preprocessor &PP;
0032 IdentifierInfo *const Ident__VA_ARGS__;
0033 IdentifierInfo *const Ident__VA_OPT__;
0034
0035 public:
0036 VariadicMacroScopeGuard(const Preprocessor &P)
0037 : PP(P), Ident__VA_ARGS__(PP.Ident__VA_ARGS__),
0038 Ident__VA_OPT__(PP.Ident__VA_OPT__) {
0039 assert(Ident__VA_ARGS__->isPoisoned() && "__VA_ARGS__ should be poisoned "
0040 "outside an ISO C/C++ variadic "
0041 "macro definition!");
0042 assert(Ident__VA_OPT__->isPoisoned() && "__VA_OPT__ should be poisoned!");
0043 }
0044
0045
0046
0047 void enterScope() {
0048 Ident__VA_ARGS__->setIsPoisoned(false);
0049 Ident__VA_OPT__->setIsPoisoned(false);
0050 }
0051
0052
0053
0054
0055
0056 void exitScope() {
0057 Ident__VA_ARGS__->setIsPoisoned(true);
0058 Ident__VA_OPT__->setIsPoisoned(true);
0059 }
0060
0061 ~VariadicMacroScopeGuard() { exitScope(); }
0062 };
0063
0064
0065
0066 class VAOptDefinitionContext {
0067
0068 SmallVector<SourceLocation, 8> UnmatchedOpeningParens;
0069
0070 const IdentifierInfo *const Ident__VA_OPT__;
0071
0072
0073 public:
0074 VAOptDefinitionContext(Preprocessor &PP)
0075 : Ident__VA_OPT__(PP.Ident__VA_OPT__) {}
0076
0077 bool isVAOptToken(const Token &T) const {
0078 return Ident__VA_OPT__ && T.getIdentifierInfo() == Ident__VA_OPT__;
0079 }
0080
0081
0082
0083 bool isInVAOpt() const { return UnmatchedOpeningParens.size(); }
0084
0085
0086 void sawVAOptFollowedByOpeningParens(const SourceLocation LParenLoc) {
0087 assert(!isInVAOpt() && "Must NOT be within VAOPT context to call this");
0088 UnmatchedOpeningParens.push_back(LParenLoc);
0089
0090 }
0091
0092 SourceLocation getUnmatchedOpeningParenLoc() const {
0093 assert(isInVAOpt() && "Must be within VAOPT context to call this");
0094 return UnmatchedOpeningParens.back();
0095 }
0096
0097
0098
0099
0100 bool sawClosingParen() {
0101 assert(isInVAOpt() && "Must be within VAOPT context to call this");
0102 UnmatchedOpeningParens.pop_back();
0103 return !UnmatchedOpeningParens.size();
0104 }
0105
0106
0107 void sawOpeningParen(SourceLocation LParenLoc) {
0108 assert(isInVAOpt() && "Must be within VAOPT context to call this");
0109 UnmatchedOpeningParens.push_back(LParenLoc);
0110 }
0111
0112
0113 bool isAtTopLevel() const { return UnmatchedOpeningParens.size() == 1; }
0114 };
0115
0116
0117
0118 class VAOptExpansionContext : VAOptDefinitionContext {
0119
0120 Token SyntheticEOFToken;
0121
0122
0123
0124 SourceLocation VAOptLoc;
0125
0126
0127
0128
0129
0130 int NumOfTokensPriorToVAOpt = -1;
0131
0132 LLVM_PREFERRED_TYPE(bool)
0133 unsigned LeadingSpaceForStringifiedToken : 1;
0134
0135 LLVM_PREFERRED_TYPE(bool)
0136 unsigned StringifyBefore : 1;
0137 LLVM_PREFERRED_TYPE(bool)
0138 unsigned CharifyBefore : 1;
0139 LLVM_PREFERRED_TYPE(bool)
0140 unsigned BeginsWithPlaceholder : 1;
0141 LLVM_PREFERRED_TYPE(bool)
0142 unsigned EndsWithPlaceholder : 1;
0143
0144 bool hasStringifyBefore() const {
0145 assert(!isReset() &&
0146 "Must only be called if the state has not been reset");
0147 return StringifyBefore;
0148 }
0149
0150 bool isReset() const {
0151 return NumOfTokensPriorToVAOpt == -1 ||
0152 VAOptLoc.isInvalid();
0153 }
0154
0155 public:
0156 VAOptExpansionContext(Preprocessor &PP)
0157 : VAOptDefinitionContext(PP), LeadingSpaceForStringifiedToken(false),
0158 StringifyBefore(false), CharifyBefore(false),
0159 BeginsWithPlaceholder(false), EndsWithPlaceholder(false) {
0160 SyntheticEOFToken.startToken();
0161 SyntheticEOFToken.setKind(tok::eof);
0162 }
0163
0164 void reset() {
0165 VAOptLoc = SourceLocation();
0166 NumOfTokensPriorToVAOpt = -1;
0167 LeadingSpaceForStringifiedToken = false;
0168 StringifyBefore = false;
0169 CharifyBefore = false;
0170 BeginsWithPlaceholder = false;
0171 EndsWithPlaceholder = false;
0172 }
0173
0174 const Token &getEOFTok() const { return SyntheticEOFToken; }
0175
0176 void sawHashOrHashAtBefore(const bool HasLeadingSpace,
0177 const bool IsHashAt) {
0178
0179 StringifyBefore = !IsHashAt;
0180 CharifyBefore = IsHashAt;
0181 LeadingSpaceForStringifiedToken = HasLeadingSpace;
0182 }
0183
0184 void hasPlaceholderAfterHashhashAtStart() { BeginsWithPlaceholder = true; }
0185 void hasPlaceholderBeforeRParen() {
0186 if (isAtTopLevel())
0187 EndsWithPlaceholder = true;
0188 }
0189
0190
0191 bool beginsWithPlaceholder() const {
0192 assert(!isReset() &&
0193 "Must only be called if the state has not been reset");
0194 return BeginsWithPlaceholder;
0195 }
0196 bool endsWithPlaceholder() const {
0197 assert(!isReset() &&
0198 "Must only be called if the state has not been reset");
0199 return EndsWithPlaceholder;
0200 }
0201
0202 bool hasCharifyBefore() const {
0203 assert(!isReset() &&
0204 "Must only be called if the state has not been reset");
0205 return CharifyBefore;
0206 }
0207 bool hasStringifyOrCharifyBefore() const {
0208 return hasStringifyBefore() || hasCharifyBefore();
0209 }
0210
0211 unsigned int getNumberOfTokensPriorToVAOpt() const {
0212 assert(!isReset() &&
0213 "Must only be called if the state has not been reset");
0214 return NumOfTokensPriorToVAOpt;
0215 }
0216
0217 bool getLeadingSpaceForStringifiedToken() const {
0218 assert(hasStringifyBefore() &&
0219 "Must only be called if this has been marked for stringification");
0220 return LeadingSpaceForStringifiedToken;
0221 }
0222
0223 void sawVAOptFollowedByOpeningParens(const SourceLocation VAOptLoc,
0224 const unsigned int NumPriorTokens) {
0225 assert(VAOptLoc.isFileID() && "Must not come from a macro expansion");
0226 assert(isReset() && "Must only be called if the state has been reset");
0227 VAOptDefinitionContext::sawVAOptFollowedByOpeningParens(SourceLocation());
0228 this->VAOptLoc = VAOptLoc;
0229 NumOfTokensPriorToVAOpt = NumPriorTokens;
0230 assert(NumOfTokensPriorToVAOpt > -1 &&
0231 "Too many prior tokens");
0232 }
0233
0234 SourceLocation getVAOptLoc() const {
0235 assert(!isReset() &&
0236 "Must only be called if the state has not been reset");
0237 assert(VAOptLoc.isValid() && "__VA_OPT__ location must be valid");
0238 return VAOptLoc;
0239 }
0240 using VAOptDefinitionContext::isVAOptToken;
0241 using VAOptDefinitionContext::isInVAOpt;
0242 using VAOptDefinitionContext::sawClosingParen;
0243 using VAOptDefinitionContext::sawOpeningParen;
0244
0245 };
0246 }
0247
0248 #endif