[flang-commits] [flang] [flang] Diagnose assumed-type statement function dummy arguments (PR #227694)

Shrisha Kumar via flang-commits flang-commits at lists.llvm.org
Wed Oct 14 01:48:43 PDT 2026


https://github.com/Shrisha4real updated https://github.com/llvm/llvm-project/pull/227694

>From ea4b0ae72c777a510fdb31907d59b2952c481a60 Mon Sep 17 00:00:00 2001
From: shrikuma <Shrisha.Kumar at amd.com>
Date: Tue, 29 Sep 2026 20:49:50 +0530
Subject: [PATCH 1/2] [flang] Diagnose assumed-type statement function dummy
 arguments

A statement function dummy argument takes its type and type parameters
from the same-named entity in the host scope (F2023 15.6.4). A TYPE(*)
entity has no declared type, so it cannot supply one. Flang copied the
assumed type into the dummy without checking, so an uncalled definition
was silently accepted and a call hit the assertion in
genStmtFunctionRef.

Report an error in HandleStmtFunction and do not copy the assumed type.
Update the stale TODO in ConvertCall.cpp.

Also warn under -pedantic (StatementFunctionExtensions) when the
CHARACTER length of a statement function result or dummy argument is not
a constant expression. This is a portability warning, not an error,
because gfortran and ifx accept it and existing Lower tests rely on it.

Add Semantics/stmt-func05.f90.
---
 flang/lib/Lower/ConvertCall.cpp            |  5 +-
 flang/lib/Semantics/check-declarations.cpp | 22 +++++++++
 flang/lib/Semantics/resolve-names.cpp      |  8 +++-
 flang/test/Semantics/stmt-func05.f90       | 56 ++++++++++++++++++++++
 4 files changed, 87 insertions(+), 4 deletions(-)
 create mode 100644 flang/test/Semantics/stmt-func05.f90

diff --git a/flang/lib/Lower/ConvertCall.cpp b/flang/lib/Lower/ConvertCall.cpp
index de17170614ad5..bcf68c367b598 100644
--- a/flang/lib/Lower/ConvertCall.cpp
+++ b/flang/lib/Lower/ConvertCall.cpp
@@ -931,9 +931,8 @@ static hlfir::EntityWithAttributes genStmtFunctionRef(
     assert(arg && "alternate return in statement function");
     assert(bind && "optional argument in statement function");
     const auto *expr = bind->UnwrapExpr();
-    // TODO: assumed type in statement function, that surprisingly seems
-    // allowed, probably because nobody thought of restricting this usage.
-    // gfortran/ifort compiles this.
+    // Assumed-type entities cannot be statement function dummy arguments
+    // (F2023 15.6.4); semantics rejects them in HandleStmtFunction.
     assert(expr && "assumed type used as statement function argument");
     // As per Fortran 2018 C1580, statement function arguments can only be
     // scalars.
diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp
index 9e783915039ba..0807ac5f56aa6 100644
--- a/flang/lib/Semantics/check-declarations.cpp
+++ b/flang/lib/Semantics/check-declarations.cpp
@@ -1701,6 +1701,28 @@ void CheckHelper::CheckSubprogram(
             *host);
       }
     }
