1// RUN: %clang_cc1 %s -std=c++98 -triple %itanium_abi_triple -emit-llvm -o - | FileCheck %s
2// RUN: %clang_cc1 %s -std=c++98 -triple %itanium_abi_triple -emit-llvm -o - -DPROTOTYPE | FileCheck --check-prefix=CHECK-PROTOTYPE %s
3// RUN: %clang_cc1 %s -std=c++98 -triple %itanium_abi_triple -emit-llvm -o - -DINSTANTIATE | FileCheck --check-prefix=CHECK-INSTANTIATE %s
4// RUN: %clang_cc1 %s -std=c++98 -triple %itanium_abi_triple -emit-llvm -o - -DPROTOTYPE -DINSTANTIATE | FileCheck --check-prefix=CHECK-PROTOTYPE-INSTANTIATE %s
5// RUN: %clang_cc1 %s -DREDEFINE -verify
6// RUN: %clang_cc1 %s -DPROTOTYPE -DREDEFINE -verify
7// PR8007: friend function not instantiated, reordered version.
8// Corresponds to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=38392
9
10// CHECK: define linkonce_odr{{.*}}_ZlsR11std_ostreamRK8StreamerI3FooE
11// CHECK-PROTOTYPE: define linkonce_odr{{.*}}_ZlsR11std_ostreamRK8StreamerI3FooE
12// CHECK-INSTANTIATE: define linkonce_odr{{.*}}_ZlsR11std_ostreamRK8StreamerI3FooE
13// CHECK-PROTOTYPE-INSTANTIATE: define linkonce_odr{{.*}}_ZlsR11std_ostreamRK8StreamerI3FooE
14
15struct std_ostream
16{
17  int dummy;
18};
19
20std_ostream cout;
21
22template <typename STRUCT_TYPE>
23struct Streamer;
24
25typedef struct Foo {} Foo;
26
27inline std_ostream& operator << (std_ostream&, const Streamer<Foo>&);
28
29void test(const Streamer<Foo>& foo)
30{
31    cout << foo;
32}
33
34template <typename STRUCT_TYPE>
35struct Streamer
36{
37    friend std_ostream& operator << (std_ostream& o, const Streamer& f) // expected-error{{redefinition of 'operator<<'}}
38        {
39            Streamer s(f);
40            s(o);
41            return o;
42        }
43
44    Streamer(const STRUCT_TYPE& s) : s(s) {}
45
46    const STRUCT_TYPE& s;
47    void operator () (std_ostream&) const;
48};
49
50#ifdef PROTOTYPE
51std_ostream& operator << (std_ostream&, const Streamer<Foo>&);
52#endif
53
54#ifdef INSTANTIATE
55template struct Streamer<Foo>;
56#endif
57
58#ifdef REDEFINE
59std_ostream& operator << (std_ostream& o, const Streamer<Foo>&) // expected-note{{is here}}
60{
61  return o;
62}
63#endif
64
65#ifndef INSTANTIATE
66template <>
67void Streamer<Foo>::operator () (std_ostream& o) const // expected-note{{requested here}}
68{
69}
70#endif
71
72int main(void)
73{
74    Foo foo;
75    test(foo);
76}
77
78