aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2010-04-13 20:37:33 +0000
committerJohn McCall <rjmccall@apple.com>2010-04-13 20:37:33 +0000
commit77e8b11524187f81548450e9e2ad9dd0e7200909 (patch)
tree7b8b1c4517ae74c319931df7d31e3c99d6a3fa47
parentc034974f103873bdccc91da99a30ab30295b5226 (diff)
Support befriending members of class template specializations.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101173 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Sema/Sema.h1
-rw-r--r--lib/Sema/SemaDecl.cpp11
-rw-r--r--lib/Sema/SemaTemplate.cpp34
-rw-r--r--test/CXX/class.access/class.friend/p1.cpp34
4 files changed, 72 insertions, 8 deletions
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<TemplateDecl>(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<CXXMethodDecl>(Member)) {
+ cast<CXXMethodDecl>(Member)->setInstantiationOfMemberFunction(
+ cast<CXXMethodDecl>(InstantiatedFrom),
+ cast<CXXMethodDecl>(Instantiation)->getTemplateSpecializationKind());
+ } else if (InstantiatedFrom && isa<CXXRecordDecl>(Member)) {
+ cast<CXXRecordDecl>(Member)->setInstantiationOfMemberClass(
+ cast<CXXRecordDecl>(InstantiatedFrom),
+ cast<CXXRecordDecl>(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 <class T> struct X {
+ X();
+ ~X();
+ void foo();
+ void bar();
+ };
+
+ class A {
+ friend void X<int>::foo();
+ friend X<int>::X();
+ friend X<int>::X(const X&);
+
+ private:
+ A(); // expected-note 2 {{declared private here}}
+ };
+
+ template<> void X<int>::foo() {
+ A a;
+ }
+
+ template<> void X<int>::bar() {
+ A a; // expected-error {{calling a private constructor}}
+ }
+
+ template<> X<int>::X() {
+ A a;
+ }
+
+ template<> X<int>::~X() {
+ A a; // expected-error {{calling a private constructor}}
+ }
+}