Skip to content

Commit 4bcba4c

Browse files
committed
[clang] Report erroneous floating point results in _Complex math
Use handleFloatFloatBinOp to properly diagnose NaN results and divisions by zero.
1 parent 5c40db1 commit 4bcba4c

File tree

2 files changed

+55
-33
lines changed

2 files changed

+55
-33
lines changed

clang/lib/AST/ExprConstant.cpp

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15209,11 +15209,21 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
1520915209
APFloat &ResI = Result.getComplexFloatImag();
1521015210
if (LHSReal) {
1521115211
assert(!RHSReal && "Cannot have two real operands for a complex op!");
15212-
ResR = A * C;
15213-
ResI = A * D;
15212+
ResR = A;
15213+
ResI = A;
15214+
// ResR = A * C;
15215+
// ResI = A * D;
15216+
if (!handleFloatFloatBinOp(Info, E, ResR, BO_Mul, C) ||
15217+
!handleFloatFloatBinOp(Info, E, ResI, BO_Mul, D))
15218+
return false;
1521415219
} else if (RHSReal) {
15215-
ResR = C * A;
15216-
ResI = C * B;
15220+
// ResR = C * A;
15221+
// ResI = C * B;
15222+
ResR = C;
15223+
ResI = C;
15224+
if (!handleFloatFloatBinOp(Info, E, ResR, BO_Mul, A) ||
15225+
!handleFloatFloatBinOp(Info, E, ResI, BO_Mul, B))
15226+
return false;
1521715227
} else {
1521815228
// In the fully general case, we need to handle NaNs and infinities
1521915229
// robustly.
@@ -15289,8 +15299,13 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
1528915299
APFloat &ResR = Result.getComplexFloatReal();
1529015300
APFloat &ResI = Result.getComplexFloatImag();
1529115301
if (RHSReal) {
15292-
ResR = A / C;
15293-
ResI = B / C;
15302+
ResR = A;
15303+
ResI = B;
15304+
// ResR = A / C;
15305+
// ResI = B / C;
15306+
if (!handleFloatFloatBinOp(Info, E, ResR, BO_Div, C) ||
15307+
!handleFloatFloatBinOp(Info, E, ResI, BO_Div, C))
15308+
return false;
1529415309
} else {
1529515310
if (LHSReal) {
1529615311
// No real optimizations we can do here, stub out with zero.

clang/test/SemaCXX/complex-folding.cpp

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -59,41 +59,48 @@ static_assert((1.25 / (0.25 - 0.75j)) == (0.5 + 1.5j));
5959

6060
// Test that infinities are preserved, don't turn into NaNs, and do form zeros
6161
// when the divisor.
62+
constexpr _Complex float InfC = {1.0, __builtin_inf()};
63+
constexpr _Complex float InfInf = __builtin_inf() + InfC;
64+
static_assert(__real__(InfInf) == __builtin_inf());
65+
static_assert(__imag__(InfInf) == __builtin_inf());
66+
static_assert(__builtin_isnan(__real__(InfInf * InfInf)));
67+
static_assert(__builtin_isinf_sign(__imag__(InfInf * InfInf)) == 1);
68+
6269
static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) * 1.0)) == 1);
63-
static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) * 1.0)) == 1);
70+
static_assert(__builtin_isinf_sign(__imag__((1.0 + InfC) * 1.0)) == 1);
6471
static_assert(__builtin_isinf_sign(__real__(1.0 * (__builtin_inf() + 1.0j))) == 1);
65-
static_assert(__builtin_isinf_sign(__imag__(1.0 * (1.0 + __builtin_inf() * 1.0j))) == 1);
66-
72+
static_assert(__builtin_isinf_sign(__imag__(1.0 * (1.0 + InfC))) == 1);
6773
static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) * (1.0 + 1.0j))) == 1);
6874
static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) * (__builtin_inf() + 1.0j))) == 1);
6975
static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) * (__builtin_inf() + 1.0j))) == 1);
70-
71-
static_assert(__builtin_isinf_sign(__real__((1.0 + __builtin_inf() * 1.0j) * (1.0 + 1.0j))) == -1);
72-
static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) * (1.0 + 1.0j))) == 1);
73-
static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) * (1.0 + __builtin_inf() * 1.0j))) == -1);
74-
static_assert(__builtin_isinf_sign(__imag__((1.0 + 1.0j) * (1.0 + __builtin_inf() * 1.0j))) == 1);
75-
76-
static_assert(__builtin_isinf_sign(__real__((1.0 + __builtin_inf() * 1.0j) * (1.0 + __builtin_inf() * 1.0j))) == -1);
77-
static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + __builtin_inf() * 1.0j) * (__builtin_inf() + __builtin_inf() * 1.0j))) == -1);
78-
76+
static_assert(__builtin_isinf_sign(__real__((1.0 + InfC) * (1.0 + 1.0j))) == -1);
77+
static_assert(__builtin_isinf_sign(__imag__((1.0 + InfC) * (1.0 + 1.0j))) == 1);
78+
static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) * (1.0 + InfC))) == -1);
79+
static_assert(__builtin_isinf_sign(__imag__((1.0 + 1.0j) * (1.0 + InfC))) == 1);
80+
static_assert(__builtin_isinf_sign(__real__((1.0 + InfC) * (1.0 + InfC))) == -1);
81+
static_assert(__builtin_isinf_sign(__real__(InfInf * InfInf)) == 0);
7982
static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / (1.0 + 1.0j))) == 1);
80-
static_assert(__builtin_isinf_sign(__imag__(1.0 + (__builtin_inf() * 1.0j) / (1.0 + 1.0j))) == 1);
81-
static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() * 1.0j) / (1.0 + 1.0j))) == 1);
83+
static_assert(__builtin_isinf_sign(__imag__(1.0 + (InfC) / (1.0 + 1.0j))) == 1);
84+
static_assert(__builtin_isinf_sign(__imag__((InfInf) / (1.0 + 1.0j))) == 0);
8285
static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / 1.0)) == 1);
83-
static_assert(__builtin_isinf_sign(__imag__(1.0 + (__builtin_inf() * 1.0j) / 1.0)) == 1);
84-
static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() * 1.0j) / 1.0)) == 1);
85-
86+
static_assert(__builtin_isinf_sign(__imag__(1.0 + (InfC) / 1.0)) == 1);
87+
static_assert(__builtin_isinf_sign(__imag__((InfInf) / 1.0)) == 1);
8688
static_assert(((1.0 + 1.0j) / (__builtin_inf() + 1.0j)) == (0.0 + 0.0j));
87-
static_assert(((1.0 + 1.0j) / (1.0 + __builtin_inf() * 1.0j)) == (0.0 + 0.0j));
88-
static_assert(((1.0 + 1.0j) / (__builtin_inf() + __builtin_inf() * 1.0j)) == (0.0 + 0.0j));
89+
static_assert(((1.0 + 1.0j) / (1.0 + InfC)) == (0.0 + 0.0j));
90+
static_assert(((1.0 + 1.0j) / (InfInf)) == (0.0 + 0.0j));
8991
static_assert(((1.0 + 1.0j) / __builtin_inf()) == (0.0 + 0.0j));
90-
92+
static_assert(1.0j / 0.0 == 1); // expected-error {{static assertion}} \
93+
// expected-note {{division by zero}}
9194
static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) / (0.0 + 0.0j))) == 1);
92-
static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) / 0.0)) == 1);
93-
95+
static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) / 0.0)) == 1); // expected-error {{static assertion}} \
96+
// expected-note {{division by zero}}
9497
static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / (0.0 + 0.0j))) == 1);
95-
static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) / (0.0 + 0.0j))) == 1);
96-
static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() * 1.0j) / (0.0 + 0.0j))) == 1);
97-
static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / 0.0)) == 1);
98-
static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) / 0.0)) == 1);
99-
static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() * 1.0j) / 0.0)) == 1);
98+
static_assert(__builtin_isinf_sign(__imag__((1.0 + InfC) / (0.0 + 0.0j))) == 1);
99+
static_assert(__builtin_isinf_sign(__imag__((InfInf) / (0.0 + 0.0j))) == 1);
100+
static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / 0.0)) == 1); // expected-error {{static assertion}} \
101+
// expected-note {{division by zero}}
102+
static_assert(__builtin_isinf_sign(__imag__((1.0 + InfC) / 0.0)) == 1); // expected-error {{static assertion}} \
103+
// expected-note {{division by zero}}
104+
static_assert(__builtin_isinf_sign(__imag__((InfInf) / 0.0)) == 1); // expected-error {{static assertion}} \
105+
// expected-note {{division by zero}}
106+

0 commit comments

Comments
 (0)