xref: /llvm-project/clang/test/Parser/cxx1z-class-template-argument-deduction.cpp (revision ac63d63543ca824434236ffd788c46eec9339657)
1 // RUN: %clang_cc1 -std=c++1z -fcxx-exceptions -verify %s
2 
3 template <typename T> struct A { // expected-note 35{{declared here}}
4   constexpr A() {}
5   constexpr A(int) {}
6   constexpr operator int() { return 0; }
7 };
8 A() -> A<int>;
9 A(int) -> A<int>;
10 
11 // Make sure we still correctly parse cases where a template can appear without arguments.
12 namespace template_template_arg {
13   template<template<typename> typename> struct X {};
14   template<typename> struct Y {};
15 
16   X<A> xa;
17   Y<A> ya; // expected-error {{requires template arguments}}
18   X<::A> xcca;
19   Y<::A> ycca; // expected-error {{requires template arguments}}
20 
21   template<template<typename> typename = A> struct XD {};
22   template<typename = A> struct YD {}; // expected-error {{requires template arguments}}
23   template<template<typename> typename = ::A> struct XCCD {};
24   template<typename = ::A> struct YCCD {}; // expected-error {{requires template arguments}}
25 
26   // FIXME: replacing the invalid type with 'int' here is horrible
27   template <A a = A<int>()> class C { }; // expected-error {{requires template arguments}}
28   template<typename T = A> struct G { }; // expected-error {{requires template arguments}}
29 }
30 
31 namespace injected_class_name {
32   template<typename T> struct A {
33     A(T);
34     void f(int) { // expected-note {{previous}}
35       A a = 1;
36       injected_class_name::A b = 1; // expected-note {{in instantiation of template class 'injected_class_name::A<int>'}}
37     }
38     void f(T); // expected-error {{multiple overloads of 'f' instantiate to the same signature 'void (int)}}
39   };
40   A<short> ai = 1;
41   A<double>::A b(1); // expected-error {{constructor name}}
42 }
43 
44 struct member {
45   A a; // expected-error {{requires template arguments}}
46   A *b; // expected-error {{requires template arguments}}
47   const A c; // expected-error {{requires template arguments}}
48 
49   void f() throw (A); // expected-error {{requires template arguments}}
50 
51   friend A; // expected-error {{requires template arguments; argument deduction not allowed in friend declaration}}
52 
53   operator A(); // expected-error {{requires template arguments; argument deduction not allowed in conversion function type}}
54 
55   static A x; // expected-error {{declaration of variable 'x' with deduced type 'A' requires an initializer}}
56   static constexpr A y = 0;
57 };
58 
59 namespace in_typedef {
60   typedef A *AutoPtr; // expected-error {{requires template arguments; argument deduction not allowed in typedef}}
61   typedef A (*PFun)(int a); // expected-error{{requires template arguments; argument deduction not allowed in typedef}}
62   typedef A Fun(int a) -> decltype(a + a); // expected-error{{requires template arguments; argument deduction not allowed in function return type}}
63 }
64 
65 namespace stmt {
66   void g(A a) { // expected-error{{requires template arguments; argument deduction not allowed in function prototype}}
67     try { }
68     catch (A &a) { } // expected-error{{requires template arguments; argument deduction not allowed in exception declaration}}
69     catch (const A a) { } // expected-error{{requires template arguments; argument deduction not allowed in exception declaration}}
70     try { } catch (A a) { } // expected-error{{requires template arguments; argument deduction not allowed in exception declaration}}
71 
72     // FIXME: The standard only permits class template argument deduction in a
73     // simple-declaration or cast. We also permit it in conditions,
74     // for-range-declarations, member-declarations for static data members, and
75     // new-expressions, because not doing so would be bizarre.
76     A local = 0;
77     static A local_static = 0;
78     static thread_local A thread_local_static = 0;
79     if (A a = 0) {}
80     if (A a = 0; a) {}
81     switch (A a = 0) {} // expected-warning {{no case matching constant switch condition '0'}}
82     switch (A a = 0; a) {} // expected-warning {{no case matching constant switch condition '0'}}
83     for (A a = 0; a; /**/) {}
84     for (/**/; A a = 0; /**/) {}
85     while (A a = 0) {}
86     int arr[3];
87     for (A a : arr) {}
88   }
89 
90   namespace std {
91     class type_info;
92   }
93 }
94 
95 namespace expr {
96   template<typename T> struct U {};
97   void j() {
98     (void)typeid(A); // expected-error{{requires template arguments; argument deduction not allowed here}}
99     (void)sizeof(A); // expected-error{{requires template arguments; argument deduction not allowed here}}
100     (void)__alignof(A); // expected-error{{requires template arguments; argument deduction not allowed here}}
101 
102     U<A> v; // expected-error {{requires template arguments}}
103 
104     int n;
105     (void)dynamic_cast<A&>(n); // expected-error{{requires template arguments; argument deduction not allowed here}}
106     (void)static_cast<A*>(&n); // expected-error{{requires template arguments; argument deduction not allowed here}}
107     (void)reinterpret_cast<A*>(&n); // expected-error{{requires template arguments; argument deduction not allowed here}}
108     (void)const_cast<A>(n); // expected-error{{requires template arguments; argument deduction not allowed here}}
109     (void)*(A*)(&n); // expected-error{{requires template arguments; argument deduction not allowed here}}
110     (void)(A)(n); // expected-error{{requires template arguments; argument deduction not allowed here}}
111     (void)(A){n}; // expected-error{{requires template arguments; argument deduction not allowed here}}
112 
113     (void)A(n);
114     (void)A{n};
115     (void)new A(n);
116     (void)new A{n};
117     // FIXME: We should diagnose the lack of an initializer here.
118     (void)new A;
119   }
120 }
121 
122 namespace decl {
123   enum E : A {}; // expected-error{{requires template arguments; argument deduction not allowed here}}
124   struct F : A {}; // expected-error{{expected class name}}
125 
126   using B = A; // expected-error{{requires template arguments}}
127 
128   auto k() -> A; // expected-error{{requires template arguments}}
129 
130   A a; // expected-error {{declaration of variable 'a' with deduced type 'A' requires an initializer}}
131   A b = 0;
132   const A c = 0;
133   A (parens) = 0; // expected-error {{cannot use parentheses when declaring variable with deduced class template specialization type}}
134   A *p = 0; // expected-error {{cannot form pointer to deduced class template specialization type}}
135   A &r = *p; // expected-error {{cannot form reference to deduced class template specialization type}}
136   A arr[3] = 0; // expected-error {{cannot form array of deduced class template specialization type}}
137   A F::*pm = 0; // expected-error {{cannot form pointer to deduced class template specialization type}}
138   A (*fp)() = 0; // expected-error {{cannot form function returning deduced class template specialization type}}
139   A [x, y] = 0; // expected-error {{cannot be declared with type 'A'}} expected-error {{type 'A<int>' decomposes into 0 elements, but 2 names were provided}}
140 }
141 
142 namespace typename_specifier {
143   struct F {};
144 
145   void e() {
146     (void) typename ::A(0);
147     (void) typename ::A{0};
148     new typename ::A(0);
149     new typename ::A{0};
150     typename ::A a = 0;
151     const typename ::A b = 0;
152     if (typename ::A a = 0) {}
153     for (typename ::A a = 0; typename ::A b = 0; /**/) {}
154 
155     (void)(typename ::A)(0); // expected-error{{requires template arguments; argument deduction not allowed here}}
156     (void)(typename ::A){0}; // expected-error{{requires template arguments; argument deduction not allowed here}}
157   }
158   typename ::A a = 0;
159   const typename ::A b = 0;
160   typename ::A (parens) = 0; // expected-error {{cannot use parentheses when declaring variable with deduced class template specialization type}}
161   typename ::A *p = 0; // expected-error {{cannot form pointer to deduced class template specialization type}}
162   typename ::A &r = *p; // expected-error {{cannot form reference to deduced class template specialization type}}
163   typename ::A arr[3] = 0; // expected-error {{cannot form array of deduced class template specialization type}}
164   typename ::A F::*pm = 0; // expected-error {{cannot form pointer to deduced class template specialization type}}
165   typename ::A (*fp)() = 0; // expected-error {{cannot form function returning deduced class template specialization type}}
166   typename ::A [x, y] = 0; // expected-error {{cannot be declared with type 'typename ::A'}} expected-error {{type 'typename ::A<int>' (aka 'A<int>') decomposes into 0}}
167 
168   struct X { template<typename T> struct A { A(T); }; }; // expected-note 8{{declared here}}
169 
170   template<typename T> void f() {
171     (void) typename T::A(0);
172     (void) typename T::A{0};
173     new typename T::A(0);
174     new typename T::A{0};
175     typename T::A a = 0;
176     const typename T::A b = 0;
177     if (typename T::A a = 0) {} // expected-error {{value of type 'typename X::A<int>' (aka 'typename_specifier::X::A<int>') is not contextually convertible to 'bool'}}
178     for (typename T::A a = 0; typename T::A b = 0; /**/) {} // expected-error {{value of type 'typename X::A<int>' (aka 'typename_specifier::X::A<int>') is not contextually convertible to 'bool'}}
179 
180     {(void)(typename T::A)(0);} // expected-error{{refers to class template member}}
181     {(void)(typename T::A){0};} // expected-error{{refers to class template member}}
182     {typename T::A (parens) = 0;} // expected-error {{refers to class template member in 'typename_specifier::X'; argument deduction not allowed here}}
183     // expected-warning@-1 {{disambiguated as redundant parentheses around declaration of variable named 'parens'}} expected-note@-1 {{add a variable name}} expected-note@-1{{remove parentheses}} expected-note@-1 {{add enclosing parentheses}}
184     {typename T::A *p = 0;} // expected-error {{refers to class template member}}
185     {typename T::A &r = *p;} // expected-error {{refers to class template member}}
186     {typename T::A arr[3] = 0;} // expected-error {{refers to class template member}}
187     {typename T::A F::*pm = 0;} // expected-error {{refers to class template member}}
188     {typename T::A (*fp)() = 0;} // expected-error {{refers to class template member}}
189     {typename T::A [x, y] = 0;} // expected-error {{cannot be declared with type 'typename T::A'}} expected-error {{type 'typename X::A<int>' (aka 'typename_specifier::X::A<int>') decomposes into 0}}
190   }
191   template void f<X>(); // expected-note {{instantiation of}}
192 
193   template<typename T> void g(typename T::A = 0); // expected-note {{refers to class template member}}
194   void h() { g<X>(); } // expected-error {{no matching function}}
195 }
196