diff options
author | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2011-06-22 06:09:49 +0000 |
---|---|---|
committer | Argyrios Kyrtzidis <akyrtzi@gmail.com> | 2011-06-22 06:09:49 +0000 |
commit | 25a767651d14db87aa03dd5fe3e011d877dd4100 (patch) | |
tree | a4be9c9ef892b9807686250089b35afb71863238 | |
parent | fc0f40acc6877c2d1fa7e50decd8ec330a3569a4 (diff) |
Introduce DelayedCleanupPool useful for simplifying clean-up of certain resources that, while their
lifetime is well-known and restricted, cleaning them up manually is easy to miss and cause a leak.
Use it to plug the leaking of TemplateIdAnnotation objects. rdar://9634138.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133610 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DelayedCleanupPool.h | 109 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 12 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 6 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 13 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 6 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 11 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 4 | ||||
-rw-r--r-- | lib/Parse/ParseTentative.cpp | 3 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 21 | ||||
-rw-r--r-- | lib/Sema/DeclSpec.cpp | 3 |
10 files changed, 147 insertions, 41 deletions
diff --git a/include/clang/Basic/DelayedCleanupPool.h b/include/clang/Basic/DelayedCleanupPool.h new file mode 100644 index 0000000000..843205f7b0 --- /dev/null +++ b/include/clang/Basic/DelayedCleanupPool.h @@ -0,0 +1,109 @@ +//=== DelayedCleanupPool.h - Delayed Clean-up Pool Implementation *- C++ -*===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a facility to delay calling cleanup methods until specific +// points. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_DELAYEDCLEANUPPOOL_H +#define LLVM_CLANG_BASIC_DELAYEDCLEANUPPOOL_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" + +namespace clang { + +/// \brief Gathers pairs of pointer-to-object/pointer-to-cleanup-function +/// allowing the cleanup functions to get called (with the pointer as parameter) +/// at specific points. +/// +/// The use case is to simplify clean-up of certain resources that, while their +/// lifetime is well-known and restricted, cleaning them up manually is easy to +/// miss and cause a leak. +/// +/// The same pointer can be added multiple times; its clean-up function will +/// only be called once. +class DelayedCleanupPool { +public: + typedef void (*CleanupFn)(void *ptr); + + /// \brief Adds a pointer and its associated cleanup function to be called + /// at a later point. + /// + /// \returns false if the pointer is already added, true otherwise. + bool delayCleanup(void *ptr, CleanupFn fn) { + assert(ptr && "Expected valid pointer to object"); + assert(fn && "Expected valid pointer to function"); + + CleanupFn &mapFn = Ptrs[ptr]; + assert((!mapFn || mapFn == fn) && + "Adding a pointer with different cleanup function!"); + + if (!mapFn) { + mapFn = fn; + Cleanups.push_back(std::make_pair(ptr, fn)); + return true; + } + + return false; + } + + template <typename T> + bool delayDelete(T *ptr) { + return delayCleanup(ptr, cleanupWithDelete<T>); + } + + template <typename T, void (T::*Fn)()> + bool delayMemberFunc(T *ptr) { + return delayCleanup(ptr, cleanupWithMemberFunc<T, Fn>); + } + + void doCleanup() { + for (llvm::SmallVector<std::pair<void *, CleanupFn>, 8>::reverse_iterator + I = Cleanups.rbegin(), E = Cleanups.rend(); I != E; ++I) + I->second(I->first); + Cleanups.clear(); + Ptrs.clear(); + } + + ~DelayedCleanupPool() { + doCleanup(); + } + +private: + llvm::DenseMap<void *, CleanupFn> Ptrs; + llvm::SmallVector<std::pair<void *, CleanupFn>, 8> Cleanups; + + template <typename T> + static void cleanupWithDelete(void *ptr) { + delete static_cast<T *>(ptr); + } + + template <typename T, void (T::*Fn)()> + static void cleanupWithMemberFunc(void *ptr) { + (static_cast<T *>(ptr)->*Fn)(); + } +}; + +/// \brief RAII object for triggering a cleanup of a DelayedCleanupPool. +class DelayedCleanupPoint { + DelayedCleanupPool &Pool; + +public: + DelayedCleanupPoint(DelayedCleanupPool &pool) : Pool(pool) { } + + ~DelayedCleanupPoint() { + Pool.doCleanup(); + } +}; + +} // end namespace clang + +#endif diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index cb8df4c938..0b0946c010 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_PARSE_PARSER_H #include "clang/Basic/Specifiers.h" +#include "clang/Basic/DelayedCleanupPool.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/CodeCompletionHandler.h" #include "clang/Sema/Sema.h" @@ -170,6 +171,10 @@ class Parser : public CodeCompletionHandler { /// Factory object for creating AttributeList objects. AttributeFactory AttrFactory; + /// \brief Gathers and cleans up objects when parsing of a top-level + /// declaration is finished. + DelayedCleanupPool TopLevelDeclCleanupPool; + public: Parser(Preprocessor &PP, Sema &Actions); ~Parser(); @@ -467,7 +472,12 @@ private: bool TryAltiVecTokenOutOfLine(DeclSpec &DS, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, bool &isInvalid); - + + /// \brief Get the TemplateIdAnnotation from the token and put it in the + /// cleanup pool so that it gets destroyed when parsing the current top level + /// declaration is finished. + TemplateIdAnnotation *takeTemplateIdAnnotation(const Token &tok); + /// TentativeParsingAction - An object that is used as a kind of "tentative /// parsing transaction". It gets instantiated to mark the token position and /// after the token consumption is done, Commit() or Revert() is called to diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 9af7345fdd..99441e0e0e 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -1396,8 +1396,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // Thus, if the template-name is actually the constructor // name, then the code is ill-formed; this interpretation is // reinforced by the NAD status of core issue 635. - TemplateIdAnnotation *TemplateId - = static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue()); + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next); if ((DSContext == DSC_top_level || (DSContext == DSC_class && DS.isFriendSpecified())) && TemplateId->Name && @@ -1599,8 +1598,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // type-name case tok::annot_template_id: { - TemplateIdAnnotation *TemplateId - = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); if (TemplateId->Kind != TNK_Type_template) { // This template-id does not refer to a type name, so we're // done with the type-specifiers. diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 640e50176b..36eb011bc0 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -701,8 +701,7 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, CXXScopeSpec &SS) { // Check whether we have a template-id that names a type. if (Tok.is(tok::annot_template_id)) { - TemplateIdAnnotation *TemplateId - = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); if (TemplateId->Kind == TNK_Type_template || TemplateId->Kind == TNK_Dependent_template_name) { AnnotateTemplateIdTokenAsType(); @@ -976,7 +975,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } } } else if (Tok.is(tok::annot_template_id)) { - TemplateId = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + TemplateId = takeTemplateIdAnnotation(Tok); NameLoc = ConsumeToken(); if (TemplateId->Kind != TNK_Type_template && @@ -993,7 +992,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, DS.SetTypeSpecError(); SkipUntil(tok::semi, false, true); - TemplateId->Destroy(); if (SuppressingAccessChecks) Actions.ActOnStopSuppressingAccessChecks(); @@ -1051,9 +1049,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } SkipUntil(tok::comma, true); - - if (TemplateId) - TemplateId->Destroy(); return; } @@ -1149,7 +1144,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateParams? &(*TemplateParams)[0] : 0, TemplateParams? TemplateParams->size() : 0)); } - TemplateId->Destroy(); } else if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && TUK == Sema::TUK_Declaration) { // Explicit instantiation of a member of a class template @@ -2248,8 +2242,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { ParseOptionalCXXScopeSpecifier(SS, ParsedType(), false); ParsedType TemplateTypeTy; if (Tok.is(tok::annot_template_id)) { - TemplateIdAnnotation *TemplateId - = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); if (TemplateId->Kind == TNK_Type_template || TemplateId->Kind == TNK_Dependent_template_name) { AnnotateTemplateIdTokenAsType(); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 39db0e9045..154d8fd809 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -955,8 +955,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, Token Next = NextToken(); if (Next.is(tok::annot_template_id)) { - TemplateIdAnnotation *TemplateId - = static_cast<TemplateIdAnnotation *>(Next.getAnnotationValue()); + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Next); if (TemplateId->Kind == TNK_Type_template) { // We have a qualified template-id that we know refers to a // type, translate it into a type and continue parsing as a @@ -975,8 +974,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, } case tok::annot_template_id: { // [C++] template-id - TemplateIdAnnotation *TemplateId - = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); if (TemplateId->Kind == TNK_Type_template) { // We have a template-id that we know refers to a type, // translate it into a type and continue parsing as a cast diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index eab7114284..7af39aec5f 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -245,8 +245,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // So we need to check whether the simple-template-id is of the // right kind (it should name a type or be dependent), and then // convert it into a type within the nested-name-specifier. - TemplateIdAnnotation *TemplateId - = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); if (CheckForDestructor && GetLookAheadToken(2).is(tok::tilde)) { *MayBePseudoDestructor = true; return false; @@ -281,10 +280,6 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, SS.SetInvalid(SourceRange(StartLoc, CCLoc)); } - // If we are caching tokens we will process the TemplateId again, - // otherwise destroy it. - if (!PP.isBacktrackEnabled()) - TemplateId->Destroy(); continue; } @@ -1606,8 +1601,7 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, // unqualified-id: // template-id (already parsed and annotated) if (Tok.is(tok::annot_template_id)) { - TemplateIdAnnotation *TemplateId - = static_cast<TemplateIdAnnotation*>(Tok.getAnnotationValue()); + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); // If the template-name names the current class, then this is a constructor if (AllowConstructorName && TemplateId->Name && @@ -1630,7 +1624,6 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext, /*NontrivialTypeSourceInfo=*/true), TemplateId->TemplateNameLoc, TemplateId->RAngleLoc); - TemplateId->Destroy(); ConsumeToken(); return false; } diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index aa89d75c6d..9eab40a3ec 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -861,8 +861,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, void Parser::AnnotateTemplateIdTokenAsType() { assert(Tok.is(tok::annot_template_id) && "Requires template-id tokens"); - TemplateIdAnnotation *TemplateId - = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); assert((TemplateId->Kind == TNK_Type_template || TemplateId->Kind == TNK_Dependent_template_name) && "Only works for type and dependent templates"); @@ -888,7 +887,6 @@ void Parser::AnnotateTemplateIdTokenAsType() { // Replace the template-id annotation token, and possible the scope-specifier // that precedes it, with the typename annotation token. PP.AnnotateCachedTokens(Tok); - TemplateId->Destroy(); } /// \brief Determine whether the given token can end a template argument. diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 78d2c9091b..2ba0fc673f 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -908,8 +908,7 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() { return TPResult::True(); case tok::annot_template_id: { - TemplateIdAnnotation *TemplateId - = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); if (TemplateId->Kind != TNK_Type_template) return TPResult::False(); CXXScopeSpec SS; diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index f19472ccdc..1089d2309a 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -486,6 +486,7 @@ void Parser::Initialize() { /// ParseTopLevelDecl - Parse one top-level declaration, return whatever the /// action tells us to. This returns true if the EOF was encountered. bool Parser::ParseTopLevelDecl(DeclGroupPtrTy &Result) { + DelayedCleanupPoint CleanupRAII(TopLevelDeclCleanupPool); while (Tok.is(tok::annot_pragma_unused)) HandlePragmaUnused(); @@ -548,6 +549,7 @@ void Parser::ParseTranslationUnit() { Parser::DeclGroupPtrTy Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, ParsingDeclSpec *DS) { + DelayedCleanupPoint CleanupRAII(TopLevelDeclCleanupPool); ParenBraceBracketBalancer BalancerRAIIObj(*this); Decl *SingleDecl = 0; @@ -1155,6 +1157,18 @@ Parser::ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) { return move(Result); } +/// \brief Get the TemplateIdAnnotation from the token and put it in the +/// cleanup pool so that it gets destroyed when parsing the current top level +/// declaration is finished. +TemplateIdAnnotation *Parser::takeTemplateIdAnnotation(const Token &tok) { + assert(tok.is(tok::annot_template_id) && "Expected template-id token"); + TemplateIdAnnotation * + Id = static_cast<TemplateIdAnnotation *>(tok.getAnnotationValue()); + TopLevelDeclCleanupPool.delayMemberFunc< TemplateIdAnnotation, + &TemplateIdAnnotation::Destroy>(Id); + return Id; +} + /// TryAnnotateTypeOrScopeToken - If the current token position is on a /// typename (possibly qualified in C++) or a C++ scope specifier not followed /// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens @@ -1209,8 +1223,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { *Tok.getIdentifierInfo(), Tok.getLocation()); } else if (Tok.is(tok::annot_template_id)) { - TemplateIdAnnotation *TemplateId - = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); if (TemplateId->Kind == TNK_Function_template) { Diag(Tok, diag::err_typename_refers_to_non_type_template) << Tok.getAnnotationRange(); @@ -1228,7 +1241,6 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { TemplateId->LAngleLoc, TemplateArgsPtr, TemplateId->RAngleLoc); - TemplateId->Destroy(); } else { Diag(Tok, diag::err_expected_type_name_after_typename) << SS.getRange(); @@ -1311,8 +1323,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext) { } if (Tok.is(tok::annot_template_id)) { - TemplateIdAnnotation *TemplateId - = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); if (TemplateId->Kind == TNK_Type_template) { // A template-id that refers to a type was parsed into a // template-id annotation in a context where we weren't allowed diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index 5be16e7431..f1e8b4ef9c 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -792,9 +792,6 @@ bool DeclSpec::isMissingDeclaratorOk() { } void UnqualifiedId::clear() { - if (Kind == IK_TemplateId) - TemplateId->Destroy(); - Kind = IK_Identifier; Identifier = 0; StartLocation = SourceLocation(); |