diff options
Diffstat (limited to 'clang/test/SemaCXX/attr-require-constant-initialization.cpp')
-rw-r--r-- | clang/test/SemaCXX/attr-require-constant-initialization.cpp | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/clang/test/SemaCXX/attr-require-constant-initialization.cpp b/clang/test/SemaCXX/attr-require-constant-initialization.cpp new file mode 100644 index 00000000000..73f81cb1fc1 --- /dev/null +++ b/clang/test/SemaCXX/attr-require-constant-initialization.cpp @@ -0,0 +1,282 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -DTEST_ONE -std=c++03 %s +// RUN: %clang_cc1 -fsyntax-only -verify -DTEST_ONE -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -verify -DTEST_ONE -std=c++14 %s +// RUN: %clang_cc1 -fsyntax-only -verify -DTEST_TWO \ +// RUN: -Wglobal-constructors -std=c++14 %s +// RUN: %clang_cc1 -fsyntax-only -verify -DTEST_THREE -xc %s + +#define ATTR __attribute__((require_constant_initialization)) // expected-note 0+ {{expanded from macro}} + +int ReturnInt(); + +struct PODType { + int value; + int value2; +}; + +#if defined(__cplusplus) + +#if __cplusplus >= 201103L +struct LitType { + constexpr LitType() : value(0) {} + constexpr LitType(int x) : value(x) {} + LitType(void *) : value(-1) {} + int value; +}; +#endif + +struct NonLit { +#if __cplusplus >= 201402L + constexpr NonLit() : value(0) {} + constexpr NonLit(int x) : value(x) {} +#else + NonLit() : value(0) {} + NonLit(int x) : value(x) {} +#endif + NonLit(void *) : value(-1) {} + ~NonLit() {} + int value; +}; + +struct StoresNonLit { +#if __cplusplus >= 201402L + constexpr StoresNonLit() : obj() {} + constexpr StoresNonLit(int x) : obj(x) {} +#else + StoresNonLit() : obj() {} + StoresNonLit(int x) : obj(x) {} +#endif + StoresNonLit(void *p) : obj(p) {} + NonLit obj; +}; + +#endif // __cplusplus + + +#if defined(TEST_ONE) // Test semantics of attribute + +// Test diagnostics when attribute is applied to non-static declarations. +void test_func_local(ATTR int param) { // expected-error {{only applies to variables with static or thread}} + ATTR int x = 42; // expected-error {{only applies to variables with static or thread}} + ATTR extern int y; +} +struct ATTR class_mem { // expected-error {{only applies to variables with static or thread}} + ATTR int x; // expected-error {{only applies to variables with static or thread}} +}; + +// [basic.start.static]p2.1 +// if each full-expression (including implicit conversions) that appears in +// the initializer of a reference with static or thread storage duration is +// a constant expression (5.20) and the reference is bound to a glvalue +// designating an object with static storage duration, to a temporary object +// (see 12.2) or subobject thereof, or to a function; + +// Test binding to a static glvalue +const int glvalue_int = 42; +const int glvalue_int2 = ReturnInt(); +ATTR const int &glvalue_ref ATTR = glvalue_int; +ATTR const int &glvalue_ref2 ATTR = glvalue_int2; +ATTR __thread const int &glvalue_ref_tl = glvalue_int; + +void test_basic_start_static_2_1() { + const int non_global = 42; + ATTR static const int &local_init = non_global; // expected-error {{variable does not have a constant initializer}} + // expected-note@-1 {{required by 'require_constant_initializer' attribute here}} + ATTR static const int &global_init = glvalue_int; + ATTR static const int &temp_init = 42; +} + +ATTR const int &temp_ref = 42; +ATTR const int &temp_ref2 = ReturnInt(); // expected-error {{variable does not have a constant initializer}} +// expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +ATTR const NonLit &nl_temp_ref = 42; // expected-error {{variable does not have a constant initializer}} +// expected-note@-1 {{required by 'require_constant_initializer' attribute here}} + +#if __cplusplus >= 201103L +ATTR const LitType &lit_temp_ref = 42; +ATTR const int &subobj_ref = LitType{}.value; +#endif + +ATTR const int &nl_subobj_ref = NonLit().value; // expected-error {{variable does not have a constant initializer}} +// expected-note@-1 {{required by 'require_constant_initializer' attribute here}} + +struct TT1 { + ATTR static const int &no_init; + ATTR static const int &glvalue_init; + ATTR static const int &temp_init; + ATTR static const int &subobj_init; +#if __cplusplus >= 201103L + ATTR static thread_local const int &tl_glvalue_init; + ATTR static thread_local const int &tl_temp_init; // expected-note {{required by 'require_constant_initializer' attribute here}} +#endif +}; +const int &TT1::glvalue_init = glvalue_int; +const int &TT1::temp_init = 42; +const int &TT1::subobj_init = PODType().value; +#if __cplusplus >= 201103L +thread_local const int &TT1::tl_glvalue_init = glvalue_int; +thread_local const int &TT1::tl_temp_init = 42; // expected-error {{variable does not have a constant initializer}} +#endif + +// [basic.start.static]p2.2 +// if an object with static or thread storage duration is initialized by a +// constructor call, and if the initialization full-expression is a constant +// initializer for the object; + +void test_basic_start_static_2_2() { +#if __cplusplus < 201103L + ATTR static PODType pod; +#else + ATTR static PODType pod; // expected-error {{variable does not have a constant initializer}} +// expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +#endif + ATTR static PODType pot2 = {ReturnInt()}; // expected-error {{variable does not have a constant initializer}} + // expected-note@-1 {{required by 'require_constant_initializer' attribute here}} + +#if __cplusplus >= 201103L + constexpr LitType l; + ATTR static LitType static_lit = l; + ATTR static LitType static_lit2 = (void *)0; // expected-error {{variable does not have a constant initializer}} + // expected-note@-1 {{required by 'require_constant_initializer' attribute here}} + ATTR static LitType static_lit3 = ReturnInt(); // expected-error {{variable does not have a constant initializer}} + // expected-note@-1 {{required by 'require_constant_initializer' attribute here}} + ATTR thread_local LitType tls = 42; +#endif +} + +struct TT2 { + ATTR static PODType pod_noinit; +#if __cplusplus >= 201103L +// expected-note@-2 {{required by 'require_constant_initializer' attribute here}} +#endif + ATTR static PODType pod_copy_init; // expected-note {{required by 'require_constant_initializer' attribute here}} +#if __cplusplus >= 201402L + ATTR static constexpr LitType lit = {}; + ATTR static const NonLit non_lit; + ATTR static const NonLit non_lit_list_init; + ATTR static const NonLit non_lit_copy_init; // expected-note {{required by 'require_constant_initializer' attribute here}} +#endif +}; +PODType TT2::pod_noinit; +#if __cplusplus >= 201103L +// expected-error@-2 {{variable does not have a constant initializer}} +#endif +PODType TT2::pod_copy_init(TT2::pod_noinit); // expected-error {{variable does not have a constant initializer}} +#if __cplusplus >= 201402L +const NonLit TT2::non_lit(42); +const NonLit TT2::non_lit_list_init = {42}; +const NonLit TT2::non_lit_copy_init = 42; // expected-error {{variable does not have a constant initializer}} +#endif + +#if __cplusplus >= 201103L +ATTR LitType lit_ctor; +ATTR LitType lit_ctor2{}; +ATTR LitType lit_ctor3 = {}; +ATTR __thread LitType lit_ctor_tl = {}; + +#if __cplusplus >= 201402L +ATTR NonLit nl_ctor; +ATTR NonLit nl_ctor2{}; +ATTR NonLit nl_ctor3 = {}; +ATTR thread_local NonLit nl_ctor_tl = {}; +ATTR StoresNonLit snl; +#else +ATTR NonLit nl_ctor; // expected-error {{variable does not have a constant initializer}} +// expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +ATTR NonLit nl_ctor2{}; // expected-error {{variable does not have a constant initializer}} +// expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +ATTR NonLit nl_ctor3 = {}; // expected-error {{variable does not have a constant initializer}} +// expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +ATTR thread_local NonLit nl_ctor_tl = {}; // expected-error {{variable does not have a constant initializer}} +// expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +ATTR StoresNonLit snl; // expected-error {{variable does not have a constant initializer}} +// expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +#endif + +// Non-literal types cannot appear in the initializer of a non-literal type. +ATTR int nl_in_init = NonLit{42}.value; // expected-error {{variable does not have a constant initializer}} +// expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +ATTR int lit_in_init = LitType{42}.value; +#endif + +// [basic.start.static]p2.3 +// if an object with static or thread storage duration is not initialized by a +// constructor call and if either the object is value-initialized or every +// full-expression that appears in its initializer is a constant expression. +void test_basic_start_static_2_3() { + ATTR static int static_local = 42; + ATTR static int static_local2; // zero-initialization takes place +#if __cplusplus >= 201103L + ATTR thread_local int tl_local = 42; +#endif +} + +ATTR int no_init; // zero initialization takes place +ATTR int arg_init = 42; +ATTR PODType pod_init = {}; +ATTR PODType pod_missing_init = {42 /* should have second arg */}; +ATTR PODType pod_full_init = {1, 2}; +ATTR PODType pod_non_constexpr_init = {1, ReturnInt()}; // expected-error {{variable does not have a constant initializer}} +// expected-note@-1 {{required by 'require_constant_initializer' attribute here}} + +#if __cplusplus >= 201103L +ATTR int val_init{}; +ATTR int brace_init = {}; +#endif + +ATTR __thread int tl_init = 0; +typedef const char *StrType; + +#if __cplusplus >= 201103L + +// Test that the validity of the selected constructor is checked, not just the +// initializer +struct NotC { + constexpr NotC(void *) {} + NotC(int) {} +}; +template <class T> +struct TestCtor { + constexpr TestCtor(int x) : value(x) {} + T value; +}; +ATTR TestCtor<NotC> t(42); // expected-error {{variable does not have a constant initializer}} +// expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +#endif + +// Test various array types +ATTR const char *foo[] = {"abc", "def"}; +ATTR PODType bar[] = {{}, {123, 456}}; + +#elif defined(TEST_TWO) // Test for duplicate warnings +struct NotC { + constexpr NotC(void *) {} + NotC(int) {} // expected-note 2 {{declared here}} +}; +template <class T> +struct TestCtor { + constexpr TestCtor(int x) : value(x) {} // expected-note 2 {{non-constexpr constructor}} + T value; +}; + +ATTR LitType non_const_lit(nullptr); // expected-error {{variable does not have a constant initializer}} +// expected-note@-1 {{required by 'require_constant_initializer' attribute here}} +ATTR NonLit non_const(nullptr); // expected-error {{variable does not have a constant initializer}} +// expected-warning@-1 {{declaration requires a global destructor}} +// expected-note@-2 {{required by 'require_constant_initializer' attribute here}} +LitType const_init_lit(nullptr); // expected-warning {{declaration requires a global constructor}} +NonLit const_init{42}; // expected-warning {{declaration requires a global destructor}} +constexpr TestCtor<NotC> inval_constexpr(42); // expected-error {{must be initialized by a constant expression}} +// expected-note@-1 {{in call to 'TestCtor(42)'}} +ATTR constexpr TestCtor<NotC> inval_constexpr2(42); // expected-error {{must be initialized by a constant expression}} +// expected-note@-1 {{in call to 'TestCtor(42)'}} + +#elif defined(TEST_THREE) +#if defined(__cplusplus) +#error This test requires C +#endif +// Test that using the attribute in C results in a diagnostic +ATTR int x = 0; // expected-warning {{attribute ignored}} +#else +#error No test case specified +#endif // defined(TEST_N) |