268 lines
5.6 KiB
C
268 lines
5.6 KiB
C
/* Test for _Atomic in C11. Test of valid code. See c11-atomic-2.c
|
|
for more exhaustive tests of assignment cases. */
|
|
/* { dg-do compile } */
|
|
/* { dg-options "-std=c11 -pedantic-errors" } */
|
|
|
|
/* The use of _Atomic as a qualifier, and of _Atomic (type-name), give
|
|
the same type. */
|
|
extern _Atomic int a;
|
|
extern _Atomic (int) a;
|
|
extern int *_Atomic b;
|
|
extern _Atomic (int *) b;
|
|
extern void f (int [_Atomic]);
|
|
extern void f (int *_Atomic);
|
|
|
|
/* _Atomic may be applied to arbitrary types, with or without other
|
|
qualifiers, and assignments may be made as with non-atomic
|
|
types. Structure and union elements may be atomic. */
|
|
_Atomic int ai1, ai2;
|
|
int i1;
|
|
volatile _Atomic long double ald1;
|
|
const _Atomic long double ald2;
|
|
long double ld1;
|
|
_Atomic _Complex double acd1, acd2;
|
|
_Complex double d1;
|
|
_Atomic volatile _Bool ab1;
|
|
int *p;
|
|
int *_Atomic restrict ap;
|
|
struct s { char c[1000]; };
|
|
_Atomic struct s as1;
|
|
struct s s1;
|
|
struct t { _Atomic int i; };
|
|
_Atomic struct t at1;
|
|
_Atomic struct t *atp1;
|
|
struct t t1;
|
|
union u { char c[1000]; };
|
|
_Atomic union u au1;
|
|
union u u1;
|
|
union v { _Atomic int i; };
|
|
_Atomic union v av1;
|
|
union v v1;
|
|
|
|
void
|
|
func (_Atomic volatile long al1)
|
|
{
|
|
ai1 = ai2;
|
|
ai1 = i1;
|
|
i1 = ai2;
|
|
ai1 = ald2;
|
|
ald1 = d1;
|
|
ld1 = acd2;
|
|
acd1 += ab1;
|
|
acd2 /= ai1;
|
|
p = ap;
|
|
ap = p;
|
|
ab1 = p;
|
|
as1 = s1;
|
|
s1 = as1;
|
|
at1 = t1;
|
|
t1 = at1;
|
|
/* It's unclear whether the undefined behavior (6.5.2.3#5) for
|
|
accessing elements of atomic structures and unions is at
|
|
translation or execution time; presume here that it's at
|
|
execution time. */
|
|
t1.i = at1.i; /* { dg-warning "accessing a member .i. of an atomic structure" } */
|
|
at1.i = t1.i; /* { dg-warning "accessing a member .i. of an atomic structure" } */
|
|
atp1->i = t1.i; /* { dg-warning "accessing a member .i. of an atomic structure" } */
|
|
au1 = u1;
|
|
u1 = au1;
|
|
av1 = v1;
|
|
v1 = av1;
|
|
v1.i = av1.i; /* { dg-warning "accessing a member .i. of an atomic union" } */
|
|
av1.i = v1.i; /* { dg-warning "accessing a member .i. of an atomic union" } */
|
|
/* _Atomic is valid on register variables, even if not particularly
|
|
useful. */
|
|
register _Atomic volatile int ra1 = 1, ra2 = 2;
|
|
ra1 = ra2;
|
|
ra2 = ra1;
|
|
/* And on parameters. */
|
|
al1 = ra1;
|
|
ra2 = al1;
|
|
}
|
|
|
|
/* A function may return an atomic type. */
|
|
_Atomic int
|
|
func2 (int i)
|
|
{
|
|
return i;
|
|
}
|
|
|
|
/* Casts may specify atomic type. */
|
|
int
|
|
func3 (int i)
|
|
{
|
|
return func2 ((_Atomic long) i);
|
|
}
|
|
|
|
/* The _Atomic void type is valid. */
|
|
_Atomic void *avp;
|
|
|
|
/* An array of atomic elements is valid (the elements being atomic,
|
|
not the array). */
|
|
_Atomic int aa[10];
|
|
int
|
|
func4 (void)
|
|
{
|
|
return aa[2];
|
|
}
|
|
|
|
/* Increment and decrement are valid for atomic types when they are
|
|
valid for non-atomic types. */
|
|
void
|
|
func5 (void)
|
|
{
|
|
ald1++;
|
|
ald1--;
|
|
++ald1;
|
|
--ald1;
|
|
ai1++;
|
|
ai1--;
|
|
++ai1;
|
|
--ai1;
|
|
ab1++;
|
|
ab1--;
|
|
++ab1;
|
|
--ab1;
|
|
ap++;
|
|
ap--;
|
|
++ap;
|
|
--ap;
|
|
}
|
|
|
|
/* Compound literals may have atomic type. */
|
|
_Atomic int *aiclp = &(_Atomic int) { 1 };
|
|
|
|
/* Test unary & and *. */
|
|
void
|
|
func6 (void)
|
|
{
|
|
int i = *aiclp;
|
|
_Atomic int *p = &ai2;
|
|
}
|
|
|
|
/* Casts to atomic type are valid (although the _Atomic has little
|
|
effect because the result is an rvalue). */
|
|
int i2 = (_Atomic int) 1.0;
|
|
|
|
/* For pointer subtraction and comparisons, _Atomic does not count as
|
|
a qualifier. Likewise for conditional expressions. */
|
|
_Atomic int *xaip1;
|
|
volatile _Atomic int *xaip2;
|
|
void *xvp1;
|
|
|
|
void
|
|
func7 (void)
|
|
{
|
|
int r;
|
|
r = xaip1 - xaip2;
|
|
r = xaip1 < xaip2;
|
|
r = xaip1 > xaip2;
|
|
r = xaip1 <= xaip2;
|
|
r = xaip1 >= xaip2;
|
|
r = xaip1 == xaip2;
|
|
r = xaip1 != xaip2;
|
|
r = xaip1 == xvp1;
|
|
r = xaip1 != xvp1;
|
|
r = xvp1 == xaip1;
|
|
r = xvp1 != xaip1;
|
|
r = xaip1 == 0;
|
|
r = ((void *) 0) == xaip2;
|
|
(void) (r ? xaip1 : xaip2);
|
|
(void) (r ? xvp1 : xaip2);
|
|
(void) (r ? xaip2 : xvp1);
|
|
(void) (r ? xaip1 : 0);
|
|
(void) (r ? 0 : xaip1);
|
|
/* The result of a conditional expression between a pointer to
|
|
qualified or unqualified (but not atomic) void, and a pointer to
|
|
an atomic type, is a pointer to appropriately qualified, not
|
|
atomic, void. As such, it is valid to use further in conditional
|
|
expressions with other pointer types. */
|
|
(void) (r ? xaip1 : (r ? xaip1 : xvp1));
|
|
}
|
|
|
|
/* Pointer += and -= integer is valid. */
|
|
void
|
|
func8 (void)
|
|
{
|
|
b += 1;
|
|
b -= 2ULL;
|
|
ap += 3;
|
|
}
|
|
|
|
/* Various other cases of simple assignment are valid (some already
|
|
tested above). */
|
|
void
|
|
func9 (void)
|
|
{
|
|
ap = 0;
|
|
ap = (void *) 0;
|
|
xvp1 = atp1;
|
|
atp1 = xvp1;
|
|
}
|
|
|
|
/* Test compatibility of function types in cases where _Atomic matches
|
|
(see c11-atomic-3.c for corresponding cases where it doesn't
|
|
match). */
|
|
void fc0a (int const);
|
|
void fc0a (int);
|
|
void fc0b (int _Atomic);
|
|
void fc0b (int _Atomic);
|
|
void fc1a (int);
|
|
void
|
|
fc1a (x)
|
|
volatile int x;
|
|
{
|
|
}
|
|
void fc1b (_Atomic int);
|
|
void
|
|
fc1b (x)
|
|
volatile _Atomic int x;
|
|
{
|
|
}
|
|
void
|
|
fc2a (x)
|
|
const int x;
|
|
{
|
|
}
|
|
void fc2a (int); /* { dg-warning "follows non-prototype" } */
|
|
void
|
|
fc2b (x)
|
|
_Atomic int x;
|
|
{
|
|
}
|
|
void fc2b (_Atomic int); /* { dg-warning "follows non-prototype" } */
|
|
void fc3a (int);
|
|
void
|
|
fc3a (x)
|
|
volatile short x;
|
|
{
|
|
}
|
|
void fc3b (_Atomic int);
|
|
void
|
|
fc3b (x)
|
|
_Atomic short x;
|
|
{
|
|
}
|
|
void
|
|
fc4a (x)
|
|
const short x;
|
|
{
|
|
}
|
|
void fc4a (int); /* { dg-warning "follows non-prototype" } */
|
|
void
|
|
fc4b (x)
|
|
_Atomic short x;
|
|
{
|
|
}
|
|
void fc4b (_Atomic int); /* { dg-warning "follows non-prototype" } */
|
|
|
|
/* Test cases involving C_MAYBE_CONST_EXPR work. */
|
|
void
|
|
func10 (_Atomic int *p)
|
|
{
|
|
p[0 / 0] = 1; /* { dg-warning "division by zero" } */
|
|
p[0 / 0] += 1; /* { dg-warning "division by zero" } */
|
|
*p = 0 / 0; /* { dg-warning "division by zero" } */
|
|
*p += 0 / 0; /* { dg-warning "division by zero" } */
|
|
}
|