[llvm] [clang] [clang-tools-extra] [CLANG] Add warning when INF or NAN are used in a binary operation or as function argument in fast math mode. (PR #76873)

Zahira Ammarguellat via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 17 12:24:47 PST 2024


https://github.com/zahiraam updated https://github.com/llvm/llvm-project/pull/76873

>From 7dbaf037b6b2196cee7c0c837e0a89ce3c2556ed Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Wed, 3 Jan 2024 14:37:17 -0800
Subject: [PATCH 1/6] [CLANG] Add warning when comparing to INF or NAN in fast
 math mode.

---
 .../clang/Basic/DiagnosticSemaKinds.td        |   3 +
 clang/include/clang/Sema/Sema.h               |   4 +
 clang/lib/Sema/SemaChecking.cpp               |  65 +++++++
 clang/lib/Sema/SemaExpr.cpp                   |   7 +-
 clang/test/Sema/warn-fp-fast-compare.cpp      | 171 ++++++++++++++++++
 5 files changed, 248 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/Sema/warn-fp-fast-compare.cpp

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index e54f969c19039dd..1b75ae8f678b68d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6771,6 +6771,9 @@ def warn_pointer_sub_null_ptr : Warning<
 def warn_floatingpoint_eq : Warning<
   "comparing floating point with == or != is unsafe">,
   InGroup<DiagGroup<"float-equal">>, DefaultIgnore;
+def warn_fast_floatingpoint_eq : Warning<
+  "explicit comparison with %0 in fast floating point mode">,
+  InGroup<TautologicalConstantCompare>;
 
 def err_setting_eval_method_used_in_unsafe_context : Error <
   "%select{'#pragma clang fp eval_method'|option 'ffp-eval-method'}0 cannot be used with "
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 5e3b57ea33220b4..6125e7ebb6b48a2 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13998,6 +13998,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);
 
@@ -14024,6 +14026,8 @@ class Sema final {
 public:
   void CheckFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS,
                             BinaryOperatorKind Opcode);
+  void CheckInfNaNFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS,
+                                  BinaryOperatorKind Opcode);
 
 private:
   void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation());
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 3168d38dd66c36e..2e9f61f40b795b6 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,6 +2246,11 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
   case Builtin::BI__builtin_islessequal:
   case Builtin::BI__builtin_islessgreater:
   case Builtin::BI__builtin_isunordered:
+    if (BuiltinID == Builtin::BI__builtin_isunordered) {
+      if (TheCall->getFPFeaturesInEffect(getLangOpts()).getNoHonorNaNs())
+        Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
+            << "NaN" << TheCall->getSourceRange();
+    }
     if (SemaBuiltinUnorderedCompare(TheCall))
       return ExprError();
     break;
@@ -2267,6 +2273,16 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
   case Builtin::BI__builtin_signbit:
   case Builtin::BI__builtin_signbitf:
   case Builtin::BI__builtin_signbitl:
+    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_fast_floatingpoint_eq)
+          << "infinity" << TheCall->getSourceRange();
+    if (FPO.getNoHonorNaNs() && (BuiltinID == Builtin::BI__builtin_isnan ||
+                                 BuiltinID == Builtin::BI__builtin_isunordered))
+      Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
+          << "NaN" << TheCall->getSourceRange();
     if (SemaBuiltinFPClassification(TheCall, 1))
       return ExprError();
     break;
@@ -7621,6 +7637,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);
@@ -12878,6 +12895,23 @@ static bool IsStdFunction(const FunctionDecl *FDecl,
   return true;
 }
 
+void Sema::CheckInfNaNFunction(const CallExpr *Call,
+                               const FunctionDecl *FDecl) {
+  if (Call->getNumArgs() != 1 && Call->getNumArgs() != 2)
+    return;
+
+  FPOptions FPO = Call->getFPFeaturesInEffect(getLangOpts());
+  if ((IsStdFunction(FDecl, "isnan") || IsStdFunction(FDecl, "isunordered")) &&
+      FPO.getNoHonorNaNs())
+    Diag(Call->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
+        << "NaN" << Call->getSourceRange();
+  else if ((IsStdFunction(FDecl, "isinf") ||
+            (IsStdFunction(FDecl, "isfinite"))) &&
+           FPO.getNoHonorInfs())
+    Diag(Call->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
+        << "infinity" << Call->getSourceRange();
+}
+
 // Warn when using the wrong abs() function.
 void Sema::CheckAbsoluteValueFunction(const CallExpr *Call,
                                       const FunctionDecl *FDecl) {
@@ -13846,6 +13880,37 @@ Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType,
     CheckPPCMMAType(RetValExp->getType(), ReturnLoc);
 }
 
+/// Diagnose comparison to NAN or INFINITY in fast math modes.
+/// The comparison to NaN or INFINITY is always false in
+/// fast modes: float evaluation will not result in inf or nan.
+void Sema::CheckInfNaNFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS,
+                                      BinaryOperatorKind Opcode) {
+  Expr *LeftExprSansParen = LHS->IgnoreParenImpCasts();
+  Expr *RightExprSansParen = RHS->IgnoreParenImpCasts();
+
+  FPOptions FPO = LHS->getFPFeaturesInEffect(getLangOpts());
+  bool NoHonorNaNs = FPO.getNoHonorNaNs();
+  bool NoHonorInfs = FPO.getNoHonorInfs();
+  llvm::APFloat Value(0.0);
+  bool IsConstant;
+  IsConstant = !LHS->isValueDependent() &&
+               LeftExprSansParen->EvaluateAsFloat(Value, Context,
+                                                  Expr::SE_AllowSideEffects);
+  if (IsConstant &&
+      ((NoHonorNaNs && Value.isNaN()) || (NoHonorInfs && Value.isInfinity())))
+    Diag(Loc, diag::warn_fast_floatingpoint_eq)
+        << (Value.isNaN() ? "NaN" : "infinity") << LHS->getSourceRange()
+        << RHS->getSourceRange();
+  IsConstant = !RHS->isValueDependent() &&
+               RightExprSansParen->EvaluateAsFloat(Value, Context,
+                                                   Expr::SE_AllowSideEffects);
+  if (IsConstant &&
+      ((NoHonorNaNs && Value.isNaN()) || (NoHonorInfs && Value.isInfinity())))
+    Diag(Loc, diag::warn_fast_floatingpoint_eq)
+        << (Value.isNaN() ? "NaN" : "infinity") << LHS->getSourceRange()
+        << RHS->getSourceRange();
+}
+
 /// Check for comparisons of floating-point values using == and !=. Issue a
 /// warning if the comparison is not likely to do what the programmer intended.
 void Sema::CheckFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS,
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 960f513d1111b2c..005ddfa882195d5 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -13044,9 +13044,12 @@ static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS,
   if (Type->isAnyComplexType() && BinaryOperator::isRelationalOp(Opc))
     return S.InvalidOperands(Loc, LHS, RHS);
 
-  // Check for comparisons of floating point operands using != and ==.
-  if (Type->hasFloatingRepresentation())
+  if (Type->hasFloatingRepresentation()) {
+    // Check for comparisons to NAN or INFINITY in fast math mode.
+    S.CheckInfNaNFloatComparison(Loc, LHS.get(), RHS.get(), Opc);
+    // Check for comparisons of floating point operands using != and ==.
     S.CheckFloatComparison(Loc, LHS.get(), RHS.get(), Opc);
+  }
 
   // The result of comparisons is 'bool' in C++, 'int' in C.
   return S.Context.getLogicalOperationType();
diff --git a/clang/test/Sema/warn-fp-fast-compare.cpp b/clang/test/Sema/warn-fp-fast-compare.cpp
new file mode 100644
index 000000000000000..07eeaf0eeab1257
--- /dev/null
+++ b/clang/test/Sema/warn-fp-fast-compare.cpp
@@ -0,0 +1,171 @@
+// RUN: %clang_cc1 -x c++ -verify -triple powerpc64le-unknown-unknown %s \
+// RUN: -menable-no-infs -menable-no-nans  -DFAST=1
+
+// RUN: %clang_cc1 -x c++ -verify -triple powerpc64le-unknown-unknown %s \
+// RUN: -DNOFAST=1
+
+// RUN: %clang_cc1 -x c++ -verify -triple powerpc64le-unknown-unknown %s \
+// RUN: -menable-no-infs -DNO_INFS=1
+
+// RUN: %clang_cc1 -x c++ -verify -triple powerpc64le-unknown-unknown %s \
+// RUN: -menable-no-nans -DNO_NANS=1
+
+int isunorderedf (float x, float y);
+#if NOFAST
+// expected-no-diagnostics
+#endif
+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())
+
+int compareit(float a, float b) {
+  volatile int i, j, k, l, m, n, o, p;
+#if FAST
+// expected-warning at +5 {{explicit comparison with infinity in fast floating point mode}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{explicit comparison with infinity in fast floating point mode}}
+#endif
+  i = a == INFINITY;
+#if FAST
+// expected-warning at +5 {{explicit comparison with infinity in fast floating point mode}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{explicit comparison with infinity in fast floating point mode}}
+#endif
+  j = INFINITY == a;
+#if FAST
+// expected-warning at +5 {{explicit comparison with NaN in fast floating point mode}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{explicit comparison with NaN in fast floating point mode}}
+#endif
+  i = a == NAN;
+#if FAST
+// expected-warning at +5 {{explicit comparison with NaN in fast floating point mode}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{explicit comparison with NaN in fast floating point mode}}
+#endif
+  j = NAN == a;
+#if FAST
+// expected-warning at +5 {{explicit comparison with infinity in fast floating point mode}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{explicit comparison with infinity in fast floating point mode}}
+#endif
+  j = INFINITY <= a;
+#if FAST
+// expected-warning at +5 {{explicit comparison with infinity in fast floating point mode}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{explicit comparison with infinity in fast floating point mode}}
+#endif
+  j = INFINITY < a;
+#if FAST
+// expected-warning at +5 {{explicit comparison with NaN in fast floating point mode}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{explicit comparison with NaN in fast floating point mode}}
+#endif
+  j = a > NAN;
+#if FAST
+// expected-warning at +5 {{explicit comparison with NaN in fast floating point mode}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{explicit comparison with NaN in fast floating point mode}}
+#endif
+  j = a >= NAN;
+#if FAST
+// expected-warning at +5 {{explicit comparison with infinity in fast floating point mode}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{explicit comparison with infinity in fast floating point mode}}
+#endif
+k = std::isinf(a);
+#if FAST
+// expected-warning at +5 {{explicit comparison with NaN in fast floating point mode}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{explicit comparison with NaN in fast floating point mode}}
+#endif
+  l = std::isnan(a);
+#if FAST
+// expected-warning at +5 {{explicit comparison with infinity in fast floating point mode}}
+#endif
+#if NO_INFS
+//expected-warning at +2 {{explicit comparison with infinity in fast floating point mode}}
+#endif
+  o = std::isfinite(a);
+#if FAST
+// expected-warning at +5 {{explicit comparison with infinity in fast floating point mode}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{explicit comparison with infinity in fast floating point mode}}
+#endif
+  m = __builtin_isinf(a);
+#if FAST
+// expected-warning at +5 {{explicit comparison with NaN in fast floating point mode}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{explicit comparison with NaN in fast floating point mode}}
+#endif
+  n = __builtin_isnan(a);
+#if FAST
+//expected-warning at +5 {{explicit comparison with infinity in fast floating point mode}}
+#endif
+#if NO_INFS
+//expected-warning at +2 {{explicit comparison with infinity in fast floating point mode}}
+#endif
+  p = __builtin_isfinite(a);
+
+  // These should NOT warn, since they are not comparing with NaN or infinity.
+  j = a > 1.1;
+  j = b < 1.1;
+  j = a >= 1.1;
+  j = b <= 1.1;
+  j = isunorderedf(a, NAN);
+  j = isunorderedf(a, INFINITY);
+#if FAST
+// expected-warning at +5 {{explicit comparison with NaN in fast floating point mode}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{explicit comparison with NaN in fast floating point mode}}
+#endif
+  i = std::isunordered(a, NAN);
+#if FAST
+// expected-warning at +5 {{explicit comparison with NaN in fast floating point mode}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{explicit comparison with NaN in fast floating point mode}}
+#endif
+  i = std::isunordered(a, INFINITY);
+  return 0;
+}  

