Home | History | Annotate | Line # | Download | only in Parse
      1 //===--- RAIIObjectsForParser.h - RAII helpers for the parser ---*- 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 and implements the some simple RAII objects that are used
     10 // by the parser to manage bits in recursion.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #ifndef LLVM_CLANG_LIB_PARSE_RAIIOBJECTSFORPARSER_H
     15 #define LLVM_CLANG_LIB_PARSE_RAIIOBJECTSFORPARSER_H
     16 
     17 #include "clang/Parse/ParseDiagnostic.h"
     18 #include "clang/Parse/Parser.h"
     19 #include "clang/Sema/DelayedDiagnostic.h"
     20 #include "clang/Sema/ParsedTemplate.h"
     21 #include "clang/Sema/Sema.h"
     22 
     23 namespace clang {
     24   // TODO: move ParsingClassDefinition here.
     25   // TODO: move TentativeParsingAction here.
     26 
     27   /// 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   /// 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, DeclaratorContext 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   /// Activates OpenMP parsing mode to preseve OpenMP specific annotation
    291   /// tokens.
    292   class ParsingOpenMPDirectiveRAII {
    293     Parser &P;
    294     bool OldVal;
    295 
    296   public:
    297     ParsingOpenMPDirectiveRAII(Parser &P, bool Value = true)
    298         : P(P), OldVal(P.OpenMPDirectiveParsing) {
    299       P.OpenMPDirectiveParsing = Value;
    300     }
    301 
    302     /// This can be used to restore the state early, before the dtor
    303     /// is run.
    304     void restore() { P.OpenMPDirectiveParsing = OldVal; }
    305 
    306     ~ParsingOpenMPDirectiveRAII() { restore(); }
    307   };
    308 
    309   /// RAII object that makes '>' behave either as an operator
    310   /// or as the closing angle bracket for a template argument list.
    311   class GreaterThanIsOperatorScope {
    312     bool &GreaterThanIsOperator;
    313     bool OldGreaterThanIsOperator;
    314   public:
    315     GreaterThanIsOperatorScope(bool &GTIO, bool Val)
    316     : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) {
    317       GreaterThanIsOperator = Val;
    318     }
    319 
    320     ~GreaterThanIsOperatorScope() {
    321       GreaterThanIsOperator = OldGreaterThanIsOperator;
    322     }
    323   };
    324 
    325   class InMessageExpressionRAIIObject {
    326     bool &InMessageExpression;
    327     bool OldValue;
    328 
    329   public:
    330     InMessageExpressionRAIIObject(Parser &P, bool Value)
    331       : InMessageExpression(P.InMessageExpression),
    332         OldValue(P.InMessageExpression) {
    333       InMessageExpression = Value;
    334     }
    335 
    336     ~InMessageExpressionRAIIObject() {
    337       InMessageExpression = OldValue;
    338     }
    339   };
    340 
    341   /// RAII object that makes sure paren/bracket/brace count is correct
    342   /// after declaration/statement parsing, even when there's a parsing error.
    343   class ParenBraceBracketBalancer {
    344     Parser &P;
    345     unsigned short ParenCount, BracketCount, BraceCount;
    346   public:
    347     ParenBraceBracketBalancer(Parser &p)
    348       : P(p), ParenCount(p.ParenCount), BracketCount(p.BracketCount),
    349         BraceCount(p.BraceCount) { }
    350 
    351     ~ParenBraceBracketBalancer() {
    352       P.AngleBrackets.clear(P);
    353       P.ParenCount = ParenCount;
    354       P.BracketCount = BracketCount;
    355       P.BraceCount = BraceCount;
    356     }
    357   };
    358 
    359   class PoisonSEHIdentifiersRAIIObject {
    360     PoisonIdentifierRAIIObject Ident_AbnormalTermination;
    361     PoisonIdentifierRAIIObject Ident_GetExceptionCode;
    362     PoisonIdentifierRAIIObject Ident_GetExceptionInfo;
    363     PoisonIdentifierRAIIObject Ident__abnormal_termination;
    364     PoisonIdentifierRAIIObject Ident__exception_code;
    365     PoisonIdentifierRAIIObject Ident__exception_info;
    366     PoisonIdentifierRAIIObject Ident___abnormal_termination;
    367     PoisonIdentifierRAIIObject Ident___exception_code;
    368     PoisonIdentifierRAIIObject Ident___exception_info;
    369   public:
    370     PoisonSEHIdentifiersRAIIObject(Parser &Self, bool NewValue)
    371       : Ident_AbnormalTermination(Self.Ident_AbnormalTermination, NewValue),
    372         Ident_GetExceptionCode(Self.Ident_GetExceptionCode, NewValue),
    373         Ident_GetExceptionInfo(Self.Ident_GetExceptionInfo, NewValue),
    374         Ident__abnormal_termination(Self.Ident__abnormal_termination, NewValue),
    375         Ident__exception_code(Self.Ident__exception_code, NewValue),
    376         Ident__exception_info(Self.Ident__exception_info, NewValue),
    377         Ident___abnormal_termination(Self.Ident___abnormal_termination, NewValue),
    378         Ident___exception_code(Self.Ident___exception_code, NewValue),
    379         Ident___exception_info(Self.Ident___exception_info, NewValue) {
    380     }
    381   };
    382 
    383   /// RAII class that helps handle the parsing of an open/close delimiter
    384   /// pair, such as braces { ... } or parentheses ( ... ).
    385   class BalancedDelimiterTracker : public GreaterThanIsOperatorScope {
    386     Parser& P;
    387     tok::TokenKind Kind, Close, FinalToken;
    388     SourceLocation (Parser::*Consumer)();
    389     SourceLocation LOpen, LClose;
    390 
    391     unsigned short &getDepth() {
    392       switch (Kind) {
    393         case tok::l_brace: return P.BraceCount;
    394         case tok::l_square: return P.BracketCount;
    395         case tok::l_paren: return P.ParenCount;
    396         default: llvm_unreachable("Wrong token kind");
    397       }
    398     }
    399 
    400     bool diagnoseOverflow();
    401     bool diagnoseMissingClose();
    402 
    403   public:
    404     BalancedDelimiterTracker(Parser& p, tok::TokenKind k,
    405                              tok::TokenKind FinalToken = tok::semi)
    406       : GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true),
    407         P(p), Kind(k), FinalToken(FinalToken)
    408     {
    409       switch (Kind) {
    410         default: llvm_unreachable("Unexpected balanced token");
    411         case tok::l_brace:
    412           Close = tok::r_brace;
    413           Consumer = &Parser::ConsumeBrace;
    414           break;
    415         case tok::l_paren:
    416           Close = tok::r_paren;
    417           Consumer = &Parser::ConsumeParen;
    418           break;
    419 
    420         case tok::l_square:
    421           Close = tok::r_square;
    422           Consumer = &Parser::ConsumeBracket;
    423           break;
    424       }
    425     }
    426 
    427     SourceLocation getOpenLocation() const { return LOpen; }
    428     SourceLocation getCloseLocation() const { return LClose; }
    429     SourceRange getRange() const { return SourceRange(LOpen, LClose); }
    430 
    431     bool consumeOpen() {
    432       if (!P.Tok.is(Kind))
    433         return true;
    434 
    435       if (getDepth() < P.getLangOpts().BracketDepth) {
    436         LOpen = (P.*Consumer)();
    437         return false;
    438       }
    439 
    440       return diagnoseOverflow();
    441     }
    442 
    443     bool expectAndConsume(unsigned DiagID = diag::err_expected,
    444                           const char *Msg = "",
    445                           tok::TokenKind SkipToTok = tok::unknown);
    446     bool consumeClose() {
    447       if (P.Tok.is(Close)) {
    448         LClose = (P.*Consumer)();
    449         return false;
    450       } else if (P.Tok.is(tok::semi) && P.NextToken().is(Close)) {
    451         SourceLocation SemiLoc = P.ConsumeToken();
    452         P.Diag(SemiLoc, diag::err_unexpected_semi)
    453             << Close << FixItHint::CreateRemoval(SourceRange(SemiLoc, SemiLoc));
    454         LClose = (P.*Consumer)();
    455         return false;
    456       }
    457 
    458       return diagnoseMissingClose();
    459     }
    460     void skipToEnd();
    461   };
    462 } // end namespace clang
    463 
    464 #endif
    465