[flang-commits] [flang] ceccfc8 - [flang] Don't construct TBP bindings for abstract derived types
Peter Klausler via flang-commits
flang-commits at lists.llvm.org
Mon Aug 29 10:53:59 PDT 2022
Author: Peter Klausler
Date: 2022-08-29T10:53:43-07:00
New Revision: ceccfc85a0f70b79169974aeaf104026d4922635
URL: https://github.com/llvm/llvm-project/commit/ceccfc85a0f70b79169974aeaf104026d4922635
DIFF: https://github.com/llvm/llvm-project/commit/ceccfc85a0f70b79169974aeaf104026d4922635.diff
LOG: [flang] Don't construct TBP bindings for abstract derived types
The tables constructed by semantics that describe derived types to
the runtime support library must not include "vtable" entries for
the deferred type-bound procedures of abstract derived types;
these can turn out to be unsatisfiable external references to
procedures whose interfaces were used in the definitions of those
bindings.
Differential Revision: https://reviews.llvm.org/D132774
Added:
Modified:
flang/lib/Semantics/runtime-type-info.cpp
Removed:
################################################################################
diff --git a/flang/lib/Semantics/runtime-type-info.cpp b/flang/lib/Semantics/runtime-type-info.cpp
index eae8c0c977a2..ace2c8a6bb07 100644
--- a/flang/lib/Semantics/runtime-type-info.cpp
+++ b/flang/lib/Semantics/runtime-type-info.cpp
@@ -555,44 +555,47 @@ const Symbol *RuntimeTableBuilder::DescribeType(Scope &dtScope) {
static_cast<evaluate::ConstantSubscript>(
procPtrComponents.size())}));
// Compile the "vtable" of type-bound procedure bindings
- std::vector<evaluate::StructureConstructor> bindings{
- DescribeBindings(dtScope, scope)};
- AddValue(dtValues, derivedTypeSchema_, "binding"s,
- SaveDerivedPointerTarget(scope, SaveObjectName(".v."s + distinctName),
- std::move(bindings),
- evaluate::ConstantSubscripts{
- static_cast<evaluate::ConstantSubscript>(bindings.size())}));
- // Describe "special" bindings to defined assignments, FINAL subroutines,
- // and user-defined derived type I/O subroutines.
- const DerivedTypeDetails &dtDetails{dtSymbol->get<DerivedTypeDetails>()};
- for (const auto &pair : dtDetails.finals()) {
- DescribeSpecialProc(
- specials, *pair.second, false /*!isAssignment*/, true, std::nullopt);
- }
- IncorporateDefinedIoGenericInterfaces(
- specials, GenericKind::DefinedIo::ReadFormatted, &scope);
- IncorporateDefinedIoGenericInterfaces(
- specials, GenericKind::DefinedIo::ReadUnformatted, &scope);
- IncorporateDefinedIoGenericInterfaces(
- specials, GenericKind::DefinedIo::WriteFormatted, &scope);
- IncorporateDefinedIoGenericInterfaces(
- specials, GenericKind::DefinedIo::WriteUnformatted, &scope);
- // Pack the special procedure bindings in ascending order of their "which"
- // code values, and compile a little-endian bit-set of those codes for
- // use in O(1) look-up at run time.
- std::vector<evaluate::StructureConstructor> sortedSpecials;
std::uint32_t specialBitSet{0};
- for (auto &pair : specials) {
- auto bit{std::uint32_t{1} << pair.first};
- CHECK(!(specialBitSet & bit));
- specialBitSet |= bit;
- sortedSpecials.emplace_back(std::move(pair.second));
+ bool isAbstractType{dtSymbol->attrs().test(Attr::ABSTRACT)};
+ if (!isAbstractType) {
+ std::vector<evaluate::StructureConstructor> bindings{
+ DescribeBindings(dtScope, scope)};
+ AddValue(dtValues, derivedTypeSchema_, "binding"s,
+ SaveDerivedPointerTarget(scope, SaveObjectName(".v."s + distinctName),
+ std::move(bindings),
+ evaluate::ConstantSubscripts{
+ static_cast<evaluate::ConstantSubscript>(bindings.size())}));
+ // Describe "special" bindings to defined assignments, FINAL subroutines,
+ // and user-defined derived type I/O subroutines.
+ const DerivedTypeDetails &dtDetails{dtSymbol->get<DerivedTypeDetails>()};
+ for (const auto &pair : dtDetails.finals()) {
+ DescribeSpecialProc(specials, *pair.second, false /*!isAssignment*/,
+ true, std::nullopt);
+ }
+ IncorporateDefinedIoGenericInterfaces(
+ specials, GenericKind::DefinedIo::ReadFormatted, &scope);
+ IncorporateDefinedIoGenericInterfaces(
+ specials, GenericKind::DefinedIo::ReadUnformatted, &scope);
+ IncorporateDefinedIoGenericInterfaces(
+ specials, GenericKind::DefinedIo::WriteFormatted, &scope);
+ IncorporateDefinedIoGenericInterfaces(
+ specials, GenericKind::DefinedIo::WriteUnformatted, &scope);
+ // Pack the special procedure bindings in ascending order of their "which"
+ // code values, and compile a little-endian bit-set of those codes for
+ // use in O(1) look-up at run time.
+ std::vector<evaluate::StructureConstructor> sortedSpecials;
+ for (auto &pair : specials) {
+ auto bit{std::uint32_t{1} << pair.first};
+ CHECK(!(specialBitSet & bit));
+ specialBitSet |= bit;
+ sortedSpecials.emplace_back(std::move(pair.second));
+ }
+ AddValue(dtValues, derivedTypeSchema_, "special"s,
+ SaveDerivedPointerTarget(scope, SaveObjectName(".s."s + distinctName),
+ std::move(sortedSpecials),
+ evaluate::ConstantSubscripts{
+ static_cast<evaluate::ConstantSubscript>(specials.size())}));
}
- AddValue(dtValues, derivedTypeSchema_, "special"s,
- SaveDerivedPointerTarget(scope, SaveObjectName(".s."s + distinctName),
- std::move(sortedSpecials),
- evaluate::ConstantSubscripts{
- static_cast<evaluate::ConstantSubscript>(specials.size())}));
AddValue(dtValues, derivedTypeSchema_, "specialbitset"s,
IntExpr<4>(specialBitSet));
// Note the presence/absence of a parent component
@@ -602,14 +605,16 @@ const Symbol *RuntimeTableBuilder::DescribeType(Scope &dtScope) {
// instances without any initialized components, analyze the type
// and set a flag if there's nothing to do for it at run time.
AddValue(dtValues, derivedTypeSchema_, "noinitializationneeded"s,
- IntExpr<1>(
- derivedTypeSpec && !derivedTypeSpec->HasDefaultInitialization()));
+ IntExpr<1>(isAbstractType ||
+ (derivedTypeSpec && !derivedTypeSpec->HasDefaultInitialization())));
// Similarly, a flag to short-circuit destruction when not needed.
AddValue(dtValues, derivedTypeSchema_, "nodestructionneeded"s,
- IntExpr<1>(derivedTypeSpec && !derivedTypeSpec->HasDestruction()));
+ IntExpr<1>(isAbstractType ||
+ (derivedTypeSpec && !derivedTypeSpec->HasDestruction())));
// Similarly, a flag to short-circuit finalization when not needed.
AddValue(dtValues, derivedTypeSchema_, "nofinalizationneeded"s,
- IntExpr<1>(derivedTypeSpec && !IsFinalizable(*derivedTypeSpec)));
+ IntExpr<1>(isAbstractType ||
+ (derivedTypeSpec && !IsFinalizable(*derivedTypeSpec))));
}
dtObject.get<ObjectEntityDetails>().set_init(MaybeExpr{
StructureExpr(Structure(derivedTypeSchema_, std::move(dtValues)))});
More information about the flang-commits
mailing list