>From f4aa37980d861617719b3f027f69e652c0502515 Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Fri, 5 Jan 2024 13:54:42 -0800
Subject: [PATCH 2/6] Addressed review comments.

---
 .../clang/Basic/DiagnosticSemaKinds.td        |   2 +-
 clang/include/clang/Sema/Sema.h               |   5 +-
 clang/lib/Sema/SemaChecking.cpp               |  73 ++++-----
 clang/test/Sema/warn-fp-fast-compare.cpp      | 138 ++++++++++++++----
 4 files changed, 148 insertions(+), 70 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 1b75ae8f678b68d..d19be567a1bf66c 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6772,7 +6772,7 @@ def warn_floatingpoint_eq : Warning<
   "comparing floating point with == or != is unsafe">,
   InGroup<DiagGroup<"float-equal">>, DefaultIgnore;
 def warn_fast_floatingpoint_eq : Warning<
-  "explicit comparison with %0 in fast floating point mode">,
+  "explicit comparison with %0 when the program is assumed to not use or produce %0">,
   InGroup<TautologicalConstantCompare>;
 
 def err_setting_eval_method_used_in_unsafe_context : Error <
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6125e7ebb6b48a2..b19ce6312e83bc8 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -13893,8 +13893,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);
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 2e9f61f40b795b6..2c4d628ab160d22 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2246,20 +2246,15 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
   case Builtin::BI__builtin_islessequal:
   case Builtin::BI__builtin_islessgreater:
   case Builtin::BI__builtin_isunordered:
-    if (BuiltinID == Builtin::BI__builtin_isunordered) {
-      if (TheCall->getFPFeaturesInEffect(getLangOpts()).getNoHonorNaNs())
-        Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
-            << "NaN" << TheCall->getSourceRange();
-    }
-    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:
@@ -2273,17 +2268,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
   case Builtin::BI__builtin_signbit:
   case Builtin::BI__builtin_signbitf:
   case Builtin::BI__builtin_signbitl:
-    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_fast_floatingpoint_eq)
-          << "infinity" << TheCall->getSourceRange();
-    if (FPO.getNoHonorNaNs() && (BuiltinID == Builtin::BI__builtin_isnan ||
-                                 BuiltinID == Builtin::BI__builtin_isunordered))
-      Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
-          << "NaN" << TheCall->getSourceRange();
-    if (SemaBuiltinFPClassification(TheCall, 1))
+    if (SemaBuiltinFPClassification(TheCall, 1, BuiltinID))
       return ExprError();
     break;
   case Builtin::BI__builtin_shufflevector:
@@ -9107,10 +9092,16 @@ 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) {
+    if (TheCall->getFPFeaturesInEffect(getLangOpts()).getNoHonorNaNs())
+      Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
+          << "NaN" << TheCall->getSourceRange();
+  }
+
   ExprResult OrigArg0 = TheCall->getArg(0);
   ExprResult OrigArg1 = TheCall->getArg(1);
 
@@ -9145,10 +9136,22 @@ 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_fast_floatingpoint_eq)
+        << "infinity" << TheCall->getSourceRange();
+  if (FPO.getNoHonorNaNs() && (BuiltinID == Builtin::BI__builtin_isnan ||
+                               BuiltinID == Builtin::BI__builtin_isunordered))
+    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
+        << "NaN" << TheCall->getSourceRange();
+
   bool IsFPClass = NumArgs == 2;
 
   // Find out position of floating-point argument.
