[flang-commits] [flang] [Flang] Reject keyword arguments in statement function calls (PR #198610)

via flang-commits flang-commits at lists.llvm.org
Sun May 31 04:40:40 PDT 2026


https://github.com/blazie2004 updated https://github.com/llvm/llvm-project/pull/198610

>From b4a5db0d39f7572689ae2fc56db597970d1b40b9 Mon Sep 17 00:00:00 2001
From: Jay Satish Kumar Patel <kumarpat at pe31.hpc.amslabs.hpecorp.net>
Date: Tue, 19 May 2026 13:44:07 -0500
Subject: [PATCH 1/3] Reject keyword arguments in statement function calls

---
 flang/lib/Evaluate/characteristics.cpp |  4 ++++
 flang/test/Semantics/call47.f90        | 15 +++++++++++++++
 2 files changed, 19 insertions(+)
 create mode 100644 flang/test/Semantics/call47.f90

diff --git a/flang/lib/Evaluate/characteristics.cpp b/flang/lib/Evaluate/characteristics.cpp
index 63d4c74d553e3..ba11412511638 100644
--- a/flang/lib/Evaluate/characteristics.cpp
+++ b/flang/lib/Evaluate/characteristics.cpp
@@ -642,6 +642,10 @@ static std::optional<Procedure> CharacterizeProcedure(
           [&](const semantics::SubprogramDetails &subp)
               -> std::optional<Procedure> {
             Procedure result;
+            if (subp.stmtFunction()) {
+              // Statement functions have implicit interfaces (F'2018 15.5.1)
+              result.attrs.set(Procedure::Attr::ImplicitInterface);
+            }
             if (subp.isFunction()) {
               if (auto fr{CharacterizeFunctionResult(
                       subp.result(), context, seenProcs, emitError)}) {
diff --git a/flang/test/Semantics/call47.f90 b/flang/test/Semantics/call47.f90
new file mode 100644
index 0000000000000..e2b775a60526c
--- /dev/null
+++ b/flang/test/Semantics/call47.f90
@@ -0,0 +1,15 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+! Test F'2018 15.5.1 C1535 - keyword arguments are not allowed when the
+! interface is implicit. Statement functions have implicit interfaces.
+
+program test_stmt_func_keyword
+  integer :: f1, x, c
+
+  ! Statement function definition
+  f1(x) = x / 2
+
+  ! Calling a statement function with a keyword argument is not allowed
+  ! because statement functions have implicit interfaces.
+  !ERROR: Keyword 'x=' may not appear in a reference to a procedure with an implicit interface
+  c = f1(x=10)
+end program

>From 1357ddcced5c7953c4c47dc93adb293db3d79456 Mon Sep 17 00:00:00 2001
From: Jay Satish Kumar Patel <kumarpat at pe31.hpc.amslabs.hpecorp.net>
Date: Wed, 20 May 2026 12:49:15 -0500
Subject: [PATCH 2/3] Handle implicit interface checks for statement functions

---
 flang/lib/Evaluate/characteristics.cpp |  4 ----
 flang/lib/Semantics/check-call.cpp     |  2 +-
 flang/lib/Semantics/check-call.h       |  5 +++++
 flang/lib/Semantics/expression.cpp     | 15 +++++++++++++++
 4 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/flang/lib/Evaluate/characteristics.cpp b/flang/lib/Evaluate/characteristics.cpp
index ba11412511638..63d4c74d553e3 100644
--- a/flang/lib/Evaluate/characteristics.cpp
+++ b/flang/lib/Evaluate/characteristics.cpp
@@ -642,10 +642,6 @@ static std::optional<Procedure> CharacterizeProcedure(
           [&](const semantics::SubprogramDetails &subp)
               -> std::optional<Procedure> {
             Procedure result;
-            if (subp.stmtFunction()) {
-              // Statement functions have implicit interfaces (F'2018 15.5.1)
-              result.attrs.set(Procedure::Attr::ImplicitInterface);
-            }
             if (subp.isFunction()) {
               if (auto fr{CharacterizeFunctionResult(
                       subp.result(), context, seenProcs, emitError)}) {
diff --git a/flang/lib/Semantics/check-call.cpp b/flang/lib/Semantics/check-call.cpp
index da8880482d4dc..dcd7dc4288f6f 100644
--- a/flang/lib/Semantics/check-call.cpp
+++ b/flang/lib/Semantics/check-call.cpp
@@ -27,7 +27,7 @@ namespace characteristics = Fortran::evaluate::characteristics;
 
 namespace Fortran::semantics {
 
-static void CheckImplicitInterfaceArg(evaluate::ActualArgument &arg,
+void CheckImplicitInterfaceArg(evaluate::ActualArgument &arg,
     parser::ContextualMessages &messages, SemanticsContext &context) {
   auto restorer{
       messages.SetLocation(arg.sourceLocation().value_or(messages.at()))};
diff --git a/flang/lib/Semantics/check-call.h b/flang/lib/Semantics/check-call.h
index a69b792b646e6..fb021d23dabc8 100644
--- a/flang/lib/Semantics/check-call.h
+++ b/flang/lib/Semantics/check-call.h
@@ -25,6 +25,11 @@ namespace Fortran::semantics {
 class Scope;
 class SemanticsContext;
 
+// Check constraints on actual arguments for procedures with implicit
+// interfaces. Used for statement function calls and external procedures.
+void CheckImplicitInterfaceArg(evaluate::ActualArgument &,
+    parser::ContextualMessages &, SemanticsContext &);
+
 // Argument treatingExternalAsImplicit should be true when the called procedure
 // does not actually have an explicit interface at the call site, but
 // its characteristics are known because it is a subroutine or function
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index 8ee0613bdfc5f..24b5cfa8c1f75 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -3769,6 +3769,10 @@ std::optional<characteristics::Procedure> ExpressionAnalyzer::CheckCall(
   bool treatExternalAsImplicit{
       IsExternalCalledImplicitly(callSite, proc.GetSymbol())};
   const Symbol *procSymbol{proc.GetSymbol()};
+  // Statement functions have implicit interfaces and require the same checks
+  bool isStatementFunction{procSymbol &&
+      procSymbol->has<semantics::SubprogramDetails>() &&
+      procSymbol->get<semantics::SubprogramDetails>().stmtFunction()};
   std::optional<characteristics::Procedure> chars;
   if (procSymbol && procSymbol->has<semantics::ProcEntityDetails>() &&
       procSymbol->owner().IsGlobal()) {
@@ -3838,6 +3842,17 @@ std::optional<characteristics::Procedure> ExpressionAnalyzer::CheckCall(
             name, DEREF(pure->symbol()).name());
       }
     }
+    if (isStatementFunction) {
+      // Statement functions have implicit interfaces; check for
+      // keyword arguments and other implicit interface constraints
+      parser::ContextualMessages &messages{
+          context_.foldingContext().messages()};
+      for (auto &arg : arguments) {
+        if (arg) {
+          semantics::CheckImplicitInterfaceArg(*arg, messages, context_);
+        }
+      }
+    }
     ok &= semantics::CheckArguments(*chars, arguments, context_,
         context_.FindScope(callSite), treatExternalAsImplicit,
         /*ignoreImplicitVsExplicit=*/false, specificIntrinsic);

>From 5f864bdc39995a8ff41e3da69b3c2fce3b3a4c22 Mon Sep 17 00:00:00 2001
From: Jay Satish Kumar Patel <kumarpat at pe31.hpc.amslabs.hpecorp.net>
Date: Sun, 31 May 2026 06:35:23 -0500
Subject: [PATCH 3/3] use canonical flag check, add tests for wrong keyword and
 two-arg function

---
 flang/lib/Semantics/expression.cpp |  3 +--
 flang/test/Semantics/call47.f90    | 17 ++++++++++++++---
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index 24b5cfa8c1f75..a9e7bcc11ab34 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -3771,8 +3771,7 @@ std::optional<characteristics::Procedure> ExpressionAnalyzer::CheckCall(
   const Symbol *procSymbol{proc.GetSymbol()};
   // Statement functions have implicit interfaces and require the same checks
   bool isStatementFunction{procSymbol &&
-      procSymbol->has<semantics::SubprogramDetails>() &&
-      procSymbol->get<semantics::SubprogramDetails>().stmtFunction()};
+      procSymbol->flags().test(Symbol::Flag::StmtFunction)};
   std::optional<characteristics::Procedure> chars;
   if (procSymbol && procSymbol->has<semantics::ProcEntityDetails>() &&
       procSymbol->owner().IsGlobal()) {
diff --git a/flang/test/Semantics/call47.f90 b/flang/test/Semantics/call47.f90
index e2b775a60526c..0c6e9071f33f0 100644
--- a/flang/test/Semantics/call47.f90
+++ b/flang/test/Semantics/call47.f90
@@ -1,15 +1,26 @@
 ! RUN: %python %S/test_errors.py %s %flang_fc1
-! Test F'2018 15.5.1 C1535 - keyword arguments are not allowed when the
+! Test F2018 15.5.1 C1535 - keyword arguments are not allowed when the
 ! interface is implicit. Statement functions have implicit interfaces.
 
 program test_stmt_func_keyword
-  integer :: f1, x, c
+  integer :: f1, f2, x, y, c
 
-  ! Statement function definition
+  ! Statement function definitions
   f1(x) = x / 2
+  f2(x, y) = x + y
 
   ! Calling a statement function with a keyword argument is not allowed
   ! because statement functions have implicit interfaces.
   !ERROR: Keyword 'x=' may not appear in a reference to a procedure with an implicit interface
   c = f1(x=10)
+
+  ! Wrong keyword name - gets both implicit interface error and unrecognized keyword error
+  !ERROR: Keyword 'y=' may not appear in a reference to a procedure with an implicit interface
+  !ERROR: Argument keyword 'y=' is not recognized for this procedure reference
+  c = f1(y=10)
+
+  ! Two keyword arguments - each gets its own diagnostic
+  !ERROR: Keyword 'x=' may not appear in a reference to a procedure with an implicit interface
+  !ERROR: Keyword 'y=' may not appear in a reference to a procedure with an implicit interface
+  c = f2(x=10, y=20)
 end program



More information about the flang-commits mailing list