r348473 - Diagnose friend function template redefinitions.

Serge Pavlov via cfe-commits cfe-commits at lists.llvm.org
Thu Dec 6 01:35:04 PST 2018


Author: sepavloff
Date: Thu Dec  6 01:35:04 2018
New Revision: 348473

URL: http://llvm.org/viewvc/llvm-project?rev=348473&view=rev
Log:
Diagnose friend function template redefinitions.

Friend function template defined in a class template becomes available if
the enclosing class template is instantiated. Until the function template
is used, it does not have a body, but still is considered a definition for
the purpose of redeclaration checks.

This change modifies redefinition check so that it can find the friend
function template definitions in instantiated classes.

Differential Revision: http://reviews.llvm.org/D21508

Modified:
    cfe/trunk/include/clang/AST/DeclBase.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/test/Modules/friend-definition.cpp
    cfe/trunk/test/SemaCXX/friend-template-redecl.cpp
    cfe/trunk/test/SemaCXX/friend2.cpp

Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=348473&r1=348472&r2=348473&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Thu Dec  6 01:35:04 2018
@@ -1065,11 +1065,11 @@ public:
     unsigned OldNS = IdentifierNamespace;
     assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
                      IDNS_TagFriend | IDNS_OrdinaryFriend |
-                     IDNS_LocalExtern)) &&
+                     IDNS_LocalExtern | IDNS_NonMemberOperator)) &&
            "namespace includes neither ordinary nor tag");
     assert(!(OldNS & ~(IDNS_Tag | IDNS_Ordinary | IDNS_Type |
                        IDNS_TagFriend | IDNS_OrdinaryFriend |
-                       IDNS_LocalExtern)) &&
+                       IDNS_LocalExtern | IDNS_NonMemberOperator)) &&
            "namespace includes other than ordinary or tag");
 
     Decl *Prev = getPreviousDecl();
@@ -1082,7 +1082,8 @@ public:
         IdentifierNamespace |= IDNS_Tag | IDNS_Type;
     }
 
-    if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend | IDNS_LocalExtern)) {
+    if (OldNS & (IDNS_Ordinary | IDNS_OrdinaryFriend |
+                 IDNS_LocalExtern | IDNS_NonMemberOperator)) {
       IdentifierNamespace |= IDNS_OrdinaryFriend;
       if (PerformFriendInjection ||
           (Prev && Prev->getIdentifierNamespace() & IDNS_Ordinary))

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=348473&r1=348472&r2=348473&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Dec  6 01:35:04 2018
@@ -12737,6 +12737,29 @@ Sema::CheckForFunctionRedefinition(Funct
       }
     }
   }