@@ -12897,16 +12900,15 @@ static bool IsStdFunction(const FunctionDecl *FDecl,
 
 void Sema::CheckInfNaNFunction(const CallExpr *Call,
                                const FunctionDecl *FDecl) {
-  if (Call->getNumArgs() != 1 && Call->getNumArgs() != 2)
-    return;
-
   FPOptions FPO = Call->getFPFeaturesInEffect(getLangOpts());
-  if ((IsStdFunction(FDecl, "isnan") || IsStdFunction(FDecl, "isunordered")) &&
+  if ((IsStdFunction(FDecl, "isnan") || IsStdFunction(FDecl, "isunordered") ||
+       (Call->getBuiltinCallee() == Builtin::BI__builtin_nanf)) &&
       FPO.getNoHonorNaNs())
     Diag(Call->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
         << "NaN" << Call->getSourceRange();
   else if ((IsStdFunction(FDecl, "isinf") ||
-            (IsStdFunction(FDecl, "isfinite"))) &&
+            (IsStdFunction(FDecl, "isfinite") ||
+             (Call->getBuiltinCallee() == Builtin::BI__builtin_inff))) &&
            FPO.getNoHonorInfs())
     Diag(Call->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
         << "infinity" << Call->getSourceRange();
@@ -13892,19 +13894,20 @@ void Sema::CheckInfNaNFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS,
   bool NoHonorNaNs = FPO.getNoHonorNaNs();
   bool NoHonorInfs = FPO.getNoHonorInfs();
   llvm::APFloat Value(0.0);
-  bool IsConstant;
-  IsConstant = !LHS->isValueDependent() &&
-               LeftExprSansParen->EvaluateAsFloat(Value, Context,
-                                                  Expr::SE_AllowSideEffects);
-  if (IsConstant &&
+
+  auto IsConstant = [&Value](Expr *E, Expr *ESansParen, ASTContext &Context) {
+    return !E->isValueDependent() &&
+           ESansParen->EvaluateAsFloat(Value, Context,
+                                       Expr::SE_AllowSideEffects);
+  };
+
+  if (IsConstant(LHS, LeftExprSansParen, Context) &&
       ((NoHonorNaNs && Value.isNaN()) || (NoHonorInfs && Value.isInfinity())))
     Diag(Loc, diag::warn_fast_floatingpoint_eq)
         << (Value.isNaN() ? "NaN" : "infinity") << LHS->getSourceRange()
         << RHS->getSourceRange();
-  IsConstant = !RHS->isValueDependent() &&
-               RightExprSansParen->EvaluateAsFloat(Value, Context,
-                                                   Expr::SE_AllowSideEffects);
-  if (IsConstant &&
+
+  if (IsConstant(RHS, RightExprSansParen, Context) &&
       ((NoHonorNaNs && Value.isNaN()) || (NoHonorInfs && Value.isInfinity())))
     Diag(Loc, diag::warn_fast_floatingpoint_eq)
         << (Value.isNaN() ? "NaN" : "infinity") << LHS->getSourceRange()
diff --git a/clang/test/Sema/warn-fp-fast-compare.cpp b/clang/test/Sema/warn-fp-fast-compare.cpp
index 07eeaf0eeab1257..df8c8145f538ad6 100644
--- a/clang/test/Sema/warn-fp-fast-compare.cpp
+++ b/clang/test/Sema/warn-fp-fast-compare.cpp
@@ -48,101 +48,149 @@ bool
 int compareit(float a, float b) {
   volatile int i, j, k, l, m, n, o, p;
 #if FAST
-// expected-warning at +5 {{explicit comparison with infinity in fast floating point mode}}
+// expected-warning at +11 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if FAST
+// expected-warning at +8 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if NO_INFS
+// expected-warning at +5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity in fast floating point mode}}
+// expected-warning at +2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
 #endif
   i = a == INFINITY;
 #if FAST
-// expected-warning at +5 {{explicit comparison with infinity in fast floating point mode}}
+// expected-warning at +11 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if FAST
+// expected-warning at +8 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity in fast floating point mode}}
+// expected-warning at +5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
 #endif
   j = INFINITY == a;
 #if FAST
-// expected-warning at +5 {{explicit comparison with NaN in fast floating point mode}}
+// expected-warning at +11 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if FAST
+// expected-warning at +8 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{explicit comparison with NaN in fast floating point mode}}
+// expected-warning at +5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
 #endif
   i = a == NAN;
 #if FAST
-// expected-warning at +5 {{explicit comparison with NaN in fast floating point mode}}
+// expected-warning at +11 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if FAST
+// expected-warning at +8 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_NANS
+// expected-warning at +5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{explicit comparison with NaN in fast floating point mode}}
+// expected-warning at +2 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
 #endif
   j = NAN == a;
 #if FAST
-// expected-warning at +5 {{explicit comparison with infinity in fast floating point mode}}
+// expected-warning at +11 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if FAST
+// expected-warning at +8 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if NO_INFS
+// expected-warning at +5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity in fast floating point mode}}
+// expected-warning at +2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
 #endif
   j = INFINITY <= a;
 #if FAST
-// expected-warning at +5 {{explicit comparison with infinity in fast floating point mode}}
+// expected-warning at +11 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if FAST
+// expected-warning at +8 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity in fast floating point mode}}
+  // expected-warning at +5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
 #endif
   j = INFINITY < a;
 #if FAST
-// expected-warning at +5 {{explicit comparison with NaN in fast floating point mode}}
+// expected-warning at +11 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if FAST
+// expected-warning at +8 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_NANS
+// expected-warning at +5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{explicit comparison with NaN in fast floating point mode}}
+  // expected-warning at +2 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
 #endif
   j = a > NAN;
 #if FAST
-// expected-warning at +5 {{explicit comparison with NaN in fast floating point mode}}
+// expected-warning at +11 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if FAST
+// expected-warning at +8 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_NANS
+// expected-warning at +5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{explicit comparison with NaN in fast floating point mode}}
+// expected-warning at +2 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
 #endif
   j = a >= NAN;
 #if FAST
-// expected-warning at +5 {{explicit comparison with infinity in fast floating point mode}}
+// expected-warning at +5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity in fast floating point mode}}
+// expected-warning at +2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
 #endif
 k = std::isinf(a);
 #if FAST
-// expected-warning at +5 {{explicit comparison with NaN in fast floating point mode}}
+// expected-warning at +5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{explicit comparison with NaN in fast floating point mode}}
+// expected-warning at +2 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
 #endif
   l = std::isnan(a);
 #if FAST
-// expected-warning at +5 {{explicit comparison with infinity in fast floating point mode}}
+// expected-warning at +5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
 #endif
 #if NO_INFS
-//expected-warning at +2 {{explicit comparison with infinity in fast floating point mode}}
+// expected-warning at +2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
 #endif
   o = std::isfinite(a);
 #if FAST
-// expected-warning at +5 {{explicit comparison with infinity in fast floating point mode}}
+// expected-warning at +5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity in fast floating point mode}}
+// expected-warning at +2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
 #endif
   m = __builtin_isinf(a);
 #if FAST
-// expected-warning at +5 {{explicit comparison with NaN in fast floating point mode}}
+// expected-warning at +5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{explicit comparison with NaN in fast floating point mode}}
+// expected-warning at +2 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
 #endif
   n = __builtin_isnan(a);
 #if FAST
-//expected-warning at +5 {{explicit comparison with infinity in fast floating point mode}}
+// expected-warning at +5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
 #endif
 #if NO_INFS
-//expected-warning at +2 {{explicit comparison with infinity in fast floating point mode}}
+// expected-warning at +2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
 #endif
   p = __builtin_isfinite(a);
 
@@ -151,20 +199,46 @@ k = std::isinf(a);
   j = b < 1.1;
   j = a >= 1.1;
   j = b <= 1.1;
+  j = isunorderedf(a, b);
+
+#if FAST
+// expected-warning at +5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
   j = isunorderedf(a, NAN);
+#if FAST
+// expected-warning at +5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
   j = isunorderedf(a, INFINITY);
 #if FAST
-// expected-warning at +5 {{explicit comparison with NaN in fast floating point mode}}
+// expected-warning at +11 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if FAST
+// expected-warning at +8 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{explicit comparison with NaN in fast floating point mode}}
+// expected-warning at +5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
 #endif
   i = std::isunordered(a, NAN);
 #if FAST
-// expected-warning at +5 {{explicit comparison with NaN in fast floating point mode}}
+// expected-warning at +11 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if FAST
+// expected-warning at +8 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{explicit comparison with NaN in fast floating point mode}}
+// expected-warning at +5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
 #endif
   i = std::isunordered(a, INFINITY);
   return 0;

>From 948ace771f6e696c8246789f11248ee0d237a623 Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Thu, 11 Jan 2024 12:47:03 -0800
Subject: [PATCH 3/6] Addressed review comments.

---
 .../clang/Basic/DiagnosticSemaKinds.td        |   4 +-
 clang/lib/Sema/SemaChecking.cpp               |  29 ++--
 clang/test/Sema/warn-fp-fast-compare.cpp      | 151 +++++++++++-------
 3 files changed, 109 insertions(+), 75 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index d19be567a1bf66c..e1164ef34a1b6c6 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6772,7 +6772,9 @@ def warn_floatingpoint_eq : Warning<
   "comparing floating point with == or != is unsafe">,
   InGroup<DiagGroup<"float-equal">>, DefaultIgnore;
 def warn_fast_floatingpoint_eq : Warning<
-  "explicit comparison with %0 when the program is assumed to not use or produce %0">,
+  "use of %select{infinity|NaN}0 will always be 'false' because "
+  "%select{infinity|NaN}0 will not be produced according to the currently "
+  "enabled floating-point options">,
   InGroup<TautologicalConstantCompare>;
 
 def err_setting_eval_method_used_in_unsafe_context : Error <
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 2c4d628ab160d22..027cfac1c5a641d 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -9096,11 +9096,9 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID) {
   if (checkArgCount(*this, TheCall, 2))
     return true;
 
-  if (BuiltinID == Builtin::BI__builtin_isunordered) {
-    if (TheCall->getFPFeaturesInEffect(getLangOpts()).getNoHonorNaNs())
-      Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
-          << "NaN" << TheCall->getSourceRange();
-  }
+  if (BuiltinID == Builtin::BI__builtin_isunordered &&
+      TheCall->getFPFeaturesInEffect(getLangOpts()).getNoHonorNaNs())
+    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq) << 1 << 1;
 
   ExprResult OrigArg0 = TheCall->getArg(0);
   ExprResult OrigArg1 = TheCall->getArg(1);
@@ -9145,12 +9143,10 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs,
   if (FPO.getNoHonorInfs() && (BuiltinID == Builtin::BI__builtin_isfinite ||
                                BuiltinID == Builtin::BI__builtin_isinf ||
                                BuiltinID == Builtin::BI__builtin_isinf_sign))
-    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
-        << "infinity" << TheCall->getSourceRange();
+    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq) << 0 << 0;
   if (FPO.getNoHonorNaNs() && (BuiltinID == Builtin::BI__builtin_isnan ||
                                BuiltinID == Builtin::BI__builtin_isunordered))
-    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
-        << "NaN" << TheCall->getSourceRange();
+    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq) << 1 << 1;
 
   bool IsFPClass = NumArgs == 2;
 
@@ -12904,14 +12900,13 @@ void Sema::CheckInfNaNFunction(const CallExpr *Call,
   if ((IsStdFunction(FDecl, "isnan") || IsStdFunction(FDecl, "isunordered") ||
        (Call->getBuiltinCallee() == Builtin::BI__builtin_nanf)) &&
       FPO.getNoHonorNaNs())
-    Diag(Call->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
-        << "NaN" << Call->getSourceRange();
+    Diag(Call->getBeginLoc(), diag::warn_fast_floatingpoint_eq) << 1 << 1;
   else if ((IsStdFunction(FDecl, "isinf") ||
             (IsStdFunction(FDecl, "isfinite") ||
-             (Call->getBuiltinCallee() == Builtin::BI__builtin_inff))) &&
+             (Call->getBuiltinCallee() == Builtin::BI__builtin_inff)) ||
+            (FDecl->getIdentifier() && FDecl->getName() == "infinity")) &&
            FPO.getNoHonorInfs())
-    Diag(Call->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
-        << "infinity" << Call->getSourceRange();
+    Diag(Call->getBeginLoc(), diag::warn_fast_floatingpoint_eq) << 0 << 0;
 }
 
 // Warn when using the wrong abs() function.
@@ -13904,14 +13899,12 @@ void Sema::CheckInfNaNFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS,
   if (IsConstant(LHS, LeftExprSansParen, Context) &&
       ((NoHonorNaNs && Value.isNaN()) || (NoHonorInfs && Value.isInfinity())))
     Diag(Loc, diag::warn_fast_floatingpoint_eq)
-        << (Value.isNaN() ? "NaN" : "infinity") << LHS->getSourceRange()
-        << RHS->getSourceRange();
+        << (Value.isNaN() ? 1 : 0) << (Value.isNaN() ? 1 : 0);
 
   if (IsConstant(RHS, RightExprSansParen, Context) &&
       ((NoHonorNaNs && Value.isNaN()) || (NoHonorInfs && Value.isInfinity())))
     Diag(Loc, diag::warn_fast_floatingpoint_eq)
-        << (Value.isNaN() ? "NaN" : "infinity") << LHS->getSourceRange()
-        << RHS->getSourceRange();
+        << (Value.isNaN() ? 1 : 0) << (Value.isNaN() ? 1 : 0);
 }
 
 /// Check for comparisons of floating-point values using == and !=. Issue a
diff --git a/clang/test/Sema/warn-fp-fast-compare.cpp b/clang/test/Sema/warn-fp-fast-compare.cpp
index df8c8145f538ad6..430fb58dfd7473d 100644
--- a/clang/test/Sema/warn-fp-fast-compare.cpp
+++ b/clang/test/Sema/warn-fp-fast-compare.cpp
@@ -45,152 +45,175 @@ bool
 #define NAN (__builtin_nanf(""))
 #define INFINITY (__builtin_inff())
 
+template <class _Ty>
+class numeric_limits {
+public:
+    [[nodiscard]] static constexpr _Ty infinity() noexcept {
+        return _Ty();
+    }
+};
+
+template <>
+class numeric_limits<float>  {
+public:
+    [[nodiscard]] static constexpr float infinity() noexcept {
+        return __builtin_huge_val();
+    }
+};
+template <>
+class numeric_limits<double>  {
+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;
 #if FAST
-// expected-warning at +11 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +11 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if FAST
-// expected-warning at +8 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +8 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
   i = a == INFINITY;
 #if FAST
-// expected-warning at +11 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +11 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if FAST
-// expected-warning at +8 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +8 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
   j = INFINITY == a;
 #if FAST
-// expected-warning at +11 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +11 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
 #if FAST
-// expected-warning at +8 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +8 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +5 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +2 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
   i = a == NAN;
 #if FAST
-// expected-warning at +11 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +11 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
 #if FAST
-// expected-warning at +8 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +8 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +5 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +2 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
   j = NAN == a;
 #if FAST
-// expected-warning at +11 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +11 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if FAST
-// expected-warning at +8 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +8 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
   j = INFINITY <= a;
 #if FAST
-// expected-warning at +11 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +11 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if FAST
-// expected-warning at +8 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +8 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-  // expected-warning at +5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+  // expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
   j = INFINITY < a;
 #if FAST
-// expected-warning at +11 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +11 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
 #if FAST
-// expected-warning at +8 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +8 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +5 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-  // expected-warning at +2 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+  // expected-warning at +2 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
   j = a > NAN;
 #if FAST
-// expected-warning at +11 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +11 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
 #if FAST
-// expected-warning at +8 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +8 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +5 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +2 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
   j = a >= NAN;
 #if FAST
-// expected-warning at +5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 k = std::isinf(a);
 #if FAST
-// expected-warning at +5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +5 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +2 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
   l = std::isnan(a);
 #if FAST
-// expected-warning at +5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
   o = std::isfinite(a);
 #if FAST
-// expected-warning at +5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
   m = __builtin_isinf(a);
 #if FAST
-// expected-warning at +5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +5 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +2 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
   n = __builtin_isnan(a);
 #if FAST
-// expected-warning at +5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
   p = __builtin_isfinite(a);
 
@@ -202,44 +225,60 @@ k = std::isinf(a);
   j = isunorderedf(a, b);
 
 #if FAST
-// expected-warning at +5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +5 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +2 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
   j = isunorderedf(a, NAN);
 #if FAST
-// expected-warning at +5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
   j = isunorderedf(a, INFINITY);
 #if FAST
-// expected-warning at +11 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +11 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
 #if FAST
-// expected-warning at +8 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +8 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +5 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +2 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
   i = std::isunordered(a, NAN);
 #if FAST
-// expected-warning at +11 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +11 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if FAST
-// expected-warning at +8 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +8 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+// expected-warning at +5 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
   i = std::isunordered(a, INFINITY);
+#if FAST
+// expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+#endif
+  double y = i * numeric_limits<double>::infinity();
+
+#if FAST
+// expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+#endif
+  j = numeric_limits<float>::infinity();
   return 0;
+
 }  

>From d82f5690f4811552241b22b425de30dfbc84b049 Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Sat, 13 Jan 2024 08:16:01 -0800
Subject: [PATCH 4/6] Fixed the diagnostic message.

---
 clang/docs/ReleaseNotes.rst                   |   4 +
 .../clang/Basic/DiagnosticSemaKinds.td        |   7 +-
 clang/lib/Sema/SemaChecking.cpp               |  14 +-
 clang/test/Sema/warn-fp-fast-compare.cpp      | 126 +++++++++---------
 4 files changed, 78 insertions(+), 73 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 778ce0e0e52d066..94a91e3b13dcb09 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -519,6 +519,10 @@ Improvements to Clang's diagnostics
 - Clang now diagnoses narrowing conversions involving const references.
   (`#63151: <https://github.com/llvm/llvm-project/issues/63151>`_).
 - Clang now diagnoses unexpanded packs within the template argument lists of function template specializations.
+- Clang's ``-Wtautological-logical-constant-compare`` flag now diagnoses
+  when ``INFINITY`` or ``NAN`` are used in arithmetic operations or function
+  arguments in floating-points mode where ``INFINITY`` or ``NAN`` don't have the
+  expected values.
 
 
 Improvements to Clang's time-trace
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index e1164ef34a1b6c6..856022f51fad7db 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6772,9 +6772,10 @@ def warn_floatingpoint_eq : Warning<
   "comparing floating point with == or != is unsafe">,
   InGroup<DiagGroup<"float-equal">>, DefaultIgnore;
 def warn_fast_floatingpoint_eq : Warning<
-  "use of %select{infinity|NaN}0 will always be 'false' because "
-  "%select{infinity|NaN}0 will not be produced according to the currently "
-  "enabled floating-point options">,
+  "%select{explicit comparison with|use of}0 %select{infinity|nan}1 "
+  "%select{will always return 'false'|as a function argument will not always be interpreted as such}0 "
+  "because %select{infinity|nan}1 will not be produced according to the "
+  "currently enabled floating-point options">,
   InGroup<TautologicalConstantCompare>;
 
 def err_setting_eval_method_used_in_unsafe_context : Error <
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 027cfac1c5a641d..f2a49f89b9b1ecc 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -9098,7 +9098,7 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID) {
 
   if (BuiltinID == Builtin::BI__builtin_isunordered &&
       TheCall->getFPFeaturesInEffect(getLangOpts()).getNoHonorNaNs())
-    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq) << 1 << 1;
+    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq) << 0 << 1 << 0 << 1;
 
   ExprResult OrigArg0 = TheCall->getArg(0);
   ExprResult OrigArg1 = TheCall->getArg(1);
@@ -9143,10 +9143,10 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs,
   if (FPO.getNoHonorInfs() && (BuiltinID == Builtin::BI__builtin_isfinite ||
                                BuiltinID == Builtin::BI__builtin_isinf ||
                                BuiltinID == Builtin::BI__builtin_isinf_sign))
-    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq) << 0 << 0;
+    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq) << 0 << 0 << 0 << 0;
   if (FPO.getNoHonorNaNs() && (BuiltinID == Builtin::BI__builtin_isnan ||
                                BuiltinID == Builtin::BI__builtin_isunordered))
