summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/Sema/SemaAccess.cpp4
-rw-r--r--clang/test/SemaCXX/friend.cpp55
2 files changed, 56 insertions, 3 deletions
diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp
index ffdb0aa27a6..37240c23b69 100644
--- a/clang/lib/Sema/SemaAccess.cpp
+++ b/clang/lib/Sema/SemaAccess.cpp
@@ -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.
diff --git a/clang/test/SemaCXX/friend.cpp b/clang/test/SemaCXX/friend.cpp
index 03589101e1b..55aa069803b 100644
--- a/clang/test/SemaCXX/friend.cpp
+++ b/clang/test/SemaCXX/friend.cpp
@@ -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;
+}
+}
OpenPOWER on IntegriCloud