Skip to content

Commit a3e9d3c

Browse files
committed
[flang] Allow reference to earlier generic in later interface
Name resolutions defers all resolution and checking of specific procedures in non-type-bound generic interfaces to the end of the specification part. This prevents expression analysis of references to generic functions in specification expressions in interfaces from resolving. Example (now a new test case in modfile07.f90): ``` module m12 interface generic module procedure specific end interface interface module subroutine s(a1,a2) character(*) a1 character(generic(a1)) a2 ! <-- end end interface contains pure integer function specific(x) character(*), intent(in) :: x specific = len(x) end end ``` The solution is to partially resolve specific procedures as they are defined for each generic, when they can be resolved, with the final pass at the end of the specification part to finish up any forward references and emit the necessary error messages. Making this fix caused some issues in module file output, which have all been resolved by making this simplifying change: generics are now all emitted to module file specification parts as their own group of declarations at the end of the specification part, followed only by namelists and COMMON blocks. Differential Revision: https://reviews.llvm.org/D157346
1 parent 698ae66 commit a3e9d3c

File tree

11 files changed

+231
-178
lines changed

11 files changed

+231
-178
lines changed

flang/lib/Semantics/mod-file.cpp

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -271,13 +271,6 @@ void ModFileWriter::PutSymbol(
271271
}
272272
} else {
273273
PutGeneric(symbol);
274-
if (x.specific() && &x.specific()->owner() == &symbol.owner()) {
275-
PutSymbol(typeBindings, *x.specific());
276-
}
277-
if (x.derivedType() &&
278-
&x.derivedType()->owner() == &symbol.owner()) {
279-
PutSymbol(typeBindings, *x.derivedType());
280-
}
281274
}
282275
},
283276
[&](const UseDetails &) { PutUse(symbol); },
@@ -583,21 +576,8 @@ void ModFileWriter::PutUseExtraAttr(
583576
}
584577
}
585578

