sepavloff updated this revision to Diff 74218.
sepavloff added a comment.

Updated comments, NFC otherwise.


https://reviews.llvm.org/D21508

Files:
  include/clang/AST/DeclTemplate.h
  lib/AST/DeclTemplate.cpp
  lib/Sema/SemaDecl.cpp
  test/SemaCXX/friend2.cpp

Index: test/SemaCXX/friend2.cpp
===================================================================
--- test/SemaCXX/friend2.cpp
+++ test/SemaCXX/friend2.cpp
@@ -101,7 +101,6 @@
   friend void func_12(int x = 0);  // expected-error{{friend declaration specifying a default argument must be the only declaration}}
 };
 
-
 namespace pr22307 {
 
 struct t {
@@ -170,3 +169,70 @@
 template class Test<int>;
 
 }
+
+// Case of template friend functions.
+
+template<typename T> void func_21(T *x);
+template<typename T1>
+struct C21a {
+  template<typename T> friend void func_21(T *x) {}
+};
+template<typename T1>
+struct C21b {
+  template<typename T> friend void func_21(T *x) {}
+};
+
+
+template<typename T> inline void func_22(T *x) {}
+template<typename T1>
+struct C22a {
+  template<typename T> friend void func_22(T *x) {}
+};
+template<typename T1>
+struct C22b {
+  template<typename T> friend void func_22(T *x) {}
+};
+
+
+template<typename T1>
+struct C23a {
+  template<typename T> friend void func_23(T *x) {}
+};
+template<typename T1>
+struct C23b {
+  template<typename T> friend void func_23(T *x) {}
+};
+
+
+template<typename T> inline void func_24(T *x) {}  // expected-note{{previous definition is here}}
+template<typename T1>
+struct C24 {
+  template<typename T> friend void func_24(T *x) {} // expected-error{{redefinition of 'func_24'}}
+};
+
+C24<int> v24;  // expected-note{{in instantiation of template class 'C24<int>' requested here}}
+
+
+template<typename T> inline void func_25(T *x);
+template<typename T1>
+struct C25a {
+  template<typename T> friend void func_25(T *x) {} // expected-note{{previous definition is here}}
+};
+template<typename T1>
+struct C25b {
+  template<typename T> friend void func_25(T *x) {} // expected-error{{redefinition of 'func_25'}}
+};
+
+C25a<int> v25a;
+C25b<int> v25b;  // expected-note{{in instantiation of template class 'C25b<int>' requested here}}
+
+
+template<typename T> void func_26(T *x);
+template<typename T1>
+struct C26 {
+  template<typename T> friend void func_26(T *x) {}  // expected-error{{redefinition of 'func_26'}}
+                                                     // expected-note@-1{{previous definition is here}}
+};
+
+C26<int> v26a;
+C26<long> v26b;  //expected-note{{in instantiation of template class 'C26<long>' requested here}}
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -8846,10 +8846,23 @@
 
     if (FunctionTemplateDecl *OldTemplateDecl
                                   = dyn_cast<FunctionTemplateDecl>(OldDecl)) {
-      NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());
       FunctionTemplateDecl *NewTemplateDecl
         = NewFD->getDescribedFunctionTemplate();
       assert(NewTemplateDecl && "Template/non-template mismatch");
+      Redeclaration = shouldLinkDependentDeclWithPrevious(NewTemplateDecl,
+                                                          OldTemplateDecl);
+      if (Redeclaration &&
+          (NewTemplateDecl->getFriendObjectKind() != Decl::FOK_None ||
+           OldTemplateDecl->getFriendObjectKind() != Decl::FOK_None))
+        if (FunctionTemplateDecl *NewDef = NewTemplateDecl->getDefinition())
+          if (FunctionTemplateDecl *OldDef = OldTemplateDecl->getDefinition()) {
+            Diag(NewDef->getLocation(), diag::err_redefinition)
+                << NewDef->getDeclName();
+            Diag(OldDef->getLocation(), diag::note_previous_definition);
+            Redeclaration = false;
+          }
+      if (Redeclaration)
+        NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());
       if (CXXMethodDecl *Method
             = dyn_cast<CXXMethodDecl>(NewTemplateDecl->getTemplatedDecl())) {
         Method->setAccess(OldTemplateDecl->getAccess());
Index: lib/AST/DeclTemplate.cpp
===================================================================
--- lib/AST/DeclTemplate.cpp
+++ lib/AST/DeclTemplate.cpp
@@ -289,6 +289,27 @@
   }
 }
 
+FunctionTemplateDecl *FunctionTemplateDecl::getDefinition() const {
+  for (auto *R : redecls()) {
+    FunctionTemplateDecl *F = cast<FunctionTemplateDecl>(R);
+    if (F->isThisDeclarationADefinition())
+      return F;
+
+    // If template does not have a body, probably it is instantiated from
+    // another template and is not used yet.
+    if (FunctionTemplateDecl *P = F->getInstantiatedFromMemberTemplate()) {
+      // If we have hit a point where the user provided a specialization of
+      // this template, we're done looking.
+      if (F->isMemberSpecialization())
+        return F;
+      if (FunctionTemplateDecl *Def = P->getDefinition())
+        return Def;
+    }
+  }
+
+  return nullptr;
+}
+
 llvm::FoldingSetVector<FunctionTemplateSpecializationInfo> &
 FunctionTemplateDecl::getSpecializations() const {
   LoadLazySpecializations();
Index: include/clang/AST/DeclTemplate.h
===================================================================
--- include/clang/AST/DeclTemplate.h
+++ include/clang/AST/DeclTemplate.h
@@ -933,6 +933,15 @@
     return getTemplatedDecl()->isThisDeclarationADefinition();
   }
 
+  /// \brief Returns definition for this function template of null if no
+  /// definition was found.
+  ///
+  /// To properly handle function templates defined in friend declarations, the
+  /// function scans redeclaration chain and for each declaration from there
+  /// tries to find definition in the chains formed by InstantiatedFromMember.
+  ///
+  FunctionTemplateDecl *getDefinition() const;
+
   /// \brief Return the specialization with the provided arguments if it exists,
   /// otherwise return the insertion point.
   FunctionDecl *findSpecialization(ArrayRef<TemplateArgument> Args,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to