From 70d577644b8d80f4643b113ea596f313e73ac8af Mon Sep 17 00:00:00 2001
From: John McCall <rjmccall@apple.com>
Date: Wed, 9 Sep 2015 23:04:17 +0000
Subject: [PATCH] Fix access control for lookups using the Microsoft __super
 extension.

rdar://22464808

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@247207 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/Sema/SemaLookup.cpp          | 17 +++++++++--
 test/SemaCXX/microsoft-super.cpp | 49 ++++++++++++++++++++++++++++++++
 2 files changed, 64 insertions(+), 2 deletions(-)
 create mode 100644 test/SemaCXX/microsoft-super.cpp

diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp
index dc23c13fbb3..923da4e06b6 100644
--- a/lib/Sema/SemaLookup.cpp
+++ b/lib/Sema/SemaLookup.cpp
@@ -2098,17 +2098,30 @@ bool Sema::LookupParsedName(LookupResult &R, Scope *S, CXXScopeSpec *SS,
 ///
 /// @returns True if any decls were found (but possibly ambiguous)
 bool Sema::LookupInSuper(LookupResult &R, CXXRecordDecl *Class) {
+  // The access-control rules we use here are essentially the rules for
+  // doing a lookup in Class that just magically skipped the direct
+  // members of Class itself.  That is, the naming class is Class, and the
+  // access includes the access of the base.
   for (const auto &BaseSpec : Class->bases()) {
     CXXRecordDecl *RD = cast<CXXRecordDecl>(
         BaseSpec.getType()->castAs<RecordType>()->getDecl());
     LookupResult Result(*this, R.getLookupNameInfo(), R.getLookupKind());
 	Result.setBaseObjectType(Context.getRecordType(Class));
     LookupQualifiedName(Result, RD);
-    for (auto *Decl : Result)
-      R.addDecl(Decl);
+
+    // Copy the lookup results into the target, merging the base's access into
+    // the path access.
+    for (auto I = Result.begin(), E = Result.end(); I != E; ++I) {
+      R.addDecl(I.getDecl(),
+                CXXRecordDecl::MergeAccess(BaseSpec.getAccessSpecifier(),
+                                           I.getAccess()));
+    }
+
+    Result.suppressDiagnostics();
   }
 
   R.resolveKind();
+  R.setNamingClass(Class);
 
   return !R.empty();
 }
diff --git a/test/SemaCXX/microsoft-super.cpp b/test/SemaCXX/microsoft-super.cpp
new file mode 100644
index 00000000000..bfa9d17dbc2
--- /dev/null
+++ b/test/SemaCXX/microsoft-super.cpp
@@ -0,0 +1,49 @@
+// RUN: %clang_cc1 -fms-extensions -verify %s
+
+// rdar://22464808
+
+namespace test0 {
+  class A {
+  private:
+    void foo(int*);
+  public:
+    void foo(long*);
+  };
+  class B : public A {
+    void test() {
+      __super::foo((long*) 0);
+    }
+  };
+}
+
+namespace test1 {
+  struct A {
+    static void foo(); // expected-note {{member is declared here}}
+  };
+  struct B : private A { // expected-note {{constrained by private inheritance here}}
+    void test() {
+      __super::foo();
+    }
+  };
+  struct C : public B {
+    void test() {
+      __super::foo(); // expected-error {{'foo' is a private member of 'test1::A'}}
+    }
+  };
+}
+
+namespace test2 {
+  struct A {
+    static void foo();
+  };
+  struct B : public A {
+    void test() {
+      __super::foo();
+    }
+  };
+  struct C : private B {
+    void test() {
+      __super::foo();
+    }
+  };
+}
-- 
GitLab