Skip to content

Commit 918a6bb

Browse files
committed
[flang] Fix bug with generic and homonymous specific module procedure
An unconditional EraseSymbol() call was deleting a generic interface symbol when the generic had a module procedure of the same name as a specific procedure, and the module procedure's definition appeared in the same module. Also clean up some applications of the MODULE attribute to symbols created along the way. Differential Revision: https://reviews.llvm.org/D153478
1 parent 7b35676 commit 918a6bb

File tree

2 files changed

+103
-13
lines changed

2 files changed

+103
-13
lines changed

flang/lib/Semantics/resolve-names.cpp

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -888,7 +888,8 @@ class SubprogramVisitor : public virtual ScopeHandler, public InterfaceVisitor {
888888
void CheckExtantProc(const parser::Name &, Symbol::Flag);
889889
// Create a subprogram symbol in the current scope and push a new scope.
890890
Symbol &PushSubprogramScope(const parser::Name &, Symbol::Flag,
891-
const parser::LanguageBindingSpec * = nullptr);
891+
const parser::LanguageBindingSpec * = nullptr,
892+
bool hasModulePrefix = false);
892893
Symbol *GetSpecificFromGeneric(const parser::Name &);
893894
Symbol &PostSubprogramStmt();
894895
void CreateDummyArgument(SubprogramDetails &, const parser::Name &);
@@ -3601,20 +3602,33 @@ void SubprogramVisitor::Post(const parser::PrefixSpec::Cluster_Dims &x) {
36013602
}
36023603
}
36033604

