[flang-commits] [flang] [Flang][Semantics] Fix incorrect merging of separate module procedure interfaces during USE association (PR #197173)
via flang-commits
flang-commits at lists.llvm.org
Sun Jul 5 22:32:04 PDT 2026
https://github.com/ShashwathiNavada updated https://github.com/llvm/llvm-project/pull/197173
>From 8415b3c447406cb8306a91883405320cf5e1789a Mon Sep 17 00:00:00 2001
From: ShashwathiNavada <shashwathinavada at gmail.com>
Date: Tue, 12 May 2026 07:27:05 -0500
Subject: [PATCH 1/4] [Flang][Semantics] Fix incorrect merging of separate
module procedure interfaces during USE association
---
flang/lib/Semantics/resolve-names.cpp | 36 ++++++++++++++++++++++---
flang/test/Semantics/resolve128.f90 | 39 +++++++++++++++++++++++++++
2 files changed, 71 insertions(+), 4 deletions(-)
create mode 100644 flang/test/Semantics/resolve128.f90
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index b6907cc792d76..102978816eab2 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -1511,9 +1511,9 @@ void AccVisitor::CopySymbolWithDevice(const parser::Name *name) {
// attribute.
if (context_.languageFeatures().IsEnabled(common::LanguageFeature::CUDA) &&
name && name->symbol) {
- if (Symbol * copy{currScope().CopySymbol(*name->symbol)}) {
+ if (Symbol * copy{currScope().CopySymbol(name->symbol->GetUltimate())}) {
name->symbol = copy;
- if (auto *object{copy->detailsIf<ObjectEntityDetails>()}) {
+ if (auto *object{copy->GetUltimate().detailsIf<ObjectEntityDetails>()}) {
object->set_cudaDataAttr(common::CUDADataAttr::Device);
}
}
@@ -4107,7 +4107,27 @@ void ModuleVisitor::DoAddUse(SourceName location, SourceName localName,
if (classification == ProcedureDefinitionClass::External) {
const auto *subp1{p1.detailsIf<SubprogramDetails>()};
const auto *subp2{p2.detailsIf<SubprogramDetails>()};
- return subp1 && subp1->isInterface() && subp2 && subp2->isInterface();
+ if (subp1 && subp1->isInterface() && subp2 && subp2->isInterface()) {
+ // Don't allow merging when either module has a submodule
+ // that provides a body for this procedure.
+ auto hasSubmoduleBody{[](const Symbol &p) {
+ const Scope &owner{p.owner()};
+ if (!owner.IsModule()) {
+ return false;
+ }
+ for (const Scope &child : owner.children()) {
+ if (child.IsSubmodule()) {
+ auto it{child.find(p.name())};
+ if (it != child.end() &&
+ IsProcedure((*it->second).GetUltimate())) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }};
+ return !hasSubmoduleBody(p1) && !hasSubmoduleBody(p2);
+ }
} else if (classification == ProcedureDefinitionClass::Module) {
return AreSameModuleSymbol(p1, p2);
}
@@ -4687,6 +4707,10 @@ bool SubprogramVisitor::HandleStmtFunction(const parser::StmtFunctionStmt &x) {
"Name '%s' from host scope should have a type declaration before its local statement function definition"_port_en_US,
name.source);
MakeSymbol(name, Attrs{}, UnknownDetails{});
+ // 'name' may still point to a host-associated SubprogramNameDetails
+ // symbol. Reset it so statement-function processing
+ // re-resolves to the new local SubprogramDetails.
+ name.symbol = nullptr;
} else if (auto *entity{ultimate.detailsIf<EntityDetails>()};
entity && !ultimate.has<ProcEntityDetails>()) {
resultType = entity->type();
@@ -6012,7 +6036,11 @@ bool DeclarationVisitor::Pre(const parser::CUDAAttributesStmt &x) {
if (!symbol) {
symbol = &MakeSymbol(name, ObjectEntityDetails{});
}
- SetCUDADataAttr(name.source, *symbol, attr);
+ if (attr == common::CUDADataAttr::Value) {
+ SetExplicitAttr(*symbol, Attr::VALUE);
+ } else {
+ SetCUDADataAttr(name.source, *symbol, attr);
+ }
}
}
return false;
diff --git a/flang/test/Semantics/resolve128.f90 b/flang/test/Semantics/resolve128.f90
new file mode 100644
index 0000000000000..8924ce265e29f
--- /dev/null
+++ b/flang/test/Semantics/resolve128.f90
@@ -0,0 +1,39 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+
+module submodules_03_one
+ integer :: one_i
+ interface
+ subroutine inside_one()
+ end subroutine
+ end interface
+ end module
+
+ submodule (submodules_03_one) submodules_03_sub_one
+ contains
+ subroutine inside_one()
+ one_i = 6
+ end subroutine
+ end submodule
+
+ module submodules_03_two
+ integer :: two_i
+ interface
+ subroutine inside_one()
+ end subroutine
+ end interface
+ end module
+
+ submodule (submodules_03_two) sub_one
+ contains
+ subroutine inside_one()
+ two_i = 6
+ end subroutine
+ end submodule
+
+ program p
+ use submodules_03_one
+ use submodules_03_two
+ !ERROR: Reference to 'inside_one' is ambiguous
+ call inside_one()
+ end program
+
\ No newline at end of file
>From 695e6ec058b710c5de6ea363e9c55a5f49ae3784 Mon Sep 17 00:00:00 2001
From: ShashwathiNavada <shashwathinavada at gmail.com>
Date: Tue, 12 May 2026 18:46:28 +0530
Subject: [PATCH 2/4] Rename resolve128.f90 to resolve130.f90
---
flang/test/Semantics/{resolve128.f90 => resolve130.f90} | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
rename flang/test/Semantics/{resolve128.f90 => resolve130.f90} (99%)
diff --git a/flang/test/Semantics/resolve128.f90 b/flang/test/Semantics/resolve130.f90
similarity index 99%
rename from flang/test/Semantics/resolve128.f90
rename to flang/test/Semantics/resolve130.f90
index 8924ce265e29f..e3d3165748a9b 100644
--- a/flang/test/Semantics/resolve128.f90
+++ b/flang/test/Semantics/resolve130.f90
@@ -36,4 +36,4 @@ program p
!ERROR: Reference to 'inside_one' is ambiguous
call inside_one()
end program
-
\ No newline at end of file
+
>From 436f12113a2df71941342b9b7ce86b5cb237d1d8 Mon Sep 17 00:00:00 2001
From: ShashwathiNavada <shashwathinavada at gmail.com>
Date: Tue, 12 May 2026 19:40:21 +0530
Subject: [PATCH 3/4] Update resolve-names.cpp
---
flang/lib/Semantics/resolve-names.cpp | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index b4d4dbac63500..850d69c2afc7a 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -1616,16 +1616,15 @@ bool AccVisitor::Pre(const parser::OpenACCBlockConstruct &x) {
}
void AccVisitor::CopySymbolWithDevice(const parser::Name *name) {
- // When CUDA Fortran is enabled together with OpenACC, new
- // symbols are created for the one appearing in the use_device
- // clause. These new symbols have the CUDA Fortran device
- // attribute.
- if (context_.languageFeatures().IsEnabled(common::LanguageFeature::CUDA) &&
- name && name->symbol) {
- if (Symbol * copy{currScope().CopySymbol(name->symbol->GetUltimate())}) {
- name->symbol = copy;
- if (auto *object{copy->GetUltimate().detailsIf<ObjectEntityDetails>()}) {
- object->set_cudaDataAttr(common::CUDADataAttr::Device);
+ // New symbols are created for those appearing in the use_device clause.
+ // These new symbols get the CUDA UseDevice attribute so that generic
+ // resolution can distinguish them from true DEVICE variables: UseDevice
+ // actuals are compatible with both host and device dummy arguments.
+ if (name && name->symbol) {
+ Symbol *copy{CopyUseDeviceSymbol(*name->symbol)};
+ if (copy) {
+ if (auto *object{copy->detailsIf<ObjectEntityDetails>()}) {
+ object->set_cudaDataAttr(common::CUDADataAttr::UseDevice);
}
name->symbol = copy;
}
>From bd5ecf42f784bbb892eebd220dba050cf4db1e03 Mon Sep 17 00:00:00 2001
From: ShashwathiNavada <shashwathinavada at gmail.com>
Date: Mon, 6 Jul 2026 00:31:39 -0500
Subject: [PATCH 4/4] Suggested changes
---
flang/lib/Semantics/resolve-names.cpp | 39 +++++++++----------
.../{resolve130.f90 => resolve132.f90} | 5 ++-
2 files changed, 21 insertions(+), 23 deletions(-)
rename flang/test/Semantics/{resolve130.f90 => resolve132.f90} (62%)
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 850d69c2afc7a..4a27f510b4169 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -4252,27 +4252,7 @@ void ModuleVisitor::DoAddUse(SourceName location, SourceName localName,
if (classification == ProcedureDefinitionClass::External) {
const auto *subp1{p1.detailsIf<SubprogramDetails>()};
const auto *subp2{p2.detailsIf<SubprogramDetails>()};
- if (subp1 && subp1->isInterface() && subp2 && subp2->isInterface()) {
- // Don't allow merging when either module has a submodule
- // that provides a body for this procedure.
- auto hasSubmoduleBody{[](const Symbol &p) {
- const Scope &owner{p.owner()};
- if (!owner.IsModule()) {
- return false;
- }
- for (const Scope &child : owner.children()) {
- if (child.IsSubmodule()) {
- auto it{child.find(p.name())};
- if (it != child.end() &&
- IsProcedure((*it->second).GetUltimate())) {
- return true;
- }
- }
- }
- return false;
- }};
- return !hasSubmoduleBody(p1) && !hasSubmoduleBody(p2);
- }
+ return subp1 && subp1->isInterface() && subp2 && subp2->isInterface();
} else if (classification == ProcedureDefinitionClass::Module) {
return AreSameModuleSymbol(p1, p2);
}
@@ -5659,6 +5639,23 @@ const Symbol *SubprogramVisitor::CheckExtantProc(
Symbol *SubprogramVisitor::PushSubprogramScope(const parser::Name &name,
Symbol::Flag subpFlag, const parser::LanguageBindingSpec *bindingSpec,
bool hasModulePrefix) {
+ if (!inInterfaceBlock() && currScope().IsSubmodule() && !hasModulePrefix) {
+ const Scope &parent{currScope().parent()};
+ if (parent.IsModule()) {
+ if (const Symbol *host{parent.FindSymbol(name.source)}) {
+ const Symbol &hostUlt{host->GetUltimate()};
+ const auto *hostSubp{hostUlt.detailsIf<SubprogramDetails>()};
+ if (hostSubp && hostSubp->isInterface() &&
+ hostUlt.attrs().test(Attr::EXTERNAL)) {
+ context().Warn(common::UsageWarning::Portability, name.source,
+ "Subprogram '%s' in this submodule hides an external interface "
+ "from its parent module; did you mean 'MODULE %s'?"_port_en_US,
+ name.source,
+ subpFlag == Symbol::Flag::Subroutine ? "SUBROUTINE" : "FUNCTION");
+ }
+ }
+ }
+ }
Symbol *symbol{GetSpecificFromGeneric(name)};
const DeclTypeSpec *previousImplicitType{nullptr};
SourceName previousName;
diff --git a/flang/test/Semantics/resolve130.f90 b/flang/test/Semantics/resolve132.f90
similarity index 62%
rename from flang/test/Semantics/resolve130.f90
rename to flang/test/Semantics/resolve132.f90
index e3d3165748a9b..985ddbf694da2 100644
--- a/flang/test/Semantics/resolve130.f90
+++ b/flang/test/Semantics/resolve132.f90
@@ -1,4 +1,4 @@
-! RUN: %python %S/test_errors.py %s %flang_fc1
+! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic -Werror
module submodules_03_one
integer :: one_i
@@ -10,6 +10,7 @@ subroutine inside_one()
submodule (submodules_03_one) submodules_03_sub_one
contains
+ !PORTABILITY: Subprogram 'inside_one' in this submodule hides an external interface from its parent module; did you mean 'MODULE SUBROUTINE'? [-Wportability]
subroutine inside_one()
one_i = 6
end subroutine
@@ -25,6 +26,7 @@ subroutine inside_one()
submodule (submodules_03_two) sub_one
contains
+ !PORTABILITY: Subprogram 'inside_one' in this submodule hides an external interface from its parent module; did you mean 'MODULE SUBROUTINE'? [-Wportability]
subroutine inside_one()
two_i = 6
end subroutine
@@ -33,7 +35,6 @@ subroutine inside_one()
program p
use submodules_03_one
use submodules_03_two
- !ERROR: Reference to 'inside_one' is ambiguous
call inside_one()
end program
More information about the flang-commits
mailing list