[PATCH] D21508: Diagnose friend function template redefinitions

2018-12-06 Thread Serge Pavlov via Phabricator via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL348473: Diagnose friend function template redefinitions. 
(authored by sepavloff, committed by ).
Herald added a subscriber: llvm-commits.

Changed prior to commit:
  https://reviews.llvm.org/D21508?vs=176763=176938#toc

Repository:
  rL LLVM

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D21508/new/

https://reviews.llvm.org/D21508

Files:
  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

Index: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1817,7 +1817,9 @@
   // 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;
Index: cfe/trunk/lib/Sema/SemaDecl.cpp
===
--- cfe/trunk/lib/Sema/SemaDecl.cpp
+++ cfe/trunk/lib/Sema/SemaDecl.cpp
@@ -12737,6 +12737,29 @@
   }
 }
   }
+
+  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(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;
 
Index: cfe/trunk/include/clang/AST/DeclBase.h
===
--- cfe/trunk/include/clang/AST/DeclBase.h
+++ cfe/trunk/include/clang/AST/DeclBase.h
@@ -1065,11 +1065,11 @@
 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 @@
 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))
Index: cfe/trunk/test/SemaCXX/friend-template-redecl.cpp
===
--- cfe/trunk/test/SemaCXX/friend-template-redecl.cpp
+++ cfe/trunk/test/SemaCXX/friend-template-redecl.cpp
@@ -18,16 +18,3 @@
   foo(x);
   bar(x);
 }
-
-namespace PR39742 {
-template
-struct wrapper {
-  template
-  friend void friend_function_template() {}
-};
-
-wrapper x;
-// FIXME: We should really error here because of the redefinition of
-// friend_function_template.
-wrapper y;
-}
Index: cfe/trunk/test/SemaCXX/friend2.cpp
===
--- cfe/trunk/test/SemaCXX/friend2.cpp
+++ cfe/trunk/test/SemaCXX/friend2.cpp
@@ -129,6 +129,83 @@
 void func_22() {} // expected-error{{redefinition of 'func_22'}}
 
 
+// Case of template friend functions.
+
+template void func_31(T *x);
+template
+struct C31a {
+  template friend void func_31(T *x) {}
+};
+template
+struct C31b {
+  template friend void func_31(T *x) {}
+};
+
+
+template inline void func_32(T *x) {}
+template
+struct C32a {
+  template friend void func_32(T *x) {}
+};
+template
+struct C32b {
+ 

[PATCH] D21508: Diagnose friend function template redefinitions

2018-12-05 Thread Richard Smith - zygoloid via Phabricator via cfe-commits
rsmith accepted this revision.
rsmith marked an inline comment as done.
rsmith added a comment.
This revision is now accepted and ready to land.

Thanks (and sorry for dropping the ball on this review).


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D21508/new/

https://reviews.llvm.org/D21508



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D21508: Diagnose friend function template redefinitions

2018-12-04 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 176763.
sepavloff added a comment.

Updated patch

The fix for https://bugs.llvm.org/show_bug.cgi?id=39742 put a test
case, which is not a valid code. The error is detected with this
patch, tests are updated accordingly.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D21508/new/

https://reviews.llvm.org/D21508

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

Index: test/SemaCXX/friend2.cpp
===
--- test/SemaCXX/friend2.cpp
+++ test/SemaCXX/friend2.cpp
@@ -129,6 +129,83 @@
 void func_22() {} // expected-error{{redefinition of 'func_22'}}
 
 
+// Case of template friend functions.
+
+template void func_31(T *x);
+template
+struct C31a {
+  template friend void func_31(T *x) {}
+};
+template
+struct C31b {
+  template friend void func_31(T *x) {}
+};
+
+
+template inline void func_32(T *x) {}
+template
+struct C32a {
+  template friend void func_32(T *x) {}
+};
+template
+struct C32b {
+  template friend void func_32(T *x) {}
+};
+
+
+template
+struct C33a {
+  template friend void func_33(T *x) {}
+};
+template
+struct C33b {
+  template friend void func_33(T *x) {}
+};
+
+
+template inline void func_34(T *x) {}  // expected-note{{previous definition is here}}
+template
+struct C34 {
+  template friend void func_34(T *x) {} // expected-error{{redefinition of 'func_34'}}
+};
+
+C34 v34;  // expected-note{{in instantiation of template class 'C34' requested here}}
+
+
+template inline void func_35(T *x);
+template
+struct C35a {
+  template friend void func_35(T *x) {} // expected-note{{previous definition is here}}
+};
+template
+struct C35b {
+  template friend void func_35(T *x) {} // expected-error{{redefinition of 'func_35'}}
+};
+
+C35a v35a;
+C35b v35b;  // expected-note{{in instantiation of template class 'C35b' requested here}}
+
+
+template void func_36(T *x);
+template
+struct C36 {
+  template friend void func_36(T *x) {}  // expected-error{{redefinition of 'func_36'}}
+ // expected-note@-1{{previous definition is here}}
+};
+
+C36 v36a;
+C36 v36b;  //expected-note{{in instantiation of template class 'C36' requested here}}
+
+
+template void func_37(T *x);
+template
+struct C37 {
+  template friend void func_37(T *x) {} // expected-note{{previous definition is here}}
+};
+
+C37 v37;
+template void func_37(T *x) {} // expected-error{{redefinition of 'func_37'}}
+
 
 namespace pr22307 {
 
@@ -235,3 +312,15 @@
   cache.insert();
 }
 }
