[clang] 4b5fe9c - [clang][Interp] Check floating results for NaNs

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Mon Sep 11 03:21:51 PDT 2023


Author: Timm Bäder
Date: 2023-09-11T12:21:36+02:00
New Revision: 4b5fe9c42d94905a6f940e50958c56ed2d47a2cc

URL: https://github.com/llvm/llvm-project/commit/4b5fe9c42d94905a6f940e50958c56ed2d47a2cc
DIFF: https://github.com/llvm/llvm-project/commit/4b5fe9c42d94905a6f940e50958c56ed2d47a2cc.diff

LOG: [clang][Interp] Check floating results for NaNs

Differential Revision: https://reviews.llvm.org/D156506

Added: 
    

Modified: 
    clang/lib/AST/Interp/Interp.cpp
    clang/lib/AST/Interp/Interp.h
    clang/test/AST/Interp/floats.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index de6ab4a145a1422..67fc11d9c9bf9c1 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -495,13 +495,25 @@ bool CheckPotentialReinterpretCast(InterpState &S, CodePtr OpPC,
   return false;
 }
 
-bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status) {
+bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
+                      APFloat::opStatus Status) {
+  const SourceInfo &E = S.Current->getSource(OpPC);
+
+  // [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 (Result.isNan()) {
+    S.CCEDiag(E, diag::note_constexpr_float_arithmetic)
+        << /*NaN=*/true << S.Current->getRange(OpPC);
+    return S.noteUndefinedBehavior();
+  }
+
   // In a constant context, assume that any dynamic rounding mode or FP
   // exception state matches the default floating-point environment.
   if (S.inConstantContext())
     return true;
 
-  const SourceInfo &E = S.Current->getSource(OpPC);
   FPOptions FPO = E.asExpr()->getFPFeaturesInEffect(S.Ctx.getLangOpts());
 
   if ((Status & APFloat::opInexact) &&

diff  --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index d33c22ad60f9c02..b109f2bda17bfb1 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -172,7 +172,8 @@ bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
 
 /// Checks if the result of a floating-point operation is valid
 /// in the current context.
-bool CheckFloatResult(InterpState &S, CodePtr OpPC, APFloat::opStatus Status);
+bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,
+                      APFloat::opStatus Status);
 
 /// Interpreter entry point.
 bool Interpret(InterpState &S, APValue &Result);
@@ -304,7 +305,7 @@ inline bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
   Floating Result;
   auto Status = Floating::add(LHS, RHS, RM, &Result);
   S.Stk.push<Floating>(Result);
-  return CheckFloatResult(S, OpPC, Status);
+  return CheckFloatResult(S, OpPC, Result, Status);
 }
 
 template <PrimType Name, class T = typename PrimConv<Name>::T>
@@ -322,7 +323,7 @@ inline bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
   Floating Result;
   auto Status = Floating::sub(LHS, RHS, RM, &Result);
   S.Stk.push<Floating>(Result);
-  return CheckFloatResult(S, OpPC, Status);
+  return CheckFloatResult(S, OpPC, Result, Status);
 }
 
 template <PrimType Name, class T = typename PrimConv<Name>::T>
@@ -340,7 +341,7 @@ inline bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
   Floating Result;
   auto Status = Floating::mul(LHS, RHS, RM, &Result);
   S.Stk.push<Floating>(Result);
-  return CheckFloatResult(S, OpPC, Status);
+  return CheckFloatResult(S, OpPC, Result, Status);
 }
 /// 1) Pops the RHS from the stack.
 /// 2) Pops the LHS from the stack.
@@ -443,7 +444,7 @@ inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
   Floating Result;
   auto Status = Floating::div(LHS, RHS, RM, &Result);
   S.Stk.push<Floating>(Result);
-  return CheckFloatResult(S, OpPC, Status);
+  return CheckFloatResult(S, OpPC, Result, Status);
 }
 
 //===----------------------------------------------------------------------===//
@@ -622,7 +623,7 @@ bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
 
   Ptr.deref<Floating>() = Result;
 
-  return CheckFloatResult(S, OpPC, Status);
+  return CheckFloatResult(S, OpPC, Result, Status);
 }
 
 inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {
@@ -1525,7 +1526,7 @@ bool CastIntegralFloating(InterpState &S, CodePtr OpPC,
   auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);
   S.Stk.push<Floating>(Result);
 
-  return CheckFloatResult(S, OpPC, Status);
+  return CheckFloatResult(S, OpPC, Result, Status);
 }
 
 template <PrimType Name, class T = typename PrimConv<Name>::T>
@@ -1550,7 +1551,7 @@ bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) {
     }
 
     S.Stk.push<T>(T(Result));
-    return CheckFloatResult(S, OpPC, Status);
+    return CheckFloatResult(S, OpPC, F, Status);
   }
 }
 

diff  --git a/clang/test/AST/Interp/floats.cpp b/clang/test/AST/Interp/floats.cpp
index a3b058e1eafb399..e17167f5bf6dbbf 100644
--- a/clang/test/AST/Interp/floats.cpp
+++ b/clang/test/AST/Interp/floats.cpp
@@ -202,3 +202,18 @@ namespace Compare {
   static_assert(!(inf < nan), "");
   static_assert(!(inf > nan), "");
 }
+
+namespace nan {
+  constexpr double nan = __builtin_nan("");
+  static_assert(nan);
+
+  constexpr double D1 = 1 + nan; // ref-error {{must be initialized by a constant expression}} \
+                                 // ref-note {{produces a NaN}} \
+                                 // expected-error {{must be initialized by a constant expression}} \
+                                 // expected-note {{produces a NaN}}
+
+  constexpr double D2 = __builtin_inf() / __builtin_inf(); // ref-error {{must be initialized by a constant expression}} \
+                                                           // ref-note {{produces a NaN}} \
+                                                           // expected-error {{must be initialized by a constant expression}} \
+                                                           // expected-note {{produces a NaN}}
+}


        


More information about the cfe-commits mailing list