When computing the effective context for access control,
make sure we walk up the DC chain for the current context,
rather than allowing ourselves to get switched over to the
canonical DC chain.  Fixes PR13642.

llvm-svn: 162616
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index ed72a56..58b1a51 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -97,14 +97,19 @@
     // functions (which can gain privileges through friendship), but we
     // take that as an oversight.
     while (true) {
+      // We want to add canonical declarations to the EC lists for
+      // simplicity of checking, but we need to walk up through the
+      // actual current DC chain.  Otherwise, something like a local
+      // extern or friend which happens to be the canonical
+      // declaration will really mess us up.
+
       if (isa<CXXRecordDecl>(DC)) {
-        CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl();
-        Records.push_back(Record);
+        CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
+        Records.push_back(Record->getCanonicalDecl());
         DC = Record->getDeclContext();
       } else if (isa<FunctionDecl>(DC)) {
-        FunctionDecl *Function = cast<FunctionDecl>(DC)->getCanonicalDecl();
-        Functions.push_back(Function);
-        
+        FunctionDecl *Function = cast<FunctionDecl>(DC);
+        Functions.push_back(Function->getCanonicalDecl());
         if (Function->getFriendObjectKind())
           DC = Function->getLexicalDeclContext();
         else
diff --git a/clang/test/CXX/class.access/class.friend/p1.cpp b/clang/test/CXX/class.access/class.friend/p1.cpp
index 3d3c5f7..19d94cf 100644
--- a/clang/test/CXX/class.access/class.friend/p1.cpp
+++ b/clang/test/CXX/class.access/class.friend/p1.cpp
@@ -356,3 +356,19 @@
     }
   };
 }
+
+// PR13642.  When computing the effective context, we were walking up
+// the DC chain for the canonical decl, which is unfortunate if that's
+// (e.g.) a friend declaration.
+namespace test14 {
+  class A {
+    class B { // expected-note {{implicitly declared private here}}
+      static int i;
+      friend void c();
+    };
+  };
+
+  void c() {
+    A::B::i = 5; // expected-error {{'B' is a private member of 'test14::A'}}
+  }
+}
diff --git a/clang/test/CXX/class.access/class.protected/p1.cpp b/clang/test/CXX/class.access/class.protected/p1.cpp
index c9491e1..132ff61 100644
--- a/clang/test/CXX/class.access/class.protected/p1.cpp
+++ b/clang/test/CXX/class.access/class.protected/p1.cpp
@@ -423,7 +423,7 @@
 // This friendship is not considered because a public member of A is
 // inaccessible in C.
 namespace test13 {
-  class A { protected: int foo(); }; // expected-note {{can only access this member on an object of type}}
+  class A { protected: int foo(); }; // expected-note {{declared protected here}}
   class B : private virtual A {};
   class C : private B { friend void test(); };
   class D : public virtual A {};