From e3b6b9299c9691c7dcde0f80b8af679a50540979 Mon Sep 17 00:00:00 2001 From: Peter Klausler Date: Tue, 14 Mar 2023 17:11:48 -0700 Subject: [PATCH] [flang] Emit error when a positional actual argument follows an argument with a keyword A positional (non-keyword) actual argument or alternate return label is not allowed to follow an actual argument with a keyword. Differential Revision: https://reviews.llvm.org/D146575 --- flang/lib/Evaluate/intrinsics.cpp | 36 +++++++++++++++++++++++----------- flang/lib/Semantics/check-call.cpp | 11 ++++++++++- flang/test/Evaluate/fold-ishftc.f90 | 2 +- flang/test/Semantics/collectives01.f90 | 2 +- flang/test/Semantics/collectives02.f90 | 2 +- flang/test/Semantics/collectives03.f90 | 2 +- flang/test/Semantics/collectives04.f90 | 2 +- flang/test/Semantics/lcobound.f90 | 3 +++ flang/test/Semantics/ucobound.f90 | 3 +++ 9 files changed, 46 insertions(+), 17 deletions(-) diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp index 7e8285a..a27d211 100644 --- a/flang/lib/Evaluate/intrinsics.cpp +++ b/flang/lib/Evaluate/intrinsics.cpp @@ -1543,17 +1543,32 @@ std::optional IntrinsicInterface::Match( dummy[dummyArgPatterns - 1].optionality == Optionality::repeats}; std::vector actualForDummy( isMaxMin ? 0 : dummyArgPatterns, nullptr); - int missingActualArguments{0}; + bool anyMissingActualArgument{false}; std::set maxMinKeywords; + bool anyKeyword{false}; + int which{0}; for (std::optional &arg : arguments) { - if (!arg) { - ++missingActualArguments; - } else if (arg->isAlternateReturn()) { - messages.Say(arg->sourceLocation(), - "alternate return specifier not acceptable on call to intrinsic '%s'"_err_en_US, - name); - return std::nullopt; - } else if (isMaxMin) { + ++which; + if (arg) { + if (arg->isAlternateReturn()) { + messages.Say(arg->sourceLocation(), + "alternate return specifier not acceptable on call to intrinsic '%s'"_err_en_US, + name); + return std::nullopt; + } + if (arg->keyword()) { + anyKeyword = true; + } else if (anyKeyword) { + messages.Say(arg ? arg->sourceLocation() : std::nullopt, + "actual argument #%d without a keyword may not follow an actual argument with a keyword"_err_en_US, + which); + return std::nullopt; + } + } else { + anyMissingActualArgument = true; + continue; + } + if (isMaxMin) { if (CheckMaxMinArgument(arg->keyword(), maxMinKeywords, name, messages)) { actualForDummy.push_back(&*arg); } else { @@ -1561,7 +1576,6 @@ std::optional IntrinsicInterface::Match( } } else { bool found{false}; - int slot{missingActualArguments}; for (std::size_t j{0}; j < dummyArgPatterns && !found; ++j) { if (dummy[j].optionality == Optionality::missing) { continue; @@ -1584,7 +1598,7 @@ std::optional IntrinsicInterface::Match( } } } else { - found = !actualForDummy[j] && slot-- == 0; + found = !actualForDummy[j] && !anyMissingActualArgument; } if (found) { actualForDummy[j] = &*arg; diff --git a/flang/lib/Semantics/check-call.cpp b/flang/lib/Semantics/check-call.cpp index e4b65fc..d398c5e 100644 --- a/flang/lib/Semantics/check-call.cpp +++ b/flang/lib/Semantics/check-call.cpp @@ -873,8 +873,11 @@ static void RearrangeArguments(const characteristics::Procedure &proc, actuals.size(), proc.dummyArguments.size()); } std::map kwArgs; + bool anyKeyword{false}; + int which{1}; for (auto &x : actuals) { - if (x && x->keyword()) { + if (!x) { + } else if (x->keyword()) { auto emplaced{ kwArgs.try_emplace(x->keyword()->ToString(), std::move(*x))}; if (!emplaced.second) { @@ -883,7 +886,13 @@ static void RearrangeArguments(const characteristics::Procedure &proc, *x->keyword()); } x.reset(); + anyKeyword = true; + } else if (anyKeyword) { + messages.Say(x ? x->sourceLocation() : std::nullopt, + "Actual argument #%d without a keyword may not follow any actual argument with a keyword"_err_en_US, + which); } + ++which; } if (!kwArgs.empty()) { int index{0}; diff --git a/flang/test/Evaluate/fold-ishftc.f90 b/flang/test/Evaluate/fold-ishftc.f90 index 7051348..9fca017 100644 --- a/flang/test/Evaluate/fold-ishftc.f90 +++ b/flang/test/Evaluate/fold-ishftc.f90 @@ -1,7 +1,7 @@ ! RUN: %python %S/test_folding.py %s %flang_fc1 ! Tests folding of ISHFTC module m - integer, parameter :: shift8s(*) = ishftc(257, shift = [(ict, ict = -8, 8)], 8) + integer, parameter :: shift8s(*) = ishftc(257, shift = [(ict, ict = -8, 8)], size=8) integer, parameter :: expect1(*) = 256 + [1, 2, 4, 8, 16, 32, 64, 128, & 1, 2, 4, 8, 16, 32, 64, 128, 1] logical, parameter :: test_1 = all(shift8s == expect1) diff --git a/flang/test/Semantics/collectives01.f90 b/flang/test/Semantics/collectives01.f90 index c87e228..00e2aef 100644 --- a/flang/test/Semantics/collectives01.f90 +++ b/flang/test/Semantics/collectives01.f90 @@ -135,7 +135,7 @@ program test_co_sum !ERROR: 'errmsg=' argument has unacceptable rank 1 call co_sum(d, errmsg=character_array) - !ERROR: too many actual arguments for intrinsic 'co_sum' + !ERROR: actual argument #5 without a keyword may not follow an actual argument with a keyword call co_sum(r, result_image=1, stat=status, errmsg=message, 3.4) ! keyword argument with incorrect name diff --git a/flang/test/Semantics/collectives02.f90 b/flang/test/Semantics/collectives02.f90 index 96485ce..4febeee 100644 --- a/flang/test/Semantics/collectives02.f90 +++ b/flang/test/Semantics/collectives02.f90 @@ -120,7 +120,7 @@ program test_co_min !ERROR: 'errmsg=' argument has unacceptable rank 1 call co_min(d, errmsg=character_array) - !ERROR: too many actual arguments for intrinsic 'co_min' + !ERROR: actual argument #5 without a keyword may not follow an actual argument with a keyword call co_min(r, result_image=1, stat=status, errmsg=message, 3.4) !ERROR: unknown keyword argument to intrinsic 'co_min' diff --git a/flang/test/Semantics/collectives03.f90 b/flang/test/Semantics/collectives03.f90 index e5de68b..811a7b7 100644 --- a/flang/test/Semantics/collectives03.f90 +++ b/flang/test/Semantics/collectives03.f90 @@ -120,7 +120,7 @@ program test_co_max !ERROR: 'errmsg=' argument has unacceptable rank 1 call co_max(d, errmsg=character_array) - !ERROR: too many actual arguments for intrinsic 'co_max' + !ERROR: actual argument #5 without a keyword may not follow an actual argument with a keyword call co_max(r, result_image=1, stat=status, errmsg=message, 3.4) !ERROR: unknown keyword argument to intrinsic 'co_max' diff --git a/flang/test/Semantics/collectives04.f90 b/flang/test/Semantics/collectives04.f90 index 3cd3c3f..bcd1a7e 100644 --- a/flang/test/Semantics/collectives04.f90 +++ b/flang/test/Semantics/collectives04.f90 @@ -126,7 +126,7 @@ program test_co_broadcast !ERROR: 'errmsg=' argument has unacceptable rank 1 call co_broadcast(d, errmsg=character_array, source_image=1) - !ERROR: too many actual arguments for intrinsic 'co_broadcast' + !ERROR: actual argument #5 without a keyword may not follow an actual argument with a keyword call co_broadcast(r, source_image=1, stat=status, errmsg=message, 3.4) !ERROR: unknown keyword argument to intrinsic 'co_broadcast' diff --git a/flang/test/Semantics/lcobound.f90 b/flang/test/Semantics/lcobound.f90 index 8feb496..ce2f001 100644 --- a/flang/test/Semantics/lcobound.f90 +++ b/flang/test/Semantics/lcobound.f90 @@ -104,8 +104,11 @@ program lcobound_tests !ERROR: missing mandatory 'coarray=' argument n = lcobound(dim=i, kind=c_int32_t) + !ERROR: actual argument #2 without a keyword may not follow an actual argument with a keyword n = lcobound(coarray=scalar_coarray, i) + n = lcobound(coarray=scalar_coarray, dim=i) + !ERROR: missing mandatory 'coarray=' argument lcobounds = lcobound() diff --git a/flang/test/Semantics/ucobound.f90 b/flang/test/Semantics/ucobound.f90 index da9f995..f9da11a0 100644 --- a/flang/test/Semantics/ucobound.f90 +++ b/flang/test/Semantics/ucobound.f90 @@ -104,8 +104,11 @@ program ucobound_tests !ERROR: missing mandatory 'coarray=' argument n = ucobound(dim=i, kind=c_int32_t) + !ERROR: actual argument #2 without a keyword may not follow an actual argument with a keyword n = ucobound(coarray=scalar_coarray, i) + n = ucobound(coarray=scalar_coarray, dim=i) + !ERROR: missing mandatory 'coarray=' argument ucobounds = ucobound() -- 2.7.4