-    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq) << 1 << 1;
+    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq) << 1 << 1 << 1 << 1;
 
   bool IsFPClass = NumArgs == 2;
 
@@ -12900,13 +12900,13 @@ void Sema::CheckInfNaNFunction(const CallExpr *Call,
   if ((IsStdFunction(FDecl, "isnan") || IsStdFunction(FDecl, "isunordered") ||
        (Call->getBuiltinCallee() == Builtin::BI__builtin_nanf)) &&
       FPO.getNoHonorNaNs())
-    Diag(Call->getBeginLoc(), diag::warn_fast_floatingpoint_eq) << 1 << 1;
+    Diag(Call->getBeginLoc(), diag::warn_fast_floatingpoint_eq) << 1 << 1 << 1 << 1;
   else if ((IsStdFunction(FDecl, "isinf") ||
             (IsStdFunction(FDecl, "isfinite") ||
              (Call->getBuiltinCallee() == Builtin::BI__builtin_inff)) ||
             (FDecl->getIdentifier() && FDecl->getName() == "infinity")) &&
            FPO.getNoHonorInfs())
-    Diag(Call->getBeginLoc(), diag::warn_fast_floatingpoint_eq) << 0 << 0;
+    Diag(Call->getBeginLoc(), diag::warn_fast_floatingpoint_eq) << 1 << 0 << 1 << 0;
 }
 
 // Warn when using the wrong abs() function.
