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< 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/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/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 +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, "");