Skip to content

[flang] Handle separate module procedures with INTERFACE dummy arguments #67608

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 40 additions & 16 deletions flang/lib/Semantics/resolve-names-utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,7 @@ class SymbolMapper : public evaluate::AnyTraverse<SymbolMapper, bool> {
return false;
}
void MapSymbolExprs(Symbol &);
Symbol *CopySymbol(const Symbol *);

private:
void MapParamValue(ParamValue &param) const { (*this)(param.GetExplicit()); }
Expand All @@ -797,16 +798,44 @@ class SymbolMapper : public evaluate::AnyTraverse<SymbolMapper, bool> {
SymbolAndTypeMappings &map_;
};

void SymbolMapper::MapSymbolExprs(Symbol &symbol) {
if (auto *object{symbol.detailsIf<ObjectEntityDetails>()}) {
if (const DeclTypeSpec *type{object->type()}) {
if (const DeclTypeSpec *newType{MapType(*type)}) {
object->ReplaceType(*newType);
Symbol *SymbolMapper::CopySymbol(const Symbol *symbol) {
if (symbol) {
if (auto *subp{symbol->detailsIf<SubprogramDetails>()}) {
if (subp->isInterface()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The else case of this is a no-op, there is never a case where one would want a non interface SubprogramDetails to be copied into a new scope?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a SubprogramDetails is not an interface, then it's not a dummy procedure and not a procedure pointer, and it doesn't need to be localized.

if (auto pair{scope_.try_emplace(symbol->name(), symbol->attrs())};
pair.second) {
Symbol &copy{*pair.first->second};
map_.symbolMap[symbol] = &copy;
copy.set(symbol->test(Symbol::Flag::Subroutine)
? Symbol::Flag::Subroutine
: Symbol::Flag::Function);
Scope &newScope{scope_.MakeScope(Scope::Kind::Subprogram, &copy)};
copy.set_scope(&newScope);
copy.set_details(SubprogramDetails{});
auto &newSubp{copy.get<SubprogramDetails>()};
newSubp.set_isInterface(true);
newSubp.set_isDummy(subp->isDummy());
newSubp.set_defaultIgnoreTKR(subp->defaultIgnoreTKR());
MapSubprogramToNewSymbols(*symbol, copy, newScope, &map_);
return &copy;
}
}
} else if (Symbol * copy{scope_.CopySymbol(*symbol)}) {
map_.symbolMap[symbol] = copy;
return copy;
}
}
return nullptr;
}

void SymbolMapper::MapSymbolExprs(Symbol &symbol) {
common::visit(
common::visitors{[&](ObjectEntityDetails &object) {
if (const DeclTypeSpec * type{object.type()}) {
if (const DeclTypeSpec * newType{MapType(*type)}) {
object.ReplaceType(*newType);
}
}
for (ShapeSpec &spec : object.shape()) {
MapShapeSpec(spec);
}
Expand Down Expand Up @@ -892,13 +921,7 @@ const Symbol *SymbolMapper::MapInterface(const Symbol *interface) {
return interface;
} else if (const auto *subp{interface->detailsIf<SubprogramDetails>()};
subp && subp->isInterface()) {
if (Symbol *newSymbol{scope_.CopySymbol(*interface)}) {
newSymbol->get<SubprogramDetails>().set_isInterface(true);
map_.symbolMap[interface] = newSymbol;
Scope &newScope{scope_.MakeScope(Scope::Kind::Subprogram, newSymbol)};
MapSubprogramToNewSymbols(*interface, *newSymbol, newScope, &map_);
return newSymbol;
}
return CopySymbol(interface);
}
}
return nullptr;
Expand All @@ -913,23 +936,24 @@ void MapSubprogramToNewSymbols(const Symbol &oldSymbol, Symbol &newSymbol,
mappings->symbolMap[&oldSymbol] = &newSymbol;
const auto &oldDetails{oldSymbol.get<SubprogramDetails>()};
auto &newDetails{newSymbol.get<SubprogramDetails>()};
SymbolMapper mapper{newScope, *mappings};
for (const Symbol *dummyArg : oldDetails.dummyArgs()) {
if (!dummyArg) {
newDetails.add_alternateReturn();
} else if (Symbol *copy{newScope.CopySymbol(*dummyArg)}) {
} else if (Symbol * copy{mapper.CopySymbol(dummyArg)}) {
copy->set(Symbol::Flag::Implicit, false);
newDetails.add_dummyArg(*copy);
mappings->symbolMap[dummyArg] = copy;
}
}
if (oldDetails.isFunction()) {
newScope.erase(newSymbol.name());
if (Symbol *copy{newScope.CopySymbol(oldDetails.result())}) {
const Symbol &result{oldDetails.result()};
if (Symbol * copy{mapper.CopySymbol(&result)}) {
newDetails.set_result(*copy);
mappings->symbolMap[&oldDetails.result()] = copy;
mappings->symbolMap[&result] = copy;
}
}
SymbolMapper mapper{newScope, *mappings};
for (auto &[_, ref] : newScope) {
mapper.MapSymbolExprs(*ref);
}
Expand Down
40 changes: 40 additions & 0 deletions flang/test/Semantics/separate-mp05.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
! RUN: %python %S/test_symbols.py %s %flang_fc1
! Ensure that SMPs work with dummy procedures declared as interfaces
!DEF: /m Module
module m
implicit none
interface
!DEF: /m/smp MODULE, PUBLIC, PURE (Function) Subprogram REAL(4)
!DEF: /m/smp/f EXTERNAL, PURE (Function) Subprogram REAL(4)
!DEF: /m/smp/x INTENT(IN) ObjectEntity REAL(4)
!DEF: /m/smp/res (Implicit) ObjectEntity REAL(4)
pure module function smp(f, x) result(res)
interface
!REF: /m/smp/f
!DEF: /m/smp/f/x INTENT(IN) ObjectEntity REAL(4)
!DEF: /m/smp/f/r ObjectEntity REAL(4)
pure function f(x) result(r)
!REF: /m/smp/f/x
real, intent(in) :: x
!REF: /m/smp/f/r
real r
end function
end interface
!REF: /m/smp/x
real, intent(in) :: x
end function
end interface
end module
!REF: /m
!DEF: /m/sm Module
submodule (m)sm
implicit none
contains
!DEF: /m/sm/smp MODULE, PUBLIC, PURE (Function) Subprogram REAL(4)
module procedure smp
!DEF: /m/sm/smp/res (Implicit) ObjectEntity REAL(4)
!DEF: /m/sm/smp/f EXTERNAL, PURE (Function) Subprogram REAL(4)
!DEF: /m/sm/smp/x INTENT(IN) ObjectEntity REAL(4)
res = f(x)
end procedure
end submodule