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
|
// RUN: %clang_cc1 %s -verify=expected,access -fsyntax-only
// RUN: %clang_cc1 %s -std=c2x -verify=expected,access -fsyntax-only
// RUN: %clang_cc1 %s -std=c2x -pedantic -verify=expected,access -fsyntax-only
// RUN: %clang_cc1 %s -verify -fsyntax-only -Wno-atomic-access
// RUN: %clang_cc1 %s -verify=expected,access -fsyntax-only -fexperimental-new-constant-interpreter
// RUN: %clang_cc1 %s -std=c2x -verify=expected,access -fsyntax-only -fexperimental-new-constant-interpreter
// RUN: %clang_cc1 %s -std=c2x -pedantic -verify=expected,access -fsyntax-only -fexperimental-new-constant-interpreter
// RUN: %clang_cc1 %s -verify -fsyntax-only -Wno-atomic-access -fexperimental-new-constant-interpreter
_Atomic(unsigned int) data1;
int _Atomic data2;
// Shift operations
int func_01 (int x) {
return data1 << x;
}
int func_02 (int x) {
return x << data1;
}
int func_03 (int x) {
return data2 << x;
}
int func_04 (int x) {
return x << data2;
}
int func_05 (void) {
return data2 << data1;
}
int func_06 (void) {
return data1 << data2;
}
void func_07 (int x) {
data1 <<= x;
}
void func_08 (int x) {
data2 <<= x;
}
void func_09 (int* xp) {
*xp <<= data1;
}
void func_10 (int* xp) {
*xp <<= data2;
}
int func_11 (int x) {
return data1 == x;
}
int func_12 (void) {
return data1 < data2;
}
int func_13 (int x, unsigned y) {
return x ? data1 : y;
}
int func_14 (void) {
return data1 == 0;
}
void func_15(void) {
// Ensure that the result of an assignment expression properly strips the
// _Atomic qualifier; Issue 48742.
_Atomic int x;
int y = (x = 2);
int z = (int)(x = 2);
y = (x = 2);
z = (int)(x = 2);
y = (x += 2);
_Static_assert(__builtin_types_compatible_p(__typeof__(x = 2), int), "incorrect");
_Static_assert(__builtin_types_compatible_p(__typeof__(x += 2), int), "incorrect");
}
// Ensure that member access of an atomic structure or union type is properly
// diagnosed as being undefined behavior; Issue 54563.
void func_16(void) {
// LHS member access.
_Atomic struct { int val; } x, *xp;
x.val = 12; // access-error {{accessing a member of an atomic structure or union is undefined behavior}}
xp->val = 12; // access-error {{accessing a member of an atomic structure or union is undefined behavior}}
_Atomic union {
int ival;
float fval;
} y, *yp;
y.ival = 12; // access-error {{accessing a member of an atomic structure or union is undefined behavior}}
yp->fval = 1.2f; // access-error {{accessing a member of an atomic structure or union is undefined behavior}}
// RHS member access.
int xval = x.val; // access-error {{accessing a member of an atomic structure or union is undefined behavior}}
xval = xp->val; // access-error {{accessing a member of an atomic structure or union is undefined behavior}}
int yval = y.ival; // access-error {{accessing a member of an atomic structure or union is undefined behavior}}
yval = yp->ival; // access-error {{accessing a member of an atomic structure or union is undefined behavior}}
// Using the type specifier instead of the type qualifier.
_Atomic(struct { int val; }) z;
z.val = 12; // access-error {{accessing a member of an atomic structure or union is undefined behavior}}
int zval = z.val; // access-error {{accessing a member of an atomic structure or union is undefined behavior}}
// Don't diagnose in an unevaluated context, however.
(void)sizeof(x.val);
(void)sizeof(xp->val);
(void)sizeof(y.ival);
(void)sizeof(yp->ival);
// Also, do not diagnose in unreachable code paths.
{
if (0) {
x.val = 12;
xp->val = 12;
(void)y.ival;
(void)yp->ival;
}
return;
x.val = 12;
xp->val = 12;
(void)y.ival;
(void)yp->ival;
}
}
// Ensure that we correctly implement assignment constraints from C2x 6.5.16.1.
void func_17(void) {
// The left operand has atomic ... arithmetic type, and the right operand has
// arithmetic type;
_Atomic int i = 0;
_Atomic float f = 0.0f;
// the left operand has an atomic ... version of a structure or union type
// compatible with the type of the right operand;
struct S { int i; } non_atomic_s;
_Atomic struct S s = non_atomic_s;
union U { int i; float f; } non_atomic_u;
_Atomic union U u = non_atomic_u;
// the left operand has atomic ... pointer type, and (considering the type
// the left operand would have after lvalue conversion) both operands are
// pointers to qualified or unqualified versions of compatible types, and the
// type pointed to by the left operand has all the qualifiers of the type
// pointed to by the right operand;
const int *cip = 0;
volatile const int *vcip = 0;
const int * const cicp = 0;
_Atomic(const int *) acip = cip;
_Atomic(const int *) bad_acip = vcip; // expected-warning {{initializing '_Atomic(const int *)' with an expression of type 'const volatile int *' discards qualifiers}}
_Atomic(const int *) acip2 = cicp;
_Atomic(int *) aip = &i; // expected-warning {{incompatible pointer types initializing '_Atomic(int *)' with an expression of type '_Atomic(int) *'}} \
// the left operand has atomic ... pointer type, and (considering the type
// the left operand would have after lvalue conversion) one operand is a
// pointer to an object type, and the other is a pointer to a qualified or
// unqualified version of void, and the type pointed to by the left operand
// has all the qualifiers of the type pointed to by the right operand;
const void *cvp = 0;
_Atomic(const int *) acip3 = cvp;
_Atomic(const void *) acvip = cip;
_Atomic(const int *) acip4 = vcip; // expected-warning {{initializing '_Atomic(const int *)' with an expression of type 'const volatile int *' discards qualifiers}}
_Atomic(const void *) acvip2 = vcip; // expected-warning {{initializing '_Atomic(const void *)' with an expression of type 'const volatile int *' discards qualifiers}}
_Atomic(const int *) acip5 = cicp;
_Atomic(const void *) acvip3 = cicp;
#if __STDC_VERSION__ >= 202311L
// the left operand has an atomic ... version of the nullptr_t type and the
// right operand is a null pointer constant or its type is nullptr_t
typedef typeof(nullptr) nullptr_t;
nullptr_t n;
_Atomic nullptr_t cn2 = n;
_Atomic nullptr_t cn3 = nullptr;
#endif // __STDC_VERSION__ >= 202311L
// the left operand is an atomic ... pointer, and the right operand is a null
// pointer constant or its type is nullptr_t;
_Atomic(int *) aip2 = 0;
#if __STDC_VERSION__ >= 202311L
_Atomic(int *) ip2 = n;
_Atomic(int *) ip3 = nullptr;
_Atomic(const int *) ip4 = nullptr;
#endif // __STDC_VERSION__ >= 202311L
}
// Ensure that the assignment constraints also work at file scope.
_Atomic int ai = 0;
_Atomic float af = 0.0f;
_Atomic(int *) aip1 = 0;
struct S { int a; } non_atomic_s;
_Atomic struct S as = non_atomic_s; // expected-error {{initializer element is not a compile-time constant}}
const int *cip = 0;
_Atomic(const int *) acip1 = cip; // expected-error {{initializer element is not a compile-time constant}}
const void *cvp = 0;
_Atomic(const int *) acip2 = cvp; // expected-error {{initializer element is not a compile-time constant}}
#if __STDC_VERSION__ >= 202311L
// the left operand has an atomic ... version of the nullptr_t type and the
// right operand is a null pointer constant or its type is nullptr_t
typedef typeof(nullptr) nullptr_t;
nullptr_t n;
_Atomic nullptr_t cn2 = n; // expected-error {{initializer element is not a compile-time constant}}
_Atomic(int *) aip2 = nullptr;
#endif // __STDC_VERSION__ >= 202311L
// FIXME: &ai is an address constant, so this should be accepted as an
// initializer, but the bit-cast inserted due to the pointer conversion is
// tripping up the test for whether the initializer is a constant expression.
// The warning is correct but the error is not.
_Atomic(int *) aip3 = &ai; /* expected-warning {{incompatible pointer types initializing '_Atomic(int *)' with an expression of type '_Atomic(int) *'}}
expected-error {{initializer element is not a compile-time constant}}
*/
// Test the behavior when converting the null pointer constant to an atomic
// function pointer.
_Atomic(int (*)(char)) afp = (void *)0;
void func_18(void) {
// Ensure we can cast to atomic scalar types.
data2 = (_Atomic int)0;
(void)(_Atomic(int *))0;
// But that we correctly reject casts to atomic aggregate types.
struct S { int a; } s;
struct T { int a; };
(void)(_Atomic struct T)s; // expected-error {{used type 'struct T' where arithmetic or pointer type is required}}
}
// Test if we can handle an _Atomic qualified integer in a switch statement.
void func_19(void) {
_Atomic int a = 0;
switch (a) { }
}
|