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
diff --git a/clang/include/clang/AST/UnresolvedSet.h b/clang/include/clang/AST/UnresolvedSet.h
index cad7e61..cbe0082 100644
--- a/clang/include/clang/AST/UnresolvedSet.h
+++ b/clang/include/clang/AST/UnresolvedSet.h
@@ -45,6 +45,7 @@
 
   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 6259b85..b9c7d79 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -4134,13 +4134,16 @@
 ///
 /// \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 @@
     }
     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 @@
   // 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 @@
 
     // 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 @@
     
     // 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 a04de37..dee6d13 100644
--- a/clang/test/SemaCXX/default-assignment-operator.cpp
+++ b/clang/test/SemaCXX/default-assignment-operator.cpp
@@ -89,3 +89,31 @@
   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; }
+}