| 1 | // RUN: %clang_cc1 -std=c++1z -verify %s |
| 2 | |
| 3 | struct A { |
| 4 | A() {} |
| 5 | A(int) : A() {} // ok |
| 6 | |
| 7 | virtual void f() = 0; // expected-note 1+{{unimplemented}} |
| 8 | }; |
| 9 | |
| 10 | template<typename> struct SecretlyAbstract { |
| 11 | SecretlyAbstract(); |
| 12 | SecretlyAbstract(int); |
| 13 | virtual void f() = 0; // expected-note 1+{{unimplemented}} |
| 14 | }; |
| 15 | using B = SecretlyAbstract<int>; |
| 16 | using C = SecretlyAbstract<float>; |
| 17 | using D = SecretlyAbstract<char>[1]; |
| 18 | |
| 19 | B b; // expected-error {{abstract class}} |
| 20 | D d; // expected-error {{abstract class}} |
| 21 | |
| 22 | template<int> struct N; |
| 23 | |
| 24 | // Note: C is not instantiated anywhere in this file, so we never discover that |
| 25 | // it is in fact abstract. The C++ standard suggests that we need to |
| 26 | // instantiate in all cases where abstractness could affect the validity of a |
| 27 | // program, but that breaks a *lot* of code, so we don't do that. |
| 28 | // |
| 29 | // FIXME: Once DR1640 is resolved, remove the check on forming an abstract |
| 30 | // array type entirely. The only restriction we need is that you can't create |
| 31 | // an object of abstract (most-derived) type. |
| 32 | |
| 33 | |
| 34 | // An abstract class shall not be used |
| 35 | |
| 36 | // - as a parameter type |
| 37 | void f(A&); |
| 38 | void f(A); // expected-error {{abstract class}} |
| 39 | void f(A[1]); // expected-error {{abstract class}} |
| 40 | void f(B); // expected-error {{abstract class}} |
| 41 | void f(B[1]); // expected-error {{abstract class}} |
| 42 | void f(C); |
| 43 | void f(C[1]); |
| 44 | void f(D); // expected-error {{abstract class}} |
| 45 | void f(D[1]); // expected-error {{abstract class}} |
| 46 | |
| 47 | // - as a function return type |
| 48 | A &f(N<0>); |
| 49 | A *f(N<1>); |
| 50 | A f(N<2>); // expected-error {{abstract class}} |
| 51 | A (&f(N<3>))[2]; // expected-error {{abstract class}} |
| 52 | B f(N<4>); // expected-error {{abstract class}} |
| 53 | B (&f(N<5>))[2]; // expected-error {{abstract class}} |
| 54 | C f(N<6>); |
| 55 | C (&f(N<7>))[2]; |
| 56 | |
| 57 | // - as the type of an explicit conversion |
| 58 | void g(A&&); |
| 59 | void h() { |
| 60 | A(); // expected-error {{abstract class}} |
| 61 | A(0); // expected-error {{abstract class}} |
| 62 | A{}; // expected-error {{abstract class}} |
| 63 | A{0}; // expected-error {{abstract class}} |
| 64 | (A)(0); // expected-error {{abstract class}} |
| 65 | (A){}; // expected-error {{abstract class}} |
| 66 | (A){0}; // expected-error {{abstract class}} |
| 67 | |
| 68 | D(); // expected-error {{array type}} |
| 69 | D{}; // expected-error {{abstract class}} |
| 70 | D{0}; // expected-error {{abstract class}} |
| 71 | (D){}; // expected-error {{abstract class}} |
| 72 | (D){0}; // expected-error {{abstract class}} |
| 73 | } |
| 74 | |
| 75 | template<typename T> void t(T); // expected-note 2{{abstract class}} |
| 76 | void i(A &a, B &b, C &c, D &d) { |
| 77 | // FIXME: These should be handled consistently. We currently reject the first |
| 78 | // two early because we (probably incorrectly, depending on dr1640) take |
| 79 | // abstractness into account in forming implicit conversion sequences. |
| 80 | t(a); // expected-error {{no matching function}} |
| 81 | t(b); // expected-error {{no matching function}} |
| 82 | t(c); // expected-error {{allocating an object of abstract class type}} |
| 83 | t(d); // ok, decays to pointer |
| 84 | } |
| 85 | |
| 86 | struct E : A { |
| 87 | E() : A() {} // ok |
| 88 | E(int n) : A( A(n) ) {} // expected-error {{abstract class}} |
| 89 | }; |
| 90 | |
| 91 | namespace std { |
| 92 | template<typename T> struct initializer_list { |
| 93 | const T *begin, *end; |
| 94 | initializer_list(); |
| 95 | }; |
| 96 | } |
| 97 | std::initializer_list<A> ila = {1, 2, 3, 4}; // expected-error {{abstract class}} |
| 98 | |