+
+namespace PR39742 {
+template
+struct wrapper {
+  template
+  friend void friend_function_template() {}  // expected-error{{redefinition of 'friend_function_template'}}
+ // expected-note@-1{{previous definition is here}}
+};
+
+wrapper x;
+wrapper y;  // expected-note{{in instantiation of template class 'PR39742::wrapper' requested here}}
+}
Index: test/SemaCXX/friend-template-redecl.cpp
===
--- test/SemaCXX/friend-template-redecl.cpp
+++ test/SemaCXX/friend-template-redecl.cpp
@@ -18,14 +18,3 @@
   foo(x);
   bar(x);
 }
-
-namespace PR39742 {
-template
-struct wrapper {
-  template
-  friend void friend_function_template() {}
-};
-
-wrapper x;
-wrapper y;
-}
Index: test/Modules/friend-definition.cpp
===
--- test/Modules/friend-definition.cpp
+++ test/Modules/friend-definition.cpp
@@ -7,6 +7,7 @@
 #pragma clang module begin A
 template struct A {
   friend A operator+(const A&, const A&) { return {}; }
+  template friend void func_1(const A&, const T2 &) {}
 };
 #pragma clang module end
 #pragma clang module endbuild
@@ -36,4 +37,5 @@
 void h() {
   A a;
   a + a;
+  func_1(a, 0);
 }
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1817,7 +1817,9 @@
   // 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;
Index: lib/Sema/SemaDecl.cpp
===
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -12744,6 +12744,29 @@
   }
 }
   }
+
+  if (!Definition)
+// Similar to friend functions a friend function template may be a
+// definition and do not have a 

[PATCH] D21508: Diagnose friend function template redefinitions

2018-08-13 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 160298.
sepavloff added a comment.

Rebased the patch


Repository:
  rC Clang

https://reviews.llvm.org/D21508

Files:
  include/clang/AST/DeclBase.h
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/Modules/friend-definition.cpp
  test/SemaCXX/friend2.cpp

Index: test/SemaCXX/friend2.cpp
===
--- test/SemaCXX/friend2.cpp
+++ test/SemaCXX/friend2.cpp
@@ -129,6 +129,83 @@
 void func_22() {} // expected-error{{redefinition of 'func_22'}}
 
 
