1200583Srdivacky//===--- RAIIObjectsForParser.h - RAII helpers for the parser ---*- C++ -*-===// 2200583Srdivacky// 3200583Srdivacky// The LLVM Compiler Infrastructure 4200583Srdivacky// 5200583Srdivacky// This file is distributed under the University of Illinois Open Source 6200583Srdivacky// License. See LICENSE.TXT for details. 7200583Srdivacky// 8200583Srdivacky//===----------------------------------------------------------------------===// 9200583Srdivacky// 10200583Srdivacky// This file defines and implements the some simple RAII objects that are used 11200583Srdivacky// by the parser to manage bits in recursion. 12200583Srdivacky// 13200583Srdivacky//===----------------------------------------------------------------------===// 14200583Srdivacky 15280031Sdim#ifndef LLVM_CLANG_LIB_PARSE_RAIIOBJECTSFORPARSER_H 16280031Sdim#define LLVM_CLANG_LIB_PARSE_RAIIOBJECTSFORPARSER_H 17200583Srdivacky 18200583Srdivacky#include "clang/Parse/ParseDiagnostic.h" 19239462Sdim#include "clang/Parse/Parser.h" 20239462Sdim#include "clang/Sema/DelayedDiagnostic.h" 21239462Sdim#include "clang/Sema/Sema.h" 22200583Srdivacky 23200583Srdivackynamespace clang { 24200583Srdivacky // TODO: move ParsingClassDefinition here. 25200583Srdivacky // TODO: move TentativeParsingAction here. 26239462Sdim 27239462Sdim /// \brief A RAII object used to temporarily suppress access-like 28239462Sdim /// checking. Access-like checks are those associated with 29239462Sdim /// controlling the use of a declaration, like C++ access control 30239462Sdim /// errors and deprecation warnings. They are contextually 31239462Sdim /// dependent, in that they can only be resolved with full 32239462Sdim /// information about what's being declared. They are also 33239462Sdim /// suppressed in certain contexts, like the template arguments of 34239462Sdim /// an explicit instantiation. However, those suppression contexts 35239462Sdim /// cannot necessarily be fully determined in advance; for 36239462Sdim /// example, something starting like this: 37239462Sdim /// template <> class std::vector<A::PrivateType> 38239462Sdim /// might be the entirety of an explicit instantiation: 39239462Sdim /// template <> class std::vector<A::PrivateType>; 40239462Sdim /// or just an elaborated type specifier: 41239462Sdim /// template <> class std::vector<A::PrivateType> make_vector<>(); 42239462Sdim /// Therefore this class collects all the diagnostics and permits 43239462Sdim /// them to be re-delayed in a new context. 44239462Sdim class SuppressAccessChecks { 45239462Sdim Sema &S; 46239462Sdim sema::DelayedDiagnosticPool DiagnosticPool; 47239462Sdim Sema::ParsingDeclState State; 48239462Sdim bool Active; 49239462Sdim 50239462Sdim public: 51239462Sdim /// Begin suppressing access-like checks 52239462Sdim SuppressAccessChecks(Parser &P, bool activate = true) 53276479Sdim : S(P.getActions()), DiagnosticPool(nullptr) { 54239462Sdim if (activate) { 55239462Sdim State = S.PushParsingDeclaration(DiagnosticPool); 56239462Sdim Active = true; 57239462Sdim } else { 58239462Sdim Active = false; 59239462Sdim } 60239462Sdim } 61288943Sdim SuppressAccessChecks(SuppressAccessChecks &&Other) 62288943Sdim : S(Other.S), DiagnosticPool(std::move(Other.DiagnosticPool)), 63288943Sdim State(Other.State), Active(Other.Active) { 64288943Sdim Other.Active = false; 65288943Sdim } 66288943Sdim void operator=(SuppressAccessChecks &&Other) = delete; 67239462Sdim 68239462Sdim void done() { 69239462Sdim assert(Active && "trying to end an inactive suppression"); 70276479Sdim S.PopParsingDeclaration(State, nullptr); 71239462Sdim Active = false; 72239462Sdim } 73239462Sdim 74239462Sdim void redelay() { 75239462Sdim assert(!Active && "redelaying without having ended first"); 76239462Sdim if (!DiagnosticPool.pool_empty()) 77239462Sdim S.redelayDiagnostics(DiagnosticPool); 78239462Sdim assert(DiagnosticPool.pool_empty()); 79239462Sdim } 80239462Sdim 81239462Sdim ~SuppressAccessChecks() { 82239462Sdim if (Active) done(); 83239462Sdim } 84239462Sdim }; 85239462Sdim 86239462Sdim /// \brief RAII object used to inform the actions that we're 87239462Sdim /// currently parsing a declaration. This is active when parsing a 88239462Sdim /// variable's initializer, but not when parsing the body of a 89239462Sdim /// class or function definition. 90239462Sdim class ParsingDeclRAIIObject { 91239462Sdim Sema &Actions; 92239462Sdim sema::DelayedDiagnosticPool DiagnosticPool; 93239462Sdim Sema::ParsingDeclState State; 94239462Sdim bool Popped; 95239462Sdim 96288943Sdim ParsingDeclRAIIObject(const ParsingDeclRAIIObject &) = delete; 97288943Sdim void operator=(const ParsingDeclRAIIObject &) = delete; 98239462Sdim 99239462Sdim public: 100239462Sdim enum NoParent_t { NoParent }; 101239462Sdim ParsingDeclRAIIObject(Parser &P, NoParent_t _) 102276479Sdim : Actions(P.getActions()), DiagnosticPool(nullptr) { 103239462Sdim push(); 104239462Sdim } 105239462Sdim 106239462Sdim /// Creates a RAII object whose pool is optionally parented by another. 107239462Sdim ParsingDeclRAIIObject(Parser &P, 108239462Sdim const sema::DelayedDiagnosticPool *parentPool) 109239462Sdim : Actions(P.getActions()), DiagnosticPool(parentPool) { 110239462Sdim push(); 111239462Sdim } 112239462Sdim 113239462Sdim /// Creates a RAII object and, optionally, initialize its 114239462Sdim /// diagnostics pool by stealing the diagnostics from another 115239462Sdim /// RAII object (which is assumed to be the current top pool). 116239462Sdim ParsingDeclRAIIObject(Parser &P, ParsingDeclRAIIObject *other) 117239462Sdim : Actions(P.getActions()), 118276479Sdim DiagnosticPool(other ? other->DiagnosticPool.getParent() : nullptr) { 119239462Sdim if (other) { 120239462Sdim DiagnosticPool.steal(other->DiagnosticPool); 121239462Sdim other->abort(); 122239462Sdim } 123239462Sdim push(); 124239462Sdim } 125239462Sdim 126239462Sdim ~ParsingDeclRAIIObject() { 127239462Sdim abort(); 128239462Sdim } 129239462Sdim 130239462Sdim sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() { 131239462Sdim return DiagnosticPool; 132239462Sdim } 133239462Sdim const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const { 134239462Sdim return DiagnosticPool; 135239462Sdim } 136239462Sdim 137239462Sdim /// Resets the RAII object for a new declaration. 138239462Sdim void reset() { 139239462Sdim abort(); 140239462Sdim push(); 141239462Sdim } 142239462Sdim 143239462Sdim /// Signals that the context was completed without an appropriate 144239462Sdim /// declaration being parsed. 145239462Sdim void abort() { 146276479Sdim pop(nullptr); 147239462Sdim } 148239462Sdim 149239462Sdim void complete(Decl *D) { 150239462Sdim assert(!Popped && "ParsingDeclaration has already been popped!"); 151239462Sdim pop(D); 152239462Sdim } 153239462Sdim 154239462Sdim /// Unregister this object from Sema, but remember all the 155239462Sdim /// diagnostics that were emitted into it. 156239462Sdim void abortAndRemember() { 157276479Sdim pop(nullptr); 158239462Sdim } 159239462Sdim 160239462Sdim private: 161239462Sdim void push() { 162239462Sdim State = Actions.PushParsingDeclaration(DiagnosticPool); 163239462Sdim Popped = false; 164239462Sdim } 165239462Sdim 166239462Sdim void pop(Decl *D) { 167239462Sdim if (!Popped) { 168239462Sdim Actions.PopParsingDeclaration(State, D); 169239462Sdim Popped = true; 170239462Sdim } 171239462Sdim } 172239462Sdim }; 173239462Sdim 174239462Sdim /// A class for parsing a DeclSpec. 175239462Sdim class ParsingDeclSpec : public DeclSpec { 176239462Sdim ParsingDeclRAIIObject ParsingRAII; 177239462Sdim 178239462Sdim public: 179239462Sdim ParsingDeclSpec(Parser &P) 180239462Sdim : DeclSpec(P.getAttrFactory()), 181239462Sdim ParsingRAII(P, ParsingDeclRAIIObject::NoParent) {} 182239462Sdim ParsingDeclSpec(Parser &P, ParsingDeclRAIIObject *RAII) 183239462Sdim : DeclSpec(P.getAttrFactory()), 184239462Sdim ParsingRAII(P, RAII) {} 185239462Sdim 186239462Sdim const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const { 187239462Sdim return ParsingRAII.getDelayedDiagnosticPool(); 188239462Sdim } 189239462Sdim 190239462Sdim void complete(Decl *D) { 191239462Sdim ParsingRAII.complete(D); 192239462Sdim } 193239462Sdim 194239462Sdim void abort() { 195239462Sdim ParsingRAII.abort(); 196239462Sdim } 197239462Sdim }; 198239462Sdim 199239462Sdim /// A class for parsing a declarator. 200239462Sdim class ParsingDeclarator : public Declarator { 201239462Sdim ParsingDeclRAIIObject ParsingRAII; 202239462Sdim 203239462Sdim public: 204239462Sdim ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, TheContext C) 205239462Sdim : Declarator(DS, C), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) { 206239462Sdim } 207239462Sdim 208239462Sdim const ParsingDeclSpec &getDeclSpec() const { 209239462Sdim return static_cast<const ParsingDeclSpec&>(Declarator::getDeclSpec()); 210239462Sdim } 211239462Sdim 212239462Sdim ParsingDeclSpec &getMutableDeclSpec() const { 213239462Sdim return const_cast<ParsingDeclSpec&>(getDeclSpec()); 214239462Sdim } 215239462Sdim 216239462Sdim void clear() { 217239462Sdim Declarator::clear(); 218239462Sdim ParsingRAII.reset(); 219239462Sdim } 220239462Sdim 221239462Sdim void complete(Decl *D) { 222239462Sdim ParsingRAII.complete(D); 223239462Sdim } 224239462Sdim }; 225239462Sdim 226239462Sdim /// A class for parsing a field declarator. 227239462Sdim class ParsingFieldDeclarator : public FieldDeclarator { 228239462Sdim ParsingDeclRAIIObject ParsingRAII; 229239462Sdim 230239462Sdim public: 231239462Sdim ParsingFieldDeclarator(Parser &P, const ParsingDeclSpec &DS) 232239462Sdim : FieldDeclarator(DS), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) { 233239462Sdim } 234239462Sdim 235239462Sdim const ParsingDeclSpec &getDeclSpec() const { 236239462Sdim return static_cast<const ParsingDeclSpec&>(D.getDeclSpec()); 237239462Sdim } 238239462Sdim 239239462Sdim ParsingDeclSpec &getMutableDeclSpec() const { 240239462Sdim return const_cast<ParsingDeclSpec&>(getDeclSpec()); 241239462Sdim } 242239462Sdim 243239462Sdim void complete(Decl *D) { 244239462Sdim ParsingRAII.complete(D); 245239462Sdim } 246239462Sdim }; 247239462Sdim 248200583Srdivacky /// ExtensionRAIIObject - This saves the state of extension warnings when 249200583Srdivacky /// constructed and disables them. When destructed, it restores them back to 250200583Srdivacky /// the way they used to be. This is used to handle __extension__ in the 251200583Srdivacky /// parser. 252200583Srdivacky class ExtensionRAIIObject { 253288943Sdim ExtensionRAIIObject(const ExtensionRAIIObject &) = delete; 254288943Sdim void operator=(const ExtensionRAIIObject &) = delete; 255243830Sdim 256226633Sdim DiagnosticsEngine &Diags; 257200583Srdivacky public: 258226633Sdim ExtensionRAIIObject(DiagnosticsEngine &diags) : Diags(diags) { 259200583Srdivacky Diags.IncrementAllExtensionsSilenced(); 260200583Srdivacky } 261200583Srdivacky 262200583Srdivacky ~ExtensionRAIIObject() { 263200583Srdivacky Diags.DecrementAllExtensionsSilenced(); 264200583Srdivacky } 265200583Srdivacky }; 266200583Srdivacky 267200583Srdivacky /// ColonProtectionRAIIObject - This sets the Parser::ColonIsSacred bool and 268200583Srdivacky /// restores it when destroyed. This says that "foo:" should not be 269200583Srdivacky /// considered a possible typo for "foo::" for error recovery purposes. 270200583Srdivacky class ColonProtectionRAIIObject { 271200583Srdivacky Parser &P; 272200583Srdivacky bool OldVal; 273200583Srdivacky public: 274200583Srdivacky ColonProtectionRAIIObject(Parser &p, bool Value = true) 275200583Srdivacky : P(p), OldVal(P.ColonIsSacred) { 276200583Srdivacky P.ColonIsSacred = Value; 277200583Srdivacky } 278200583Srdivacky 279200583Srdivacky /// restore - This can be used to restore the state early, before the dtor 280200583Srdivacky /// is run. 281200583Srdivacky void restore() { 282200583Srdivacky P.ColonIsSacred = OldVal; 283200583Srdivacky } 284200583Srdivacky 285200583Srdivacky ~ColonProtectionRAIIObject() { 286200583Srdivacky restore(); 287200583Srdivacky } 288200583Srdivacky }; 289200583Srdivacky 290200583Srdivacky /// \brief RAII object that makes '>' behave either as an operator 291200583Srdivacky /// or as the closing angle bracket for a template argument list. 292200583Srdivacky class GreaterThanIsOperatorScope { 293200583Srdivacky bool &GreaterThanIsOperator; 294200583Srdivacky bool OldGreaterThanIsOperator; 295200583Srdivacky public: 296200583Srdivacky GreaterThanIsOperatorScope(bool >IO, bool Val) 297200583Srdivacky : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) { 298200583Srdivacky GreaterThanIsOperator = Val; 299200583Srdivacky } 300200583Srdivacky 301200583Srdivacky ~GreaterThanIsOperatorScope() { 302200583Srdivacky GreaterThanIsOperator = OldGreaterThanIsOperator; 303200583Srdivacky } 304200583Srdivacky }; 305200583Srdivacky 306218893Sdim class InMessageExpressionRAIIObject { 307218893Sdim bool &InMessageExpression; 308218893Sdim bool OldValue; 309218893Sdim 310218893Sdim public: 311218893Sdim InMessageExpressionRAIIObject(Parser &P, bool Value) 312218893Sdim : InMessageExpression(P.InMessageExpression), 313218893Sdim OldValue(P.InMessageExpression) { 314218893Sdim InMessageExpression = Value; 315218893Sdim } 316218893Sdim 317218893Sdim ~InMessageExpressionRAIIObject() { 318218893Sdim InMessageExpression = OldValue; 319218893Sdim } 320218893Sdim }; 321218893Sdim 322210299Sed /// \brief RAII object that makes sure paren/bracket/brace count is correct 323210299Sed /// after declaration/statement parsing, even when there's a parsing error. 324210299Sed class ParenBraceBracketBalancer { 325210299Sed Parser &P; 326210299Sed unsigned short ParenCount, BracketCount, BraceCount; 327210299Sed public: 328210299Sed ParenBraceBracketBalancer(Parser &p) 329210299Sed : P(p), ParenCount(p.ParenCount), BracketCount(p.BracketCount), 330210299Sed BraceCount(p.BraceCount) { } 331210299Sed 332210299Sed ~ParenBraceBracketBalancer() { 333210299Sed P.ParenCount = ParenCount; 334210299Sed P.BracketCount = BracketCount; 335210299Sed P.BraceCount = BraceCount; 336210299Sed } 337210299Sed }; 338221345Sdim 339221345Sdim class PoisonSEHIdentifiersRAIIObject { 340221345Sdim PoisonIdentifierRAIIObject Ident_AbnormalTermination; 341221345Sdim PoisonIdentifierRAIIObject Ident_GetExceptionCode; 342221345Sdim PoisonIdentifierRAIIObject Ident_GetExceptionInfo; 343221345Sdim PoisonIdentifierRAIIObject Ident__abnormal_termination; 344221345Sdim PoisonIdentifierRAIIObject Ident__exception_code; 345221345Sdim PoisonIdentifierRAIIObject Ident__exception_info; 346221345Sdim PoisonIdentifierRAIIObject Ident___abnormal_termination; 347221345Sdim PoisonIdentifierRAIIObject Ident___exception_code; 348221345Sdim PoisonIdentifierRAIIObject Ident___exception_info; 349221345Sdim public: 350221345Sdim PoisonSEHIdentifiersRAIIObject(Parser &Self, bool NewValue) 351221345Sdim : Ident_AbnormalTermination(Self.Ident_AbnormalTermination, NewValue), 352221345Sdim Ident_GetExceptionCode(Self.Ident_GetExceptionCode, NewValue), 353221345Sdim Ident_GetExceptionInfo(Self.Ident_GetExceptionInfo, NewValue), 354221345Sdim Ident__abnormal_termination(Self.Ident__abnormal_termination, NewValue), 355221345Sdim Ident__exception_code(Self.Ident__exception_code, NewValue), 356221345Sdim Ident__exception_info(Self.Ident__exception_info, NewValue), 357221345Sdim Ident___abnormal_termination(Self.Ident___abnormal_termination, NewValue), 358221345Sdim Ident___exception_code(Self.Ident___exception_code, NewValue), 359221345Sdim Ident___exception_info(Self.Ident___exception_info, NewValue) { 360221345Sdim } 361221345Sdim }; 362221345Sdim 363239462Sdim /// \brief RAII class that helps handle the parsing of an open/close delimiter 364239462Sdim /// pair, such as braces { ... } or parentheses ( ... ). 365239462Sdim class BalancedDelimiterTracker : public GreaterThanIsOperatorScope { 366239462Sdim Parser& P; 367261991Sdim tok::TokenKind Kind, Close, FinalToken; 368239462Sdim SourceLocation (Parser::*Consumer)(); 369239462Sdim SourceLocation LOpen, LClose; 370239462Sdim 371239462Sdim unsigned short &getDepth() { 372239462Sdim switch (Kind) { 373239462Sdim case tok::l_brace: return P.BraceCount; 374239462Sdim case tok::l_square: return P.BracketCount; 375239462Sdim case tok::l_paren: return P.ParenCount; 376239462Sdim default: llvm_unreachable("Wrong token kind"); 377239462Sdim } 378239462Sdim } 379239462Sdim 380239462Sdim enum { MaxDepth = 256 }; 381239462Sdim 382239462Sdim bool diagnoseOverflow(); 383239462Sdim bool diagnoseMissingClose(); 384239462Sdim 385239462Sdim public: 386261991Sdim BalancedDelimiterTracker(Parser& p, tok::TokenKind k, 387261991Sdim tok::TokenKind FinalToken = tok::semi) 388239462Sdim : GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true), 389261991Sdim P(p), Kind(k), FinalToken(FinalToken) 390239462Sdim { 391239462Sdim switch (Kind) { 392239462Sdim default: llvm_unreachable("Unexpected balanced token"); 393239462Sdim case tok::l_brace: 394239462Sdim Close = tok::r_brace; 395239462Sdim Consumer = &Parser::ConsumeBrace; 396239462Sdim break; 397239462Sdim case tok::l_paren: 398239462Sdim Close = tok::r_paren; 399239462Sdim Consumer = &Parser::ConsumeParen; 400239462Sdim break; 401239462Sdim 402239462Sdim case tok::l_square: 403239462Sdim Close = tok::r_square; 404239462Sdim Consumer = &Parser::ConsumeBracket; 405239462Sdim break; 406239462Sdim } 407239462Sdim } 408239462Sdim 409239462Sdim SourceLocation getOpenLocation() const { return LOpen; } 410239462Sdim SourceLocation getCloseLocation() const { return LClose; } 411239462Sdim SourceRange getRange() const { return SourceRange(LOpen, LClose); } 412239462Sdim 413239462Sdim bool consumeOpen() { 414239462Sdim if (!P.Tok.is(Kind)) 415239462Sdim return true; 416239462Sdim 417249423Sdim if (getDepth() < P.getLangOpts().BracketDepth) { 418239462Sdim LOpen = (P.*Consumer)(); 419239462Sdim return false; 420239462Sdim } 421239462Sdim 422239462Sdim return diagnoseOverflow(); 423239462Sdim } 424276479Sdim 425276479Sdim bool expectAndConsume(unsigned DiagID = diag::err_expected, 426239462Sdim const char *Msg = "", 427239462Sdim tok::TokenKind SkipToTok = tok::unknown); 428239462Sdim bool consumeClose() { 429239462Sdim if (P.Tok.is(Close)) { 430239462Sdim LClose = (P.*Consumer)(); 431239462Sdim return false; 432288943Sdim } else if (P.Tok.is(tok::semi) && P.NextToken().is(Close)) { 433288943Sdim SourceLocation SemiLoc = P.ConsumeToken(); 434288943Sdim P.Diag(SemiLoc, diag::err_unexpected_semi) 435288943Sdim << Close << FixItHint::CreateRemoval(SourceRange(SemiLoc, SemiLoc)); 436288943Sdim LClose = (P.*Consumer)(); 437288943Sdim return false; 438288943Sdim } 439239462Sdim 440239462Sdim return diagnoseMissingClose(); 441239462Sdim } 442239462Sdim void skipToEnd(); 443239462Sdim }; 444239462Sdim 445200583Srdivacky} // end namespace clang 446200583Srdivacky 447200583Srdivacky#endif 448