https://github.com/tbaederr created 
https://github.com/llvm/llvm-project/pull/90588

Use handleFloatFloatBinOp to properly diagnose NaN results and divisions by 
zero.

Fixes #84871

>From edb5cd5c610f112bca4c9d027a017e9e6dc9bf10 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com>
Date: Tue, 30 Apr 2024 12:25:20 +0200
Subject: [PATCH] [clang][Interp] Report erroneous floating point results in
 _Complex math

Use handleFloatFloatBinOp to properly diagnose NaN results and divisions
by zero.
---
 clang/lib/AST/ExprConstant.cpp         | 27 +++++++---
 clang/test/SemaCXX/complex-folding.cpp | 73 ++++++++++++++++----------
 2 files changed, 65 insertions(+), 35 deletions(-)

diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index f1aa19e4409e15..86fb396fabe2d9 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -15209,11 +15209,21 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const 
BinaryOperator *E) {
       APFloat &ResI = Result.getComplexFloatImag();
       if (LHSReal) {
         assert(!RHSReal && "Cannot have two real operands for a complex op!");
-        ResR = A * C;
-        ResI = A * D;
+        ResR = A;
+        ResI = A;
+        // ResR = A * C;
+        // ResI = A * D;
+        if (!handleFloatFloatBinOp(Info, E, ResR, BO_Mul, C) ||
+            !handleFloatFloatBinOp(Info, E, ResI, BO_Mul, D))
+          return false;
       } else if (RHSReal) {
-        ResR = C * A;
-        ResI = C * B;
+        // ResR = C * A;
+        // ResI = C * B;
+        ResR = C;
+        ResI = C;
+        if (!handleFloatFloatBinOp(Info, E, ResR, BO_Mul, A) ||
+            !handleFloatFloatBinOp(Info, E, ResI, BO_Mul, B))
+          return false;
       } else {
         // In the fully general case, we need to handle NaNs and infinities
         // robustly.
@@ -15289,8 +15299,13 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const 
BinaryOperator *E) {
       APFloat &ResR = Result.getComplexFloatReal();
       APFloat &ResI = Result.getComplexFloatImag();
       if (RHSReal) {
-        ResR = A / C;
-        ResI = B / C;
+        ResR = A;
+        ResI = B;
+        // ResR = A / C;
+        // ResI = B / C;
+        if (!handleFloatFloatBinOp(Info, E, ResR, BO_Div, C) ||
+            !handleFloatFloatBinOp(Info, E, ResI, BO_Div, C))
+          return false;
       } else {
         if (LHSReal) {
           // No real optimizations we can do here, stub out with zero.
diff --git a/clang/test/SemaCXX/complex-folding.cpp 
b/clang/test/SemaCXX/complex-folding.cpp
index 054f159e9ce0dd..d3e428f2b75cc2 100644
--- a/clang/test/SemaCXX/complex-folding.cpp
+++ b/clang/test/SemaCXX/complex-folding.cpp
@@ -57,43 +57,58 @@ static_assert(((1.25 + 0.5j) / (0.25 - 0.75j)) == (-0.1 + 
1.7j));
 static_assert(((1.25 + 0.5j) / 0.25) == (5.0 + 2.0j));
 static_assert((1.25 / (0.25 - 0.75j)) == (0.5 + 1.5j));
 
-// Test that infinities are preserved, don't turn into NaNs, and do form zeros
-// when the divisor.
+
 static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) * 1.0)) 
== 1);
-static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) * 
1.0)) == 1);
+static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) * 
1.0)) == 1); // expected-error {{static assertion}} \
+                                                                               
           // expected-note {{produces a NaN}}
 static_assert(__builtin_isinf_sign(__real__(1.0 * (__builtin_inf() + 1.0j))) 
== 1);
-static_assert(__builtin_isinf_sign(__imag__(1.0 * (1.0 + __builtin_inf() * 
1.0j))) == 1);
-
+static_assert(__builtin_isinf_sign(__imag__(1.0 * (1.0 + __builtin_inf() * 
1.0j))) == 1); // expected-error {{static assertion}} \
+                                                                               
           // expected-note {{produces a NaN}}
 static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) * (1.0 + 
1.0j))) == 1);
 static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) * (__builtin_inf() + 
1.0j))) == 1);
 static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) * 
(__builtin_inf() + 1.0j))) == 1);
-
-static_assert(__builtin_isinf_sign(__real__((1.0 + __builtin_inf() * 1.0j) * 
(1.0 + 1.0j))) == -1);
-static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) * 
(1.0 + 1.0j))) == 1);
-static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) * (1.0 + 
__builtin_inf() * 1.0j))) == -1);
-static_assert(__builtin_isinf_sign(__imag__((1.0 + 1.0j) * (1.0 + 
__builtin_inf() * 1.0j))) == 1);
-
-static_assert(__builtin_isinf_sign(__real__((1.0 + __builtin_inf() * 1.0j) * 
(1.0 + __builtin_inf() * 1.0j))) == -1);
-static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + __builtin_inf() 
* 1.0j) * (__builtin_inf() + __builtin_inf() * 1.0j))) == -1);
-
+static_assert(__builtin_isinf_sign(__real__((1.0 + __builtin_inf() * 1.0j) * 
(1.0 + 1.0j))) == -1);  // expected-error {{static assertion}} \
+                                                                               
                      // expected-note {{produces a NaN}}
