From a742db0032d8f458fe229600d2082981a1fb1481 Mon Sep 17 00:00:00 2001 From: John McCall Date: Wed, 17 Mar 2010 20:01:29 +0000 Subject: [PATCH] Implement non-dependent friend functions and classes. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@98764 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaAccess.cpp | 112 ++++++++++++++++---- test/CXX/temp/temp.decls/temp.friend/p1.cpp | 33 +++++- 2 files changed, 126 insertions(+), 19 deletions(-) diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index e7ec229d52..6c01fee74c 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -93,6 +93,88 @@ static CXXRecordDecl *FindDeclaringClass(NamedDecl *D) { return DeclaringClass; } +static Sema::AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + const CXXRecordDecl *Friend) { + // FIXME: close matches becuse of dependency + if (EC.includesClass(Friend)) + return Sema::AR_accessible; + + return Sema::AR_inaccessible; +} + +static Sema::AccessResult MatchesFriend(Sema &S, + const EffectiveContext &EC, + FriendDecl *Friend) { + if (Type *T = Friend->getFriendType()) { + CanQualType CT = T->getCanonicalTypeUnqualified(); + if (const RecordType *RT = CT->getAs()) + return MatchesFriend(S, EC, cast(RT->getDecl())); + + // TODO: we can fail early for a lot of type classes. + if (T->isDependentType()) + return Sema::AR_dependent; + + return Sema::AR_inaccessible; + } + + NamedDecl *D + = cast(Friend->getFriendDecl()->getCanonicalDecl()); + + // FIXME: declarations with dependent or templated scope. + + // For class templates, we want to check whether any of the records + // are possible specializations of the template. + if (isa(D)) { + for (llvm::SmallVectorImpl::const_iterator + I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { + CXXRecordDecl *Record = *I; + ClassTemplateDecl *CTD; + + // A specialization of the template... + if (isa(Record)) { + CTD = cast(Record) + ->getSpecializedTemplate(); + + // ... or the template pattern itself. + } else { + CTD = Record->getDescribedClassTemplate(); + } + + if (CTD && D == CTD->getCanonicalDecl()) + return Sema::AR_accessible; + } + + return Sema::AR_inaccessible; + } + + // Same thing for function templates. + if (isa(D)) { + if (!EC.Function) return Sema::AR_inaccessible; + + FunctionTemplateDecl *FTD = EC.Function->getPrimaryTemplate(); + if (!FTD) + FTD = EC.Function->getDescribedFunctionTemplate(); + + if (FTD && D == FTD->getCanonicalDecl()) + return Sema::AR_accessible; + + return Sema::AR_inaccessible; + } + + // Friend functions. FIXME: close matches due to dependency. + // + // The decl pointers in EC have been canonicalized, so pointer + // equality is sufficient. + if (D == EC.Function) + return Sema::AR_accessible; + + if (isa(D)) + return MatchesFriend(S, EC, cast(D)); + + return Sema::AR_inaccessible; +} + static Sema::AccessResult GetFriendKind(Sema &S, const EffectiveContext &EC, const CXXRecordDecl *Class) { @@ -107,26 +189,20 @@ static Sema::AccessResult GetFriendKind(Sema &S, E = Class->friend_end(); I != E; ++I) { FriendDecl *Friend = *I; - if (Type *T = Friend->getFriendType()) { - CanQualType CT = T->getCanonicalTypeUnqualified(); - if (const RecordType *RT = CT->getAs()) - if (EC.includesClass(cast(RT->getDecl()))) - return Sema::AR_accessible; - } else { - NamedDecl *D - = cast(Friend->getFriendDecl()->getCanonicalDecl()); - - // The decl pointers in EC have been canonicalized, so pointer - // equality is sufficient. - if (D == EC.Function) - return Sema::AR_accessible; + switch (MatchesFriend(S, EC, Friend)) { + case Sema::AR_accessible: + return Sema::AR_accessible; - if (isa(D) && - EC.includesClass(cast(D))) - return Sema::AR_accessible; - } + case Sema::AR_inaccessible: + break; - // FIXME: templates! templated contexts! dependent delay! + case Sema::AR_dependent: + OnFailure = Sema::AR_dependent; + break; + + case Sema::AR_delayed: + llvm_unreachable("cannot get delayed answer from MatchesFriend"); + } } // That's it, give up. diff --git a/test/CXX/temp/temp.decls/temp.friend/p1.cpp b/test/CXX/temp/temp.decls/temp.friend/p1.cpp index 7a28e70c9a..f1b3c814c4 100644 --- a/test/CXX/temp/temp.decls/temp.friend/p1.cpp +++ b/test/CXX/temp/temp.decls/temp.friend/p1.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm-only %s +// RUN: %clang_cc1 -faccess-control -verify -emit-llvm-only %s template struct Num { T value_; @@ -54,3 +54,34 @@ int calc2() { Num result = x * n; return result.get(); } + +// Reduced from GNU +namespace test1 { + class A { + bool b; // expected-note {{declared private here}} + template friend bool has(const A&); + }; + template bool has(const A &x) { + return x.b; + } + template bool hasnot(const A &x) { + return x.b; // expected-error {{'b' is a private member of 'test1::A'}} + } +} + +namespace test2 { + class A { + bool b; // expected-note {{declared private here}} + template friend class HasChecker; + }; + template class HasChecker { + bool check(A *a) { + return a->b; + } + }; + template class HasNotChecker { + bool check(A *a) { + return a->b; // expected-error {{'b' is a private member of 'test2::A'}} + } + }; +} -- 2.40.0