+// Case of template friend functions.
+
+template void func_31(T *x);
+template
+struct C31a {
+  template friend void func_31(T *x) {}
+};
+template
+struct C31b {
+  template friend void func_31(T *x) {}
+};
+
+
+template inline void func_32(T *x) {}
+template
+struct C32a {
+  template friend void func_32(T *x) {}
+};
+template
+struct C32b {
+  template friend void func_32(T *x) {}
+};
+
+
+template
+struct C33a {
+  template friend void func_33(T *x) {}
+};
+template
+struct C33b {
+  template friend void func_33(T *x) {}
+};
+
+
+template inline void func_34(T *x) {}  // expected-note{{previous definition is here}}
+template
+struct C34 {
+  template friend void func_34(T *x) {} // expected-error{{redefinition of 'func_34'}}
+};
+
+C34 v34;  // expected-note{{in instantiation of template class 'C34' requested here}}
+
+
+template inline void func_35(T *x);
+template
+struct C35a {
+  template friend void func_35(T *x) {} // expected-note{{previous definition is here}}
+};
+template
+struct C35b {
+  template friend void func_35(T *x) {} // expected-error{{redefinition of 'func_35'}}
+};
+
+C35a v35a;
+C35b v35b;  // expected-note{{in instantiation of template class 'C35b' requested here}}
+
+
+template void func_36(T *x);
+template
+struct C36 {
+  template friend void func_36(T *x) {}  // expected-error{{redefinition of 'func_36'}}
+ // expected-note@-1{{previous definition is here}}
+};
+
+C36 v36a;
+C36 v36b;  //expected-note{{in instantiation of template class 'C36' requested here}}
+
+
+template void func_37(T *x);
+template
+struct C37 {
+  template friend void func_37(T *x) {} // expected-note{{previous definition is here}}
+};
+
+C37 v37;
+template void func_37(T *x) {} // expected-error{{redefinition of 'func_37'}}
+
 
 namespace pr22307 {
 
Index: test/Modules/friend-definition.cpp
===
--- test/Modules/friend-definition.cpp
+++ test/Modules/friend-definition.cpp
@@ -7,6 +7,7 @@
 #pragma clang module begin A
 template struct A {
   friend A operator+(const A&, const A&) { return {}; }
+  template friend void func_1(const A&, const T2 &) {}
 };
 #pragma clang module end
 #pragma clang module endbuild
@@ -36,4 +37,5 @@
 void h() {
   A a;
   a + a;
+  func_1(a, 0);
 }
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1793,7 +1793,9 @@
   // 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;
Index: lib/Sema/SemaDecl.cpp
===
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -12654,6 +12654,29 @@
   }
 }
   }
