diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp --- a/flang/lib/Evaluate/intrinsics.cpp +++ b/flang/lib/Evaluate/intrinsics.cpp @@ -1462,6 +1462,37 @@ return true; } +static void CheckMaxMinA1A2Argument(const ActualArguments &arguments, + std::set &set, parser::ContextualMessages &messages) { + parser::CharBlock kwA1{"a1", 2}; + parser::CharBlock kwA2{"a2", 2}; + bool missingA1{set.find(kwA1) == set.end()}; + bool missingA2{set.find(kwA2) == set.end()}; + + if (arguments.size() > 1) { + if (arguments.at(0)->keyword()) { + // If the keyword is specified in the first argument, the following + // arguments must have the keywords. + if (missingA1 && missingA2) { + messages.Say("missing mandatory '%s=' and '%s=' arguments"_err_en_US, + kwA1.ToString(), kwA2.ToString()); + } else if (missingA1 && !missingA2) { + messages.Say( + "missing mandatory '%s=' argument"_err_en_US, kwA1.ToString()); + } else if (!missingA1 && missingA2) { + messages.Say( + "missing mandatory '%s=' argument"_err_en_US, kwA2.ToString()); + } + } else if (arguments.at(1)->keyword()) { + // No keyword is specified in the first argument. + if (missingA1 && missingA2) { + messages.Say( + "missing mandatory '%s=' argument"_err_en_US, kwA2.ToString()); + } + } + } +} + static bool CheckAtomicKind(const ActualArgument &arg, const semantics::Scope *builtinsScope, parser::ContextualMessages &messages) { @@ -1570,6 +1601,17 @@ } } + if (isMaxMin) { + int nArgs{0}; + // max() / max(x) is invalid + while ((arguments.size() + nArgs) < 2) { + actualForDummy.push_back(nullptr); + nArgs++; + } + + CheckMaxMinA1A2Argument(arguments, maxMinKeywords, messages); + } + std::size_t dummies{actualForDummy.size()}; // Check types and kinds of the actual arguments against the intrinsic's @@ -1590,7 +1632,23 @@ const ActualArgument *arg{actualForDummy[j]}; if (!arg) { if (d.optionality == Optionality::required) { - messages.Say("missing mandatory '%s=' argument"_err_en_US, d.keyword); + std::string kw{d.keyword}; + if (isMaxMin && maxMinKeywords.size() == 1) { + // max(a1=x) or max(a2=x) + const auto kwA1{dummy[0].keyword}; + const auto kwA2{dummy[1].keyword}; + if (maxMinKeywords.begin()->ToString().compare(kwA1) == 0) { + messages.Say("missing mandatory 'a2=' argument"_err_en_US); + } else if (maxMinKeywords.begin()->ToString().compare(kwA2) == 0) { + messages.Say("missing mandatory 'a1=' argument"_err_en_US); + } else { + messages.Say( + "missing mandatory 'a1=' and 'a2=' arguments"_err_en_US); + } + } else { + messages.Say( + "missing mandatory '%s=' argument"_err_en_US, kw.c_str()); + } return std::nullopt; // missing non-OPTIONAL argument } else { continue; diff --git a/flang/test/Semantics/call23.f90 b/flang/test/Semantics/call23.f90 --- a/flang/test/Semantics/call23.f90 +++ b/flang/test/Semantics/call23.f90 @@ -1,6 +1,6 @@ ! RUN: %python %S/test_errors.py %s %flang_fc1 ! Check errors on MAX/MIN with keywords, a weird case in Fortran -real :: x = 0.0 ! prevent folding +real :: x = 0.0, y = 0.0 , y1 = 0.0 ! prevent folding !ERROR: Argument keyword 'a1=' was repeated in call to 'max' print *, max(a1=x,a1=1) !ERROR: Keyword argument 'a1=' has already been specified positionally (#1) in this procedure reference @@ -9,4 +9,28 @@ print *, max(x,0,a99=0) ! ok !ERROR: Argument keyword 'a06=' is not known in call to 'max' print *, max(a1=x,a2=0,a06=0) +!ERROR: missing mandatory 'a2=' argument +print *, max(a3=y, a1=x) +!ERROR: missing mandatory 'a1=' argument +print *, max(a3=y, a2=x) +!ERROR: missing mandatory 'a1=' and 'a2=' arguments +print *, max(a3=y, a4=x) +!ERROR: missing mandatory 'a2=' argument +print *, max(y1, a3=y) +!ERROR: missing mandatory 'a1=' and 'a2=' arguments +print *, max(a9=x, a5=y, a4=y1) +!ERROR: missing mandatory 'a2=' argument +print *, max(x) +!ERROR: missing mandatory 'a2=' argument +print *, max(a1=x) +!ERROR: missing mandatory 'a1=' argument +print *, max(a2=y) +!ERROR: missing mandatory 'a1=' and 'a2=' arguments +print *, max(a3=x) +!ERROR: Argument keyword 'a0=' is not known in call to 'max' +print *, max(a0=x) +!ERROR: Argument keyword 'a03=' is not known in call to 'max' +print *, max(a03=x) +!ERROR: Argument keyword 'abad=' is not known in call to 'max' +print *, max(abad=x) end