Richard Smith 8ce732b46f DR674, PR38883, PR40238: Qualified friend lookup should look for a
template specialization if there is no matching non-template function.

This exposed a couple of related bugs:
 - we would sometimes substitute into a friend template instead of a
   suitable non-friend declaration; this would now crash because we'd
   decide the specialization of the friend is a redeclaration of itself
 - ADL failed to properly handle the case where an invisible local
   extern declaration redeclares an invisible friend

Both are fixed herein: in particular, we now never make invisible
friends or local extern declarations visible to name lookup unless
they are the only declaration of the entity. (We already mostly did
this for local extern declarations.)

llvm-svn: 350505
2019-01-07 06:00:46 +00:00

93 lines
3.0 KiB
C++

// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct Outer {
struct Inner {
int intfield;
};
};
struct Base {
void base_member();
typedef int Int;
Int typedeffed_member();
};
struct Derived : public Base {
};
int myglobal;
void global_function();
extern "C" {
void global_c_function();
}
class A {
class AInner {
};
friend class PreDeclared;
friend class Outer::Inner;
friend int Outer::Inner::intfield; // expected-error {{friends can only be classes or functions}}
friend int Outer::Inner::missing_field; //expected-error {{friends can only be classes or functions}}
friend int myoperation(float); // okay
friend int myglobal; // expected-error {{friends can only be classes or functions}}
friend void global_function();
friend void global_c_function();
friend class UndeclaredSoFar;
UndeclaredSoFar x; // expected-error {{unknown type name 'UndeclaredSoFar'}}
void a_member();
friend void A::a_member();
#if __cplusplus <= 199711L
// expected-error@-2 {{friends cannot be members of the declaring class}}
#endif
friend void a_member(); // okay (because we ignore class scopes when looking up friends)
friend class A::AInner; // this is okay as an extension
friend class AInner; // okay, refers to ::AInner
friend void Derived::missing_member(); // expected-error {{friend declaration of 'missing_member' does not match any declaration in 'Derived'}}
friend void Derived::base_member(); // expected-error {{friend declaration of 'base_member' does not match any declaration in 'Derived'}}
friend int Base::typedeffed_member(); // okay: should look through typedef
// These test that the friend is properly not being treated as a
// member function.
friend A operator|(const A& l, const A& r); // okay
friend A operator|(const A& r); // expected-error {{overloaded 'operator|' must be a binary operator (has 1 parameter)}}
friend operator bool() const; // expected-error {{must use a qualified name when declaring a conversion operator as a friend}} \
// expected-error{{non-member function cannot have 'const' qualifier}}
typedef void ftypedef();
friend ftypedef typedeffed_function; // okay (because it's not declared as a member)
class facet;
friend class facet; // should not assert
class facet {};
friend int Unknown::thing(); // expected-error {{use of undeclared identifier}}
friend int friendfunc(), Unknown::thing(); // expected-error {{use of undeclared identifier}}
friend int friendfunc(), Unknown::thing() : 4; // expected-error {{use of undeclared identifier}}
};
A::UndeclaredSoFar y; // expected-error {{no type named 'UndeclaredSoFar' in 'A'}}
class PreDeclared;
int myoperation(float f) {
return (int) f;
}
template <typename T>
class B {
template <typename U>
friend B<U>() {} // expected-error {{must use a qualified name when declaring a constructor as a friend}}
};