+
+  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(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;
 
Index: include/clang/AST/DeclBase.h
===
--- include/clang/AST/DeclBase.h
+++ include/clang/AST/DeclBase.h
@@ -1078,11 +1078,11 @@
 unsigned OldNS = IdentifierNamespace;
 assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
  IDNS_TagFriend | 

[PATCH] D21508: Diagnose friend function template redefinitions

2018-03-19 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff added a comment.

Other compilers successfully recognize errors (checked using 
https://godbolt.org/). For instance, the code:

  template inline void func_35(T *x);
  template
  struct C35a {
template friend void func_35(T *x) {}
  };
  template
  struct C35b {
template friend void func_35(T *x) {}
  };
  C35a v35a;
  C35b v35b;

is rejected by MSVC 19:

  example.cpp
  (7): error C2995: 'void func_37(T *)': function template has already 
been defined
  (1): note: see declaration of 'func_37'
  Microsoft (R) C/C++ Optimizing Compiler Version 19.10.25017 for x64
  Copyright (C) Microsoft Corporation.  All rights reserved.
  Compiler returned: 2

by  gcc 7.3:

  :7:27: error: redefinition of 'template void func_37(T*)'
   template void func_37(T *x) {}
 ^~~
  :1:27: note: 'template void func_37(T*)' previously declared 
here
   template void func_37(T *x);
 ^~~
  Compiler returned: 1

and icc 18:

  (7): error: function template "func_37" has already been defined
template void func_37(T *x) {}
  ^
  compilation aborted for  (code 2)
  Compiler returned: 2


Repository:
  rC Clang

https://reviews.llvm.org/D21508



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D21508: Diagnose friend function template redefinitions

2018-03-14 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 138303.
sepavloff added a comment.

Updated patch

- Rebased relative to recent ToT
- Removed the change in `FunctionDecl::getTemplateInstantiationPattern()`, as 
it is not necessary for error detection,
- Added test for use in module.


Repository:
  rC Clang

https://reviews.llvm.org/D21508

Files:
  include/clang/AST/DeclBase.h
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/Modules/friend-definition.cpp
  test/SemaCXX/friend2.cpp

Index: test/SemaCXX/friend2.cpp
===
--- test/SemaCXX/friend2.cpp
+++ test/SemaCXX/friend2.cpp
@@ -129,6 +129,83 @@
 void func_22() {} // expected-error{{redefinition of 'func_22'}}
 
 
+// Case of template friend functions.
+
+template void func_31(T *x);
+template
+struct C31a {
+  template friend void func_31(T *x) {}
+};
+template
+struct C31b {
+  template friend void func_31(T *x) {}
+};
+
+
+template inline void func_32(T *x) {}
+template
+struct C32a {
+  template friend void func_32(T *x) {}
+};
+template
+struct C32b {
+  template friend void func_32(T *x) {}
+};
+
+
+template
+struct C33a {
+  template friend void func_33(T *x) {}
+};
+template
+struct C33b {
+  template friend void func_33(T *x) {}
+};
+
+
+template inline void func_34(T *x) {}  // expected-note{{previous definition is here}}
+template
+struct C34 {
+  template friend void func_34(T *x) {} // expected-error{{redefinition of 'func_34'}}
+};
+
+C34 v34;  // expected-note{{in instantiation of template class 'C34' requested here}}
+
+
+template inline void func_35(T *x);
+template
+struct C35a {
+  template friend void func_35(T *x) {} // expected-note{{previous definition is here}}
+};
+template
+struct C35b {
+  template friend void func_35(T *x) {} // expected-error{{redefinition of 'func_35'}}
+};
+
+C35a v35a;
+C35b v35b;  // expected-note{{in instantiation of template class 'C35b' requested here}}
+
+
+template void func_36(T *x);
+template
+struct C36 {
+  template friend void func_36(T *x) {}  // expected-error{{redefinition of 'func_36'}}
+ // expected-note@-1{{previous definition is here}}
+};
+
+C36 v36a;
+C36 v36b;  //expected-note{{in instantiation of template class 'C36' requested here}}
+
+
+template void func_37(T *x);
+template
+struct C37 {
+  template friend void func_37(T *x) {} // expected-note{{previous definition is here}}
+};
+
+C37 v37;
+template void func_37(T *x) {} // expected-error{{redefinition of 'func_37'}}
+
 
 namespace pr22307 {
 
Index: test/Modules/friend-definition.cpp
===
--- test/Modules/friend-definition.cpp
+++ test/Modules/friend-definition.cpp
@@ -7,6 +7,7 @@
 #pragma clang module begin A
 template struct A {
   friend A operator+(const A&, const A&) { return {}; }
+  template friend void func_1(const A&, const T2 &) {}
 };
 #pragma clang module end
 #pragma clang module endbuild
@@ -36,4 +37,5 @@
 void h() {
   A a;
   a + a;
+  func_1(a, 0);
 }
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1795,7 +1795,9 @@
   // 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;
Index: lib/Sema/SemaDecl.cpp
===
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -12321,6 +12321,29 @@
   }
 }
   }
