// RUN: %clang_cc1 -std=c++1z -verify %s struct A { A() {} A(int) : A() {} // ok virtual void f() = 0; // expected-note 1+{{unimplemented}} }; template struct SecretlyAbstract { SecretlyAbstract(); SecretlyAbstract(int); virtual void f() = 0; // expected-note 1+{{unimplemented}} }; using B = SecretlyAbstract; using C = SecretlyAbstract; using D = SecretlyAbstract[1]; B b; // expected-error {{abstract class}} D d; // expected-error {{abstract class}} template struct N; // Note: C is not instantiated anywhere in this file, so we never discover that // it is in fact abstract. The C++ standard suggests that we need to // instantiate in all cases where abstractness could affect the validity of a // program, but that breaks a *lot* of code, so we don't do that. // // FIXME: Once DR1640 is resolved, remove the check on forming an abstract // array type entirely. The only restriction we need is that you can't create // an object of abstract (most-derived) type. // An abstract class shall not be used // - as a parameter type void f(A&); void f(A); // expected-error {{abstract class}} void f(A[1]); // expected-error {{abstract class}} void f(B); // expected-error {{abstract class}} void f(B[1]); // expected-error {{abstract class}} void f(C); void f(C[1]); void f(D); // expected-error {{abstract class}} void f(D[1]); // expected-error {{abstract class}} // - as a function return type A &f(N<0>); A *f(N<1>); A f(N<2>); // expected-error {{abstract class}} A (&f(N<3>))[2]; // expected-error {{abstract class}} B f(N<4>); // expected-error {{abstract class}} B (&f(N<5>))[2]; // expected-error {{abstract class}} C f(N<6>); C (&f(N<7>))[2]; // - as the type of an explicit conversion void g(A&&); void h() { A(); // expected-error {{abstract class}} A(0); // expected-error {{abstract class}} A{}; // expected-error {{abstract class}} A{0}; // expected-error {{abstract class}} (A)(0); // expected-error {{abstract class}} (A){}; // expected-error {{abstract class}} (A){0}; // expected-error {{abstract class}} D(); // expected-error {{array type}} D{}; // expected-error {{abstract class}} D{0}; // expected-error {{abstract class}} (D){}; // expected-error {{abstract class}} (D){0}; // expected-error {{abstract class}} } template void t(T); // expected-note 2{{abstract class}} void i(A &a, B &b, C &c, D &d) { // FIXME: These should be handled consistently. We currently reject the first // two early because we (probably incorrectly, depending on dr1640) take // abstractness into account in forming implicit conversion sequences. t(a); // expected-error {{no matching function}} t(b); // expected-error {{no matching function}} t(c); // expected-error {{allocating an object of abstract class type}} t(d); // ok, decays to pointer } struct E : A { E() : A() {} // ok E(int n) : A( A(n) ) {} // expected-error {{abstract class}} }; namespace std { template struct initializer_list { const T *begin, *end; initializer_list(); }; } std::initializer_list ila = {1, 2, 3, 4}; // expected-error {{abstract class}}