From: John McCall Date: Mon, 9 Apr 2012 20:53:23 +0000 (+0000) Subject: Fix the access check performed as part of the determination of whether X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=12d8d80fb0f8d9cddecb34da0f37b0dc9fcaf5e6;p=clang 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154343 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 453c7f37f4..eb8b7998ce 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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); diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index 74c4f34d75..dea5e76d9e 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -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, diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 975ea5b7a7..704ff834b4 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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()) { + 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()) { diff --git a/test/CXX/class.access/class.protected/p1-cxx11.cpp b/test/CXX/class.access/class.protected/p1-cxx11.cpp new file mode 100644 index 0000000000..dc9b20d17c --- /dev/null +++ b/test/CXX/class.access/class.protected/p1-cxx11.cpp @@ -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; + } +}