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;
|
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,
|
static Sema::AccessResult GetFriendKind(Sema &S,
|
||||||
const EffectiveContext &EC,
|
const EffectiveContext &EC,
|
||||||
const CXXRecordDecl *Class) {
|
const CXXRecordDecl *Class) {
|
||||||
|
@ -107,26 +189,20 @@ static Sema::AccessResult GetFriendKind(Sema &S,
|
||||||
E = Class->friend_end(); I != E; ++I) {
|
E = Class->friend_end(); I != E; ++I) {
|
||||||
FriendDecl *Friend = *I;
|
FriendDecl *Friend = *I;
|
||||||
|
|
||||||
if (Type *T = Friend->getFriendType()) {
|
switch (MatchesFriend(S, EC, Friend)) {
|
||||||
CanQualType CT = T->getCanonicalTypeUnqualified();
|
case Sema::AR_accessible:
|
||||||
if (const RecordType *RT = CT->getAs<RecordType>())
|
return Sema::AR_accessible;
|
||||||
if (EC.includesClass(cast<CXXRecordDecl>(RT->getDecl())))
|
|
||||||
return Sema::AR_accessible;
|
|
||||||
} else {
|
|
||||||
NamedDecl *D
|
|
||||||
= cast<NamedDecl>(Friend->getFriendDecl()->getCanonicalDecl());
|
|
||||||
|
|
||||||
// The decl pointers in EC have been canonicalized, so pointer
|
case Sema::AR_inaccessible:
|
||||||
// equality is sufficient.
|
break;
|
||||||
if (D == EC.Function)
|
|
||||||
return Sema::AR_accessible;
|
|
||||||
|
|
||||||
if (isa<CXXRecordDecl>(D) &&
|
case Sema::AR_dependent:
|
||||||
EC.includesClass(cast<CXXRecordDecl>(D)))
|
OnFailure = Sema::AR_dependent;
|
||||||
return Sema::AR_accessible;
|
break;
|
||||||
|
|
||||||
|
case Sema::AR_delayed:
|
||||||
|
llvm_unreachable("cannot get delayed answer from MatchesFriend");
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: templates! templated contexts! dependent delay!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// That's it, give up.
|
// 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 {
|
template <typename T> struct Num {
|
||||||
T value_;
|
T value_;
|
||||||
|
@ -54,3 +54,34 @@ int calc2() {
|
||||||
Num<int> result = x * n;
|
Num<int> result = x * n;
|
||||||
return result.get();
|
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