diff options
Diffstat (limited to 'flang/lib/Semantics/runtime-type-info.cpp')
-rw-r--r-- | flang/lib/Semantics/runtime-type-info.cpp | 268 |
1 files changed, 192 insertions, 76 deletions
diff --git a/flang/lib/Semantics/runtime-type-info.cpp b/flang/lib/Semantics/runtime-type-info.cpp index 5f62a0870745..827bb8e9fbf7 100644 --- a/flang/lib/Semantics/runtime-type-info.cpp +++ b/flang/lib/Semantics/runtime-type-info.cpp @@ -1037,32 +1037,31 @@ RuntimeTableBuilder::DescribeSpecialGenerics(const Scope &dtScope, void RuntimeTableBuilder::DescribeSpecialGeneric(const GenericDetails &generic, std::map<int, evaluate::StructureConstructor> &specials, const Scope &dtScope, const DerivedTypeSpec *derivedTypeSpec) const { - common::visit(common::visitors{ - [&](const GenericKind::OtherKind &k) { - if (k == GenericKind::OtherKind::Assignment) { - for (auto ref : generic.specificProcs()) { - DescribeSpecialProc(specials, *ref, true, - false /*!final*/, std::nullopt, &dtScope, - derivedTypeSpec, true); - } - } - }, - [&](const common::DefinedIo &io) { - switch (io) { - case common::DefinedIo::ReadFormatted: - case common::DefinedIo::ReadUnformatted: - case common::DefinedIo::WriteFormatted: - case common::DefinedIo::WriteUnformatted: - for (auto ref : generic.specificProcs()) { - DescribeSpecialProc(specials, *ref, false, - false /*!final*/, io, &dtScope, derivedTypeSpec, - true); - } - break; - } - }, - [](const auto &) {}, - }, + common::visit( + common::visitors{ + [&](const GenericKind::OtherKind &k) { + if (k == GenericKind::OtherKind::Assignment) { + for (auto ref : generic.specificProcs()) { + DescribeSpecialProc(specials, *ref, true, false /*!final*/, + std::nullopt, &dtScope, derivedTypeSpec, true); + } + } + }, + [&](const common::DefinedIo &io) { + switch (io) { + case common::DefinedIo::ReadFormatted: + case common::DefinedIo::ReadUnformatted: + case common::DefinedIo::WriteFormatted: + case common::DefinedIo::WriteUnformatted: + for (auto ref : generic.specificProcs()) { + DescribeSpecialProc(specials, *ref, false, false /*!final*/, io, + &dtScope, derivedTypeSpec, true); + } + break; + } + }, + [](const auto &) {}, + }, generic.kind().u); } @@ -1219,68 +1218,93 @@ RuntimeDerivedTypeTables BuildRuntimeDerivedTypeTables( return result; } +// Find the type of a defined I/O procedure's interface's initial "dtv" +// dummy argument. Returns a non-null DeclTypeSpec pointer only if that +// dtv argument exists and is a derived type. +static const DeclTypeSpec *GetDefinedIoSpecificArgType(const Symbol &specific) { + const Symbol *interface { + &specific.GetUltimate() + }; + if (const auto *procEntity{specific.detailsIf<ProcEntityDetails>()}) { + interface = procEntity->procInterface(); + } + if (interface) { + if (const SubprogramDetails * + subprogram{interface->detailsIf<SubprogramDetails>()}; + subprogram && !subprogram->dummyArgs().empty()) { + if (const Symbol * dtvArg{subprogram->dummyArgs().at(0)}) { + if (const DeclTypeSpec * declType{dtvArg->GetType()}) { + return declType->AsDerived() ? declType : nullptr; + } + } + } + } + return nullptr; +} + +// Locate a particular scope's generic interface for a specific kind of +// defined I/O. +static const Symbol *FindGenericDefinedIo( + const Scope &scope, common::DefinedIo which) { + if (const Symbol * symbol{scope.FindSymbol(GenericKind::AsFortran(which))}) { + const Symbol &generic{symbol->GetUltimate()}; + const auto &genericDetails{generic.get<GenericDetails>()}; + CHECK(std::holds_alternative<common::DefinedIo>(genericDetails.kind().u)); + CHECK(std::get<common::DefinedIo>(genericDetails.kind().u) == which); + return &generic; + } else { + return nullptr; + } +} + std::multimap<const Symbol *, NonTbpDefinedIo> -CollectNonTbpDefinedIoGenericInterfaces(const Scope &scope) { +CollectNonTbpDefinedIoGenericInterfaces( + const Scope &scope, bool useRuntimeTypeInfoEntries) { std::multimap<const Symbol *, NonTbpDefinedIo> result; if (!scope.IsTopLevel() && (scope.GetImportKind() == Scope::ImportKind::All || scope.GetImportKind() == Scope::ImportKind::Default)) { - result = CollectNonTbpDefinedIoGenericInterfaces(scope.parent()); + result = CollectNonTbpDefinedIoGenericInterfaces( + scope.parent(), useRuntimeTypeInfoEntries); } if (scope.kind() != Scope::Kind::DerivedType) { for (common::DefinedIo which : {common::DefinedIo::ReadFormatted, common::DefinedIo::ReadUnformatted, common::DefinedIo::WriteFormatted, common::DefinedIo::WriteUnformatted}) { - if (auto iter{scope.find(GenericKind::AsFortran(which))}; - iter != scope.end()) { - const Symbol &generic{iter->second->GetUltimate()}; - const auto *genericDetails{generic.detailsIf<GenericDetails>()}; - CHECK(genericDetails != nullptr); - CHECK(std::holds_alternative<common::DefinedIo>( - genericDetails->kind().u)); - CHECK(std::get<common::DefinedIo>(genericDetails->kind().u) == which); - for (auto specific : genericDetails->specificProcs()) { - const Symbol *interface { - &specific->GetUltimate() - }; - if (const auto *procEntity{ - specific->detailsIf<ProcEntityDetails>()}) { - interface = procEntity->procInterface(); - } - const SubprogramDetails *subprogram{ - interface ? interface->detailsIf<SubprogramDetails>() : nullptr}; - const Symbol *dtvArg{subprogram && subprogram->dummyArgs().size() > 0 - ? subprogram->dummyArgs().at(0) - : nullptr}; - const DeclTypeSpec *declType{dtvArg ? dtvArg->GetType() : nullptr}; - const DerivedTypeSpec *derived{ - declType ? declType->AsDerived() : nullptr}; - if (const Symbol * - dtDesc{derived && derived->scope() - ? derived->scope()->runtimeDerivedTypeDescription() - : nullptr}) { - if (&derived->scope()->parent() == &generic.owner()) { - // This non-TBP defined I/O generic was defined in the - // same scope as the derived type, and it will be - // included in the derived type's special bindings - // by IncorporateDefinedIoGenericInterfaces(). - } else { - // Local scope's specific overrides host's for this type - bool updated{false}; - for (auto [iter, end]{result.equal_range(dtDesc)}; iter != end; - ++iter) { - NonTbpDefinedIo &nonTbp{iter->second}; - if (nonTbp.definedIo == which) { - nonTbp.subroutine = &*specific; - nonTbp.isDtvArgPolymorphic = declType->IsPolymorphic(); - updated = true; + auto name{GenericKind::AsFortran(which)}; + if (const Symbol * generic{FindGenericDefinedIo(scope, which)}) { + for (auto specific : generic->get<GenericDetails>().specificProcs()) { + if (const DeclTypeSpec * + declType{GetDefinedIoSpecificArgType(*specific)}) { + const DerivedTypeSpec &derived{DEREF(declType->AsDerived())}; + if (const Symbol * + dtDesc{derived.scope() + ? derived.scope()->runtimeDerivedTypeDescription() + : nullptr}) { + if (useRuntimeTypeInfoEntries && + &derived.scope()->parent() == &generic->owner()) { + // This non-TBP defined I/O generic was defined in the + // same scope as the derived type, and it will be + // included in the derived type's special bindings + // by IncorporateDefinedIoGenericInterfaces(). + } else { + // Local scope's specific overrides host's for this type + bool updated{false}; + for (auto [iter, end]{result.equal_range(dtDesc)}; iter != end; + ++iter) { + NonTbpDefinedIo &nonTbp{iter->second}; + if (nonTbp.definedIo == which) { + nonTbp.subroutine = &*specific; + nonTbp.isDtvArgPolymorphic = declType->IsPolymorphic(); + updated = true; + } + } + if (!updated) { + result.emplace(dtDesc, + NonTbpDefinedIo{ + &*specific, which, declType->IsPolymorphic()}); } - } - if (!updated) { - result.emplace(dtDesc, - NonTbpDefinedIo{ - &*specific, which, declType->IsPolymorphic()}); } } } @@ -1291,4 +1315,96 @@ CollectNonTbpDefinedIoGenericInterfaces(const Scope &scope) { return result; } +// ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces() +// +// Returns a true result when a kind of defined I/O generic procedure +// has a type (from a symbol or a NAMELIST) such that +// (1) there is a specific procedure matching that type for a non-type-bound +// generic defined in the scope of the type, and +// (2) that specific procedure is unavailable or overridden in a particular +// local scope. +// Specific procedures of non-type-bound defined I/O generic interfaces +// declared in the scope of a derived type are identified as special bindings +// in the derived type's runtime type information, as if they had been +// type-bound. This predicate is meant to determine local situations in +// which those special bindings are not to be used. Its result is intended +// to be put into the "ignoreNonTbpEntries" flag of +// runtime::NonTbpDefinedIoTable and passed (negated) as the +// "useRuntimeTypeInfoEntries" argument of +// CollectNonTbpDefinedIoGenericInterfaces() above. + +static const Symbol *FindSpecificDefinedIo(const Scope &scope, + const evaluate::DynamicType &derived, common::DefinedIo which) { + if (const Symbol * generic{FindGenericDefinedIo(scope, which)}) { + for (auto ref : generic->get<GenericDetails>().specificProcs()) { + const Symbol &specific{*ref}; + if (const DeclTypeSpec * + thisType{GetDefinedIoSpecificArgType(specific)}) { + if (evaluate::DynamicType{DEREF(thisType->AsDerived()), true} + .IsTkCompatibleWith(derived)) { + return &specific.GetUltimate(); + } + } + } + } + return nullptr; +} + +bool ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces( + const Scope &scope, const DerivedTypeSpec *derived) { + if (!derived) { + return false; + } + const Symbol &typeSymbol{derived->typeSymbol()}; + const Scope &typeScope{typeSymbol.GetUltimate().owner()}; + evaluate::DynamicType dyType{*derived}; + for (common::DefinedIo which : + {common::DefinedIo::ReadFormatted, common::DefinedIo::ReadUnformatted, + common::DefinedIo::WriteFormatted, + common::DefinedIo::WriteUnformatted}) { + if (const Symbol * + specific{FindSpecificDefinedIo(typeScope, dyType, which)}) { + // There's a non-TBP defined I/O procedure in the scope of the type's + // definition that applies to this type. It will appear in the type's + // runtime information. Determine whether it still applies in the + // scope of interest. + if (FindSpecificDefinedIo(scope, dyType, which) != specific) { + return true; + } + } + } + return false; +} + +bool ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces( + const Scope &scope, const DeclTypeSpec *type) { + return type && + ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces( + scope, type->AsDerived()); +} + +bool ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces( + const Scope &scope, const Symbol *symbol) { + if (!symbol) { + return false; + } + return common::visit( + common::visitors{ + [&](const NamelistDetails &x) { + for (auto ref : x.objects()) { + if (ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces( + scope, &*ref)) { + return true; + } + } + return false; + }, + [&](const auto &) { + return ShouldIgnoreRuntimeTypeInfoNonTbpGenericInterfaces( + scope, symbol->GetType()); + }, + }, + symbol->GetUltimate().details()); +} + } // namespace Fortran::semantics |