Skip to content

Conversation

@klausler
Copy link
Contributor

PROCEDURE() declares a procedure with no interface or result type. (When used to declare a derived type component, it must also be a NOPASS POINTER.) Document that we allow such procedures to be called as subroutines with implicit interfaces, despite the ISO standard -- this is a universal extension to the language.

However, no longer allow such procedure entities to be referenced as implicitly-typed functions -- this usage is neither portable nor well-defined, as the compilers that do allow it do not respect the implicit typing rules established at the point of declaration.

PROCEDURE() declares a procedure with no interface or result type.
(When used to declare a derived type component, it must also be
a NOPASS POINTER.)  Document that we allow such procedures to be
called as subroutines with implicit interfaces, despite the ISO
standard -- this is a universal extension to the language.

However, no longer allow such procedure entities to be
referenced as implicitly-typed functions -- this usage is neither
portable nor well-defined, as the compilers that do allow it do
not respect the implicit typing rules established at the point of
declaration.
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:semantics labels Oct 30, 2025
@llvmbot
Copy link
Member

llvmbot commented Oct 30, 2025

@llvm/pr-subscribers-flang-semantics

Author: Peter Klausler (klausler)

Changes

PROCEDURE() declares a procedure with no interface or result type. (When used to declare a derived type component, it must also be a NOPASS POINTER.) Document that we allow such procedures to be called as subroutines with implicit interfaces, despite the ISO standard -- this is a universal extension to the language.

However, no longer allow such procedure entities to be referenced as implicitly-typed functions -- this usage is neither portable nor well-defined, as the compilers that do allow it do not respect the implicit typing rules established at the point of declaration.


Full diff: https://github.com/llvm/llvm-project/pull/165786.diff

3 Files Affected:

  • (modified) flang/docs/Extensions.md (+7-1)
  • (modified) flang/lib/Semantics/resolve-names.cpp (+12-7)
  • (modified) flang/test/Semantics/resolve09.f90 (+4-4)
diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md
index 6d872094811e3..c9cc02703fbc8 100644
--- a/flang/docs/Extensions.md
+++ b/flang/docs/Extensions.md
@@ -182,6 +182,13 @@ end
   Note that internally the main program symbol name is all uppercase, unlike
   the names of all other symbols, which are usually all lowercase. This
   may make a difference in testing/debugging.
+* A `PROCEDURE()` with no interface name or type may be called as an
+  subroutine with an implicit interface, F'2023 15.4.3.6 paragraph 4 and
+  C1525 notwithstanding.
+  This is a universally portable feature, and it also applies to
+  `PROCEDURE(), POINTER, NOPASS` derived type components.
+  Such procedures may *not* be referenced as implicitly typed functions
+  without first being associated with a function pointer.
 
 ## Extensions, deletions, and legacy features supported by default
 
@@ -954,4 +961,3 @@ print *, [(j,j=1,10)]
   "&GRP A(1:)=1. 2. 3./".
   This extension is necessarily disabled when the type of the array
   has an accessible defined formatted READ subroutine.
-
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 0e6d4c71b30de..cb9dd792d0ad3 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -9435,13 +9435,18 @@ bool ResolveNamesVisitor::SetProcFlag(
     SayWithDecl(name, symbol,
         "Implicit declaration of function '%s' has a different result type than in previous declaration"_err_en_US);
     return false;
-  } else if (symbol.has<ProcEntityDetails>()) {
-    symbol.set(flag); // in case it hasn't been set yet
-    if (flag == Symbol::Flag::Function) {
-      ApplyImplicitRules(symbol);
-    }
-    if (symbol.attrs().test(Attr::INTRINSIC)) {
-      AcquireIntrinsicProcedureFlags(symbol);
+  } else if (const auto *proc{symbol.detailsIf<ProcEntityDetails>()}) {
+    if (IsPointer(symbol) && !proc->type() && !proc->procInterface()) {
+      // PROCEDURE(), POINTER -- errors will be emitted later about a lack
+      // of known characteristics if used as a function
+    } else {
+      symbol.set(flag); // in case it hasn't been set yet
+      if (flag == Symbol::Flag::Function) {
+        ApplyImplicitRules(symbol);
+      }
+      if (symbol.attrs().test(Attr::INTRINSIC)) {
+        AcquireIntrinsicProcedureFlags(symbol);
+      }
     }
   } else if (symbol.GetType() && flag == Symbol::Flag::Subroutine) {
     SayWithDecl(
diff --git a/flang/test/Semantics/resolve09.f90 b/flang/test/Semantics/resolve09.f90
index 2fe21aebf66bd..3384b05bf8f27 100644
--- a/flang/test/Semantics/resolve09.f90
+++ b/flang/test/Semantics/resolve09.f90
@@ -140,11 +140,11 @@ subroutine s9
     procedure(), nopass, pointer :: p1, p2
   end type
   type(t) x
+  !ERROR: Function result characteristics are not known
   print *, x%p1()
-  call x%p2
-  !ERROR: Cannot call function 'p1' like a subroutine
-  call x%p1
-  !ERROR: Cannot call subroutine 'p2' like a function
+  call x%p2 ! ok
+  call x%p1 ! ok
+  !ERROR: Function result characteristics are not known
   print *, x%p2()
 end subroutine
 

@klausler klausler merged commit 2abcb19 into llvm:main Oct 31, 2025
13 checks passed
@klausler klausler deleted the bug1051b branch October 31, 2025 17:27
DEBADRIBASAK pushed a commit to DEBADRIBASAK/llvm-project that referenced this pull request Nov 3, 2025
PROCEDURE() declares a procedure with no interface or result type. (When
used to declare a derived type component, it must also be a NOPASS
POINTER.) Document that we allow such procedures to be called as
subroutines with implicit interfaces, despite the ISO standard -- this
is a universal extension to the language.

However, no longer allow such procedure entities to be referenced as
implicitly-typed functions -- this usage is neither portable nor
well-defined, as the compilers that do allow it do not respect the
implicit typing rules established at the point of declaration.
ckoparkar pushed a commit to ckoparkar/llvm-project that referenced this pull request Nov 6, 2025
PROCEDURE() declares a procedure with no interface or result type. (When
used to declare a derived type component, it must also be a NOPASS
POINTER.) Document that we allow such procedures to be called as
subroutines with implicit interfaces, despite the ISO standard -- this
is a universal extension to the language.

However, no longer allow such procedure entities to be referenced as
implicitly-typed functions -- this usage is neither portable nor
well-defined, as the compilers that do allow it do not respect the
implicit typing rules established at the point of declaration.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

flang:semantics flang Flang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants