diff options
| author | Douglas Gregor <dgregor@apple.com> | 2010-05-04 15:20:55 +0000 |
|---|---|---|
| committer | Douglas Gregor <dgregor@apple.com> | 2010-05-04 15:20:55 +0000 |
| commit | 40c92bbe4fec5b8edba3c33aa837a94486f0f28d (patch) | |
| tree | 17fdb7a13f6c9327a58997d4881b0a0f9ebb53d4 | |
| parent | 8815f38312b7ecda9a307fa8bbf291f617d19828 (diff) | |
| download | bcm5719-llvm-40c92bbe4fec5b8edba3c33aa837a94486f0f28d.tar.gz bcm5719-llvm-40c92bbe4fec5b8edba3c33aa837a94486f0f28d.zip | |
When creating a call to a base subobject's operator= in an
implicitly-defined copy assignment operator, suppress the protected
access check. This eliminates the remaining failure in the
Boost.SmartPtr library (that was a product of the copy-assignment
generation rewrite) and, presumably, the Boost.TR1 library as well.
llvm-svn: 103010
| -rw-r--r-- | clang/include/clang/AST/UnresolvedSet.h | 1 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 33 | ||||
| -rw-r--r-- | clang/test/SemaCXX/default-assignment-operator.cpp | 28 |
3 files changed, 58 insertions, 4 deletions
diff --git a/clang/include/clang/AST/UnresolvedSet.h b/clang/include/clang/AST/UnresolvedSet.h index cad7e61d553..cbe00827d00 100644 --- a/clang/include/clang/AST/UnresolvedSet.h +++ b/clang/include/clang/AST/UnresolvedSet.h @@ -45,6 +45,7 @@ public: NamedDecl *getDecl() const { return ir->getDecl(); } AccessSpecifier getAccess() const { return ir->getAccess(); } + void setAccess(AccessSpecifier AS) { ir->setAccess(AS); } DeclAccessPair getPair() const { return *ir; } NamedDecl *operator*() const { return getDecl(); } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 6259b85af48..b9c7d7948f2 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -4134,13 +4134,16 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, /// /// \param From The expression we are copying from. /// +/// \param CopyingBaseSubobject Whether we're copying a base subobject. +/// Otherwise, it's a non-static member subobject. +/// /// \param Depth Internal parameter recording the depth of the recursion. /// /// \returns A statement or a loop that copies the expressions. static Sema::OwningStmtResult BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, Sema::OwningExprResult To, Sema::OwningExprResult From, - unsigned Depth = 0) { + bool CopyingBaseSubobject, unsigned Depth = 0) { typedef Sema::OwningStmtResult OwningStmtResult; typedef Sema::OwningExprResult OwningExprResult; @@ -4172,6 +4175,25 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, } F.done(); + // Suppress the protected check (C++ [class.protected]) for each of the + // assignment operators we found. This strange dance is required when + // we're assigning via a base classes's copy-assignment operator. To + // ensure that we're getting the right base class subobject (without + // ambiguities), we need to cast "this" to that subobject type; to + // ensure that we don't go through the virtual call mechanism, we need + // to qualify the operator= name with the base class (see below). However, + // this means that if the base class has a protected copy assignment + // operator, the protected member access check will fail. So, we + // rewrite "protected" access to "public" access in this case, since we + // know by construction that we're calling from a derived class. + if (CopyingBaseSubobject) { + for (LookupResult::iterator L = OpLookup.begin(), LEnd = OpLookup.end(); + L != LEnd; ++L) { + if (L.getAccess() == AS_protected) + L.setAccess(AS_public); + } + } + // Create the nested-name-specifier that will be used to qualify the // reference to operator=; this is required to suppress the virtual // call mechanism. @@ -4277,7 +4299,8 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, // Build the copy for an individual element of the array. OwningStmtResult Copy = BuildSingleCopyAssign(S, Loc, ArrayTy->getElementType(), - move(To), move(From), Depth+1); + move(To), move(From), + CopyingBaseSubobject, Depth+1); if (Copy.isInvalid()) { InitStmt->Destroy(S.Context); return S.StmtError(); @@ -4381,7 +4404,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // Build the copy. OwningStmtResult Copy = BuildSingleCopyAssign(*this, Loc, BaseType, - move(To), Owned(From)); + move(To), Owned(From), + /*CopyingBaseSubobject=*/true); if (Copy.isInvalid()) { Invalid = true; continue; @@ -4501,7 +4525,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // Build the copy of this field. OwningStmtResult Copy = BuildSingleCopyAssign(*this, Loc, FieldType, - move(To), move(From)); + move(To), move(From), + /*CopyingBaseSubobject=*/false); if (Copy.isInvalid()) { Invalid = true; continue; diff --git a/clang/test/SemaCXX/default-assignment-operator.cpp b/clang/test/SemaCXX/default-assignment-operator.cpp index a04de37fcb6..dee6d131e4a 100644 --- a/clang/test/SemaCXX/default-assignment-operator.cpp +++ b/clang/test/SemaCXX/default-assignment-operator.cpp @@ -89,3 +89,31 @@ void j() { e1 = e2; } +namespace ProtectedCheck { + struct X { + protected: + X &operator=(const X&); // expected-note{{declared protected here}} + }; + + struct Y : public X { }; + + void f(Y y) { y = y; } + + struct Z { // expected-error{{'operator=' is a protected member of 'ProtectedCheck::X'}} + X x; + }; + + void f(Z z) { z = z; } // +} + +namespace MultiplePaths { + struct X0 { + X0 &operator=(const X0&); + }; + + struct X1 : public virtual X0 { }; + + struct X2 : X0, X1 { }; + + void f(X2 x2) { x2 = x2; } +} |

