Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:58

0001 //===- VariadicMacroSupport.h - state machines and scope guards -*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 // This file defines support types to help with preprocessing variadic macro
0010 // (i.e. macros that use: ellipses __VA_ARGS__ ) definitions and
0011 // expansions.
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   /// An RAII class that tracks when the Preprocessor starts and stops lexing
0025   /// the definition of a (ISO C/C++) variadic macro.  As an example, this is
0026   /// useful for unpoisoning and repoisoning certain identifiers (such as
0027   /// __VA_ARGS__) that are only allowed in this context.  Also, being a friend
0028   /// of the Preprocessor class allows it to access PP's cached identifiers
0029   /// directly (as opposed to performing a lookup each time).
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     /// Client code should call this function just before the Preprocessor is
0046     /// about to Lex tokens from the definition of a variadic (ISO C/C++) macro.
0047     void enterScope() {
0048       Ident__VA_ARGS__->setIsPoisoned(false);
0049       Ident__VA_OPT__->setIsPoisoned(false);
0050     }
0051 
0052     /// Client code should call this function as soon as the Preprocessor has
0053     /// either completed lexing the macro's definition tokens, or an error
0054     /// occurred and the context is being exited.  This function is idempotent
0055     /// (might be explicitly called, and then reinvoked via the destructor).
0056     void exitScope() {
0057       Ident__VA_ARGS__->setIsPoisoned(true);
0058       Ident__VA_OPT__->setIsPoisoned(true);
0059     }
0060 
0061     ~VariadicMacroScopeGuard() { exitScope(); }
0062   };
0063 
0064   /// A class for tracking whether we're inside a VA_OPT during a
0065   /// traversal of the tokens of a variadic macro definition.
0066   class VAOptDefinitionContext {
0067     /// Contains all the locations of so far unmatched lparens.
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     /// Returns true if we have seen the __VA_OPT__ and '(' but before having
0082     /// seen the matching ')'.
0083     bool isInVAOpt() const { return UnmatchedOpeningParens.size(); }
0084 
0085     /// Call this function as soon as you see __VA_OPT__ and '('.
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     /// Call this function each time an rparen is seen.  It returns true only if
0098     /// the rparen that was just seen was the eventual (non-nested) closing
0099     /// paren for VAOPT, and ejects us out of the VAOPT context.
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     /// Call this function each time an lparen is seen.
0107     void sawOpeningParen(SourceLocation LParenLoc) {
0108       assert(isInVAOpt() && "Must be within VAOPT context to call this");
0109       UnmatchedOpeningParens.push_back(LParenLoc);
0110     }
0111 
0112     /// Are we at the top level within the __VA_OPT__?
0113     bool isAtTopLevel() const { return UnmatchedOpeningParens.size() == 1; }
0114   };
0115 
0116   /// A class for tracking whether we're inside a VA_OPT during a
0117   /// traversal of the tokens of a macro during macro expansion.
0118   class VAOptExpansionContext : VAOptDefinitionContext {
0119 
0120     Token SyntheticEOFToken;
0121 
0122     // The (spelling) location of the current __VA_OPT__ in the replacement list
0123     // of the function-like macro being expanded.
0124     SourceLocation VAOptLoc;
0125 
0126     // NumOfTokensPriorToVAOpt : when != -1, contains the index *of* the first
0127     // token of the current VAOPT contents (so we know where to start eager
0128     // token-pasting and stringification) *within*  the substituted tokens of
0129     // the function-like macro's new replacement list.
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 }  // end namespace clang
0247 
0248 #endif