Fix the access check performed as part of the determination of whether

to define a special member function as deleted so that it properly
establishes an object context for the accesses to the base subobject
members.

llvm-svn: 154343
This commit is contained in:
John McCall 2012-04-09 20:53:23 +00:00
parent 883f2bb1f9
commit d42742143c
4 changed files with 69 additions and 2 deletions

View File

@ -4129,6 +4129,9 @@ public:
bool ForceUnprivileged = false);
void CheckLookupAccess(const LookupResult &R);
bool IsSimplyAccessible(NamedDecl *decl, DeclContext *Ctx);
bool isSpecialMemberAccessibleForDeletion(CXXMethodDecl *decl,
AccessSpecifier access,
QualType objectType);
void HandleDependentAccessCheck(const DependentDiagnostic &DD,
const MultiLevelTemplateArgumentList &TemplateArgs);

View File

@ -1507,6 +1507,29 @@ Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E,
return CheckAccess(*this, E->getMemberLoc(), Entity);
}
/// Is the given special member function accessible for the purposes of
/// deciding whether to define a special member function as deleted?
bool Sema::isSpecialMemberAccessibleForDeletion(CXXMethodDecl *decl,
AccessSpecifier access,
QualType objectType) {
// Fast path.
if (access == AS_public || !getLangOpts().AccessControl) return true;
AccessTarget entity(Context, AccessTarget::Member, decl->getParent(),
DeclAccessPair::make(decl, access), objectType);
// Suppress diagnostics.
entity.setDiag(PDiag());
switch (CheckAccess(*this, SourceLocation(), entity)) {
case AR_accessible: return true;
case AR_inaccessible: return false;
case AR_dependent: llvm_unreachable("dependent for =delete computation");
case AR_delayed: llvm_unreachable("cannot delay =delete computation");
}
llvm_unreachable("bad access result");
}
Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
CXXDestructorDecl *Dtor,
const PartialDiagnostic &PDiag,

View File

@ -4397,9 +4397,31 @@ struct SpecialMemberDeletionInfo {
bool shouldDeleteForSubobjectCall(Subobject Subobj,
Sema::SpecialMemberOverloadResult *SMOR,
bool IsDtorCallInCtor);
bool isAccessible(Subobject Subobj, CXXMethodDecl *D);
};
}
/// Is the given special member inaccessible when used on the given
/// sub-object.
bool SpecialMemberDeletionInfo::isAccessible(Subobject Subobj,
CXXMethodDecl *target) {
/// If we're operating on a base class, the object type is the
/// type of this special member.
QualType objectTy;
AccessSpecifier access = target->getAccess();;
if (CXXBaseSpecifier *base = Subobj.dyn_cast<CXXBaseSpecifier*>()) {
objectTy = S.Context.getTypeDeclType(MD->getParent());
access = CXXRecordDecl::MergeAccess(base->getAccessSpecifier(), access);
// If we're operating on a field, the object type is the type of the field.
} else {
objectTy = S.Context.getTypeDeclType(target->getParent());
}
return S.isSpecialMemberAccessibleForDeletion(target, access, objectTy);
}
/// Check whether we should delete a special member due to the implicit
/// definition containing a call to a special member of a subobject.
bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
@ -4414,8 +4436,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
DiagKind = !Decl ? 0 : 1;
else if (SMOR->getKind() == Sema::SpecialMemberOverloadResult::Ambiguous)
DiagKind = 2;
else if (S.CheckDirectMemberAccess(Loc, Decl, S.PDiag())
!= Sema::AR_accessible)
else if (!isAccessible(Subobj, Decl))
DiagKind = 3;
else if (!IsDtorCallInCtor && Field && Field->getParent()->isUnion() &&
!Decl->isTrivial()) {

View File

@ -0,0 +1,20 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// PR12497
namespace test0 {
class A {
protected:
A() {}
A(const A &) {}
~A() {}
A &operator=(const A &a) { return *this; }
};
class B : public A {};
void test() {
B b1;
B b2 = b1;
b1 = b2;
}
}