1 // RUN: %clang_cc1 -fsyntax-only -verify %s
2 template<typename T> struct A {
3   struct B { };
4 
5   friend struct B;
6 };
7 
f()8 void f() {
9   A<int>::B b;
10 }
11 
12 struct C0 {
13   friend struct A<int>;
14 };
15 
16 namespace PR6770 {
17   namespace N {
18     int f1(int);
19   }
20   using namespace N;
21 
22   namespace M {
23     float f1(float);
24   }
25   using M::f1;
26 
27   template<typename T> void f1(T, T);
28   template <class T>
f()29   void f() {
30     friend class f; // expected-error{{'friend' used outside of class}}
31     friend class f1; // expected-error{{'friend' used outside of class}}
32   }
33 }
34 
35 namespace friend_redecl_inline {
36 // We had a bug where instantiating the foo friend declaration would check the
37 // defined-ness of the most recent decl while checking if the canonical decl was
38 // inlined.
39 void foo();
40 void bar();
41 template <typename T>
42 class C {
43   friend void foo();
44   friend inline void bar();
45 };
foo()46 inline void foo() {}
bar()47 inline void bar() {}
48 C<int> c;
49 }
50 
51 namespace qualified_friend {
52   void f(int); // expected-note 2{{type mismatch at 1st parameter}}
53   template<typename T> void f(T*); // expected-note 2{{could not match 'type-parameter-0-0 *' against 'double'}}
54   template<typename T> void nondep();
55 
56   template<typename> struct X1 {
57     friend void qualified_friend::f(double); // expected-error {{friend declaration of 'f' does not match any declaration in namespace 'qualified_friend'}}
58     friend void qualified_friend::g(); // expected-error {{friend declaration of 'g' does not match any declaration in namespace 'qualified_friend'}}
59   };
60   template<typename T> struct X2 {
61     friend void qualified_friend::f(T); // expected-error {{friend declaration of 'f' does not match any declaration in namespace 'qualified_friend'}}
62   };
63   X1<int> xi;
64   X2<double> xd; // expected-note {{in instantiation of}}
65   X2<int> x2i;
66 
67   struct Y {
68     void f(int); // expected-note 2{{type mismatch at 1st parameter}}
69     template<typename T> void f(T*); // expected-note 2{{could not match 'type-parameter-0-0 *' against 'double'}}
70     template<typename T> void nondep();
71   };
72 
73   template<typename> struct Z1 {
74     friend void Y::f(double); // expected-error {{friend declaration of 'f' does not match any declaration in 'qualified_friend::Y'}}
75     friend void Y::g(); // expected-error {{friend declaration of 'g' does not match any declaration in 'qualified_friend::Y'}}
76   };
77   template<typename T> struct Z2 {
78     friend void Y::f(T); // expected-error {{friend declaration of 'f' does not match any declaration in 'qualified_friend::Y'}}
79   };
80   Z1<int> zi;
81   Z2<double> zd; // expected-note {{in instantiation of}}
82   Z2<int> z2i;
83 
84   template<typename T>
85   struct OK {
86     friend void qualified_friend::f(int);
87     friend void qualified_friend::f(int*);
88     friend void qualified_friend::f(T*);
89     friend void qualified_friend::f<T>(T*);
90     friend void qualified_friend::nondep<int>();
91     friend void qualified_friend::nondep<T>();
92 
93     friend void Y::f(int);
94     friend void Y::f(int*);
95     friend void Y::f(T*);
96     friend void Y::f<T>(T*);
97     friend void Y::nondep<int>();
98     friend void Y::nondep<T>();
99   };
100   OK<float> ok;
101 }
102 
103 namespace qualified_friend_finds_nothing {
104   // FIXME: The status of this example is unclear. For now, we diagnose if the
105   // qualified declaration has nothing it can redeclare, but allow qualified
106   // lookup to find later-declared function templates during instantiation.
107   //
108   // This matches the behavior of GCC, EDG, ICC, and MSVC (except that GCC and
109   // ICC bizarrely accept the instantiation of B<float>).
110   namespace N {}
111 
112   template<typename T> struct A {
113     friend void N::f(T); // expected-error {{friend declaration of 'f' does not match}}
114   };
115   namespace N { void f(); } // expected-note {{different number of parameters}}
116 
117   template<typename T> struct B {
118     friend void N::f(T); // expected-error {{friend declaration of 'f' does not match}}
119   };
120   B<float> bf; // expected-note {{in instantiation of}}
121 
122   namespace N { void f(int); }
123   B<int> bi; // ok?!
124 }
125