From 393f4e7615b1f08b4cb878f318a0da7bf5b639ca Mon Sep 17 00:00:00 2001
From: Vassil Vassilev <vvasilev@cern.ch>
Date: Tue, 10 Dec 2013 10:52:00 +0100
Subject: [PATCH] Remove 'properly' the function template specializations.

---
 .../cling/lib/Interpreter/ASTNodeEraser.cpp   | 49 +++++++++++++------
 1 file changed, 33 insertions(+), 16 deletions(-)

diff --git a/interpreter/cling/lib/Interpreter/ASTNodeEraser.cpp b/interpreter/cling/lib/Interpreter/ASTNodeEraser.cpp
index 312b84146cc..4212d52007d 100644
--- a/interpreter/cling/lib/Interpreter/ASTNodeEraser.cpp
+++ b/interpreter/cling/lib/Interpreter/ASTNodeEraser.cpp
@@ -435,25 +435,43 @@ namespace cling {
     class FunctionTemplateDeclExt : public FunctionTemplateDecl {
     public:
       static void removeSpecialization(FunctionTemplateDecl* self, 
-                                const FunctionTemplateSpecializationInfo* info) {
-        assert(self && "Cannot be null!");
-        typedef llvm::SmallVector<FunctionTemplateSpecializationInfo*,4> Vector;
+                                       const FunctionDecl* specialization) {
+        assert(self && specialization && "Cannot be null!");
+        typedef llvm::SmallVector<FunctionDecl*, 4> Specializations;
         typedef llvm::FoldingSetVector< FunctionTemplateSpecializationInfo> Set;
+
         FunctionTemplateDeclExt* This = (FunctionTemplateDeclExt*) self;
-        Vector specInfos;
-        Set specs = This->getSpecializations();
-        // Copy the addresses and then cleanup the list of specializations.
-        for(Set::iterator I = specs.begin(), E = specs.end(); I != E; ++I)
-          specInfos.push_back(&*I);
+        Specializations specializations;
+        const Set& specs = This->getSpecializations();
+
+        if (!specs.size()) // nothing to remove
+          return;
+
+        // Collect all the specializations without the one to remove.
+        for(Set::const_iterator I = specs.begin(),E = specs.end(); I != E; ++I){
+          assert(I->Function && "Must have a specialization.");
+          if (I->Function != specialization)
+            specializations.push_back(I->Function);
+        }
+
         This->getSpecializations().clear();
 
-        //Append the new list of specializations.
+        //Readd the collected specializations.
         void* InsertPos = 0;
-        for (size_t i = 0, e = specInfos.size(); i < e; ++i)
-          if (specInfos[i] != info) {
-            specInfos[i]->SetNextInBucket(0); // reset the next in bucket.
-            This->addSpecialization(specInfos[i], InsertPos);
-          }
+        FunctionTemplateSpecializationInfo* FTSI = 0;
+        for (size_t i = 0, e = specializations.size(); i < e; ++i) {
+          FTSI = specializations[i]->getTemplateSpecializationInfo();
+          assert(FTSI && "Must not be null.");
+          // Avoid assertion on add.
+          FTSI->SetNextInBucket(0);
+          This->addSpecialization(FTSI, InsertPos);
+        }
+#ifndef NDEBUG
+        const TemplateArgumentList* args
+          = specialization->getTemplateSpecializationArgs();
+        assert(!self->findSpecialization(args->data(), args->size(),  InsertPos)
+               && "Finds the removed decl again!");
+#endif
       }
     };
 
@@ -464,8 +482,7 @@ namespace cling {
       FunctionDecl* CanFD = FD->getCanonicalDecl();
       FunctionTemplateDecl* FTD
         = FD->getTemplateSpecializationInfo()->getTemplate();
-      FunctionTemplateDeclExt::removeSpecialization(FTD, 
-                                         CanFD->getTemplateSpecializationInfo());
+      FunctionTemplateDeclExt::removeSpecialization(FTD, CanFD);
     }
 
     return Successful;
-- 
GitLab