[flang-commits] [flang] [flang] Diagnose assumed-type statement function dummy arguments (PR #227694)
via flang-commits
flang-commits at lists.llvm.org
Wed Sep 30 06:02:49 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-semantics
Author: Shrisha Kumar (Shrisha4real)
<details>
<summary>Changes</summary>
Flang accepted a statement function whose dummy argument corresponds to a
`TYPE(*)` (assumed-type) entity in the host scope. If the function was never
referenced it compiled silently, and if it was referenced, lowering hit an
internal assertion in `genStmtFunctionRef`. This patch rejects the construct
in Semantics with a normal diagnostic.
## Problem
This PR is related to the issue : https://github.com/llvm/llvm-project/issues/207304
F2023 15.6.4 says each statement function dummy argument has the same type
and type parameters as the entity of the same name in the scoping unit
containing the statement function statement. Per 7.3.2.2, a `TYPE(*)` entity is
not declared to have a type, so it cannot supply one.
```fortran
subroutine sub(a)
type(*) :: a
integer :: c
integer :: func
func(a) = 1
c = func(a)
end subroutine
```
Before this patch:
- Without the call `c = func(a)`, the source compiled with no diagnostic.
- With the call, compilation aborted with
`Assertion 'expr && "assumed type used as statement function argument"' failed`
in `flang/lib/Lower/ConvertCall.cpp`.
In `SubprogramVisitor::HandleStmtFunction`, the dummy took its type from the
same-named entity in the enclosing scope via `set_type` without checking it,
so the assumed type was copied into the dummy.
## Changes
- `resolve-names.cpp` (`HandleStmtFunction`): if the enclosing entity has an
assumed type, emit
`Statement function dummy argument '%s' cannot have assumed type`
and do not copy the type. The dummy then falls back to implicit typing so
analysis can continue. Compilation fails, so lowering is never reached.
- `ConvertCall.cpp`: replace the stale TODO (which said assumed-type in a
statement function "seems allowed" and that gfortran/ifort accept it) with a
comment saying Semantics rejects it. The assertion is kept as an internal
invariant check.
- `check-declarations.cpp`: also report, under `-pedantic`, when the CHARACTER
length of a statement function result or dummy argument is not a constant
expression (F2023 15.6.4). This uses the existing
`StatementFunctionExtensions` portability warning, like the other
statement-function checks (C1577), and is not an error, because gfortran and
ifx accept it and existing Lower tests
(`Lower/statement-function.f90`, `Lower/HLFIR/statement-functions.f90`)
deliberately use a non-constant length such as `character(n)` and rely on it.
- `flang/test/Semantics/stmt-func05.f90` (new): covers the uncalled and called
assumed-type cases, valid controls, and the CHARACTER length warnings.
## Behavior after the patch
For the reproducer above:
```
error: Statement function dummy argument 'a' cannot have assumed type
error: Assumed-type 'a' may be associated only with an assumed-type dummy argument 'a='
```
The second error is an existing call-site check that fires because the dummy
now has an implicit type. There is no assertion failure.
---
Full diff: https://github.com/llvm/llvm-project/pull/227694.diff
4 Files Affected:
- (modified) flang/lib/Lower/ConvertCall.cpp (+2-3)
- (modified) flang/lib/Semantics/check-declarations.cpp (+22)
- (modified) flang/lib/Semantics/resolve-names.cpp (+7-1)
- (added) flang/test/Semantics/stmt-func05.f90 (+56)
``````````diff
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
``````````
</details>
https://github.com/llvm/llvm-project/pull/227694
More information about the flang-commits
mailing list