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

Make more correct template function definition lookup

Lookup is made recursive to cover more cases.


http://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
@@ -91,6 +91,73 @@
   friend int func10(int);  // expected-error{{functions that differ only in their return type cannot be overloaded}}
 };
 
+// Case of template friend functions.
+
+template<typename T> void func_11(T *x);
+template<typename T1>
+struct C11a {
+  template<typename T> friend void func_11(T *x) {}
+};
+template<typename T1>
+struct C11b {
+  template<typename T> friend void func_11(T *x) {}
+};
+
+
+template<typename T> inline void func_12(T *x) {}
+template<typename T1>
+struct C12a {
+  template<typename T> friend void func_12(T *x) {}
+};
+template<typename T1>
+struct C12b {
+  template<typename T> friend void func_12(T *x) {}
+};
+
+
+template<typename T1>
+struct C13a {
+  template<typename T> friend void func_13(T *x) {}
+};
+template<typename T1>
+struct C13b {
+  template<typename T> friend void func_13(T *x) {}
+};
+
+
+template<typename T> inline void func_14(T *x) {}  // expected-note{{previous definition is here}}
+template<typename T1>
+struct C14 {
+  template<typename T> friend void func_14(T *x) {} // expected-error{{redefinition of 'func_14'}}
+};
+
+C14<int> v14;  // expected-note{{in instantiation of template class 'C14<int>' requested here}}
+
+
+template<typename T> inline void func_15(T *x);
+template<typename T1>
+struct C15a {
+  template<typename T> friend void func_15(T *x) {} // expected-note{{previous definition is here}}
+};
+template<typename T1>
+struct C15b {
+  template<typename T> friend void func_15(T *x) {} // expected-error{{redefinition of 'func_15'}}
+};
+
+C15a<int> v15a;
+C15b<int> v15b;  // expected-note{{in instantiation of template class 'C15b<int>' requested here}}
+
+
+template<typename T> void func_16(T *x);
+template<typename T1>
+struct C16 {
+  template<typename T> friend void func_16(T *x) {}  // expected-error{{redefinition of 'func_16'}}
+                                                     // expected-note@-1{{previous definition is here}}
+};
+
+C16<int> v16a;
+C16<long> v16b;  //expected-note{{in instantiation of template class 'C16<long>' requested here}}
+
 
 namespace pr22307 {
 
Index: lib/Sema/SemaDecl.cpp
===================================================================
--- lib/Sema/SemaDecl.cpp
+++ lib/Sema/SemaDecl.cpp
@@ -8807,10 +8807,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,34 @@
   }
 }
 
+/// \brief Returns definition for this function template of null if no
+/// definition found.
+///
+/// This function scans not only redeclarations but also templates from which
+/// these declarations are instantiated, if the function template was
+/// instantiated from another template.
+///
+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, which 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
@@ -908,6 +908,8 @@
     return getTemplatedDecl()->isThisDeclarationADefinition();
   }
 
+  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