summaryrefslogtreecommitdiff
path: root/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
blob: d21fbf28928997f36540a1cba3ab0ddec1a81525 (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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
// RUN: %clang_cc1 -std=c++1z -verify %s -DERRORS -Wundefined-func-template
// RUN: %clang_cc1 -std=c++1z -verify %s -UERRORS -Wundefined-func-template

// This test is split into two because we only produce "undefined internal"
// warnings if we didn't produce any errors.
#if ERRORS

namespace std {
  using size_t = decltype(sizeof(0));
  template<typename T> struct initializer_list {
    const T *p;
    size_t n;
    initializer_list();
  };
  // FIXME: This should probably not be necessary.
  template<typename T> initializer_list(initializer_list<T>) -> initializer_list<T>;
}

template<typename T> constexpr bool has_type(...) { return false; }
template<typename T> constexpr bool has_type(T) { return true; }

std::initializer_list il = {1, 2, 3, 4, 5};

template<typename T> struct vector {
  template<typename Iter> vector(Iter, Iter);
  vector(std::initializer_list<T>);
};

template<typename T> vector(std::initializer_list<T>) -> vector<T>;
template<typename Iter> explicit vector(Iter, Iter) -> vector<typename Iter::value_type>;
template<typename T> explicit vector(std::size_t, T) -> vector<T>;

vector v1 = {1, 2, 3, 4};
static_assert(has_type<vector<int>>(v1));

struct iter { typedef char value_type; } it, end;
vector v2(it, end);
static_assert(has_type<vector<char>>(v2));

vector v3(5, 5);
static_assert(has_type<vector<int>>(v3));

vector v4 = {it, end};
static_assert(has_type<vector<iter>>(v4));

vector v5{it, end};
static_assert(has_type<vector<iter>>(v5));

template<typename ...T> struct tuple { tuple(T...); };
template<typename ...T> explicit tuple(T ...t) -> tuple<T...>; // expected-note {{declared}}
// FIXME: Remove
template<typename ...T> tuple(tuple<T...>) -> tuple<T...>;

const int n = 4;
tuple ta = tuple{1, 'a', "foo", n};
static_assert(has_type<tuple<int, char, const char*, int>>(ta));

tuple tb{ta};
static_assert(has_type<tuple<int, char, const char*, int>>(tb));

// FIXME: This should be tuple<tuple<...>>; when the above guide is removed.
tuple tc = {ta};
static_assert(has_type<tuple<int, char, const char*, int>>(tc));

tuple td = {1, 2, 3}; // expected-error {{selected an explicit deduction guide}}
static_assert(has_type<tuple<int, char, const char*, int>>(td));

// FIXME: This is a GCC extension for now; if CWG don't allow this, at least
// add a warning for it.
namespace new_expr {
  tuple<int> *p = new tuple{0};
  tuple<float, float> *q = new tuple(1.0f, 2.0f);
}

namespace ambiguity {
  template<typename T> struct A {};
  A(unsigned short) -> A<int>; // expected-note {{candidate}}
  A(short) -> A<int>; // expected-note {{candidate}}
  A a = 0; // expected-error {{ambiguous deduction for template arguments of 'A'}}

  template<typename T> struct B {};
  template<typename T> B(T(&)(int)) -> B<int>; // expected-note {{candidate function [with T = int]}}
  template<typename T> B(int(&)(T)) -> B<int>; // expected-note {{candidate function [with T = int]}}
  int f(int);
  B b = f; // expected-error {{ambiguous deduction for template arguments of 'B'}}
}

// FIXME: Revisit this once CWG decides if attributes, and [[deprecated]] in
// particular, should be permitted here.
namespace deprecated {
  template<typename T> struct A { A(int); };
  [[deprecated]] A(int) -> A<void>; // expected-note {{marked deprecated here}}
  A a = 0; // expected-warning {{'<deduction guide for A>' is deprecated}}
}

namespace dependent {
  template<template<typename...> typename A> decltype(auto) a = A{1, 2, 3};
  static_assert(has_type<vector<int>>(a<vector>));
  static_assert(has_type<tuple<int, int, int>>(a<tuple>));

  struct B {
    template<typename T> struct X { X(T); };
    X(int) -> X<int>;
    template<typename T> using Y = X<T>; // expected-note {{template}}
  };
  template<typename T> void f() {
    typename T::X tx = 0;
    typename T::Y ty = 0; // expected-error {{alias template 'Y' requires template arguments; argument deduction only allowed for class templates}}
  }
  template void f<B>(); // expected-note {{in instantiation of}}

  template<typename T> struct C { C(T); };
  template<typename T> C(T) -> C<T>;
  template<typename T> void g(T a) {
    C b = 0;
    C c = a;
    using U = decltype(b); // expected-note {{previous}}
    using U = decltype(c); // expected-error {{different types ('C<const char *>' vs 'C<int>')}}
  }
  void h() {
    g(0);
    g("foo"); // expected-note {{instantiation of}}
  }
}

namespace look_into_current_instantiation {
  template<typename U> struct Q {};
  template<typename T> struct A {
    using U = T;
    template<typename> using V = Q<A<T>::U>;
    template<typename W = int> A(V<W>);
  };
  A a = Q<float>(); // ok, can look through class-scope typedefs and alias
                    // templates, and members of the current instantiation
  A<float> &r = a;

  template<typename T> struct B { // expected-note {{could not match 'B<T>' against 'int'}}
    struct X {
      typedef T type;
    };
    B(typename X::type); // expected-note {{couldn't infer template argument 'T'}}
  };
  B b = 0; // expected-error {{no viable}}

  // We should have a substitution failure in the immediate context of
  // deduction when using the C(T, U) constructor (probably; core wording
  // unclear).
  template<typename T> struct C {
    using U = typename T::type;
    C(T, U);
  };

  struct R { R(int); typedef R type; };
  C(...) -> C<R>;

  C c = {1, 2};
}

namespace nondeducible {
  template<typename A, typename B> struct X {};

  template<typename A> // expected-note {{non-deducible template parameter 'A'}}
  X() -> X<A, int>; // expected-error {{deduction guide template contains a template parameter that cannot be deduced}}

  template<typename A> // expected-note {{non-deducible template parameter 'A'}}
  X(typename X<A, int>::type) -> X<A, int>; // expected-error {{deduction guide template contains a template parameter that cannot be deduced}}

  template<typename A = int,
           typename B> // expected-note {{non-deducible template parameter 'B'}}
  X(int) -> X<A, B>; // expected-error {{deduction guide template contains a template parameter that cannot be deduced}}

  template<typename A = int,
           typename ...B>
  X(float) -> X<A, B...>; // ok
}

namespace default_args_from_ctor {
  template <class A> struct S { S(A = 0) {} };
  S s(0);

  template <class A> struct T { template<typename B> T(A = 0, B = 0) {} };
  T t(0, 0);
}

namespace transform_params {
  template<typename T, T N, template<T (*v)[N]> typename U, T (*X)[N]>
  struct A {
    template<typename V, V M, V (*Y)[M], template<V (*v)[M]> typename W>
    A(U<X>, W<Y>);

    static constexpr T v = N;
  };

  int n[12];
  template<int (*)[12]> struct Q {};
  Q<&n> qn;
  A a(qn, qn);
  static_assert(a.v == 12);

  template<typename ...T> struct B {
    template<T ...V> B(const T (&...p)[V]) {
      constexpr int Vs[] = {V...};
      static_assert(Vs[0] == 3 && Vs[1] == 4 && Vs[2] == 4);
    }
    static constexpr int (*p)(T...) = (int(*)(int, char, char))nullptr;
  };
  B b({1, 2, 3}, "foo", {'x', 'y', 'z', 'w'}); // ok

  template<typename ...T> struct C {
    template<T ...V, template<T...> typename X>
      C(X<V...>);
  };
  template<int...> struct Y {};
  C c(Y<0, 1, 2>{});

  template<typename ...T> struct D {
    template<T ...V> D(Y<V...>);
  };
  D d(Y<0, 1, 2>{});
}

namespace variadic {
  int arr3[3], arr4[4];

  // PR32673
  template<typename T> struct A {
    template<typename ...U> A(T, U...);
  };
  A a(1, 2, 3);

  template<typename T> struct B {
    template<int ...N> B(T, int (&...r)[N]);
  };
  B b(1, arr3, arr4);

  template<typename T> struct C {
    template<template<typename> typename ...U> C(T, U<int>...);
  };
  C c(1, a, b);

  template<typename ...U> struct X {
    template<typename T> X(T, U...);
  };
  X x(1, 2, 3);

  template<int ...N> struct Y {
    template<typename T> Y(T, int (&...r)[N]);
  };
  Y y(1, arr3, arr4);

  template<template<typename> typename ...U> struct Z {
    template<typename T> Z(T, U<int>...);
  };
  Z z(1, a, b);
}

namespace tuple_tests {
  // The converting n-ary constructor appears viable, deducing T as an empty
  // pack (until we check its SFINAE constraints).
  namespace libcxx_1 {
    template<class ...T> struct tuple {
      template<class ...Args> struct X { static const bool value = false; };
      template<class ...U, bool Y = X<U...>::value> tuple(U &&...u);
    };
    tuple a = {1, 2, 3};
  }

  // Don't get caught by surprise when X<...> doesn't even exist in the
  // selected specialization!
  namespace libcxx_2 {
    template<class ...T> struct tuple { // expected-note {{candidate}}
      template<class ...Args> struct X { static const bool value = false; };
      template<class ...U, bool Y = X<U...>::value> tuple(U &&...u);
      // expected-note@-1 {{substitution failure [with T = <>, U = <int, int, int>]: cannot reference member of primary template because deduced class template specialization 'tuple<>' is an explicit specialization}}
    };
    template <> class tuple<> {};
    tuple a = {1, 2, 3}; // expected-error {{no viable constructor or deduction guide}}
  }

  namespace libcxx_3 {
    template<typename ...T> struct scoped_lock {
      scoped_lock(T...);
    };
    template<> struct scoped_lock<> {};
    scoped_lock l = {};
  }
}

namespace dependent {
  template<typename T> struct X {
    X(T);
  };
  template<typename T> int Var(T t) {
    X x(t);
    return X(x) + 1; // expected-error {{invalid operands}}
  }
  template<typename T> int Cast(T t) {
    return X(X(t)) + 1; // expected-error {{invalid operands}}
  }
  template<typename T> int New(T t) {
    return X(new X(t)) + 1; // expected-error {{invalid operands}}
  };
  template int Var(float); // expected-note {{instantiation of}}
  template int Cast(float); // expected-note {{instantiation of}}
  template int New(float); // expected-note {{instantiation of}}
  template<typename T> int operator+(X<T>, int);
  template int Var(int);
  template int Cast(int);
  template int New(int);
}

namespace injected_class_name {
  template<typename T = void> struct A {
    A();
    template<typename U> A(A<U>);
  };
  A<int> a;
  A b = a;
  using T = decltype(a);
  using T = decltype(b);
}

#else

// expected-no-diagnostics
namespace undefined_warnings {
  // Make sure we don't get an "undefined but used internal symbol" warning for the deduction guide here.
  namespace {
    template <typename T>
    struct TemplDObj {
      explicit TemplDObj(T func) noexcept {}
    };
    auto test1 = TemplDObj(0);

    TemplDObj(float) -> TemplDObj<double>;
    auto test2 = TemplDObj(.0f);
  }
}
#endif