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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits