[flang-commits] [flang] [flang] Reject type bound procedure overrides with mismatched passed-object dummy names (PR #210876)
via flang-commits
flang-commits at lists.llvm.org
Thu Jul 30 21:15:42 PDT 2026
https://github.com/ejose02 updated https://github.com/llvm/llvm-project/pull/210876
>From a9bd9439c86fdbf25e47c336897c5cde563d46de Mon Sep 17 00:00:00 2001
From: ejose <ejose at amd.com>
Date: Tue, 21 Jul 2026 05:05:55 +0000
Subject: [PATCH 1/3] [flang] Reject type bound procedure overrides with
mismatched passed-object dummy names
Fixes #206913
Issue:
Flang wrongly accepts a type-bound procedure override when the implementing procedure uses a different dummy name than the parent deferred interface.
Root cause:
The PASS override check uses CanOverride, which compares dummy types but not dummy names for the passed-object argument.
Fix:
Check that dummy names match before CanOverride and report a clear error
---
flang/lib/Semantics/check-declarations.cpp | 20 +++++++++++++++++
flang/test/Semantics/bindings08.f90 | 25 ++++++++++++++++++++++
2 files changed, 45 insertions(+)
create mode 100644 flang/test/Semantics/bindings08.f90
diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp
index 0a62e199d9779..bdd12811c00b8 100644
--- a/flang/lib/Semantics/check-declarations.cpp
+++ b/flang/lib/Semantics/check-declarations.cpp
@@ -2700,6 +2700,19 @@ void CheckHelper::CheckPassArg(
}
}
+static bool OverrideDummyNamesMatch(
+ const Procedure &binding, const Procedure &overridden) {
+ if (binding.dummyArguments.size() != overridden.dummyArguments.size()) {
+ return false;
+ }
+ for (std::size_t j{0}; j < binding.dummyArguments.size(); ++j) {
+ if (binding.dummyArguments[j].name != overridden.dummyArguments[j].name) {
+ return false;
+ }
+ }
+ return true;
+}
+
void CheckHelper::CheckProcBinding(
const Symbol &symbol, const ProcBindingDetails &binding) {
const Scope &dtScope{symbol.owner()};
@@ -2783,6 +2796,13 @@ void CheckHelper::CheckProcBinding(
if (*passIndex != *overriddenPassIndex) {
SayWithDeclaration(*overridden,
"A type-bound procedure and its override must use the same PASS argument"_err_en_US);
+ } else if (!OverrideDummyNamesMatch(
+ *bindingChars, *overriddenChars)) {
+ SayWithDeclaration(*overridden,
+ "Passed-object dummy arguments of type-bound procedure "
+ "'%s' "
+ "and its override must correspond by name and position"_err_en_US,
+ symbol.name());
} else if (!bindingChars->CanOverride(
*overriddenChars, passIndex)) {
SayWithDeclaration(*overridden,
diff --git a/flang/test/Semantics/bindings08.f90 b/flang/test/Semantics/bindings08.f90
new file mode 100644
index 0000000000000..4542e0091a0c9
--- /dev/null
+++ b/flang/test/Semantics/bindings08.f90
@@ -0,0 +1,25 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+
+module m
+ type, abstract :: parent
+ contains
+ procedure(ip), deferred :: set
+ end type
+ abstract interface
+ subroutine ip(x)
+ import parent
+ class(parent) :: x
+ end subroutine
+ end interface
+ type, public, extends(parent), abstract :: child
+ end type
+ type, extends(child) :: grandchild
+ contains
+ !ERROR: Passed-object dummy arguments of type-bound procedure 'set' and its override must correspond by name and position
+ procedure :: set
+ end type
+ contains
+ subroutine set(y)
+ class(grandchild) :: y
+ end subroutine
+end module
>From ead38ff433cc65ec6b86c58c0e0749d14f7d64f1 Mon Sep 17 00:00:00 2001
From: ejose <ejose at amd.com>
Date: Tue, 28 Jul 2026 05:09:35 +0000
Subject: [PATCH 2/3] Addressed the review concerns: - Return nullopt on
arg-count mismatch so CanOverride still reports compatible interfaces. -
Applied name check to NOPASS. - Broadened diagnostic and expanded
bindings08.f90 with regression cases.
---
flang/lib/Semantics/check-declarations.cpp | 22 ++--
flang/test/Semantics/bindings08.f90 | 133 +++++++++++++++++----
2 files changed, 123 insertions(+), 32 deletions(-)
diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp
index bdd12811c00b8..17e2095c61167 100644
--- a/flang/lib/Semantics/check-declarations.cpp
+++ b/flang/lib/Semantics/check-declarations.cpp
@@ -2700,17 +2700,17 @@ void CheckHelper::CheckPassArg(
}
}
-static bool OverrideDummyNamesMatch(
+static std::optional<std::size_t> FindOverrideDummyNameMismatch(
const Procedure &binding, const Procedure &overridden) {
if (binding.dummyArguments.size() != overridden.dummyArguments.size()) {
- return false;
+ return std::nullopt;
}
for (std::size_t j{0}; j < binding.dummyArguments.size(); ++j) {
if (binding.dummyArguments[j].name != overridden.dummyArguments[j].name) {
- return false;
+ return j;
}
}
- return true;
+ return std::nullopt;
}
void CheckHelper::CheckProcBinding(
@@ -2783,7 +2783,12 @@ void CheckHelper::CheckProcBinding(
const auto *bindingChars{Characterize(symbol)};
const auto *overriddenChars{Characterize(*overridden)};
if (bindingChars && overriddenChars) {
- if (isNopass) {
+ if (FindOverrideDummyNameMismatch(*bindingChars, *overriddenChars)) {
+ SayWithDeclaration(*overridden,
+ "Dummy arguments of type-bound procedure '%s' and its override "
+ "must correspond by name and position"_err_en_US,
+ symbol.name());
+ } else if (isNopass) {
if (!bindingChars->CanOverride(*overriddenChars, std::nullopt)) {
SayWithDeclaration(*overridden,
"A NOPASS type-bound procedure and its override must have identical interfaces"_err_en_US);
@@ -2796,13 +2801,6 @@ void CheckHelper::CheckProcBinding(
if (*passIndex != *overriddenPassIndex) {
SayWithDeclaration(*overridden,
"A type-bound procedure and its override must use the same PASS argument"_err_en_US);
- } else if (!OverrideDummyNamesMatch(
- *bindingChars, *overriddenChars)) {
- SayWithDeclaration(*overridden,
- "Passed-object dummy arguments of type-bound procedure "
- "'%s' "
- "and its override must correspond by name and position"_err_en_US,
- symbol.name());
} else if (!bindingChars->CanOverride(
*overriddenChars, passIndex)) {
SayWithDeclaration(*overridden,
diff --git a/flang/test/Semantics/bindings08.f90 b/flang/test/Semantics/bindings08.f90
index 4542e0091a0c9..36b16bcd17752 100644
--- a/flang/test/Semantics/bindings08.f90
+++ b/flang/test/Semantics/bindings08.f90
@@ -1,25 +1,118 @@
! RUN: %python %S/test_errors.py %s %flang_fc1
module m
- type, abstract :: parent
- contains
- procedure(ip), deferred :: set
- end type
- abstract interface
- subroutine ip(x)
- import parent
- class(parent) :: x
- end subroutine
- end interface
- type, public, extends(parent), abstract :: child
- end type
- type, extends(child) :: grandchild
- contains
- !ERROR: Passed-object dummy arguments of type-bound procedure 'set' and its override must correspond by name and position
- procedure :: set
- end type
- contains
- subroutine set(y)
- class(grandchild) :: y
+ type, abstract :: parent
+ contains
+ procedure(ip), deferred :: set
+ end type
+ abstract interface
+ subroutine ip(x)
+ import parent
+ class(parent) :: x
end subroutine
+ end interface
+ type, public, extends(parent), abstract :: child
+ end type
+ type, extends(child) :: grandchild
+ contains
+ !ERROR: Dummy arguments of type-bound procedure 'set' and its override must correspond by name and position
+ procedure :: set
+ end type
+ contains
+ subroutine set(y)
+ class(grandchild) :: y
+ end subroutine
+end module
+
+! Valid override with matching dummy names
+module m_ok
+ type, abstract :: t
+ contains
+ procedure(ip), deferred :: set
+ end type
+ abstract interface
+ subroutine ip(x)
+ import t
+ class(t) :: x
+ end subroutine
+ end interface
+ type, extends(t) :: e
+ contains
+ procedure :: set
+ end type
+ contains
+ subroutine set(x)
+ class(e) :: x
+ end subroutine
+end module
+
+! Extra dummy argument: interface mismatch, not a name error
+module m_extra
+ type, abstract :: t
+ contains
+ procedure(ip), deferred :: set
+ end type
+ abstract interface
+ subroutine ip(x)
+ import t
+ class(t) :: x
+ end subroutine
+ end interface
+ type, extends(t) :: e
+ contains
+ !ERROR: A type-bound procedure and its override must have compatible interfaces
+ procedure :: set
+ end type
+ contains
+ subroutine set(x, n)
+ class(e) :: x
+ integer :: n
+ end subroutine
+end module
+
+! Non-pass dummy renamed
+module m_rename
+ type, abstract :: t
+ contains
+ procedure(ip), deferred :: set
+ end type
+ abstract interface
+ subroutine ip(x, n)
+ import t
+ class(t) :: x
+ integer :: n
+ end subroutine
+ end interface
+ type, extends(t) :: e
+ contains
+ !ERROR: Dummy arguments of type-bound procedure 'set' and its override must correspond by name and position
+ procedure :: set
+ end type
+ contains
+ subroutine set(x, m2)
+ class(e) :: x
+ integer :: m2
+ end subroutine
+end module
+
+! NOPASS deferred override with mismatched dummy name
+module m_nopass
+ type, abstract :: t
+ contains
+ procedure(ip), deferred, nopass :: act
+ end type
+ abstract interface
+ subroutine ip(a)
+ integer :: a
+ end subroutine
+ end interface
+ type, extends(t) :: e
+ contains
+ !ERROR: Dummy arguments of type-bound procedure 'act' and its override must correspond by name and position
+ procedure, nopass :: act => impl
+ end type
+ contains
+ subroutine impl(b)
+ integer :: b
+ end subroutine
end module
>From 41649b5edcafa545e4c85c217319667837f70269 Mon Sep 17 00:00:00 2001
From: ejose <ejose at amd.com>
Date: Fri, 31 Jul 2026 04:14:27 +0000
Subject: [PATCH 3/3] [flang] Name mismatched TBP override dummies in
diagnostic
Use the index from FindOverrideDummyNameMismatch to report the override and overridden dummy argument names.
---
flang/lib/Semantics/check-declarations.cpp | 10 ++++++----
flang/test/Semantics/bindings08.f90 | 6 +++---
2 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp
index 17e2095c61167..41ddb61c4340d 100644
--- a/flang/lib/Semantics/check-declarations.cpp
+++ b/flang/lib/Semantics/check-declarations.cpp
@@ -2783,11 +2783,13 @@ void CheckHelper::CheckProcBinding(
const auto *bindingChars{Characterize(symbol)};
const auto *overriddenChars{Characterize(*overridden)};
if (bindingChars && overriddenChars) {
- if (FindOverrideDummyNameMismatch(*bindingChars, *overriddenChars)) {
+ if (auto mismatch{FindOverrideDummyNameMismatch(
+ *bindingChars, *overriddenChars)}) {
SayWithDeclaration(*overridden,
- "Dummy arguments of type-bound procedure '%s' and its override "
- "must correspond by name and position"_err_en_US,
- symbol.name());
+ "Dummy argument '%s' of type-bound procedure '%s' must "
+ "correspond by name to '%s' in the overridden procedure"_err_en_US,
+ bindingChars->dummyArguments[*mismatch].name, symbol.name(),
+ overriddenChars->dummyArguments[*mismatch].name);
} else if (isNopass) {
if (!bindingChars->CanOverride(*overriddenChars, std::nullopt)) {
SayWithDeclaration(*overridden,
diff --git a/flang/test/Semantics/bindings08.f90 b/flang/test/Semantics/bindings08.f90
index 36b16bcd17752..bfc118cd74308 100644
--- a/flang/test/Semantics/bindings08.f90
+++ b/flang/test/Semantics/bindings08.f90
@@ -15,7 +15,7 @@ subroutine ip(x)
end type
type, extends(child) :: grandchild
contains
- !ERROR: Dummy arguments of type-bound procedure 'set' and its override must correspond by name and position
+ !ERROR: Dummy argument 'y' of type-bound procedure 'set' must correspond by name to 'x' in the overridden procedure
procedure :: set
end type
contains
@@ -85,7 +85,7 @@ subroutine ip(x, n)
end interface
type, extends(t) :: e
contains
- !ERROR: Dummy arguments of type-bound procedure 'set' and its override must correspond by name and position
+ !ERROR: Dummy argument 'm2' of type-bound procedure 'set' must correspond by name to 'n' in the overridden procedure
procedure :: set
end type
contains
@@ -108,7 +108,7 @@ subroutine ip(a)
end interface
type, extends(t) :: e
contains
- !ERROR: Dummy arguments of type-bound procedure 'act' and its override must correspond by name and position
+ !ERROR: Dummy argument 'b' of type-bound procedure 'act' must correspond by name to 'a' in the overridden procedure
procedure, nopass :: act => impl
end type
contains
More information about the flang-commits
mailing list