[flang-commits] [flang] [flang] Better error reporting for MOD/MODULO/NEAREST (PR #96114)
Peter Klausler via flang-commits
flang-commits at lists.llvm.org
Wed Jun 19 13:40:26 PDT 2024
https://github.com/klausler created https://github.com/llvm/llvm-project/pull/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.
>From 3e9e9f7de40b0e0689252fb3dfc0e9f8dc6bcb01 Mon Sep 17 00:00:00 2001
From: Peter Klausler <pklausler at nvidia.com>
Date: Wed, 19 Jun 2024 13:24:21 -0700
Subject: [PATCH] [flang] Better error reporting for MOD/MODULO/NEAREST
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.
---
flang/lib/Evaluate/fold-integer.cpp | 30 +++++++++--
flang/lib/Evaluate/fold-real.cpp | 79 +++++++++++++++++++---------
flang/test/Evaluate/fold-nearest.f90 | 6 +++
flang/test/Evaluate/folding04.f90 | 13 ++++-
4 files changed, 99 insertions(+), 29 deletions(-)
diff --git a/flang/lib/Evaluate/fold-integer.cpp b/flang/lib/Evaluate/fold-integer.cpp
index b76b9d49b5823..981cdff7f350b 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 f71addcc4094a..69c7a924cc1c3 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 bd8b020c392ac..a7366e6d75407 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 86ae8debd6ef1..c7815b0340360 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