--- /dev/null
+// 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;
+ };
+}