[flang] Always incorporate parent types' special generic bindings
The runtime type information table generator was broken when dealing with an extension derived type that didn't include a special generic procedure binding for ASSIGNMENT(=) or user-defined I/O, but one of whose ancestor types did. Ensure that the runtime derived type info tables have complete subtables for all of these special bindings, and respect any overrides that may have been defined. Motivating example: type parent contains procedure :: dtWrite => dtWrite1 generic :: write(formatted) => dtWrite end type type, extends(parent) :: extended contains procedure :: dtWrite => dtWrite2 end type The runtime derived type information table for "extended" must include a special generic procedure entry for "write(formatted)" that points to "dtWrite2" even though "extend" has no generic procedure for "write(formatted)". Differential Revision: https://reviews.llvm.org/D144148
This commit is contained in:
parent
1538761303
commit
7ed26ad10c
|
@ -67,11 +67,16 @@ private:
|
|||
SomeExpr PackageIntValueExpr(const SomeExpr &genre, std::int64_t = 0) const;
|
||||
std::vector<evaluate::StructureConstructor> DescribeBindings(
|
||||
const Scope &dtScope, Scope &);
|
||||
void DescribeGeneric(const GenericDetails &,
|
||||
std::map<int, evaluate::StructureConstructor> &, const DerivedTypeSpec *);
|
||||
std::map<int, evaluate::StructureConstructor> DescribeSpecialGenerics(
|
||||
const Scope &dtScope, const Scope &thisScope,
|
||||
const DerivedTypeSpec *) const;
|
||||
void DescribeSpecialGeneric(const GenericDetails &,
|
||||
std::map<int, evaluate::StructureConstructor> &, const Scope &,
|
||||
const DerivedTypeSpec *) const;
|
||||
void DescribeSpecialProc(std::map<int, evaluate::StructureConstructor> &,
|
||||
const Symbol &specificOrBinding, bool isAssignment, bool isFinal,
|
||||
std::optional<GenericKind::DefinedIo>, const DerivedTypeSpec *);
|
||||
std::optional<GenericKind::DefinedIo>, const Scope *,
|
||||
const DerivedTypeSpec *) const;
|
||||
void IncorporateDefinedIoGenericInterfaces(
|
||||
std::map<int, evaluate::StructureConstructor> &, GenericKind::DefinedIo,
|
||||
const Scope *, const DerivedTypeSpec *);
|
||||
|
@ -498,7 +503,6 @@ const Symbol *RuntimeTableBuilder::DescribeType(Scope &dtScope) {
|
|||
if (!isPDTdefinitionWithKindParameters) {
|
||||
std::vector<const Symbol *> dataComponentSymbols;
|
||||
std::vector<evaluate::StructureConstructor> procPtrComponents;
|
||||
std::map<int, evaluate::StructureConstructor> specials;
|
||||
for (const auto &pair : dtScope) {
|
||||
const Symbol &symbol{*pair.second};
|
||||
auto locationRestorer{common::ScopedSet(location_, symbol.name())};
|
||||
|
@ -518,8 +522,7 @@ const Symbol *RuntimeTableBuilder::DescribeType(Scope &dtScope) {
|
|||
},
|
||||
[&](const ProcBindingDetails &) { // handled in a later pass
|
||||
},
|
||||
[&](const GenericDetails &generic) {
|
||||
DescribeGeneric(generic, specials, derivedTypeSpec);
|
||||
[&](const GenericDetails &) { // ditto
|
||||
},
|
||||
[&](const auto &) {
|
||||
common::die(
|
||||
|
@ -565,11 +568,15 @@ const Symbol *RuntimeTableBuilder::DescribeType(Scope &dtScope) {
|
|||
evaluate::ConstantSubscripts{
|
||||
static_cast<evaluate::ConstantSubscript>(bindings.size())}));
|
||||
// Describe "special" bindings to defined assignments, FINAL subroutines,
|
||||
// and user-defined derived type I/O subroutines.
|
||||
// and user-defined derived type I/O subroutines. Defined assignments
|
||||
// and I/O subroutines override any parent bindings; FINAL subroutines
|
||||
// do not (the runtime will call all of them).
|
||||
std::map<int, evaluate::StructureConstructor> specials{
|
||||
DescribeSpecialGenerics(dtScope, dtScope, derivedTypeSpec)};
|
||||
const DerivedTypeDetails &dtDetails{dtSymbol->get<DerivedTypeDetails>()};
|
||||
for (const auto &pair : dtDetails.finals()) {
|
||||
DescribeSpecialProc(specials, *pair.second, false /*!isAssignment*/,
|
||||
true, std::nullopt, derivedTypeSpec);
|
||||
true, std::nullopt, nullptr, derivedTypeSpec);
|
||||
}
|
||||
if (derivedTypeSpec) {
|
||||
IncorporateDefinedIoGenericInterfaces(specials,
|
||||
|
@ -986,15 +993,33 @@ RuntimeTableBuilder::DescribeBindings(const Scope &dtScope, Scope &scope) {
|
|||
return result;
|
||||
}
|
||||
|
||||
void RuntimeTableBuilder::DescribeGeneric(const GenericDetails &generic,
|
||||
std::map<int, evaluate::StructureConstructor>
|
||||
RuntimeTableBuilder::DescribeSpecialGenerics(const Scope &dtScope,
|
||||
const Scope &thisScope, const DerivedTypeSpec *derivedTypeSpec) const {
|
||||
std::map<int, evaluate::StructureConstructor> specials;
|
||||
if (const Scope * parentScope{dtScope.GetDerivedTypeParent()}) {
|
||||
specials =
|
||||
DescribeSpecialGenerics(*parentScope, thisScope, derivedTypeSpec);
|
||||
}
|
||||
for (auto pair : dtScope) {
|
||||
const Symbol &symbol{*pair.second};
|
||||
if (const auto *generic{symbol.detailsIf<GenericDetails>()}) {
|
||||
DescribeSpecialGeneric(*generic, specials, thisScope, derivedTypeSpec);
|
||||
}
|
||||
}
|
||||
return specials;
|
||||
}
|
||||
|
||||
void RuntimeTableBuilder::DescribeSpecialGeneric(const GenericDetails &generic,
|
||||
std::map<int, evaluate::StructureConstructor> &specials,
|
||||
const DerivedTypeSpec *derivedTypeSpec) {
|
||||
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, derivedTypeSpec);
|
||||
false /*!final*/, std::nullopt, &dtScope,
|
||||
derivedTypeSpec);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1006,7 +1031,7 @@ void RuntimeTableBuilder::DescribeGeneric(const GenericDetails &generic,
|
|||
case GenericKind::DefinedIo::WriteUnformatted:
|
||||
for (auto ref : generic.specificProcs()) {
|
||||
DescribeSpecialProc(specials, *ref, false,
|
||||
false /*!final*/, io, derivedTypeSpec);
|
||||
false /*!final*/, io, &dtScope, derivedTypeSpec);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1019,9 +1044,13 @@ void RuntimeTableBuilder::DescribeGeneric(const GenericDetails &generic,
|
|||
void RuntimeTableBuilder::DescribeSpecialProc(
|
||||
std::map<int, evaluate::StructureConstructor> &specials,
|
||||
const Symbol &specificOrBinding, bool isAssignment, bool isFinal,
|
||||
std::optional<GenericKind::DefinedIo> io,
|
||||
const DerivedTypeSpec *derivedTypeSpec) {
|
||||
std::optional<GenericKind::DefinedIo> io, const Scope *dtScope,
|
||||
const DerivedTypeSpec *derivedTypeSpec) const {
|
||||
const auto *binding{specificOrBinding.detailsIf<ProcBindingDetails>()};
|
||||
if (binding && dtScope) { // use most recent override
|
||||
binding = &DEREF(dtScope->FindComponent(specificOrBinding.name()))
|
||||
.get<ProcBindingDetails>();
|
||||
}
|
||||
const Symbol &specific{*(binding ? &binding->symbol() : &specificOrBinding)};
|
||||
if (auto proc{evaluate::characteristics::Procedure::Characterize(
|
||||
specific, context_.foldingContext())}) {
|
||||
|
@ -1123,9 +1152,10 @@ void RuntimeTableBuilder::DescribeSpecialProc(
|
|||
IntExpr<1>(isArgDescriptorSet));
|
||||
AddValue(values, specialSchema_, "proc"s,
|
||||
SomeExpr{evaluate::ProcedureDesignator{specific}});
|
||||
auto pair{specials.try_emplace(
|
||||
*index, DEREF(specialSchema_.AsDerived()), std::move(values))};
|
||||
CHECK(pair.second); // ensure not already present
|
||||
// index might already be present in the case of an override
|
||||
specials.emplace(*index,
|
||||
evaluate::StructureConstructor{
|
||||
DEREF(specialSchema_.AsDerived()), std::move(values)});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1144,7 +1174,7 @@ void RuntimeTableBuilder::IncorporateDefinedIoGenericInterfaces(
|
|||
definedIo);
|
||||
for (auto ref : genericDetails.specificProcs()) {
|
||||
DescribeSpecialProc(
|
||||
specials, *ref, false, false, definedIo, derivedTypeSpec);
|
||||
specials, *ref, false, false, definedIo, nullptr, derivedTypeSpec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ module __Fortran_type_info
|
|||
! "TBP" bindings appear first. Inherited bindings, with overrides already
|
||||
! applied, appear in the initial entries in the same order as they
|
||||
! appear in the parent type's bindings, if any. They are followed
|
||||
! by new local bindings in alphabetic order of theing binding names.
|
||||
! by new local bindings in alphabetic order of their binding names.
|
||||
type(Binding), pointer, contiguous :: binding(:)
|
||||
character(len=:), pointer :: name
|
||||
integer(kind=int64) :: sizeInBytes
|
||||
|
|
|
@ -208,7 +208,7 @@ public:
|
|||
|
||||
const DerivedType *GetParentType() const;
|
||||
|
||||
// Finds a data component by name in this derived type or tis ancestors.
|
||||
// Finds a data component by name in this derived type or its ancestors.
|
||||
const Component *FindDataComponent(
|
||||
const char *name, std::size_t nameLen) const;
|
||||
|
||||
|
|
33
flang/test/Semantics/typeinfo02.f90
Normal file
33
flang/test/Semantics/typeinfo02.f90
Normal file
|
@ -0,0 +1,33 @@
|
|||
!RUN: bbc --dump-symbols %s | FileCheck %s
|
||||
!RUN: %flang_fc1 -fdebug-dump-symbols %s | FileCheck %s
|
||||
|
||||
module m1
|
||||
type base
|
||||
contains
|
||||
procedure :: wf => wf1
|
||||
generic :: write(formatted) => wf
|
||||
end type
|
||||
type, extends(base) :: extended
|
||||
contains
|
||||
procedure :: wf => wf2
|
||||
end type
|
||||
contains
|
||||
subroutine wf1(x,u,iot,v,iostat,iomsg)
|
||||
class(base), intent(in) :: x
|
||||
integer, intent(in) :: u
|
||||
character(len=*), intent(in) :: iot
|
||||
integer, intent(in) :: v(:)
|
||||
integer, intent(out) :: iostat
|
||||
character(len=*), intent(inout) :: iomsg
|
||||
end subroutine
|
||||
subroutine wf2(x,u,iot,v,iostat,iomsg)
|
||||
class(extended), intent(in) :: x
|
||||
integer, intent(in) :: u
|
||||
character(len=*), intent(in) :: iot
|
||||
integer, intent(in) :: v(:)
|
||||
integer, intent(out) :: iostat
|
||||
character(len=*), intent(inout) :: iomsg
|
||||
end subroutine
|
||||
end module
|
||||
!CHECK: .s.base, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=5_1,isargdescriptorset=1_1,proc=wf1)]
|
||||
!CHECK: .s.extended, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=5_1,isargdescriptorset=1_1,proc=wf2)]
|
Loading…
Reference in New Issue
Block a user