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 | |