summaryrefslogtreecommitdiff
path: root/test/SemaCXX/attr-require-constant-initialization.cpp
blob: 2dd72ea6dba98b3ac063a8048fd49a58923f3e66 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
// 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(); // expected-note 0+ {{declared here}}

struct PODType { // expected-note 0+ {{declared here}}
  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) {} // expected-note 0+ {{declared here}}
  int value;
};
#endif

struct NonLit { // expected-note 0+ {{declared here}}
#if __cplusplus >= 201402L
  constexpr NonLit() : value(0) {}
  constexpr NonLit(int x) : value(x) {}
#else
  NonLit() : value(0) {} // expected-note 0+ {{declared here}}
  NonLit(int x) : value(x) {}
#endif
  NonLit(void *) : value(-1) {} // expected-note 0+ {{declared here}}
  ~NonLit() {}
  int value;
};

struct StoresNonLit {
#if __cplusplus >= 201402L
  constexpr StoresNonLit() : obj() {}
  constexpr StoresNonLit(int x) : obj(x) {}
#else
  StoresNonLit() : obj() {} // expected-note 0+ {{declared here}}
  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 global variables}}
  ATTR int x = 42;                     // expected-error {{only applies to}}
  ATTR extern int y;
}
struct ATTR class_mem { // expected-error {{only applies to}}
  ATTR int x;           // expected-error {{only applies to}}
};

// [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_initialization' attribute here}}
#if __cplusplus >= 201103L
  // expected-note@-3 {{reference to 'non_global' is not a constant expression}}
  // expected-note@-5 {{declared here}}
#else
  // expected-note@-6 {{subexpression not valid in a constant expression}}
#endif
  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_initialization' attribute here}}
#if __cplusplus >= 201103L
// expected-note@-3 {{non-constexpr function 'ReturnInt' cannot be used in a constant expression}}
#else
// expected-note@-5 {{subexpression not valid in a constant expression}}
#endif
ATTR const NonLit &nl_temp_ref = 42; // expected-error {{variable does not have a constant initializer}}
// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
#if __cplusplus >= 201103L
// expected-note@-3 {{non-literal type 'const NonLit' cannot be used in a constant expression}}
#else
// expected-note@-5 {{subexpression not valid in a constant expression}}
#endif

#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_initialization' attribute here}}
#if __cplusplus >= 201103L
// expected-note-re@-3 {{non-literal type '{{.*}}' cannot be used in a constant expression}}
#else
// expected-note@-5 {{subexpression not valid in a constant expression}}
#endif

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_initialization' 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}}
// expected-note@-1 {{reference to temporary is not a constant expression}}
// expected-note@-2 {{temporary created here}}
#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_initialization' attribute here}}
// expected-note@-2 {{non-constexpr constructor 'PODType' cannot be used in a constant expression}}
#endif
  ATTR static PODType pot2 = {ReturnInt()}; // expected-error {{variable does not have a constant initializer}}
                                            // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
#if __cplusplus >= 201103L
// expected-note@-3 {{non-constexpr function 'ReturnInt' cannot be used in a constant expression}}
#else
// expected-note@-5 {{subexpression not valid in a constant expression}}
#endif

#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_initialization' attribute here}}
  // expected-note@-2 {{non-constexpr constructor 'LitType' cannot be used in a constant expression}}
  ATTR static LitType static_lit3 = ReturnInt(); // expected-error {{variable does not have a constant initializer}}
  // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
  // expected-note@-2 {{non-constexpr function 'ReturnInt' cannot be used in a constant expression}}
  ATTR thread_local LitType tls = 42;
#endif
}

struct TT2 {
  ATTR static PODType pod_noinit;
#if __cplusplus >= 201103L
// expected-note@-2 {{required by 'require_constant_initialization' attribute here}}
#endif
  ATTR static PODType pod_copy_init; // expected-note {{required by 'require_constant_initialization' 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_initialization' attribute here}}
#endif
};
PODType TT2::pod_noinit; // expected-note 0+ {{declared here}}
#if __cplusplus >= 201103L
// expected-error@-2 {{variable does not have a constant initializer}}
// expected-note@-3 {{non-constexpr constructor 'PODType' cannot be used in a constant expression}}
#endif
PODType TT2::pod_copy_init(TT2::pod_noinit); // expected-error {{variable does not have a constant initializer}}
#if __cplusplus >= 201103L
// expected-note@-2 {{read of non-constexpr variable 'pod_noinit' is not allowed in a constant expression}}
// expected-note@-3 {{in call to 'PODType(pod_noinit)'}}
#else
// expected-note@-5 {{subexpression not valid in a constant expression}}
#endif
#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}}
// expected-note@-1 {{subexpression not valid in a constant expression}}
#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_initialization' attribute here}}
// expected-note@-2 {{non-constexpr constructor 'NonLit' cannot be used in a constant expression}}
ATTR NonLit nl_ctor2{}; // expected-error {{variable does not have a constant initializer}}
// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
// expected-note@-2 {{non-constexpr constructor 'NonLit' cannot be used in a constant expression}}
ATTR NonLit nl_ctor3 = {}; // expected-error {{variable does not have a constant initializer}}
// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
// expected-note@-2 {{non-constexpr constructor 'NonLit' cannot be used in a constant expression}}
ATTR thread_local NonLit nl_ctor_tl = {}; // expected-error {{variable does not have a constant initializer}}
// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
// expected-note@-2 {{non-constexpr constructor 'NonLit' cannot be used in a constant expression}}
ATTR StoresNonLit snl; // expected-error {{variable does not have a constant initializer}}
// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
// expected-note@-2 {{non-constexpr constructor 'StoresNonLit' cannot be used in a constant expression}}
#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_initialization' attribute here}}
// expected-note@-2 {{non-literal type 'NonLit' cannot be used in a constant expression}}
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_initialization' attribute here}}
#if __cplusplus >= 201103L
// expected-note@-3 {{non-constexpr function 'ReturnInt' cannot be used in a constant expression}}
#else
// expected-note@-5 {{subexpression not valid in a constant expression}}
#endif

#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) {} // expected-note 0+ {{declared here}}
};
template <class T>
struct TestCtor {
  constexpr TestCtor(int x) : value(x) {}
  // expected-note@-1  {{non-constexpr constructor 'NotC' cannot be used in a constant expression}}
  T value;
};
ATTR TestCtor<NotC> t(42); // expected-error {{variable does not have a constant initializer}}
// expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
// expected-note@-2 {{in call to 'TestCtor(42)'}}
#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_initialization' attribute here}}
// expected-note@-2 {{non-constexpr constructor 'LitType' cannot be used in a constant expression}}
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_initialization' attribute here}}
// expected-note@-3 {{non-constexpr constructor 'NonLit' cannot be used in a constant expression}}
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)