Skip to content

Commit aaea4e3

Browse files
committed
[flang] Add more diagnostic for MAX/MIN intrinsic
Fix llvm#56303 Differential Revision: https://reviews.llvm.org/D137742
1 parent 6f81795 commit aaea4e3

File tree

2 files changed

+84
-2
lines changed

2 files changed

+84
-2
lines changed

flang/lib/Evaluate/intrinsics.cpp

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1462,6 +1462,37 @@ static bool CheckMaxMinArgument(std::optional<parser::CharBlock> keyword,
14621462
return true;
14631463
}
14641464

1465+
static void CheckMaxMinA1A2Argument(const ActualArguments &arguments,
1466+
std::set<parser::CharBlock> &set, parser::ContextualMessages &messages) {
1467+
parser::CharBlock kwA1{"a1", 2};
1468+
parser::CharBlock kwA2{"a2", 2};
1469+
bool missingA1{set.find(kwA1) == set.end()};
1470+
bool missingA2{set.find(kwA2) == set.end()};
1471+
1472+
if (arguments.size() > 1) {
1473+
if (arguments.at(0)->keyword()) {
1474+
// If the keyword is specified in the first argument, the following
1475+
// arguments must have the keywords.
1476+
if (missingA1 && missingA2) {
1477+
messages.Say("missing mandatory '%s=' and '%s=' arguments"_err_en_US,
1478+
kwA1.ToString(), kwA2.ToString());
1479+
} else if (missingA1 && !missingA2) {
1480+
messages.Say(
1481+
"missing mandatory '%s=' argument"_err_en_US, kwA1.ToString());
1482+
} else if (!missingA1 && missingA2) {
1483+
messages.Say(
1484+
"missing mandatory '%s=' argument"_err_en_US, kwA2.ToString());
1485+
}
1486+
} else if (arguments.at(1)->keyword()) {
1487+
// No keyword is specified in the first argument.
1488+
if (missingA1 && missingA2) {
1489+
messages.Say(
1490+
"missing mandatory '%s=' argument"_err_en_US, kwA2.ToString());
1491+
}
1492+
}
1493+
}
1494+
}
1495+
14651496
static bool CheckAtomicKind(const ActualArgument &arg,
14661497
const semantics::Scope *builtinsScope,
14671498
parser::ContextualMessages &messages) {
@@ -1570,6 +1601,17 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
15701601
}
15711602
}
15721603

1604+
if (isMaxMin) {
1605+
int nArgs{0};
1606+
// max() / max(x) is invalid
1607+
while ((arguments.size() + nArgs) < 2) {
1608+
actualForDummy.push_back(nullptr);
1609+
nArgs++;
1610+
}
1611+
1612+
CheckMaxMinA1A2Argument(arguments, maxMinKeywords, messages);
1613+
}
1614+
15731615
std::size_t dummies{actualForDummy.size()};
15741616

15751617
// Check types and kinds of the actual arguments against the intrinsic's
@@ -1590,7 +1632,23 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
15901632
const ActualArgument *arg{actualForDummy[j]};
15911633
if (!arg) {
15921634
if (d.optionality == Optionality::required) {
1593-
messages.Say("missing mandatory '%s=' argument"_err_en_US, d.keyword);
1635+
std::string kw{d.keyword};
1636+
if (isMaxMin && maxMinKeywords.size() == 1) {
1637+
// max(a1=x) or max(a2=x)
1638+
const auto kwA1{dummy[0].keyword};
1639+
const auto kwA2{dummy[1].keyword};
1640+
if (maxMinKeywords.begin()->ToString().compare(kwA1) == 0) {
1641+
messages.Say("missing mandatory 'a2=' argument"_err_en_US);
1642+
} else if (maxMinKeywords.begin()->ToString().compare(kwA2) == 0) {
1643+
messages.Say("missing mandatory 'a1=' argument"_err_en_US);
1644+
} else {
1645+
messages.Say(
1646+
"missing mandatory 'a1=' and 'a2=' arguments"_err_en_US);
1647+
}
1648+
} else {
1649+
messages.Say(
1650+
"missing mandatory '%s=' argument"_err_en_US, kw.c_str());
1651+
}
15941652
return std::nullopt; // missing non-OPTIONAL argument
15951653
} else {
15961654
continue;

flang/test/Semantics/call23.f90

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
! RUN: %python %S/test_errors.py %s %flang_fc1
22
! Check errors on MAX/MIN with keywords, a weird case in Fortran
3-
real :: x = 0.0 ! prevent folding
3+
real :: x = 0.0, y = 0.0 , y1 = 0.0 ! prevent folding
44
!ERROR: Argument keyword 'a1=' was repeated in call to 'max'
55
print *, max(a1=x,a1=1)
66
!ERROR: Keyword argument 'a1=' has already been specified positionally (#1) in this procedure reference
@@ -9,4 +9,28 @@
99
print *, max(x,0,a99=0) ! ok
1010
!ERROR: Argument keyword 'a06=' is not known in call to 'max'
1111
print *, max(a1=x,a2=0,a06=0)
12+
!ERROR: missing mandatory 'a2=' argument
13+
print *, max(a3=y, a1=x)
14+
!ERROR: missing mandatory 'a1=' argument
15+
print *, max(a3=y, a2=x)
16+
!ERROR: missing mandatory 'a1=' and 'a2=' arguments
17+
print *, max(a3=y, a4=x)
18+
!ERROR: missing mandatory 'a2=' argument
19+
print *, max(y1, a3=y)
20+
!ERROR: missing mandatory 'a1=' and 'a2=' arguments
21+
print *, max(a9=x, a5=y, a4=y1)
22+
!ERROR: missing mandatory 'a2=' argument
23+
print *, max(x)
24+
!ERROR: missing mandatory 'a2=' argument
25+
print *, max(a1=x)
26+
!ERROR: missing mandatory 'a1=' argument
27+
print *, max(a2=y)
28+
!ERROR: missing mandatory 'a1=' and 'a2=' arguments
29+
print *, max(a3=x)
30+
!ERROR: Argument keyword 'a0=' is not known in call to 'max'
31+
print *, max(a0=x)
32+
!ERROR: Argument keyword 'a03=' is not known in call to 'max'
33+
print *, max(a03=x)
34+
!ERROR: Argument keyword 'abad=' is not known in call to 'max'
35+
print *, max(abad=x)
1236
end

0 commit comments

Comments
 (0)