Skip to content

Commit 456fdf8

Browse files
committed
[flang] Enable more usage of generics with forward-referenced specifics in specification parts
Earlier work allowed a specification expression to reference a generic function that was defined earlier, so long as the relevant specific procedure of the generic had been defined before the generic. This patch extends that work so that the generic can also be used in cases where the relevant specific procedure has been defined after the generic and before the reference. Differential Revision: https://reviews.llvm.org/D159034
1 parent 2fce8f7 commit 456fdf8

File tree

2 files changed

+113
-34
lines changed

2 files changed

+113
-34
lines changed

flang/lib/Semantics/resolve-names.cpp

Lines changed: 51 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -135,14 +135,15 @@ class MessageHandler {
135135
// + AttrsVisitor
136136
// | + DeclTypeSpecVisitor
137137
// | + ImplicitRulesVisitor
138-
// | + ScopeHandler -----------+--+
139-
// | + ModuleVisitor ========|==+
140-
// | + InterfaceVisitor | |
141-
// | +-+ SubprogramVisitor ==|==+
142-
// + ArraySpecVisitor | |
143-
// + DeclarationVisitor <--------+ |
144-
// + ConstructVisitor |
145-
// + ResolveNamesVisitor <------+
138+
// | + ScopeHandler ------------------+
139+
// | + ModuleVisitor -------------+ |
140+
// | + GenericHandler -------+ | |
141+
// | | + InterfaceVisitor | | |
142+
// | +-+ SubprogramVisitor ==|==+ | |
143+
// + ArraySpecVisitor | | | |
144+
// + DeclarationVisitor <--------+ | | |
145+
// + ConstructVisitor | | |
146+
// + ResolveNamesVisitor <------+-+-+
146147

147148
class BaseVisitor {
148149
public:
@@ -809,7 +810,23 @@ class ModuleVisitor : public virtual ScopeHandler {
809810
Scope *ancestor = nullptr);
810811
};
811812

812-
class InterfaceVisitor : public virtual ScopeHandler {
813+
class GenericHandler : public virtual ScopeHandler {
814+
protected:
815+
using ProcedureKind = parser::ProcedureStmt::Kind;
816+
void ResolveSpecificsInGeneric(Symbol &, bool isEndOfSpecificationPart);
817+
void DeclaredPossibleSpecificProc(Symbol &);
818+
819+
// Mappings of generics to their as-yet specific proc names and kinds
820+
using SpecificProcMapType =
821+
std::multimap<Symbol *, std::pair<const parser::Name *, ProcedureKind>>;
822+
SpecificProcMapType specificsForGenericProcs_;
823+
// inversion of SpecificProcMapType: maps pending proc names to generics
824+
using GenericProcMapType = std::multimap<SourceName, Symbol *>;
825+
GenericProcMapType genericsForSpecificProcs_;
826+
};
827+
828+
class InterfaceVisitor : public virtual ScopeHandler,
829+
public virtual GenericHandler {
813830
public:
814831
bool Pre(const parser::InterfaceStmt &);
815832
void Post(const parser::InterfaceStmt &);
@@ -840,15 +857,7 @@ class InterfaceVisitor : public virtual ScopeHandler {
840857
std::stack<GenericInfo> genericInfo_;
841858
const GenericInfo &GetGenericInfo() const { return genericInfo_.top(); }
842859
void SetGenericSymbol(Symbol &symbol) { genericInfo_.top().symbol = &symbol; }
843-
844-
using ProcedureKind = parser::ProcedureStmt::Kind;
845-
// mapping of generic to its specific proc names and kinds
846-
using SpecificProcMapType =
847-
std::multimap<Symbol *, std::pair<const parser::Name *, ProcedureKind>>;
848-
SpecificProcMapType specificProcs_;
849-
850860
void AddSpecificProcs(const std::list<parser::Name> &, ProcedureKind);
851-
void ResolveSpecificsInGeneric(Symbol &, bool isEndOfSpecificationPart);
852861
void ResolveNewSpecifics();
853862
};
854863

@@ -904,7 +913,7 @@ class SubprogramVisitor : public virtual ScopeHandler, public InterfaceVisitor {
904913
};
905914

906915
class DeclarationVisitor : public ArraySpecVisitor,
907-
public virtual ScopeHandler {
916+
public virtual GenericHandler {
908917
public:
909918
using ArraySpecVisitor::Post;
910919
using ScopeHandler::Post;
@@ -3309,35 +3318,32 @@ bool InterfaceVisitor::isAbstract() const {
33093318

33103319
void InterfaceVisitor::AddSpecificProcs(
33113320
const std::list<parser::Name> &names, ProcedureKind kind) {
3312-
for (const auto &name : names) {
3313-
specificProcs_.emplace(
3314-
GetGenericInfo().symbol, std::make_pair(&name, kind));
3321+
if (Symbol * symbol{GetGenericInfo().symbol};
3322+
symbol && symbol->has<GenericDetails>()) {
3323+
for (const auto &name : names) {
3324+
specificsForGenericProcs_.emplace(symbol, std::make_pair(&name, kind));
3325+
genericsForSpecificProcs_.emplace(name.source, symbol);
3326+
}
33153327
}
33163328
}
33173329

33183330
// By now we should have seen all specific procedures referenced by name in
33193331
// this generic interface. Resolve those names to symbols.
3320-
void InterfaceVisitor::ResolveSpecificsInGeneric(
3332+
void GenericHandler::ResolveSpecificsInGeneric(
33213333
Symbol &generic, bool isEndOfSpecificationPart) {
33223334
auto &details{generic.get<GenericDetails>()};
33233335
UnorderedSymbolSet symbolsSeen;
33243336
for (const Symbol &symbol : details.specificProcs()) {
33253337
symbolsSeen.insert(symbol.GetUltimate());
33263338
}
3327-
auto range{specificProcs_.equal_range(&generic)};
3339+
auto range{specificsForGenericProcs_.equal_range(&generic)};
33283340
SpecificProcMapType retain;
33293341
for (auto it{range.first}; it != range.second; ++it) {
33303342
const parser::Name *name{it->second.first};
33313343
auto kind{it->second.second};
3332-
const Symbol *symbol{FindSymbol(*name)};
3333-
if (!isEndOfSpecificationPart && symbol &&
3334-
&symbol->owner() != &generic.owner()) {
3335-
// Don't mistakenly use a name from the enclosing scope while there's
3336-
// still a chance that it could be overridden by a later declaration in
3337-
// this scope.
3338-
retain.emplace(&generic, std::make_pair(name, kind));
3339-
continue;
3340-
}
3344+
const Symbol *symbol{isEndOfSpecificationPart
3345+
? FindSymbol(*name)
3346+
: FindInScope(generic.owner(), *name)};
33413347
ProcedureDefinitionClass defClass{ProcedureDefinitionClass::None};
33423348
const Symbol *specific{symbol};
33433349
const Symbol *ultimate{nullptr};
@@ -3400,8 +3406,15 @@ void InterfaceVisitor::ResolveSpecificsInGeneric(
34003406
MakeOpName(generic.name()));
34013407
}
34023408
}
3403-
specificProcs_.erase(range.first, range.second);
3404-
specificProcs_.merge(std::move(retain));
3409+
specificsForGenericProcs_.erase(range.first, range.second);
3410+
specificsForGenericProcs_.merge(std::move(retain));
3411+
}
3412+
3413+
void GenericHandler::DeclaredPossibleSpecificProc(Symbol &proc) {
3414+
auto range{genericsForSpecificProcs_.equal_range(proc.name())};
3415+
for (auto iter{range.first}; iter != range.second; ++iter) {
3416+
ResolveSpecificsInGeneric(*iter->second, false);
3417+
}
34053418
}
34063419

34073420
void InterfaceVisitor::ResolveNewSpecifics() {
@@ -4141,6 +4154,9 @@ void SubprogramVisitor::EndSubprogram(
41414154
}
41424155
}
41434156
}
4157+
if (inInterfaceBlock() && currScope().symbol()) {
4158+
DeclaredPossibleSpecificProc(*currScope().symbol());
4159+
}
41444160
PopScope();
41454161
}
41464162

@@ -5477,6 +5493,7 @@ void DeclarationVisitor::Post(const parser::ProcDecl &x) {
54775493
if (dtDetails) {
54785494
dtDetails->add_component(symbol);
54795495
}
5496+
DeclaredPossibleSpecificProc(symbol);
54805497
}
54815498

54825499
bool DeclarationVisitor::Pre(const parser::TypeBoundProcedurePart &) {

flang/test/Semantics/symbol29.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+
! References to generic functions with forward-referenced specifics.
3+
!DEF: /m Module
4+
module m
5+
contains
6+
!DEF: /m/specific4 PUBLIC (Function) Subprogram INTEGER(4)
7+
!DEF: /m/specific4/x INTENT(IN) ObjectEntity INTEGER(4)
8+
integer function specific4(x)
9+
!REF: /m/specific4/x
10+
integer, intent(in) :: x(*)
11+
end function
12+
!DEF: /m/test PUBLIC (Subroutine) Subprogram
13+
!DEF: /m/test/specific1 EXTERNAL (Function) Subprogram INTEGER(4)
14+
subroutine test (specific1)
15+
!DEF: /m/test/generic (Function) Generic
16+
interface generic
17+
!REF: /m/test/specific1
18+
procedure :: specific1
19+
!DEF: /m/test/specific2 EXTERNAL, PURE (Function) Subprogram INTEGER(4)
20+
procedure :: specific2
21+
!DEF: /m/test/specific3 EXTERNAL (Function) Subprogram INTEGER(4)
22+
procedure :: specific3
23+
!DEF: /m/test/specific4 EXTERNAL (Function) Subprogram INTEGER(4)
24+
procedure :: specific4
25+
end interface
26+
interface
27+
!REF: /m/test/specific1
28+
!DEF: /m/test/specific1/x INTENT(IN) ObjectEntity INTEGER(4)
29+
integer function specific1(x)
30+
!REF: /m/test/specific1/x
31+
integer, intent(in) :: x
32+
end function
33+
!REF: /m/test/specific2
34+
!DEF: /m/test/specific2/x INTENT(IN) ObjectEntity INTEGER(4)
35+
!DEF: /m/test/specific2/y INTENT(IN) ObjectEntity INTEGER(4)
36+
pure integer function specific2(x, y)
37+
!REF: /m/test/specific2/x
38+
!REF: /m/test/specific2/y
39+
integer, intent(in) :: x, y
40+
end function
41+
!REF: /m/test/specific3
42+
!DEF: /m/test/specific3/x INTENT(IN) ObjectEntity INTEGER(4)
43+
!DEF: /m/test/specific3/y INTENT(IN) ObjectEntity INTEGER(4)
44+
integer function specific3(x, y)
45+
!REF: /m/test/generic
46+
import :: generic
47+
!REF: /m/test/specific3/x
48+
!REF: /m/test/specific3/y
49+
!REF: /m/test/specific2
50+
integer, intent(in) :: x, y(generic(1, x))
51+
end function
52+
!REF: /m/test/specific4
53+
!DEF: /m/test/specific4/x INTENT(IN) ObjectEntity INTEGER(4)
54+
integer function specific4(x)
55+
!REF: /m/test/specific4/x
56+
integer, intent(in) :: x(:)
57+
end function
58+
end interface
59+
!REF: /m/test/specific4
60+
print *, generic([1])
61+
end subroutine
62+
end module

0 commit comments

Comments
 (0)