From e5992b686bb06dd53a4ff1e9586fa350d3ff43b5 Mon Sep 17 00:00:00 2001 From: Amr Hesham Date: Mon, 20 Jan 2025 22:21:48 +0100 Subject: [PATCH] [Clang] Fix warning for non std functions with name `infinity` (#123417) Fix reporting diagnostic for non std functions that has the name `infinity` Fixes: #123231 --- clang/docs/ReleaseNotes.rst | 2 + clang/lib/Sema/SemaChecking.cpp | 47 +++++++++++++------ .../Sema/warn-infinity-nan-disabled-lnx.cpp | 42 +++++++++++++++-- .../Sema/warn-infinity-nan-disabled-win.cpp | 43 +++++++++++++++-- 4 files changed, 111 insertions(+), 23 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index f6d5c346021d..d7456082e32d 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -798,6 +798,8 @@ Improvements to Clang's diagnostics } - Diagnose invalid declarators in the declaration of constructors and destructors (#GH121706). +- Fix false positives warning for non-std functions with name `infinity` (#123231). + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 881907ac311a..c41164a2f1af 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -8454,26 +8454,43 @@ static bool IsInfOrNanFunction(StringRef calleeName, MathCheck Check) { llvm_unreachable("unknown MathCheck"); } +static bool IsInfinityFunction(const FunctionDecl *FDecl) { + if (FDecl->getName() != "infinity") + return false; + + if (const CXXMethodDecl *MDecl = dyn_cast(FDecl)) { + const CXXRecordDecl *RDecl = MDecl->getParent(); + if (RDecl->getName() != "numeric_limits") + return false; + + if (const NamespaceDecl *NSDecl = + dyn_cast(RDecl->getDeclContext())) + return NSDecl->isStdNamespace(); + } + + return false; +} + void Sema::CheckInfNaNFunction(const CallExpr *Call, const FunctionDecl *FDecl) { + if (!FDecl->getIdentifier()) + return; + FPOptions FPO = Call->getFPFeaturesInEffect(getLangOpts()); - bool HasIdentifier = FDecl->getIdentifier() != nullptr; - bool IsNaNOrIsUnordered = - IsStdFunction(FDecl, "isnan") || IsStdFunction(FDecl, "isunordered"); - bool IsSpecialNaN = - HasIdentifier && IsInfOrNanFunction(FDecl->getName(), MathCheck::NaN); - if ((IsNaNOrIsUnordered || IsSpecialNaN) && FPO.getNoHonorNaNs()) { + if (FPO.getNoHonorNaNs() && + (IsStdFunction(FDecl, "isnan") || IsStdFunction(FDecl, "isunordered") || + IsInfOrNanFunction(FDecl->getName(), MathCheck::NaN))) { Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled) << 1 << 0 << Call->getSourceRange(); - } else { - bool IsInfOrIsFinite = - IsStdFunction(FDecl, "isinf") || IsStdFunction(FDecl, "isfinite"); - bool IsInfinityOrIsSpecialInf = - HasIdentifier && ((FDecl->getName() == "infinity") || - IsInfOrNanFunction(FDecl->getName(), MathCheck::Inf)); - if ((IsInfOrIsFinite || IsInfinityOrIsSpecialInf) && FPO.getNoHonorInfs()) - Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled) - << 0 << 0 << Call->getSourceRange(); + return; + } + + if (FPO.getNoHonorInfs() && + (IsStdFunction(FDecl, "isinf") || IsStdFunction(FDecl, "isfinite") || + IsInfinityFunction(FDecl) || + IsInfOrNanFunction(FDecl->getName(), MathCheck::Inf))) { + Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled) + << 0 << 0 << Call->getSourceRange(); } } diff --git a/clang/test/Sema/warn-infinity-nan-disabled-lnx.cpp b/clang/test/Sema/warn-infinity-nan-disabled-lnx.cpp index 357c9e5b6410..4f46b777c887 100644 --- a/clang/test/Sema/warn-infinity-nan-disabled-lnx.cpp +++ b/clang/test/Sema/warn-infinity-nan-disabled-lnx.cpp @@ -45,24 +45,48 @@ namespace std __attribute__((__visibility__("default"))) { isnan(double __x); bool isnan(long double __x); -bool + bool isfinite(float __x); bool isfinite(double __x); bool isfinte(long double __x); - bool + bool isunordered(float __x, float __y); bool isunordered(double __x, double __y); bool isunordered(long double __x, long double __y); + +template +class numeric_limits { +public: + [[nodiscard]] static constexpr _Ty infinity() noexcept { + return _Ty(); + } +}; } // namespace ) } #define NAN (__builtin_nanf("")) #define INFINITY (__builtin_inff()) +template <> +class std::numeric_limits { +public: + [[nodiscard]] static constexpr float infinity() noexcept { + return __builtin_huge_val(); + } +}; + +template <> +class std::numeric_limits { +public: + [[nodiscard]] static constexpr double infinity() noexcept { + return __builtin_huge_val(); + } +}; + template class numeric_limits { public: @@ -78,6 +102,7 @@ public: return __builtin_huge_val(); } }; + template <> class numeric_limits { public: @@ -86,6 +111,8 @@ public: } }; +double infinity() { return 0; } + int compareit(float a, float b) { volatile int i, j, k, l, m, n, o, p; // no-inf-no-nan-warning@+4 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} @@ -225,11 +252,18 @@ int compareit(float a, float b) { // 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(); + double y = i * std::numeric_limits::infinity(); + + y = i * numeric_limits::infinity(); // expected-no-diagnostics // 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(); + j = std::numeric_limits::infinity(); + + j = numeric_limits::infinity(); // expected-no-diagnostics + + y = infinity(); // expected-no-diagnostics + return 0; } diff --git a/clang/test/Sema/warn-infinity-nan-disabled-win.cpp b/clang/test/Sema/warn-infinity-nan-disabled-win.cpp index ee4eb33a16e4..655024f5909b 100644 --- a/clang/test/Sema/warn-infinity-nan-disabled-win.cpp +++ b/clang/test/Sema/warn-infinity-nan-disabled-win.cpp @@ -48,24 +48,49 @@ namespace std __attribute__((__visibility__("default"))) { isnan(double __x); bool isnan(long double __x); -bool + bool isfinite(float __x); bool isfinite(double __x); bool isfinte(long double __x); - bool + bool isunordered(float __x, float __y); bool isunordered(double __x, double __y); bool isunordered(long double __x, long double __y); + +template +class numeric_limits { +public: + [[nodiscard]] static constexpr _Ty infinity() noexcept { + return _Ty(); + } +}; + } // namespace ) } #define INFINITY ((float)(1e+300 * 1e+300)) #define NAN (-(float)(INFINITY * 0.0F)) +template <> +class std::numeric_limits { +public: + [[nodiscard]] static constexpr float infinity() noexcept { + return __builtin_huge_val(); + } +}; + +template <> +class std::numeric_limits { +public: + [[nodiscard]] static constexpr double infinity() noexcept { + return __builtin_huge_val(); + } +}; + template class numeric_limits { public: @@ -81,6 +106,7 @@ public: return __builtin_huge_val(); } }; + template <> class numeric_limits { public: @@ -89,6 +115,8 @@ public: } }; +double infinity() { return 0; } + 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}} @@ -216,11 +244,18 @@ int compareit(float a, float b) { // 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(); + double y = i * std::numeric_limits::infinity(); + + y = i * numeric_limits::infinity(); // expected-no-diagnostics // 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(); + j = std::numeric_limits::infinity(); + + j = numeric_limits::infinity(); // expected-no-diagnostics + + y = infinity(); // expected-no-diagnostics + return 0; }