From: John McCall Date: Tue, 13 Apr 2010 20:37:33 +0000 (+0000) Subject: Support befriending members of class template specializations. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=77e8b11524187f81548450e9e2ad9dd0e7200909;p=clang Support befriending members of class template specializations. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101173 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 0b42e8dba1..c997630213 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2771,6 +2771,7 @@ public: const CXXScopeSpec &SS, TemplateParameterList **ParamLists, unsigned NumParamLists, + bool IsFriend, bool &IsExplicitSpecialization); DeclResult CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 675cc36346..ab61487b68 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2393,6 +2393,7 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, D.getCXXScopeSpec(), (TemplateParameterList**)TemplateParamLists.get(), TemplateParamLists.size(), + /*never a friend*/ false, isExplicitSpecialization)) { if (TemplateParams->size() > 0) { // There is no such thing as a variable template. @@ -2943,6 +2944,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, D.getCXXScopeSpec(), (TemplateParameterList**)TemplateParamLists.get(), TemplateParamLists.size(), + isFriend, isExplicitSpecialization)) { if (TemplateParams->size() > 0) { // This is a function template @@ -3041,10 +3043,8 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, if (FunctionTemplate) { FunctionTemplate->setObjectOfFriendDecl(false); FunctionTemplate->setAccess(AS_public); - } else { - NewFD->setObjectOfFriendDecl(false); } - + NewFD->setObjectOfFriendDecl(false); NewFD->setAccess(AS_public); } @@ -3198,10 +3198,6 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, NewFD->setInvalidDecl(); } - // Make sure this is set before checking the function declaration. - // We'll override the visibility type later. - if (isFriend) NewFD->setObjectOfFriendDecl(false); - // Perform semantic checking on the function declaration. bool OverloadableAttrRequired = false; // FIXME: HACK! CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization, @@ -4766,6 +4762,7 @@ Sema::DeclPtrTy Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, = MatchTemplateParametersToScopeSpecifier(KWLoc, SS, (TemplateParameterList**)TemplateParameterLists.get(), TemplateParameterLists.size(), + TUK == TUK_Friend, isExplicitSpecialization)) { if (TemplateParams->size() > 0) { // This is a declaration or definition of a class template (which may diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 828085b8bc..9816e76530 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1229,6 +1229,10 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, /// /// \param NumParamLists the number of template parameter lists in ParamLists. /// +/// \param IsFriend Whether to apply the slightly different rules for +/// matching template parameters to scope specifiers in friend +/// declarations. +/// /// \param IsExplicitSpecialization will be set true if the entity being /// declared is an explicit specialization, false otherwise. /// @@ -1243,6 +1247,7 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, const CXXScopeSpec &SS, TemplateParameterList **ParamLists, unsigned NumParamLists, + bool IsFriend, bool &IsExplicitSpecialization) { IsExplicitSpecialization = false; @@ -1308,6 +1313,13 @@ Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, if (Idx >= NumParamLists) { // We have a template-id without a corresponding template parameter // list. + + // ...which is fine if this is a friend declaration. + if (IsFriend) { + IsExplicitSpecialization = true; + break; + } + if (DependentTemplateId) { // FIXME: the location information here isn't great. Diag(SS.getRange().getBegin(), @@ -3538,6 +3550,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, SS, (TemplateParameterList**)TemplateParameterLists.get(), TemplateParameterLists.size(), + TUK == TUK_Friend, isExplicitSpecialization); if (TemplateParams && TemplateParams->size() > 0) { isPartialSpecialization = true; @@ -4302,7 +4315,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, bool Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { assert(!isa(Member) && "Only for non-template members"); - + // Try to find the member we are instantiating. NamedDecl *Instantiation = 0; NamedDecl *InstantiatedFrom = 0; @@ -4348,6 +4361,25 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { // this mismatch later. return false; } + + // If this is a friend, just bail out here before we start turning + // things into explicit specializations. + if (Member->getFriendObjectKind() != Decl::FOK_None) { + // Preserve instantiation information. + if (InstantiatedFrom && isa(Member)) { + cast(Member)->setInstantiationOfMemberFunction( + cast(InstantiatedFrom), + cast(Instantiation)->getTemplateSpecializationKind()); + } else if (InstantiatedFrom && isa(Member)) { + cast(Member)->setInstantiationOfMemberClass( + cast(InstantiatedFrom), + cast(Instantiation)->getTemplateSpecializationKind()); + } + + Previous.clear(); + Previous.addDecl(Instantiation); + return false; + } // Make sure that this is a specialization of a member. if (!InstantiatedFrom) { diff --git a/test/CXX/class.access/class.friend/p1.cpp b/test/CXX/class.access/class.friend/p1.cpp index 991f611cdd..8dffd1dd86 100644 --- a/test/CXX/class.access/class.friend/p1.cpp +++ b/test/CXX/class.access/class.friend/p1.cpp @@ -222,3 +222,37 @@ namespace test6 { friend A &A::operator=(const A&); }; } + +namespace test7 { + template struct X { + X(); + ~X(); + void foo(); + void bar(); + }; + + class A { + friend void X::foo(); + friend X::X(); + friend X::X(const X&); + + private: + A(); // expected-note 2 {{declared private here}} + }; + + template<> void X::foo() { + A a; + } + + template<> void X::bar() { + A a; // expected-error {{calling a private constructor}} + } + + template<> X::X() { + A a; + } + + template<> X::~X() { + A a; // expected-error {{calling a private constructor}} + } +}