Skip to content

[CLANG] Add warning when INF or NAN are used in a binary operation or as function argument in fast math mode. #76873

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Jan 22, 2024

Conversation

zahiraam
Copy link
Contributor

@zahiraam zahiraam commented Jan 3, 2024

Check for operations using INF or NaN when in ffast-math mode and generate a warning.

@zahiraam zahiraam requested a review from andykaylor January 3, 2024 22:39
Copy link
Contributor

@andykaylor andykaylor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expanding the scope a bit, it would also be useful to have warnings for constant NaN or Inf values passed as arguments or used in binary operations.

@@ -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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this check be in SemaBuiltinUnorderedCompare()?

@@ -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());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these checks be in SemaBuiltinFPClassification()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

/// 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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is 81 characters long.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's 79 chars long.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, sorry. I must have copied the "+ " when I checked it. It just looked longer than the surrounding text.

bool NoHonorInfs = FPO.getNoHonorInfs();
llvm::APFloat Value(0.0);
bool IsConstant;
IsConstant = !LHS->isValueDependent() &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use a lambda here to avoid code duplication for LHS and RHS checking.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be done in CheckFloatComparison()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@zahiraam
Copy link
Contributor Author

zahiraam commented Jan 5, 2024

Expanding the scope a bit, it would also be useful to have warnings for constant NaN or Inf values passed as arguments or used in binary operations.

Added that.

@zahiraam zahiraam requested a review from andykaylor January 5, 2024 21:57
@zahiraam zahiraam marked this pull request as ready for review January 8, 2024 13:09
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jan 8, 2024
@zahiraam zahiraam requested a review from arsenm January 8, 2024 13:09
@llvmbot
Copy link
Member

llvmbot commented Jan 8, 2024

@llvm/pr-subscribers-clang

Author: Zahira Ammarguellat (zahiraam)

Changes

Check for comparisons to INF and NaN when in ffast-math mode and generate a warning.


Full diff: https://github.com/llvm/llvm-project/pull/76873.diff

5 Files Affected:

  • (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+3)
  • (modified) clang/include/clang/Sema/Sema.h (+7-2)
  • (modified) clang/lib/Sema/SemaChecking.cpp (+74-6)
  • (modified) clang/lib/Sema/SemaExpr.cpp (+5-2)
  • (added) clang/test/Sema/warn-fp-fast-compare.cpp (+245)
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index e54f969c19039d..d19be567a1bf66 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 when the program is assumed to not use or produce %0">,
+  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 5e3b57ea33220b..b19ce6312e83bc 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);
@@ -13998,6 +13999,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 +14027,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 3168d38dd66c36..2c4d628ab160d2 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -2169,6 +2169,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
     ICEArguments &= ~(1 << ArgNo);
   }
 
+  FPOptions FPO;
   switch (BuiltinID) {
   case Builtin::BI__builtin___CFStringMakeConstantString:
     // CFStringMakeConstantString is currently not implemented for GOFF (i.e.,
@@ -2245,15 +2246,15 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
   case Builtin::BI__builtin_islessequal:
   case Builtin::BI__builtin_islessgreater:
   case Builtin::BI__builtin_isunordered:
-    if (SemaBuiltinUnorderedCompare(TheCall))
+    if (SemaBuiltinUnorderedCompare(TheCall, BuiltinID))
       return ExprError();
     break;
   case Builtin::BI__builtin_fpclassify:
-    if (SemaBuiltinFPClassification(TheCall, 6))
+    if (SemaBuiltinFPClassification(TheCall, 6, BuiltinID))
       return ExprError();
     break;
   case Builtin::BI__builtin_isfpclass:
-    if (SemaBuiltinFPClassification(TheCall, 2))
+    if (SemaBuiltinFPClassification(TheCall, 2, BuiltinID))
       return ExprError();
     break;
   case Builtin::BI__builtin_isfinite:
@@ -2267,7 +2268,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
   case Builtin::BI__builtin_signbit:
   case Builtin::BI__builtin_signbitf:
   case Builtin::BI__builtin_signbitl:
-    if (SemaBuiltinFPClassification(TheCall, 1))
+    if (SemaBuiltinFPClassification(TheCall, 1, BuiltinID))
       return ExprError();
     break;
   case Builtin::BI__builtin_shufflevector:
@@ -7621,6 +7622,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);
@@ -9090,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);
 