+static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) * 
(1.0 + 1.0j))) == 1); // expected-error {{static assertion}} \
+                                                                               
                    // expected-note {{produces a NaN}}
+static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) * (1.0 + 
__builtin_inf() * 1.0j))) == -1); // expected-error {{static assertion}} \
+                                                                               
                     // expected-note {{produces a NaN}}
+static_assert(__builtin_isinf_sign(__imag__((1.0 + 1.0j) * (1.0 + 
__builtin_inf() * 1.0j))) == 1); // expected-error {{static assertion}} \
+                                                                               
                    // expected-note {{produces a NaN}}
+static_assert(__builtin_isinf_sign(__real__((1.0 + __builtin_inf() * 1.0j) * 
(1.0 + __builtin_inf() * 1.0j))) == -1); // expected-error {{static assertion}} 
\
+                                                                               
                                       // expected-note {{produces a NaN}}
+static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + __builtin_inf() 
* 1.0j) * (__builtin_inf() + __builtin_inf() * 1.0j))) == -1); // 
expected-error {{static assertion}} \
+                                                                               
                                                               // expected-note 
{{produces a NaN}}
 static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / (1.0 + 
1.0j))) == 1);
-static_assert(__builtin_isinf_sign(__imag__(1.0 + (__builtin_inf() * 1.0j) / 
(1.0 + 1.0j))) == 1);
-static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() 
* 1.0j) / (1.0 + 1.0j))) == 1);
+static_assert(__builtin_isinf_sign(__imag__(1.0 + (__builtin_inf() * 1.0j) / 
(1.0 + 1.0j))) == 1); // expected-error {{static assertion}} \
+                                                                               
                    // expected-note {{produces a NaN}}
+static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() 
* 1.0j) / (1.0 + 1.0j))) == 1); // expected-error {{static assertion}} \
+                                                                               
                                // expected-note {{produces a NaN}}
 static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / 1.0)) 
== 1);
-static_assert(__builtin_isinf_sign(__imag__(1.0 + (__builtin_inf() * 1.0j) / 
1.0)) == 1);
-static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() 
* 1.0j) / 1.0)) == 1);
-
+static_assert(__builtin_isinf_sign(__imag__(1.0 + (__builtin_inf() * 1.0j) / 
1.0)) == 1); // expected-error {{static assertion}} \
+                                                                               
           // expected-note {{produces a NaN}}
+static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() 
* 1.0j) / 1.0)) == 1); // expected-error {{static assertion}} \
+                                                                               
                       // expected-note {{produces a NaN}}
 static_assert(((1.0 + 1.0j) / (__builtin_inf() + 1.0j)) == (0.0 + 0.0j));
-static_assert(((1.0 + 1.0j) / (1.0 + __builtin_inf() * 1.0j)) == (0.0 + 0.0j));
-static_assert(((1.0 + 1.0j) / (__builtin_inf() + __builtin_inf() * 1.0j)) == 
(0.0 + 0.0j));
+static_assert(((1.0 + 1.0j) / (1.0 + __builtin_inf() * 1.0j)) == (0.0 + 
0.0j)); // expected-error {{static assertion}} \
+                                                                               
 // expected-note {{produces a NaN}}
+static_assert(((1.0 + 1.0j) / (__builtin_inf() + __builtin_inf() * 1.0j)) == 
(0.0 + 0.0j)); // expected-error {{static assertion}} \
+                                                                               
             // expected-note {{produces a NaN}}
 static_assert(((1.0 + 1.0j) / __builtin_inf()) == (0.0 + 0.0j));
-
+static_assert(1.0j / 0.0 == 1); // expected-error {{static assertion}} \
+                                // expected-note {{division by zero}}
 static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) / (0.0 + 0.0j))) == 
1);
-static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) / 0.0)) == 1);
-
+static_assert(__builtin_isinf_sign(__real__((1.0 + 1.0j) / 0.0)) == 1); // 
expected-error {{static assertion}} \
+                                                                        // 
expected-note {{division by zero}}
 static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / (0.0 + 
0.0j))) == 1);
-static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) / 
(0.0 + 0.0j))) == 1);
-static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() 
* 1.0j) / (0.0 + 0.0j))) == 1);
-static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / 0.0)) 
== 1);
-static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) / 
0.0)) == 1);
-static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() 
* 1.0j) / 0.0)) == 1);
+static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) / 
(0.0 + 0.0j))) == 1); // expected-error {{static assertion}} \
+                                                                               
                    // expected-note {{produces a NaN}}
+static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() 
* 1.0j) / (0.0 + 0.0j))) == 1); // expected-error {{static assertion}} \
+                                                                               
                                // expected-note {{produces a NaN}}
+static_assert(__builtin_isinf_sign(__real__((__builtin_inf() + 1.0j) / 0.0)) 
== 1); // expected-error {{static assertion}} \
+                                                                               
     // expected-note {{division by zero}}
+static_assert(__builtin_isinf_sign(__imag__((1.0 + __builtin_inf() * 1.0j) / 
0.0)) == 1); // expected-error {{static assertion}} \
+                                                                               
           // expected-note {{produces a NaN}}
+static_assert(__builtin_isinf_sign(__imag__((__builtin_inf() + __builtin_inf() 
* 1.0j) / 0.0)) == 1); // expected-error {{static assertion}} \
+                                                                               
                       // expected-note {{produces a NaN}}
+

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to