[flang-commits] [flang] [flang] Implement check for statement function dummy argument names (PR #204417)

via flang-commits flang-commits at lists.llvm.org
Thu Jun 18 07:40:03 PDT 2026


https://github.com/kwyatt-ext updated https://github.com/llvm/llvm-project/pull/204417

>From e0742f7e798ce223d44c6ae08951d30a5520618e Mon Sep 17 00:00:00 2001
From: Kevin Wyatt <kwyatt at hpe.com>
Date: Wed, 17 Jun 2026 14:12:53 -0500
Subject: [PATCH] Added check to prevent re-use of identifiers in statement
 function dummy args.

---
 flang/lib/Semantics/resolve-names.cpp | 18 ++++++++
 flang/test/Semantics/bug121973.f90    |  1 +
 flang/test/Semantics/stmt-func04.f90  | 66 +++++++++++++++++++++++++++
 3 files changed, 85 insertions(+)
 create mode 100644 flang/test/Semantics/stmt-func04.f90

diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 6d2d0bf24b194..60bdb98046bad 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -10451,6 +10451,24 @@ void ResolveNamesVisitor::AnalyzeStmtFunctionStmt(
       details->moduleInterface() || symbol->test(Symbol::Flag::Subroutine)) {
     return; // error recovery
   }
+
+  // F2023 19.4 p2: a statement-function dummy argument name may be the same
+  // as an accessible name only if that name is a scalar variable.  The lookup
+  // walks the host chain (but not into the global scope), so host-associated
+  // identifiers are also considered.
+  for (const auto &dummyName : std::get<std::list<parser::Name>>(stmtFunc.t)) {
+    if (const Symbol *hostSymbol{currScope().FindSymbol(dummyName.source)}) {
+      const Symbol &ultimate{hostSymbol->GetUltimate()};
+      const bool isScalarVariable{(ultimate.has<ObjectEntityDetails>() ||
+                                      ultimate.has<EntityDetails>()) &&
+          !IsNamedConstant(ultimate) && ultimate.Rank() == 0};
+      if (!isScalarVariable) {
+        Say(dummyName.source,
+            "The name '%s' of a statement function dummy argument may not be the same as an accessible name unless that name is a scalar variable"_err_en_US);
+      }
+    }
+  }
+
   // Resolve the symbols on the RHS of the statement function.
   PushScope(*symbol->scope());
   const auto &parsedExpr{std::get<parser::Scalar<parser::Expr>>(stmtFunc.t)};
diff --git a/flang/test/Semantics/bug121973.f90 b/flang/test/Semantics/bug121973.f90
index 0ae04c808e416..2ec2260aeb557 100644
--- a/flang/test/Semantics/bug121973.f90
+++ b/flang/test/Semantics/bug121973.f90
@@ -3,6 +3,7 @@ subroutine s()
   real(8) :: a
   !ERROR: COMPLEX(KIND=128) is not a supported type
   complex(128) :: x
+  !ERROR: The name 'i' of a statement function dummy argument may not be the same as an accessible name unless that name is a scalar variable
   a(i)=a + ((i)+1) + 3.14
   !ERROR: 'a' has not been declared as an array or pointer-valued function
   a()=z(a * a + n-1 - x) + i((/0,0,0,0,0,0,0,0,0,0/)) + 8
diff --git a/flang/test/Semantics/stmt-func04.f90 b/flang/test/Semantics/stmt-func04.f90
new file mode 100644
index 0000000000000..f216fbd6912c4
--- /dev/null
+++ b/flang/test/Semantics/stmt-func04.f90
@@ -0,0 +1,66 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+! F2023 19.4 p2: a statement function dummy argument name may be the same as an
+! accessible global identifier or local identifier of class (1) only if that
+! name is a scalar variable.
+
+! Clashes within the statement function's own scoping unit.
+subroutine local_clashes
+  real, external :: extf       ! external procedure
+  real, parameter :: namedc = 1.0
+  real :: arr(10)              ! array
+  type t; end type             ! derived type
+  real :: scalarvar            ! scalar variable (legal to shadow)
+
+  !ERROR: The name 'extf' of a statement function dummy argument may not be the same as an accessible name unless that name is a scalar variable
+  f1(extf) = extf + 1
+  !ERROR: The name 'namedc' of a statement function dummy argument may not be the same as an accessible name unless that name is a scalar variable
+  f2(namedc) = namedc + 1
+  !ERROR: The name 'arr' of a statement function dummy argument may not be the same as an accessible name unless that name is a scalar variable
+  f3(arr) = arr + 1
+  !ERROR: The name 't' of a statement function dummy argument may not be the same as an accessible name unless that name is a scalar variable
+  f4(t) = 1
+  f5(scalarvar) = scalarvar + 1 ! ok: scalar variable shadowing is permitted
+end subroutine
+
+! Clashes with host-associated identifiers (module scope).
+module m
+  integer :: hostarr(10)
+  integer :: hostscalar
+  integer, parameter :: hostconst = 3
+contains
+  subroutine host_clashes
+    !ERROR: The name 'hostarr' of a statement function dummy argument may not be the same as an accessible name unless that name is a scalar variable
+    g1(hostarr) = hostarr + 1
+    !ERROR: The name 'hostconst' of a statement function dummy argument may not be the same as an accessible name unless that name is a scalar variable
+    g2(hostconst) = hostconst + 1
+    g3(hostscalar) = hostscalar + 1 ! ok: host scalar variable
+  end subroutine
+end module
+
+! Clashes with grandparent-associated identifiers (internal procedure).
+program p
+  integer :: grandarr(5)
+  integer :: grandscalar
+contains
+  subroutine grand_clashes
+    !ERROR: The name 'grandarr' of a statement function dummy argument may not be the same as an accessible name unless that name is a scalar variable
+    h1(grandarr) = grandarr + 1
+    h2(grandscalar) = grandscalar + 1 ! ok: grandparent scalar variable
+  end subroutine
+end program
+
+! Clashes with USE-associated identifiers.
+module m_used
+  integer :: usearr(10)
+  integer :: usescalar
+  integer, parameter :: useconst = 5
+end module
+subroutine use_clashes
+  use m_used
+  !ERROR: The name 'usearr' of a statement function dummy argument may not be the same as an accessible name unless that name is a scalar variable
+  k1(usearr) = usearr + 1
+  !ERROR: The name 'useconst' of a statement function dummy argument may not be the same as an accessible name unless that name is a scalar variable
+  k2(useconst) = useconst + 1
+  k3(usescalar) = usescalar + 1 ! ok: USE-associated scalar variable
+end subroutine
+



More information about the flang-commits mailing list