+
+  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(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;
 
Index: include/clang/AST/DeclBase.h
===
--- include/clang/AST/DeclBase.h
+++ 

[PATCH] D21508: Diagnose friend function template redefinitions

2017-09-16 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 115539.
sepavloff added a comment.

Rebased


https://reviews.llvm.org/D21508

Files:
  include/clang/AST/DeclBase.h
  lib/AST/Decl.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/SemaCXX/friend2.cpp

Index: test/SemaCXX/friend2.cpp
===
--- test/SemaCXX/friend2.cpp
+++ test/SemaCXX/friend2.cpp
@@ -129,6 +129,83 @@
 void func_22() {} // expected-error{{redefinition of 'func_22'}}
 
 
+// Case of template friend functions.
+
+template void func_31(T *x);
+template
+struct C31a {
+  template friend void func_31(T *x) {}
+};
+template
+struct C31b {
+  template friend void func_31(T *x) {}
+};
+
+
+template inline void func_32(T *x) {}
+template
+struct C32a {
+  template friend void func_32(T *x) {}
+};
+template
+struct C32b {
+  template friend void func_32(T *x) {}
+};
+
+
+template
+struct C33a {
+  template friend void func_33(T *x) {}
+};
+template
+struct C33b {
+  template friend void func_33(T *x) {}
+};
+
+
+template inline void func_34(T *x) {}  // expected-note{{previous definition is here}}
+template
+struct C34 {
+  template friend void func_34(T *x) {} // expected-error{{redefinition of 'func_34'}}
+};
+
+C34 v34;  // expected-note{{in instantiation of template class 'C34' requested here}}
+
+
+template inline void func_35(T *x);
+template
+struct C35a {
+  template friend void func_35(T *x) {} // expected-note{{previous definition is here}}
+};
+template
+struct C35b {
+  template friend void func_35(T *x) {} // expected-error{{redefinition of 'func_35'}}
+};
+
+C35a v35a;
+C35b v35b;  // expected-note{{in instantiation of template class 'C35b' requested here}}
+
+
+template void func_36(T *x);
+template
+struct C36 {
+  template friend void func_36(T *x) {}  // expected-error{{redefinition of 'func_36'}}
+ // expected-note@-1{{previous definition is here}}
+};
+
+C36 v36a;
+C36 v36b;  //expected-note{{in instantiation of template class 'C36' requested here}}
+
+
+template void func_37(T *x);
+template
+struct C37 {
+  template friend void func_37(T *x) {} // expected-note{{previous definition is here}}
+};
+
+C37 v37;
+template void func_37(T *x) {} // expected-error{{redefinition of 'func_37'}}
+
 
 namespace pr22307 {
 
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1795,7 +1795,9 @@
   // 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 (FunctionTemplate)
+  FunctionTemplate->setObjectOfFriendDecl();
 DC->makeDeclVisibleInContext(PrincipalDecl);
 
 bool QueuedInstantiation = false;
Index: lib/Sema/SemaDecl.cpp
===
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -12004,6 +12004,29 @@
   }
 }
   }
+
+  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(I);
+if (D != FTD) {
+  assert(!D->isThisDeclarationADefinition() &&
+ "Underlying function declaration must be a definition");
+  if (D->getFriendObjectKind() != Decl::FOK_None)
+if (FunctionTemplateDecl *FT =
+   D->getInstantiatedFromMemberTemplate()) {
+  if (FT->isThisDeclarationADefinition()) {
+Definition = D->getTemplatedDecl();
+break;
+  }
+}
+}
+  }
+}
+
   if (!Definition)
 return;
 
Index: lib/AST/Decl.cpp
===
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -3267,6 +3267,14 @@
   if (auto *MFD = getInstantiatedFromMemberFunction())
 return getDefinitionOrSelf(MFD);
 
+  if (FunctionTemplateDecl *TD = getDescribedFunctionTemplate()) {
+if (TD->getFriendObjectKind() != FOK_None) {
+  while (FunctionTemplateDecl *FT = TD->getInstantiatedFromMemberTemplate())
+TD = FT;
+  return TD->getTemplatedDecl();
+}
+  }
+
   return nullptr;
 }
 
Index: include/clang/AST/DeclBase.h
===
--- include/clang/AST/DeclBase.h
+++ include/clang/AST/DeclBase.h
@@ -1034,11 +1034,11 @@
 unsigned OldNS = IdentifierNamespace;
 assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
  IDNS_TagFriend | IDNS_OrdinaryFriend |
- 

[PATCH] D21508: Diagnose friend function template redefinitions

2017-07-18 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 107091.
sepavloff added a comment.

Simplified patch


https://reviews.llvm.org/D21508

Files:
  include/clang/AST/DeclBase.h
  lib/AST/Decl.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/SemaCXX/friend2.cpp

Index: test/SemaCXX/friend2.cpp
===
--- test/SemaCXX/friend2.cpp
+++ test/SemaCXX/friend2.cpp
@@ -129,6 +129,83 @@
 void func_22() {} // expected-error{{redefinition of 'func_22'}}
 
 
