-
Notifications
You must be signed in to change notification settings - Fork 10.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[C99] Claim conformance for _Complex support (#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.
- Loading branch information
1 parent
83dc419
commit 0318ce8
Showing
4 changed files
with
213 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
// RUN: %clang_cc1 -verify -std=c99 %s | ||
|
||
/* WG14 N620, N638, N657, N694, N809: Partial | ||
* Complex and imaginary support in <complex.h> | ||
* | ||
* 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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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' <FloatingComplexCast> | ||
// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex float' <LValueToRValue> | ||
// CHECK-NEXT: DeclRefExpr {{.*}} 'cf' | ||
|
||
cf = cd; | ||
// CHECK: BinaryOperator {{.*}} '_Complex float' '=' | ||
// CHECK-NEXT: DeclRefExpr {{.*}} 'cf' | ||
// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex float' <FloatingComplexCast> | ||
// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex double' <LValueToRValue> | ||
// 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' <FloatingComplexCast> | ||
// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex float' <LValueToRValue> | ||
// 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' <LValueToRValue> | ||
// CHECK-NEXT: DeclRefExpr {{.*}} 'cd' | ||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'double' <FloatingCast> | ||
// 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' <LValueToRValue> | ||
// CHECK-NEXT: DeclRefExpr {{.*}} 'cf' | ||
// CHECK-NEXT: ImplicitCastExpr {{.*}} 'float' <IntegralToFloating> | ||
// 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 {{.*}} <FunctionToPointerDecay> | ||
// CHECK-NEXT: DeclRefExpr {{.*}} 'variadic' | ||
// CHECK-NEXT: IntegerLiteral {{.*}} 'int' 1 | ||
// CHECK-NEXT: ImplicitCastExpr {{.*}} '_Complex float' <LValueToRValue> | ||
// CHECK-NEXT: DeclRefExpr {{.*}} 'cf' | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters