From 1e2a4ccb6237b6db9db7dc3fd11a94410ec9b0df Mon Sep 17 00:00:00 2001 From: Zahira Ammarguellat Date: Mon, 22 Jan 2024 11:38:30 -0800 Subject: [PATCH] [CLANG] Add warning when INF or NAN are used in a binary operation or as function argument in fast math mode. (#76873) Check for operations using INF or NaN when in ffast-math mode and generate a warning. --- clang/docs/ReleaseNotes.rst | 5 + .../clang/Basic/DiagnosticCommonKinds.td | 4 + clang/include/clang/Lex/Preprocessor.h | 9 + clang/include/clang/Sema/Sema.h | 7 +- clang/lib/Lex/Preprocessor.cpp | 5 + clang/lib/Sema/SemaChecking.cpp | 48 ++++- .../Sema/warn-infinity-nan-disabled-lnx.cpp | 176 +++++++++++++++++ .../Sema/warn-infinity-nan-disabled-win.cpp | 179 ++++++++++++++++++ 8 files changed, 425 insertions(+), 8 deletions(-) create mode 100644 clang/test/Sema/warn-infinity-nan-disabled-lnx.cpp create mode 100644 clang/test/Sema/warn-infinity-nan-disabled-win.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 5846503af3acdf..13e6c5e8db3ea9 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -596,6 +596,11 @@ Improvements to Clang's diagnostics - Clang now diagnoses narrowing conversions involving const references. (`#63151: `_). - Clang now diagnoses unexpanded packs within the template argument lists of function template specializations. +- The warning `-Wnan-infinity-disabled` is now emitted when ``INFINITY`` + or ``NAN`` are used in arithmetic operations or function arguments in + floating-point mode where ``INFINITY`` or ``NAN`` don't have the expected + values. + - Clang now diagnoses attempts to bind a bitfield to an NTTP of a reference type as erroneous converted constant expression and not as a reference to subobject. - Clang now diagnoses ``auto`` and ``decltype(auto)`` in declarations of conversion function template diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td index 5544dc88004d9a..b1bada65cb6b28 100644 --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -70,6 +70,10 @@ def warn_pragma_debug_missing_argument : Warning< def warn_pragma_debug_unexpected_argument : Warning< "unexpected argument to debug command">, InGroup; +def warn_fp_nan_inf_when_disabled : Warning< + "use of %select{infinity|NaN}0%select{| via a macro}1 is undefined behavior " + "due to the currently enabled floating-point options">, + InGroup>; } // Parse && Sema diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 4ec21a8b6be2c8..fed3c1b7703837 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -2835,6 +2835,13 @@ class Preprocessor { if (Identifier.getIdentifierInfo()->isRestrictExpansion() && !SourceMgr.isInMainFile(Identifier.getLocation())) emitRestrictExpansionWarning(Identifier); + + if (Identifier.getIdentifierInfo()->getName() == "INFINITY") + if (getLangOpts().NoHonorInfs) + emitRestrictInfNaNWarning(Identifier, 0); + if (Identifier.getIdentifierInfo()->getName() == "NAN") + if (getLangOpts().NoHonorNaNs) + emitRestrictInfNaNWarning(Identifier, 1); } static void processPathForFileMacro(SmallVectorImpl &Path, @@ -2850,6 +2857,8 @@ class Preprocessor { void emitMacroDeprecationWarning(const Token &Identifier) const; void emitRestrictExpansionWarning(const Token &Identifier) const; void emitFinalMacroWarning(const Token &Identifier, bool IsUndef) const; + void emitRestrictInfNaNWarning(const Token &Identifier, + unsigned DiagSelection) const; /// This boolean state keeps track if the current scanned token (by this PP) /// is in an "-Wunsafe-buffer-usage" opt-out region. Assuming PP scans a diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index d0f62afdf7bb16..1f1cbd11ff7358 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -13932,8 +13932,9 @@ class Sema final { bool SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall); bool SemaBuiltinVAStartARMMicrosoft(CallExpr *Call); - bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); - bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs); + bool SemaBuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID); + bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs, + unsigned BuiltinID); bool SemaBuiltinComplex(CallExpr *TheCall); bool SemaBuiltinVSX(CallExpr *TheCall); bool SemaBuiltinOSLogFormat(CallExpr *TheCall); @@ -14037,6 +14038,8 @@ class Sema final { SourceRange range, llvm::SmallBitVector &CheckedVarArgs); + void CheckInfNaNFunction(const CallExpr *Call, const FunctionDecl *FDecl); + void CheckAbsoluteValueFunction(const CallExpr *Call, const FunctionDecl *FDecl); diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 64f54c6fc6382f..7fdb5d4c0d7b82 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -1457,6 +1457,11 @@ void Preprocessor::emitRestrictExpansionWarning(const Token &Identifier) const { Diag(Info.Location, diag::note_pp_macro_annotation) << 1; } +void Preprocessor::emitRestrictInfNaNWarning(const Token &Identifier, + unsigned DiagSelection) const { + Diag(Identifier, diag::warn_fp_nan_inf_when_disabled) << DiagSelection << 1; +} + void Preprocessor::emitFinalMacroWarning(const Token &Identifier, bool IsUndef) const { const MacroAnnotations &A = diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 3e0d94e8176348..28f5667a1b6ba1 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2169,6 +2169,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, ICEArguments &= ~(1 << ArgNo); } + FPOptions FPO; switch (BuiltinID) { case Builtin::BI__builtin___CFStringMakeConstantString: // CFStringMakeConstantString is currently not implemented for GOFF (i.e., @@ -2245,15 +2246,15 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_islessequal: case Builtin::BI__builtin_islessgreater: case Builtin::BI__builtin_isunordered: - if (SemaBuiltinUnorderedCompare(TheCall)) + if (SemaBuiltinUnorderedCompare(TheCall, BuiltinID)) return ExprError(); break; case Builtin::BI__builtin_fpclassify: - if (SemaBuiltinFPClassification(TheCall, 6)) + if (SemaBuiltinFPClassification(TheCall, 6, BuiltinID)) return ExprError(); break; case Builtin::BI__builtin_isfpclass: - if (SemaBuiltinFPClassification(TheCall, 2)) + if (SemaBuiltinFPClassification(TheCall, 2, BuiltinID)) return ExprError(); break; case Builtin::BI__builtin_isfinite: @@ -2267,7 +2268,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_signbit: case Builtin::BI__builtin_signbitf: case Builtin::BI__builtin_signbitl: - if (SemaBuiltinFPClassification(TheCall, 1)) + if (SemaBuiltinFPClassification(TheCall, 1, BuiltinID)) return ExprError(); break; case Builtin::BI__builtin_shufflevector: @@ -7648,6 +7649,7 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, CheckAbsoluteValueFunction(TheCall, FDecl); CheckMaxUnsignedZero(TheCall, FDecl); + CheckInfNaNFunction(TheCall, FDecl); if (getLangOpts().ObjC) DiagnoseCStringFormatDirectiveInCFAPI(*this, FDecl, Args, NumArgs); @@ -9117,10 +9119,15 @@ bool Sema::SemaBuiltinVAStartARMMicrosoft(CallExpr *Call) { /// SemaBuiltinUnorderedCompare - Handle functions like __builtin_isgreater and /// friends. This is declared to take (...), so we have to check everything. -bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) { +bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID) { if (checkArgCount(*this, TheCall, 2)) return true; + if (BuiltinID == Builtin::BI__builtin_isunordered && + TheCall->getFPFeaturesInEffect(getLangOpts()).getNoHonorNaNs()) + Diag(TheCall->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled) + << 1 << 0 << TheCall->getSourceRange(); + ExprResult OrigArg0 = TheCall->getArg(0); ExprResult OrigArg1 = TheCall->getArg(1); @@ -9155,10 +9162,23 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) { /// SemaBuiltinSemaBuiltinFPClassification - Handle functions like /// __builtin_isnan and friends. This is declared to take (...), so we have /// to check everything. -bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { +bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs, + unsigned BuiltinID) { if (checkArgCount(*this, TheCall, NumArgs)) return true; + FPOptions FPO = TheCall->getFPFeaturesInEffect(getLangOpts()); + if (FPO.getNoHonorInfs() && (BuiltinID == Builtin::BI__builtin_isfinite || + BuiltinID == Builtin::BI__builtin_isinf || + BuiltinID == Builtin::BI__builtin_isinf_sign)) + Diag(TheCall->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled) + << 0 << 0 << TheCall->getSourceRange(); + + if (FPO.getNoHonorNaNs() && (BuiltinID == Builtin::BI__builtin_isnan || + BuiltinID == Builtin::BI__builtin_isunordered)) + Diag(TheCall->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled) + << 1 << 0 << TheCall->getSourceRange(); + bool IsFPClass = NumArgs == 2; // Find out position of floating-point argument. @@ -12905,6 +12925,22 @@ static bool IsStdFunction(const FunctionDecl *FDecl, return true; } +void Sema::CheckInfNaNFunction(const CallExpr *Call, + const FunctionDecl *FDecl) { + FPOptions FPO = Call->getFPFeaturesInEffect(getLangOpts()); + if ((IsStdFunction(FDecl, "isnan") || IsStdFunction(FDecl, "isunordered") || + (Call->getBuiltinCallee() == Builtin::BI__builtin_nanf)) && + FPO.getNoHonorNaNs()) + Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled) + << 1 << 0 << Call->getSourceRange(); + else if ((IsStdFunction(FDecl, "isinf") || + (IsStdFunction(FDecl, "isfinite") || + (FDecl->getIdentifier() && FDecl->getName() == "infinity"))) && + FPO.getNoHonorInfs()) + Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled) + << 0 << 0 << Call->getSourceRange(); +} + // Warn when using the wrong abs() function. void Sema::CheckAbsoluteValueFunction(const CallExpr *Call, const FunctionDecl *FDecl) { diff --git a/clang/test/Sema/warn-infinity-nan-disabled-lnx.cpp b/clang/test/Sema/warn-infinity-nan-disabled-lnx.cpp new file mode 100644 index 00000000000000..8a610fa0e737e1 --- /dev/null +++ b/clang/test/Sema/warn-infinity-nan-disabled-lnx.cpp @@ -0,0 +1,176 @@ +// RUN: %clang_cc1 -x c++ -verify=no-inf-no-nan -triple powerpc64le-unknown-unknown %s \ +// RUN: -menable-no-infs -menable-no-nans + +// RUN: %clang_cc1 -x c++ -verify=no-fast -triple powerpc64le-unknown-unknown %s + +// RUN: %clang_cc1 -x c++ -verify=no-inf -triple powerpc64le-unknown-unknown %s \ +// RUN: -menable-no-infs + +// RUN: %clang_cc1 -x c++ -verify=no-nan -triple powerpc64le-unknown-unknown %s \ +// RUN: -menable-no-nans + +// no-fast-no-diagnostics + +int isunorderedf (float x, float y); +extern "C++" { +namespace std __attribute__((__visibility__("default"))) { + bool + isinf(float __x); + bool + isinf(double __x); + bool + isinf(long double __x); + bool + isnan(float __x); + bool + isnan(double __x); + bool + isnan(long double __x); +bool + isfinite(float __x); + bool + isfinite(double __x); + bool + isfinte(long double __x); + bool + isunordered(float __x, float __y); + bool + isunordered(double __x, double __y); + bool + isunordered(long double __x, long double __y); +} // namespace ) +} + +#define NAN (__builtin_nanf("")) +#define INFINITY (__builtin_inff()) + +template +class numeric_limits { +public: + [[nodiscard]] static constexpr _Ty infinity() noexcept { + return _Ty(); + } +}; + +template <> +class numeric_limits { +public: + [[nodiscard]] static constexpr float infinity() noexcept { + return __builtin_huge_val(); + } +}; +template <> +class numeric_limits { +public: + [[nodiscard]] static constexpr double infinity() noexcept { + return __builtin_huge_val(); + } +}; + +int compareit(float a, float b) { + volatile int i, j, k, l, m, n, o, p; +// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} + i = a == INFINITY; + +// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} + j = INFINITY == a; + +// no-inf-no-nan-warning@+4 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+3 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+2 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+1 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} + i = a == NAN; + +// no-inf-no-nan-warning@+4 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+3 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+2 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+1 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} + j = NAN == a; + +// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} + j = INFINITY <= a; + +// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} + j = INFINITY < a; + +// no-inf-no-nan-warning@+4 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+3 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+2 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+1 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} + j = a > NAN; + +// no-inf-no-nan-warning@+4 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+3 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+2 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+1 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} + j = a >= NAN; + +// no-inf-no-nan-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} + k = std::isinf(a); + +// no-inf-no-nan-warning@+2 {{use of NaN is undefined behavior due to the currently enabled floating-point option}} +// no-nan-warning@+1 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} + l = std::isnan(a); + +// no-inf-no-nan-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} + o = std::isfinite(a); + +// no-inf-no-nan-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} + m = __builtin_isinf(a); + +// no-inf-no-nan-warning@+2 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+1 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} + n = __builtin_isnan(a); + +// no-inf-no-nan-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} + p = __builtin_isfinite(a); + + // These should NOT warn, since they are not using NaN or infinity. + j = a > 1.1; + j = b < 1.1; + j = a >= 1.1; + j = b <= 1.1; + j = isunorderedf(a, b); + +// no-inf-no-nan-warning@+4 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+3 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+2 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+1 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} + j = isunorderedf(a, NAN); + +// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} + j = isunorderedf(a, INFINITY); + +// no-inf-no-nan-warning@+6 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+5 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+4 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+3 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+2 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+1 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} + i = std::isunordered(a, NAN); + +// no-inf-no-nan-warning@+4 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+3 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+1 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} + i = std::isunordered(a, INFINITY); + +// no-inf-no-nan-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} + double y = i * numeric_limits::infinity(); + +// no-inf-no-nan-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} + j = numeric_limits::infinity(); + return 0; + +} diff --git a/clang/test/Sema/warn-infinity-nan-disabled-win.cpp b/clang/test/Sema/warn-infinity-nan-disabled-win.cpp new file mode 100644 index 00000000000000..19a575386e3293 --- /dev/null +++ b/clang/test/Sema/warn-infinity-nan-disabled-win.cpp @@ -0,0 +1,179 @@ +// Use of NAN macro will trigger a warning "infinity defined in macro" because +// on Windows the NAN macro is defined using INFINITY. See below. + +// RUN: %clang_cc1 -x c++ -verify=no-inf-no-nan -triple powerpc64le-unknown-unknown %s \ +// RUN: -menable-no-infs -menable-no-nans + +// RUN: %clang_cc1 -x c++ -verify=no-fast -triple powerpc64le-unknown-unknown %s + +// RUN: %clang_cc1 -x c++ -verify=no-inf -triple powerpc64le-unknown-unknown %s \ +// RUN: -menable-no-infs + +// RUN: %clang_cc1 -x c++ -verify=no-nan -triple powerpc64le-unknown-unknown %s \ +// RUN: -menable-no-nans + +// no-fast-no-diagnostics + +int isunorderedf (float x, float y); +extern "C++" { +namespace std __attribute__((__visibility__("default"))) { + bool + isinf(float __x); + bool + isinf(double __x); + bool + isinf(long double __x); + bool + isnan(float __x); + bool + isnan(double __x); + bool + isnan(long double __x); +bool + isfinite(float __x); + bool + isfinite(double __x); + bool + isfinte(long double __x); + bool + isunordered(float __x, float __y); + bool + isunordered(double __x, double __y); + bool + isunordered(long double __x, long double __y); +} // namespace ) +} + +#define INFINITY ((float)(1e+300 * 1e+300)) +#define NAN (-(float)(INFINITY * 0.0F)) + +template +class numeric_limits { +public: + [[nodiscard]] static constexpr _Ty infinity() noexcept { + return _Ty(); + } +}; + +template <> +class numeric_limits { +public: + [[nodiscard]] static constexpr float infinity() noexcept { + return __builtin_huge_val(); + } +}; +template <> +class numeric_limits { +public: + [[nodiscard]] static constexpr double infinity() noexcept { + return __builtin_huge_val(); + } +}; + +int compareit(float a, float b) { + volatile int i, j, k, l, m, n, o, p; +// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} + i = a == INFINITY; + +// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} + j = INFINITY == a; + +// no-inf-no-nan-warning@+4 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+3 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+1 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} + i = a == NAN; + +// no-inf-no-nan-warning@+4 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+3 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+1 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} + j = NAN == a; + +// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} + j = INFINITY <= a; + +// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} + j = INFINITY < a; + +// no-inf-no-nan-warning@+4 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+3 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+1 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} + j = a > NAN; + +// no-inf-no-nan-warning@+4 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+3 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+1 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} + j = a >= NAN; + +// no-inf-no-nan-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} + k = std::isinf(a); + +// no-inf-no-nan-warning@+2 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+1 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} + l = std::isnan(a); + +// no-inf-no-nan-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} + o = std::isfinite(a); + +// no-inf-no-nan-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} + m = __builtin_isinf(a); + +// no-inf-no-nan-warning@+2 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+1 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} + n = __builtin_isnan(a); + +// no-inf-no-nan-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} + p = __builtin_isfinite(a); + + // These should NOT warn, since they are not using NaN or infinity. + j = a > 1.1; + j = b < 1.1; + j = a >= 1.1; + j = b <= 1.1; + j = isunorderedf(a, b); + +// no-inf-no-nan-warning@+4 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point option}} +// no-inf-no-nan-warning@+3 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+1 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} + j = isunorderedf(a, NAN); + +// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} + j = isunorderedf(a, INFINITY); + +// no-inf-no-nan-warning@+6 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+5 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+4 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+3 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+2 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+1 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} + i = std::isunordered(a, NAN); + +// no-inf-no-nan-warning@+4 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+3 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-nan-warning@+1 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} + i = std::isunordered(a, INFINITY); + +// no-inf-no-nan-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} + double y = i * numeric_limits::infinity(); + +// no-inf-no-nan-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+1 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} + j = numeric_limits::infinity(); + return 0; + +}