3605+
static bool HasModulePrefix(const std::list<parser::PrefixSpec> &prefixes) {
3606+
for (const auto &prefix : prefixes) {
3607+
if (std::holds_alternative<parser::PrefixSpec::Module>(prefix.u)) {
3608+
return true;
3609+
}
3610+
}
3611+
return false;
3612+
}
3613+
36043614
bool SubprogramVisitor::Pre(const parser::InterfaceBody::Subroutine &x) {
3605-
const auto &name{std::get<parser::Name>(
3606-
std::get<parser::Statement<parser::SubroutineStmt>>(x.t).statement.t)};
3607-
return BeginSubprogram(name, Symbol::Flag::Subroutine);
3615+
const auto &stmtTuple{
3616+
std::get<parser::Statement<parser::SubroutineStmt>>(x.t).statement.t};
3617+
return BeginSubprogram(std::get<parser::Name>(stmtTuple),
3618+
Symbol::Flag::Subroutine,
3619+
HasModulePrefix(std::get<std::list<parser::PrefixSpec>>(stmtTuple)));
36083620
}
36093621
void SubprogramVisitor::Post(const parser::InterfaceBody::Subroutine &x) {
36103622
const auto &stmt{std::get<parser::Statement<parser::SubroutineStmt>>(x.t)};
36113623
EndSubprogram(stmt.source,
36123624
&std::get<std::optional<parser::LanguageBindingSpec>>(stmt.statement.t));
36133625
}
36143626
bool SubprogramVisitor::Pre(const parser::InterfaceBody::Function &x) {
3615-
const auto &name{std::get<parser::Name>(
3616-
std::get<parser::Statement<parser::FunctionStmt>>(x.t).statement.t)};
3617-
return BeginSubprogram(name, Symbol::Flag::Function);
3627+
const auto &stmtTuple{
3628+
std::get<parser::Statement<parser::FunctionStmt>>(x.t).statement.t};
3629+
return BeginSubprogram(std::get<parser::Name>(stmtTuple),
3630+
Symbol::Flag::Function,
3631+
HasModulePrefix(std::get<std::list<parser::PrefixSpec>>(stmtTuple)));
36183632
}
36193633
void SubprogramVisitor::Post(const parser::InterfaceBody::Function &x) {
36203634
const auto &stmt{std::get<parser::Statement<parser::FunctionStmt>>(x.t)};
@@ -4023,10 +4037,16 @@ bool SubprogramVisitor::BeginSubprogram(const parser::Name &name,
40234037
if (moduleInterface && &moduleInterface->owner() == &currScope()) {
40244038
// Subprogram is MODULE FUNCTION or MODULE SUBROUTINE with an interface
40254039
// previously defined in the same scope.
4026-
EraseSymbol(name);
4040+
if (GenericDetails *
4041+
generic{DEREF(FindSymbol(name)).detailsIf<GenericDetails>()}) {
4042+
generic->clear_specific();
4043+
} else {
4044+
EraseSymbol(name);
4045+
}
40274046
}
40284047
}
4029-
Symbol &newSymbol{PushSubprogramScope(name, subpFlag, bindingSpec)};
4048+
Symbol &newSymbol{
4049+
PushSubprogramScope(name, subpFlag, bindingSpec, hasModulePrefix)};
40304050
if (moduleInterface) {
40314051
newSymbol.get<SubprogramDetails>().set_moduleInterface(*moduleInterface);
40324052
if (moduleInterface->attrs().test(Attr::PRIVATE)) {
@@ -4134,7 +4154,8 @@ void SubprogramVisitor::CheckExtantProc(
41344154
}
41354155

41364156
Symbol &SubprogramVisitor::PushSubprogramScope(const parser::Name &name,
4137-
Symbol::Flag subpFlag, const parser::LanguageBindingSpec *bindingSpec) {
4157+
Symbol::Flag subpFlag, const parser::LanguageBindingSpec *bindingSpec,
4158+
bool hasModulePrefix) {
41384159
Symbol *symbol{GetSpecificFromGeneric(name)};
41394160
if (!symbol) {
41404161
if (bindingSpec && currScope().IsGlobal() && bindingSpec->v) {
@@ -4159,6 +4180,8 @@ Symbol &SubprogramVisitor::PushSubprogramScope(const parser::Name &name,
41594180
details.set_isInterface();
41604181
if (isAbstract()) {
41614182
SetExplicitAttr(*symbol, Attr::ABSTRACT);
4183+
} else if (hasModulePrefix) {
4184+
SetExplicitAttr(*symbol, Attr::MODULE);
41624185
} else {
41634186
MakeExternal(*symbol);
41644187
}
@@ -4172,7 +4195,10 @@ Symbol &SubprogramVisitor::PushSubprogramScope(const parser::Name &name,
41724195
}
41734196
set_inheritFromParent(false);
41744197
}
4175-
FindSymbol(name)->set(subpFlag); // PushScope() created symbol
4198+
if (Symbol * found{FindSymbol(name)};
4199+
found && found->has<HostAssocDetails>()) {
4200+
found->set(subpFlag); // PushScope() created symbol
4201+
}
41764202
return *symbol;
41774203
}
41784204

@@ -4208,6 +4234,7 @@ Symbol *SubprogramVisitor::GetSpecificFromGeneric(const parser::Name &name) {
42084234
} else if (auto *details{symbol->detailsIf<GenericDetails>()}) {
42094235
// found generic, want specific procedure
42104236
auto *specific{details->specific()};
4237+
Attrs moduleAttr;
42114238
if (inInterfaceBlock()) {
42124239
if (specific) {
42134240
// Defining an interface in a generic of the same name which is
@@ -4218,6 +4245,7 @@ Symbol *SubprogramVisitor::GetSpecificFromGeneric(const parser::Name &name) {
42184245
// The shadowed procedure is a separate module procedure that is
42194246
// actually defined later in this (sub)module.
42204247
// Define its interface now as a new symbol.
4248+
moduleAttr.set(Attr::MODULE);
42214249
specific = nullptr;
42224250
} else if (&specific->owner() != &symbol->owner()) {
42234251
// The shadowed procedure was from an enclosing scope and will be
@@ -4236,8 +4264,8 @@ Symbol *SubprogramVisitor::GetSpecificFromGeneric(const parser::Name &name) {
42364264
}
42374265
}
42384266
if (!specific) {
4239-
specific =
4240-
&currScope().MakeSymbol(name.source, Attrs{}, SubprogramDetails{});
4267+
specific = &currScope().MakeSymbol(
4268+
name.source, std::move(moduleAttr), SubprogramDetails{});
42414269
if (details->derivedType()) {
42424270
// A specific procedure with the same name as a derived type
42434271
SayAlreadyDeclared(name, *details->derivedType());

flang/test/Semantics/symbol28.f90

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
! RUN: %python %S/test_symbols.py %s %flang_fc1
2+
!DEF: /m1 Module
3+
module m1
4+
!DEF: /m1/s PUBLIC (Subroutine) Generic
5+
interface s
6+
!DEF: /m1/s MODULE (Subroutine) Subprogram
7+
module subroutine s
8+
end subroutine
9+
!DEF: /m1/s2 MODULE, PUBLIC (Subroutine) Subprogram
10+
!DEF: /m1/s2/j INTENT(IN) ObjectEntity INTEGER(4)
11+
module subroutine s2 (j)
12+
!REF: /m1/s2/j
13+
integer, intent(in) :: j
14+
end subroutine
15+
end interface
16+
contains
17+
!DEF: /m1/s MODULE (Subroutine) SubprogramName
18+
module subroutine s
19+
end subroutine
20+
!REF: /m1/s2
21+
module procedure s2
22+
end procedure
23+
!DEF: /m1/test PUBLIC (Subroutine) Subprogram
24+
subroutine test
25+
!REF: /m1/s
26+
call s
27+
!REF: /m1/s2
28+
call s(1)
29+
end subroutine
30+
end module
31+
!DEF: /m2 Module
32+
module m2
33+
!DEF: /m2/s PUBLIC (Subroutine) Generic
34+
interface s
35+
!DEF: /m2/s MODULE (Subroutine) Subprogram
36+
module subroutine s
37+
end subroutine
38+
!DEF: /m2/s2 MODULE, PUBLIC (Subroutine) Subprogram
39+
!DEF: /m2/s2/j INTENT(IN) ObjectEntity INTEGER(4)
40+
module subroutine s2 (j)
41+
!REF: /m2/s2/j
42+
integer, intent(in) :: j
43+
end subroutine
44+
end interface
45+
contains
46+
!DEF: /m2/s MODULE SubprogramName
47+
module procedure s
48+
end procedure
49+
!DEF: /m2/s2 MODULE, PUBLIC (Subroutine) Subprogram
50+
!DEF: /m2/s2/j INTENT(IN) ObjectEntity INTEGER(4)
51+
module subroutine s2 (j)
52+
!REF: /m2/s2/j
53+
integer, intent(in) :: j
54+
end subroutine
55+
!DEF: /m2/test PUBLIC (Subroutine) Subprogram
56+
subroutine test
57+
!REF: /m2/s
58+
call s
59+
!REF: /m2/s2
60+
call s(1)
61+
end subroutine
62+
end module

0 commit comments

Comments
 (0)