Introduce a sequence number into class template partial
specializations, which keeps track of the order in which they were
originally declared. We use this number so that we can always walk the
list of partial specializations in a predictable order during matching
or template instantiation. This also fixes a failure in Boost.Proto,
where SourceManager::isBeforeInTranslationUnit was behaving
poorly in inconsistent ways.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102693 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h
index 2bb971d..1ec38ba 100644
--- a/include/clang/AST/DeclTemplate.h
+++ b/include/clang/AST/DeclTemplate.h
@@ -1011,6 +1011,11 @@
   TemplateArgumentLoc *ArgsAsWritten;
   unsigned NumArgsAsWritten;
 
+  /// \brief Sequence number indicating when this class template partial
+  /// specialization was added to the set of partial specializations for
+  /// its owning class template.
+  unsigned SequenceNumber;
+    
   /// \brief The class template partial specialization from which this 
   /// class template partial specialization was instantiated.
   ///
@@ -1026,13 +1031,15 @@
                                          TemplateArgumentListBuilder &Builder,
                                          TemplateArgumentLoc *ArgInfos,
                                          unsigned NumArgInfos,
-                               ClassTemplatePartialSpecializationDecl *PrevDecl)
+                               ClassTemplatePartialSpecializationDecl *PrevDecl,
+                                         unsigned SequenceNumber)
     : ClassTemplateSpecializationDecl(Context,
                                       ClassTemplatePartialSpecialization,
                                       DC, L, SpecializedTemplate, Builder,
                                       PrevDecl),
       TemplateParams(Params), ArgsAsWritten(ArgInfos),
-      NumArgsAsWritten(NumArgInfos), InstantiatedFromMember(0, false) { }
+      NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber),
+      InstantiatedFromMember(0, false) { }
 
 public:
   static ClassTemplatePartialSpecializationDecl *
@@ -1042,7 +1049,8 @@
          TemplateArgumentListBuilder &Builder,
          const TemplateArgumentListInfo &ArgInfos,
          QualType CanonInjectedType,
-         ClassTemplatePartialSpecializationDecl *PrevDecl);
+         ClassTemplatePartialSpecializationDecl *PrevDecl,
+         unsigned SequenceNumber);
 
   /// Get the list of template parameters
   TemplateParameterList *getTemplateParameters() const {
@@ -1059,6 +1067,10 @@
     return NumArgsAsWritten;
   }
 
+  /// \brief Get the sequence number for this class template partial
+  /// specialization.
+  unsigned getSequenceNumber() const { return SequenceNumber; }
+    
   /// \brief Retrieve the member class template partial specialization from
   /// which this particular class template partial specialization was
   /// instantiated.
@@ -1226,6 +1238,10 @@
     return CommonPtr->PartialSpecializations;
   }
 
+  /// \brief Retrieve the partial specializations as an ordered list.
+  void getPartialSpecializations(
+          llvm::SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS);
+  
   /// \brief Find a class template partial specialization with the given
   /// type T.
   ///
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index e3d30a0..c498dea 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -178,6 +178,20 @@
   C.Deallocate((void*)this);
 }
 
+void ClassTemplateDecl::getPartialSpecializations(
+          llvm::SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS) {
+  llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> &PartialSpecs
+    = CommonPtr->PartialSpecializations;
+  PS.clear();
+  PS.resize(PartialSpecs.size());
+  for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
+       P = PartialSpecs.begin(), PEnd = PartialSpecs.end();
+       P != PEnd; ++P) {
+    assert(!PS[P->getSequenceNumber()]);
+    PS[P->getSequenceNumber()] = &*P;
+  }
+}
+
 ClassTemplatePartialSpecializationDecl *
 ClassTemplateDecl::findPartialSpecialization(QualType T) {
   ASTContext &Context = getASTContext();
@@ -456,7 +470,8 @@
        TemplateArgumentListBuilder &Builder,
        const TemplateArgumentListInfo &ArgInfos,
        QualType CanonInjectedType,
-       ClassTemplatePartialSpecializationDecl *PrevDecl) {
+       ClassTemplatePartialSpecializationDecl *PrevDecl,
+       unsigned SequenceNumber) {
   unsigned N = ArgInfos.size();
   TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N];
   for (unsigned I = 0; I != N; ++I)
