/* 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; at1.i = t1.i; atp1->i = t1.i; au1 = u1; u1 = au1; av1 = v1; v1 = av1; v1.i = av1.i; av1.i = v1.i; /* _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" } */ }