@@ -13899,12 +13899,12 @@ void Sema::CheckInfNaNFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS,
   if (IsConstant(LHS, LeftExprSansParen, Context) &&
       ((NoHonorNaNs && Value.isNaN()) || (NoHonorInfs && Value.isInfinity())))
     Diag(Loc, diag::warn_fast_floatingpoint_eq)
-        << (Value.isNaN() ? 1 : 0) << (Value.isNaN() ? 1 : 0);
+        << 0 << (Value.isNaN() ? 1 : 0) << 0 << (Value.isNaN() ? 1 : 0);
 
   if (IsConstant(RHS, RightExprSansParen, Context) &&
       ((NoHonorNaNs && Value.isNaN()) || (NoHonorInfs && Value.isInfinity())))
     Diag(Loc, diag::warn_fast_floatingpoint_eq)
-        << (Value.isNaN() ? 1 : 0) << (Value.isNaN() ? 1 : 0);
+        << 0 << (Value.isNaN() ? 1 : 0) << 0 <<  (Value.isNaN() ? 1 : 0);
 }
 
 /// Check for comparisons of floating-point values using == and !=. Issue a
diff --git a/clang/test/Sema/warn-fp-fast-compare.cpp b/clang/test/Sema/warn-fp-fast-compare.cpp
index 430fb58dfd7473d..c6f746c3f8de11a 100644
--- a/clang/test/Sema/warn-fp-fast-compare.cpp
+++ b/clang/test/Sema/warn-fp-fast-compare.cpp
@@ -71,149 +71,149 @@ class numeric_limits<double>  {
 int compareit(float a, float b) {
   volatile int i, j, k, l, m, n, o, p;
 #if FAST
-// expected-warning at +11 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +11 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if FAST
-// expected-warning at +8 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +8 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +5 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +2 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
   i = a == INFINITY;
 #if FAST
-// expected-warning at +11 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +11 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if FAST
-// expected-warning at +8 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +8 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +5 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +2 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
   j = INFINITY == a;
 #if FAST
-// expected-warning at +11 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +11 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
 #endif
 #if FAST
-// expected-warning at +8 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +8 {{explicit comparison with nan will always return 'false' because nan will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +5 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +5 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +2 {{explicit comparison with nan will always return 'false' because nan will not be produced according to the currently enabled floating-point options}}
 #endif
   i = a == NAN;
 #if FAST
-// expected-warning at +11 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +11 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
 #endif
 #if FAST
-// expected-warning at +8 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +8 {{explicit comparison with nan will always return 'false' because nan will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +5 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +5 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +2 {{explicit comparison with nan will always return 'false' because nan will not be produced according to the currently enabled floating-point options}}
 #endif
   j = NAN == a;
 #if FAST
-// expected-warning at +11 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +11 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if FAST
-// expected-warning at +8 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +8 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +5 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +2 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
   j = INFINITY <= a;
 #if FAST
-// expected-warning at +11 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +11 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if FAST
-// expected-warning at +8 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +8 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-  // expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +5 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +2 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
   j = INFINITY < a;
 #if FAST
-// expected-warning at +11 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +11 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
 #endif
 #if FAST
-// expected-warning at +8 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +8 {{explicit comparison with nan will always return 'false' because nan will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +5 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +5 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-  // expected-warning at +2 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +2 {{explicit comparison with nan will always return 'false' because nan will not be produced according to the currently enabled floating-point options}}
 #endif
   j = a > NAN;
 #if FAST
-// expected-warning at +11 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +11 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
 #endif
 #if FAST
-// expected-warning at +8 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +8 {{explicit comparison with nan will always return 'false' because nan will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +5 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +5 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +2 {{explicit comparison with nan will always return 'false' because nan will not be produced according to the currently enabled floating-point options}}
 #endif
   j = a >= NAN;
 #if FAST
-// expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +5 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +2 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
-k = std::isinf(a);
+  k = std::isinf(a);
 #if FAST
-// expected-warning at +5 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +5 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +2 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
 #endif
   l = std::isnan(a);
 #if FAST
-// expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +5 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +2 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
   o = std::isfinite(a);
 #if FAST
-// expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +5 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}} 
 #endif
 #if NO_INFS
-// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +2 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}} 
 #endif
   m = __builtin_isinf(a);
 #if FAST
-// expected-warning at +5 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +5 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +2 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
 #endif
   n = __builtin_isnan(a);
 #if FAST
-// expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +5 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +2 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
   p = __builtin_isfinite(a);
 
@@ -225,58 +225,58 @@ k = std::isinf(a);
   j = isunorderedf(a, b);
 
 #if FAST
-// expected-warning at +5 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +5 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +2 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
 #endif
   j = isunorderedf(a, NAN);
 #if FAST
-// expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +5 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +2 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
   j = isunorderedf(a, INFINITY);
 #if FAST
-// expected-warning at +11 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +11 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
 #endif
 #if FAST
-// expected-warning at +8 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +8 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +5 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +5 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_NANS
-// expected-warning at +2 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +2 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
 #endif
   i = std::isunordered(a, NAN);
 #if FAST
-// expected-warning at +11 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +11 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if FAST
-// expected-warning at +8 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_NANS
-// expected-warning at +5 {{use of NaN will always be 'false' because NaN will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +8 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +5 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
 #endif
   i = std::isunordered(a, INFINITY);
 #if FAST
-// expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +5 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +2 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
   double y = i * numeric_limits<double>::infinity();
 
 #if FAST
-// expected-warning at +5 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +5 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
 #if NO_INFS
-// expected-warning at +2 {{use of infinity will always be 'false' because infinity will not be produced according to the currently enabled floating-point options}}
+// expected-warning at +2 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
 #endif
   j = numeric_limits<float>::infinity();
   return 0;

>From b603724027071ae75ce509f69c3dbb8445edd42f Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Sat, 13 Jan 2024 08:23:24 -0800
Subject: [PATCH 5/6] Fix format.

---
 clang/lib/Sema/SemaChecking.cpp | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index f2a49f89b9b1ecc..4a8078a772006e5 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -9098,7 +9098,8 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID) {
 
   if (BuiltinID == Builtin::BI__builtin_isunordered &&
       TheCall->getFPFeaturesInEffect(getLangOpts()).getNoHonorNaNs())
-    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq) << 0 << 1 << 0 << 1;
+    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
+        << 0 << 1 << 0 << 1;
 
   ExprResult OrigArg0 = TheCall->getArg(0);
   ExprResult OrigArg1 = TheCall->getArg(1);
@@ -9143,10 +9144,12 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs,
   if (FPO.getNoHonorInfs() && (BuiltinID == Builtin::BI__builtin_isfinite ||
                                BuiltinID == Builtin::BI__builtin_isinf ||
                                BuiltinID == Builtin::BI__builtin_isinf_sign))
-    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq) << 0 << 0 << 0 << 0;
+    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
+        << 0 << 0 << 0 << 0;
   if (FPO.getNoHonorNaNs() && (BuiltinID == Builtin::BI__builtin_isnan ||
                                BuiltinID == Builtin::BI__builtin_isunordered))
