Don't assume friended C++ method decls have qualifiers
authorReid Kleckner <reid@kleckner.net>
Wed, 17 Dec 2014 23:40:46 +0000 (23:40 +0000)
committerReid Kleckner <reid@kleckner.net>
Wed, 17 Dec 2014 23:40:46 +0000 (23:40 +0000)
There are a few cases where unqualified lookup can find C++ methods.
Unfortunately, none of them seem to have illegal access paths, so I
can't excercise the diagnostic source range code that I am changing
here.

Fixes PR21851, which was a crash on valid.

llvm-svn: 224471

clang/lib/Sema/SemaAccess.cpp
clang/test/SemaCXX/friend.cpp

index ffdb0aa..37240c2 100644 (file)
@@ -1749,14 +1749,14 @@ Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) {
     return AR_accessible;
 
   CXXMethodDecl *method = cast<CXXMethodDecl>(target->getAsFunction());
-  assert(method->getQualifier());
 
   AccessTarget entity(Context, AccessTarget::Member,
                       cast<CXXRecordDecl>(target->getDeclContext()),
                       DeclAccessPair::make(target, access),
                       /*no instance context*/ QualType());
   entity.setDiag(diag::err_access_friend_function)
-    << method->getQualifierLoc().getSourceRange();
+      << (method->getQualifier() ? method->getQualifierLoc().getSourceRange()
+                                 : method->getNameInfo().getSourceRange());
 
   // We need to bypass delayed-diagnostics because we might be called
   // while the ParsingDeclarator is active.
index 0358910..55aa069 100644 (file)
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++14
 
 friend class A; // expected-error {{'friend' used outside of class}}
 void f() { friend class A; } // expected-error {{'friend' used outside of class}}
@@ -296,3 +296,56 @@ namespace test11 {
     friend class __attribute__((visibility("hidden"), noreturn)) B; // expected-warning {{'noreturn' attribute only applies to functions and methods}}
   };
 }
+
+namespace pr21851 {
+// PR21851 was a problem where we assumed that when the friend function redecl
+// lookup found a C++ method, it would necessarily have a qualifier. Below we
+// have some test cases where unqualified lookup finds C++ methods without using
+// qualifiers. Unfortunately, we can't exercise the case of an access check
+// failure because nested classes always have access to the members of outer
+// classes.
+
+void friend_own_method() {
+  class A {
+    void m() {}
+    friend void m();
+  };
+}
+
+void friend_enclosing_method() {
+  class A;
+  class C {
+    int p;
+    friend class A;
+  };
+  class A {
+    void enclosing_friend() {
+      (void)b->p;
+      (void)c->p;
+    }
+    class B {
+      void b(A *a) {
+        (void)a->c->p;
+      }
+      int p;
+      friend void enclosing_friend();
+    };
+    B *b;
+    C *c;
+  };
+}
+
+static auto friend_file_func() {
+  extern void file_scope_friend();
+  class A {
+    int p;
+    friend void file_scope_friend();
+  };
+  return A();
+}
+
+void file_scope_friend() {
+  auto a = friend_file_func();
+  (void)a.p;
+}
+}