Index: clang/include/clang/Basic/DiagnosticCommonKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticCommonKinds.td +++ clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -124,6 +124,9 @@ "'consteval' specifier is incompatible with C++ standards before C++20">, InGroup, DefaultIgnore; +def warn_eval_method_setting_is_meaningless_in_value_unsafe_context : Warning< + "setting the eval method via '-ffp-eval-method' or '#pragma clang fp eval_method' " + "has not effect when numeric results of floating-point calculations aren't value-safe.">, InGroup; } let CategoryName = "Nullability Issue" in { Index: clang/lib/Sema/Sema.cpp =================================================================== --- clang/lib/Sema/Sema.cpp +++ clang/lib/Sema/Sema.cpp @@ -252,10 +252,22 @@ // Use setting from TargetInfo. PP.setCurrentFPEvalMethod(SourceLocation(), ctxt.getTargetInfo().getFPEvalMethod()); - else + else { // Set initial value of __FLT_EVAL_METHOD__ from the command line. PP.setCurrentFPEvalMethod(SourceLocation(), getLangOpts().getFPEvalMethod()); + if (getLangOpts().ApproxFunc || getLangOpts().AllowFPReassoc || + getLangOpts().AllowRecip) + // When these options are used, the compiler is allowed to make + // transformation that may affect the final result. For example + // (x+y)+z is transformed to x+(y+z) but may not give the same + // final result; it's not value safe. + // Another example can be to simlify x/x to 1.0 but x could be 0.0, INF + // or NaN. Final result may then differ. + Diags.Report( + diag:: + warn_eval_method_setting_is_meaningless_in_value_unsafe_context); + } CurFPFeatures.setFPEvalMethod(PP.getCurrentFPEvalMethod()); } Index: clang/lib/Sema/SemaAttr.cpp =================================================================== --- clang/lib/Sema/SemaAttr.cpp +++ clang/lib/Sema/SemaAttr.cpp @@ -486,6 +486,10 @@ NewFPFeatures.setFPEvalMethodOverride(LangOptions::FEM_Extended); break; } + if (getLangOpts().ApproxFunc || getLangOpts().AllowFPReassoc || + getLangOpts().AllowRecip) + Diags.Report( + diag::warn_eval_method_setting_is_meaningless_in_value_unsafe_context); FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewFPFeatures); CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); PP.setCurrentFPEvalMethod(Loc, Value); Index: clang/test/Sema/eval-method-with-unsafe-math.c =================================================================== --- /dev/null +++ clang/test/Sema/eval-method-with-unsafe-math.c @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple x86_64-linux-gnu -ffp-eval-method=source \ +// RUN: -verify %s + +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple x86_64-linux-gnu -fapprox-func -ffp-eval-method=source \ +// RUN: %s 2>&1 | FileCheck %s --check-prefix=WARN + +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple x86_64-linux-gnu -freciprocal-math -ffp-eval-method=source \ +// RUN: %s 2>&1 | FileCheck %s --check-prefix=WARN + +// RUN: %clang_cc1 -fexperimental-strict-floating-point \ +// RUN: -triple x86_64-linux-gnu -mreassociate -ffp-eval-method=source \ +// RUN: %s 2>&1 | FileCheck %s --check-prefix=WARN + +// expected-no-diagnostics + +float f1(float a, float b, float c) { + return a * b + c; + // WARN: setting the eval method via the '-ffp-eval-method' option or '#pragma clang fp eval_method' has not effect when numeric results of floating-point calculations aren't value-safe. +} + +float f2(float a, float b, float c) { +#pragma clang fp eval_method(double) + // WARN: setting the eval method via the '-ffp-eval-method' option or '#pragma clang fp eval_method' has not effect when numeric results of floating-point calculations aren't value-safe. + return a * b + c; +}