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

Douglas Gregor dgregor at apple.com
Mon May 17 22:45:02 PDT 2010


Author: dgregor
Date: Tue May 18 00:45:02 2010
New Revision: 104014

URL: http://llvm.org/viewvc/llvm-project?rev=104014&view=rev
Log:
I hate this commit.

Revert much of the implementation of C++98/03 [temp.friend]p5 in
r103943 and its follow-ons r103948 and r103952. While our
implementation was technically correct, other compilers don't seem to
implement this paragraph (which forces the instantiation of friend
functions defined in a class template when a class template
specialization is instantiated), and doing so broke a bunch of Boost
libraries. 

Since this behavior has changed in C++0x (which instantiates the
friend function definitions when they are used), we're going to skip
the nowhere-implemented C++98/03 semantics and go straight to the
C++0x semantics.

This commit is a band-aid to get Boost up and running again. It
doesn't really fix PR6952 (which this commit un-fixes), but it does
deal with the way Boost.Units abuses this particular paragraph.

Modified:
    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/p4.cpp

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=104014&r1=104013&r2=104014&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Tue May 18 00:45:02 2010
@@ -1049,23 +1049,6 @@
     // TODO: should we remember this connection regardless of whether
     // the friend declaration provided a body?
     Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
-    if (!SemaRef.getLangOptions().CPlusPlus0x) {
-      // C++03 [temp.friend]p4:
-      //   When a function is defined in a friend function declaration in a 
-      //   class template, the function is defined at each instantiation of the
-      //   class template. The function is defined even if it is never used.
-      if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Owner)) {
-        if (ClassTemplateSpecializationDecl *Spec 
-                        = dyn_cast<ClassTemplateSpecializationDecl>(Record))
-          InstantiateAtPOI = Spec->getPointOfInstantiation();
-        else if (MemberSpecializationInfo *MSInfo 
-                                      = Record->getMemberSpecializationInfo())
-          InstantiateAtPOI = MSInfo->getPointOfInstantiation();
-      }
-      
-      if (InstantiateAtPOI.isInvalid())
-        InstantiateAtPOI = Function->getLocation();        
-    }
   }
     
   if (InitFunctionInstantiation(Function, D))
@@ -1146,17 +1129,44 @@
 
     PrincipalDecl->setObjectOfFriendDecl(PrevDecl != 0);
     DC->makeDeclVisibleInContext(PrincipalDecl, /*Recoverable=*/ false);
+    
+    if (!SemaRef.getLangOptions().CPlusPlus0x &&
+        D->isThisDeclarationADefinition()) {
+      // Check for a function body.
+      const FunctionDecl *Definition = 0;
+      if (Function->getBody(Definition) &&
+          Definition->getTemplateSpecializationKind() == TSK_Undeclared) {
+        SemaRef.Diag(Function->getLocation(), diag::err_redefinition) 
+          << Function->getDeclName();
+        SemaRef.Diag(Definition->getLocation(), diag::note_previous_definition);
+        Function->setInvalidDecl();        
+      } 
+      // Check for redefinitions due to other instantiations of this or
+      // a similar friend function.
+      else for (FunctionDecl::redecl_iterator R = Function->redecls_begin(),
+                                           REnd = Function->redecls_end();
+                R != REnd; ++R) {
+        if (*R != Function && 
+            ((*R)->getFriendObjectKind() != Decl::FOK_None)) {
+          if (const FunctionDecl *RPattern
+              = (*R)->getTemplateInstantiationPattern())
+            if (RPattern->getBody(RPattern)) {
+              SemaRef.Diag(Function->getLocation(), diag::err_redefinition) 
+                << Function->getDeclName();
+              SemaRef.Diag((*R)->getLocation(), diag::note_previous_definition);
+              Function->setInvalidDecl();
+              break;
+            }
+        }
+      }
+    }
+      
   }
 
   if (Function->isOverloadedOperator() && !DC->isRecord() &&
       PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary))
     PrincipalDecl->setNonMemberOperator();
 
-  // If we need to instantiate this function now (because it is a C++98/03 
-  // friend function defined inside a class template), do so.
-  if (InstantiateAtPOI.isValid())
-    SemaRef.MarkDeclarationReferenced(InstantiateAtPOI, Function);
-
   return Function;
 }
 
@@ -1981,34 +1991,13 @@
                                          FunctionDecl *Function,
                                          bool Recursive,
                                          bool DefinitionRequired) {
-  if (Function->isInvalidDecl())
+  if (Function->isInvalidDecl() || Function->getBody())
     return;
 
   // 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);
-      Function->setInvalidDecl();
-    }    
-    
-    // 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();
   Stmt *Pattern = 0;
@@ -2035,32 +2024,6 @@
     return;
   }
 
-  // If this is an instantiation of friend function defined within a class
-  // template or class template specialization or member class thereof, 
-  // determine whether there were multiple instantiations of its lexical class.
-  if (PatternDecl->getFriendObjectKind() != Decl::FOK_None) {
-    for (FunctionDecl::redecl_iterator R = Function->redecls_begin(),
-                                    REnd = Function->redecls_end();
-         R != REnd; ++R) {
-      if (*R != Function && 
-          ((*R)->getFriendObjectKind() != Decl::FOK_None)) {
-        if (const FunctionDecl *RPattern
-                                    = (*R)->getTemplateInstantiationPattern())
-          if (RPattern->getBody(RPattern)) {
-            InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
-            if (Inst)
-              return;  
-            
-            Diag(Function->getLocation(), diag::err_redefinition) 
-              << Function->getDeclName();
-            Diag((*R)->getLocation(), diag::note_previous_definition);
-            Function->setInvalidDecl();
-            return;
-          }
-      }
-    }
-  }
-  
   // C++0x [temp.explicit]p9:
   //   Except for inline functions, other explicit instantiation declarations
   //   have the effect of suppressing the implicit instantiation of the entity

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=104014&r1=104013&r2=104014&view=diff
==============================================================================
--- cfe/trunk/test/CXX/class.access/class.friend/p1.cpp (original)
+++ cfe/trunk/test/CXX/class.access/class.friend/p1.cpp Tue May 18 00:45:02 2010
@@ -188,8 +188,8 @@
 
   struct Inequal {};
   bool test() {
-    Holder<Inequal> a, b; // expected-note {{requested here}}
-    return a == b; 
+    Holder<Inequal> a, b;
+    return a == b;  // expected-note {{requested here}}
   }
 }
 

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=104014&r1=104013&r2=104014&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 Tue May 18 00:45:02 2010
@@ -1,52 +1,10 @@
 // RUN: %clang_cc1 -fsyntax-only -verify %s
 
 template<typename T>
-struct X {
-  friend void f(int x) { T* y = x; } // expected-error{{cannot initialize a variable of type 'int *' with an lvalue of type 'int'}}
-};
-
-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}}
   friend void f6(int) { } // expected-error{{redefinition of}} \
                           // expected-note{{previous definition}}
 };
 
-void f2(int) { } // expected-note{{previous definition}}
-void f4(int) { } // expected-note{{previous definition}}
-
-X1<int> x1a; // expected-note 7{{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;}
-
-template<typename T>
-struct X2 {
-  friend void g0(T) { } // expected-error{{redefinition of 'g0'}}
-};
-
-template<typename T>
-struct X3 {
-  friend void g0(T) { } // expected-note{{previous definition is here}}
-};
-
-X2<float> x2; // expected-note{{in instantiation of}}
-X3<float> x3;
+X1<int> x1a; 
+X1<float> x1b; // expected-note {{in instantiation of}}





More information about the cfe-commits mailing list