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 *);
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())};
},
[&](const ProcBindingDetails &) { // handled in a later pass
},
- [&](const GenericDetails &generic) {
- DescribeGeneric(generic, specials, derivedTypeSpec);
+ [&](const GenericDetails &) { // ditto
},
[&](const auto &) {
common::die(
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,
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);
}
}
},
case GenericKind::DefinedIo::WriteUnformatted:
for (auto ref : generic.specificProcs()) {
DescribeSpecialProc(specials, *ref, false,
- false /*!final*/, io, derivedTypeSpec);
+ false /*!final*/, io, &dtScope, derivedTypeSpec);
}
break;
}
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())}) {
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)});
}
}
definedIo);
for (auto ref : genericDetails.specificProcs()) {
DescribeSpecialProc(
- specials, *ref, false, false, definedIo, derivedTypeSpec);
+ specials, *ref, false, false, definedIo, nullptr, derivedTypeSpec);
}
}
}
--- /dev/null
+!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)]