aboutsummaryrefslogtreecommitdiff
path: root/clang/test/SemaTemplate/GH55509.cpp
blob: b1ba8e513356d9035c7be7556ea0c7f6a4c10a0a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++26 %s

namespace t1 {
  template<int N> struct A {
    template<class C> friend auto cica(const A<N-1>&, C) {
      return N;
    }
  };

  template<> struct A<0> {
    template<class C> friend auto cica(const A<0>&, C);
    // expected-note@-1 {{declared here}}
  };

  void test() {
    cica(A<0>{}, 0);
    // expected-error@-1 {{function 'cica<int>' with deduced return type cannot be used before it is defined}}

    (void)A<1>{};
    cica(A<0>{}, 0);
  }
} // namespace t1
namespace t2 {
  template<int N> struct A {
    template<class C> friend auto cica(const A<N-1>&, C) {
      return N;
    }
  };

  template<> struct A<0> {
    template<class C> friend auto cica(const A<0>&, C);
  };

  template <int N, class = decltype(cica(A<N>{}, nullptr))>
  void MakeCica();
  // expected-note@-1 {{candidate function}}

  template <int N> void MakeCica(A<N+1> = {});
  // expected-note@-1 {{candidate function}}

  void test() {
    MakeCica<0>();

    MakeCica<0>();
    // expected-error@-1 {{call to 'MakeCica' is ambiguous}}
  }
} // namespace t2
namespace t3 {
  template<int N> struct A {
    template<class C> friend auto cica(const A<N-1>&, C) {
      return N-1;
    }
  };

  template<> struct A<0> {
    template<class C> friend auto cica(const A<0>&, C);
  };

  template <int N, class AT, class = decltype(cica(AT{}, nullptr))>
  static constexpr bool MakeCica(int);

  template <int N, class AT>
  static constexpr bool MakeCica(short, A<N+1> = {});

  template <int N, class AT = A<N>, class Val = decltype(MakeCica<N, AT>(0))>
  static constexpr bool has_cica = Val{};

  constexpr bool cica2 = has_cica<0> || has_cica<0>;
} // namespace t3
namespace t4 {
  template<int N> struct A {
    template<class C> friend auto cica(const A<N-1>&, C);
  };

  template<> struct A<0> {
    template<class C> friend auto cica(const A<0>&, C) {
      C a;
    }
  };

  template struct A<1>;

  void test() {
    cica(A<0>{}, 0);
  }
} // namespace t4
namespace regression1 {
  template <class> class A;

  template <class T> [[gnu::abi_tag("TAG")]] void foo(A<T>);

  template <class> struct A {
    friend void foo <>(A);
  };

  template struct A<int>;

  template <class T> [[gnu::abi_tag("TAG")]] void foo(A<T>) {}

  template void foo<int>(A<int>);
} // namespace regression1
namespace regression2 {
  template <class> struct A {
    template <class T> static void f() {
      A<int>::f<T>();
    }
  };
  template <> template <class T> void A<int>::f() {
    static_assert(__is_same(T, long));
  }
  template void A<void>::f<long>();
} // namespace regression2

namespace GH139226 {

struct FakeStream {};

template <typename T>
class BinaryTree;

template <typename T>
FakeStream& operator<<(FakeStream& os, BinaryTree<T>& b);

template <typename T>
FakeStream& operator>>(FakeStream& os, BinaryTree<T>& b) {
  return os;
}

template <typename T>
struct BinaryTree {
  T* root{};
  friend FakeStream& operator<< <T>(FakeStream& os, BinaryTree&) {
    // expected-error@-1 {{friend function specialization cannot be defined}}
    return os;
  }

  friend FakeStream& operator>> <T>(FakeStream& os, BinaryTree&);
};

void foo() {
  FakeStream fakeout;
  BinaryTree<int> a{};
  fakeout << a;
  fakeout >> a;
}

}