]> granicus.if.org Git - clang/commitdiff
Introduce DelayedCleanupPool useful for simplifying clean-up of certain resources...
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Wed, 22 Jun 2011 06:09:49 +0000 (06:09 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Wed, 22 Jun 2011 06:09:49 +0000 (06:09 +0000)
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

include/clang/Basic/DelayedCleanupPool.h [new file with mode: 0644]
include/clang/Parse/Parser.h
lib/Parse/ParseDecl.cpp
lib/Parse/ParseDeclCXX.cpp
lib/Parse/ParseExpr.cpp
lib/Parse/ParseExprCXX.cpp
lib/Parse/ParseTemplate.cpp
lib/Parse/ParseTentative.cpp
lib/Parse/Parser.cpp
lib/Sema/DeclSpec.cpp

diff --git a/include/clang/Basic/DelayedCleanupPool.h b/include/clang/Basic/DelayedCleanupPool.h
new file mode 100644 (file)
index 0000000..843205f
--- /dev/null
@@ -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
index cb8df4c938a82c3bc6509decb316c23d11e5cb8b..0b0946c0100c4caff8a133bc2ef320f0c1ad47e4 100644 (file)
@@ -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
index 9af7345fdd63a09c3bad6d806d983996832da1ce..99441e0e0e3fd4d0a82cfd8679d1ee179eb03450 100644 (file)
@@ -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.
index 640e50176bc3c3c471fbcbf067d220c443ad62d1..36eb011bc03521a5d2c28422be4557434ed7c3db 100644 (file)
@@ -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();
index 39db0e90450d4f3370a3cfc822e5f873f0394949..154d8fd80923548d40b1e107559fd500c94ec7e2 100644 (file)
@@ -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
index eab7114284defc7e17179d0c544f10e8ab937b46..7af39aec5f9a56a0b7da7fea2fe7d0d276a589d9 100644 (file)
@@ -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;
       }
index aa89d75c6d1beb8bbfb5ee43762a9d863fb79cc4..9eab40a3ecdfc84f9874212098a21741a92ea710 100644 (file)
@@ -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.
index 78d2c9091b1bad4a61307d2dd7fae61056ab5b1b..2ba0fc673f6703b1a9104f4bf86935981c2b78b5 100644 (file)
@@ -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;
index f19472ccdc041c4db2b565876b36eaa6a6bdf8ac..1089d2309aff7f1090338ded92a70bebbef3ebb3 100644 (file)
@@ -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
index 5be16e7431c1365e269b013bf477ee3343b01b0f..f1e8b4ef9cc3a32941d5e92653b7520f821b9033 100644 (file)
@@ -792,9 +792,6 @@ bool DeclSpec::isMissingDeclaratorOk() {
 }
 
 void UnqualifiedId::clear() {
-  if (Kind == IK_TemplateId)
-    TemplateId->Destroy();
-  
   Kind = IK_Identifier;
   Identifier = 0;
   StartLocation = SourceLocation();