Skip to content

Commit 317277e

Browse files
authored
[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.
1 parent 3602efa commit 317277e

File tree

4 files changed

+99
-29
lines changed

4 files changed

+99
-29
lines changed

flang/lib/Evaluate/fold-integer.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1116,14 +1116,25 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
11161116
return FoldMaxvalMinval<T>(
11171117
context, std::move(funcRef), RelationalOperator::LT, T::Scalar::HUGE());
11181118
} else if (name == "mod") {
1119+
bool badPConst{false};
1120+
if (auto *pExpr{UnwrapExpr<Expr<T>>(args[1])}) {
1121+
*pExpr = Fold(context, std::move(*pExpr));
1122+
if (auto pConst{GetScalarConstantValue<T>(*pExpr)}; pConst &&
1123+
pConst->IsZero() &&
1124+
context.languageFeatures().ShouldWarn(
1125+
common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
1126+
context.messages().Say("MOD: P argument is zero"_warn_en_US);
1127+
badPConst = true;
1128+
}
1129+
}
11191130
return FoldElementalIntrinsic<T, T, T>(context, std::move(funcRef),
11201131
ScalarFuncWithContext<T, T, T>(
1121-
[](FoldingContext &context, const Scalar<T> &x,
1132+
[badPConst](FoldingContext &context, const Scalar<T> &x,
11221133
const Scalar<T> &y) -> Scalar<T> {
11231134
auto quotRem{x.DivideSigned(y)};
11241135
if (context.languageFeatures().ShouldWarn(
11251136
common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
1126-
if (quotRem.divisionByZero) {
1137+
if (!badPConst && quotRem.divisionByZero) {
11271138
context.messages().Say("mod() by zero"_warn_en_US);
11281139
} else if (quotRem.overflow) {
11291140
context.messages().Say("mod() folding overflowed"_warn_en_US);
@@ -1132,12 +1143,23 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
11321143
return quotRem.remainder;
11331144
}));
11341145
} else if (name == "modulo") {
1146+
bool badPConst{false};
1147+
if (auto *pExpr{UnwrapExpr<Expr<T>>(args[1])}) {
1148+
*pExpr = Fold(context, std::move(*pExpr));
1149+
if (auto pConst{GetScalarConstantValue<T>(*pExpr)}; pConst &&
1150+
pConst->IsZero() &&
1151+
context.languageFeatures().ShouldWarn(
1152+
common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
1153+
context.messages().Say("MODULO: P argument is zero"_warn_en_US);
1154+
badPConst = true;
1155+
}
1156+
}
11351157
return FoldElementalIntrinsic<T, T, T>(context, std::move(funcRef),
1136-
ScalarFuncWithContext<T, T, T>([](FoldingContext &context,
1158+
ScalarFuncWithContext<T, T, T>([badPConst](FoldingContext &context,
11371159
const Scalar<T> &x,
11381160
const Scalar<T> &y) -> Scalar<T> {
11391161
auto result{x.MODULO(y)};
1140-
if (result.overflow &&
1162+
if (!badPConst && result.overflow &&
11411163
context.languageFeatures().ShouldWarn(
11421164
common::UsageWarning::FoldingException)) {
11431165
context.messages().Say("modulo() folding overflowed"_warn_en_US);

flang/lib/Evaluate/fold-real.cpp

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -303,41 +303,72 @@ Expr<Type<TypeCategory::Real, KIND>> FoldIntrinsicFunction(
303303
context, std::move(funcRef), RelationalOperator::LT, T::Scalar::HUGE());
304304
} else if (name == "mod") {
305305
CHECK(args.size() == 2);
306+
bool badPConst{false};
307+
if (auto *pExpr{UnwrapExpr<Expr<T>>(args[1])}) {
308+
*pExpr = Fold(context, std::move(*pExpr));
309+
if (auto pConst{GetScalarConstantValue<T>(*pExpr)}; pConst &&
310+
pConst->IsZero() &&
311+
context.languageFeatures().ShouldWarn(
312+
common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
313+
context.messages().Say("MOD: P argument is zero"_warn_en_US);
314+
badPConst = true;
315+
}
316+
}
306317
return FoldElementalIntrinsic<T, T, T>(context, std::move(funcRef),
307-
ScalarFunc<T, T, T>(
308-
[&context](const Scalar<T> &x, const Scalar<T> &y) -> Scalar<T> {
309-
auto result{x.MOD(y)};
310-
if (result.flags.test(RealFlag::DivideByZero) &&
311-
context.languageFeatures().ShouldWarn(
312-
common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
313-
context.messages().Say(
314-
"second argument to MOD must not be zero"_warn_en_US);
315-
}
316-
return result.value;
317-
}));
318+
ScalarFunc<T, T, T>([&context, badPConst](const Scalar<T> &x,
319+
const Scalar<T> &y) -> Scalar<T> {
320+
auto result{x.MOD(y)};
321+
if (!badPConst && result.flags.test(RealFlag::DivideByZero) &&
322+
context.languageFeatures().ShouldWarn(
323+
common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
324+
context.messages().Say(
325+
"second argument to MOD must not be zero"_warn_en_US);
326+
}
327+
return result.value;
328+
}));
318329
} else if (name == "modulo") {
319330
CHECK(args.size() == 2);
331+
bool badPConst{false};
332+
if (auto *pExpr{UnwrapExpr<Expr<T>>(args[1])}) {
333+
*pExpr = Fold(context, std::move(*pExpr));
334+
if (auto pConst{GetScalarConstantValue<T>(*pExpr)}; pConst &&
335+
pConst->IsZero() &&
336+
context.languageFeatures().ShouldWarn(
337+
common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
338+
context.messages().Say("MODULO: P argument is zero"_warn_en_US);
339+
badPConst = true;
340+
}
341+
}
320342
return FoldElementalIntrinsic<T, T, T>(context, std::move(funcRef),
321-
ScalarFunc<T, T, T>(
322-
[&context](const Scalar<T> &x, const Scalar<T> &y) -> Scalar<T> {
323-
auto result{x.MODULO(y)};
324-
if (result.flags.test(RealFlag::DivideByZero) &&
325-
context.languageFeatures().ShouldWarn(
326-
common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
327-
context.messages().Say(
328-
"second argument to MODULO must not be zero"_warn_en_US);
329-
}
330-
return result.value;
331-
}));
343+
ScalarFunc<T, T, T>([&context, badPConst](const Scalar<T> &x,
344+
const Scalar<T> &y) -> Scalar<T> {
345+
auto result{x.MODULO(y)};
346+
if (!badPConst && result.flags.test(RealFlag::DivideByZero) &&
347+
context.languageFeatures().ShouldWarn(
348+
common::UsageWarning::FoldingAvoidsRuntimeCrash)) {
349+
context.messages().Say(
350+
"second argument to MODULO must not be zero"_warn_en_US);
351+
}
352+
return result.value;
353+
}));
332354
} else if (name == "nearest") {
333-
if (const auto *sExpr{UnwrapExpr<Expr<SomeReal>>(args[1])}) {
355+
if (auto *sExpr{UnwrapExpr<Expr<SomeReal>>(args[1])}) {
356+
*sExpr = Fold(context, std::move(*sExpr));
334357
return common::visit(
335358
[&](const auto &sVal) {
336359
using TS = ResultType<decltype(sVal)>;
360+
bool badSConst{false};
361+
if (auto sConst{GetScalarConstantValue<TS>(sVal)}; sConst &&
362+
sConst->IsZero() &&
363+
context.languageFeatures().ShouldWarn(
364+
common::UsageWarning::FoldingValueChecks)) {
365+
context.messages().Say("NEAREST: S argument is zero"_warn_en_US);
366+
badSConst = true;
367+
}
337368
return FoldElementalIntrinsic<T, T, TS>(context, std::move(funcRef),
338369
ScalarFunc<T, T, TS>([&](const Scalar<T> &x,
339370
const Scalar<TS> &s) -> Scalar<T> {
340-
if (s.IsZero() &&
371+
if (!badSConst && s.IsZero() &&
341372
context.languageFeatures().ShouldWarn(
342373
common::UsageWarning::FoldingValueChecks)) {
343374
context.messages().Say(

flang/test/Evaluate/fold-nearest.f90

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ module m1
2828
logical, parameter :: test_15 = nearest(negZero, 0.) == minSubnormal
2929
logical, parameter :: test_16 = nearest(tiny(1.),-1.) == 1.1754942E-38
3030
logical, parameter :: test_17 = nearest(tiny(1.),1.) == 1.1754945E-38
31+
contains
32+
subroutine subr(a)
33+
real, intent(in) :: a
34+
!WARN: warning: NEAREST: S argument is zero
35+
print *, nearest(a, 0.)
36+
end
3137
end module
3238

3339
module m2

flang/test/Evaluate/folding04.f90

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,22 @@ module real_tests
3232
!WARN: warning: invalid argument on evaluation of intrinsic function or operation
3333
real(4), parameter :: nan_r4_acos5 = acos(r4_pinf)
3434
TEST_ISNAN(nan_r4_acos5)
35-
!WARN: warning: second argument to MOD must not be zero
35+
!WARN: warning: MOD: P argument is zero
3636
real(4), parameter :: nan_r4_mod = mod(3.5, 0.)
3737
TEST_ISNAN(nan_r4_mod)
3838
!WARN: warning: overflow on evaluation of intrinsic function or operation
3939
logical, parameter :: test_exp_overflow = exp(256._4).EQ.r4_pinf
40+
contains
41+
subroutine s1(a,j)
42+
!WARN: warning: MOD: P argument is zero
43+
print *, mod(a, 0.)
44+
!WARN: warning: MODULO: P argument is zero
45+
print *, modulo(a, 0.)
46+
!WARN: warning: MOD: P argument is zero
47+
print *, mod(j, 0.)
48+
!WARN: warning: MODULO: P argument is zero
49+
print *, modulo(j, 0.)
50+
end
4051
end module
4152

4253
module parentheses

0 commit comments

Comments
 (0)