Skip to content

Commit

Permalink
[flang] Fix merging of use associated generics
Browse files Browse the repository at this point in the history
When we use-associate a generic interface name and then add more
procedures to the generic, we create a new symbol for the merged
generic. That symbol has to include a pointer to the derived type
or procedure with the same name, just as the original generic did.

To achieve that, change `AddSpecificProcsFrom` to also copy those
fields from the original symbol and change its name to `CopyFrom`
to reflect its new purpose. Also, change it to take `GenericDetails`
instead of `Symbol` as its argument so we can't call it on the wrong
kind of symbol.

Original-commit: flang-compiler/f18@1e22970
Reviewed-on: flang-compiler/f18#614
  • Loading branch information
tskeith committed Aug 1, 2019
1 parent 5e39c9a commit 723add0
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 9 deletions.
10 changes: 5 additions & 5 deletions flang/lib/semantics/resolve-names.cc
Expand Up @@ -1984,7 +1984,7 @@ void ModuleVisitor::AddUse(
// new generic in this scope
auto genericDetails{ultimate.get<GenericDetails>()};
genericDetails.set_useDetails(*useDetails);
genericDetails.AddSpecificProcsFrom(useSymbol);
genericDetails.CopyFrom(useSymbol.get<GenericDetails>());
EraseSymbol(localSymbol);
MakeSymbol(
localSymbol.name(), ultimate.attrs(), std::move(genericDetails));
Expand All @@ -1995,8 +1995,8 @@ void ModuleVisitor::AddUse(
auto *genericDetails{localSymbol.detailsIf<GenericDetails>()};
if (genericDetails && genericDetails->useDetails().has_value()) {
// localSymbol came from merging two use-associated generics
if (useSymbol.has<GenericDetails>()) {
genericDetails->AddSpecificProcsFrom(useSymbol);
if (auto *useDetails{useSymbol.detailsIf<GenericDetails>()}) {
genericDetails->CopyFrom(*useDetails);
} else {
ConvertToUseError(localSymbol, location, *useModuleScope_);
}
Expand Down Expand Up @@ -5051,8 +5051,8 @@ void ResolveNamesVisitor::CreateGeneric(const parser::GenericSpec &x) {
return; // already have generic, add to it
}
Symbol &ultimate{existing->GetUltimate()};
if (ultimate.has<GenericDetails>()) {
genericDetails.AddSpecificProcsFrom(ultimate);
if (auto *ultimateDetails{ultimate.detailsIf<GenericDetails>()}) {
genericDetails.CopyFrom(*ultimateDetails);
} else if (ultimate.has<SubprogramDetails>() ||
ultimate.has<SubprogramNameDetails>()) {
genericDetails.set_specific(ultimate);
Expand Down
12 changes: 10 additions & 2 deletions flang/lib/semantics/symbol.cc
Expand Up @@ -182,8 +182,16 @@ Symbol *GenericDetails::CheckSpecific() {
}
}

void GenericDetails::AddSpecificProcsFrom(const Symbol &generic) {
const auto &procs{generic.get<GenericDetails>().specificProcs()};
void GenericDetails::CopyFrom(const GenericDetails &from) {
if (from.specific_) {
CHECK(!specific_);
specific_ = from.specific_;
}
if (from.derivedType_) {
CHECK(!derivedType_);
derivedType_ = from.derivedType_;
}
auto &procs{from.specificProcs_};
specificProcs_.insert(specificProcs_.end(), procs.begin(), procs.end());
}

Expand Down
5 changes: 3 additions & 2 deletions flang/lib/semantics/symbol.h
Expand Up @@ -393,14 +393,12 @@ class GenericDetails {
public:
GenericDetails() {}
GenericDetails(const SymbolVector &specificProcs);
GenericDetails(Symbol *specific) : specific_{specific} {}

GenericKind kind() const { return kind_; }
void set_kind(GenericKind kind) { kind_ = kind; }

const SymbolVector &specificProcs() const { return specificProcs_; }
void add_specificProc(const Symbol &proc) { specificProcs_.push_back(&proc); }
void AddSpecificProcsFrom(const Symbol &generic);

// specific and derivedType indicate a specific procedure or derived type
// with the same name as this generic. Only one of them may be set.
Expand All @@ -411,6 +409,9 @@ class GenericDetails {
const Symbol *derivedType() const { return derivedType_; }
void set_derivedType(Symbol &derivedType);

// Copy in specificProcs, specific, and derivedType from another generic
void CopyFrom(const GenericDetails &);

// Check that specific is one of the specificProcs. If not, return the
// specific as a raw pointer.
const Symbol *CheckSpecific() const;
Expand Down
22 changes: 22 additions & 0 deletions flang/test/semantics/resolve18.f90
Expand Up @@ -76,3 +76,25 @@ module m4b
function foo(x)
end
end

! Use associating a name that is a generic and a derived type
module m5a
interface g
end interface
type g
end type
end module
module m5b
use m5a
interface g
procedure f
end interface
type(g) :: x
contains
function f(i)
end function
end module
subroutine s5
use m5b
type(g) :: y
end

0 comments on commit 723add0

Please sign in to comment.