@@ -468,7 +483,8 @@
                                                           SpecializedTemplate,
                                                           Builder,
                                                           ClonedArgs, N,
-                                                          PrevDecl);
+                                                          PrevDecl,
+                                                          SequenceNumber);
   Result->setSpecializationKind(TSK_ExplicitSpecialization);
 
   Context.getInjectedClassNameType(Result, CanonInjectedType);
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 70a92ca..a84ceab 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -3781,6 +3781,8 @@
     // Create a new class template partial specialization declaration node.
     ClassTemplatePartialSpecializationDecl *PrevPartial
       = cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl);
+    unsigned SequenceNumber = PrevPartial? PrevPartial->getSequenceNumber()
+                            : ClassTemplate->getPartialSpecializations().size();
     ClassTemplatePartialSpecializationDecl *Partial
       = ClassTemplatePartialSpecializationDecl::Create(Context,
                                              ClassTemplate->getDeclContext(),
@@ -3790,7 +3792,8 @@
                                                        Converted,
                                                        TemplateArgs,
                                                        CanonType,
-                                                       PrevPartial);
+                                                       PrevPartial,
+                                                       SequenceNumber);
     SetNestedNameSpecifier(Partial, SS);
 
     if (PrevPartial) {
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 7dee0ad..a75a80b 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1278,21 +1278,20 @@
   typedef std::pair<ClassTemplatePartialSpecializationDecl *,
                     TemplateArgumentList *> MatchResult;
   llvm::SmallVector<MatchResult, 4> Matched;
-  for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
-         Partial = Template->getPartialSpecializations().begin(),
-         PartialEnd = Template->getPartialSpecializations().end();
-       Partial != PartialEnd;
-       ++Partial) {
+  llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
+  Template->getPartialSpecializations(PartialSpecs);
+  for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) {
+    ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I];
     TemplateDeductionInfo Info(Context, PointOfInstantiation);
     if (TemplateDeductionResult Result
-          = DeduceTemplateArguments(&*Partial,
+          = DeduceTemplateArguments(Partial,
                                     ClassTemplateSpec->getTemplateArgs(),
                                     Info)) {
       // FIXME: Store the failed-deduction information for use in
       // diagnostics, later.
       (void)Result;
     } else {
-      Matched.push_back(std::make_pair(&*Partial, Info.take()));
+      Matched.push_back(std::make_pair(Partial, Info.take()));
     }
   }
 
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 4575d47..25ba282 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -620,21 +620,6 @@
   return 0;
 }
 
-namespace {
-  class SortDeclByLocation {
-    SourceManager &SourceMgr;
-    
-  public:
-    explicit SortDeclByLocation(SourceManager &SourceMgr) 
-      : SourceMgr(SourceMgr) { }
-    
-    bool operator()(const Decl *X, const Decl *Y) const {
-      return SourceMgr.isBeforeInTranslationUnit(X->getLocation(),
-                                                 Y->getLocation());
-    }
-  };
-}
-
 Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) {
   bool isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
 
@@ -791,19 +776,10 @@
   
   Owner->addDecl(Inst);
   
-  // First, we sort the partial specializations by location, so 
-  // that we instantiate them in the order they were declared.
-  llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
-  for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator
-         P = D->getPartialSpecializations().begin(), 
-         PEnd = D->getPartialSpecializations().end();
-       P != PEnd; ++P)
-    PartialSpecs.push_back(&*P);
-  std::sort(PartialSpecs.begin(), PartialSpecs.end(),
-            SortDeclByLocation(SemaRef.SourceMgr));
-  
   // Instantiate all of the partial specializations of this member class 
   // template.
+  llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> PartialSpecs;
+  D->getPartialSpecializations(PartialSpecs);
   for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I)
     InstantiateClassTemplatePartialSpecialization(Inst, PartialSpecs[I]);
   
@@ -1768,7 +1744,8 @@
                                                      Converted,
                                                      InstTemplateArgs,
                                                      CanonType,
-                                                     0);
+                                                     0,
+                             ClassTemplate->getPartialSpecializations().size());
   // Substitute the nested name specifier, if any.
   if (SubstQualifier(PartialSpec, InstPartialSpec))
     return 0;