-    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq) << 1 << 1 << 1 << 1;
+    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
+        << 1 << 1 << 1 << 1;
 
   bool IsFPClass = NumArgs == 2;
 
@@ -12900,13 +12903,15 @@ void Sema::CheckInfNaNFunction(const CallExpr *Call,
   if ((IsStdFunction(FDecl, "isnan") || IsStdFunction(FDecl, "isunordered") ||
        (Call->getBuiltinCallee() == Builtin::BI__builtin_nanf)) &&
       FPO.getNoHonorNaNs())
-    Diag(Call->getBeginLoc(), diag::warn_fast_floatingpoint_eq) << 1 << 1 << 1 << 1;
+    Diag(Call->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
+        << 1 << 1 << 1 << 1;
   else if ((IsStdFunction(FDecl, "isinf") ||
             (IsStdFunction(FDecl, "isfinite") ||
              (Call->getBuiltinCallee() == Builtin::BI__builtin_inff)) ||
             (FDecl->getIdentifier() && FDecl->getName() == "infinity")) &&
            FPO.getNoHonorInfs())
-    Diag(Call->getBeginLoc(), diag::warn_fast_floatingpoint_eq) << 1 << 0 << 1 << 0;
+    Diag(Call->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
+        << 1 << 0 << 1 << 0;
 }
 
 // Warn when using the wrong abs() function.
@@ -13904,7 +13909,7 @@ void Sema::CheckInfNaNFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS,
   if (IsConstant(RHS, RightExprSansParen, Context) &&
       ((NoHonorNaNs && Value.isNaN()) || (NoHonorInfs && Value.isInfinity())))
     Diag(Loc, diag::warn_fast_floatingpoint_eq)
-        << 0 << (Value.isNaN() ? 1 : 0) << 0 <<  (Value.isNaN() ? 1 : 0);
+        << 0 << (Value.isNaN() ? 1 : 0) << 0 << (Value.isNaN() ? 1 : 0);
 }
 
 /// Check for comparisons of floating-point values using == and !=. Issue a

>From 0b2cec264b4cb90088774bb13c35995104975f36 Mon Sep 17 00:00:00 2001
From: Ammarguellat <zahira.ammarguellat at intel.com>
Date: Wed, 17 Jan 2024 12:23:06 -0800
Subject: [PATCH 6/6] After discussion with Aaron separated the warning so one
 is triggered when INFINITY/NAN macros are used and the other when
 __builtin_inf() and __builtin_nan() are used.

---
 .../clang/Basic/DiagnosticCommonKinds.td      |   5 +-
 .../clang/Basic/DiagnosticSemaKinds.td        |   8 +-
 clang/include/clang/Lex/Preprocessor.h        |   4 +
 clang/include/clang/Sema/Sema.h               |   2 -
 clang/lib/Lex/Preprocessor.cpp                |   5 +
 clang/lib/Sema/SemaChecking.cpp               |  54 +---
 clang/lib/Sema/SemaExpr.cpp                   |   5 +-
 clang/test/Sema/warn-fp-fast-compare.cpp      | 284 ------------------
 .../Sema/warn-infinity-nan-disabled-lnx.cpp   | 237 +++++++++++++++
 .../Sema/warn-infinity-nan-disabled-win.cpp   | 240 +++++++++++++++
 10 files changed, 506 insertions(+), 338 deletions(-)
 delete mode 100644 clang/test/Sema/warn-fp-fast-compare.cpp
 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/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index 72952b08c04a490..8c096568ebd450e 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -69,7 +69,10 @@ def warn_pragma_debug_missing_argument : Warning<
   "missing argument to debug command '%0'">, InGroup<IgnoredPragmas>;
 def warn_pragma_debug_unexpected_argument : Warning<
   "unexpected argument to debug command">, InGroup<IgnoredPragmas>;
-
+def warn_infinity_defined_in_macro : Warning<
+  "infinity defined via a macro will result in an undefined behavior "
+  "due to the currently enabled floating-point options">,
+  InGroup<DiagGroup<"infinity-disabled">>;
 }
 
 // Parse && Sema
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 865b9db0f5e93e0..070986aa4531303 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -6784,12 +6784,10 @@ def warn_pointer_sub_null_ptr : Warning<
 def warn_floatingpoint_eq : Warning<
   "comparing floating point with == or != is unsafe">,
   InGroup<DiagGroup<"float-equal">>, DefaultIgnore;
-def warn_fast_floatingpoint_eq : Warning<
-  "%select{explicit comparison with|use of}0 %select{infinity|nan}1 "
-  "%select{will always return 'false'|as a function argument will not always be interpreted as such}0 "
-  "because %select{infinity|nan}1 will not be produced according to the "
+def warn_fp_nan_inf_when_disabled : Warning<
+  "use of %select{infinity|NaN}0 results in undefined behavior due to the "
   "currently enabled floating-point options">,
-  InGroup<TautologicalConstantCompare>;
+  InGroup<DiagGroup<"nan-and-infinity-disabled">>;
 
 def err_setting_eval_method_used_in_unsafe_context : Error <
   "%select{'#pragma clang fp eval_method'|option 'ffp-eval-method'}0 cannot be used with "
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index 4ec21a8b6be2c85..4ad034c02d6b11f 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -2835,6 +2835,9 @@ class Preprocessor {
     if (Identifier.getIdentifierInfo()->isRestrictExpansion() &&
         !SourceMgr.isInMainFile(Identifier.getLocation()))
       emitRestrictExpansionWarning(Identifier);
+
+    if (Identifier.getIdentifierInfo()->getName() == "INFINITY")
+      emitRestrictInfNaNWarning(Identifier);
   }
 
   static void processPathForFileMacro(SmallVectorImpl<char> &Path,
@@ -2850,6 +2853,7 @@ 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) 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 a9d720f97ff0800..8d915c8c730ea85 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -14035,8 +14035,6 @@ class Sema final {
 public:
   void CheckFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS,
                             BinaryOperatorKind Opcode);
-  void CheckInfNaNFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS,
-                                  BinaryOperatorKind Opcode);
 
 private:
   void CheckImplicitConversions(Expr *E, SourceLocation CC = SourceLocation());
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 64f54c6fc6382f2..da8e57ff084028c 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) const {
+  if (getLangOpts().NoHonorInfs)
+    Diag(Identifier, diag::warn_infinity_defined_in_macro);
+}
+
 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 bd29318ce893dbf..6195d0b361a788e 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -9113,8 +9113,8 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID) {
 
   if (BuiltinID == Builtin::BI__builtin_isunordered &&
       TheCall->getFPFeaturesInEffect(getLangOpts()).getNoHonorNaNs())
-    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
-        << 0 << 1 << 0 << 1;
+    Diag(TheCall->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled)
+        << 1 << TheCall->getSourceRange();
 
   ExprResult OrigArg0 = TheCall->getArg(0);
   ExprResult OrigArg1 = TheCall->getArg(1);
@@ -9159,12 +9159,13 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs,
   if (FPO.getNoHonorInfs() && (BuiltinID == Builtin::BI__builtin_isfinite ||
                                BuiltinID == Builtin::BI__builtin_isinf ||
                                BuiltinID == Builtin::BI__builtin_isinf_sign))
-    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
-        << 0 << 0 << 0 << 0;
+    Diag(TheCall->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled)
+        << 0 << TheCall->getSourceRange();
+
   if (FPO.getNoHonorNaNs() && (BuiltinID == Builtin::BI__builtin_isnan ||
                                BuiltinID == Builtin::BI__builtin_isunordered))
-    Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
-        << 1 << 1 << 1 << 1;
+    Diag(TheCall->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled)
+        << 1 << TheCall->getSourceRange();
 
   bool IsFPClass = NumArgs == 2;
 
@@ -12918,15 +12919,14 @@ void Sema::CheckInfNaNFunction(const CallExpr *Call,
   if ((IsStdFunction(FDecl, "isnan") || IsStdFunction(FDecl, "isunordered") ||
        (Call->getBuiltinCallee() == Builtin::BI__builtin_nanf)) &&
       FPO.getNoHonorNaNs())
-    Diag(Call->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
-        << 1 << 1 << 1 << 1;
+    Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled)
+        << 1 << Call->getSourceRange();
   else if ((IsStdFunction(FDecl, "isinf") ||
             (IsStdFunction(FDecl, "isfinite") ||
-             (Call->getBuiltinCallee() == Builtin::BI__builtin_inff)) ||
-            (FDecl->getIdentifier() && FDecl->getName() == "infinity")) &&
+             (FDecl->getIdentifier() && FDecl->getName() == "infinity"))) &&
            FPO.getNoHonorInfs())
