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