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