tbaeder created this revision.
tbaeder added reviewers: jcranmer-intel, clang.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Split out from https://reviews.llvm.org/D156506.

Before adding this behavior to the new constexpr interpreter, I'd like to first 
see it in the current one.

This patch removes the checks for a NaN result of floating point operations and 
instead checks the input operands for signaling NaNs.

There are only three tests for the NaN-result check as far as I can see, so I 
added a few new ones.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D157072

Files:
  clang/include/clang/Basic/DiagnosticASTKinds.td
  clang/lib/AST/ExprConstant.cpp
  clang/test/CXX/expr/expr.const/p2-0x.cpp
  clang/test/SemaCXX/constexpr-float.cpp

Index: clang/test/SemaCXX/constexpr-float.cpp
===================================================================
--- /dev/null
+++ clang/test/SemaCXX/constexpr-float.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+
+template<typename T>
+constexpr bool isNan(T V) {
+  return __builtin_isnan(V);
+}
+
+constexpr double Signaling = __builtin_nans("");
+static_assert(isNan(Signaling), "");
+constexpr double Quiet = __builtin_nan("");
+static_assert(isNan(Quiet), "");
+
+
+static_assert(Signaling + 1 == 0, ""); // expected-error {{not an integral constant expression}} \
+                                       // expected-note {{NaN input to a floating point operation}}
+static_assert(Signaling - 1 == 0, ""); // expected-error {{not an integral constant expression}} \
+                                       // expected-note {{NaN input to a floating point operation}}
+static_assert(Signaling / 1 == 0, ""); // expected-error {{not an integral constant expression}} \
+                                       // expected-note {{NaN input to a floating point operation}}
+static_assert(Signaling * 1 == 0, ""); // expected-error {{not an integral constant expression}} \
+                                       // expected-note {{NaN input to a floating point operation}}
+
+static_assert(Quiet + 1 != 0, "");
+static_assert(isNan(Quiet + 1), "");
+static_assert(-Signaling != 0, "");
+static_assert(+Signaling != 0, "");
Index: clang/test/CXX/expr/expr.const/p2-0x.cpp
===================================================================
--- clang/test/CXX/expr/expr.const/p2-0x.cpp
+++ clang/test/CXX/expr/expr.const/p2-0x.cpp
@@ -278,9 +278,9 @@
     constexpr float f7 = 0.f / 0.f; // expected-error {{constant expression}} expected-note {{division by zero}}
     constexpr float f8 = 1.f / 0.f; // expected-error {{constant expression}} expected-note {{division by zero}}
     constexpr float f9 = 1e308 / 1e-308; // ok, +inf
-    constexpr float f10 = f2 - f2; // expected-error {{constant expression}} expected-note {{produces a NaN}}
-    constexpr float f11 = f2 + f4; // expected-error {{constant expression}} expected-note {{produces a NaN}}
-    constexpr float f12 = f2 / f2; // expected-error {{constant expression}} expected-note {{produces a NaN}}
+    constexpr float f10 = f2 - f2;
+    constexpr float f11 = f2 + f4;
+    constexpr float f12 = f2 / f2;
 #pragma float_control(push)
 #pragma float_control(except, on)
 constexpr float pi = 3.14f;
Index: clang/lib/AST/ExprConstant.cpp
===================================================================
--- clang/lib/AST/ExprConstant.cpp
+++ clang/lib/AST/ExprConstant.cpp
@@ -2628,6 +2628,16 @@
   return RM;
 }
 
+/// Signaling NaNs are invalid inputs to floating point operations.
+static bool checkFloatingPointInput(EvalInfo &Info, const Expr *E,
+                                    const APFloat &Input) {
+  if (!Input.isSignaling())
+    return true;
+
+  Info.CCEDiag(E, diag::note_constexpr_float_nan_input) << E->getSourceRange();
+  return Info.noteUndefinedBehavior();
+}
+
 /// Check if the given evaluation result is allowed for constant evaluation.
 static bool checkFloatingPointResult(EvalInfo &Info, const Expr *E,
                                      APFloat::opStatus St) {
@@ -2904,6 +2914,10 @@
 static bool handleFloatFloatBinOp(EvalInfo &Info, const BinaryOperator *E,
                                   APFloat &LHS, BinaryOperatorKind Opcode,
                                   const APFloat &RHS) {
+  if (!checkFloatingPointInput(Info, E->getLHS(), LHS) ||
+      !checkFloatingPointInput(Info, E->getRHS(), RHS))
+    return false;
+
   llvm::RoundingMode RM = getActiveRoundingMode(Info, E);
   APFloat::opStatus St;
   switch (Opcode) {
@@ -2928,15 +2942,6 @@
     break;
   }
 
-  // [expr.pre]p4:
-  //   If during the evaluation of an expression, the result is not
-  //   mathematically defined [...], the behavior is undefined.
-  // FIXME: C++ rules require us to not conform to IEEE 754 here.
-  if (LHS.isNaN()) {
-    Info.CCEDiag(E, diag::note_constexpr_float_arithmetic) << LHS.isNaN();
-    return Info.noteUndefinedBehavior();
-  }
-
   return checkFloatingPointResult(Info, E, St);
 }
 
Index: clang/include/clang/Basic/DiagnosticASTKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticASTKinds.td
+++ clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -79,6 +79,8 @@
   "in a constant expression">;
 def note_constexpr_float_arithmetic : Note<
   "floating point arithmetic produces %select{an infinity|a NaN}0">;
+def note_constexpr_float_nan_input : Note<
+  "NaN input to a floating point operation">;
 def note_constexpr_dynamic_rounding : Note<
   "cannot evaluate this expression if rounding mode is dynamic">;
 def note_constexpr_float_arithmetic_strict : Note<
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D157072: [clang][ExprC... Timm Bäder via Phabricator via cfe-commits

Reply via email to