@@ -9128,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.
@@ -12878,6 +12898,22 @@ static bool IsStdFunction(const FunctionDecl *FDecl,
   return true;
 }
 
+void Sema::CheckInfNaNFunction(const CallExpr *Call,
+                               const FunctionDecl *FDecl) {
+  FPOptions FPO = Call->getFPFeaturesInEffect(getLangOpts());
+  if ((IsStdFunction(FDecl, "isnan") || IsStdFunction(FDecl, "isunordered") ||
+       (Call->getBuiltinCallee() == Builtin::BI__builtin_nanf)) &&
+      FPO.getNoHonorNaNs())
+    Diag(Call->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
+        << "NaN" << Call->getSourceRange();
+  else if ((IsStdFunction(FDecl, "isinf") ||
+            (IsStdFunction(FDecl, "isfinite") ||
+             (Call->getBuiltinCallee() == Builtin::BI__builtin_inff))) &&
+           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 +13882,38 @@ 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)
+        << (Value.isNaN() ? "NaN" : "infinity") << LHS->getSourceRange()
+        << RHS->getSourceRange();
+
+  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();
+}
+
 /// 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 960f513d1111b2..005ddfa882195d 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 00000000000000..df8c8145f538ad
--- /dev/null
+++ b/clang/test/Sema/warn-fp-fast-compare.cpp
@@ -0,0 +1,245 @@
+// 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@+11 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if FAST
+// expected-warning@+8 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if NO_INFS
+// expected-warning@+5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if NO_INFS
+// expected-warning@+2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+  i = a == INFINITY;
+#if FAST
+// expected-warning@+11 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if FAST
+// expected-warning@+8 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if NO_INFS
+// expected-warning@+5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if NO_INFS
+// expected-warning@+2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+  j = INFINITY == a;
+#if FAST
+// expected-warning@+11 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if FAST
+// expected-warning@+8 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_NANS
+// expected-warning@+5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_NANS
+// expected-warning@+2 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+  i = a == NAN;
+#if FAST
+// expected-warning@+11 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if FAST
+// expected-warning@+8 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_NANS
+// expected-warning@+5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_NANS
+// expected-warning@+2 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+  j = NAN == a;
+#if FAST
+// expected-warning@+11 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if FAST
+// expected-warning@+8 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if NO_INFS
+// expected-warning@+5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if NO_INFS
+// expected-warning@+2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+  j = INFINITY <= a;
+#if FAST
+// expected-warning@+11 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if FAST
+// expected-warning@+8 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if NO_INFS
+  // expected-warning@+5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if NO_INFS
+// expected-warning@+2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+  j = INFINITY < a;
+#if FAST
+// expected-warning@+11 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if FAST
+// expected-warning@+8 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_NANS
+// expected-warning@+5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_NANS
+  // expected-warning@+2 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+  j = a > NAN;
+#if FAST
+// expected-warning@+11 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if FAST
+// expected-warning@+8 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_NANS
+// expected-warning@+5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_NANS
+// expected-warning@+2 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+  j = a >= NAN;
+#if FAST
+// expected-warning@+5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if NO_INFS
+// expected-warning@+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@+5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_NANS
+// expected-warning@+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@+5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if NO_INFS
+// expected-warning@+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@+5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if NO_INFS
+// expected-warning@+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@+5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_NANS
+// expected-warning@+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@+5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if NO_INFS
+// expected-warning@+2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#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@+5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_NANS
+// expected-warning@+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@+5 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if NO_INFS
+// expected-warning@+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@+11 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if FAST
+// expected-warning@+8 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_NANS
+// expected-warning@+5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_NANS
+// expected-warning@+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@+11 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+#if FAST
+// expected-warning@+8 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_NANS
+// expected-warning@+5 {{explicit comparison with NaN when the program is assumed to not use or produce NaN}}
+#endif
+#if NO_INFS
+// expected-warning@+2 {{explicit comparison with infinity when the program is assumed to not use or produce infinity}}
+#endif
+  i = std::isunordered(a, INFINITY);
+  return 0;
+}  

