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 15200583Srdivacky#ifndef LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_H 16200583Srdivacky#define LLVM_CLANG_PARSE_RAII_OBJECTS_FOR_PARSER_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) 53239462Sdim : S(P.getActions()), DiagnosticPool(NULL) { 54239462Sdim if (activate) { 55239462Sdim State = S.PushParsingDeclaration(DiagnosticPool); 56239462Sdim Active = true; 57239462Sdim } else { 58239462Sdim Active = false; 59239462Sdim } 60239462Sdim } 61239462Sdim 62239462Sdim void done() { 63239462Sdim assert(Active && "trying to end an inactive suppression"); 64239462Sdim S.PopParsingDeclaration(State, NULL); 65239462Sdim Active = false; 66239462Sdim } 67239462Sdim 68239462Sdim void redelay() { 69239462Sdim assert(!Active && "redelaying without having ended first"); 70239462Sdim if (!DiagnosticPool.pool_empty()) 71239462Sdim S.redelayDiagnostics(DiagnosticPool); 72239462Sdim assert(DiagnosticPool.pool_empty()); 73239462Sdim } 74239462Sdim 75239462Sdim ~SuppressAccessChecks() { 76239462Sdim if (Active) done(); 77239462Sdim } 78239462Sdim }; 79239462Sdim 80239462Sdim /// \brief RAII object used to inform the actions that we're 81239462Sdim /// currently parsing a declaration. This is active when parsing a 82239462Sdim /// variable's initializer, but not when parsing the body of a 83239462Sdim /// class or function definition. 84239462Sdim class ParsingDeclRAIIObject { 85239462Sdim Sema &Actions; 86239462Sdim sema::DelayedDiagnosticPool DiagnosticPool; 87239462Sdim Sema::ParsingDeclState State; 88239462Sdim bool Popped; 89239462Sdim 90243830Sdim ParsingDeclRAIIObject(const ParsingDeclRAIIObject &) LLVM_DELETED_FUNCTION; 91243830Sdim void operator=(const ParsingDeclRAIIObject &) LLVM_DELETED_FUNCTION; 92239462Sdim 93239462Sdim public: 94239462Sdim enum NoParent_t { NoParent }; 95239462Sdim ParsingDeclRAIIObject(Parser &P, NoParent_t _) 96239462Sdim : Actions(P.getActions()), DiagnosticPool(NULL) { 97239462Sdim push(); 98239462Sdim } 99239462Sdim 100239462Sdim /// Creates a RAII object whose pool is optionally parented by another. 101239462Sdim ParsingDeclRAIIObject(Parser &P, 102239462Sdim const sema::DelayedDiagnosticPool *parentPool) 103239462Sdim : Actions(P.getActions()), DiagnosticPool(parentPool) { 104239462Sdim push(); 105239462Sdim } 106239462Sdim 107239462Sdim /// Creates a RAII object and, optionally, initialize its 108239462Sdim /// diagnostics pool by stealing the diagnostics from another 109239462Sdim /// RAII object (which is assumed to be the current top pool). 110239462Sdim ParsingDeclRAIIObject(Parser &P, ParsingDeclRAIIObject *other) 111239462Sdim : Actions(P.getActions()), 112239462Sdim DiagnosticPool(other ? other->DiagnosticPool.getParent() : NULL) { 113239462Sdim if (other) { 114239462Sdim DiagnosticPool.steal(other->DiagnosticPool); 115239462Sdim other->abort(); 116239462Sdim } 117239462Sdim push(); 118239462Sdim } 119239462Sdim 120239462Sdim ~ParsingDeclRAIIObject() { 121239462Sdim abort(); 122239462Sdim } 123239462Sdim 124239462Sdim sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() { 125239462Sdim return DiagnosticPool; 126239462Sdim } 127239462Sdim const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const { 128239462Sdim return DiagnosticPool; 129239462Sdim } 130239462Sdim 131239462Sdim /// Resets the RAII object for a new declaration. 132239462Sdim void reset() { 133239462Sdim abort(); 134239462Sdim push(); 135239462Sdim } 136239462Sdim 137239462Sdim /// Signals that the context was completed without an appropriate 138239462Sdim /// declaration being parsed. 139239462Sdim void abort() { 140239462Sdim pop(0); 141239462Sdim } 142239462Sdim 143239462Sdim void complete(Decl *D) { 144239462Sdim assert(!Popped && "ParsingDeclaration has already been popped!"); 145239462Sdim pop(D); 146239462Sdim } 147239462Sdim 148239462Sdim /// Unregister this object from Sema, but remember all the 149239462Sdim /// diagnostics that were emitted into it. 150239462Sdim void abortAndRemember() { 151239462Sdim pop(0); 152239462Sdim } 153239462Sdim 154239462Sdim private: 155239462Sdim void push() { 156239462Sdim State = Actions.PushParsingDeclaration(DiagnosticPool); 157239462Sdim Popped = false; 158239462Sdim } 159239462Sdim 160239462Sdim void pop(Decl *D) { 161239462Sdim if (!Popped) { 162239462Sdim Actions.PopParsingDeclaration(State, D); 163239462Sdim Popped = true; 164239462Sdim } 165239462Sdim } 166239462Sdim }; 167239462Sdim 168239462Sdim /// A class for parsing a DeclSpec. 169239462Sdim class ParsingDeclSpec : public DeclSpec { 170239462Sdim ParsingDeclRAIIObject ParsingRAII; 171239462Sdim 172239462Sdim public: 173239462Sdim ParsingDeclSpec(Parser &P) 174239462Sdim : DeclSpec(P.getAttrFactory()), 175239462Sdim ParsingRAII(P, ParsingDeclRAIIObject::NoParent) {} 176239462Sdim ParsingDeclSpec(Parser &P, ParsingDeclRAIIObject *RAII) 177239462Sdim : DeclSpec(P.getAttrFactory()), 178239462Sdim ParsingRAII(P, RAII) {} 179239462Sdim 180239462Sdim const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const { 181239462Sdim return ParsingRAII.getDelayedDiagnosticPool(); 182239462Sdim } 183239462Sdim 184239462Sdim void complete(Decl *D) { 185239462Sdim ParsingRAII.complete(D); 186239462Sdim } 187239462Sdim 188239462Sdim void abort() { 189239462Sdim ParsingRAII.abort(); 190239462Sdim } 191239462Sdim }; 192239462Sdim 193239462Sdim /// A class for parsing a declarator. 194239462Sdim class ParsingDeclarator : public Declarator { 195239462Sdim ParsingDeclRAIIObject ParsingRAII; 196239462Sdim 197239462Sdim public: 198239462Sdim ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, TheContext C) 199239462Sdim : Declarator(DS, C), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) { 200239462Sdim } 201239462Sdim 202239462Sdim const ParsingDeclSpec &getDeclSpec() const { 203239462Sdim return static_cast<const ParsingDeclSpec&>(Declarator::getDeclSpec()); 204239462Sdim } 205239462Sdim 206239462Sdim ParsingDeclSpec &getMutableDeclSpec() const { 207239462Sdim return const_cast<ParsingDeclSpec&>(getDeclSpec()); 208239462Sdim } 209239462Sdim 210239462Sdim void clear() { 211239462Sdim Declarator::clear(); 212239462Sdim ParsingRAII.reset(); 213239462Sdim } 214239462Sdim 215239462Sdim void complete(Decl *D) { 216239462Sdim ParsingRAII.complete(D); 217239462Sdim } 218239462Sdim }; 219239462Sdim 220239462Sdim /// A class for parsing a field declarator. 221239462Sdim class ParsingFieldDeclarator : public FieldDeclarator { 222239462Sdim ParsingDeclRAIIObject ParsingRAII; 223239462Sdim 224239462Sdim public: 225239462Sdim ParsingFieldDeclarator(Parser &P, const ParsingDeclSpec &DS) 226239462Sdim : FieldDeclarator(DS), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) { 227239462Sdim } 228239462Sdim 229239462Sdim const ParsingDeclSpec &getDeclSpec() const { 230239462Sdim return static_cast<const ParsingDeclSpec&>(D.getDeclSpec()); 231239462Sdim } 232239462Sdim 233239462Sdim ParsingDeclSpec &getMutableDeclSpec() const { 234239462Sdim return const_cast<ParsingDeclSpec&>(getDeclSpec()); 235239462Sdim } 236239462Sdim 237239462Sdim void complete(Decl *D) { 238239462Sdim ParsingRAII.complete(D); 239239462Sdim } 240239462Sdim }; 241239462Sdim 242200583Srdivacky /// ExtensionRAIIObject - This saves the state of extension warnings when 243200583Srdivacky /// constructed and disables them. When destructed, it restores them back to 244200583Srdivacky /// the way they used to be. This is used to handle __extension__ in the 245200583Srdivacky /// parser. 246200583Srdivacky class ExtensionRAIIObject { 247243830Sdim ExtensionRAIIObject(const ExtensionRAIIObject &) LLVM_DELETED_FUNCTION; 248243830Sdim void operator=(const ExtensionRAIIObject &) LLVM_DELETED_FUNCTION; 249243830Sdim 250226633Sdim DiagnosticsEngine &Diags; 251200583Srdivacky public: 252226633Sdim ExtensionRAIIObject(DiagnosticsEngine &diags) : Diags(diags) { 253200583Srdivacky Diags.IncrementAllExtensionsSilenced(); 254200583Srdivacky } 255200583Srdivacky 256200583Srdivacky ~ExtensionRAIIObject() { 257200583Srdivacky Diags.DecrementAllExtensionsSilenced(); 258200583Srdivacky } 259200583Srdivacky }; 260200583Srdivacky 261200583Srdivacky /// ColonProtectionRAIIObject - This sets the Parser::ColonIsSacred bool and 262200583Srdivacky /// restores it when destroyed. This says that "foo:" should not be 263200583Srdivacky /// considered a possible typo for "foo::" for error recovery purposes. 264200583Srdivacky class ColonProtectionRAIIObject { 265200583Srdivacky Parser &P; 266200583Srdivacky bool OldVal; 267200583Srdivacky public: 268200583Srdivacky ColonProtectionRAIIObject(Parser &p, bool Value = true) 269200583Srdivacky : P(p), OldVal(P.ColonIsSacred) { 270200583Srdivacky P.ColonIsSacred = Value; 271200583Srdivacky } 272200583Srdivacky 273200583Srdivacky /// restore - This can be used to restore the state early, before the dtor 274200583Srdivacky /// is run. 275200583Srdivacky void restore() { 276200583Srdivacky P.ColonIsSacred = OldVal; 277200583Srdivacky } 278200583Srdivacky 279200583Srdivacky ~ColonProtectionRAIIObject() { 280200583Srdivacky restore(); 281200583Srdivacky } 282200583Srdivacky }; 283200583Srdivacky 284200583Srdivacky /// \brief RAII object that makes '>' behave either as an operator 285200583Srdivacky /// or as the closing angle bracket for a template argument list. 286200583Srdivacky class GreaterThanIsOperatorScope { 287200583Srdivacky bool &GreaterThanIsOperator; 288200583Srdivacky bool OldGreaterThanIsOperator; 289200583Srdivacky public: 290200583Srdivacky GreaterThanIsOperatorScope(bool >IO, bool Val) 291200583Srdivacky : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) { 292200583Srdivacky GreaterThanIsOperator = Val; 293200583Srdivacky } 294200583Srdivacky 295200583Srdivacky ~GreaterThanIsOperatorScope() { 296200583Srdivacky GreaterThanIsOperator = OldGreaterThanIsOperator; 297200583Srdivacky } 298200583Srdivacky }; 299200583Srdivacky 300218893Sdim class InMessageExpressionRAIIObject { 301218893Sdim bool &InMessageExpression; 302218893Sdim bool OldValue; 303218893Sdim 304218893Sdim public: 305218893Sdim InMessageExpressionRAIIObject(Parser &P, bool Value) 306218893Sdim : InMessageExpression(P.InMessageExpression), 307218893Sdim OldValue(P.InMessageExpression) { 308218893Sdim InMessageExpression = Value; 309218893Sdim } 310218893Sdim 311218893Sdim ~InMessageExpressionRAIIObject() { 312218893Sdim InMessageExpression = OldValue; 313218893Sdim } 314218893Sdim }; 315218893Sdim 316210299Sed /// \brief RAII object that makes sure paren/bracket/brace count is correct 317210299Sed /// after declaration/statement parsing, even when there's a parsing error. 318210299Sed class ParenBraceBracketBalancer { 319210299Sed Parser &P; 320210299Sed unsigned short ParenCount, BracketCount, BraceCount; 321210299Sed public: 322210299Sed ParenBraceBracketBalancer(Parser &p) 323210299Sed : P(p), ParenCount(p.ParenCount), BracketCount(p.BracketCount), 324210299Sed BraceCount(p.BraceCount) { } 325210299Sed 326210299Sed ~ParenBraceBracketBalancer() { 327210299Sed P.ParenCount = ParenCount; 328210299Sed P.BracketCount = BracketCount; 329210299Sed P.BraceCount = BraceCount; 330210299Sed } 331210299Sed }; 332221345Sdim 333221345Sdim class PoisonSEHIdentifiersRAIIObject { 334221345Sdim PoisonIdentifierRAIIObject Ident_AbnormalTermination; 335221345Sdim PoisonIdentifierRAIIObject Ident_GetExceptionCode; 336221345Sdim PoisonIdentifierRAIIObject Ident_GetExceptionInfo; 337221345Sdim PoisonIdentifierRAIIObject Ident__abnormal_termination; 338221345Sdim PoisonIdentifierRAIIObject Ident__exception_code; 339221345Sdim PoisonIdentifierRAIIObject Ident__exception_info; 340221345Sdim PoisonIdentifierRAIIObject Ident___abnormal_termination; 341221345Sdim PoisonIdentifierRAIIObject Ident___exception_code; 342221345Sdim PoisonIdentifierRAIIObject Ident___exception_info; 343221345Sdim public: 344221345Sdim PoisonSEHIdentifiersRAIIObject(Parser &Self, bool NewValue) 345221345Sdim : Ident_AbnormalTermination(Self.Ident_AbnormalTermination, NewValue), 346221345Sdim Ident_GetExceptionCode(Self.Ident_GetExceptionCode, NewValue), 347221345Sdim Ident_GetExceptionInfo(Self.Ident_GetExceptionInfo, NewValue), 348221345Sdim Ident__abnormal_termination(Self.Ident__abnormal_termination, NewValue), 349221345Sdim Ident__exception_code(Self.Ident__exception_code, NewValue), 350221345Sdim Ident__exception_info(Self.Ident__exception_info, NewValue), 351221345Sdim Ident___abnormal_termination(Self.Ident___abnormal_termination, NewValue), 352221345Sdim Ident___exception_code(Self.Ident___exception_code, NewValue), 353221345Sdim Ident___exception_info(Self.Ident___exception_info, NewValue) { 354221345Sdim } 355221345Sdim }; 356221345Sdim 357239462Sdim /// \brief RAII class that helps handle the parsing of an open/close delimiter 358239462Sdim /// pair, such as braces { ... } or parentheses ( ... ). 359239462Sdim class BalancedDelimiterTracker : public GreaterThanIsOperatorScope { 360239462Sdim Parser& P; 361239462Sdim tok::TokenKind Kind, Close; 362239462Sdim SourceLocation (Parser::*Consumer)(); 363239462Sdim SourceLocation LOpen, LClose; 364239462Sdim 365239462Sdim unsigned short &getDepth() { 366239462Sdim switch (Kind) { 367239462Sdim case tok::l_brace: return P.BraceCount; 368239462Sdim case tok::l_square: return P.BracketCount; 369239462Sdim case tok::l_paren: return P.ParenCount; 370239462Sdim default: llvm_unreachable("Wrong token kind"); 371239462Sdim } 372239462Sdim } 373239462Sdim 374239462Sdim enum { MaxDepth = 256 }; 375239462Sdim 376239462Sdim bool diagnoseOverflow(); 377239462Sdim bool diagnoseMissingClose(); 378239462Sdim 379239462Sdim public: 380239462Sdim BalancedDelimiterTracker(Parser& p, tok::TokenKind k) 381239462Sdim : GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true), 382239462Sdim P(p), Kind(k) 383239462Sdim { 384239462Sdim switch (Kind) { 385239462Sdim default: llvm_unreachable("Unexpected balanced token"); 386239462Sdim case tok::l_brace: 387239462Sdim Close = tok::r_brace; 388239462Sdim Consumer = &Parser::ConsumeBrace; 389239462Sdim break; 390239462Sdim case tok::l_paren: 391239462Sdim Close = tok::r_paren; 392239462Sdim Consumer = &Parser::ConsumeParen; 393239462Sdim break; 394239462Sdim 395239462Sdim case tok::l_square: 396239462Sdim Close = tok::r_square; 397239462Sdim Consumer = &Parser::ConsumeBracket; 398239462Sdim break; 399239462Sdim } 400239462Sdim } 401239462Sdim 402239462Sdim SourceLocation getOpenLocation() const { return LOpen; } 403239462Sdim SourceLocation getCloseLocation() const { return LClose; } 404239462Sdim SourceRange getRange() const { return SourceRange(LOpen, LClose); } 405239462Sdim 406239462Sdim bool consumeOpen() { 407239462Sdim if (!P.Tok.is(Kind)) 408239462Sdim return true; 409239462Sdim 410249423Sdim if (getDepth() < P.getLangOpts().BracketDepth) { 411239462Sdim LOpen = (P.*Consumer)(); 412239462Sdim return false; 413239462Sdim } 414239462Sdim 415239462Sdim return diagnoseOverflow(); 416239462Sdim } 417239462Sdim 418239462Sdim bool expectAndConsume(unsigned DiagID, 419239462Sdim const char *Msg = "", 420239462Sdim tok::TokenKind SkipToTok = tok::unknown); 421239462Sdim bool consumeClose() { 422239462Sdim if (P.Tok.is(Close)) { 423239462Sdim LClose = (P.*Consumer)(); 424239462Sdim return false; 425239462Sdim } 426239462Sdim 427239462Sdim return diagnoseMissingClose(); 428239462Sdim } 429239462Sdim void skipToEnd(); 430239462Sdim }; 431239462Sdim 432200583Srdivacky} // end namespace clang 433200583Srdivacky 434200583Srdivacky#endif 435