C23 6.3.1.8 ‘Usual arithmetic conversions’ p1 states (emphasis mine): > Otherwise, if the corresponding real type of either operand is `float`, the other operand is converted, *without change of type domain*, to a type whose corresponding real type is `float`. ‘type domain’ here refers to `_Complex` vs real (i.e. non-`_Complex`); there is another clause that states the same for `double`. Consider the following code: ```c++ _Complex float f; int x; f / x; ``` After talking this over with @AaronBallman, we came to the conclusion that `x` should be converted to `float` and *not* `_Complex float` (that is, we should perform a division of `_Complex float / float`, and *not* `_Complex float / _Complex float`; the same also applies to `-+*`). This was already being done correctly for cases where `x` was already a `float`; it’s just mixed `_Complex float`+`int` operations that currently suffer from this problem. This pr removes the extra `FloatingRealToComplex` conversion that we were erroneously inserting and adds some tests to make sure we’re actually doing `_Complex float / float` and not `_Complex float / _Complex float` (and analogously for `double` and `-+*`). The only exception here is `float / _Complex float`, which calls a library function (`__divsc3`) that takes 4 `float`s, so we end up having to convert the `float` to a `_Complex float` after all (and analogously for `double`); I don’t believe there is a way around this. Lastly, we were also missing tests for `_Complex` arithmetic at compile time, so this adds some tests for that as well.
116 lines
3.0 KiB
C
116 lines
3.0 KiB
C
// RUN: %clang_cc1 -verify %s
|
|
// expected-no-diagnostics
|
|
|
|
// This tests evaluation of _Complex arithmetic at compile time.
|
|
|
|
#define APPROX_EQ(a, b) ( \
|
|
__builtin_fabs(__real (a) - __real (b)) < 0.0001 && \
|
|
__builtin_fabs(__imag (a) - __imag (b)) < 0.0001 \
|
|
)
|
|
|
|
#define EVAL(a, b) _Static_assert(a == b, "")
|
|
#define EVALF(a, b) _Static_assert(APPROX_EQ(a, b), "")
|
|
|
|
// _Complex float + _Complex float
|
|
void a() {
|
|
EVALF((2.f + 3i) + (4.f + 5i), 6.f + 8i);
|
|
EVALF((2.f + 3i) - (4.f + 5i), -2.f - 2i);
|
|
EVALF((2.f + 3i) * (4.f + 5i), -7.f + 22i);
|
|
EVALF((2.f + 3i) / (4.f + 5i), 0.5609f + 0.0487i);
|
|
|
|
EVALF((2. + 3i) + (4. + 5i), 6. + 8i);
|
|
EVALF((2. + 3i) - (4. + 5i), -2. - 2i);
|
|
EVALF((2. + 3i) * (4. + 5i), -7. + 22i);
|
|
EVALF((2. + 3i) / (4. + 5i), .5609 + .0487i);
|
|
}
|
|
|
|
// _Complex int + _Complex int
|
|
void b() {
|
|
EVAL((2 + 3i) + (4 + 5i), 6 + 8i);
|
|
EVAL((2 + 3i) - (4 + 5i), -2 - 2i);
|
|
EVAL((2 + 3i) * (4 + 5i), -7 + 22i);
|
|
EVAL((8 + 30i) / (4 + 5i), 4 + 1i);
|
|
}
|
|
|
|
// _Complex float + float
|
|
void c() {
|
|
EVALF((2.f + 4i) + 3.f, 5.f + 4i);
|
|
EVALF((2.f + 4i) - 3.f, -1.f + 4i);
|
|
EVALF((2.f + 4i) * 3.f, 6.f + 12i);
|
|
EVALF((2.f + 4i) / 2.f, 1.f + 2i);
|
|
|
|
EVALF(3.f + (2.f + 4i), 5.f + 4i);
|
|
EVALF(3.f - (2.f + 4i), 1.f - 4i);
|
|
EVALF(3.f * (2.f + 4i), 6.f + 12i);
|
|
EVALF(3.f / (2.f + 4i), .3f - 0.6i);
|
|
|
|
EVALF((2. + 4i) + 3., 5. + 4i);
|
|
EVALF((2. + 4i) - 3., -1. + 4i);
|
|
EVALF((2. + 4i) * 3., 6. + 12i);
|
|
EVALF((2. + 4i) / 2., 1. + 2i);
|
|
|
|
EVALF(3. + (2. + 4i), 5. + 4i);
|
|
EVALF(3. - (2. + 4i), 1. - 4i);
|
|
EVALF(3. * (2. + 4i), 6. + 12i);
|
|
EVALF(3. / (2. + 4i), .3 - 0.6i);
|
|
}
|
|
|
|
// _Complex int + int
|
|
void d() {
|
|
EVAL((2 + 4i) + 3, 5 + 4i);
|
|
EVAL((2 + 4i) - 3, -1 + 4i);
|
|
EVAL((2 + 4i) * 3, 6 + 12i);
|
|
EVAL((2 + 4i) / 2, 1 + 2i);
|
|
|
|
EVAL(3 + (2 + 4i), 5 + 4i);
|
|
EVAL(3 - (2 + 4i), 1 - 4i);
|
|
EVAL(3 * (2 + 4i), 6 + 12i);
|
|
EVAL(20 / (2 + 4i), 2 - 4i);
|
|
}
|
|
|
|
// _Complex float + int
|
|
void e() {
|
|
EVALF((2.f + 4i) + 3, 5.f + 4i);
|
|
EVALF((2.f + 4i) - 3, -1.f + 4i);
|
|
EVALF((2.f + 4i) * 3, 6.f + 12i);
|
|
EVALF((2.f + 4i) / 2, 1.f + 2i);
|
|
|
|
EVALF(3 + (2.f + 4i), 5.f + 4i);
|
|
EVALF(3 - (2.f + 4i), 1.f - 4i);
|
|
EVALF(3 * (2.f + 4i), 6.f + 12i);
|
|
EVALF(3 / (2.f + 4i), .3f - 0.6i);
|
|
|
|
EVALF((2. + 4i) + 3, 5. + 4i);
|
|
EVALF((2. + 4i) - 3, -1. + 4i);
|
|
EVALF((2. + 4i) * 3, 6. + 12i);
|
|
EVALF((2. + 4i) / 2, 1. + 2i);
|
|
|
|
EVALF(3 + (2. + 4i), 5. + 4i);
|
|
EVALF(3 - (2. + 4i), 1. - 4i);
|
|
EVALF(3 * (2. + 4i), 6. + 12i);
|
|
EVALF(3 / (2. + 4i), .3 - 0.6i);
|
|
}
|
|
|
|
// _Complex int + float
|
|
void f() {
|
|
EVALF((2 + 4i) + 3.f, 5.f + 4i);
|
|
EVALF((2 + 4i) - 3.f, -1.f + 4i);
|
|
EVALF((2 + 4i) * 3.f, 6.f + 12i);
|
|
EVALF((2 + 4i) / 2.f, 1.f + 2i);
|
|
|
|
EVALF(3.f + (2 + 4i), 5.f + 4i);
|
|
EVALF(3.f - (2 + 4i), 1.f - 4i);
|
|
EVALF(3.f * (2 + 4i), 6.f + 12i);
|
|
EVALF(3.f / (2 + 4i), .3f - 0.6i);
|
|
|
|
EVALF((2 + 4i) + 3., 5. + 4i);
|
|
EVALF((2 + 4i) - 3., -1. + 4i);
|
|
EVALF((2 + 4i) * 3., 6. + 12i);
|
|
EVALF((2 + 4i) / 2., 1. + 2i);
|
|
|
|
EVALF(3. + (2 + 4i), 5. + 4i);
|
|
EVALF(3. - (2 + 4i), 1. - 4i);
|
|
EVALF(3. * (2 + 4i), 6. + 12i);
|
|
EVALF(3. / (2 + 4i), .3 - 0.6i);
|
|
}
|