From ac57f0b9097e04f70a631549383a2944f74ad844 Mon Sep 17 00:00:00 2001
From: Douglas Gregor <dgregor@apple.com>
Date: Sun, 9 Oct 2011 22:38:36 +0000
Subject: [PATCH] The effective context of a friend function is its lexical
 context. Fixes PR9103.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141520 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Sema/SemaAccess.cpp                      |  6 +++++-
 test/CXX/class.access/class.friend/p1.cpp    | 13 +++++++++++++
 test/CXX/class.access/class.protected/p1.cpp |  2 +-
 3 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp
index 14c8ebafe7d..d322ebd4100 100644
--- a/lib/Sema/SemaAccess.cpp
+++ b/lib/Sema/SemaAccess.cpp
@@ -103,7 +103,11 @@ struct EffectiveContext {
       } else if (isa<FunctionDecl>(DC)) {
         FunctionDecl *Function = cast<FunctionDecl>(DC)->getCanonicalDecl();
         Functions.push_back(Function);
-        DC = Function->getDeclContext();
+        
+        if (Function->getFriendObjectKind())
+          DC = Function->getLexicalDeclContext();
+        else
+          DC = Function->getDeclContext();
       } else if (DC->isFileContext()) {
         break;
       } else {
diff --git a/test/CXX/class.access/class.friend/p1.cpp b/test/CXX/class.access/class.friend/p1.cpp
index 1668155c181..68ff83fee83 100644
--- a/test/CXX/class.access/class.friend/p1.cpp
+++ b/test/CXX/class.access/class.friend/p1.cpp
@@ -341,3 +341,16 @@ namespace test12 {
     void *var = static_cast<B*>(this)->mem;
   }
 }
+
+namespace PR9103 {
+  struct base {
+  protected:
+    static void foo(void) {}
+  };
+
+  struct cls: base {
+    friend void bar(void) {
+      base::foo();
+    }
+  };
+}
diff --git a/test/CXX/class.access/class.protected/p1.cpp b/test/CXX/class.access/class.protected/p1.cpp
index 8698fb1da8a..79bb6cd67ea 100644
--- a/test/CXX/class.access/class.protected/p1.cpp
+++ b/test/CXX/class.access/class.protected/p1.cpp
@@ -423,7 +423,7 @@ namespace test12 {
 // This friendship is not considered because a public member of A is
 // inaccessible in C.
 namespace test13 {
-  class A { protected: int foo(); }; // expected-note {{declared protected here}}
+  class A { protected: int foo(); }; // expected-note {{object type 'test13::D' must derive from context type 'test13::C'}}
   class B : private virtual A {};
   class C : private B { friend void test(); };
   class D : public virtual A {};
-- 
GitLab