+// Case of template friend functions.
+
+template void func_31(T *x);
+template
+struct C31a {
+  template friend void func_31(T *x) {}
+};
+template
+struct C31b {
+  template friend void func_31(T *x) {}
+};
+
+
+template inline void func_32(T *x) {}
+template
+struct C32a {
+  template friend void func_32(T *x) {}
+};
+template
+struct C32b {
+  template friend void func_32(T *x) {}
+};
+
+
+template
+struct C33a {
+  template friend void func_33(T *x) {}
+};
+template
+struct C33b {
+  template friend void func_33(T *x) {}
+};
+
+
+template inline void func_34(T *x) {}  // expected-note{{previous definition is here}}
+template
+struct C34 {
+  template friend void func_34(T *x) {} // expected-error{{redefinition of 'func_34'}}
+};
+
+C34 v34;  // expected-note{{in instantiation of template class 'C34' requested here}}
+
+
+template inline void func_35(T *x);
+template
+struct C35a {
+  template friend void func_35(T *x) {} // expected-note{{previous definition is here}}
+};
+template
+struct C35b {
+  template friend void func_35(T *x) {} // expected-error{{redefinition of 'func_35'}}
+};
+
+C35a v35a;
+C35b v35b;  // expected-note{{in instantiation of template class 'C35b' requested here}}
+
+
+template void func_36(T *x);
+template
+struct C36 {
+  template friend void func_36(T *x) {}  // expected-error{{redefinition of 'func_36'}}
+ // expected-note@-1{{previous definition is here}}
+};
+
+C36 v36a;
+C36 v36b;  //expected-note{{in instantiation of template class 'C36' requested here}}
+
+
+template void func_37(T *x);
+template
+struct C37 {
+  template friend void func_37(T *x) {} // expected-note{{previous definition is here}}
+};
+
+C37 v37;
+template void func_37(T *x) {} // expected-error{{redefinition of 'func_37'}}
+
 
 namespace pr22307 {
 
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1795,7 +1795,9 @@
   // 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 (FunctionTemplate)
+  FunctionTemplate->setObjectOfFriendDecl();
 DC->makeDeclVisibleInContext(PrincipalDecl);
 
 bool QueuedInstantiation = false;
Index: lib/Sema/SemaDecl.cpp
===
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -11990,6 +11990,29 @@
   }
 }
   }
+
+  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(I);
+if (D != FTD) {
+  assert(!D->isThisDeclarationADefinition() &&
+ "Underlying function declaration must be a definition");
+  if (D->getFriendObjectKind() != Decl::FOK_None)
+if (FunctionTemplateDecl *FT =
+   D->getInstantiatedFromMemberTemplate()) {
+  if (FT->isThisDeclarationADefinition()) {
+Definition = D->getTemplatedDecl();
+break;
+  }
+}
+}
+  }
+}
+
   if (!Definition)
 return;
 
Index: lib/AST/Decl.cpp
===
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -3288,6 +3288,14 @@
   if (auto *MFD = getInstantiatedFromMemberFunction())
 return getDefinitionOrSelf(MFD);
 
+  if (FunctionTemplateDecl *TD = getDescribedFunctionTemplate()) {
+if (TD->getFriendObjectKind() != FOK_None) {
+  while (FunctionTemplateDecl *FT = TD->getInstantiatedFromMemberTemplate())
+TD = FT;
+  return TD->getTemplatedDecl();
+}
+  }
+
   return nullptr;
 }
 