+    // F2023 15.6.4: the length of a CHARACTER statement function result or
+    // dummy argument shall be a constant specification expression.
+    auto checkCharLength{[&](const Symbol &entity, const char *what) {
+      if (const DeclTypeSpec * type{entity.GetType()};
+          type && type->category() == DeclTypeSpec::Character) {
+        const ParamValue &length{type->characterTypeSpec().length()};
+        if (length.isExplicit() && length.GetExplicit() &&
+            !evaluate::IsConstantExpr(*length.GetExplicit())) {
+          Warn(common::LanguageFeature::StatementFunctionExtensions,
+              entity.name(),
+              "The length of %s '%s' should be a constant expression"_port_en_US,
+              what, entity.name());
+        }
+      }
+    }};
+    checkCharLength(details.result(), "CHARACTER statement function result");
+    for (const Symbol *dummy : details.dummyArgs()) {
+      if (dummy) {
+        checkCharLength(
+            *dummy, "CHARACTER statement function dummy argument");
+      }
+    }
     if (GetProgramUnitOrBlockConstructContaining(symbol).kind() ==
         Scope::Kind::BlockConstruct) { // C1107
       messages_.Say(symbol.name(),
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 3d06f7d1fa495..b58801b222072 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -5267,7 +5267,13 @@ bool SubprogramVisitor::HandleStmtFunction(const parser::StmtFunctionStmt &x) {
     ObjectEntityDetails dummyDetails{true};
     if (auto *dummySymbol{FindInScope(currScope().parent(), dummyName)}) {
       if (auto *d{dummySymbol->GetType()}) {
-        dummyDetails.set_type(*d);
+        if (d->IsAssumedType()) {
+          Say(dummyName.source,
+              "Statement function dummy argument '%s' cannot have assumed type"_err_en_US,
+              dummyName.source);
+        } else {
+          dummyDetails.set_type(*d);
+        }
       }
     }
     Symbol &dummy{MakeSymbol(dummyName, std::move(dummyDetails))};
diff --git a/flang/test/Semantics/stmt-func05.f90 b/flang/test/Semantics/stmt-func05.f90
new file mode 100644
index 0000000000000..b2dd9dab7d349
--- /dev/null
+++ b/flang/test/Semantics/stmt-func05.f90
@@ -0,0 +1,56 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic
+! A statement function dummy argument takes its type from the entity of the
+! same name in the enclosing scope, which cannot be assumed-type.
+subroutine s1(a)
+  type(*) :: a
+  integer :: func
+  !ERROR: Statement function dummy argument 'a' cannot have assumed type
+  func(a) = 1
+end subroutine
+
+! F2023 15.6.4
+subroutine s2(a, n)
+  integer :: a
+  integer :: n
+  character(len=n) :: func
+  !PORTABILITY: The length of CHARACTER statement function result 'func' should be a constant expression [-Wstatement-function-extensions]
+  func(a) = "hello"
+end subroutine
+
+subroutine s3(a)
+  integer :: a
+  integer :: c
+  real :: func
+  func(a) = 1
+  c = func(a)
+end subroutine
+
+subroutine s4(a)
+  integer :: a
+  character(len=5) :: func
+  func(a) = "hello"
+end subroutine
+
+subroutine s5(x)
+  character(len=10) :: x
+  character(len=10) :: func
+  func(x) = x
+end subroutine
+
+subroutine s6(x, n)
+  integer :: n
+  character(len=n) :: x
+  integer :: func
+  !PORTABILITY: The length of CHARACTER statement function dummy argument 'x' should be a constant expression [-Wstatement-function-extensions]
+  func(x) = 1
+end subroutine
+
+subroutine s7(a)
+  type(*) :: a
+  integer :: c
+  integer :: func
+  !ERROR: Statement function dummy argument 'a' cannot have assumed type
+  func(a) = 1
+  !ERROR: Assumed-type 'a' may be associated only with an assumed-type dummy argument 'a='
+  c = func(a)
+end subroutine

>From 89f39991caca4868f78585ecdeba44c0cdbd1488 Mon Sep 17 00:00:00 2001
From: shrikuma <Shrisha.Kumar at amd.com>
Date: Wed, 14 Oct 2026 14:18:28 +0530
Subject: [PATCH 2/2] [flang] Reuse DynamicType::IsNonConstantLengthCharacter

---
 flang/lib/Semantics/check-declarations.cpp | 19 +++++++------------
 1 file changed, 7 insertions(+), 12 deletions(-)

diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp
index 0807ac5f56aa6..209956d538377 100644
--- a/flang/lib/Semantics/check-declarations.cpp
+++ b/flang/lib/Semantics/check-declarations.cpp
@@ -1704,23 +1704,18 @@ void CheckHelper::CheckSubprogram(
     // F2023 15.6.4: the length of a CHARACTER statement function result or
     // dummy argument shall be a constant specification expression.
     auto checkCharLength{[&](const Symbol &entity, const char *what) {
-      if (const DeclTypeSpec * type{entity.GetType()};
-          type && type->category() == DeclTypeSpec::Character) {
-        const ParamValue &length{type->characterTypeSpec().length()};
-        if (length.isExplicit() && length.GetExplicit() &&
-            !evaluate::IsConstantExpr(*length.GetExplicit())) {
-          Warn(common::LanguageFeature::StatementFunctionExtensions,
-              entity.name(),
-              "The length of %s '%s' should be a constant expression"_port_en_US,
-              what, entity.name());
-        }
+      if (auto type{evaluate::DynamicType::From(entity)};
+          type && type->IsNonConstantLengthCharacter()) {
+        Warn(common::LanguageFeature::StatementFunctionExtensions,
+            entity.name(),
+            "The length of %s '%s' should be a constant expression"_port_en_US,
+            what, entity.name());
       }
     }};
     checkCharLength(details.result(), "CHARACTER statement function result");
     for (const Symbol *dummy : details.dummyArgs()) {
       if (dummy) {
-        checkCharLength(
-            *dummy, "CHARACTER statement function dummy argument");
+        checkCharLength(*dummy, "CHARACTER statement function dummy argument");
       }
     }
     if (GetProgramUnitOrBlockConstructContaining(symbol).kind() ==



More information about the flang-commits mailing list