summaryrefslogtreecommitdiff
path: root/test/SemaTemplate/temp_arg_type.cpp
blob: 9069f63e0224fee4eb0589d280bb96dbee4a445d (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
// 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
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s

template<typename T> class A; // expected-note 2 {{template parameter is declared here}} expected-note{{template is declared here}}

// [temp.arg.type]p1
A<0> *a1; // expected-error{{template argument for template type parameter must be a type}}

A<A> *a2; // expected-error{{use of class template 'A' requires template arguments}}

A<int> *a3;
A<int()> *a4; 
A<int(float)> *a5;
A<A<int> > *a6;

// Pass an overloaded function template:
template<typename T> void function_tpl(T);
A<function_tpl> a7;  // expected-error{{template argument for template type parameter must be a type}}

// Pass a qualified name:
namespace ns {
template<typename T> class B {};  // expected-note{{template is declared here}}
}
A<ns::B> a8; // expected-error{{use of class template 'ns::B' requires template arguments}}

// [temp.arg.type]p2
void f() {
  class X { };
  A<X> * a = 0;
#if __cplusplus <= 199711L
  // expected-warning@-2 {{template argument uses local type 'X'}}
#endif
}

struct { int x; } Unnamed;
#if __cplusplus <= 199711L
// expected-note@-2 {{unnamed type used in template argument was declared here}}
#endif

A<__typeof__(Unnamed)> *a9;
#if __cplusplus <= 199711L
// expected-warning@-2 {{template argument uses unnamed type}}
#endif

template<typename T, unsigned N>
struct Array {
  typedef struct { T x[N]; } type;
};

template<typename T> struct A1 { };
A1<Array<int, 17>::type> ax;

// FIXME: [temp.arg.type]p3. The check doesn't really belong here (it
// belongs somewhere in the template instantiation section).

#if __cplusplus >= 201703
// As a defect resolution, we support deducing B in noexcept(B).
namespace deduce_noexcept {
  template<typename> struct function;
  template<typename R, typename ...A, bool N>
  struct function<R(A...) noexcept(N)> {
    static constexpr bool Noexcept = N;
  };
  static_assert(function<int(float, double) noexcept>::Noexcept);
  static_assert(!function<int(float, double)>::Noexcept);

  void noexcept_function() noexcept;
  void throwing_function();

  template<typename T, bool B> float &deduce_function(T(*)() noexcept(B)); // expected-note {{candidate}}
  template<typename T> int &deduce_function(T(*)() noexcept); // expected-note {{candidate}}
  void test_function_deduction() {
    // FIXME: This should probably unambiguously select the second overload.
    int &r = deduce_function(noexcept_function); // expected-error {{ambiguous}}
    float &s = deduce_function(throwing_function);
  }

  namespace low_priority_deduction {
    template<int> struct A {};
    template<auto B> void f(A<B>, void(*)() noexcept(B)) {
      using T = decltype(B);
      using T = int;
    }
    void g() { f(A<0>(), g); } // ok, deduce B as an int
  }

  // FIXME: It's not clear whether this should work. We're told to deduce with
  // P being the function template type and A being the declared type, which
  // would accept this, but considering the exception specification in such
  // cases breaks new/delete matching.
  template<bool Noexcept> void dep() noexcept(Noexcept) {} // expected-note 3{{couldn't infer template argument 'Noexcept'}}
  template void dep(); // expected-error {{does not refer to a function template}}
  template void dep() noexcept(true); // expected-error {{does not refer to a function template}}
  template void dep() noexcept(false); // expected-error {{does not refer to a function template}}

  // FIXME: It's also not clear whether this should be valid: do we substitute
  // into the function type (including the exception specification) or not?
  template<typename T> typename T::type1 f() noexcept(T::a);
  template<typename T> typename T::type2 f() noexcept(T::b) {}
  struct X {
    static constexpr bool b = true;
    using type1 = void;
    using type2 = void;
  };
  template void f<X>();
}
#endif