Skip to content

Commit 0318ce8

Browse files
authored
[C99] Claim conformance for _Complex support (llvm#88161)
There's so much overlap between the cited papers so this condenses the status page into a single entry rather than trying to test conformance against multiple papers doing conflicting things.
1 parent 83dc419 commit 0318ce8

File tree

4 files changed

+213
-22
lines changed

4 files changed

+213
-22
lines changed

clang/test/C/C99/n809.c

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// RUN: %clang_cc1 -verify -std=c99 %s
2+
3+
/* WG14 N620, N638, N657, N694, N809: Partial
4+
* Complex and imaginary support in <complex.h>
5+
*
6+
* NB: Clang supports _Complex but not _Imaginary. In C99, _Complex support is
7+
* required outside of freestanding, but _Imaginary support is fully optional.
8+
* In C11, both are made fully optional.
9+
*
10+
* NB: _Complex support requires an underlying support library such as
11+
* compiler-rt to provide functions like __divsc3. Compiler-rt is not supported
12+
* on Windows.
13+
*
14+
* Because the functionality is so intertwined between the various papers,
15+
* we're testing all of the functionality in one file.
16+
*/
17+
18+
// Demonstrate that we support spelling complex floating-point objects.
19+
float _Complex f1;
20+
_Complex float f2;
21+
22+
double _Complex d1;
23+
_Complex double d2;
24+
25+
long double _Complex ld1;
26+
_Complex long double ld2;
27+
28+
// Show that we don't support spelling imaginary types.
29+
float _Imaginary fi1; // expected-error {{imaginary types are not supported}}
30+
_Imaginary float fi2; // expected-error {{imaginary types are not supported}}
31+
32+
double _Imaginary di1; // expected-error {{imaginary types are not supported}}
33+
_Imaginary double di2; // expected-error {{imaginary types are not supported}}
34+
35+
long double _Imaginary ldi1; // expected-error {{imaginary types are not supported}}
36+
_Imaginary long double ldi2; // expected-error {{imaginary types are not supported}}
37+
38+
// Each complex type has the same representation and alignment as an array
39+
// containing two elements of the corresponding real type. Note, it is not
40+
// mandatory that the alignment of a structure containing an array of two
41+
// elements has the same alignment as an array of two elements outside of a
42+
// structure, but this is a property Clang supports.
43+
_Static_assert(sizeof(float _Complex) == sizeof(struct { float mem[2]; }), "");
44+
_Static_assert(_Alignof(float _Complex) == _Alignof(struct { float mem[2]; }), "");
45+
46+
_Static_assert(sizeof(double _Complex) == sizeof(struct { double mem[2]; }), "");
47+
_Static_assert(_Alignof(double _Complex) == _Alignof(struct { double mem[2]; }), "");
48+
49+
_Static_assert(sizeof(long double _Complex) == sizeof(struct { long double mem[2]; }), "");
50+
_Static_assert(_Alignof(long double _Complex) == _Alignof(struct { long double mem[2]; }), "");
51+
52+
// The first element corresponds to the real part and the second element
53+
// corresponds to the imaginary part.
54+
_Static_assert(__real((float _Complex){ 1.0f, 2.0f }) == 1.0f, "");
55+
_Static_assert(__imag((float _Complex){ 1.0f, 2.0f }) == 2.0f, "");
56+
57+
_Static_assert(__real((double _Complex){ 1.0, 2.0 }) == 1.0, "");
58+
_Static_assert(__imag((double _Complex){ 1.0, 2.0 }) == 2.0, "");
59+
60+
_Static_assert(__real((long double _Complex){ 1.0L, 2.0L }) == 1.0L, "");
61+
_Static_assert(__imag((long double _Complex){ 1.0L, 2.0L }) == 2.0L, "");
62+
63+
// When a real value is converted to a complex value, the real part follows the
64+
// usual conversion rules and the imaginary part should be zero.
65+
_Static_assert(__real((float _Complex)1.0f) == 1.0f, "");
66+
_Static_assert(__imag((float _Complex)1.0f) == 0.0f, "");
67+
68+
_Static_assert(__real((double _Complex)1.0f) == 1.0, "");
69+
_Static_assert(__imag((double _Complex)1.0f) == 0.0, "");
70+
71+
_Static_assert(__real((long double _Complex)1.0f) == 1.0L, "");
72+
_Static_assert(__imag((long double _Complex)1.0f) == 0.0L, "");
73+
74+
// When a complex value is converted to a real value, the real part follows the
75+
// usual conversion rules and the imaginary part is discarded.
76+
_Static_assert((float)(float _Complex){ 1.0f, 2.0f } == 1.0f, "");
77+
_Static_assert((double)(float _Complex){ 1.0f, 2.0f } == 1.0, "");
78+
_Static_assert((long double)(float _Complex){ 1.0f, 2.0f } == 1.0L, "");
79+
80+
// Complex values are only equal if both the real and imaginary parts are equal.
81+
_Static_assert((float _Complex){ 1.0f, 2.0f } == (float _Complex){ 1.0f, 2.0f }, "");
82+
_Static_assert((double _Complex){ 1.0, 2.0 } == (double _Complex){ 1.0, 2.0 }, "");
83+
_Static_assert((long double _Complex){ 1.0L, 2.0L } == (long double _Complex){ 1.0L, 2.0L }, "");
84+
85+
_Static_assert((float _Complex){ 1.0f, 2.0f } != (float _Complex){ 2.0f, 0.0f }, "");
86+
_Static_assert((double _Complex){ 1.0, 2.0 } != (double _Complex){ 2.0, 0.0 }, "");
87+
_Static_assert((long double _Complex){ 1.0L, 2.0L } != (long double _Complex){ 2.0L, 0.0L }, "");
88+
89+
// You cannot use relational operator on complex values.
90+
int i1 = (float _Complex){ 1.0f, 2.0f } < 10; // expected-error {{invalid operands to binary expression}}
91+
int i2 = (double _Complex){ 1.0f, 2.0f } > 10; // expected-error {{invalid operands to binary expression}}
92+
int i3 = (long double _Complex){ 1.0f, 2.0f } <= 10; // expected-error {{invalid operands to binary expression}}
93+
int i4 = (float _Complex){ 1.0f, 2.0f } >= 10; // expected-error {{invalid operands to binary expression}}
94+
95+
// As a type specifier, _Complex cannot appear alone; however, we support it as
96+
// an extension by assuming _Complex double.
97+
_Complex c = 1.0f; // expected-warning {{plain '_Complex' requires a type specifier; assuming '_Complex double'}}
98+
// Because we don't support imaginary types, we don't extend the extension to
99+
// that type specifier.
100+
// FIXME: the warning diagnostic here is incorrect and should not be emitted.
101+
_Imaginary i = 1.0f; // expected-warning {{plain '_Complex' requires a type specifier; assuming '_Complex double'}} \
102+
expected-error {{imaginary types are not supported}}
103+
104+
void func(void) {
105+
#pragma clang diagnostic push
106+
#pragma clang diagnostic warning "-Wpedantic"
107+
// Increment and decrement operators have a constraint that their operand be
108+
// a real type; Clang supports this as an extension on complex types as well.
109+
_Complex float cf = 0.0f;
110+
111+
cf++; // expected-warning {{'++' on an object of complex type is a Clang extension}}
112+
++cf; // expected-warning {{'++' on an object of complex type is a Clang extension}}
113+
114+
cf--; // expected-warning {{'--' on an object of complex type is a Clang extension}}
115+
--cf; // expected-warning {{'--' on an object of complex type is a Clang extension}}
116+
117+
// However, unary + and - are fine, as is += 1.
118+
(void)-cf;
119+
(void)+cf;
120+
cf += 1;
121+
#pragma clang diagnostic pop
122+
}

clang/test/C/C99/n809_2.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// RUN: %clang_cc1 -ast-dump -std=c99 %s | FileCheck %s
2+
3+
void variadic(int i, ...);
4+
5+
void func(void) {
6+
// CHECK: FunctionDecl {{.*}} func 'void (void)'
7+
8+
// Show that we correctly convert between two complex domains.
9+
_Complex float cf = 1.0f;
10+
_Complex double cd;
11+
12+
cd = cf;
13+
// CHECK: BinaryOperator {{.*}} '_Complex double' '='
14+
// CHECK-NEXT: DeclRefExpr {{.*}} 'cd'
15+
// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex double' <FloatingComplexCast>
16+
// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex float' <LValueToRValue>
17+
// CHECK-NEXT: DeclRefExpr {{.*}} 'cf'
18+
19+
cf = cd;
20+
// CHECK: BinaryOperator {{.*}} '_Complex float' '='
21+
// CHECK-NEXT: DeclRefExpr {{.*}} 'cf'
22+
// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex float' <FloatingComplexCast>
23+
// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex double' <LValueToRValue>
24+
// CHECK-NEXT: DeclRefExpr {{.*}} 'cd'
25+
26+
// Show that we correctly convert to the common type of a complex and real.
27+
// This should convert the _Complex float to a _Complex double ("without
28+
// change of domain" c.f. C99 6.3.1.8p1).
29+
(void)(cf + 1.0);
30+
// CHECK: BinaryOperator {{.*}} '_Complex double' '+'
31+
// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex double' <FloatingComplexCast>
32+
// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex float' <LValueToRValue>
33+
// CHECK-NEXT: DeclRefExpr {{.*}} 'cf'
34+
// CHECK-NEXT: FloatingLiteral {{.*}} 'double' 1.0
35+
36+
// This should convert the float constant to double, then produce a
37+
// _Complex double.
38+
(void)(cd + 1.0f);
39+
// CHECK: BinaryOperator {{.*}} '_Complex double' '+'
40+
// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex double' <LValueToRValue>
41+
// CHECK-NEXT: DeclRefExpr {{.*}} 'cd'
42+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' <FloatingCast>
43+
// CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.0
44+
45+
// This should convert the int constant to float, then produce a
46+
// _Complex float.
47+
(void)(cf + 1);
48+
// CHECK: BinaryOperator {{.*}} '_Complex float' '+'
49+
// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex float' <LValueToRValue>
50+
// CHECK-NEXT: DeclRefExpr {{.*}} 'cf'
51+
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating>
52+
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
53+
54+
// Show that we do not promote a _Complex float to _Complex double as part of
55+
// the default argument promotions when passing to a variadic function.
56+
variadic(1, cf);
57+
// CHECK: CallExpr
58+
// CHECK-NEXT: ImplicitCastExpr {{.*}} <FunctionToPointerDecay>
59+
// CHECK-NEXT: DeclRefExpr {{.*}} 'variadic'
60+
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1
61+
// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex float' <LValueToRValue>
62+
// CHECK-NEXT: DeclRefExpr {{.*}} 'cf'
63+
}
64+

clang/test/C/C99/n809_3.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %clang_cc1 -emit-llvm -std=c99 %s -o - | FileCheck %s
2+
3+
// Demonstrate that statics are properly zero initialized.
4+
static _Complex float f_global;
5+
void func(void) {
6+
static _Complex double d_local;
7+
d_local = f_global;
8+
}
9+
10+
// CHECK-DAG: @func.d_local = internal global { double, double } zeroinitializer
11+
// CHECK-DAG: @f_global = internal global { float, float } zeroinitializer
12+

clang/www/c_status.html

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -132,29 +132,22 @@ <h2 id="c99">C99 implementation status</h2>
132132
<td>Unknown</td>
133133
<td class="full" align="center">Yes</td>
134134
</tr>
135-
<tr id="complex">
136-
<td rowspan="6">complex and imaginary support in &lt;complex.h&gt;</td>
135+
<tr>
136+
<td>complex and imaginary support in &lt;complex.h&gt;</td>
137+
<td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n693.ps">N693</a></td>
138+
<td class="partial" align="center">
139+
<details><summary>Partial</summary>
140+
Clang supports <code>_Complex</code> type specifiers but does not
141+
support <code>_Imaginary</code> type specifiers. Support for
142+
<code>_Imaginary</code> is optional in C99 and Clang does not claim
143+
conformance to Annex G.<br />
144+
<br />
145+
<code>_Complex</code> support requires an underlying support library
146+
such as compiler-rt to provide functions like <code>__divsc3</code>,
147+
but compiler-rt is not supported on Windows.
148+
</details>
149+
</td>
137150
</tr>
138-
<tr>
139-
<td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n620.ps">N620</a></td>
140-
<td class="unknown" align="center">Unknown</td>
141-
</tr>
142-
<tr>
143-
<td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n638.ps">N638</a></td>
144-
<td class="unknown" align="center">Unknown</td>
145-
</tr>
146-
<tr>
147-
<td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n657.ps">N657</a></td>
148-
<td class="unknown" align="center">Unknown</td>
149-
</tr>
150-
<tr>
151-
<td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n694.ps">N694</a></td>
152-
<td class="unknown" align="center">Unknown</td>
153-
</tr>
154-
<tr>
155-
<td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n809.ps">N809</a></td>
156-
<td class="unknown" align="center">Unknown</td>
157-
</tr>
158151
<tr>
159152
<td>type-generic math macros in &lt;tgmath.h&gt;</td>
160153
<td><a href="https://www.open-std.org/jtc1/sc22/wg14/www/docs/n693.ps">N693</a></td>

0 commit comments

Comments
 (0)