Support befriending members of class template specializations.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101173 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 828085b..9816e76 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1229,6 +1229,10 @@
 ///
 /// \param NumParamLists the number of template parameter lists in ParamLists.
 ///
+/// \param IsFriend Whether to apply the slightly different rules for
+/// matching template parameters to scope specifiers in friend
+/// declarations.
+///
 /// \param IsExplicitSpecialization will be set true if the entity being
 /// declared is an explicit specialization, false otherwise.
 ///
@@ -1243,6 +1247,7 @@
                                               const CXXScopeSpec &SS,
                                           TemplateParameterList **ParamLists,
                                               unsigned NumParamLists,
+                                              bool IsFriend,
                                               bool &IsExplicitSpecialization) {
   IsExplicitSpecialization = false;
   
@@ -1308,6 +1313,13 @@
     if (Idx >= NumParamLists) {
       // We have a template-id without a corresponding template parameter
       // list.
+
+      // ...which is fine if this is a friend declaration.
+      if (IsFriend) {
+        IsExplicitSpecialization = true;
+        break;
+      }
+
       if (DependentTemplateId) {
         // FIXME: the location information here isn't great.
         Diag(SS.getRange().getBegin(),
@@ -3538,6 +3550,7 @@
     = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS,
                         (TemplateParameterList**)TemplateParameterLists.get(),
                                               TemplateParameterLists.size(),
+                                              TUK == TUK_Friend,
                                               isExplicitSpecialization);
   if (TemplateParams && TemplateParams->size() > 0) {
     isPartialSpecialization = true;
@@ -4302,7 +4315,7 @@
 bool 
 Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
   assert(!isa<TemplateDecl>(Member) && "Only for non-template members");
-         
+
   // Try to find the member we are instantiating.
   NamedDecl *Instantiation = 0;
   NamedDecl *InstantiatedFrom = 0;
@@ -4348,6 +4361,25 @@
     // this mismatch later.
     return false;
   }
+
+  // If this is a friend, just bail out here before we start turning
+  // things into explicit specializations.
+  if (Member->getFriendObjectKind() != Decl::FOK_None) {
+    // Preserve instantiation information.
+    if (InstantiatedFrom && isa<CXXMethodDecl>(Member)) {
+      cast<CXXMethodDecl>(Member)->setInstantiationOfMemberFunction(
+                                      cast<CXXMethodDecl>(InstantiatedFrom),
+        cast<CXXMethodDecl>(Instantiation)->getTemplateSpecializationKind());
+    } else if (InstantiatedFrom && isa<CXXRecordDecl>(Member)) {
+      cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass(
+                                      cast<CXXRecordDecl>(InstantiatedFrom),
+        cast<CXXRecordDecl>(Instantiation)->getTemplateSpecializationKind());
+    }
+
+    Previous.clear();
+    Previous.addDecl(Instantiation);
+    return false;
+  }
   
   // Make sure that this is a specialization of a member.
   if (!InstantiatedFrom) {