]> granicus.if.org Git - clang/commitdiff
Support befriending members of class template specializations.
authorJohn McCall <rjmccall@apple.com>
Tue, 13 Apr 2010 20:37:33 +0000 (20:37 +0000)
committerJohn McCall <rjmccall@apple.com>
Tue, 13 Apr 2010 20:37:33 +0000 (20:37 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101173 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaTemplate.cpp
test/CXX/class.access/class.friend/p1.cpp

index 0b42e8dba1ee8ff854d642a00bc7c158e6161d5a..c9976302139d8a2b72088c34ca2282a119962294 100644 (file)
@@ -2771,6 +2771,7 @@ public:
                                           const CXXScopeSpec &SS,
                                           TemplateParameterList **ParamLists,
                                           unsigned NumParamLists,
+                                          bool IsFriend,
                                           bool &IsExplicitSpecialization);
 
   DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
index 675cc36346d2b68f0ea18f9f84984e726a7b5220..ab61487b68b322d1ad4bbed92564382338163f30 100644 (file)
@@ -2393,6 +2393,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
                                                   D.getCXXScopeSpec(),
                         (TemplateParameterList**)TemplateParamLists.get(),
                                                    TemplateParamLists.size(),
+                                                  /*never a friend*/ false,
                                                   isExplicitSpecialization)) {
     if (TemplateParams->size() > 0) {
       // There is no such thing as a variable template.
@@ -2943,6 +2944,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
                                   D.getCXXScopeSpec(),
                            (TemplateParameterList**)TemplateParamLists.get(),
                                                   TemplateParamLists.size(),
+                                                  isFriend,
                                                   isExplicitSpecialization)) {
     if (TemplateParams->size() > 0) {
       // This is a function template
@@ -3041,10 +3043,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
     if (FunctionTemplate) {
       FunctionTemplate->setObjectOfFriendDecl(false);
       FunctionTemplate->setAccess(AS_public);
-    } else {
-      NewFD->setObjectOfFriendDecl(false);
     }
-
+    NewFD->setObjectOfFriendDecl(false);
     NewFD->setAccess(AS_public);
   }
 
@@ -3198,10 +3198,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
       NewFD->setInvalidDecl();
   }
 
-  // Make sure this is set before checking the function declaration.
-  // We'll override the visibility type later.
-  if (isFriend) NewFD->setObjectOfFriendDecl(false);
-    
   // Perform semantic checking on the function declaration.
   bool OverloadableAttrRequired = false; // FIXME: HACK!
   CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization,
@@ -4766,6 +4762,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
           = MatchTemplateParametersToScopeSpecifier(KWLoc, SS,
                         (TemplateParameterList**)TemplateParameterLists.get(),
                                               TemplateParameterLists.size(),
+                                                    TUK == TUK_Friend,
                                                     isExplicitSpecialization)) {
       if (TemplateParams->size() > 0) {
         // This is a declaration or definition of a class template (which may
index 828085b8bc2d005f08182f07e156364e22297c9d..9816e76530bc208169453d904a26364afa7b80f5 100644 (file)
@@ -1229,6 +1229,10 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
 ///
 /// \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 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
                                               const CXXScopeSpec &SS,
                                           TemplateParameterList **ParamLists,
                                               unsigned NumParamLists,
+                                              bool IsFriend,
                                               bool &IsExplicitSpecialization) {
   IsExplicitSpecialization = false;
   
@@ -1308,6 +1313,13 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc,
     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 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
     = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS,
                         (TemplateParameterList**)TemplateParameterLists.get(),
                                               TemplateParameterLists.size(),
+                                              TUK == TUK_Friend,
                                               isExplicitSpecialization);
   if (TemplateParams && TemplateParams->size() > 0) {
     isPartialSpecialization = true;
@@ -4302,7 +4315,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
 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 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
     // 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) {
index 991f611cdd8ddf83f48c99e189295d8822fea578..8dffd1dd86dddb152fa137025a91f40ac2feb2df 100644 (file)
@@ -222,3 +222,37 @@ namespace test6 {
     friend A &A::operator=(const A&);
   };
 }
+
+namespace test7 {
+  template <class T> struct X {
+    X();
+    ~X();
+    void foo();
+    void bar();
+  };
+
+  class A {
+    friend void X<int>::foo();
+    friend X<int>::X();
+    friend X<int>::X(const X&);
+
+  private:
+    A(); // expected-note 2 {{declared private here}}
+  };
+
+  template<> void X<int>::foo() {
+    A a;
+  }
+
+  template<> void X<int>::bar() {
+    A a; // expected-error {{calling a private constructor}}
+  }
+
+  template<> X<int>::X() {
+    A a;
+  }
+
+  template<> X<int>::~X() {
+    A a; // expected-error {{calling a private constructor}}
+  }
+}