diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index adba32ececd1..41c621866402 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1009,6 +1009,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Params[P]->setOwningFunction(Function); Function->setParams(Params.data(), Params.size()); + SourceLocation InstantiateAtPOI; if (TemplateParams) { // Our resulting instantiation is actually a function template, since we // are substituting only the outer template parameters. For example, given @@ -1047,6 +1048,23 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, // TODO: should we remember this connection regardless of whether // the friend declaration provided a body? Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation); + if (!SemaRef.getLangOptions().CPlusPlus0x) { + // C++03 [temp.friend]p4: + // When a function is defined in a friend function declaration in a + // class template, the function is defined at each instantiation of the + // class template. The function is defined even if it is never used. + if (CXXRecordDecl *Record = dyn_cast(Owner)) { + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast(Record)) + InstantiateAtPOI = Spec->getPointOfInstantiation(); + else if (MemberSpecializationInfo *MSInfo + = Record->getMemberSpecializationInfo()) + InstantiateAtPOI = MSInfo->getPointOfInstantiation(); + } + + if (InstantiateAtPOI.isInvalid()) + InstantiateAtPOI = Function->getLocation(); + } } if (InitFunctionInstantiation(Function, D)) @@ -1133,6 +1151,11 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) PrincipalDecl->setNonMemberOperator(); + // If we need to instantiate this function now (because it is a C++98/03 + // friend function defined inside a class template), do so. + if (InstantiateAtPOI.isValid()) + SemaRef.MarkDeclarationReferenced(InstantiateAtPOI, Function); + return Function; } diff --git a/clang/test/CXX/class.access/class.friend/p1.cpp b/clang/test/CXX/class.access/class.friend/p1.cpp index 991698d5dcca..e9177d44e7d9 100644 --- a/clang/test/CXX/class.access/class.friend/p1.cpp +++ b/clang/test/CXX/class.access/class.friend/p1.cpp @@ -188,8 +188,8 @@ namespace test4 { struct Inequal {}; bool test() { - Holder a, b; - return a == b; // expected-note {{requested here}} + Holder a, b; // expected-note {{requested here}} + return a == b; } } diff --git a/clang/test/CXX/temp/temp.decls/temp.friend/p4.cpp b/clang/test/CXX/temp/temp.decls/temp.friend/p4.cpp new file mode 100644 index 000000000000..6490aeb8ee00 --- /dev/null +++ b/clang/test/CXX/temp/temp.decls/temp.friend/p4.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +template +struct X { + friend void f(int x) { T* y = x; } // expected-error{{cannot initialize a variable of type 'int *' with an lvalue of type 'int'}} +}; + +X xi; // expected-note{{in instantiation of member function 'f' requested here}} +