Home | History | Annotate | Download | only in Parse
      1 //===--- RAIIObjectsForParser.h - RAII helpers for the parser ---*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file defines and implements the some simple RAII objects that are used
     11 // by the parser to manage bits in recursion.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #ifndef LLVM_CLANG_LIB_PARSE_RAIIOBJECTSFORPARSER_H
     16 #define LLVM_CLANG_LIB_PARSE_RAIIOBJECTSFORPARSER_H
     17 
     18 #include "clang/Parse/ParseDiagnostic.h"
     19 #include "clang/Parse/Parser.h"
     20 #include "clang/Sema/DelayedDiagnostic.h"
     21 #include "clang/Sema/Sema.h"
     22 
     23 namespace clang {
     24   // TODO: move ParsingClassDefinition here.
     25   // TODO: move TentativeParsingAction here.
     26 
     27   /// \brief A RAII object used to temporarily suppress access-like
     28   /// checking.  Access-like checks are those associated with
     29   /// controlling the use of a declaration, like C++ access control
     30   /// errors and deprecation warnings.  They are contextually
     31   /// dependent, in that they can only be resolved with full
     32   /// information about what's being declared.  They are also
     33   /// suppressed in certain contexts, like the template arguments of
     34   /// an explicit instantiation.  However, those suppression contexts
     35   /// cannot necessarily be fully determined in advance;  for
     36   /// example, something starting like this:
     37   ///   template <> class std::vector<A::PrivateType>
     38   /// might be the entirety of an explicit instantiation:
     39   ///   template <> class std::vector<A::PrivateType>;
     40   /// or just an elaborated type specifier:
     41   ///   template <> class std::vector<A::PrivateType> make_vector<>();
     42   /// Therefore this class collects all the diagnostics and permits
     43   /// them to be re-delayed in a new context.
     44   class SuppressAccessChecks {
     45     Sema &S;
     46     sema::DelayedDiagnosticPool DiagnosticPool;
     47     Sema::ParsingDeclState State;
     48     bool Active;
     49 
     50   public:
     51     /// Begin suppressing access-like checks
     52     SuppressAccessChecks(Parser &P, bool activate = true)
     53         : S(P.getActions()), DiagnosticPool(nullptr) {
     54       if (activate) {
     55         State = S.PushParsingDeclaration(DiagnosticPool);
     56         Active = true;
     57       } else {
     58         Active = false;
     59       }
     60     }
     61 
     62     void done() {
     63       assert(Active && "trying to end an inactive suppression");
     64       S.PopParsingDeclaration(State, nullptr);
     65       Active = false;
     66     }
     67 
     68     void redelay() {
     69       assert(!Active && "redelaying without having ended first");
     70       if (!DiagnosticPool.pool_empty())
     71         S.redelayDiagnostics(DiagnosticPool);
     72       assert(DiagnosticPool.pool_empty());
     73     }
     74 
     75     ~SuppressAccessChecks() {
     76       if (Active) done();
     77     }
     78   };
     79 
     80   /// \brief RAII object used to inform the actions that we're
     81   /// currently parsing a declaration.  This is active when parsing a
     82   /// variable's initializer, but not when parsing the body of a
     83   /// class or function definition.
     84   class ParsingDeclRAIIObject {
     85     Sema &Actions;
     86     sema::DelayedDiagnosticPool DiagnosticPool;
     87     Sema::ParsingDeclState State;
     88     bool Popped;
     89 
     90     ParsingDeclRAIIObject(const ParsingDeclRAIIObject &) = delete;
     91     void operator=(const ParsingDeclRAIIObject &) = delete;
     92 
     93   public:
     94     enum NoParent_t { NoParent };
     95     ParsingDeclRAIIObject(Parser &P, NoParent_t _)
     96         : Actions(P.getActions()), DiagnosticPool(nullptr) {
     97       push();
     98     }
     99 
    100     /// Creates a RAII object whose pool is optionally parented by another.
    101     ParsingDeclRAIIObject(Parser &P,
    102                           const sema::DelayedDiagnosticPool *parentPool)
    103         : Actions(P.getActions()), DiagnosticPool(parentPool) {
    104       push();
    105     }
    106 
    107     /// Creates a RAII object and, optionally, initialize its
    108     /// diagnostics pool by stealing the diagnostics from another
    109     /// RAII object (which is assumed to be the current top pool).
    110     ParsingDeclRAIIObject(Parser &P, ParsingDeclRAIIObject *other)
    111         : Actions(P.getActions()),
    112           DiagnosticPool(other ? other->DiagnosticPool.getParent() : nullptr) {
    113       if (other) {
    114         DiagnosticPool.steal(other->DiagnosticPool);
    115         other->abort();
    116       }
    117       push();
    118     }
    119 
    120     ~ParsingDeclRAIIObject() {
    121       abort();
    122     }
    123 
    124     sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() {
    125       return DiagnosticPool;
    126     }
    127     const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const {
    128       return DiagnosticPool;
    129     }
    130 
    131     /// Resets the RAII object for a new declaration.
    132     void reset() {
    133       abort();
    134       push();
    135     }
    136 
    137     /// Signals that the context was completed without an appropriate
    138     /// declaration being parsed.
    139     void abort() {
    140       pop(nullptr);
    141     }
    142 
    143     void complete(Decl *D) {
    144       assert(!Popped && "ParsingDeclaration has already been popped!");
    145       pop(D);
    146     }
    147 
    148     /// Unregister this object from Sema, but remember all the
    149     /// diagnostics that were emitted into it.
    150     void abortAndRemember() {
    151       pop(nullptr);
    152     }
    153 
    154   private:
    155     void push() {
    156       State = Actions.PushParsingDeclaration(DiagnosticPool);
    157       Popped = false;
    158     }
    159 
    160     void pop(Decl *D) {
    161       if (!Popped) {
    162         Actions.PopParsingDeclaration(State, D);
    163         Popped = true;
    164       }
    165     }
    166   };
    167 
    168   /// A class for parsing a DeclSpec.
    169   class ParsingDeclSpec : public DeclSpec {
    170     ParsingDeclRAIIObject ParsingRAII;
    171 
    172   public:
    173     ParsingDeclSpec(Parser &P)
    174       : DeclSpec(P.getAttrFactory()),
    175         ParsingRAII(P, ParsingDeclRAIIObject::NoParent) {}
    176     ParsingDeclSpec(Parser &P, ParsingDeclRAIIObject *RAII)
    177       : DeclSpec(P.getAttrFactory()),
    178         ParsingRAII(P, RAII) {}
    179 
    180     const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const {
    181       return ParsingRAII.getDelayedDiagnosticPool();
    182     }
    183 
    184     void complete(Decl *D) {
    185       ParsingRAII.complete(D);
    186     }
    187 
    188     void abort() {
    189       ParsingRAII.abort();
    190     }
    191   };
    192 
    193   /// A class for parsing a declarator.
    194   class ParsingDeclarator : public Declarator {
    195     ParsingDeclRAIIObject ParsingRAII;
    196 
    197   public:
    198     ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, TheContext C)
    199       : Declarator(DS, C), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {
    200     }
    201 
    202     const ParsingDeclSpec &getDeclSpec() const {
    203       return static_cast<const ParsingDeclSpec&>(Declarator::getDeclSpec());
    204     }
    205 
    206     ParsingDeclSpec &getMutableDeclSpec() const {
    207       return const_cast<ParsingDeclSpec&>(getDeclSpec());
    208     }
    209 
    210     void clear() {
    211       Declarator::clear();
    212       ParsingRAII.reset();
    213     }
    214 
    215     void complete(Decl *D) {
    216       ParsingRAII.complete(D);
    217     }
    218   };
    219 
    220   /// A class for parsing a field declarator.
    221   class ParsingFieldDeclarator : public FieldDeclarator {
    222     ParsingDeclRAIIObject ParsingRAII;
    223 
    224   public:
    225     ParsingFieldDeclarator(Parser &P, const ParsingDeclSpec &DS)
    226       : FieldDeclarator(DS), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {
    227     }
    228 
    229     const ParsingDeclSpec &getDeclSpec() const {
    230       return static_cast<const ParsingDeclSpec&>(D.getDeclSpec());
    231     }
    232 
    233     ParsingDeclSpec &getMutableDeclSpec() const {
    234       return const_cast<ParsingDeclSpec&>(getDeclSpec());
    235     }
    236 
    237     void complete(Decl *D) {
    238       ParsingRAII.complete(D);
    239     }
    240   };
    241 
    242   /// ExtensionRAIIObject - This saves the state of extension warnings when
    243   /// constructed and disables them.  When destructed, it restores them back to
    244   /// the way they used to be.  This is used to handle __extension__ in the
    245   /// parser.
    246   class ExtensionRAIIObject {
    247     ExtensionRAIIObject(const ExtensionRAIIObject &) = delete;
    248     void operator=(const ExtensionRAIIObject &) = delete;
    249 
    250     DiagnosticsEngine &Diags;
    251   public:
    252     ExtensionRAIIObject(DiagnosticsEngine &diags) : Diags(diags) {
    253       Diags.IncrementAllExtensionsSilenced();
    254     }
    255 
    256     ~ExtensionRAIIObject() {
    257       Diags.DecrementAllExtensionsSilenced();
    258     }
    259   };
    260 
    261   /// ColonProtectionRAIIObject - This sets the Parser::ColonIsSacred bool and
    262   /// restores it when destroyed.  This says that "foo:" should not be
    263   /// considered a possible typo for "foo::" for error recovery purposes.
    264   class ColonProtectionRAIIObject {
    265     Parser &P;
    266     bool OldVal;
    267   public:
    268     ColonProtectionRAIIObject(Parser &p, bool Value = true)
    269       : P(p), OldVal(P.ColonIsSacred) {
    270       P.ColonIsSacred = Value;
    271     }
    272 
    273     /// restore - This can be used to restore the state early, before the dtor
    274     /// is run.
    275     void restore() {
    276       P.ColonIsSacred = OldVal;
    277     }
    278 
    279     ~ColonProtectionRAIIObject() {
    280       restore();
    281     }
    282   };
    283 
    284   /// \brief RAII object that makes '>' behave either as an operator
    285   /// or as the closing angle bracket for a template argument list.
    286   class GreaterThanIsOperatorScope {
    287     bool &GreaterThanIsOperator;
    288     bool OldGreaterThanIsOperator;
    289   public:
    290     GreaterThanIsOperatorScope(bool &GTIO, bool Val)
    291     : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) {
    292       GreaterThanIsOperator = Val;
    293     }
    294 
    295     ~GreaterThanIsOperatorScope() {
    296       GreaterThanIsOperator = OldGreaterThanIsOperator;
    297     }
    298   };
    299 
    300   class InMessageExpressionRAIIObject {
    301     bool &InMessageExpression;
    302     bool OldValue;
    303 
    304   public:
    305     InMessageExpressionRAIIObject(Parser &P, bool Value)
    306       : InMessageExpression(P.InMessageExpression),
    307         OldValue(P.InMessageExpression) {
    308       InMessageExpression = Value;
    309     }
    310 
    311     ~InMessageExpressionRAIIObject() {
    312       InMessageExpression = OldValue;
    313     }
    314   };
    315 
    316   /// \brief RAII object that makes sure paren/bracket/brace count is correct
    317   /// after declaration/statement parsing, even when there's a parsing error.
    318   class ParenBraceBracketBalancer {
    319     Parser &P;
    320     unsigned short ParenCount, BracketCount, BraceCount;
    321   public:
    322     ParenBraceBracketBalancer(Parser &p)
    323       : P(p), ParenCount(p.ParenCount), BracketCount(p.BracketCount),
    324         BraceCount(p.BraceCount) { }
    325 
    326     ~ParenBraceBracketBalancer() {
    327       P.ParenCount = ParenCount;
    328       P.BracketCount = BracketCount;
    329       P.BraceCount = BraceCount;
    330     }
    331   };
    332 
    333   class PoisonSEHIdentifiersRAIIObject {
    334     PoisonIdentifierRAIIObject Ident_AbnormalTermination;
    335     PoisonIdentifierRAIIObject Ident_GetExceptionCode;
    336     PoisonIdentifierRAIIObject Ident_GetExceptionInfo;
    337     PoisonIdentifierRAIIObject Ident__abnormal_termination;
    338     PoisonIdentifierRAIIObject Ident__exception_code;
    339     PoisonIdentifierRAIIObject Ident__exception_info;
    340     PoisonIdentifierRAIIObject Ident___abnormal_termination;
    341     PoisonIdentifierRAIIObject Ident___exception_code;
    342     PoisonIdentifierRAIIObject Ident___exception_info;
    343   public:
    344     PoisonSEHIdentifiersRAIIObject(Parser &Self, bool NewValue)
    345       : Ident_AbnormalTermination(Self.Ident_AbnormalTermination, NewValue),
    346         Ident_GetExceptionCode(Self.Ident_GetExceptionCode, NewValue),
    347         Ident_GetExceptionInfo(Self.Ident_GetExceptionInfo, NewValue),
    348         Ident__abnormal_termination(Self.Ident__abnormal_termination, NewValue),
    349         Ident__exception_code(Self.Ident__exception_code, NewValue),
    350         Ident__exception_info(Self.Ident__exception_info, NewValue),
    351         Ident___abnormal_termination(Self.Ident___abnormal_termination, NewValue),
    352         Ident___exception_code(Self.Ident___exception_code, NewValue),
    353         Ident___exception_info(Self.Ident___exception_info, NewValue) {
    354     }
    355   };
    356 
    357   /// \brief RAII class that helps handle the parsing of an open/close delimiter
    358   /// pair, such as braces { ... } or parentheses ( ... ).
    359   class BalancedDelimiterTracker : public GreaterThanIsOperatorScope {
    360     Parser& P;
    361     tok::TokenKind Kind, Close, FinalToken;
    362     SourceLocation (Parser::*Consumer)();
    363     SourceLocation LOpen, LClose;
    364 
    365     unsigned short &getDepth() {
    366       switch (Kind) {
    367         case tok::l_brace: return P.BraceCount;
    368         case tok::l_square: return P.BracketCount;
    369         case tok::l_paren: return P.ParenCount;
    370         default: llvm_unreachable("Wrong token kind");
    371       }
    372     }
    373 
    374     enum { MaxDepth = 256 };
    375 
    376     bool diagnoseOverflow();
    377     bool diagnoseMissingClose();
    378 
    379   public:
    380     BalancedDelimiterTracker(Parser& p, tok::TokenKind k,
    381                              tok::TokenKind FinalToken = tok::semi)
    382       : GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true),
    383         P(p), Kind(k), FinalToken(FinalToken)
    384     {
    385       switch (Kind) {
    386         default: llvm_unreachable("Unexpected balanced token");
    387         case tok::l_brace:
    388           Close = tok::r_brace;
    389           Consumer = &Parser::ConsumeBrace;
    390           break;
    391         case tok::l_paren:
    392           Close = tok::r_paren;
    393           Consumer = &Parser::ConsumeParen;
    394           break;
    395 
    396         case tok::l_square:
    397           Close = tok::r_square;
    398           Consumer = &Parser::ConsumeBracket;
    399           break;
    400       }
    401     }
    402 
    403     SourceLocation getOpenLocation() const { return LOpen; }
    404     SourceLocation getCloseLocation() const { return LClose; }
    405     SourceRange getRange() const { return SourceRange(LOpen, LClose); }
    406 
    407     bool consumeOpen() {
    408       if (!P.Tok.is(Kind))
    409         return true;
    410 
    411       if (getDepth() < P.getLangOpts().BracketDepth) {
    412         LOpen = (P.*Consumer)();
    413         return false;
    414       }
    415 
    416       return diagnoseOverflow();
    417     }
    418 
    419     bool expectAndConsume(unsigned DiagID = diag::err_expected,
    420                           const char *Msg = "",
    421                           tok::TokenKind SkipToTok = tok::unknown);
    422     bool consumeClose() {
    423       if (P.Tok.is(Close)) {
    424         LClose = (P.*Consumer)();
    425         return false;
    426       }
    427 
    428       return diagnoseMissingClose();
    429     }
    430     void skipToEnd();
    431   };
    432 
    433 } // end namespace clang
    434 
    435 #endif
    436