Skip to content

Commit fc51099

Browse files
committed
[flang] Fix edge case in USE-associated generics
It is generally an error when a USE-associated name clashes with a name defined locally, but not in all cases; a generic interface can be both USE-associated and locally defined. This works, but not when there is also a local subprogram with the same name, which is valid when that subprogram is a specific of the local generic. A bogus error issues at the point of the USE because name resolution will have already defined a symbol for the local subprogram. The solution is to collect the names of local generics when creating the program tree, and then create their symbols as well if their names are also local subprograms, prior to any USE association processing. Differential Revision: https://reviews.llvm.org/D119566
1 parent dafe4c0 commit fc51099

File tree

4 files changed

+82
-4
lines changed

4 files changed

+82
-4
lines changed

flang/lib/Semantics/program-tree.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,37 @@ static void GetEntryStmts(
4444
}
4545
}
4646

47+
// Collects generics that define simple names that could include
48+
// identically-named subprograms as specific procedures.
49+
static void GetGenerics(
50+
ProgramTree &node, const parser::SpecificationPart &spec) {
51+
for (const auto &decl :
52+
std::get<std::list<parser::DeclarationConstruct>>(spec.t)) {
53+
if (const auto *spec{
54+
std::get_if<parser::SpecificationConstruct>(&decl.u)}) {
55+
if (const auto *generic{std::get_if<
56+
parser::Statement<common::Indirection<parser::GenericStmt>>>(
57+
&spec->u)}) {
58+
const parser::GenericStmt &genericStmt{generic->statement.value()};
59+
const auto &genericSpec{std::get<parser::GenericSpec>(genericStmt.t)};
60+
node.AddGeneric(genericSpec);
61+
} else if (const auto *interface{
62+
std::get_if<common::Indirection<parser::InterfaceBlock>>(
63+
&spec->u)}) {
64+
const parser::InterfaceBlock &interfaceBlock{interface->value()};
65+
const parser::InterfaceStmt &interfaceStmt{
66+
std::get<parser::Statement<parser::InterfaceStmt>>(interfaceBlock.t)
67+
.statement};
68+
const auto *genericSpec{
69+
std::get_if<std::optional<parser::GenericSpec>>(&interfaceStmt.u)};
70+
if (genericSpec && genericSpec->has_value()) {
71+
node.AddGeneric(**genericSpec);
72+
}
73+
}
74+
}
75+
}
76+
}
77+
4778
template <typename T>
4879
static ProgramTree BuildSubprogramTree(const parser::Name &name, const T &x) {
4980
const auto &spec{std::get<parser::SpecificationPart>(x.t)};
@@ -53,6 +84,7 @@ static ProgramTree BuildSubprogramTree(const parser::Name &name, const T &x) {
5384
ProgramTree node{name, spec, &exec};
5485
GetEntryStmts(node, spec);
5586
GetEntryStmts(node, exec);
87+
GetGenerics(node, spec);
5688
if (subps) {
5789
for (const auto &subp :
5890
std::get<std::list<parser::InternalSubprogram>>(subps->t)) {
@@ -75,6 +107,7 @@ static ProgramTree BuildModuleTree(const parser::Name &name, const T &x) {
75107
const auto &spec{std::get<parser::SpecificationPart>(x.t)};
76108
const auto &subps{std::get<std::optional<parser::ModuleSubprogramPart>>(x.t)};
77109
ProgramTree node{name, spec};
110+
GetGenerics(node, spec);
78111
if (subps) {
79112
for (const auto &subp :
80113
std::get<std::list<parser::ModuleSubprogram>>(subps->t)) {
@@ -230,4 +263,8 @@ void ProgramTree::AddEntry(const parser::EntryStmt &entryStmt) {
230263
entryStmts_.emplace_back(entryStmt);
231264
}
232265

266+
void ProgramTree::AddGeneric(const parser::GenericSpec &generic) {
267+
genericSpecs_.emplace_back(generic);
268+
}
269+
233270
} // namespace Fortran::semantics

flang/lib/Semantics/program-tree.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ class Scope;
3030
class ProgramTree {
3131
public:
3232
using EntryStmtList = std::list<common::Reference<const parser::EntryStmt>>;
33+
using GenericSpecList =
34+
std::list<common::Reference<const parser::GenericSpec>>;
3335

3436
// Build the ProgramTree rooted at one of these program units.
3537
static ProgramTree Build(const parser::ProgramUnit &);
@@ -71,17 +73,17 @@ class ProgramTree {
7173
const parser::ExecutionPart *exec() const { return exec_; }
7274
std::list<ProgramTree> &children() { return children_; }
7375
const std::list<ProgramTree> &children() const { return children_; }
74-
const std::list<common::Reference<const parser::EntryStmt>> &
75-
entryStmts() const {
76-
return entryStmts_;
77-
}
76+
const EntryStmtList &entryStmts() const { return entryStmts_; }
77+
const GenericSpecList &genericSpecs() const { return genericSpecs_; }
78+
7879
Symbol::Flag GetSubpFlag() const;
7980
bool IsModule() const; // Module or Submodule
8081
bool HasModulePrefix() const; // in function or subroutine stmt
8182
Scope *scope() const { return scope_; }
8283
void set_scope(Scope &);
8384
void AddChild(ProgramTree &&);
8485
void AddEntry(const parser::EntryStmt &);
86+
void AddGeneric(const parser::GenericSpec &);
8587

8688
template <typename T>
8789
ProgramTree &set_stmt(const parser::Statement<T> &stmt) {
@@ -102,6 +104,7 @@ class ProgramTree {
102104
const parser::ExecutionPart *exec_{nullptr};
103105
std::list<ProgramTree> children_;
104106
EntryStmtList entryStmts_;
107+
GenericSpecList genericSpecs_;
105108
Scope *scope_{nullptr};
106109
const parser::CharBlock *endStmt_{nullptr};
107110
bool isSpecificationPartResolved_{false};

flang/lib/Semantics/resolve-names.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7054,6 +7054,18 @@ void ResolveNamesVisitor::AddSubpNames(ProgramTree &node) {
70547054
symbol.set(child.GetSubpFlag());
70557055
}
70567056
}
7057+
for (const auto &generic : node.genericSpecs()) {
7058+
if (const auto *name{std::get_if<parser::Name>(&generic->u)}) {
7059+
if (currScope().find(name->source) != currScope().end()) {
7060+
// If this scope has both a generic interface and a contained
7061+
// subprogram with the same name, create the generic's symbol
7062+
// now so that any other generics of the same name that are pulled
7063+
// into scope later via USE association will properly merge instead
7064+
// of raising a bogus error due a conflict with the subprogram.
7065+
CreateGeneric(*generic);
7066+
}
7067+
}
7068+
}
70577069
}
70587070

70597071
// Push a new scope for this node or return false on error.

flang/test/Semantics/resolve18.f90

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,29 @@ end function f13
182182
function f13()
183183
end function f13
184184
end module m13
185+
186+
! Not an error
187+
module m14
188+
interface gen1
189+
module procedure s
190+
end interface
191+
generic :: gen2 => s
192+
contains
193+
subroutine s(x)
194+
integer(1) :: x
195+
end subroutine s
196+
end module m14
197+
module m15
198+
use m14
199+
interface gen1
200+
module procedure gen1
201+
end interface
202+
generic :: gen2 => gen2
203+
contains
204+
subroutine gen1(x)
205+
integer(2) :: x
206+
end subroutine gen1
207+
subroutine gen2(x)
208+
integer(4) :: x
209+
end subroutine gen2
210+
end module m15

0 commit comments

Comments
 (0)