+
+  if (!Definition)
+    // Similar to friend functions a friend function template may be a
+    // definition and do not have a body if it is instantiated in a class
+    // template.
+    if (FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) {
+      for (auto I : FTD->redecls()) {
+        auto D = cast<FunctionTemplateDecl>(I);
+        if (D != FTD) {
+          assert(!D->isThisDeclarationADefinition() &&
+                 "More than one definition in redeclaration chain");
+          if (D->getFriendObjectKind() != Decl::FOK_None)
+            if (FunctionTemplateDecl *FT =
+                                       D->getInstantiatedFromMemberTemplate()) {
+              if (FT->isThisDeclarationADefinition()) {
+                Definition = D->getTemplatedDecl();
+                break;
+              }
+            }
+        }
+      }
+    }
+
   if (!Definition)
     return;
 

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=348473&r1=348472&r2=348473&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Dec  6 01:35:04 2018
@@ -1817,7 +1817,9 @@ Decl *TemplateDeclInstantiator::VisitFun
   // If the original function was part of a friend declaration,
   // inherit its namespace state and add it to the owner.
   if (isFriend) {
-    PrincipalDecl->setObjectOfFriendDecl();
+    Function->setObjectOfFriendDecl();
+    if (FunctionTemplateDecl *FT = Function->getDescribedFunctionTemplate())
+      FT->setObjectOfFriendDecl();
     DC->makeDeclVisibleInContext(PrincipalDecl);
 
     bool QueuedInstantiation = false;

Modified: cfe/trunk/test/Modules/friend-definition.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/friend-definition.cpp?rev=348473&r1=348472&r2=348473&view=diff
==============================================================================
--- cfe/trunk/test/Modules/friend-definition.cpp (original)
+++ cfe/trunk/test/Modules/friend-definition.cpp Thu Dec  6 01:35:04 2018
@@ -7,6 +7,7 @@ module A {}
 #pragma clang module begin A
 template<typename T> struct A {
   friend A operator+(const A&, const A&) { return {}; }
+  template<typename T2> friend void func_1(const A&, const T2 &) {}
 };
 #pragma clang module end
 #pragma clang module endbuild
@@ -36,4 +37,5 @@ inline void g() { A<int> a; }
 void h() {
   A<int> a;
   a + a;
+  func_1(a, 0);
 }

Modified: cfe/trunk/test/SemaCXX/friend-template-redecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/friend-template-redecl.cpp?rev=348473&r1=348472&r2=348473&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/friend-template-redecl.cpp (original)
+++ cfe/trunk/test/SemaCXX/friend-template-redecl.cpp Thu Dec  6 01:35:04 2018
@@ -18,16 +18,3 @@ void f() {
   foo(x);
   bar(x);
 }
-
-namespace PR39742 {
-template<typename>
-struct wrapper {
-  template<typename>
-  friend void friend_function_template() {}
-};
-
-wrapper<bool> x;
-// FIXME: We should really error here because of the redefinition of
-// friend_function_template.
-wrapper<int> y;
-}

Modified: cfe/trunk/test/SemaCXX/friend2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/friend2.cpp?rev=348473&r1=348472&r2=348473&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/friend2.cpp (original)
+++ cfe/trunk/test/SemaCXX/friend2.cpp Thu Dec  6 01:35:04 2018
@@ -129,6 +129,83 @@ C22b<int> c22bi;
 void func_22() {} // expected-error{{redefinition of 'func_22'}}
 
 
+// Case of template friend functions.
+
+template<typename T> void func_31(T *x);
+template<typename T1>
+struct C31a {
+  template<typename T> friend void func_31(T *x) {}
+};
+template<typename T1>
+struct C31b {
+  template<typename T> friend void func_31(T *x) {}
+};
+
+
+template<typename T> inline void func_32(T *x) {}
+template<typename T1>
+struct C32a {
+  template<typename T> friend void func_32(T *x) {}
+};
+template<typename T1>
+struct C32b {
+  template<typename T> friend void func_32(T *x) {}
+};
+
+
+template<typename T1>
+struct C33a {
+  template<typename T> friend void func_33(T *x) {}
+};
+template<typename T1>
+struct C33b {
+  template<typename T> friend void func_33(T *x) {}
+};
+
+
+template<typename T> inline void func_34(T *x) {}  // expected-note{{previous definition is here}}
+template<typename T1>
+struct C34 {
+  template<typename T> friend void func_34(T *x) {} // expected-error{{redefinition of 'func_34'}}
+};
+
+C34<int> v34;  // expected-note{{in instantiation of template class 'C34<int>' requested here}}
+
+
+template<typename T> inline void func_35(T *x);
+template<typename T1>
+struct C35a {
+  template<typename T> friend void func_35(T *x) {} // expected-note{{previous definition is here}}
+};
+template<typename T1>
+struct C35b {
+  template<typename T> friend void func_35(T *x) {} // expected-error{{redefinition of 'func_35'}}
+};
+
+C35a<int> v35a;
+C35b<int> v35b;  // expected-note{{in instantiation of template class 'C35b<int>' requested here}}
+
+
+template<typename T> void func_36(T *x);
+template<typename T1>
+struct C36 {
+  template<typename T> friend void func_36(T *x) {}  // expected-error{{redefinition of 'func_36'}}
+                                                     // expected-note at -1{{previous definition is here}}
+};
+
+C36<int> v36a;
+C36<long> v36b;  //expected-note{{in instantiation of template class 'C36<long>' requested here}}
+
+
+template<typename T> void func_37(T *x);
+template<typename T1>
+struct C37 {
+  template<typename T> friend void func_37(T *x) {} // expected-note{{previous definition is here}}
+};
+
+C37<int> v37;
+template<typename T> void func_37(T *x) {} // expected-error{{redefinition of 'func_37'}}
+
 
 namespace pr22307 {
 
@@ -235,3 +312,15 @@ void func() {
   cache.insert();
 }
 }
+
+namespace PR39742 {
+template<typename>
+struct wrapper {
+  template<typename>
+  friend void friend_function_template() {}  // expected-error{{redefinition of 'friend_function_template'}}
+                                             // expected-note at -1{{previous definition is here}}
+};
+
+wrapper<bool> x;
+wrapper<int> y;  // expected-note{{in instantiation of template class 'PR39742::wrapper<int>' requested here}}
+}




More information about the cfe-commits mailing list