sepavloff updated this revision to Diff 99789.
sepavloff edited the summary of this revision.
sepavloff added a comment.

Updated patch


https://reviews.llvm.org/D21508

Files:
  include/clang/AST/DeclTemplate.h
  lib/AST/Decl.cpp
  lib/AST/DeclTemplate.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<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@-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 {
 
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -1792,7 +1792,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
@@ -11874,9 +11874,35 @@
                                    const FunctionDecl *EffectiveDefinition,
                                    SkipBodyInfo *SkipBody) {
   const FunctionDecl *Definition = EffectiveDefinition;
-  if (!Definition)
-    if (!FD->isOdrDefined(Definition))
+  if (!Definition) {
+    if (FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) {
+      FunctionTemplateDecl *DefTD = nullptr;
+      if (!FTD->isDefined(DefTD))
+        return;
+      const FunctionDecl *Def = DefTD->getTemplatedDecl();
+
+      // If the found definition is a template with uninstantiated body, it
+      // can be replaced in specialization:
+      //
+      //    template<typename T> struct X {
+      //      template<typename U> void f(T, U) { }
+      //    };
+      //    template<> template<typename U> void X<int>::f(int x, U y) {
+      //      x = y;
+      //    }
+      //
+      // In this example the specialization 'X<int>' contains declaration of
+      // 'f', which is considered a definition by 'isDefined' because it is
+      // obtained by instantiation of 'X<T>::f', which has a body.
+      //
+      if (isa<ClassTemplateSpecializationDecl>(Def->getLexicalDeclContext()) &&
+          !Def->isThisDeclarationADefinition() &&
+          Def->getFriendObjectKind() == Decl::FOK_None)
+        return;
+      Definition = Def;
+    } else if (!FD->isOdrDefined(Definition))
       return;
+  }
   assert(Definition);
 
   if (FD == Definition)
Index: lib/AST/DeclTemplate.cpp
===================================================================
--- lib/AST/DeclTemplate.cpp
+++ lib/AST/DeclTemplate.cpp
@@ -231,6 +231,30 @@
   return CommonPtr;
 }
 
+bool FunctionTemplateDecl::isDefined(FunctionTemplateDecl *&Def) const {
+  FunctionTemplateDecl *UninstantiatedDef = nullptr;
+  for (auto I : redecls()) {
+    auto FTD = cast<FunctionTemplateDecl>(I);
+    // If this declaration is a definition, return the result.
+    if (FTD->isThisDeclarationADefinition()) {
+      Def = FTD;
+      return true;
+    }
+    // If this declaration has uninstantiated body, return it if no other
+    // definition exists.
+    if (FunctionTemplateDecl *Orig = FTD->getInstantiatedFromMemberTemplate()) {
+      FunctionTemplateDecl *D;
+      if (Orig->isDefined(D))
+        UninstantiatedDef = FTD;
+    }
+  }
+  if (UninstantiatedDef) {
+    Def = UninstantiatedDef;
+    return true;
+  }
+  return false;
+}
+
 void FunctionTemplateDecl::LoadLazySpecializations() const {
   // Grab the most recent declaration to ensure we've loaded any lazy
   // redeclarations of this template.
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -3245,6 +3245,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/DeclTemplate.h
===================================================================
--- include/clang/AST/DeclTemplate.h
+++ include/clang/AST/DeclTemplate.h
@@ -1005,6 +1005,16 @@
     return getTemplatedDecl()->isThisDeclarationADefinition();
   }
 
+  /// Checks if this template declaration or some of its redeclaration defines
+  /// the template.
+  /// \param [out] FT is assigned defining declaration if it exists.
+  ///
+  /// The function can find a definition that has no body (as it is not
+  /// instantiated yet) if there are no other definitions. Call to
+  /// isThisDeclarationADefinition returns false for such definitions.
+  ///
+  bool isDefined(FunctionTemplateDecl *&FT) 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