[flang-commits] [flang] [flang][Semantics] Resolve private PDT binding overrides (PR #218832)
via flang-commits
flang-commits at lists.llvm.org
Fri Aug 28 05:41:58 PDT 2026
================
@@ -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())};
----------------
jeanPerier wrote:
Interesting. Discussing about your change with AIs, we identified that the story around cloned generic's specific procedures is a bit sketchy: DerivedTypeSpec::Instantiate makes a new derived-type scope under the instantiation site, then Clone()s every symbol, including GenericDetails. The cloned generic’s specificProcs_ still point at the original template bindings.
It seems to me that this is a bit odd and that the new GenericDetails should probably point to the new cloned specificProcs. However, changing this would break your patch and more places that are trying to find the declaration scope.
Anyway, that may not be the core issue. The core issue rather seems to be that it is tricky to know whether you are getting the instantiation or the type declaration scope of PRIVATE components when doing a lookup with such pattern.
For instance, AI is pointing out that similar bugs may still occur after your patch (the error is correctly reported when using non PDT types):
```
! After PR 218832: PDT clone can make a PRIVATE specific look accessible
! at the instantiation site. Direct x%binding from outside the declaring
! module should be illegal (F2023 7.5.5 p9).
module priv_pdt
integer, parameter :: sp = kind(1.0)
type, abstract :: base_t(k)
integer, kind :: k = sp
integer :: n = 0
contains
procedure(iface), private, deferred :: binding
generic, public :: generic => binding
end type
type, extends(base_t) :: extension_t
contains
procedure, private :: binding => impl
end type
abstract interface
subroutine iface(x, n)
import base_t, sp
class(base_t(sp)), intent(inout) :: x
integer, intent(in) :: n
end subroutine
end interface
contains
subroutine impl(x, n)
class(extension_t(sp)), intent(inout) :: x
integer, intent(in) :: n
x%n = n
end subroutine
end module
program leak_private_name
use priv_pdt
implicit none
type(extension_t(sp)) :: x
! Should not compile: binding is PRIVATE to priv_pdt.
call x%binding(1)
print *, x%n
end program
```
And the following valid program will also not run correctly (did not compiled before your patch). It will print `poly generic 2` instead of `poly generic 1` (like ifx does for instance).
```
module m1
integer, parameter :: sp = kind(1.0)
type, abstract :: base_t(k)
integer, kind :: k = sp
integer :: which = 0
contains
procedure(iface), private, deferred :: binding
generic, public :: generic => binding
end type
type, extends(base_t) :: extension_t
contains
procedure, private :: binding => impl
end type
abstract interface
subroutine iface(x, n)
import base_t, sp
class(base_t(sp)), intent(inout) :: x
integer, intent(in) :: n
end subroutine
end interface
contains
subroutine impl(x, n)
class(extension_t(sp)), intent(inout) :: x
integer, intent(in) :: n
x%which = 1
end subroutine
end module
module m2
use m1
type, extends(extension_t) :: further_t
contains
procedure :: binding => unrelated
end type
contains
subroutine unrelated(x, n)
class(further_t(sp)), intent(inout) :: x
integer, intent(in) :: n
x%which = 2
end subroutine
end module
program poly_only
use m2
implicit none
class(extension_t(sp)), allocatable :: poly
allocate(further_t(sp) :: poly)
call poly%generic(0)
print *, 'poly generic', poly%which
end program
```
Both are pre-existing issues and not caused by the line you are changing, so your patch LGTM. Just digging a bit more to find related issues and harden the compiler^^
https://github.com/llvm/llvm-project/pull/218832
More information about the flang-commits
mailing list