[cfe-commits] r103948 - in /cfe/trunk: lib/AST/Decl.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/CXX/temp/temp.decls/temp.friend/p4.cpp

Douglas Gregor dgregor at apple.com
Mon May 17 10:34:56 PDT 2010


Author: dgregor
Date: Mon May 17 12:34:56 2010
New Revision: 103948

URL: http://llvm.org/viewvc/llvm-project?rev=103948&view=rev
Log:
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.

Modified:
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p4.cpp

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=103948&r1=103947&r2=103948&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Mon May 17 12:34:56 2010
@@ -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()) {

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=103948&r1=103947&r2=103948&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon May 17 12:34:56 2010
@@ -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()) {

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=103948&r1=103947&r2=103948&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon May 17 12:34:56 2010
@@ -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;
     }
 

Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p4.cpp?rev=103948&r1=103947&r2=103948&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p4.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.friend/p4.cpp Mon May 17 12:34:56 2010
@@ -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;}





More information about the cfe-commits mailing list