586-
// When a generic interface has the same name as a derived type
587-
// in the same scope, the generic shadows the derived type.
588-
// If the derived type were declared first, emit the generic
589-
// interface at the position of derived type's declaration.
590-
// (ReplaceName() is not used for this purpose because doing so
591-
// would confusingly position error messages pertaining to the generic
592-
// interface upon the derived type's declaration.)
593579
static inline SourceName NameInModuleFile(const Symbol &symbol) {
594-
if (const auto *generic{symbol.detailsIf<GenericDetails>()}) {
595-
if (const auto *derivedTypeOverload{generic->derivedType()}) {
596-
if (derivedTypeOverload->name().begin() < symbol.name().begin()) {
597-
return derivedTypeOverload->name();
598-
}
599-
}
600-
} else if (const auto *use{symbol.detailsIf<UseDetails>()}) {
580+
if (const auto *use{symbol.detailsIf<UseDetails>()}) {
601581
if (use->symbol().attrs().test(Attr::PRIVATE)) {
602582
// Avoid the use in sorting of names created to access private
603583
// specific procedures as a result of generic resolution;
@@ -609,17 +589,26 @@ static inline SourceName NameInModuleFile(const Symbol &symbol) {
609589
}
610590

611591
// Collect the symbols of this scope sorted by their original order, not name.
612-
// Namelists are an exception: they are sorted after other symbols.
592+
// Generics and namelists are exceptions: they are sorted after other symbols.
613593
void CollectSymbols(
614594
const Scope &scope, SymbolVector &sorted, SymbolVector &uses) {
615-
SymbolVector namelist;
595+
SymbolVector namelist, generics;
616596
std::size_t commonSize{scope.commonBlocks().size()};
617597
auto symbols{scope.GetSymbols()};
618598
sorted.reserve(symbols.size() + commonSize);
619599
for (SymbolRef symbol : symbols) {
620600
if (!symbol->test(Symbol::Flag::ParentComp)) {
621601
if (symbol->has<NamelistDetails>()) {
622602
namelist.push_back(symbol);
603+
} else if (const auto *generic{symbol->detailsIf<GenericDetails>()}) {
604+
if (generic->specific() &&
605+
&generic->specific()->owner() == &symbol->owner()) {
606+
sorted.push_back(*generic->specific());
607+
} else if (generic->derivedType() &&
608+
&generic->derivedType()->owner() == &symbol->owner()) {
609+
sorted.push_back(*generic->derivedType());
610+
}
611+
generics.push_back(symbol);
623612
} else {
624613
sorted.push_back(symbol);
625614
}
@@ -630,9 +619,12 @@ void CollectSymbols(
630619
}
631620
// Sort most symbols by name: use of Symbol::ReplaceName ensures the source
632621
// location of a symbol's name is the first "real" use.
633-
std::sort(sorted.begin(), sorted.end(), [](SymbolRef x, SymbolRef y) {
634-
return NameInModuleFile(x).begin() < NameInModuleFile(y).begin();
635-
});
622+
auto sorter{[](SymbolRef x, SymbolRef y) {
623+
return NameInModuleFile(*x).begin() < NameInModuleFile(*y).begin();
624+
}};
625+
std::sort(sorted.begin(), sorted.end(), sorter);
626+
std::sort(generics.begin(), generics.end(), sorter);
627+
sorted.insert(sorted.end(), generics.begin(), generics.end());
636628
sorted.insert(sorted.end(), namelist.begin(), namelist.end());
637629
for (const auto &pair : scope.commonBlocks()) {
638630
sorted.push_back(*pair.second);

flang/lib/Semantics/resolve-names.cpp

Lines changed: 68 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -843,11 +843,13 @@ class InterfaceVisitor : public virtual ScopeHandler {
843843

844844
using ProcedureKind = parser::ProcedureStmt::Kind;
845845
// mapping of generic to its specific proc names and kinds
846-
std::multimap<Symbol *, std::pair<const parser::Name *, ProcedureKind>>
847-
specificProcs_;
846+
using SpecificProcMapType =
847+
std::multimap<Symbol *, std::pair<const parser::Name *, ProcedureKind>>;
848+
SpecificProcMapType specificProcs_;
848849

849850
void AddSpecificProcs(const std::list<parser::Name> &, ProcedureKind);
850-
void ResolveSpecificsInGeneric(Symbol &generic);
851+
void ResolveSpecificsInGeneric(Symbol &, bool isEndOfSpecificationPart);
852+
void ResolveNewSpecifics();
851853
};
852854

853855
class SubprogramVisitor : public virtual ScopeHandler, public InterfaceVisitor {
@@ -3258,6 +3260,7 @@ bool InterfaceVisitor::Pre(const parser::InterfaceStmt &x) {
32583260
void InterfaceVisitor::Post(const parser::InterfaceStmt &) { EndAttrs(); }
32593261

32603262
void InterfaceVisitor::Post(const parser::EndInterfaceStmt &) {
3263+
ResolveNewSpecifics();
32613264
genericInfo_.pop();
32623265
}
32633266

@@ -3277,11 +3280,11 @@ bool InterfaceVisitor::Pre(const parser::GenericSpec &x) {
32773280
bool InterfaceVisitor::Pre(const parser::ProcedureStmt &x) {
32783281
if (!isGeneric()) {
32793282
Say("A PROCEDURE statement is only allowed in a generic interface block"_err_en_US);
3280-
return false;
3283+
} else {
3284+
auto kind{std::get<parser::ProcedureStmt::Kind>(x.t)};
3285+
const auto &names{std::get<std::list<parser::Name>>(x.t)};
3286+
AddSpecificProcs(names, kind);
32813287
}
3282-
auto kind{std::get<parser::ProcedureStmt::Kind>(x.t)};
3283-
const auto &names{std::get<std::list<parser::Name>>(x.t)};
3284-
AddSpecificProcs(names, kind);
32853288
return false;
32863289
}
32873290

@@ -3295,6 +3298,7 @@ void InterfaceVisitor::Post(const parser::GenericStmt &x) {
32953298
}
32963299
const auto &names{std::get<std::list<parser::Name>>(x.t)};
32973300
AddSpecificProcs(names, ProcedureKind::Procedure);
3301+
ResolveNewSpecifics();
32983302
genericInfo_.pop();
32993303
}
33003304

@@ -3318,36 +3322,48 @@ void InterfaceVisitor::AddSpecificProcs(
33183322

33193323
// By now we should have seen all specific procedures referenced by name in
33203324
// this generic interface. Resolve those names to symbols.
3321-
void InterfaceVisitor::ResolveSpecificsInGeneric(Symbol &generic) {
3325+
void InterfaceVisitor::ResolveSpecificsInGeneric(
3326+
Symbol &generic, bool isEndOfSpecificationPart) {
33223327
auto &details{generic.get<GenericDetails>()};
33233328
UnorderedSymbolSet symbolsSeen;
33243329
for (const Symbol &symbol : details.specificProcs()) {
33253330
symbolsSeen.insert(symbol.GetUltimate());
33263331
}
33273332
auto range{specificProcs_.equal_range(&generic)};
3333+
SpecificProcMapType retain;
33283334
for (auto it{range.first}; it != range.second; ++it) {
33293335
const parser::Name *name{it->second.first};
33303336
auto kind{it->second.second};
3331-
const auto *symbol{FindSymbol(*name)};
3332-
if (!symbol) {
3333-
Say(*name, "Procedure '%s' not found"_err_en_US);
3337+
const Symbol *symbol{FindSymbol(*name)};
3338+
if (!isEndOfSpecificationPart && symbol &&
3339+
&symbol->owner() != &generic.owner()) {
3340+
// Don't mistakenly use a name from the enclosing scope while there's
3341+
// still a chance that it could be overridden by a later declaration in
3342+
// this scope.
3343+
retain.emplace(&generic, std::make_pair(name, kind));
33343344
continue;
33353345
}
3336-
// Subtlety: when *symbol is a use- or host-association, the specific
3337-
// procedure that is recorded in the GenericDetails below must be *symbol,
3338-
// not the specific procedure shadowed by a generic, because that specific
3339-
// procedure may be a symbol from another module and its name unavailable to
3340-
// emit to a module file.
3341-
const Symbol &bypassed{BypassGeneric(*symbol)};
3342-
const Symbol &specific{
3343-
symbol == &symbol->GetUltimate() ? bypassed : *symbol};
3344-
const Symbol &ultimate{bypassed.GetUltimate()};
3345-
ProcedureDefinitionClass defClass{ClassifyProcedure(ultimate)};
3346+
ProcedureDefinitionClass defClass{ProcedureDefinitionClass::None};
3347+
const Symbol *specific{symbol};
3348+
const Symbol *ultimate{nullptr};
3349+
if (symbol) {
3350+
// Subtlety: when *symbol is a use- or host-association, the specific
3351+
// procedure that is recorded in the GenericDetails below must be *symbol,
3352+
// not the specific procedure shadowed by a generic, because that specific
3353+
// procedure may be a symbol from another module and its name unavailable
3354+
// to emit to a module file.
3355+
const Symbol &bypassed{BypassGeneric(*symbol)};
3356+
if (symbol == &symbol->GetUltimate()) {
3357+
specific = &bypassed;
3358+
}
3359+
ultimate = &bypassed.GetUltimate();
3360+
defClass = ClassifyProcedure(*ultimate);
3361+
}
3362+
std::optional<MessageFixedText> error;
33463363
if (defClass == ProcedureDefinitionClass::Module) {
33473364
// ok
33483365
} else if (kind == ProcedureKind::ModuleProcedure) {
3349-
Say(*name, "'%s' is not a module procedure"_err_en_US);
3350-
continue;
3366+
error = "'%s' is not a module procedure"_err_en_US;
33513367
} else {
33523368
switch (defClass) {
33533369
case ProcedureDefinitionClass::Intrinsic:
@@ -3357,47 +3373,58 @@ void InterfaceVisitor::ResolveSpecificsInGeneric(Symbol &generic) {
33573373
case ProcedureDefinitionClass::Pointer:
33583374
break;
33593375
case ProcedureDefinitionClass::None:
3360-
Say(*name, "'%s' is not a procedure"_err_en_US);
3361-
continue;
3376+
error = "'%s' is not a procedure"_err_en_US;
3377+
break;
33623378
default:
3363-
Say(*name,
3364-
"'%s' is not a procedure that can appear in a generic interface"_err_en_US);
3365-
continue;
3379+
error =
3380+
"'%s' is not a procedure that can appear in a generic interface"_err_en_US;
3381+
break;
33663382
}
33673383
}
3368-
if (symbolsSeen.insert(ultimate).second /*true if added*/) {
3384+
if (error) {
3385+
if (isEndOfSpecificationPart) {
3386+
Say(*name, std::move(*error));
3387+
} else {
3388+
// possible forward reference, catch it later
3389+
retain.emplace(&generic, std::make_pair(name, kind));
3390+
}
3391+
} else if (!ultimate) {
3392+
} else if (symbolsSeen.insert(*ultimate).second /*true if added*/) {
33693393
// When a specific procedure is a USE association, that association
33703394
// is saved in the generic's specifics, not its ultimate symbol,
33713395
// so that module file output of interfaces can distinguish them.
3372-
details.AddSpecificProc(specific, name->source);
3373-
} else if (&specific == &ultimate) {
3396+
details.AddSpecificProc(*specific, name->source);
3397+
} else if (specific == ultimate) {
33743398
Say(name->source,
33753399
"Procedure '%s' is already specified in generic '%s'"_err_en_US,
33763400
name->source, MakeOpName(generic.name()));
33773401
} else {
33783402
Say(name->source,
33793403
"Procedure '%s' from module '%s' is already specified in generic '%s'"_err_en_US,
3380-
ultimate.name(), ultimate.owner().GetName().value(),
3404+
ultimate->name(), ultimate->owner().GetName().value(),
33813405
MakeOpName(generic.name()));
33823406
}
33833407
}
33843408
specificProcs_.erase(range.first, range.second);
3409+
specificProcs_.merge(std::move(retain));
3410+
}
3411+
3412+
void InterfaceVisitor::ResolveNewSpecifics() {
3413+
if (Symbol * generic{genericInfo_.top().symbol};
3414+
generic && generic->has<GenericDetails>()) {
3415+
ResolveSpecificsInGeneric(*generic, false);
3416+
}
33853417
}
33863418

33873419
// Mixed interfaces are allowed by the standard.
33883420
// If there is a derived type with the same name, they must all be functions.
33893421
void InterfaceVisitor::CheckGenericProcedures(Symbol &generic) {
3390-
ResolveSpecificsInGeneric(generic);
3422+
ResolveSpecificsInGeneric(generic, true);
33913423
auto &details{generic.get<GenericDetails>()};
33923424
if (auto *proc{details.CheckSpecific()}) {
3393-
auto msg{
3394-
"'%s' should not be the name of both a generic interface and a"
3395-
" procedure unless it is a specific procedure of the generic"_warn_en_US};
3396-
if (proc->name().begin() > generic.name().begin()) {
3397-
Say(proc->name(), std::move(msg));
3398-
} else {
3399-
Say(generic.name(), std::move(msg));
3400-
}
3425+
Say(proc->name().begin() > generic.name().begin() ? proc->name()
3426+
: generic.name(),
3427+
"'%s' should not be the name of both a generic interface and a procedure unless it is a specific procedure of the generic"_warn_en_US);
34013428
}
34023429
auto &specifics{details.specificProcs()};
34033430
if (specifics.empty()) {

0 commit comments

Comments
 (0)