clang API Documentation
00001 //===--- RAIIObjectsForParser.h - RAII helpers for the parser ---*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines and implements the some simple RAII objects that are used 00011 // by the parser to manage bits in recursion. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #ifndef LLVM_CLANG_LIB_PARSE_RAIIOBJECTSFORPARSER_H 00016 #define LLVM_CLANG_LIB_PARSE_RAIIOBJECTSFORPARSER_H 00017 00018 #include "clang/Parse/ParseDiagnostic.h" 00019 #include "clang/Parse/Parser.h" 00020 #include "clang/Sema/DelayedDiagnostic.h" 00021 #include "clang/Sema/Sema.h" 00022 00023 namespace clang { 00024 // TODO: move ParsingClassDefinition here. 00025 // TODO: move TentativeParsingAction here. 00026 00027 /// \brief A RAII object used to temporarily suppress access-like 00028 /// checking. Access-like checks are those associated with 00029 /// controlling the use of a declaration, like C++ access control 00030 /// errors and deprecation warnings. They are contextually 00031 /// dependent, in that they can only be resolved with full 00032 /// information about what's being declared. They are also 00033 /// suppressed in certain contexts, like the template arguments of 00034 /// an explicit instantiation. However, those suppression contexts 00035 /// cannot necessarily be fully determined in advance; for 00036 /// example, something starting like this: 00037 /// template <> class std::vector<A::PrivateType> 00038 /// might be the entirety of an explicit instantiation: 00039 /// template <> class std::vector<A::PrivateType>; 00040 /// or just an elaborated type specifier: 00041 /// template <> class std::vector<A::PrivateType> make_vector<>(); 00042 /// Therefore this class collects all the diagnostics and permits 00043 /// them to be re-delayed in a new context. 00044 class SuppressAccessChecks { 00045 Sema &S; 00046 sema::DelayedDiagnosticPool DiagnosticPool; 00047 Sema::ParsingDeclState State; 00048 bool Active; 00049 00050 public: 00051 /// Begin suppressing access-like checks 00052 SuppressAccessChecks(Parser &P, bool activate = true) 00053 : S(P.getActions()), DiagnosticPool(nullptr) { 00054 if (activate) { 00055 State = S.PushParsingDeclaration(DiagnosticPool); 00056 Active = true; 00057 } else { 00058 Active = false; 00059 } 00060 } 00061 00062 void done() { 00063 assert(Active && "trying to end an inactive suppression"); 00064 S.PopParsingDeclaration(State, nullptr); 00065 Active = false; 00066 } 00067 00068 void redelay() { 00069 assert(!Active && "redelaying without having ended first"); 00070 if (!DiagnosticPool.pool_empty()) 00071 S.redelayDiagnostics(DiagnosticPool); 00072 assert(DiagnosticPool.pool_empty()); 00073 } 00074 00075 ~SuppressAccessChecks() { 00076 if (Active) done(); 00077 } 00078 }; 00079 00080 /// \brief RAII object used to inform the actions that we're 00081 /// currently parsing a declaration. This is active when parsing a 00082 /// variable's initializer, but not when parsing the body of a 00083 /// class or function definition. 00084 class ParsingDeclRAIIObject { 00085 Sema &Actions; 00086 sema::DelayedDiagnosticPool DiagnosticPool; 00087 Sema::ParsingDeclState State; 00088 bool Popped; 00089 00090 ParsingDeclRAIIObject(const ParsingDeclRAIIObject &) LLVM_DELETED_FUNCTION; 00091 void operator=(const ParsingDeclRAIIObject &) LLVM_DELETED_FUNCTION; 00092 00093 public: 00094 enum NoParent_t { NoParent }; 00095 ParsingDeclRAIIObject(Parser &P, NoParent_t _) 00096 : Actions(P.getActions()), DiagnosticPool(nullptr) { 00097 push(); 00098 } 00099 00100 /// Creates a RAII object whose pool is optionally parented by another. 00101 ParsingDeclRAIIObject(Parser &P, 00102 const sema::DelayedDiagnosticPool *parentPool) 00103 : Actions(P.getActions()), DiagnosticPool(parentPool) { 00104 push(); 00105 } 00106 00107 /// Creates a RAII object and, optionally, initialize its 00108 /// diagnostics pool by stealing the diagnostics from another 00109 /// RAII object (which is assumed to be the current top pool). 00110 ParsingDeclRAIIObject(Parser &P, ParsingDeclRAIIObject *other) 00111 : Actions(P.getActions()), 00112 DiagnosticPool(other ? other->DiagnosticPool.getParent() : nullptr) { 00113 if (other) { 00114 DiagnosticPool.steal(other->DiagnosticPool); 00115 other->abort(); 00116 } 00117 push(); 00118 } 00119 00120 ~ParsingDeclRAIIObject() { 00121 abort(); 00122 } 00123 00124 sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() { 00125 return DiagnosticPool; 00126 } 00127 const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const { 00128 return DiagnosticPool; 00129 } 00130 00131 /// Resets the RAII object for a new declaration. 00132 void reset() { 00133 abort(); 00134 push(); 00135 } 00136 00137 /// Signals that the context was completed without an appropriate 00138 /// declaration being parsed. 00139 void abort() { 00140 pop(nullptr); 00141 } 00142 00143 void complete(Decl *D) { 00144 assert(!Popped && "ParsingDeclaration has already been popped!"); 00145 pop(D); 00146 } 00147 00148 /// Unregister this object from Sema, but remember all the 00149 /// diagnostics that were emitted into it. 00150 void abortAndRemember() { 00151 pop(nullptr); 00152 } 00153 00154 private: 00155 void push() { 00156 State = Actions.PushParsingDeclaration(DiagnosticPool); 00157 Popped = false; 00158 } 00159 00160 void pop(Decl *D) { 00161 if (!Popped) { 00162 Actions.PopParsingDeclaration(State, D); 00163 Popped = true; 00164 } 00165 } 00166 }; 00167 00168 /// A class for parsing a DeclSpec. 00169 class ParsingDeclSpec : public DeclSpec { 00170 ParsingDeclRAIIObject ParsingRAII; 00171 00172 public: 00173 ParsingDeclSpec(Parser &P) 00174 : DeclSpec(P.getAttrFactory()), 00175 ParsingRAII(P, ParsingDeclRAIIObject::NoParent) {} 00176 ParsingDeclSpec(Parser &P, ParsingDeclRAIIObject *RAII) 00177 : DeclSpec(P.getAttrFactory()), 00178 ParsingRAII(P, RAII) {} 00179 00180 const sema::DelayedDiagnosticPool &getDelayedDiagnosticPool() const { 00181 return ParsingRAII.getDelayedDiagnosticPool(); 00182 } 00183 00184 void complete(Decl *D) { 00185 ParsingRAII.complete(D); 00186 } 00187 00188 void abort() { 00189 ParsingRAII.abort(); 00190 } 00191 }; 00192 00193 /// A class for parsing a declarator. 00194 class ParsingDeclarator : public Declarator { 00195 ParsingDeclRAIIObject ParsingRAII; 00196 00197 public: 00198 ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, TheContext C) 00199 : Declarator(DS, C), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) { 00200 } 00201 00202 const ParsingDeclSpec &getDeclSpec() const { 00203 return static_cast<const ParsingDeclSpec&>(Declarator::getDeclSpec()); 00204 } 00205 00206 ParsingDeclSpec &getMutableDeclSpec() const { 00207 return const_cast<ParsingDeclSpec&>(getDeclSpec()); 00208 } 00209 00210 void clear() { 00211 Declarator::clear(); 00212 ParsingRAII.reset(); 00213 } 00214 00215 void complete(Decl *D) { 00216 ParsingRAII.complete(D); 00217 } 00218 }; 00219 00220 /// A class for parsing a field declarator. 00221 class ParsingFieldDeclarator : public FieldDeclarator { 00222 ParsingDeclRAIIObject ParsingRAII; 00223 00224 public: 00225 ParsingFieldDeclarator(Parser &P, const ParsingDeclSpec &DS) 00226 : FieldDeclarator(DS), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) { 00227 } 00228 00229 const ParsingDeclSpec &getDeclSpec() const { 00230 return static_cast<const ParsingDeclSpec&>(D.getDeclSpec()); 00231 } 00232 00233 ParsingDeclSpec &getMutableDeclSpec() const { 00234 return const_cast<ParsingDeclSpec&>(getDeclSpec()); 00235 } 00236 00237 void complete(Decl *D) { 00238 ParsingRAII.complete(D); 00239 } 00240 }; 00241 00242 /// ExtensionRAIIObject - This saves the state of extension warnings when 00243 /// constructed and disables them. When destructed, it restores them back to 00244 /// the way they used to be. This is used to handle __extension__ in the 00245 /// parser. 00246 class ExtensionRAIIObject { 00247 ExtensionRAIIObject(const ExtensionRAIIObject &) LLVM_DELETED_FUNCTION; 00248 void operator=(const ExtensionRAIIObject &) LLVM_DELETED_FUNCTION; 00249 00250 DiagnosticsEngine &Diags; 00251 public: 00252 ExtensionRAIIObject(DiagnosticsEngine &diags) : Diags(diags) { 00253 Diags.IncrementAllExtensionsSilenced(); 00254 } 00255 00256 ~ExtensionRAIIObject() { 00257 Diags.DecrementAllExtensionsSilenced(); 00258 } 00259 }; 00260 00261 /// ColonProtectionRAIIObject - This sets the Parser::ColonIsSacred bool and 00262 /// restores it when destroyed. This says that "foo:" should not be 00263 /// considered a possible typo for "foo::" for error recovery purposes. 00264 class ColonProtectionRAIIObject { 00265 Parser &P; 00266 bool OldVal; 00267 public: 00268 ColonProtectionRAIIObject(Parser &p, bool Value = true) 00269 : P(p), OldVal(P.ColonIsSacred) { 00270 P.ColonIsSacred = Value; 00271 } 00272 00273 /// restore - This can be used to restore the state early, before the dtor 00274 /// is run. 00275 void restore() { 00276 P.ColonIsSacred = OldVal; 00277 } 00278 00279 ~ColonProtectionRAIIObject() { 00280 restore(); 00281 } 00282 }; 00283 00284 /// \brief RAII object that makes '>' behave either as an operator 00285 /// or as the closing angle bracket for a template argument list. 00286 class GreaterThanIsOperatorScope { 00287 bool &GreaterThanIsOperator; 00288 bool OldGreaterThanIsOperator; 00289 public: 00290 GreaterThanIsOperatorScope(bool >IO, bool Val) 00291 : GreaterThanIsOperator(GTIO), OldGreaterThanIsOperator(GTIO) { 00292 GreaterThanIsOperator = Val; 00293 } 00294 00295 ~GreaterThanIsOperatorScope() { 00296 GreaterThanIsOperator = OldGreaterThanIsOperator; 00297 } 00298 }; 00299 00300 class InMessageExpressionRAIIObject { 00301 bool &InMessageExpression; 00302 bool OldValue; 00303 00304 public: 00305 InMessageExpressionRAIIObject(Parser &P, bool Value) 00306 : InMessageExpression(P.InMessageExpression), 00307 OldValue(P.InMessageExpression) { 00308 InMessageExpression = Value; 00309 } 00310 00311 ~InMessageExpressionRAIIObject() { 00312 InMessageExpression = OldValue; 00313 } 00314 }; 00315 00316 /// \brief RAII object that makes sure paren/bracket/brace count is correct 00317 /// after declaration/statement parsing, even when there's a parsing error. 00318 class ParenBraceBracketBalancer { 00319 Parser &P; 00320 unsigned short ParenCount, BracketCount, BraceCount; 00321 public: 00322 ParenBraceBracketBalancer(Parser &p) 00323 : P(p), ParenCount(p.ParenCount), BracketCount(p.BracketCount), 00324 BraceCount(p.BraceCount) { } 00325 00326 ~ParenBraceBracketBalancer() { 00327 P.ParenCount = ParenCount; 00328 P.BracketCount = BracketCount; 00329 P.BraceCount = BraceCount; 00330 } 00331 }; 00332 00333 class PoisonSEHIdentifiersRAIIObject { 00334 PoisonIdentifierRAIIObject Ident_AbnormalTermination; 00335 PoisonIdentifierRAIIObject Ident_GetExceptionCode; 00336 PoisonIdentifierRAIIObject Ident_GetExceptionInfo; 00337 PoisonIdentifierRAIIObject Ident__abnormal_termination; 00338 PoisonIdentifierRAIIObject Ident__exception_code; 00339 PoisonIdentifierRAIIObject Ident__exception_info; 00340 PoisonIdentifierRAIIObject Ident___abnormal_termination; 00341 PoisonIdentifierRAIIObject Ident___exception_code; 00342 PoisonIdentifierRAIIObject Ident___exception_info; 00343 public: 00344 PoisonSEHIdentifiersRAIIObject(Parser &Self, bool NewValue) 00345 : Ident_AbnormalTermination(Self.Ident_AbnormalTermination, NewValue), 00346 Ident_GetExceptionCode(Self.Ident_GetExceptionCode, NewValue), 00347 Ident_GetExceptionInfo(Self.Ident_GetExceptionInfo, NewValue), 00348 Ident__abnormal_termination(Self.Ident__abnormal_termination, NewValue), 00349 Ident__exception_code(Self.Ident__exception_code, NewValue), 00350 Ident__exception_info(Self.Ident__exception_info, NewValue), 00351 Ident___abnormal_termination(Self.Ident___abnormal_termination, NewValue), 00352 Ident___exception_code(Self.Ident___exception_code, NewValue), 00353 Ident___exception_info(Self.Ident___exception_info, NewValue) { 00354 } 00355 }; 00356 00357 /// \brief RAII class that helps handle the parsing of an open/close delimiter 00358 /// pair, such as braces { ... } or parentheses ( ... ). 00359 class BalancedDelimiterTracker : public GreaterThanIsOperatorScope { 00360 Parser& P; 00361 tok::TokenKind Kind, Close, FinalToken; 00362 SourceLocation (Parser::*Consumer)(); 00363 SourceLocation LOpen, LClose; 00364 00365 unsigned short &getDepth() { 00366 switch (Kind) { 00367 case tok::l_brace: return P.BraceCount; 00368 case tok::l_square: return P.BracketCount; 00369 case tok::l_paren: return P.ParenCount; 00370 default: llvm_unreachable("Wrong token kind"); 00371 } 00372 } 00373 00374 enum { MaxDepth = 256 }; 00375 00376 bool diagnoseOverflow(); 00377 bool diagnoseMissingClose(); 00378 00379 public: 00380 BalancedDelimiterTracker(Parser& p, tok::TokenKind k, 00381 tok::TokenKind FinalToken = tok::semi) 00382 : GreaterThanIsOperatorScope(p.GreaterThanIsOperator, true), 00383 P(p), Kind(k), FinalToken(FinalToken) 00384 { 00385 switch (Kind) { 00386 default: llvm_unreachable("Unexpected balanced token"); 00387 case tok::l_brace: 00388 Close = tok::r_brace; 00389 Consumer = &Parser::ConsumeBrace; 00390 break; 00391 case tok::l_paren: 00392 Close = tok::r_paren; 00393 Consumer = &Parser::ConsumeParen; 00394 break; 00395 00396 case tok::l_square: 00397 Close = tok::r_square; 00398 Consumer = &Parser::ConsumeBracket; 00399 break; 00400 } 00401 } 00402 00403 SourceLocation getOpenLocation() const { return LOpen; } 00404 SourceLocation getCloseLocation() const { return LClose; } 00405 SourceRange getRange() const { return SourceRange(LOpen, LClose); } 00406 00407 bool consumeOpen() { 00408 if (!P.Tok.is(Kind)) 00409 return true; 00410 00411 if (getDepth() < P.getLangOpts().BracketDepth) { 00412 LOpen = (P.*Consumer)(); 00413 return false; 00414 } 00415 00416 return diagnoseOverflow(); 00417 } 00418 00419 bool expectAndConsume(unsigned DiagID = diag::err_expected, 00420 const char *Msg = "", 00421 tok::TokenKind SkipToTok = tok::unknown); 00422 bool consumeClose() { 00423 if (P.Tok.is(Close)) { 00424 LClose = (P.*Consumer)(); 00425 return false; 00426 } 00427 00428 return diagnoseMissingClose(); 00429 } 00430 void skipToEnd(); 00431 }; 00432 00433 } // end namespace clang 00434 00435 #endif