diff options
author | John McCall <rjmccall@apple.com> | 2010-03-16 06:11:48 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2010-03-16 06:11:48 +0000 |
commit | b020748a9954c995f2e616f50bb9ed4fe2df1f72 (patch) | |
tree | 8e5ba77226256d7a7b66ee039355a03bcfa2400e | |
parent | c3d43b783dfb1a1502aa8b31ab1985cf237b1f77 (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.td | 14 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 3 | ||||
-rw-r--r-- | lib/Sema/SemaAccess.cpp | 17 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 32 | ||||
-rw-r--r-- | test/CXX/class.access/p4.cpp | 37 |
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; + } +} |