xref: /llvm-project/clang/test/SemaCXX/attr-require-constant-initialization.cpp (revision 22db4824b9e03fe8c2e9217d6832b71ac23c175f)
1 // RUN: %clang_cc1 -fsyntax-only -verify -DTEST_ONE -std=c++03 %s
2 // RUN: %clang_cc1 -fsyntax-only -verify -DTEST_ONE -std=c++11 %s
3 // RUN: %clang_cc1 -fsyntax-only -verify -DTEST_ONE -std=c++14 %s
4 // RUN: %clang_cc1 -fsyntax-only -verify -DTEST_TWO \
5 // RUN: -Wglobal-constructors -std=c++14 %s
6 // RUN: %clang_cc1 -fsyntax-only -verify -DTEST_THREE -xc %s
7 
8 #define ATTR __attribute__((require_constant_initialization)) // expected-note 0+ {{expanded from macro}}
9 
10 int ReturnInt(void); // expected-note 0+ {{declared here}}
11 
12 struct PODType { // expected-note 0+ {{declared here}}
13   int value; // expected-note 0-2 {{declared here}}
14   int value2;
15 };
16 
17 #if defined(__cplusplus)
18 
19 #if __cplusplus >= 201103L
20 struct LitType {
LitTypeLitType21   constexpr LitType() : value(0) {}
LitTypeLitType22   constexpr LitType(int x) : value(x) {}
LitTypeLitType23   LitType(void *) : value(-1) {} // expected-note 0+ {{declared here}}
24   int value;
25 };
26 #endif
27 
28 struct NonLit { // expected-note 0+ {{declared here}}
29 #if __cplusplus >= 201402L
NonLitNonLit30   constexpr NonLit() : value(0) {}
NonLitNonLit31   constexpr NonLit(int x) : value(x) {}
32 #else
33   NonLit() : value(0) {} // expected-note 0+ {{declared here}}
34   NonLit(int x) : value(x) {}
35 #endif
NonLitNonLit36   NonLit(void *) : value(-1) {} // expected-note 0+ {{declared here}}
~NonLitNonLit37   ~NonLit() {}
38   int value;
39 };
40 
41 struct StoresNonLit {
42 #if __cplusplus >= 201402L
StoresNonLitStoresNonLit43   constexpr StoresNonLit() : obj() {}
StoresNonLitStoresNonLit44   constexpr StoresNonLit(int x) : obj(x) {}
45 #else
46   StoresNonLit() : obj() {} // expected-note 0+ {{declared here}}
47   StoresNonLit(int x) : obj(x) {}
48 #endif
StoresNonLitStoresNonLit49   StoresNonLit(void *p) : obj(p) {}
50   NonLit obj;
51 };
52 
53 #endif // __cplusplus
54 
55 
56 #if defined(TEST_ONE) // Test semantics of attribute
57 
58 // Test diagnostics when attribute is applied to non-static declarations.
test_func_local(ATTR int param)59 void test_func_local(ATTR int param) { // expected-error {{only applies to global variables}}
60   ATTR int x = 42;                     // expected-error {{only applies to}}
61   ATTR extern int y;
62 }
63 struct ATTR class_mem { // expected-error {{only applies to}}
64   ATTR int x;           // expected-error {{only applies to}}
65 };
66 
67 // [basic.start.static]p2.1
68 // if each full-expression (including implicit conversions) that appears in
69 // the initializer of a reference with static or thread storage duration is
70 // a constant expression (5.20) and the reference is bound to a glvalue
71 // designating an object with static storage duration, to a temporary object
72 // (see 12.2) or subobject thereof, or to a function;
73 
74 // Test binding to a static glvalue
75 const int glvalue_int = 42;
76 const int glvalue_int2 = ReturnInt();
77 ATTR const int &glvalue_ref ATTR = glvalue_int;
78 ATTR const int &glvalue_ref2 ATTR = glvalue_int2;
79 ATTR __thread const int &glvalue_ref_tl = glvalue_int;
80 
test_basic_start_static_2_1(void)81 void test_basic_start_static_2_1(void) {
82   const int non_global = 42;
83   ATTR static const int &local_init = non_global; // expected-error {{variable does not have a constant initializer}}
84   // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
85 #if __cplusplus >= 201103L
86   // expected-note@-3 {{reference to 'non_global' is not a constant expression}}
87   // expected-note@-5 {{declared here}}
88 #else
89   // expected-note@-6 {{subexpression not valid in a constant expression}}
90 #endif
91   ATTR static const int &global_init = glvalue_int;
92   ATTR static const int &temp_init = 42;
93 }
94 
95 ATTR const int &temp_ref = 42;
96 ATTR const int &temp_ref2 = ReturnInt(); // expected-error {{variable does not have a constant initializer}}
97 // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
98 #if __cplusplus >= 201103L
99 // expected-note@-3 {{non-constexpr function 'ReturnInt' cannot be used in a constant expression}}
100 #else
101 // expected-note@-5 {{subexpression not valid in a constant expression}}
102 #endif
103 ATTR const NonLit &nl_temp_ref = 42; // expected-error {{variable does not have a constant initializer}}
104 // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
105 #if __cplusplus >= 201103L
106 // expected-note@-3 {{non-literal type 'const NonLit' cannot be used in a constant expression}}
107 #else
108 // expected-note@-5 {{subexpression not valid in a constant expression}}
109 #endif
110 
111 #if __cplusplus >= 201103L
112 ATTR const LitType &lit_temp_ref = 42;
113 ATTR const int &subobj_ref = LitType{}.value;
114 #endif
115 
116 ATTR const int &nl_subobj_ref = NonLit().value; // expected-error {{variable does not have a constant initializer}}
117 // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
118 #if __cplusplus >= 201103L
119 // expected-note-re@-3 {{non-literal type '{{.*}}' cannot be used in a constant expression}}
120 #else
121 // expected-note@-5 {{subexpression not valid in a constant expression}}
122 #endif
123 
124 struct TT1 {
125   ATTR static const int &no_init;
126   ATTR static const int &glvalue_init;
127   ATTR static const int &temp_init;
128   ATTR static const int &subobj_init;
129 #if __cplusplus >= 201103L
130   ATTR static thread_local const int &tl_glvalue_init;
131   ATTR static thread_local const int &tl_temp_init; // expected-note {{required by 'require_constant_initialization' attribute here}}
132 #endif
133 };
134 const int &TT1::glvalue_init = glvalue_int;
135 const int &TT1::temp_init = 42;
136 const int &TT1::subobj_init = PODType().value;
137 #if __cplusplus >= 201103L
138 thread_local const int &TT1::tl_glvalue_init = glvalue_int;
139 thread_local const int &TT1::tl_temp_init = 42; // expected-error {{variable does not have a constant initializer}}
140 // expected-note@-1 {{reference to temporary is not a constant expression}}
141 // expected-note@-2 {{temporary created here}}
142 #endif
143 
144 // [basic.start.static]p2.2
145 // if an object with static or thread storage duration is initialized by a
146 // constructor call, and if the initialization full-expression is a constant
147 // initializer for the object;
148 
test_basic_start_static_2_2(void)149 void test_basic_start_static_2_2(void) {
150 #if __cplusplus < 201103L
151   ATTR static PODType pod;
152 #else
153   ATTR static PODType pod; // expected-error {{variable does not have a constant initializer}}
154 // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
155 // expected-note-re@-2 {{{{non-constexpr constructor|subobject of type 'int' is not initialized}}}}
156 #endif
157   ATTR static PODType pot2 = {ReturnInt()}; // expected-error {{variable does not have a constant initializer}}
158                                             // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
159 #if __cplusplus >= 201103L
160 // expected-note@-3 {{non-constexpr function 'ReturnInt' cannot be used in a constant expression}}
161 #else
162 // expected-note@-5 {{subexpression not valid in a constant expression}}
163 #endif
164 
165 #if __cplusplus >= 201103L
166   constexpr LitType l;
167   ATTR static LitType static_lit = l;
168   ATTR static LitType static_lit2 = (void *)0; // expected-error {{variable does not have a constant initializer}}
169   // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
170   // expected-note@-2 {{non-constexpr constructor 'LitType' cannot be used in a constant expression}}
171   ATTR static LitType static_lit3 = ReturnInt(); // expected-error {{variable does not have a constant initializer}}
172   // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
173   // expected-note@-2 {{non-constexpr function 'ReturnInt' cannot be used in a constant expression}}
174   ATTR thread_local LitType tls = 42;
175 #endif
176 }
177 
178 struct TT2 {
179   ATTR static PODType pod_noinit;
180 #if __cplusplus >= 201103L
181 // expected-note@-2 {{required by 'require_constant_initialization' attribute here}}
182 #endif
183   ATTR static PODType pod_copy_init; // expected-note {{required by 'require_constant_initialization' attribute here}}
184 #if __cplusplus >= 201402L
185   ATTR static constexpr LitType lit = {};
186   ATTR static const NonLit non_lit;
187   ATTR static const NonLit non_lit_list_init;
188   ATTR static const NonLit non_lit_copy_init;
189 #endif
190 };
191 PODType TT2::pod_noinit; // expected-note 0+ {{declared here}}
192 #if __cplusplus >= 201103L
193 // expected-error@-2 {{variable does not have a constant initializer}}
194 // expected-note-re@-3 {{{{non-constexpr constructor|subobject of type 'int' is not initialized}}}}
195 #endif
196 PODType TT2::pod_copy_init(TT2::pod_noinit); // expected-error {{variable does not have a constant initializer}}
197 #if __cplusplus >= 201103L
198 // expected-note@-2 {{read of non-constexpr variable 'pod_noinit' is not allowed in a constant expression}}
199 // expected-note@-3 {{in call to 'PODType(pod_noinit)'}}
200 #else
201 // expected-note@-5 {{subexpression not valid in a constant expression}}
202 #endif
203 #if __cplusplus >= 201402L
204 const NonLit TT2::non_lit(42);
205 const NonLit TT2::non_lit_list_init = {42};
206 // FIXME: This is invalid, but we incorrectly elide the copy. It's OK if we
207 // start diagnosing this.
208 const NonLit TT2::non_lit_copy_init = 42;
209 #endif
210 
211 #if __cplusplus >= 201103L
212 ATTR LitType lit_ctor;
213 ATTR LitType lit_ctor2{};
214 ATTR LitType lit_ctor3 = {};
215 ATTR __thread LitType lit_ctor_tl = {};
216 
217 #if __cplusplus >= 201402L
218 ATTR NonLit nl_ctor;
219 ATTR NonLit nl_ctor2{};
220 ATTR NonLit nl_ctor3 = {};
221 ATTR thread_local NonLit nl_ctor_tl = {};
222 ATTR StoresNonLit snl;
223 #else
224 ATTR NonLit nl_ctor; // expected-error {{variable does not have a constant initializer}}
225 // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
226 // expected-note@-2 {{non-constexpr constructor 'NonLit' cannot be used in a constant expression}}
227 ATTR NonLit nl_ctor2{}; // expected-error {{variable does not have a constant initializer}}
228 // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
229 // expected-note@-2 {{non-constexpr constructor 'NonLit' cannot be used in a constant expression}}
230 ATTR NonLit nl_ctor3 = {}; // expected-error {{variable does not have a constant initializer}}
231 // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
232 // expected-note@-2 {{non-constexpr constructor 'NonLit' cannot be used in a constant expression}}
233 ATTR thread_local NonLit nl_ctor_tl = {}; // expected-error {{variable does not have a constant initializer}}
234 // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
235 // expected-note@-2 {{non-constexpr constructor 'NonLit' cannot be used in a constant expression}}
236 ATTR StoresNonLit snl; // expected-error {{variable does not have a constant initializer}}
237 // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
238 // expected-note@-2 {{non-constexpr constructor 'StoresNonLit' cannot be used in a constant expression}}
239 #endif
240 
241 // Non-literal types cannot appear in the initializer of a non-literal type.
242 ATTR int nl_in_init = NonLit{42}.value; // expected-error {{variable does not have a constant initializer}}
243 // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
244 // expected-note@-2 {{non-literal type 'NonLit' cannot be used in a constant expression}}
245 ATTR int lit_in_init = LitType{42}.value;
246 #endif
247 
248 // [basic.start.static]p2.3
249 // if an object with static or thread storage duration is not initialized by a
250 // constructor call and if either the object is value-initialized or every
251 // full-expression that appears in its initializer is a constant expression.
test_basic_start_static_2_3(void)252 void test_basic_start_static_2_3(void) {
253   ATTR static int static_local = 42;
254   ATTR static int static_local2; // zero-initialization takes place
255 #if __cplusplus >= 201103L
256   ATTR thread_local int tl_local = 42;
257 #endif
258 }
259 
260 ATTR int no_init; // zero initialization takes place
261 ATTR int arg_init = 42;
262 ATTR PODType pod_init = {};
263 ATTR PODType pod_missing_init = {42 /* should have second arg */};
264 ATTR PODType pod_full_init = {1, 2};
265 ATTR PODType pod_non_constexpr_init = {1, ReturnInt()}; // expected-error {{variable does not have a constant initializer}}
266 // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
267 #if __cplusplus >= 201103L
268 // expected-note@-3 {{non-constexpr function 'ReturnInt' cannot be used in a constant expression}}
269 #else
270 // expected-note@-5 {{subexpression not valid in a constant expression}}
271 #endif
272 
273 #if __cplusplus >= 201103L
274 ATTR int val_init{};
275 ATTR int brace_init = {};
276 #endif
277 
278 ATTR __thread int tl_init = 0;
279 typedef const char *StrType;
280 
281 #if __cplusplus >= 201103L
282 
283 // Test that the validity of the selected constructor is checked, not just the
284 // initializer
285 struct NotC {
NotCNotC286   constexpr NotC(void *) {}
NotCNotC287   NotC(int) {} // expected-note 0+ {{declared here}}
288 };
289 template <class T>
290 struct TestCtor {
TestCtorTestCtor291   constexpr TestCtor(int x) : value(x) {}
292   // expected-note@-1  {{non-constexpr constructor 'NotC' cannot be used in a constant expression}}
293   T value;
294 };
295 ATTR TestCtor<NotC> t(42); // expected-error {{variable does not have a constant initializer}}
296 // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
297 // expected-note@-2 {{in call to 'TestCtor(42)'}}
298 #endif
299 
300 // Test various array types
301 ATTR const char *foo[] = {"abc", "def"};
302 ATTR PODType bar[] = {{}, {123, 456}};
303 
304 
305 namespace AttrAddedTooLate {
306   struct A {
307     static const int n = 0; // expected-note {{here}}
308   };
309   ATTR const int A::n; // expected-warning {{added after initialization}}
310 
311   int m = 0; // expected-note {{here}}
312   extern ATTR int m; // expected-warning {{added after initialization}}
313 }
314 
315 #elif defined(TEST_TWO) // Test for duplicate warnings
316 struct NotC {
NotCNotC317   constexpr NotC(void *) {}
NotCNotC318   NotC(int) {} // expected-note 2 {{declared here}}
319 };
320 template <class T>
321 struct TestCtor {
TestCtorTestCtor322   constexpr TestCtor(int x) : value(x) {} // expected-note 2 {{non-constexpr constructor}}
323   T value;
324 };
325 
326 ATTR LitType non_const_lit(nullptr); // expected-error {{variable does not have a constant initializer}}
327 // expected-note@-1 {{required by 'require_constant_initialization' attribute here}}
328 // expected-note@-2 {{non-constexpr constructor 'LitType' cannot be used in a constant expression}}
329 ATTR NonLit non_const(nullptr); // expected-error {{variable does not have a constant initializer}}
330 // expected-warning@-1 {{declaration requires a global destructor}}
331 // expected-note@-2 {{required by 'require_constant_initialization' attribute here}}
332 // expected-note@-3 {{non-constexpr constructor 'NonLit' cannot be used in a constant expression}}
333 LitType const_init_lit(nullptr);              // expected-warning {{declaration requires a global constructor}}
334 NonLit const_init{42};                        // expected-warning {{declaration requires a global destructor}}
335 constexpr TestCtor<NotC> inval_constexpr(42); // expected-error {{must be initialized by a constant expression}}
336 // expected-note@-1 {{in call to 'TestCtor(42)'}}
337 ATTR constexpr TestCtor<NotC> inval_constexpr2(42); // expected-error {{must be initialized by a constant expression}}
338 // expected-note@-1 {{in call to 'TestCtor(42)'}}
339 
340 #elif defined(TEST_THREE)
341 #if defined(__cplusplus)
342 #error This test requires C
343 #endif
344 // Test that using the attribute in C results in a diagnostic
345 ATTR int x = 0; // expected-warning {{attribute ignored}}
346 #else
347 #error No test case specified
348 #endif // defined(TEST_N)
349