Index: include/clang/AST/DeclBase.h
===
--- include/clang/AST/DeclBase.h
+++ include/clang/AST/DeclBase.h
@@ -1032,11 +1032,11 @@
 unsigned OldNS = IdentifierNamespace;
 assert((OldNS & (IDNS_Tag | IDNS_Ordinary |
  IDNS_TagFriend | IDNS_OrdinaryFriend |
- 

[PATCH] D21508: Diagnose friend function template redefinitions

2017-07-17 Thread Serge Pavlov via Phabricator via cfe-commits
sepavloff updated this revision to Diff 106912.
sepavloff edited the summary of this revision.
sepavloff added a comment.

Aligned implementation with https://reviews.llvm.org/D30170.


https://reviews.llvm.org/D21508

Files:
  include/clang/AST/DeclBase.h
  lib/AST/Decl.cpp
  lib/Sema/SemaDecl.cpp
  lib/Sema/SemaTemplateInstantiateDecl.cpp
  test/SemaCXX/friend2.cpp

Index: test/SemaCXX/friend2.cpp
===
--- test/SemaCXX/friend2.cpp
+++ test/SemaCXX/friend2.cpp
@@ -129,6 +129,83 @@
 void func_22() {} // expected-error{{redefinition of 'func_22'}}
 
 
+// Case of template friend functions.
+
+template void func_31(T *x);
+template
+struct C31a {
+  template friend void func_31(T *x) {}
+};
+template
+struct C31b {
+  template friend void func_31(T *x) {}
+};
+
+
+template inline void func_32(T *x) {}
+template
+struct C32a {
+  template friend void func_32(T *x) {}
+};
+template
+struct C32b {
+  template friend void func_32(T *x) {}
+};
+
+
+template
+struct C33a {
+  template friend void func_33(T *x) {}
+};
+template
+struct C33b {
+  template friend void func_33(T *x) {}
+};
+
+
+template inline void func_34(T *x) {}  // expected-note{{previous definition is here}}
+template
+struct C34 {
+  template friend void func_34(T *x) {} // expected-error{{redefinition of 'func_34'}}
+};
+
+C34 v34;  // expected-note{{in instantiation of template class 'C34' requested here}}
+
+
+template inline void func_35(T *x);
+template
+struct C35a {
+  template friend void func_35(T *x) {} // expected-note{{previous definition is here}}
+};
+template
+struct C35b {
+  template friend void func_35(T *x) {} // expected-error{{redefinition of 'func_35'}}
+};
+
+C35a v35a;
+C35b v35b;  // expected-note{{in instantiation of template class 'C35b' requested here}}
+
+
+template void func_36(T *x);
+template
+struct C36 {
+  template friend void func_36(T *x) {}  // expected-error{{redefinition of 'func_36'}}
+ // expected-note@-1{{previous definition is here}}
+};
+
+C36 v36a;
+C36 v36b;  //expected-note{{in instantiation of template class 'C36' requested here}}
+
+
+template void func_37(T *x);
+template
+struct C37 {
+  template friend void func_37(T *x) {} // expected-note{{previous definition is here}}
+};
+
+C37 v37;
+template void func_37(T *x) {} // expected-error{{redefinition of 'func_37'}}
+
 
 namespace pr22307 {
 
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1795,7 +1795,9 @@
   // 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 (FunctionTemplate)
+  FunctionTemplate->setObjectOfFriendDecl();
 DC->makeDeclVisibleInContext(PrincipalDecl);
 
 bool QueuedInstantiation = false;
Index: lib/Sema/SemaDecl.cpp
===
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -11962,6 +11962,22 @@
   return MissingPrototype;
 }
 
+static FunctionTemplateDecl *findRedefinition(FunctionTemplateDecl *FTD) {
+  FunctionTemplateDecl *UninstantiatedDef = nullptr;
+  for (auto I : FTD->redecls()) {
+auto D = cast(I);
+if (D != FTD) {
+  if (D->isThisDeclarationADefinition())
+return D;
+  if (FunctionTemplateDecl *Orig = D->getInstantiatedFromMemberTemplate()) {
+if (Orig->isThisDeclarationADefinition() || findRedefinition(Orig))
+  UninstantiatedDef = D;
+  }
+}
+  }
+  return UninstantiatedDef;
+}
+
 void
 Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
const FunctionDecl *EffectiveDefinition,
@@ -11990,6 +12006,31 @@
   }
 }
   }
+
+  if (!Definition)
+if (FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) {
+  if (FunctionTemplateDecl *DefTD = findRedefinition(FTD)) {
+const FunctionDecl *Def = DefTD->getTemplatedDecl();
+// If the found definition is a template with uninstantiated body, it
+// can be replaced in specialization:
+//
+//template struct X {
+//  template void f(T, U) { }
+//};
+//template<> template void X::f(int x, U y) { }
+//
+// In this example the specialization 'X' contains declaration of
+// 'f', which is considered a definition by 'isDefined' because it is
+// obtained by instantiation of 'X::f', which has a body.
+//
+if (isa(FTD->getDeclContext()) &&
+!Def->isThisDeclarationADefinition() &&
+Def->getFriendObjectKind() == Decl::FOK_None)
+  return;
+Definition = Def;
+  }
+}
+
   if