diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index de6ab4a145a14..67fc11d9c9bf9 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 d33c22ad60f9c..b109f2bda17bf 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(Result); - return CheckFloatResult(S, OpPC, Status); + return CheckFloatResult(S, OpPC, Result, Status); } template ::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(Result); - return CheckFloatResult(S, OpPC, Status); + return CheckFloatResult(S, OpPC, Result, Status); } template ::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(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(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() = 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(Result); - return CheckFloatResult(S, OpPC, Status); + return CheckFloatResult(S, OpPC, Result, Status); } template ::T> @@ -1550,7 +1551,7 @@ bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) { } S.Stk.push(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 a3b058e1eafb3..e17167f5bf6db 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}} +}