Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  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).
  30.   class VariadicMacroScopeGuard {
  31.     const Preprocessor &PP;
  32.     IdentifierInfo *const Ident__VA_ARGS__;
  33.     IdentifierInfo *const Ident__VA_OPT__;
  34.  
  35.   public:
  36.     VariadicMacroScopeGuard(const Preprocessor &P)
  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.  
  61.     ~VariadicMacroScopeGuard() { exitScope(); }
  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.
  66.   class VAOptDefinitionContext {
  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:
  74.     VAOptDefinitionContext(Preprocessor &PP)
  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 '('.
  86.     void sawVAOptFollowedByOpeningParens(const SourceLocation LParenLoc) {
  87.       assert(!isInVAOpt() && "Must NOT be within VAOPT context to call this");
  88.       UnmatchedOpeningParens.push_back(LParenLoc);
  89.  
  90.     }
  91.  
  92.     SourceLocation getUnmatchedOpeningParenLoc() const {
  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.
  100.     bool sawClosingParen() {
  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.
  118.   class VAOptExpansionContext : VAOptDefinitionContext {
  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:
  151.     VAOptExpansionContext(Preprocessor &PP)
  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; }
  180.     void hasPlaceholderBeforeRParen() {
  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.     }
  202.     bool hasStringifyOrCharifyBefore() const {
  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.  
  212.     bool getLeadingSpaceForStringifiedToken() const {
  213.       assert(hasStringifyBefore() &&
  214.              "Must only be called if this has been marked for stringification");
  215.       return LeadingSpaceForStringifiedToken;
  216.     }
  217.  
  218.     void sawVAOptFollowedByOpeningParens(const SourceLocation VAOptLoc,
  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");
  222.       VAOptDefinitionContext::sawVAOptFollowedByOpeningParens(SourceLocation());
  223.       this->VAOptLoc = VAOptLoc;
  224.       NumOfTokensPriorToVAOpt = NumPriorTokens;
  225.       assert(NumOfTokensPriorToVAOpt > -1 &&
  226.              "Too many prior tokens");
  227.     }
  228.  
  229.     SourceLocation getVAOptLoc() const {
  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.     }
  235.     using VAOptDefinitionContext::isVAOptToken;
  236.     using VAOptDefinitionContext::isInVAOpt;
  237.     using VAOptDefinitionContext::sawClosingParen;
  238.     using VAOptDefinitionContext::sawOpeningParen;
  239.  
  240.   };
  241. }  // end namespace clang
  242.  
  243. #endif
  244.