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