-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[C99] Claim conformance for _Complex support #88161
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9639b31
708f342
325afe9
e3eb3cd
66cbde9
7fea623
c3f7d6e
9453c35
98ad653
18c5710
5932155
e89e5ba
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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, ""); | ||
Comment on lines
+54
to
+55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is using an extension for complex initializers, not a standard feature, so I'm a little bit uncomfortable that it's actually testing the assertion that the first element of the array corresponds to the real. That said, I'm not sure there's any non-extension way to test that as a constant expression anyways, so... 🤷 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The other alternative would be to use a builtin function, I can go either way. Maybe I should use one of each to show they're equivalent? |
||
|
||
_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 | ||
} |
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' | ||
} | ||
|
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 | ||
|
Uh oh!
There was an error while loading. Please reload this page.