forked from OSchip/llvm-project
Implement non-dependent friend functions and classes.
llvm-svn: 98764
This commit is contained in:
parent
a4d1c8f59f
commit
39e8288b40
|
@ -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<RecordType>())
|
||||
return MatchesFriend(S, EC, cast<CXXRecordDecl>(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<NamedDecl>(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<ClassTemplateDecl>(D)) {
|
||||
for (llvm::SmallVectorImpl<CXXRecordDecl*>::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<ClassTemplateSpecializationDecl>(Record)) {
|
||||
CTD = cast<ClassTemplateSpecializationDecl>(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<FunctionTemplateDecl>(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<CXXRecordDecl>(D))
|
||||
return MatchesFriend(S, EC, cast<CXXRecordDecl>(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<RecordType>())
|
||||
if (EC.includesClass(cast<CXXRecordDecl>(RT->getDecl())))
|
||||
return Sema::AR_accessible;
|
||||
} else {
|
||||
NamedDecl *D
|
||||
= cast<NamedDecl>(Friend->getFriendDecl()->getCanonicalDecl());
|
||||
switch (MatchesFriend(S, EC, Friend)) {
|
||||
case Sema::AR_accessible:
|
||||
return Sema::AR_accessible;
|
||||
|
||||
// The decl pointers in EC have been canonicalized, so pointer
|
||||
// equality is sufficient.
|
||||
if (D == EC.Function)
|
||||
return Sema::AR_accessible;
|
||||
case Sema::AR_inaccessible:
|
||||
break;
|
||||
|
||||
if (isa<CXXRecordDecl>(D) &&
|
||||
EC.includesClass(cast<CXXRecordDecl>(D)))
|
||||
return Sema::AR_accessible;
|
||||
case Sema::AR_dependent:
|
||||
OnFailure = Sema::AR_dependent;
|
||||
break;
|
||||
|
||||
case Sema::AR_delayed:
|
||||
llvm_unreachable("cannot get delayed answer from MatchesFriend");
|
||||
}
|
||||
|
||||
// FIXME: templates! templated contexts! dependent delay!
|
||||
}
|
||||
|
||||
// That's it, give up.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: %clang_cc1 -emit-llvm-only %s
|
||||
// RUN: %clang_cc1 -faccess-control -verify -emit-llvm-only %s
|
||||
|
||||
template <typename T> struct Num {
|
||||
T value_;
|
||||
|
@ -54,3 +54,34 @@ int calc2() {
|
|||
Num<int> result = x * n;
|
||||
return result.get();
|
||||
}
|
||||
|
||||
// Reduced from GNU <locale>
|
||||
namespace test1 {
|
||||
class A {
|
||||
bool b; // expected-note {{declared private here}}
|
||||
template <typename T> friend bool has(const A&);
|
||||
};
|
||||
template <typename T> bool has(const A &x) {
|
||||
return x.b;
|
||||
}
|
||||
template <typename T> 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 <typename T> friend class HasChecker;
|
||||
};
|
||||
template <typename T> class HasChecker {
|
||||
bool check(A *a) {
|
||||
return a->b;
|
||||
}
|
||||
};
|
||||
template <typename T> class HasNotChecker {
|
||||
bool check(A *a) {
|
||||
return a->b; // expected-error {{'b' is a private member of 'test2::A'}}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue