C2x was finalized at the June 2023 WG14 meeting. The DIS is out for balloting and the comment period for that closes later this year/early next year. While that does leave an opportunity for more changes to the standard during the DIS ballot resolution process, only editorial changes are anticipated and as a result, the C committee considers C2x to be final. The committee took a straw poll on what we'd prefer the informal name of the standard be, and we decided it should be called C23 regardless of what year ISO publishes it. However, because the final publication is not out, this patch does not add the language standard alias for the -std=iso9899:<year> spelling of the standard mode; that will be added once ISO finally publishes the document and the year chosen will match the publication date. This also changes the value of __STDC_VERSION__ from the placeholder value 202000L to the final value 202311L. Subsequent patches will start renaming things from c2x to c23, cleaning up documentation, etc. Differential Revision: https://reviews.llvm.org/D157606
219 lines
7.8 KiB
C
219 lines
7.8 KiB
C
// 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
|
|
|
|
_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);
|
|
}
|
|
|
|
// 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}}
|
|
}
|