-    Diag(Call->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
-        << 1 << 0 << 1 << 0;
+    Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled)
+        << 0 << Call->getSourceRange();
 }
 
 // Warn when using the wrong abs() function.
@@ -13897,36 +13897,6 @@ Sema::CheckReturnValExpr(Expr *RetValExp, QualType lhsType,
     CheckPPCMMAType(RetValExp->getType(), ReturnLoc);
 }
 
-/// Diagnose comparison to NAN or INFINITY in fast math modes.
-/// The comparison to NaN or INFINITY is always false in
-/// fast modes: float evaluation will not result in inf or nan.
-void Sema::CheckInfNaNFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS,
-                                      BinaryOperatorKind Opcode) {
-  Expr *LeftExprSansParen = LHS->IgnoreParenImpCasts();
-  Expr *RightExprSansParen = RHS->IgnoreParenImpCasts();
-
-  FPOptions FPO = LHS->getFPFeaturesInEffect(getLangOpts());
-  bool NoHonorNaNs = FPO.getNoHonorNaNs();
-  bool NoHonorInfs = FPO.getNoHonorInfs();
-  llvm::APFloat Value(0.0);
-
-  auto IsConstant = [&Value](Expr *E, Expr *ESansParen, ASTContext &Context) {
-    return !E->isValueDependent() &&
-           ESansParen->EvaluateAsFloat(Value, Context,
-                                       Expr::SE_AllowSideEffects);
-  };
-
-  if (IsConstant(LHS, LeftExprSansParen, Context) &&
-      ((NoHonorNaNs && Value.isNaN()) || (NoHonorInfs && Value.isInfinity())))
-    Diag(Loc, diag::warn_fast_floatingpoint_eq)
-        << 0 << (Value.isNaN() ? 1 : 0) << 0 << (Value.isNaN() ? 1 : 0);
-
-  if (IsConstant(RHS, RightExprSansParen, Context) &&
-      ((NoHonorNaNs && Value.isNaN()) || (NoHonorInfs && Value.isInfinity())))
-    Diag(Loc, diag::warn_fast_floatingpoint_eq)
-        << 0 << (Value.isNaN() ? 1 : 0) << 0 << (Value.isNaN() ? 1 : 0);
-}
-
 /// Check for comparisons of floating-point values using == and !=. Issue a
 /// warning if the comparison is not likely to do what the programmer intended.
 void Sema::CheckFloatComparison(SourceLocation Loc, Expr *LHS, Expr *RHS,
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 8920137169596f2..f3aa1e978aa65c5 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -13044,12 +13044,9 @@ static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS,
   if (Type->isAnyComplexType() && BinaryOperator::isRelationalOp(Opc))
     return S.InvalidOperands(Loc, LHS, RHS);
 
-  if (Type->hasFloatingRepresentation()) {
-    // Check for comparisons to NAN or INFINITY in fast math mode.
-    S.CheckInfNaNFloatComparison(Loc, LHS.get(), RHS.get(), Opc);
+  if (Type->hasFloatingRepresentation())
     // Check for comparisons of floating point operands using != and ==.
     S.CheckFloatComparison(Loc, LHS.get(), RHS.get(), Opc);
-  }
 
   // The result of comparisons is 'bool' in C++, 'int' in C.
   return S.Context.getLogicalOperationType();
diff --git a/clang/test/Sema/warn-fp-fast-compare.cpp b/clang/test/Sema/warn-fp-fast-compare.cpp
deleted file mode 100644
index c6f746c3f8de11a..000000000000000
--- a/clang/test/Sema/warn-fp-fast-compare.cpp
+++ /dev/null
@@ -1,284 +0,0 @@
-// RUN: %clang_cc1 -x c++ -verify -triple powerpc64le-unknown-unknown %s \
-// RUN: -menable-no-infs -menable-no-nans  -DFAST=1
-
-// RUN: %clang_cc1 -x c++ -verify -triple powerpc64le-unknown-unknown %s \
-// RUN: -DNOFAST=1
-
-// RUN: %clang_cc1 -x c++ -verify -triple powerpc64le-unknown-unknown %s \
-// RUN: -menable-no-infs -DNO_INFS=1
-
-// RUN: %clang_cc1 -x c++ -verify -triple powerpc64le-unknown-unknown %s \
-// RUN: -menable-no-nans -DNO_NANS=1
-
-int isunorderedf (float x, float y);
-#if NOFAST
-// expected-no-diagnostics
-#endif
-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 _Ty>
-class numeric_limits {
-public:
-    [[nodiscard]] static constexpr _Ty infinity() noexcept {
-        return _Ty();
-    }
-};
-
-template <>
-class numeric_limits<float>  {
-public:
-    [[nodiscard]] static constexpr float infinity() noexcept {
-        return __builtin_huge_val();
-    }
-};
-template <>
-class numeric_limits<double>  {
-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;
-#if FAST
-// expected-warning at +11 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-#if FAST
-// expected-warning at +8 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_INFS
-// expected-warning at +5 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-  i = a == INFINITY;
-#if FAST
-// expected-warning at +11 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-#if FAST
-// expected-warning at +8 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_INFS
-// expected-warning at +5 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-  j = INFINITY == a;
-#if FAST
-// expected-warning at +11 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-#if FAST
-// expected-warning at +8 {{explicit comparison with nan will always return 'false' because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_NANS
-// expected-warning at +5 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_NANS
-// expected-warning at +2 {{explicit comparison with nan will always return 'false' because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-  i = a == NAN;
-#if FAST
-// expected-warning at +11 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-#if FAST
-// expected-warning at +8 {{explicit comparison with nan will always return 'false' because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_NANS
-// expected-warning at +5 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_NANS
-// expected-warning at +2 {{explicit comparison with nan will always return 'false' because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-  j = NAN == a;
-#if FAST
-// expected-warning at +11 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-#if FAST
-// expected-warning at +8 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_INFS
-// expected-warning at +5 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-  j = INFINITY <= a;
-#if FAST
-// expected-warning at +11 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-#if FAST
-// expected-warning at +8 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_INFS
-// expected-warning at +5 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-  j = INFINITY < a;
-#if FAST
-// expected-warning at +11 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-#if FAST
-// expected-warning at +8 {{explicit comparison with nan will always return 'false' because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_NANS
-// expected-warning at +5 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_NANS
-// expected-warning at +2 {{explicit comparison with nan will always return 'false' because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-  j = a > NAN;
-#if FAST
-// expected-warning at +11 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-#if FAST
-// expected-warning at +8 {{explicit comparison with nan will always return 'false' because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_NANS
-// expected-warning at +5 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_NANS
-// expected-warning at +2 {{explicit comparison with nan will always return 'false' because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-  j = a >= NAN;
-#if FAST
-// expected-warning at +5 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_INFS
-// expected-warning at +2 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-  k = std::isinf(a);
-#if FAST
-// expected-warning at +5 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_NANS
-// expected-warning at +2 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-  l = std::isnan(a);
-#if FAST
-// expected-warning at +5 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_INFS
-// expected-warning at +2 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-  o = std::isfinite(a);
-#if FAST
-// expected-warning at +5 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}} 
-#endif
-#if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}} 
-#endif
-  m = __builtin_isinf(a);
-#if FAST
-// expected-warning at +5 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_NANS
-// expected-warning at +2 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-  n = __builtin_isnan(a);
-#if FAST
-// expected-warning at +5 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_INFS
-// expected-warning at +2 {{explicit comparison with infinity will always return 'false' because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-  p = __builtin_isfinite(a);
-
-  // These should NOT warn, since they are not comparing with NaN or infinity.
-  j = a > 1.1;
-  j = b < 1.1;
-  j = a >= 1.1;
-  j = b <= 1.1;
-  j = isunorderedf(a, b);
-
-#if FAST
-// expected-warning at +5 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_NANS
-// expected-warning at +2 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-  j = isunorderedf(a, NAN);
-#if FAST
-// expected-warning at +5 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_INFS
-// expected-warning at +2 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-  j = isunorderedf(a, INFINITY);
-#if FAST
-// expected-warning at +11 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-#if FAST
-// expected-warning at +8 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_NANS
-// expected-warning at +5 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_NANS
-// expected-warning at +2 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-  i = std::isunordered(a, NAN);
-#if FAST
-// expected-warning at +11 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-#if FAST
-// expected-warning at +8 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_INFS
-// expected-warning at +5 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_NANS
-// expected-warning at +2 {{use of nan as a function argument will not always be interpreted as such because nan will not be produced according to the currently enabled floating-point options}}
-#endif
-  i = std::isunordered(a, INFINITY);
-#if FAST
-// expected-warning at +5 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_INFS
-// expected-warning at +2 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-  double y = i * numeric_limits<double>::infinity();
-
-#if FAST
-// expected-warning at +5 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-#if NO_INFS
-// expected-warning at +2 {{use of infinity as a function argument will not always be interpreted as such because infinity will not be produced according to the currently enabled floating-point options}}
-#endif
-  j = numeric_limits<float>::infinity();
-  return 0;
-
-}  
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 000000000000000..b23bceeacc1d9fd
--- /dev/null
+++ b/clang/test/Sema/warn-infinity-nan-disabled-lnx.cpp
@@ -0,0 +1,237 @@
+// RUN: %clang_cc1 -x c++ -verify -triple powerpc64le-unknown-unknown %s \
+// RUN: -menable-no-infs -menable-no-nans  -DFAST=1
+
+// RUN: %clang_cc1 -x c++ -verify -triple powerpc64le-unknown-unknown %s \
+// RUN: -DNOFAST=1
+
+// RUN: %clang_cc1 -x c++ -verify -triple powerpc64le-unknown-unknown %s \
+// RUN: -menable-no-infs -DNO_INFS=1
+
+// RUN: %clang_cc1 -x c++ -verify -triple powerpc64le-unknown-unknown %s \
+// RUN: -menable-no-nans -DNO_NANS=1
+
+int isunorderedf (float x, float y);
+#if NOFAST
+// expected-no-diagnostics
+#endif
+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 _Ty>
+class numeric_limits {
+public:
+    [[nodiscard]] static constexpr _Ty infinity() noexcept {
+        return _Ty();
+    }
+};
+
+template <>
+class numeric_limits<float>  {
+public:
+    [[nodiscard]] static constexpr float infinity() noexcept {
+        return __builtin_huge_val();
+    }
+};
+template <>
+class numeric_limits<double>  {
+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;
+#if FAST
+// expected-warning at +5 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+  i = a == INFINITY;
+#if FAST
+// expected-warning at +5 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point option}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+  j = INFINITY == a;
+#if FAST
+// expected-warning at +5 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  i = a == NAN;
+#if FAST
+// expected-warning at +5 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  j = NAN == a;
+#if FAST
+// expected-warning at +5 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+  j = INFINITY <= a;
+#if FAST
+// expected-warning at +5 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+  j = INFINITY < a;
+#if FAST
+// expected-warning at +5 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  j = a > NAN;
+#if FAST
+// expected-warning at +5 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  j = a >= NAN;
+#if FAST
+// expected-warning at +5 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  k = std::isinf(a);
+#if FAST
+// expected-warning at +5 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  l = std::isnan(a);
+#if FAST
+// expected-warning at +5 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  o = std::isfinite(a);
+#if FAST
+// expected-warning at +5 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}} 
+#endif
+#if NO_INFS
+// expected-warning at +2 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}} 
+#endif
+  m = __builtin_isinf(a);
+#if FAST
+// expected-warning at +5 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  n = __builtin_isnan(a);
+#if FAST
+// expected-warning at +5 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  p = __builtin_isfinite(a);
+
+  // These should NOT warn, since they are not comparing with NaN or infinity.
+  j = a > 1.1;
+  j = b < 1.1;
+  j = a >= 1.1;
+  j = b <= 1.1;
+  j = isunorderedf(a, b);
+
+#if FAST
+// expected-warning at +5 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  j = isunorderedf(a, NAN);
+#if FAST
+// expected-warning at +5 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+  j = isunorderedf(a, INFINITY);
+#if FAST
+// expected-warning at +11 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if FAST
+// expected-warning at +8 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_NANS
+// expected-warning at +5 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  i = std::isunordered(a, NAN);
+#if FAST
+// expected-warning at +11 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point option}}
+#endif
+#if FAST
+// expected-warning at +8 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +5 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  i = std::isunordered(a, INFINITY);
+#if FAST
+// expected-warning at +5 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  double y = i * numeric_limits<double>::infinity();
+
+#if FAST
+// expected-warning at +5 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  j = numeric_limits<float>::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 000000000000000..085de5b92f84ca0
--- /dev/null
+++ b/clang/test/Sema/warn-infinity-nan-disabled-win.cpp
@@ -0,0 +1,240 @@
+// 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 -triple powerpc64le-unknown-unknown %s \
+// RUN: -menable-no-infs -menable-no-nans  -DFAST=1
+
+// RUN: %clang_cc1 -x c++ -verify -triple powerpc64le-unknown-unknown %s \
+// RUN: -DNOFAST=1
+
+// RUN: %clang_cc1 -x c++ -verify -triple powerpc64le-unknown-unknown %s \
+// RUN: -menable-no-infs -DNO_INFS=1
+
+// RUN: %clang_cc1 -x c++ -verify -triple powerpc64le-unknown-unknown %s \
+// RUN: -menable-no-nans -DNO_NANS=1
+
+int isunorderedf (float x, float y);
+#if NOFAST
+// expected-no-diagnostics
+#endif
+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 _Ty>
+class numeric_limits {
+public:
+    [[nodiscard]] static constexpr _Ty infinity() noexcept {
+        return _Ty();
+    }
+};
+
+template <>
+class numeric_limits<float>  {
+public:
+    [[nodiscard]] static constexpr float infinity() noexcept {
+        return __builtin_huge_val();
+    }
+};
+template <>
+class numeric_limits<double>  {
+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;
+#if FAST
+// expected-warning at +5 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+  i = a == INFINITY;
+#if FAST
+// expected-warning at +5 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+  j = INFINITY == a;
+#if FAST
+// expected-warning at +5 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+  i = a == NAN;
+#if FAST
+// expected-warning at +5 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+  j = NAN == a;
+#if FAST
+// expected-warning at +5 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+  j = INFINITY <= a;
+#if FAST
+// expected-warning at +5 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+  j = INFINITY < a;
+#if FAST
+// expected-warning at +5 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+  j = a > NAN;
+#if FAST
+// expected-warning at +5 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+  j = a >= NAN;
+#if FAST
+// expected-warning at +5 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  k = std::isinf(a);
+#if FAST
+// expected-warning at +5 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  l = std::isnan(a);
+#if FAST
+// expected-warning at +5 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  o = std::isfinite(a);
+#if FAST
+// expected-warning at +5 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}} 
+#endif
+#if NO_INFS
+// expected-warning at +2 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}} 
+#endif
+  m = __builtin_isinf(a);
+#if FAST
+// expected-warning at +5 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  n = __builtin_isnan(a);
+#if FAST
+// expected-warning at +5 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  p = __builtin_isfinite(a);
+
+  // These should NOT warn, since they are not comparing with NaN or infinity.
+  j = a > 1.1;
+  j = b < 1.1;
+  j = a >= 1.1;
+  j = b <= 1.1;
+  j = isunorderedf(a, b);
+
+#if FAST
+// expected-warning at +5 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+  j = isunorderedf(a, NAN);
+#if FAST
+// expected-warning at +5 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+  j = isunorderedf(a, INFINITY);
+#if FAST
+// expected-warning at +11 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if FAST
+// expected-warning at +8 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +5 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  i = std::isunordered(a, NAN);
+#if FAST
+// expected-warning at +11 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if FAST
+// expected-warning at +8 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +5 {{infinity defined via a macro will result in an undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_NANS
+// expected-warning at +2 {{use of NaN results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  i = std::isunordered(a, INFINITY);
+#if FAST
+// expected-warning at +5 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  double y = i * numeric_limits<double>::infinity();
+
+#if FAST
+// expected-warning at +5 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+#if NO_INFS
+// expected-warning at +2 {{use of infinity results in undefined behavior due to the currently enabled floating-point options}}
+#endif
+  j = numeric_limits<float>::infinity();
+  return 0;
+
+}  



More information about the cfe-commits mailing list