Function->setInstantiationOfMemberFunction(D, TSK_ImplicitInstantiation);
}
+ if (isFriend)
+ Function->setObjectOfFriendDecl();
+
if (InitFunctionInstantiation(Function, D))
Function->setInvalidDecl();
- bool isExplicitSpecialization = false;
+ bool IsExplicitSpecialization = false;
LookupResult Previous(
SemaRef, Function->getDeclName(), SourceLocation(),
= D->getDependentSpecializationInfo()) {
assert(isFriend && "non-friend has dependent specialization info?");
- // This needs to be set now for future sanity.
- Function->setObjectOfFriendDecl();
-
// Instantiate the explicit template arguments.
TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(),
Info->getRAngleLoc());
Previous))
Function->setInvalidDecl();
- isExplicitSpecialization = true;
+ IsExplicitSpecialization = true;
+ } else if (const ASTTemplateArgumentListInfo *Info =
+ D->getTemplateSpecializationArgsAsWritten()) {
+ // The name of this function was written as a template-id.
+ SemaRef.LookupQualifiedName(Previous, DC);
+ // Instantiate the explicit template arguments.
+ TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(),
+ Info->getRAngleLoc());
+ if (SemaRef.Subst(Info->getTemplateArgs(), Info->getNumTemplateArgs(),
+ ExplicitArgs, TemplateArgs))
+ return nullptr;
+
+ if (SemaRef.CheckFunctionTemplateSpecialization(Function,
+ &ExplicitArgs,
+ Previous))
+ Function->setInvalidDecl();
+
+ IsExplicitSpecialization = true;
} else if (TemplateParams || !FunctionTemplate) {
// Look only into the namespace where the friend would be declared to
// find a previous declaration. This is the innermost enclosing namespace,
Previous.clear();
}
- if (isFriend)
- Function->setObjectOfFriendDecl();
-
SemaRef.CheckFunctionDeclaration(/*Scope*/ nullptr, Function, Previous,
- isExplicitSpecialization);
+ IsExplicitSpecialization);
NamedDecl *PrincipalDecl = (TemplateParams
? cast<NamedDecl>(FunctionTemplate)
LookupResult Previous(SemaRef, NameInfo, Sema::LookupOrdinaryName,
Sema::ForExternalRedeclaration);
- if (!FunctionTemplate || TemplateParams || isFriend) {
+ bool IsExplicitSpecialization = false;
+
+ // If the name of this function was written as a template-id, instantiate
+ // the explicit template arguments.
+ if (DependentFunctionTemplateSpecializationInfo *Info
+ = D->getDependentSpecializationInfo()) {
+ assert(isFriend && "non-friend has dependent specialization info?");
+
+ // Instantiate the explicit template arguments.
+ TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(),
+ Info->getRAngleLoc());
+ if (SemaRef.Subst(Info->getTemplateArgs(), Info->getNumTemplateArgs(),
+ ExplicitArgs, TemplateArgs))
+ return nullptr;
+
+ // Map the candidate templates to their instantiations.
+ for (unsigned I = 0, E = Info->getNumTemplates(); I != E; ++I) {
+ Decl *Temp = SemaRef.FindInstantiatedDecl(D->getLocation(),
+ Info->getTemplate(I),
+ TemplateArgs);
+ if (!Temp) return nullptr;
+
+ Previous.addDecl(cast<FunctionTemplateDecl>(Temp));
+ }
+
+ if (SemaRef.CheckFunctionTemplateSpecialization(Method,
+ &ExplicitArgs,
+ Previous))
+ Method->setInvalidDecl();
+
+ IsExplicitSpecialization = true;
+ } else if (const ASTTemplateArgumentListInfo *Info =
+ D->getTemplateSpecializationArgsAsWritten()) {
+ SemaRef.LookupQualifiedName(Previous, DC);
+
+ TemplateArgumentListInfo ExplicitArgs(Info->getLAngleLoc(),
+ Info->getRAngleLoc());
+ if (SemaRef.Subst(Info->getTemplateArgs(), Info->getNumTemplateArgs(),
+ ExplicitArgs, TemplateArgs))
+ return nullptr;
+
+ if (SemaRef.CheckFunctionTemplateSpecialization(Method,
+ &ExplicitArgs,
+ Previous))
+ Method->setInvalidDecl();
+
+ IsExplicitSpecialization = true;
+ } else if (!FunctionTemplate || TemplateParams || isFriend) {
SemaRef.LookupQualifiedName(Previous, Record);
// In C++, the previous declaration we find might be a tag type
}
if (!IsClassScopeSpecialization)
- SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous, false);
+ SemaRef.CheckFunctionDeclaration(nullptr, Method, Previous,
+ IsExplicitSpecialization);
if (D->isPure())
SemaRef.CheckPureMethod(Method, SourceRange());
inline void bar() {}
C<int> c;
}
+
+namespace qualified_friend {
+ void f(int); // expected-note 2{{type mismatch at 1st parameter}}
+ template<typename T> void f(T*); // expected-note 2{{could not match 'type-parameter-0-0 *' against 'double'}}
+ template<typename T> void nondep();
+
+ template<typename> struct X1 {
+ friend void qualified_friend::f(double); // expected-error {{friend declaration of 'f' does not match any declaration in namespace 'qualified_friend'}}
+ friend void qualified_friend::g(); // expected-error {{friend declaration of 'g' does not match any declaration in namespace 'qualified_friend'}}
+ };
+ template<typename T> struct X2 {
+ friend void qualified_friend::f(T); // expected-error {{friend declaration of 'f' does not match any declaration in namespace 'qualified_friend'}}
+ };
+ X1<int> xi;
+ X2<double> xd; // expected-note {{in instantiation of}}
+ X2<int> x2i;
+
+ struct Y {
+ void f(int); // expected-note 2{{type mismatch at 1st parameter}}
+ template<typename T> void f(T*); // expected-note 2{{could not match 'type-parameter-0-0 *' against 'double'}}
+ template<typename T> void nondep();
+ };
+
+ template<typename> struct Z1 {
+ friend void Y::f(double); // expected-error {{friend declaration of 'f' does not match any declaration in 'qualified_friend::Y'}}
+ friend void Y::g(); // expected-error {{friend declaration of 'g' does not match any declaration in 'qualified_friend::Y'}}
+ };
+ template<typename T> struct Z2 {
+ friend void Y::f(T); // expected-error {{friend declaration of 'f' does not match any declaration in 'qualified_friend::Y'}}
+ };
+ Z1<int> zi;
+ Z2<double> zd; // expected-note {{in instantiation of}}
+ Z2<int> z2i;
+
+ template<typename T>
+ struct OK {
+ friend void qualified_friend::f(int);
+ friend void qualified_friend::f(int*);
+ friend void qualified_friend::f(T*);
+ friend void qualified_friend::f<T>(T*);
+ friend void qualified_friend::nondep<int>();
+ friend void qualified_friend::nondep<T>();
+
+ friend void Y::f(int);
+ friend void Y::f(int*);
+ friend void Y::f(T*);
+ friend void Y::f<T>(T*);
+ friend void Y::nondep<int>();
+ friend void Y::nondep<T>();
+ };
+ OK<float> ok;
+}
+
+namespace qualified_friend_finds_nothing {
+ // FIXME: The status of this example is unclear. For now, we diagnose if the
+ // qualified declaration has nothing it can redeclare, but allow qualified
+ // lookup to find later-declared function templates during instantiation.
+ //
+ // This matches the behavior of GCC, EDG, ICC, and MSVC (except that GCC and
+ // ICC bizarrely accept the instantiation of B<float>).
+ namespace N {}
+
+ template<typename T> struct A {
+ friend void N::f(T); // expected-error {{friend declaration of 'f' does not match}}
+ };
+ namespace N { void f(); } // expected-note {{different number of parameters}}
+
+ template<typename T> struct B {
+ friend void N::f(T); // expected-error {{friend declaration of 'f' does not match}}
+ };
+ B<float> bf; // expected-note {{in instantiation of}}
+
+ namespace N { void f(int); }
+ B<int> bi; // ok?!
+}