When elevating access along an inheritance path, initialize the computed
access to the (elevated) access of the accessed declaration, if applicable,
rather than plunking that access onto the end after we've calculated the
inheritance access.

Also, being a friend of a derived class gives you public access to its
members (subject to later modification by further inheritance);  it does
not simply ignore a single location of restricted inheritance.

Also, when computing the best unprivileged path to a subobject, preserve
the information that the worst path might be AS_none (forbidden) rather
than a minimum of AS_private.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@98899 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/CXX/class.access/class.friend/p1.cpp b/test/CXX/class.access/class.friend/p1.cpp
index 83b4227..851cd3d 100644
--- a/test/CXX/class.access/class.friend/p1.cpp
+++ b/test/CXX/class.access/class.friend/p1.cpp
@@ -115,3 +115,37 @@
     }
   };
 }
+
+// Make sure that friends have access to inherited protected members.
+namespace test2 {
+  struct X;
+
+  class ilist_half_node {
+    friend struct ilist_walker_bad;
+    X *Prev;
+  protected:
+    X *getPrev() { return Prev; }
+  };
+
+  class ilist_node : private ilist_half_node { // expected-note {{declared private here}} expected-note {{constrained by private inheritance here}}
+    friend struct ilist_walker;
+    X *Next;
+    X *getNext() { return Next; } // expected-note {{declared private here}}
+  };
+
+  struct X : ilist_node {};
+
+  struct ilist_walker {
+    static X *getPrev(X *N) { return N->getPrev(); }
+    static X *getNext(X *N) { return N->getNext(); }
+  };  
+
+  struct ilist_walker_bad {
+    static X *getPrev(X *N) { return N->getPrev(); } // \
+    // expected-error {{'getPrev' is a private member of 'test2::ilist_half_node'}} \
+    // expected-error {{cannot cast 'test2::X' to its private base class 'test2::ilist_half_node'}}
+
+    static X *getNext(X *N) { return N->getNext(); } // \
+    // expected-error {{'getNext' is a private member of 'test2::ilist_node'}}
+  };  
+}
diff --git a/test/CXX/class.access/p4.cpp b/test/CXX/class.access/p4.cpp
index d101dcb..bc69bee 100644
--- a/test/CXX/class.access/p4.cpp
+++ b/test/CXX/class.access/p4.cpp
@@ -250,3 +250,15 @@
     new (2) A();
   }
 }
+
+// Don't silently upgrade forbidden-access paths to private.
+namespace test9 {
+  class A {
+    public: static int x;
+  };
+  class B : private A { // expected-note {{constrained by private inheritance here}}
+  };
+  class C : public B {
+    static int getX() { return x; } // expected-error {{'x' is a private member of 'test9::A'}}
+  };
+}
diff --git a/test/SemaCXX/access-base-class.cpp b/test/SemaCXX/access-base-class.cpp
index eeb5f1c..25fd9e5 100644
--- a/test/SemaCXX/access-base-class.cpp
+++ b/test/SemaCXX/access-base-class.cpp
@@ -63,13 +63,14 @@
   
   class A {};
   
-  class B : private A { // expected-note {{declared private here}}
+  class B : private A { // expected-note {{declared private here}} expected-note {{constrained by private inheritance here}}
     void f(C* c);
   };
   
   class C : public B { 
     void f(C *c) {
-      A* a = c; // expected-error {{cannot cast 'T6::C' to its private base class 'T6::A'}}
+      A* a = c; // expected-error {{cannot cast 'T6::C' to its private base class 'T6::A'}} \
+                // expected-error {{'A' is a private member of 'T6::A'}}
     }
   };