diff --git a/clang/test/C/C99/n809.c b/clang/test/C/C99/n809.c new file mode 100644 index 0000000000000..7297443a777cc --- /dev/null +++ b/clang/test/C/C99/n809.c @@ -0,0 +1,122 @@ +// RUN: %clang_cc1 -verify -std=c99 %s + +/* WG14 N620, N638, N657, N694, N809: Partial + * Complex and imaginary support in + * + * NB: Clang supports _Complex but not _Imaginary. In C99, _Complex support is + * required outside of freestanding, but _Imaginary support is fully optional. + * In C11, both are made fully optional. + * + * NB: _Complex support requires an underlying support library such as + * compiler-rt to provide functions like __divsc3. Compiler-rt is not supported + * on Windows. + * + * Because the functionality is so intertwined between the various papers, + * we're testing all of the functionality in one file. + */ + +// Demonstrate that we support spelling complex floating-point objects. +float _Complex f1; +_Complex float f2; + +double _Complex d1; +_Complex double d2; + +long double _Complex ld1; +_Complex long double ld2; + +// Show that we don't support spelling imaginary types. +float _Imaginary fi1; // expected-error {{imaginary types are not supported}} +_Imaginary float fi2; // expected-error {{imaginary types are not supported}} + +double _Imaginary di1; // expected-error {{imaginary types are not supported}} +_Imaginary double di2; // expected-error {{imaginary types are not supported}} + +long double _Imaginary ldi1; // expected-error {{imaginary types are not supported}} +_Imaginary long double ldi2; // expected-error {{imaginary types are not supported}} + +// Each complex type has the same representation and alignment as an array +// containing two elements of the corresponding real type. Note, it is not +// mandatory that the alignment of a structure containing an array of two +// elements has the same alignment as an array of two elements outside of a +// structure, but this is a property Clang supports. +_Static_assert(sizeof(float _Complex) == sizeof(struct { float mem[2]; }), ""); +_Static_assert(_Alignof(float _Complex) == _Alignof(struct { float mem[2]; }), ""); + +_Static_assert(sizeof(double _Complex) == sizeof(struct { double mem[2]; }), ""); +_Static_assert(_Alignof(double _Complex) == _Alignof(struct { double mem[2]; }), ""); + +_Static_assert(sizeof(long double _Complex) == sizeof(struct { long double mem[2]; }), ""); +_Static_assert(_Alignof(long double _Complex) == _Alignof(struct { long double mem[2]; }), ""); + +// The first element corresponds to the real part and the second element +// corresponds to the imaginary part. +_Static_assert(__real((float _Complex){ 1.0f, 2.0f }) == 1.0f, ""); +_Static_assert(__imag((float _Complex){ 1.0f, 2.0f }) == 2.0f, ""); + +_Static_assert(__real((double _Complex){ 1.0, 2.0 }) == 1.0, ""); +_Static_assert(__imag((double _Complex){ 1.0, 2.0 }) == 2.0, ""); + +_Static_assert(__real((long double _Complex){ 1.0L, 2.0L }) == 1.0L, ""); +_Static_assert(__imag((long double _Complex){ 1.0L, 2.0L }) == 2.0L, ""); + +// When a real value is converted to a complex value, the real part follows the +// usual conversion rules and the imaginary part should be zero. +_Static_assert(__real((float _Complex)1.0f) == 1.0f, ""); +_Static_assert(__imag((float _Complex)1.0f) == 0.0f, ""); + +_Static_assert(__real((double _Complex)1.0f) == 1.0, ""); +_Static_assert(__imag((double _Complex)1.0f) == 0.0, ""); + +_Static_assert(__real((long double _Complex)1.0f) == 1.0L, ""); +_Static_assert(__imag((long double _Complex)1.0f) == 0.0L, ""); + +// When a complex value is converted to a real value, the real part follows the +// usual conversion rules and the imaginary part is discarded. +_Static_assert((float)(float _Complex){ 1.0f, 2.0f } == 1.0f, ""); +_Static_assert((double)(float _Complex){ 1.0f, 2.0f } == 1.0, ""); +_Static_assert((long double)(float _Complex){ 1.0f, 2.0f } == 1.0L, ""); + +// Complex values are only equal if both the real and imaginary parts are equal. +_Static_assert((float _Complex){ 1.0f, 2.0f } == (float _Complex){ 1.0f, 2.0f }, ""); +_Static_assert((double _Complex){ 1.0, 2.0 } == (double _Complex){ 1.0, 2.0 }, ""); +_Static_assert((long double _Complex){ 1.0L, 2.0L } == (long double _Complex){ 1.0L, 2.0L }, ""); + +_Static_assert((float _Complex){ 1.0f, 2.0f } != (float _Complex){ 2.0f, 0.0f }, ""); +_Static_assert((double _Complex){ 1.0, 2.0 } != (double _Complex){ 2.0, 0.0 }, ""); +_Static_assert((long double _Complex){ 1.0L, 2.0L } != (long double _Complex){ 2.0L, 0.0L }, ""); + +// You cannot use relational operator on complex values. +int i1 = (float _Complex){ 1.0f, 2.0f } < 10; // expected-error {{invalid operands to binary expression}} +int i2 = (double _Complex){ 1.0f, 2.0f } > 10; // expected-error {{invalid operands to binary expression}} +int i3 = (long double _Complex){ 1.0f, 2.0f } <= 10; // expected-error {{invalid operands to binary expression}} +int i4 = (float _Complex){ 1.0f, 2.0f } >= 10; // expected-error {{invalid operands to binary expression}} + +// As a type specifier, _Complex cannot appear alone; however, we support it as +// an extension by assuming _Complex double. +_Complex c = 1.0f; // expected-warning {{plain '_Complex' requires a type specifier; assuming '_Complex double'}} +// Because we don't support imaginary types, we don't extend the extension to +// that type specifier. +// FIXME: the warning diagnostic here is incorrect and should not be emitted. +_Imaginary i = 1.0f; // expected-warning {{plain '_Complex' requires a type specifier; assuming '_Complex double'}} \ + expected-error {{imaginary types are not supported}} + +void func(void) { +#pragma clang diagnostic push +#pragma clang diagnostic warning "-Wpedantic" + // Increment and decrement operators have a constraint that their operand be + // a real type; Clang supports this as an extension on complex types as well. + _Complex float cf = 0.0f; + + cf++; // expected-warning {{'++' on an object of complex type is a Clang extension}} + ++cf; // expected-warning {{'++' on an object of complex type is a Clang extension}} + + cf--; // expected-warning {{'--' on an object of complex type is a Clang extension}} + --cf; // expected-warning {{'--' on an object of complex type is a Clang extension}} + + // However, unary + and - are fine, as is += 1. + (void)-cf; + (void)+cf; + cf += 1; +#pragma clang diagnostic pop +} diff --git a/clang/test/C/C99/n809_2.c b/clang/test/C/C99/n809_2.c new file mode 100644 index 0000000000000..3bf163126521a --- /dev/null +++ b/clang/test/C/C99/n809_2.c @@ -0,0 +1,64 @@ +// RUN: %clang_cc1 -ast-dump -std=c99 %s | FileCheck %s + +void variadic(int i, ...); + +void func(void) { + // CHECK: FunctionDecl {{.*}} func 'void (void)' + + // Show that we correctly convert between two complex domains. + _Complex float cf = 1.0f; + _Complex double cd; + + cd = cf; + // CHECK: BinaryOperator {{.*}} '_Complex double' '=' + // CHECK-NEXT: DeclRefExpr {{.*}} 'cd' + // CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex double' + // CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex float' + // CHECK-NEXT: DeclRefExpr {{.*}} 'cf' + + cf = cd; + // CHECK: BinaryOperator {{.*}} '_Complex float' '=' + // CHECK-NEXT: DeclRefExpr {{.*}} 'cf' + // CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex float' + // CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex double' + // CHECK-NEXT: DeclRefExpr {{.*}} 'cd' + + // Show that we correctly convert to the common type of a complex and real. + // This should convert the _Complex float to a _Complex double ("without + // change of domain" c.f. C99 6.3.1.8p1). + (void)(cf + 1.0); + // CHECK: BinaryOperator {{.*}} '_Complex double' '+' + // CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex double' + // CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex float' + // CHECK-NEXT: DeclRefExpr {{.*}} 'cf' + // CHECK-NEXT: FloatingLiteral {{.*}} 'double' 1.0 + + // This should convert the float constant to double, then produce a + // _Complex double. + (void)(cd + 1.0f); + // CHECK: BinaryOperator {{.*}} '_Complex double' '+' + // CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex double' + // CHECK-NEXT: DeclRefExpr {{.*}} 'cd' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' + // CHECK-NEXT: FloatingLiteral {{.*}} 'float' 1.0 + + // This should convert the int constant to float, then produce a + // _Complex float. + (void)(cf + 1); + // CHECK: BinaryOperator {{.*}} '_Complex float' '+' + // CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex float' + // CHECK-NEXT: DeclRefExpr {{.*}} 'cf' + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' + // CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1 + + // Show that we do not promote a _Complex float to _Complex double as part of + // the default argument promotions when passing to a variadic function. + variadic(1, cf); + // CHECK: CallExpr + // CHECK-NEXT: ImplicitCastExpr {{.*}} + // CHECK-NEXT: DeclRefExpr {{.*}} 'variadic' + // CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1 + // CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex float' + // CHECK-NEXT: DeclRefExpr {{.*}} 'cf' +} + diff --git a/clang/test/C/C99/n809_3.c b/clang/test/C/C99/n809_3.c new file mode 100644 index 0000000000000..f1283f5fe1632 --- /dev/null +++ b/clang/test/C/C99/n809_3.c @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -emit-llvm -std=c99 %s -o - | FileCheck %s + +// Demonstrate that statics are properly zero initialized. +static _Complex float f_global; +void func(void) { + static _Complex double d_local; + d_local = f_global; +} + +// CHECK-DAG: @func.d_local = internal global { double, double } zeroinitializer +// CHECK-DAG: @f_global = internal global { float, float } zeroinitializer + diff --git a/clang/www/c_status.html b/clang/www/c_status.html index 411f55447be77..9893170ae8473 100644 --- a/clang/www/c_status.html +++ b/clang/www/c_status.html @@ -132,29 +132,22 @@

C99 implementation status

Unknown Yes - - complex and imaginary support in <complex.h> + + complex and imaginary support in <complex.h> + N693 + +
Partial + Clang supports _Complex type specifiers but does not + support _Imaginary type specifiers. Support for + _Imaginary is optional in C99 and Clang does not claim + conformance to Annex G.
+
+ _Complex support requires an underlying support library + such as compiler-rt to provide functions like __divsc3, + but compiler-rt is not supported on Windows. +
+ - - N620 - Unknown - - - N638 - Unknown - - - N657 - Unknown - - - N694 - Unknown - - - N809 - Unknown - type-generic math macros in <tgmath.h> N693