[cfe-commits] r99610 - in /cfe/trunk: lib/Sema/SemaAccess.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/CXX/class.access/class.friend/p1.cpp test/CXX/temp/temp.decls/temp.friend/p1.cpp

John McCall rjmccall at apple.com
Thu Mar 25 21:53:08 PDT 2010


Author: rjmccall
Date: Thu Mar 25 23:53:08 2010
New Revision: 99610

URL: http://llvm.org/viewvc/llvm-project?rev=99610&view=rev
Log:
Reapply r99596 with a fix:  link an instantiated friend function to its
pattern if it has a body.


Modified:
    cfe/trunk/lib/Sema/SemaAccess.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/CXX/class.access/class.friend/p1.cpp
    cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp

Modified: cfe/trunk/lib/Sema/SemaAccess.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaAccess.cpp?rev=99610&r1=99609&r2=99610&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaAccess.cpp (original)
+++ cfe/trunk/lib/Sema/SemaAccess.cpp Thu Mar 25 23:53:08 2010
@@ -319,7 +319,7 @@
   if (Friend == FTD->getCanonicalDecl())
     return Sema::AR_accessible;
 
-  if (MightInstantiateTo(S, FTD, Friend))
+  if (EC.isDependent() && MightInstantiateTo(S, FTD, Friend))
     return Sema::AR_dependent;
 
   return Sema::AR_inaccessible;

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=99610&r1=99609&r2=99610&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Mar 25 23:53:08 2010
@@ -904,8 +904,15 @@
   // Check whether there is already a function template specialization for
   // this declaration.
   FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
+
+  bool isFriend;
+  if (FunctionTemplate)
+    isFriend = (FunctionTemplate->getFriendObjectKind() != Decl::FOK_None);
+  else
+    isFriend = (D->getFriendObjectKind() != Decl::FOK_None);
+
   void *InsertPos = 0;
-  if (FunctionTemplate && !TemplateParams) {
+  if (!isFriend && FunctionTemplate && !TemplateParams) {
     llvm::FoldingSetNodeID ID;
     FunctionTemplateSpecializationInfo::Profile(ID,
                              TemplateArgs.getInnermost().getFlatArgumentList(),
@@ -933,14 +940,29 @@
     return 0;
   QualType T = TInfo->getType();
 
+  NestedNameSpecifier *Qualifier = D->getQualifier();
+  if (Qualifier) {
+    Qualifier = SemaRef.SubstNestedNameSpecifier(Qualifier,
+                                                 D->getQualifierRange(),
+                                                 TemplateArgs);
+    if (!Qualifier) return 0;
+  }
+
   // If we're instantiating a local function declaration, put the result
   // in the owner;  otherwise we need to find the instantiated context.
   DeclContext *DC;
   if (D->getDeclContext()->isFunctionOrMethod())
     DC = Owner;
-  else
+  else if (isFriend && Qualifier) {
+    CXXScopeSpec SS;
+    SS.setScopeRep(Qualifier);
+    SS.setRange(D->getQualifierRange());
+    DC = SemaRef.computeDeclContext(SS);
+    if (!DC) return 0;
+  } else {
     DC = SemaRef.FindInstantiatedContext(D->getLocation(), D->getDeclContext(), 
                                          TemplateArgs);
+  }
 
   FunctionDecl *Function =
       FunctionDecl::Create(SemaRef.Context, DC, D->getLocation(),
@@ -948,9 +970,8 @@
                            D->getStorageClass(),
                            D->isInlineSpecified(), D->hasWrittenPrototype());
 
-  // Substitute the nested name specifier, if any.
-  if (SubstQualifier(D, Function))
-    return 0;
+  if (Qualifier)
+    Function->setQualifierInfo(Qualifier, D->getQualifierRange());
 
   Function->setLexicalDeclContext(Owner);
 
@@ -974,17 +995,28 @@
     // which means substituting int for T, but leaving "f" as a friend function
     // template.
     // Build the function template itself.
-    FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, Owner,
+    FunctionTemplate = FunctionTemplateDecl::Create(SemaRef.Context, DC,
                                                     Function->getLocation(),
                                                     Function->getDeclName(),
                                                     TemplateParams, Function);
     Function->setDescribedFunctionTemplate(FunctionTemplate);
     FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext());
+
+    if (isFriend && D->isThisDeclarationADefinition()) {
+      // TODO: should we remember this connection regardless of whether
+      // the friend declaration provided a body?
+      FunctionTemplate->setInstantiatedFromMemberTemplate(
+                                           D->getDescribedFunctionTemplate());
+    }
   } else if (FunctionTemplate) {
     // Record this function template specialization.
     Function->setFunctionTemplateSpecialization(FunctionTemplate,
                                                 &TemplateArgs.getInnermost(),
                                                 InsertPos);
+  } else if (isFriend && D->isThisDeclarationADefinition()) {
+    // TODO: should we remember this connection regardless of whether
+    // the friend declaration provided a body?
+    Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
   }
     
   if (InitFunctionInstantiation(Function, D))
@@ -1016,9 +1048,7 @@
 
   // If the original function was part of a friend declaration,
   // inherit its namespace state and add it to the owner.
-  NamedDecl *FromFriendD 
-      = TemplateParams? cast<NamedDecl>(D->getDescribedFunctionTemplate()) : D;
-  if (FromFriendD->getFriendObjectKind()) {
+  if (isFriend) {
     NamedDecl *ToFriendD = 0;
     NamedDecl *PrevDecl;
     if (TemplateParams) {
@@ -1029,11 +1059,7 @@
       PrevDecl = Function->getPreviousDeclaration();
     }
     ToFriendD->setObjectOfFriendDecl(PrevDecl != NULL);
-    if (!Owner->isDependentContext() && !PrevDecl)
-      DC->makeDeclVisibleInContext(ToFriendD, /* Recoverable = */ false);
-
-    if (!TemplateParams)
-      Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
+    DC->makeDeclVisibleInContext(ToFriendD, /*Recoverable=*/ false);
   }
 
   return Function;

Modified: cfe/trunk/test/CXX/class.access/class.friend/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/class.access/class.friend/p1.cpp?rev=99610&r1=99609&r2=99610&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class.access/class.friend/p1.cpp (original)
+++ cfe/trunk/test/CXX/class.access/class.friend/p1.cpp Thu Mar 25 23:53:08 2010
@@ -165,3 +165,18 @@
     return p->x; // expected-error {{'x' is a protected member of 'test3::A'}}
   }
 }
+
+namespace test4 {
+  template <class T> class Holder {
+    T object;
+    friend bool operator==(Holder &a, Holder &b) {
+      return a.object == b.object; // expected-error {{invalid operands to binary expression}}
+    }
+  };
+
+  struct Inequal {};
+  bool test() {
+    Holder<Inequal> a, b;
+    return a == b; // expected-note {{requested here}}
+  }
+}

Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp?rev=99610&r1=99609&r2=99610&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p1.cpp Thu Mar 25 23:53:08 2010
@@ -178,3 +178,16 @@
   };
   template class D<int>;
 }
+
+namespace test8 {
+  template <class N> class A {
+    static int x;
+    template <class T> friend void foo();
+  };
+  template class A<int>;
+
+  template <class T> void foo() {
+    A<int>::x = 0;
+  }
+  template void foo<int>();
+}





More information about the cfe-commits mailing list