aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn McCall <rjmccall@apple.com>2010-03-16 06:11:48 +0000
committerJohn McCall <rjmccall@apple.com>2010-03-16 06:11:48 +0000
commitb020748a9954c995f2e616f50bb9ed4fe2df1f72 (patch)
tree8e5ba77226256d7a7b66ee039355a03bcfa2400e
parentc3d43b783dfb1a1502aa8b31ab1985cf237b1f77 (diff)
Access control for implicit calls to copy assignment operators and copy
constructors from implicitly-defined members. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@98614 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td14
-rw-r--r--lib/Sema/Sema.h3
-rw-r--r--lib/Sema/SemaAccess.cpp17
-rw-r--r--lib/Sema/SemaDeclCXX.cpp32
-rw-r--r--test/CXX/class.access/p4.cpp37
5 files changed, 99 insertions, 4 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 749b0467a6..9a9b7cc85f 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -447,6 +447,20 @@ def err_access_dtor_field :
def err_access_dtor_var :
Error<"variable of type %1 has %select{private|protected}2 destructor">,
NoSFINAE;
+def err_access_assign_field :
+ Error<"field of type %1 has %select{private|protected}2 copy assignment"
+ " operator">,
+ NoSFINAE;
+def err_access_assign_base :
+ Error<"base class %0 has %select{private|protected}1 copy assignment"
+ " operator">,
+ NoSFINAE;
+def err_access_copy_field :
+ Error<"field of type %1 has %select{private|protected}2 copy constructor">,
+ NoSFINAE;
+def err_access_copy_base :
+ Error<"base class %0 has %select{private|protected}1 copy constructor">,
+ NoSFINAE;
def note_previous_access_declaration : Note<
"previously declared '%1' here">;
def err_access_outside_class : Error<
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 2675734eca..4c258448da 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2628,6 +2628,9 @@ public:
AccessResult CheckDestructorAccess(SourceLocation Loc,
CXXDestructorDecl *Dtor,
const PartialDiagnostic &PDiag);
+ AccessResult CheckDirectMemberAccess(SourceLocation Loc,
+ NamedDecl *D,
+ const PartialDiagnostic &PDiag);
AccessResult CheckMemberOperatorAccess(SourceLocation Loc,
Expr *ObjectExpr,
Expr *ArgExpr,
diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 818d369f74..f0a38d5970 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -495,6 +495,23 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
return CheckAccess(*this, UseLoc, Entity);
}
+/// Checks direct (i.e. non-inherited) access to an arbitrary class
+/// member.
+Sema::AccessResult Sema::CheckDirectMemberAccess(SourceLocation UseLoc,
+ NamedDecl *Target,
+ const PartialDiagnostic &Diag) {
+ AccessSpecifier Access = Target->getAccess();
+ if (!getLangOptions().AccessControl ||
+ Access == AS_public)
+ return AR_accessible;
+
+ CXXRecordDecl *NamingClass = cast<CXXRecordDecl>(Target->getDeclContext());
+ AccessedEntity Entity(AccessedEntity::Member, NamingClass, Access, Target);
+ Entity.setDiag(Diag);
+ return CheckAccess(*this, UseLoc, Entity);
+}
+
+
/// Checks access to an overloaded member operator, including
/// conversion operators.
Sema::AccessResult Sema::CheckMemberOperatorAccess(SourceLocation OpLoc,
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 1b3612d1c7..c27b0d5013 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -3862,8 +3862,14 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (CXXMethodDecl *BaseAssignOpMethod =
getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0),
- BaseClassDecl))
+ BaseClassDecl)) {
+ CheckDirectMemberAccess(Base->getSourceRange().getBegin(),
+ BaseAssignOpMethod,
+ PartialDiagnostic(diag::err_access_assign_base)
+ << Base->getType());
+
MarkDeclarationReferenced(CurrentLocation, BaseAssignOpMethod);
+ }
}
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
E = ClassDecl->field_end(); Field != E; ++Field) {
@@ -3875,8 +3881,14 @@ void Sema::DefineImplicitOverloadedAssign(SourceLocation CurrentLocation,
= cast<CXXRecordDecl>(FieldClassType->getDecl());
if (CXXMethodDecl *FieldAssignOpMethod =
getAssignOperatorMethod(CurrentLocation, MethodDecl->getParamDecl(0),
- FieldClassDecl))
+ FieldClassDecl)) {
+ CheckDirectMemberAccess(Field->getLocation(),
+ FieldAssignOpMethod,
+ PartialDiagnostic(diag::err_access_assign_field)
+ << Field->getDeclName() << Field->getType());
+
MarkDeclarationReferenced(CurrentLocation, FieldAssignOpMethod);
+ }
} else if (FieldType->isReferenceType()) {
Diag(ClassDecl->getLocation(), diag::err_uninitialized_member_for_assign)
<< Context.getTagDeclType(ClassDecl) << 0 << Field->getDeclName();
@@ -3951,8 +3963,14 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CXXRecordDecl *BaseClassDecl
= cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl());
if (CXXConstructorDecl *BaseCopyCtor =
- BaseClassDecl->getCopyConstructor(Context, TypeQuals))
+ BaseClassDecl->getCopyConstructor(Context, TypeQuals)) {
+ CheckDirectMemberAccess(Base->getSourceRange().getBegin(),
+ BaseCopyCtor,
+ PartialDiagnostic(diag::err_access_copy_base)
+ << Base->getType());
+
MarkDeclarationReferenced(CurrentLocation, BaseCopyCtor);
+ }
}
for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(),
FieldEnd = ClassDecl->field_end();
@@ -3964,8 +3982,14 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation,
CXXRecordDecl *FieldClassDecl
= cast<CXXRecordDecl>(FieldClassType->getDecl());
if (CXXConstructorDecl *FieldCopyCtor =
- FieldClassDecl->getCopyConstructor(Context, TypeQuals))
+ FieldClassDecl->getCopyConstructor(Context, TypeQuals)) {
+ CheckDirectMemberAccess(Field->getLocation(),
+ FieldCopyCtor,
+ PartialDiagnostic(diag::err_access_copy_field)
+ << Field->getDeclName() << Field->getType());
+
MarkDeclarationReferenced(CurrentLocation, FieldCopyCtor);
+ }
}
}
CopyConstructor->setUsed();
diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp
index 49afcef9df..15b336a4d8 100644
--- a/test/CXX/class.access/p4.cpp
+++ b/test/CXX/class.access/p4.cpp
@@ -183,3 +183,40 @@ namespace test4 {
Private test1(Derived4 &d) { return d; }
Public test2(Derived4 &d) { return d; }
}
+
+// Implicit copy assignment operator uses.
+namespace test5 {
+ class A {
+ void operator=(const A &); // expected-note 2 {{declared private here}}
+ };
+
+ class Test1 { A a; }; // expected-error {{field of type 'test5::A' has private copy assignment operator}}
+ void test1() {
+ Test1 a;
+ a = Test1();
+ }
+
+ class Test2 : A {}; // expected-error {{base class 'test5::A' has private copy assignment operator}}
+ void test2() {
+ Test2 a;
+ a = Test2();
+ }
+}
+
+// Implicit copy constructor uses.
+namespace test6 {
+ class A {
+ public: A();
+ private: A(const A &); // expected-note 2 {{declared private here}}
+ };
+
+ class Test1 { A a; }; // expected-error {{field of type 'test6::A' has private copy constructor}}
+ void test1(const Test1 &t) {
+ Test1 a = t;
+ }
+
+ class Test2 : A {}; // expected-error {{base class 'test6::A' has private copy constructor}}
+ void test2(const Test2 &t) {
+ Test2 a = t;
+ }
+}