[flang-commits] [flang] [flang][Semantics] Resolve private PDT binding overrides (PR #218832)
Eugene Epshteyn via flang-commits
flang-commits at lists.llvm.org
Tue Aug 25 20:43:28 PDT 2026
https://github.com/eugeneepshteyn created https://github.com/llvm/llvm-project/pull/218832
Use the selected binding declaration owner when determining the module in which a private binding may be overridden. A generic cloned into a PDT instantiation is owned by the instantiation scope, which can otherwise cause a legal same-module override to be skipped.
Add coverage for external, unrelated-module, module-owned, use-renamed, and cross-module private/public PDT cases.
Fixes #218683
Assisted-by: AI
>From 935e992d2cb64d1572a4da8ee7c338c7ce571aaf Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Tue, 25 Aug 2026 23:36:42 -0400
Subject: [PATCH] [flang][Semantics] Resolve private PDT binding overrides
Use the selected binding declaration owner when determining the module in which a private binding may be overridden. A generic cloned into a PDT instantiation is owned by the instantiation scope, which can otherwise cause a legal same-module override to be skipped.
Add coverage for external, unrelated-module, module-owned, use-renamed, and cross-module private/public PDT cases.
Fixes #218683
---
flang/lib/Semantics/expression.cpp | 2 +-
flang/test/Semantics/bindings09.f90 | 134 ++++++++++++++++++++++++++++
2 files changed, 135 insertions(+), 1 deletion(-)
create mode 100644 flang/test/Semantics/bindings09.f90
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index efbf862a72c51..fa78379b7a4d0 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -2715,7 +2715,7 @@ auto ExpressionAnalyzer::AnalyzeProcedureComponentRef(
latest{DEREF(dyType->GetDerivedTypeSpec().typeSymbol().scope())
.FindComponent(sym->name())}) {
if (sym->attrs().test(semantics::Attr::PRIVATE)) {
- const auto *bindingModule{FindModuleContaining(generic.owner())};
+ const auto *bindingModule{FindModuleContaining(sym->owner())};
const Symbol *s{latest};
while (s && FindModuleContaining(s->owner()) != bindingModule) {
if (const auto *parent{s->owner().GetDerivedTypeParent()}) {
diff --git a/flang/test/Semantics/bindings09.f90 b/flang/test/Semantics/bindings09.f90
new file mode 100644
index 0000000000000..0992ebc09bd6e
--- /dev/null
+++ b/flang/test/Semantics/bindings09.f90
@@ -0,0 +1,134 @@
+! RUN: %flang_fc1 -fdebug-unparse %s 2>&1 | FileCheck %s
+
+! Ensure that generic resolution for a parameterized derived type uses the
+! module containing the selected binding, not the PDT instantiation site.
+
+module private_pdt
+ implicit none
+ integer, parameter :: sp = kind(1.0)
+
+ type, abstract :: base_t(k)
+ integer, kind :: k = sp
+ contains
+ procedure(private_interface), private, deferred :: binding
+ generic, public :: generic => binding
+ end type
+
+ type, extends(base_t) :: extension_t
+ contains
+ procedure, private :: binding => private_impl
+ end type
+
+ abstract interface
+ subroutine private_interface(x, n)
+ import base_t, sp
+ class(base_t(sp)), intent(inout) :: x
+ integer, intent(in) :: n
+ end subroutine
+ end interface
+
+ type(extension_t(sp)), public :: module_object
+
+contains
+ subroutine private_impl(x, n)
+ class(extension_t(sp)), intent(inout) :: x
+ integer, intent(in) :: n
+ end subroutine
+end module
+
+module third_module
+ use private_pdt
+ implicit none
+contains
+ subroutine call_from_third_module
+ type(extension_t(sp)) :: x
+ ! CHECK: CALL private_impl(x,1_4)
+ call x%generic(1)
+ end subroutine
+end module
+
+module use_renamed
+ use private_pdt, only: renamed_t => extension_t, sp
+ implicit none
+contains
+ subroutine call_use_renamed
+ type(renamed_t(sp)) :: x
+ ! CHECK: CALL private_impl(x,2_4)
+ call x%generic(2)
+ end subroutine
+end module
+
+module private_cross_module
+ use private_pdt
+ implicit none
+
+ ! The inherited private binding cannot be overridden in another module.
+ type, extends(extension_t) :: further_extension_t
+ contains
+ procedure :: binding => unrelated_impl
+ end type
+
+contains
+ subroutine unrelated_impl(x, n)
+ class(further_extension_t(sp)), intent(inout) :: x
+ integer, intent(in) :: n
+ end subroutine
+
+ subroutine call_private_cross_module
+ type(further_extension_t(sp)) :: x
+ ! CHECK: CALL private_impl(x,3_4)
+ call x%generic(3)
+ end subroutine
+end module
+
+module public_pdt
+ implicit none
+ integer, parameter :: sp = kind(1.0)
+
+ type :: base_t(k)
+ integer, kind :: k = sp
+ contains
+ procedure, public :: binding => public_base_impl
+ generic, public :: generic => binding
+ end type
+
+contains
+ subroutine public_base_impl(x, n)
+ class(base_t(sp)), intent(inout) :: x
+ integer, intent(in) :: n
+ end subroutine
+end module
+
+module public_cross_module
+ use public_pdt
+ implicit none
+
+ ! Unlike a private binding, the public binding remains overridable here.
+ type, extends(base_t) :: extension_t
+ contains
+ procedure :: binding => public_extension_impl
+ end type
+
+contains
+ subroutine public_extension_impl(x, n)
+ class(extension_t(sp)), intent(inout) :: x
+ integer, intent(in) :: n
+ end subroutine
+
+ subroutine call_public_cross_module
+ type(extension_t(sp)) :: x
+ ! CHECK: CALL public_extension_impl(x,4_4)
+ call x%generic(4)
+ end subroutine
+end module
+
+program test
+ use private_pdt
+ implicit none
+ type(extension_t(sp)) :: x
+
+ ! CHECK: CALL private_impl(x,5_4)
+ call x%generic(5)
+ ! CHECK: CALL private_impl(module_object,6_4)
+ call module_object%generic(6)
+end program
More information about the flang-commits
mailing list