@zahiraam zahiraam requested a review from AaronBallman January 8, 2024 13:09
@zahiraam zahiraam changed the title [CLANG] Add warning when comparing to INF or NAN in fast math mode. [CLANG] Add warning when INF or NAN are used in a binary operation or as function argument in fast math mode. Jan 8, 2024
}
#define NAN (__builtin_nanf(""))
#define INFINITY (__builtin_inff())

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about through std::numeric_limits::infinity?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes also need a release note.

@@ -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 when the program is assumed to not use or produce %0">,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"explicit comparison with %0 when the program is assumed to not use or produce %0">,
"explicit comparison with %select{infinity|NaN}0 will always return '%select{false|true}1' because %select{infinity|NaN}0 will not be produced according to the currently enabled floating-point options">,

How about something along these lines? I mostly want to replace the %0 with a select so we don't have to pass in constant strings at the use sites, and I want to explicitly tell the user whether the comparison will always be true or always be false.

Copy link
Contributor Author

@zahiraam zahiraam Jan 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure this makes sense. Since I am also adding this warning to things like a * INF/NaN or foo(INF). May be "explicit comparison" should be replace with "use of"?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, good point! How about...

explicit comparison of an expression involving %select{an infinity|a NaN}0 constant will always return '%select{false|true}1' because %select{infinity|NaN}0 will not be produced according to the currently enabled floating-point options

? It's a bit wordy, so maybe "use of infinity|NaN will always" is okay as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's ok I will use "use of infinity|NaN will always" only because the warning is not triggered only for comparison but for binary operators using inf/nan and function calls with inf/nan arguments.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines 9099 to 9103
if (BuiltinID == Builtin::BI__builtin_isunordered) {
if (TheCall->getFPFeaturesInEffect(getLangOpts()).getNoHonorNaNs())
Diag(TheCall->getBeginLoc(), diag::warn_fast_floatingpoint_eq)
<< "NaN" << TheCall->getSourceRange();
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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)
<< "NaN" << TheCall->getSourceRange();

@@ -6771,6 +6771,11 @@ 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<
"use of %select{infinity|NaN}0 will always be 'false' because "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't make sense to me. What does it mean for a use to be false?

Maybe we're trying to wrap too much into a single diagnostic. For comparisons, the result of the comparison will be constant, so it makes sense to have a warning that tells the user what that constant result will be. However, when a constant NaN or infinity is passed as an argument to a function call, the situation is a bit more complicated. In that case, the optimizer can treat the input as poison. What effect that will have depends on the content of the called function. It might do nothing. It might cause the entire function call to be erased.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea! not happy with this either.
May be saying something like this to warn the user the existence of inf/nan use: "use of inf/nan when the program will not be producing inf/nan according to the currently enabled floating-point options"?

Copy link

github-actions bot commented Jan 13, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

Comment on lines 6788 to 6791
"%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">,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, now that I better understand the scope of the functionality, I think we should go with:

use of %select{infinity|NaN}0 results in undefined behavior due to the currently enabled floating-point options

and move the diagnostic out of the tautological compare warning group. You should also update ExprConstant.cpp to reject use of inf/nan in a constant expression with the options disabled.

/// 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,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The basic idea I have is that it's UB to generate a constant infinity or NaN if infinity/NaN is disabled. Instead of performing special logic for float comparisons, I think the logic should live in Sema::ActOnNumericConstant() so that we capture any time a float or infinity constant is used. e.g. inf + 1 should also diagnose.

Then the tautological comparison component to this could be implemented by looking for calls to __builtin_isinf or __builtin_isnan and claim those are tautologically false (as a follow-up patch). WDYT?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have actually tried that but I noticed that getSpellingOfSingleCharacterNumericConstant of inf/nan will both return "0" so I will have no way to distinguish between inf + 1 and 0 + 1 and both will generate a warning. Unless there is other way of finding out that the token is nan/inf?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we on that path in the first place? The token length shouldn't be one character long for either inf or nan right? I was thinking you should be able to call NumericLiteralParser::GetFloatValue() within the } else if (Literal.isFloatingLiteral()) { block to get an APFloat that you can call isInfinity() or isNaN() on and then diagnose at that point.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AaronBallman Thanks.

when INFINITY/NAN macros are used and the other when __builtin_inf()
and __builtin_nan() are used.
@zahiraam zahiraam requested a review from AaronBallman January 17, 2024 20:24
@@ -70,6 +70,10 @@ def warn_pragma_debug_missing_argument : Warning<
def warn_pragma_debug_unexpected_argument : Warning<
"unexpected argument to debug command">, InGroup<IgnoredPragmas>;

def warn_fp_nan_inf_when_disabled : Warning<
"use of %select{infinity|NaN}0 %select{|via a macro}1 results in an undefined behavior "
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"use of %select{infinity|NaN}0 %select{|via a macro}1 results in an undefined behavior "
"use of %select{infinity|NaN}0%select{| via a macro}1 results in undefined behavior "

How about this?

@@ -2835,6 +2835,9 @@ class Preprocessor {
if (Identifier.getIdentifierInfo()->isRestrictExpansion() &&
!SourceMgr.isInMainFile(Identifier.getLocation()))
emitRestrictExpansionWarning(Identifier);

if (Identifier.getIdentifierInfo()->getName() == "INFINITY")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about NAN?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since NAN is defined as (-(float)(INFINITY * 0.0F)) when used in the program it will trigger the "use of infinity via a macro results in undefined behavior due to the currently enabled floating-point options [-Wnan-and-infinity-disabled]". Wouldn't that be enough? If I add NaN here we would get 2 warnings.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because there are other C standard libraries which do something different. For example, musl: https://git.musl-libc.org/cgit/musl/tree/include/math.h#n18

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since NAN is defined as (-(float)(INFINITY * 0.0F)) when used in the program it will trigger the "use of infinity via a macro results in undefined behavior due to the currently enabled floating-point options [-Wnan-and-infinity-disabled]". Wouldn't that be enough? If I add NaN here we would get 2 warnings.

This is actually a bit unfortunate. If I use "-fhonor-nans -fno-honor-infinities" this definition of NAN will trigger a warning, even though I expect that we'll constant-fold it as expected without regard to the "no-honor-infinities" setting.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will?

#ifndef _HUGE_ENUF
    #define _HUGE_ENUF  1e+300  // _HUGE_ENUF*_HUGE_ENUF must overflow
#endif

#define INFINITY   ((float)(_HUGE_ENUF * _HUGE_ENUF))
...
#define NAN        ((float)(INFINITY * 0.0F))

the multiplication for INFINITY won't form an actual infinity value in that case, so why would the multiplication with 0.0 not generate a NAN macro that folds to 0.0F?

If use of INFINITY is undefined behavior when -fno-honor-infinities is passed... it makes sense to me that the definition of NAN using INFINITY is UB by the same logic.

Comment on lines 73 to 76
def warn_fp_nan_inf_when_disabled : Warning<
"use of %select{infinity|NaN}0%select{| via a macro}1 results in undefined behavior "
"due to the currently enabled floating-point options">,
InGroup<DiagGroup<"nan-and-infinity-disabled">>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def warn_fp_nan_inf_when_disabled : Warning<
"use of %select{infinity|NaN}0%select{| via a macro}1 results in undefined behavior "
"due to the currently enabled floating-point options">,
InGroup<DiagGroup<"nan-and-infinity-disabled">>;
def warn_fp_nan_inf_when_disabled : Warning<
"use of %select{infinity|NaN}0%select{| via a macro}1 is undefined behavior "
"due to the currently enabled floating-point options">,
InGroup<DiagGroup<"nan-infinity-disabled">>;

Sorry for still puttering around with what color to paint the bikeshed, but I think this might be slightly more concise wording and a somewhat better diagnostic group.

Comment on lines 74 to 79
#if FAST
// expected-warning@+5 {{use of infinity via a macro results in undefined behavior due to the currently enabled floating-point options}}
#endif
#if NO_INFS
// expected-warning@+2 {{use of infinity via a macro results in undefined behavior due to the currently enabled floating-point options}}
#endif
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than use the preprocessor to have conditional diagnostics, it's better to use diagnostics with different prefixes. e.g.,

// RUN: %clang_cc1 -x c++ -verify=no-inf,no-nan -triple powerpc64le-unknown-unknown %s \
// RUN: -menable-no-infs -menable-no-nans 

// RUN: %clang_cc1 -x c++ -verify=no-inf -triple powerpc64le-unknown-unknown %s \
// RUN: -menable-no-infs

// RUN: %clang_cc1 -x c++ -verify=no-nan -triple powerpc64le-unknown-unknown %s \
// RUN: -menable-no-nans

...

i = a == INFINITY; // no-inf-warning {{blah blah blah}}

Copy link
Collaborator

@AaronBallman AaronBallman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes LGTM aside from some minor improvements to the tests.

Comment on lines 4 to 16
// RUN: %clang_cc1 -x c++ -verify -triple powerpc64le-unknown-unknown %s \
// RUN: -DNOFAST=1

// RUN: %clang_cc1 -x c++ -verify=no-inf -triple powerpc64le-unknown-unknown %s \
// RUN: -menable-no-infs

// RUN: %clang_cc1 -x c++ -verify=no-nan -triple powerpc64le-unknown-unknown %s \
// RUN: -menable-no-nans

int isunorderedf (float x, float y);
#if NOFAST
// expected-no-diagnostics
#endif
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// RUN: %clang_cc1 -x c++ -verify -triple powerpc64le-unknown-unknown %s \
// RUN: -DNOFAST=1
// RUN: %clang_cc1 -x c++ -verify=no-inf -triple powerpc64le-unknown-unknown %s \
// RUN: -menable-no-infs
// RUN: %clang_cc1 -x c++ -verify=no-nan -triple powerpc64le-unknown-unknown %s \
// RUN: -menable-no-nans
int isunorderedf (float x, float y);
#if NOFAST
// expected-no-diagnostics
#endif
// RUN: %clang_cc1 -x c++ -verify=no-fast -triple powerpc64le-unknown-unknown %s
// RUN: %clang_cc1 -x c++ -verify=no-inf -triple powerpc64le-unknown-unknown %s \
// RUN: -menable-no-infs
// RUN: %clang_cc1 -x c++ -verify=no-nan -triple powerpc64le-unknown-unknown %s \
// RUN: -menable-no-nans
// no-fast-no-diagnostics
int isunorderedf (float x, float y);


int isunorderedf (float x, float y);
#if NOFAST
// expected-no-diagnostics
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing here as with the other test.

@zahiraam
Copy link
Contributor Author

Any other comments from @arsenm and @andykaylor?

Copy link
Contributor

@andykaylor andykaylor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm happy with this.

@zahiraam zahiraam merged commit 1e2a4cc into llvm:main Jan 22, 2024
@mikaelholmen
Copy link
Collaborator

Hello,

It seems like with this change it warns like

w.c:1:10: warning: use of infinity via a macro is undefined behavior due to the currently enabled floating-point options [-Wnan-infinity-disabled]
    1 | # ifndef INFINITY
      |          ^
1 warning generated.

with

clang w.c -c -ffast-math

on input like

# ifndef INFINITY

# endif

Is this expected and wanted?

@AaronBallman
Copy link
Collaborator

Is this expected and wanted?

Good catch! I would not expect that diagnostic; we should silence the diagnostic if it's used in a #ifdef, #elifdef, or defined because the value isn't necessary. Perhaps we should also silence something like sizeof(INFINITY) because it's unevaluated?

@zahiraam
Copy link
Contributor Author

Is this expected and wanted?

Good catch! I would not expect that diagnostic; we should silence the diagnostic if it's used in a #ifdef, #elifdef, or defined because the value isn't necessary. Perhaps we should also silence something like sizeof(INFINITY) because it's unevaluated?

Thanks @mikaelholmen and @AaronBallman. I will take a look and create a PR to fix the issue.

@mikaelholmen
Copy link
Collaborator

Is this expected and wanted?

Good catch! I would not expect that diagnostic; we should silence the diagnostic if it's used in a #ifdef, #elifdef, or defined because the value isn't necessary. Perhaps we should also silence something like sizeof(INFINITY) because it's unevaluated?

Thanks @mikaelholmen and @AaronBallman. I will take a look and create a PR to fix the issue.

Hi @zahiraam !
Did you get anywhere with this?

@zahiraam
Copy link
Contributor Author

Is this expected and wanted?

Good catch! I would not expect that diagnostic; we should silence the diagnostic if it's used in a #ifdef, #elifdef, or defined because the value isn't necessary. Perhaps we should also silence something like sizeof(INFINITY) because it's unevaluated?

Thanks @mikaelholmen and @AaronBallman. I will take a look and create a PR to fix the issue.

Hi @zahiraam ! Did you get anywhere with this?

Sorry! I didn't have time to work on it yet. I should probably get to it next week.

@zeroomega
Copy link
Contributor

Hi, I am seeing breakages on some of our audio code on tip of tree Clang and I traced it back to this patch.

We uses -ffast-math mode for performance reasons but we also uses -fhonor-infinities, -fhonor-nans and fno-finite-math-only to ensure that the behavior of infinity is correct. But the message error: use of infinity is undefined behavior due to the currently enabled floating-point options [-Werror,-Wnan-infinity-disabled] was still produced by the compiler. Is this intended behavior? If not, could you revert, revise and reland the change please?

Thanks.

@zahiraam
Copy link
Contributor Author

Hi, I am seeing breakages on some of our audio code on tip of tree Clang and I traced it back to this patch.

We uses -ffast-math mode for performance reasons but we also uses -fhonor-infinities, -fhonor-nans and fno-finite-math-only to ensure that the behavior of infinity is correct. But the message error: use of infinity is undefined behavior due to the currently enabled floating-point options [-Werror,-Wnan-infinity-disabled] was still produced by the compiler. Is this intended behavior? If not, could you revert, revise and reland the change please?

Thanks.

I think this must be related to the comment above. I am in process of creating a PR to fix it. But if it can't wait I will revert this.
See https://godbolt.org/z/r154xP11W

@AaronBallman
Copy link
Collaborator

Hi, I am seeing breakages on some of our audio code on tip of tree Clang and I traced it back to this patch.

We uses -ffast-math mode for performance reasons but we also uses -fhonor-infinities, -fhonor-nans and fno-finite-math-only to ensure that the behavior of infinity is correct. But the message error: use of infinity is undefined behavior due to the currently enabled floating-point options [-Werror,-Wnan-infinity-disabled] was still produced by the compiler. Is this intended behavior? If not, could you revert, revise and reland the change please?

Thanks.

What is the order you're passing the flags? This may have actually pointed out a difference between what you expected and what actually happens (which is part of the point to these changes): https://godbolt.org/z/x54qTGoMG

@AaronBallman
Copy link
Collaborator

Is this expected and wanted?

Good catch! I would not expect that diagnostic; we should silence the diagnostic if it's used in a #ifdef, #elifdef, or defined because the value isn't necessary. Perhaps we should also silence something like sizeof(INFINITY) because it's unevaluated?

Thanks @mikaelholmen and @AaronBallman. I will take a look and create a PR to fix the issue.

Hi @zahiraam ! Did you get anywhere with this?

Sorry! I didn't have time to work on it yet. I should probably get to it next week.

Because these changes made it into 18.x and we're already seeing feedback about the diagnostic quality, I think we need to either revert the changes for the moment (both on main and on 18.x) or we need to commit to getting the fix as quickly as possible (and backport it to 18.x). I'd like to avoid getting into a situation where we're reverting this on 18.x later in the cycle. How about this for a plan: if there's not a fix committed by EOD Mon (2/5), we revert so that rc2 goes out in a good state (rc2 is being cut on Tue the 6th)?

@zeroomega
Copy link
Contributor

Hi, I am seeing breakages on some of our audio code on tip of tree Clang and I traced it back to this patch.
We uses -ffast-math mode for performance reasons but we also uses -fhonor-infinities, -fhonor-nans and fno-finite-math-only to ensure that the behavior of infinity is correct. But the message error: use of infinity is undefined behavior due to the currently enabled floating-point options [-Werror,-Wnan-infinity-disabled] was still produced by the compiler. Is this intended behavior? If not, could you revert, revise and reland the change please?
Thanks.

What is the order you're passing the flags? This may have actually pointed out a difference between what you expected and what actually happens (which is part of the point to these changes): https://godbolt.org/z/x54qTGoMG

Thanks for the tip.
I think it is the ordering issue on our side. The build system actually put 2 -ffast-math flags into the command line (we expect 1 but some the buildfile have a bug), The build system placed -fhonor-infinities, -fhonor-nans before the 2nd -ffast-math flag and this 2nd --ffast-math resets those honor flags I assume, and we saw the warning.

zahiraam added a commit that referenced this pull request Feb 6, 2024
In #76873 a warning was added
when the macros INFINITY and NAN are used in binary expressions when
-menable-no-nans or -menable-no-infs are used. If the user uses an
option that nullifies these two options, the warning will still be
generated. This patch adds an additional information to the warning
comment to let the user know about this. It also suppresses the warning
when #ifdef INFINITY, #ifdef NAN, #ifdef NAN or #ifndef NAN are used in
the code.
llvmbot pushed a commit to llvmbot/llvm-project that referenced this pull request Feb 6, 2024
In llvm#76873 a warning was added
when the macros INFINITY and NAN are used in binary expressions when
-menable-no-nans or -menable-no-infs are used. If the user uses an
option that nullifies these two options, the warning will still be
generated. This patch adds an additional information to the warning
comment to let the user know about this. It also suppresses the warning
when #ifdef INFINITY, #ifdef NAN, #ifdef NAN or #ifndef NAN are used in
the code.

(cherry picked from commit 62c352e)
llvmbot pushed a commit to llvmbot/llvm-project that referenced this pull request Feb 6, 2024
In llvm#76873 a warning was added
when the macros INFINITY and NAN are used in binary expressions when
-menable-no-nans or -menable-no-infs are used. If the user uses an
option that nullifies these two options, the warning will still be
generated. This patch adds an additional information to the warning
comment to let the user know about this. It also suppresses the warning
when #ifdef INFINITY, #ifdef NAN, #ifdef NAN or #ifndef NAN are used in
the code.

(cherry picked from commit 62c352e)
llvmbot pushed a commit to llvmbot/llvm-project that referenced this pull request Feb 6, 2024
In llvm#76873 a warning was added
when the macros INFINITY and NAN are used in binary expressions when
-menable-no-nans or -menable-no-infs are used. If the user uses an
option that nullifies these two options, the warning will still be
generated. This patch adds an additional information to the warning
comment to let the user know about this. It also suppresses the warning
when #ifdef INFINITY, #ifdef NAN, #ifdef NAN or #ifndef NAN are used in
the code.

(cherry picked from commit 62c352e)
tstellar pushed a commit to tstellar/llvm-project that referenced this pull request Feb 14, 2024
In llvm#76873 a warning was added
when the macros INFINITY and NAN are used in binary expressions when
-menable-no-nans or -menable-no-infs are used. If the user uses an
option that nullifies these two options, the warning will still be
generated. This patch adds an additional information to the warning
comment to let the user know about this. It also suppresses the warning
when #ifdef INFINITY, #ifdef NAN, #ifdef NAN or #ifndef NAN are used in
the code.

(cherry picked from commit 62c352e)
tstellar pushed a commit to tstellar/llvm-project that referenced this pull request Feb 14, 2024
In llvm#76873 a warning was added
when the macros INFINITY and NAN are used in binary expressions when
-menable-no-nans or -menable-no-infs are used. If the user uses an
option that nullifies these two options, the warning will still be
generated. This patch adds an additional information to the warning
comment to let the user know about this. It also suppresses the warning
when #ifdef INFINITY, #ifdef NAN, #ifdef NAN or #ifndef NAN are used in
the code.

(cherry picked from commit 62c352e)
tstellar pushed a commit to tstellar/llvm-project that referenced this pull request Feb 14, 2024
In llvm#76873 a warning was added
when the macros INFINITY and NAN are used in binary expressions when
-menable-no-nans or -menable-no-infs are used. If the user uses an
option that nullifies these two options, the warning will still be
generated. This patch adds an additional information to the warning
comment to let the user know about this. It also suppresses the warning
when #ifdef INFINITY, #ifdef NAN, #ifdef NAN or #ifndef NAN are used in
the code.

(cherry picked from commit 62c352e)
tstellar pushed a commit to tstellar/llvm-project that referenced this pull request Feb 14, 2024
In llvm#76873 a warning was added
when the macros INFINITY and NAN are used in binary expressions when
-menable-no-nans or -menable-no-infs are used. If the user uses an
option that nullifies these two options, the warning will still be
generated. This patch adds an additional information to the warning
comment to let the user know about this. It also suppresses the warning
when #ifdef INFINITY, #ifdef NAN, #ifdef NAN or #ifndef NAN are used in
the code.

(cherry picked from commit 62c352e)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants