[flang] Symbol representation for dummy SubprogramDetails

Dummy procedures can be defined as subprograms with explicit
interfaces, e.g.

  subroutine subr(dummy)
    interface
      subroutine dummy(x)
        real :: x
      end subroutine
    end interface
    ! ...
  end subroutine

but the symbol table had no means of marking such symbols as dummy
arguments, so predicates like IsDummy(dummy) would fail.  Add an
isDummy_ flag to SubprogramNameDetails, analogous to the corresponding
flag in EntityDetails, and set/test it as needed.

Differential Revision: https://reviews.llvm.org/D106697
This commit is contained in:
peter klausler 2021-07-22 14:53:50 -07:00
parent 5a865b0b1e
commit c4a65434d8
7 changed files with 27 additions and 9 deletions

View file

@ -76,6 +76,8 @@ public:
bool isFunction() const { return result_ != nullptr; }
bool isInterface() const { return isInterface_; }
void set_isInterface(bool value = true) { isInterface_ = value; }
bool isDummy() const { return isDummy_; }
void set_isDummy(bool value = true) { isDummy_ = value; }
Scope *entryScope() { return entryScope_; }
const Scope *entryScope() const { return entryScope_; }
void set_entryScope(Scope &scope) { entryScope_ = &scope; }
@ -95,6 +97,7 @@ public:
private:
bool isInterface_{false}; // true if this represents an interface-body
bool isDummy_{false}; // true when interface of dummy procedure
std::vector<Symbol *> dummyArgs_; // nullptr -> alternate return indicator
Symbol *result_{nullptr};
Scope *entryScope_{nullptr}; // if ENTRY, points to subprogram's scope

View file

@ -301,7 +301,9 @@ bool IsInitialProcedureTarget(const semantics::Symbol &symbol) {
const auto &ultimate{symbol.GetUltimate()};
return std::visit(
common::visitors{
[](const semantics::SubprogramDetails &) { return true; },
[](const semantics::SubprogramDetails &subp) {
return !subp.isDummy();
},
[](const semantics::SubprogramNameDetails &) { return true; },
[&](const semantics::ProcEntityDetails &proc) {
return !semantics::IsPointer(ultimate) && !proc.isDummy();

View file

@ -1136,6 +1136,7 @@ bool IsDummy(const Symbol &symbol) {
common::visitors{[](const EntityDetails &x) { return x.isDummy(); },
[](const ObjectEntityDetails &x) { return x.isDummy(); },
[](const ProcEntityDetails &x) { return x.isDummy(); },
[](const SubprogramDetails &x) { return x.isDummy(); },
[](const auto &) { return false; }},
ResolveAssociations(symbol).details());
}

View file

@ -845,6 +845,10 @@ void CheckHelper::CheckSubprogram(
}
}
}
// See comment on the similar check in CheckProcEntity()
if (details.isDummy() && symbol.attrs().test(Attr::ELEMENTAL)) {
messages_.Say("A dummy procedure may not be ELEMENTAL"_err_en_US);
}
}
void CheckHelper::CheckDerivedType(

View file

@ -564,6 +564,10 @@ public:
if (symbol->CanReplaceDetails(details)) {
// update the existing symbol
symbol->attrs() |= attrs;
if constexpr (std::is_same_v<SubprogramDetails, D>) {
// Dummy argument defined by explicit interface
details.set_isDummy(IsDummy(*symbol));
}
symbol->set_details(std::move(details));
return *symbol;
} else if constexpr (std::is_same_v<UnknownDetails, D>) {
@ -2972,7 +2976,7 @@ void SubprogramVisitor::Post(const parser::SubroutineStmt &stmt) {
auto &details{PostSubprogramStmt(name)};
for (const auto &dummyArg : std::get<std::list<parser::DummyArg>>(stmt.t)) {
if (const auto *dummyName{std::get_if<parser::Name>(&dummyArg.u)}) {
Symbol &dummy{MakeSymbol(*dummyName, EntityDetails(true))};
Symbol &dummy{MakeSymbol(*dummyName, EntityDetails{true})};
details.add_dummyArg(dummy);
} else {
details.add_alternateReturn();
@ -2984,7 +2988,7 @@ void SubprogramVisitor::Post(const parser::FunctionStmt &stmt) {
const auto &name{std::get<parser::Name>(stmt.t)};
auto &details{PostSubprogramStmt(name)};
for (const auto &dummyName : std::get<std::list<parser::Name>>(stmt.t)) {
Symbol &dummy{MakeSymbol(dummyName, EntityDetails(true))};
Symbol &dummy{MakeSymbol(dummyName, EntityDetails{true})};
details.add_dummyArg(dummy);
}
const parser::Name *funcResultName;
@ -3126,6 +3130,7 @@ void SubprogramVisitor::Post(const parser::EntryStmt &stmt) {
common::visitors{[](EntityDetails &x) { x.set_isDummy(); },
[](ObjectEntityDetails &x) { x.set_isDummy(); },
[](ProcEntityDetails &x) { x.set_isDummy(); },
[](SubprogramDetails &x) { x.set_isDummy(); },
[&](const auto &) {
Say2(dummyName->source,
"ENTRY dummy argument '%s' is previously declared as an item that may not be used as a dummy argument"_err_en_US,
@ -5842,12 +5847,13 @@ const parser::Name *DeclarationVisitor::ResolveDataRef(
[&](const Indirection<parser::ArrayElement> &y) {
Walk(y.value().subscripts);
const parser::Name *name{ResolveDataRef(y.value().base)};
if (!name) {
} else if (!name->symbol->has<ProcEntityDetails>()) {
ConvertToObjectEntity(*name->symbol);
} else if (!context().HasError(*name->symbol)) {
SayWithDecl(*name, *name->symbol,
"Cannot reference function '%s' as data"_err_en_US);
if (name && name->symbol) {
if (!IsProcedure(*name->symbol)) {
ConvertToObjectEntity(*name->symbol);
} else if (!context().HasError(*name->symbol)) {
SayWithDecl(*name, *name->symbol,
"Cannot reference function '%s' as data"_err_en_US);
}
}
return name;
},

View file

@ -85,6 +85,7 @@ void ModuleDetails::set_scope(const Scope *scope) {
llvm::raw_ostream &operator<<(
llvm::raw_ostream &os, const SubprogramDetails &x) {
DumpBool(os, "isInterface", x.isInterface_);
DumpBool(os, "dummy", x.isDummy_);
DumpOptional(os, "bindName", x.bindName());
if (x.result_) {
DumpType(os << " result:", x.result());

View file

@ -4,6 +4,7 @@
subroutine s01(elem, subr)
interface
!ERROR: A dummy procedure may not be ELEMENTAL
elemental real function elem(x)
real, intent(in), value :: x
end function