summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/clang/Sema/Sema.h3
-rw-r--r--lib/Sema/SemaAccess.cpp23
-rw-r--r--lib/Sema/SemaDeclCXX.cpp25
-rw-r--r--test/CXX/class.access/class.protected/p1-cxx11.cpp20
4 files changed, 69 insertions, 2 deletions
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<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()) {
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;
+ }
+}