xref: /llvm-project/clang/test/CXX/class.derived/class.abstract/p3.cpp (revision 6dc1636815cb9321657f1cb7ac87a46553870dc7)
1 // RUN: %clang_cc1 -std=c++1z -verify %s
2 
3 struct A {
AA4   A() {}
AA5   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&);
f(A)38 void f(A){} // expected-error {{abstract class}}
f(A[1])39 void f(A[1]){} // expected-error {{abstract class}}
f(B)40 void f(B){} // expected-error {{abstract class}}
f(B[1])41 void f(B[1]){} // expected-error {{abstract class}}
42 void f(C);
43 void f(C[1]);
f(D)44 void f(D){} // expected-error {{abstract class}}
f(D[1])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>);
f(N<2>)50 A f(N<2>){} // expected-error {{abstract class}}
51 A (&f(N<3>))[2]; // expected-error {{abstract class}}
f(N<4>)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&&);
h()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);
i(A & a,B & b,C & c,D & d)76 void i(A &a, B &b, C &c, D &d) {
77   t(a); // expected-error {{allocating an object of abstract class type 'A'}}
78   t(b); // expected-error {{allocating an object of abstract class type 'SecretlyAbstract<int>'}}
79   t(c); // expected-error {{allocating an object of abstract class type}}
80   t(d); // ok, decays to pointer
81 }
82 
83 struct E : A {
EE84   E() : A() {} // ok
EE85   E(int n) : A( A(n) ) {} // expected-error {{abstract class}}
86 };
87 
88 namespace std {
89   template<typename T> struct initializer_list {
90     const T *begin, *end;
91     initializer_list();
92   };
93 }
94 std::initializer_list<A> ila = {1, 2, 3, 4}; // expected-error {{abstract class}}
95