[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