[flang-commits] [flang] 317277e - [flang] Better error reporting for MOD/MODULO/NEAREST (#96114)
via flang-commits
flang-commits at lists.llvm.org
Mon Jun 24 09:21:09 PDT 2024
Author: Peter Klausler
Date: 2024-06-24T09:21:06-07:00
New Revision: 317277e4f961edf13132914a58a26408db4ab0aa
URL: https://github.com/llvm/llvm-project/commit/317277e4f961edf13132914a58a26408db4ab0aa
DIFF: https://github.com/llvm/llvm-project/commit/317277e4f961edf13132914a58a26408db4ab0aa.diff
LOG: [flang] Better error reporting for MOD/MODULO/NEAREST (#96114)
When the second argument to these intrinsic functions is a scalar
constant zero, emit a warning (if enabled) even if the first argument is
not a constant.
Added:
Modified:
flang/lib/Evaluate/fold-integer.cpp
flang/lib/Evaluate/fold-real.cpp
flang/test/Evaluate/fold-nearest.f90
flang/test/Evaluate/folding04.f90
Removed:
################################################################################
diff --git a/flang/lib/Evaluate/fold-integer.cpp b/flang/lib/Evaluate/fold-integer.cpp
index b76b9d49b58238..981cdff7f350b1 100644
--- a/flang/lib/Evaluate/fold-integer.cpp
+++ b/flang/lib/Evaluate/fold-integer.cpp
@@ -1116,14 +1116,25 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
return FoldMaxvalMinval<T>(
context, std::move(funcRef), RelationalOperator::LT, T::Scalar::HUGE());
} else if (name == "mod") {
+ bool badPConst{false};
+ if (auto *pExpr{UnwrapExpr<Expr<T>>(args[1])}) {
+ *pExpr = Fold(context, std::move(*pExpr));
+ if (auto pConst{GetScalarConstantValue<T>(*pExpr)}; pConst &&
+ pConst->IsZero() &&
+ context.languageFeatures().ShouldWarn(
+ common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
+ context.messages().Say("MOD: P argument is zero"_warn_en_US);
+ badPConst = true;
+ }
+ }
return FoldElementalIntrinsic<T, T, T>(context, std::move(funcRef),
ScalarFuncWithContext<T, T, T>(
- [](FoldingContext &context, const Scalar<T> &x,
+ [badPConst](FoldingContext &context, const Scalar<T> &x,
const Scalar<T> &y) -> Scalar<T> {
auto quotRem{x.DivideSigned(y)};
if (context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
- if (quotRem.divisionByZero) {
+ if (!badPConst && quotRem.divisionByZero) {
context.messages().Say("mod() by zero"_warn_en_US);
} else if (quotRem.overflow) {
context.messages().Say("mod() folding overflowed"_warn_en_US);
@@ -1132,12 +1143,23 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
return quotRem.remainder;
}));
} else if (name == "modulo") {
+ bool badPConst{false};
+ if (auto *pExpr{UnwrapExpr<Expr<T>>(args[1])}) {
+ *pExpr = Fold(context, std::move(*pExpr));
+ if (auto pConst{GetScalarConstantValue<T>(*pExpr)}; pConst &&
+ pConst->IsZero() &&
+ context.languageFeatures().ShouldWarn(
+ common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
+ context.messages().Say("MODULO: P argument is zero"_warn_en_US);
+ badPConst = true;
+ }
+ }
return FoldElementalIntrinsic<T, T, T>(context, std::move(funcRef),
- ScalarFuncWithContext<T, T, T>([](FoldingContext &context,
+ ScalarFuncWithContext<T, T, T>([badPConst](FoldingContext &context,
const Scalar<T> &x,
const Scalar<T> &y) -> Scalar<T> {
auto result{x.MODULO(y)};
- if (result.overflow &&
+ if (!badPConst && result.overflow &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingException)) {
context.messages().Say("modulo() folding overflowed"_warn_en_US);
diff --git a/flang/lib/Evaluate/fold-real.cpp b/flang/lib/Evaluate/fold-real.cpp
index f71addcc4094ac..69c7a924cc1c35 100644
--- a/flang/lib/Evaluate/fold-real.cpp
+++ b/flang/lib/Evaluate/fold-real.cpp
@@ -303,41 +303,72 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
context, std::move(funcRef), RelationalOperator::LT, T::Scalar::HUGE());
} else if (name == "mod") {
CHECK(args.size() == 2);
+ bool badPConst{false};
+ if (auto *pExpr{UnwrapExpr<Expr<T>>(args[1])}) {
+ *pExpr = Fold(context, std::move(*pExpr));
+ if (auto pConst{GetScalarConstantValue<T>(*pExpr)}; pConst &&
+ pConst->IsZero() &&
+ context.languageFeatures().ShouldWarn(
+ common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
+ context.messages().Say("MOD: P argument is zero"_warn_en_US);
+ badPConst = true;
+ }
+ }
return FoldElementalIntrinsic<T, T, T>(context, std::move(funcRef),
- ScalarFunc<T, T, T>(
- [&context](const Scalar<T> &x, const Scalar<T> &y) -> Scalar<T> {
- auto result{x.MOD(y)};
- if (result.flags.test(RealFlag::DivideByZero) &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
- context.messages().Say(
- "second argument to MOD must not be zero"_warn_en_US);
- }
- return result.value;
- }));
+ ScalarFunc<T, T, T>([&context, badPConst](const Scalar<T> &x,
+ const Scalar<T> &y) -> Scalar<T> {
+ auto result{x.MOD(y)};
+ if (!badPConst && result.flags.test(RealFlag::DivideByZero) &&
+ context.languageFeatures().ShouldWarn(
+ common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
+ context.messages().Say(
+ "second argument to MOD must not be zero"_warn_en_US);
+ }
+ return result.value;
+ }));
} else if (name == "modulo") {
CHECK(args.size() == 2);
+ bool badPConst{false};
+ if (auto *pExpr{UnwrapExpr<Expr<T>>(args[1])}) {
+ *pExpr = Fold(context, std::move(*pExpr));
+ if (auto pConst{GetScalarConstantValue<T>(*pExpr)}; pConst &&
+ pConst->IsZero() &&
+ context.languageFeatures().ShouldWarn(
+ common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
+ context.messages().Say("MODULO: P argument is zero"_warn_en_US);
+ badPConst = true;
+ }
+ }
return FoldElementalIntrinsic<T, T, T>(context, std::move(funcRef),
- ScalarFunc<T, T, T>(
- [&context](const Scalar<T> &x, const Scalar<T> &y) -> Scalar<T> {
- auto result{x.MODULO(y)};
- if (result.flags.test(RealFlag::DivideByZero) &&
- context.languageFeatures().ShouldWarn(
- common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
- context.messages().Say(
- "second argument to MODULO must not be zero"_warn_en_US);
- }
- return result.value;
- }));
+ ScalarFunc<T, T, T>([&context, badPConst](const Scalar<T> &x,
+ const Scalar<T> &y) -> Scalar<T> {
+ auto result{x.MODULO(y)};
+ if (!badPConst && result.flags.test(RealFlag::DivideByZero) &&
+ context.languageFeatures().ShouldWarn(
+ common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
+ context.messages().Say(
+ "second argument to MODULO must not be zero"_warn_en_US);
+ }
+ return result.value;
+ }));
} else if (name == "nearest") {
- if (const auto *sExpr{UnwrapExpr<Expr<SomeReal>>(args[1])}) {
+ if (auto *sExpr{UnwrapExpr<Expr<SomeReal>>(args[1])}) {
+ *sExpr = Fold(context, std::move(*sExpr));
return common::visit(
[&](const auto &sVal) {
using TS = ResultType<decltype(sVal)>;
+ bool badSConst{false};
+ if (auto sConst{GetScalarConstantValue<TS>(sVal)}; sConst &&
+ sConst->IsZero() &&
+ context.languageFeatures().ShouldWarn(
+ common::UsageWarning::FoldingValueChecks)) {
+ context.messages().Say("NEAREST: S argument is zero"_warn_en_US);
+ badSConst = true;
+ }
return FoldElementalIntrinsic<T, T, TS>(context, std::move(funcRef),
ScalarFunc<T, T, TS>([&](const Scalar<T> &x,
const Scalar<TS> &s) -> Scalar<T> {
- if (s.IsZero() &&
+ if (!badSConst && s.IsZero() &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::FoldingValueChecks)) {
context.messages().Say(
diff --git a/flang/test/Evaluate/fold-nearest.f90 b/flang/test/Evaluate/fold-nearest.f90
index bd8b020c392ac3..a7366e6d75407e 100644
--- a/flang/test/Evaluate/fold-nearest.f90
+++ b/flang/test/Evaluate/fold-nearest.f90
@@ -28,6 +28,12 @@ module m1
logical, parameter :: test_15 = nearest(negZero, 0.) == minSubnormal
logical, parameter :: test_16 = nearest(tiny(1.),-1.) == 1.1754942E-38
logical, parameter :: test_17 = nearest(tiny(1.),1.) == 1.1754945E-38
+ contains
+ subroutine subr(a)
+ real, intent(in) :: a
+ !WARN: warning: NEAREST: S argument is zero
+ print *, nearest(a, 0.)
+ end
end module
module m2
diff --git a/flang/test/Evaluate/folding04.f90 b/flang/test/Evaluate/folding04.f90
index 86ae8debd6ef12..c7815b03403608 100644
--- a/flang/test/Evaluate/folding04.f90
+++ b/flang/test/Evaluate/folding04.f90
@@ -32,11 +32,22 @@ module real_tests
!WARN: warning: invalid argument on evaluation of intrinsic function or operation
real(4), parameter :: nan_r4_acos5 = acos(r4_pinf)
TEST_ISNAN(nan_r4_acos5)
- !WARN: warning: second argument to MOD must not be zero
+ !WARN: warning: MOD: P argument is zero
real(4), parameter :: nan_r4_mod = mod(3.5, 0.)
TEST_ISNAN(nan_r4_mod)
!WARN: warning: overflow on evaluation of intrinsic function or operation
logical, parameter :: test_exp_overflow = exp(256._4).EQ.r4_pinf
+ contains
+ subroutine s1(a,j)
+ !WARN: warning: MOD: P argument is zero
+ print *, mod(a, 0.)
+ !WARN: warning: MODULO: P argument is zero
+ print *, modulo(a, 0.)
+ !WARN: warning: MOD: P argument is zero
+ print *, mod(j, 0.)
+ !WARN: warning: MODULO: P argument is zero
+ print *, modulo(j, 0.)
+ end
end module
module parentheses
More information about the flang-commits
mailing list