From: Reid Kleckner Date: Wed, 17 Dec 2014 23:40:46 +0000 (+0000) Subject: Don't assume friended C++ method decls have qualifiers X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=647af370c2c39e2ceabfd7bc1309dc22d02f6729;p=clang Don't assume friended C++ method decls have qualifiers 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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@224471 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index ffdb0aa27a..37240c23b6 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -1749,14 +1749,14 @@ Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) { return AR_accessible; CXXMethodDecl *method = cast(target->getAsFunction()); - assert(method->getQualifier()); AccessTarget entity(Context, AccessTarget::Member, cast(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/test/SemaCXX/friend.cpp b/test/SemaCXX/friend.cpp index 03589101e1..55aa069803 100644 --- a/test/SemaCXX/friend.cpp +++ b/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; +} +}