Skip to content

[flang] Better error reporting for MOD/MODULO/NEAREST #96114

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 1 commit into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions flang/lib/Evaluate/fold-integer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
79 changes: 55 additions & 24 deletions flang/lib/Evaluate/fold-real.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
6 changes: 6 additions & 0 deletions flang/test/Evaluate/fold-nearest.f90
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 12 additions & 1 deletion flang/test/Evaluate/folding04.f90
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading