[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