| // RUN: %clang_cc1 -std=c++2a -verify %s |
| |
| // p3: if the function is a constructor or destructor, its class shall not have |
| // any virtual base classes; |
| namespace vbase { |
| struct A {}; |
| struct B : virtual A { // expected-note {{virtual}} |
| constexpr ~B() {} // expected-error {{constexpr member function not allowed in struct with virtual base class}} |
| }; |
| } |
| |
| // p3: its function-body shall not enclose |
| // -- a goto statement |
| // -- an identifier label |
| // -- a variable of non-literal type or of static or thread storage duration |
| namespace contents { |
| struct A { |
| constexpr ~A() { |
| goto x; // expected-error {{statement not allowed in constexpr function}} |
| x: ; |
| } |
| }; |
| struct B { |
| constexpr ~B() { |
| x: ; // expected-error {{statement not allowed in constexpr function}} |
| } |
| }; |
| struct Nonlit { Nonlit(); }; // expected-note {{not literal}} |
| struct C { |
| constexpr ~C() { |
| Nonlit nl; // expected-error {{non-literal}} |
| } |
| }; |
| struct D { |
| constexpr ~D() { |
| static int a; // expected-error {{static variable}} |
| } |
| }; |
| struct E { |
| constexpr ~E() { |
| thread_local int e; // expected-error {{thread_local variable}} |
| } |
| }; |
| struct F { |
| constexpr ~F() { |
| extern int f; |
| } |
| }; |
| } |
| |
| // p5: for every subobject of class type or (possibly multi-dimensional) array |
| // thereof, that class type shall have a constexpr destructor |
| namespace subobject { |
| struct A { |
| ~A(); |
| }; |
| struct B : A { // expected-note {{here}} |
| constexpr ~B() {} // expected-error {{destructor cannot be declared constexpr because base class 'subobject::A' does not have a constexpr destructor}} |
| }; |
| struct C { |
| A a; // expected-note {{here}} |
| constexpr ~C() {} // expected-error {{destructor cannot be declared constexpr because data member 'a' does not have a constexpr destructor}} |
| }; |
| struct D : A { |
| A a; |
| constexpr ~D() = delete; |
| }; |
| } |