Index: clang/include/clang/Basic/DiagnosticFrontendKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -47,6 +47,10 @@ def warn_fe_backend_unsupported_fp_exceptions : Warning< "overriding currently unsupported use of floating point exceptions " "on this target">, InGroup; +def warn_eval_method_setting_via_option_in_value_unsafe_context : Warning< + "setting the eval method via '-ffp-eval-method' has not effect when numeric " + "results of floating-point calculations aren't value-safe.">, + InGroup; def remark_fe_backend_optimization_remark : Remark<"%0">, BackendInfo, InGroup; Index: clang/include/clang/Basic/DiagnosticGroups.td =================================================================== --- clang/include/clang/Basic/DiagnosticGroups.td +++ clang/include/clang/Basic/DiagnosticGroups.td @@ -124,6 +124,7 @@ def UnsupportedNan : DiagGroup<"unsupported-nan">; def UnsupportedAbs : DiagGroup<"unsupported-abs">; def UnsupportedFPOpt : DiagGroup<"unsupported-floating-point-opt">; +def IncompatibleFPOpts : DiagGroup<"incompatible-floating-point-opts">; def UnsupportedCB : DiagGroup<"unsupported-cb">; def UnsupportedGPOpt : DiagGroup<"unsupported-gpopt">; def UnsupportedTargetOpt : DiagGroup<"unsupported-target-opt">; Index: clang/include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6475,6 +6475,12 @@ "comparing floating point with == or != is unsafe">, InGroup>, DefaultIgnore; +def warn_eval_method_setting_via_pragma_in_value_unsafe_context : Warning< + "setting the eval method via the `pragma clang fp eval_method` " + "has no effect when numeric results of floating-point calculations aren't " + "value-safe.">, + InGroup; + def warn_remainder_division_by_zero : Warning< "%select{remainder|division}0 by zero is undefined">, InGroup; Index: clang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- clang/lib/Frontend/CompilerInvocation.cpp +++ clang/lib/Frontend/CompilerInvocation.cpp @@ -503,6 +503,18 @@ Diags.Report(diag::warn_ignored_hip_only_option) << Args.getLastArg(OPT_gpu_max_threads_per_block_EQ)->getAsString(Args); + // 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. Setting the eval method in this + // case has no effect. + if (Args.hasArg(OPT_ffp_eval_method_EQ) && (LangOpts.ApproxFunc || + LangOpts.AllowFPReassoc || LangOpts.AllowRecip)) + Diags.Report( + diag::warn_eval_method_setting_via_option_in_value_unsafe_context); + // -cl-strict-aliasing needs to emit diagnostic in the case where CL > 1.0. // This option should be deprecated for CL > 1.0 because // this option was added for compatibility with OpenCL 1.0. 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) + Diag(Loc, + diag::warn_eval_method_setting_via_pragma_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 '-ffp-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 `pragma clang fp eval_method` has no effect when numeric results of floating-point calculations aren't value-safe. + return a * b + c; +}