| 1 | // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -Wno-c++1y-extensions |
| 2 | |
| 3 | // This test creates cases where implicit instantiations of various entities |
| 4 | // would cause a diagnostic, but provides expliict specializations for those |
| 5 | // entities that avoid the diagnostic. The specializations are alternately |
| 6 | // declarations and definitions, and the intent of this test is to verify |
| 7 | // that we allow specializations only in the appropriate namespaces (and |
| 8 | // nowhere else). |
| 9 | struct NonDefaultConstructible { |
| 10 | NonDefaultConstructible(int); |
| 11 | }; |
| 12 | |
| 13 | // C++ [temp.expl.spec]p1: |
| 14 | // An explicit specialization of any of the following: |
| 15 | |
| 16 | // -- function template |
| 17 | namespace N0 { |
| 18 | template<typename T> void f0(T) { |
| 19 | T t; |
| 20 | } |
| 21 | |
| 22 | template<> void f0(NonDefaultConstructible) { } |
| 23 | |
| 24 | void test_f0(NonDefaultConstructible NDC) { |
| 25 | f0(NDC); |
| 26 | } |
| 27 | |
| 28 | template<> void f0(int); |
| 29 | template<> void f0(long); |
| 30 | } |
| 31 | |
| 32 | template<> void N0::f0(int) { } // okay |
| 33 | |
| 34 | namespace N1 { |
| 35 | template<> void N0::f0(long) { } // expected-error{{does not enclose namespace}} |
| 36 | } |
| 37 | |
| 38 | template<> void N0::f0(double) { } |
| 39 | |
| 40 | struct X1 { |
| 41 | template<typename T> void f(T); |
| 42 | |
| 43 | template<> void f(int); // OK (DR727) |
| 44 | }; |
| 45 | |
| 46 | // -- class template |
| 47 | namespace N0 { |
| 48 | |
| 49 | template<typename T> |
| 50 | struct X0 { // expected-note {{here}} |
| 51 | static T member; |
| 52 | |
| 53 | void f1(T t) { |
| 54 | t = 17; |
| 55 | } |
| 56 | |
| 57 | struct Inner : public T { }; // expected-note 2{{here}} |
| 58 | |
| 59 | template<typename U> |
| 60 | struct InnerTemplate : public T { }; // expected-note 1{{explicitly specialized}} \ |
| 61 | // expected-error{{base specifier}} |
| 62 | |
| 63 | template<typename U> |
| 64 | void ft1(T t, U u); |
| 65 | }; |
| 66 | |
| 67 | } |
| 68 | |
| 69 | template<typename T> |
| 70 | template<typename U> |
| 71 | void N0::X0<T>::ft1(T t, U u) { |
| 72 | t = u; |
| 73 | } |
| 74 | |
| 75 | template<typename T> T N0::X0<T>::member; |
| 76 | |
| 77 | template<> struct N0::X0<void> { }; |
| 78 | N0::X0<void> test_X0; |
| 79 | |
| 80 | namespace N1 { |
| 81 | template<> struct N0::X0<const void> { }; // expected-error{{class template specialization of 'X0' not in a namespace enclosing 'N0'}} |
| 82 | } |
| 83 | |
| 84 | namespace N0 { |
| 85 | template<> struct X0<volatile void>; |
| 86 | } |
| 87 | |
| 88 | template<> struct N0::X0<volatile void> { |
| 89 | void f1(void *); |
| 90 | }; |
| 91 | |
| 92 | // -- variable template [C++1y] |
| 93 | namespace N0 { |
| 94 | template<typename T> int v0; // expected-note 4{{explicitly specialized declaration is here}} |
| 95 | template<> extern int v0<char[1]>; |
| 96 | template<> extern int v0<char[2]>; |
| 97 | template<> extern int v0<char[5]>; |
| 98 | template<> extern int v0<char[6]>; |
| 99 | } |
| 100 | using N0::v0; |
| 101 | |
| 102 | template<typename T> int v1; // expected-note 4{{explicitly specialized declaration is here}} |
| 103 | template<> extern int v1<char[3]>; |
| 104 | template<> extern int v1<char[4]>; |
| 105 | template<> extern int v1<char[7]>; |
| 106 | template<> extern int v1<char[8]>; |
| 107 | |
| 108 | template<> int N0::v0<int[1]>; |
| 109 | template<> int v0<int[2]>; |
| 110 | template<> int ::v1<int[3]>; // expected-warning {{extra qualification}} |
| 111 | template<> int v1<int[4]>; |
| 112 | |
| 113 | template<> int N0::v0<char[1]>; |
| 114 | template<> int v0<char[2]>; |
| 115 | template<> int ::v1<char[3]>; // expected-warning {{extra qualification}} |
| 116 | template<> int v1<char[4]>; |
| 117 | |
| 118 | namespace N1 { |
| 119 | template<> int N0::v0<int[5]>; // expected-error {{not in a namespace enclosing 'N0'}} |
| 120 | template<> int v0<int[6]>; // expected-error {{not in a namespace enclosing 'N0'}} |
| 121 | template<> int ::v1<int[7]>; // expected-error {{must occur at global scope}} |
| 122 | template<> int v1<int[8]>; // expected-error {{must occur at global scope}} |
| 123 | |
| 124 | template<> int N0::v0<char[5]>; // expected-error {{not in a namespace enclosing 'N0'}} |
| 125 | template<> int v0<char[6]>; // expected-error {{not in a namespace enclosing 'N0'}} |
| 126 | template<> int ::v1<char[7]>; // expected-error {{must occur at global scope}} |
| 127 | template<> int v1<char[8]>; // expected-error {{must occur at global scope}} |
| 128 | } |
| 129 | |
| 130 | // -- member function of a class template |
| 131 | template<> void N0::X0<void*>::f1(void *) { } |
| 132 | |
| 133 | void test_spec(N0::X0<void*> xvp, void *vp) { |
| 134 | xvp.f1(vp); |
| 135 | } |
| 136 | |
| 137 | namespace N0 { |
| 138 | template<> void X0<volatile void>::f1(void *) { } // expected-error{{no function template matches}} |
| 139 | |
| 140 | template<> void X0<const volatile void*>::f1(const volatile void*); |
| 141 | } |
| 142 | |
| 143 | void test_x0_cvvoid(N0::X0<const volatile void*> x0, const volatile void *cvp) { |
| 144 | x0.f1(cvp); // okay: we've explicitly specialized |
| 145 | } |
| 146 | |
| 147 | // -- static data member of a class template |
| 148 | namespace N0 { |
| 149 | // This actually tests p15; the following is a declaration, not a definition. |
| 150 | template<> |
| 151 | NonDefaultConstructible X0<NonDefaultConstructible>::member; |
| 152 | |
| 153 | template<> long X0<long>::member = 17; |
| 154 | |
| 155 | template<> float X0<float>::member; |
| 156 | |
| 157 | template<> double X0<double>::member; |
| 158 | } |
| 159 | |
| 160 | NonDefaultConstructible &get_static_member() { |
| 161 | return N0::X0<NonDefaultConstructible>::member; |
| 162 | } |
| 163 | |
| 164 | template<> int N0::X0<int>::member; |
| 165 | |
| 166 | template<> float N0::X0<float>::member = 3.14f; |
| 167 | |
| 168 | namespace N1 { |
| 169 | template<> double N0::X0<double>::member = 3.14; // expected-error{{does not enclose namespace}} |
| 170 | } |
| 171 | |
| 172 | // -- member class of a class template |
| 173 | namespace N0 { |
| 174 | |
| 175 | template<> |
| 176 | struct X0<void*>::Inner { }; |
| 177 | |
| 178 | template<> |
| 179 | struct X0<int>::Inner { }; |
| 180 | |
| 181 | template<> |
| 182 | struct X0<unsigned>::Inner; |
| 183 | |
| 184 | template<> |
| 185 | struct X0<float>::Inner; |
| 186 | |
| 187 | template<> |
| 188 | struct X0<double>::Inner; // expected-note{{forward declaration}} |
| 189 | } |
| 190 | |
| 191 | template<> |
| 192 | struct N0::X0<long>::Inner { }; |
| 193 | |
| 194 | template<> |
| 195 | struct N0::X0<float>::Inner { }; |
| 196 | |
| 197 | namespace N1 { |
| 198 | template<> |
| 199 | struct N0::X0<unsigned>::Inner { }; // expected-error{{member class specialization}} |
| 200 | |
| 201 | template<> |
| 202 | struct N0::X0<unsigned long>::Inner { }; // expected-error{{member class specialization}} |
| 203 | }; |
| 204 | |
| 205 | N0::X0<void*>::Inner inner0; |
| 206 | N0::X0<int>::Inner inner1; |
| 207 | N0::X0<long>::Inner inner2; |
| 208 | N0::X0<float>::Inner inner3; |
| 209 | N0::X0<double>::Inner inner4; // expected-error{{incomplete}} |
| 210 | |
| 211 | // -- member class template of a class template |
| 212 | namespace N0 { |
| 213 | template<> |
| 214 | template<> |
| 215 | struct X0<void*>::InnerTemplate<int> { }; |
| 216 | |
| 217 | template<> template<> |
| 218 | struct X0<int>::InnerTemplate<int>; // expected-note{{forward declaration}} |
| 219 | |
| 220 | template<> template<> |
| 221 | struct X0<int>::InnerTemplate<long>; |
| 222 | |
| 223 | template<> template<> |
| 224 | struct X0<int>::InnerTemplate<double>; |
| 225 | } |
| 226 | |
| 227 | template<> template<> |
| 228 | struct N0::X0<int>::InnerTemplate<long> { }; // okay |
| 229 | |
| 230 | template<> template<> |
| 231 | struct N0::X0<int>::InnerTemplate<float> { }; |
| 232 | |
| 233 | namespace N1 { |
| 234 | template<> template<> |
| 235 | struct N0::X0<int>::InnerTemplate<double> { }; // expected-error{{enclosing}} |
| 236 | } |
| 237 | |
| 238 | N0::X0<void*>::InnerTemplate<int> inner_template0; |
| 239 | N0::X0<int>::InnerTemplate<int> inner_template1; // expected-error{{incomplete}} |
| 240 | N0::X0<int>::InnerTemplate<long> inner_template2; |
| 241 | N0::X0<int>::InnerTemplate<unsigned long> inner_template3; // expected-note{{instantiation}} |
| 242 | |
| 243 | // -- member function template of a class template |
| 244 | namespace N0 { |
| 245 | template<> |
| 246 | template<> |
| 247 | void X0<void*>::ft1(void*, const void*) { } |
| 248 | |
| 249 | template<> template<> |
| 250 | void X0<void*>::ft1(void *, int); |
| 251 | |
| 252 | template<> template<> |
| 253 | void X0<void*>::ft1(void *, unsigned); |
| 254 | |
| 255 | template<> template<> |
| 256 | void X0<void*>::ft1(void *, long); |
| 257 | } |
| 258 | |
| 259 | template<> template<> |
| 260 | void N0::X0<void*>::ft1(void *, unsigned) { } // okay |
| 261 | |
| 262 | template<> template<> |
| 263 | void N0::X0<void*>::ft1(void *, float) { } |
| 264 | |
| 265 | namespace N1 { |
| 266 | template<> template<> |
| 267 | void N0::X0<void*>::ft1(void *, long) { } // expected-error{{does not enclose namespace}} |
| 268 | } |
| 269 | |
| 270 | |
| 271 | void test_func_template(N0::X0<void *> xvp, void *vp, const void *cvp, |
| 272 | int i, unsigned u) { |
| 273 | xvp.ft1(vp, cvp); |
| 274 | xvp.ft1(vp, i); |
| 275 | xvp.ft1(vp, u); |
| 276 | } |
| 277 | |
| 278 | namespace has_inline_namespaces { |
| 279 | inline namespace inner { |
| 280 | template<class T> void f(T&); |
| 281 | |
| 282 | template<class T> |
| 283 | struct X0 { |
| 284 | struct MemberClass; |
| 285 | |
| 286 | void mem_func(); |
| 287 | |
| 288 | template<typename U> |
| 289 | struct MemberClassTemplate; |
| 290 | |
| 291 | template<typename U> |
| 292 | void mem_func_template(U&); |
| 293 | |
| 294 | static int value; |
| 295 | }; |
| 296 | } |
| 297 | |
| 298 | struct X1; |
| 299 | struct X2; |
| 300 | |
| 301 | // An explicit specialization whose declarator-id is not qualified |
| 302 | // shall be declared in the nearest enclosing namespace of the |
| 303 | // template, or, if the namespace is inline (7.3.1), any namespace |
| 304 | // from its enclosing namespace set. |
| 305 | template<> void f(X1&); |
| 306 | template<> void f<X2>(X2&); |
| 307 | |
| 308 | template<> struct X0<X1> { }; |
| 309 | |
| 310 | template<> struct X0<X2>::MemberClass { }; |
| 311 | |
| 312 | template<> void X0<X2>::mem_func(); |
| 313 | |
| 314 | template<> template<typename T> struct X0<X2>::MemberClassTemplate { }; |
| 315 | |
| 316 | template<> template<typename T> void X0<X2>::mem_func_template(T&) { } |
| 317 | |
| 318 | template<> int X0<X2>::value = 12; |
| 319 | } |
| 320 | |
| 321 | struct X3; |
| 322 | struct X4; |
| 323 | |
| 324 | template<> void has_inline_namespaces::f(X3&); |
| 325 | template<> void has_inline_namespaces::f<X4>(X4&); |
| 326 | |
| 327 | template<> struct has_inline_namespaces::X0<X3> { }; |
| 328 | |
| 329 | template<> struct has_inline_namespaces::X0<X4>::MemberClass { }; |
| 330 | |
| 331 | template<> void has_inline_namespaces::X0<X4>::mem_func(); |
| 332 | |
| 333 | template<> template<typename T> |
| 334 | struct has_inline_namespaces::X0<X4>::MemberClassTemplate { }; |
| 335 | |
| 336 | template<> template<typename T> |
| 337 | void has_inline_namespaces::X0<X4>::mem_func_template(T&) { } |
| 338 | |
| 339 | template<> int has_inline_namespaces::X0<X4>::value = 13; |
| 340 | |
| 341 | namespace PR12938 { |
| 342 | template<typename> [[noreturn]] void func(); |
| 343 | template<> void func<int>(); |
| 344 | } |
| 345 | |