|
|
@@ -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) |