diff options
Diffstat (limited to 'clang/test')
-rw-r--r-- | clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp | 17 | ||||
-rw-r--r-- | clang/test/CXX/expr/expr.const/p6-2a.cpp | 43 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/attr-no-destroy-d54344.cpp | 1 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/const-init-cxx2a.cpp | 57 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/no_destroy.cpp | 8 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/non-const-init-cxx2a.cpp | 19 |
6 files changed, 137 insertions, 8 deletions
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp index 0aaedcc0769..8d51dbde717 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p9.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++2a %s // A constexpr specifier used in an object declaration declares the object as // const. @@ -35,3 +36,19 @@ struct pixel { }; constexpr pixel ur = { 1294, 1024 }; // ok constexpr pixel origin; // expected-error {{default initialization of an object of const type 'const pixel' without a user-provided default constructor}} + +#if __cplusplus > 201702L +// A constexpr variable shall have constant destruction. +struct A { + bool ok; + constexpr A(bool ok) : ok(ok) {} + constexpr ~A() noexcept(false) { + void oops(); // expected-note 2{{declared here}} + if (!ok) oops(); // expected-note 2{{non-constexpr function}} + } +}; + +constexpr A const_dtor(true); +constexpr A non_const_dtor(false); // expected-error {{must have constant destruction}} expected-note {{in call}} +constexpr A arr_dtor[5] = {true, true, true, false, true}; // expected-error {{must have constant destruction}} expected-note {{in call to '&arr_dtor[3]->~A()'}} +#endif diff --git a/clang/test/CXX/expr/expr.const/p6-2a.cpp b/clang/test/CXX/expr/expr.const/p6-2a.cpp new file mode 100644 index 00000000000..312c2835418 --- /dev/null +++ b/clang/test/CXX/expr/expr.const/p6-2a.cpp @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -std=c++2a -verify %s + +constexpr int non_class = 42; +constexpr int arr_non_class[5] = {1, 2, 3}; + +struct A { + int member = 1; + constexpr ~A() { member = member + 1; } +}; +constexpr A class_ = {}; +constexpr A arr_class[5] = {{}, {}}; + +struct Mutable { + mutable int member = 1; // expected-note {{declared here}} + constexpr ~Mutable() { member = member + 1; } // expected-note {{read of mutable member}} +}; +constexpr Mutable mut_member; // expected-error {{must have constant destruction}} expected-note {{in call}} + +struct MutableStore { + mutable int member = 1; // expected-note {{declared here}} + constexpr ~MutableStore() { member = 2; } // expected-note {{assignment to mutable member}} +}; +constexpr MutableStore mut_store; // expected-error {{must have constant destruction}} expected-note {{in call}} + +// Note: the constant destruction rules disallow this example even though hcm.n is a const object. +struct MutableConst { + struct HasConstMember { + const int n = 4; + }; + mutable HasConstMember hcm; // expected-note {{here}} + constexpr ~MutableConst() { + int q = hcm.n; // expected-note {{read of mutable}} + } +}; +constexpr MutableConst mc; // expected-error {{must have constant destruction}} expected-note {{in call}} + +struct Temporary { + int &&temp; + constexpr ~Temporary() { + int n = temp; // expected-note {{outside the expression that created the temporary}} + } +}; +constexpr Temporary t = {3}; // expected-error {{must have constant destruction}} expected-note {{created here}} expected-note {{in call}} diff --git a/clang/test/CodeGenCXX/attr-no-destroy-d54344.cpp b/clang/test/CodeGenCXX/attr-no-destroy-d54344.cpp index 2e004d6426d..b03791e5135 100644 --- a/clang/test/CodeGenCXX/attr-no-destroy-d54344.cpp +++ b/clang/test/CodeGenCXX/attr-no-destroy-d54344.cpp @@ -14,6 +14,7 @@ class a { public: + a(); ~a(); }; class logger_base { diff --git a/clang/test/CodeGenCXX/const-init-cxx2a.cpp b/clang/test/CodeGenCXX/const-init-cxx2a.cpp index 499a16ea6dd..1195b912c25 100644 --- a/clang/test/CodeGenCXX/const-init-cxx2a.cpp +++ b/clang/test/CodeGenCXX/const-init-cxx2a.cpp @@ -1,5 +1,58 @@ -// RUN: %clang_cc1 -verify -triple x86_64-apple-darwin -emit-llvm -o - %s -std=c++2a | FileCheck %s -// expected-no-diagnostics +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -o - %s -std=c++2a | FileCheck %s --implicit-check-not=cxx_global_var_init --implicit-check-not=cxa_atexit + +// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-pch -o %t.pch %s -std=c++2a +// RUN: %clang_cc1 -triple x86_64-linux-gnu -include-pch %t.pch -x c++ /dev/null -emit-llvm -o - -std=c++2a | FileCheck %s --implicit-check-not=cxx_global_var_init --implicit-check-not=cxa_atexit // CHECK: @a = global i32 123, int a = (delete new int, 123); + +struct B { + constexpr B() {} + constexpr ~B() { n *= 5; } + int n = 123; +}; +// CHECK: @b = global {{.*}} i32 123 +extern constexpr B b = B(); + +// CHECK: @_ZL1c = internal global {{.*}} i32 123 +const B c; +int use_c() { return c.n; } + +struct D { + int n; + constexpr ~D() {} +}; +D d; +// CHECK: @d = global {{.*}} zeroinitializer + +D d_arr[3]; +// CHECK: @d_arr = global {{.*}} zeroinitializer + +thread_local D d_tl; +// CHECK: @d_tl = thread_local global {{.*}} zeroinitializer + +// CHECK-NOT: @llvm.global_ctors + +// CHECK-LABEL: define {{.*}} @_Z1fv( +void f() { + // CHECK-NOT: call + // CHECK: call {{.*}}memcpy + // CHECK-NOT: call + // CHECK: call {{.*}}memset + // CHECK-NOT: call + // CHECK: } + constexpr B b; + D d = D(); +} + +// CHECK-LABEL: define {{.*}} @_Z1gv( +void g() { + // CHECK-NOT: call + // CHECK-NOT: cxa_guard + // CHECK-NOT: _ZGV + // CHECK: } + static constexpr B b1; + static const B b2; + static D d; + thread_local D d_tl; +} diff --git a/clang/test/CodeGenCXX/no_destroy.cpp b/clang/test/CodeGenCXX/no_destroy.cpp index 3400b6080b5..607cbfb3a1f 100644 --- a/clang/test/CodeGenCXX/no_destroy.cpp +++ b/clang/test/CodeGenCXX/no_destroy.cpp @@ -5,10 +5,8 @@ struct NonTrivial { ~NonTrivial(); }; -// CHECK-LABEL: define internal void @__cxx_global_var_init // CHECK-NOT: __cxa_atexit{{.*}}_ZN10NonTrivialD1Ev [[clang::no_destroy]] NonTrivial nt1; -// CHECK-LABEL: define internal void @__cxx_global_var_init // CHECK-NOT: _tlv_atexit{{.*}}_ZN10NonTrivialD1Ev [[clang::no_destroy]] thread_local NonTrivial nt2; @@ -16,11 +14,9 @@ struct NonTrivial2 { ~NonTrivial2(); }; -// CHECK-LABEL: define internal void @__cxx_global_var_init -// CHECK: __cxa_atexit{{.*}}_ZN11NonTrivial2D1Ev +// CHECK: __cxa_atexit{{.*}}_ZN11NonTrivial2D1Ev{{.*}}nt21 NonTrivial2 nt21; -// CHECK-LABEL: define internal void @__cxx_global_var_init -// CHECK: _tlv_atexit{{.*}}_ZN11NonTrivial2D1Ev +// CHECK: _tlv_atexit{{.*}}_ZN11NonTrivial2D1Ev{{.*}}nt22 thread_local NonTrivial2 nt22; // CHECK-LABEL: define void @_Z1fv diff --git a/clang/test/CodeGenCXX/non-const-init-cxx2a.cpp b/clang/test/CodeGenCXX/non-const-init-cxx2a.cpp new file mode 100644 index 00000000000..120b32090fb --- /dev/null +++ b/clang/test/CodeGenCXX/non-const-init-cxx2a.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s -std=c++2a | FileCheck %s + +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-pch -o %t.pch %s -std=c++2a +// RUN: %clang_cc1 -triple x86_64-apple-darwin -include-pch %t.pch -x c++ /dev/null -emit-llvm -o - -std=c++2a | FileCheck %s + +struct B { + constexpr B() {} + constexpr ~B() { n *= 5; } + int n = 123; +}; + +// We emit a dynamic destructor here because b.n might have been modified +// before b is destroyed. +// +// CHECK: @b = global {{.*}} i32 123 +B b = B(); + +// CHECK: define {{.*}}cxx_global_var_init +// CHECK: call {{.*}} @__cxa_atexit({{.*}} @_ZN1BD1Ev {{.*}} @b |