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.

llvm-svn: 224471
This commit is contained in:
Reid Kleckner 2014-12-17 23:40:46 +00:00
parent 969902b43b
commit af9bf59ba9
2 changed files with 56 additions and 3 deletions

View 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.

View 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;
}
}