Determine when the instantiation of a friend function defined inside a
class template conflicts with an existing (non-template)
definition. This is another part of PR6952.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@103948 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp
index 28332bd..535bd34 100644
--- a/lib/AST/Decl.cpp
+++ b/lib/AST/Decl.cpp
@@ -1219,9 +1219,8 @@
 }
 
 bool FunctionDecl::isImplicitlyInstantiable() const {
-  // If this function already has a definition or is invalid, it can't be
-  // implicitly instantiated.
-  if (isInvalidDecl() || getBody())
+  // If the function is invalid, it can't be implicitly instantiated.
+  if (isInvalidDecl())
     return false;
   
   switch (getTemplateSpecializationKind()) {
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index b573e2d..5af5585 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -7527,7 +7527,7 @@
   if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
     // Implicit instantiation of function templates and member functions of
     // class templates.
-    if (!Function->getBody() && Function->isImplicitlyInstantiable()) {
+    if (Function->isImplicitlyInstantiable()) {
       bool AlreadyInstantiated = false;
       if (FunctionTemplateSpecializationInfo *SpecInfo
                                 = Function->getTemplateSpecializationInfo()) {
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 41c6218..3128407 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1983,11 +1983,29 @@
   if (Function->isInvalidDecl())
     return;
 
-  assert(!Function->getBody() && "Already instantiated!");
-
   // Never instantiate an explicit specialization.
   if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
     return;
+
+  const FunctionDecl *Definition = 0;
+  if (Function->getBody(Definition)) {
+    // We are trying to instantiate a friend function specialization inside
+    // a class template, but there is already another (non-template) definition
+    // of the same function.
+    if (Definition->getTemplateSpecializationKind() == TSK_Undeclared) {
+      InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
+      if (Inst)
+        return;  
+      
+      Diag(Function->getLocation(), diag::err_redefinition) 
+        << Function->getDeclName();
+      Diag(Definition->getLocation(), diag::note_previous_definition);
+    }
+    
+    // We have an explicit instantiation (which already occurred) and an
+    // implicit instantiation. Return without complaint.
+    return;
+  }
   
   // Find the function body that we'll be substituting.
   const FunctionDecl *PatternDecl = Function->getTemplateInstantiationPattern();
@@ -2680,8 +2698,7 @@
                                             Context.getSourceManager(),
                                            "instantiating function definition");
 
-      if (!Function->getBody())
-        InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true);
+      InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true);
       continue;
     }
 
diff --git a/test/CXX/temp/temp.decls/temp.friend/p4.cpp b/test/CXX/temp/temp.decls/temp.friend/p4.cpp
index 6490aeb..a1d7c69 100644
--- a/test/CXX/temp/temp.decls/temp.friend/p4.cpp
+++ b/test/CXX/temp/temp.decls/temp.friend/p4.cpp
@@ -7,3 +7,34 @@
 
 X<int> xi; // expected-note{{in instantiation of member function 'f' requested here}}
 
+void f0(double) { }
+void f0(int) { } // expected-note{{previous definition}}
+void f1(int) { } // expected-note{{previous definition}}
+void f2(int);
+void f3(int);
+
+template<typename T>
+struct X1 {
+  friend void f0(T) { } // expected-error{{redefinition of}}
+  friend void f1(T) { } // expected-error{{redefinition of}}
+  friend void f2(T) { } // expected-error{{redefinition of}}
+  friend void f3(T) { } // expected-error{{redefinition of}}
+  friend void f4(T) { } // expected-error{{redefinition of}}
+  friend void f5(T) { } // expected-error{{redefinition of}}
+
+  // FIXME: should have a redefinition error for f6(int)
+  friend void f6(int) { }
+};
+
+void f2(int) { } // expected-note{{previous definition}}
+void f4(int) { } // expected-note{{previous definition}}
+
+X1<int> x1a; // expected-note 6{{in instantiation of}}
+
+void f3(int) { } // expected-note{{previous definition}}
+void f5(int) { } // expected-note{{previous definition}}
+
+X1<float> x1b;
+
+
+X1<double> *X0d() { return 0;}