Skip to content

[flang][runtime] Fix odd "invalid descriptor" runtime crash #107785

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 10, 2024

Conversation

klausler
Copy link
Contributor

@klausler klausler commented Sep 8, 2024

A defined assignment generic interface for a given LHS/RHS type & rank combination may have a specific procedure with LHS dummy argument that is neither allocatable nor pointer, or specific procedure(s) whose LHS dummy arguments are allocatable or pointer. It is possible to have two specific procedures if one's LHS dummy argument is allocatable and the other's is pointer.

However, the runtime doesn't work with LHS dummy arguments that are allocatable, and will crash with a mysterious "invalid descriptor" error message.

Extend the list of special bindings to include ScalarAllocatableAssignment and ScalarPointerAssignment, use them when appropriate in the runtime type information tables, and handle them in Assign() in the runtime support library.

@klausler klausler requested a review from jeanPerier September 8, 2024 23:28
@llvmbot llvmbot added flang:runtime flang Flang issues not falling into any other category flang:semantics labels Sep 8, 2024
@llvmbot
Copy link
Member

llvmbot commented Sep 8, 2024

@llvm/pr-subscribers-flang-runtime

Author: Peter Klausler (klausler)

Changes

A defined assignment generic interface for a given LHS/RHS type & rank combination may have a specific procedure with LHS dummy argument that is neither allocatable nor pointer, or specific procedure(s) whose LHS dummy arguments are allocatable or pointer. It is possible to have two specific procedures if one's LHS dummy argument is allocatable and the other's is pointer.

However, the runtime doesn't work with LHS dummy arguments that are allocatable, and will crash with a mysterious "invalid descriptor" error message.

Extend the list of special bindings to include ScalarAllocatableAssignment and ScalarPointerAssignment, use them when appropriate in the runtime type information tables, and handle them in Assign() in the runtime support library.


Patch is 24.50 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/107785.diff

12 Files Affected:

  • (modified) flang/lib/Semantics/expression.cpp (+2-1)
  • (modified) flang/lib/Semantics/runtime-type-info.cpp (+17-4)
  • (modified) flang/module/__fortran_type_info.f90 (+8-5)
  • (modified) flang/runtime/assign.cpp (+13-3)
  • (modified) flang/runtime/descriptor-io.h (+1-1)
  • (modified) flang/runtime/namelist.cpp (+2-2)
  • (modified) flang/runtime/type-info.cpp (+7-2)
  • (modified) flang/runtime/type-info.h (+11-9)
  • (modified) flang/test/Semantics/typeinfo01.f90 (+9-9)
  • (modified) flang/test/Semantics/typeinfo02.f90 (+2-2)
  • (modified) flang/test/Semantics/typeinfo04.f90 (+1-1)
  • (added) flang/test/Semantics/typeinfo12.f90 (+52)
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index 3684839c187e68..50f5cd7f8b2e76 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -4605,7 +4605,8 @@ std::optional<ProcedureRef> ArgumentAnalyzer::GetDefinedAssignmentProc() {
     }
     for (std::size_t i{0}; !proc && i < actuals_.size(); ++i) {
       const Symbol *generic{nullptr};
-      if (const Symbol *binding{FindBoundOp(oprName, i, generic, true)}) {
+      if (const Symbol *
+          binding{FindBoundOp(oprName, i, generic, /*isSubroutine=*/true)}) {
         if (CheckAccessibleSymbol(scope, DEREF(generic))) {
           // ignore inaccessible type-bound ASSIGNMENT(=) generic
         } else if (const Symbol *
diff --git a/flang/lib/Semantics/runtime-type-info.cpp b/flang/lib/Semantics/runtime-type-info.cpp
index 9f3eb5fbe11a15..427a8421aeaf9d 100644
--- a/flang/lib/Semantics/runtime-type-info.cpp
+++ b/flang/lib/Semantics/runtime-type-info.cpp
@@ -149,6 +149,10 @@ class RuntimeTableBuilder {
   SomeExpr explicitEnum_; // Value::Genre::Explicit
   SomeExpr lenParameterEnum_; // Value::Genre::LenParameter
   SomeExpr scalarAssignmentEnum_; // SpecialBinding::Which::ScalarAssignment
+  SomeExpr
+      scalarAllocatableAssignmentEnum_; // SpecialBinding::Which::ScalarAllocatableAssignment
+  SomeExpr
+      scalarPointerAssignmentEnum_; // SpecialBinding::Which::ScalarPointerAssignment
   SomeExpr
       elementalAssignmentEnum_; // SpecialBinding::Which::ElementalAssignment
   SomeExpr readFormattedEnum_; // SpecialBinding::Which::ReadFormatted
@@ -174,6 +178,9 @@ RuntimeTableBuilder::RuntimeTableBuilder(
       explicitEnum_{GetEnumValue("explicit")},
       lenParameterEnum_{GetEnumValue("lenparameter")},
       scalarAssignmentEnum_{GetEnumValue("scalarassignment")},
+      scalarAllocatableAssignmentEnum_{
+          GetEnumValue("scalarallocatableassignment")},
+      scalarPointerAssignmentEnum_{GetEnumValue("scalarpointerassignment")},
       elementalAssignmentEnum_{GetEnumValue("elementalassignment")},
       readFormattedEnum_{GetEnumValue("readformatted")},
       readUnformattedEnum_{GetEnumValue("readunformatted")},
@@ -1122,10 +1129,10 @@ void RuntimeTableBuilder::DescribeSpecialProc(
       // Non-type-bound generic INTERFACEs and assignments from distinct
       // types must not be used for component intrinsic assignment.
       CHECK(proc->dummyArguments.size() == 2);
-      const auto t1{
+      const auto &ddo1{
           DEREF(std::get_if<evaluate::characteristics::DummyDataObject>(
-                    &proc->dummyArguments[0].u))
-              .type.type()};
+              &proc->dummyArguments[0].u))};
+      const auto t1{ddo1.type.type()};
       const auto t2{
           DEREF(std::get_if<evaluate::characteristics::DummyDataObject>(
                     &proc->dummyArguments[1].u))
@@ -1137,7 +1144,13 @@ void RuntimeTableBuilder::DescribeSpecialProc(
         return;
       }
       which = proc->IsElemental() ? elementalAssignmentEnum_
-                                  : scalarAssignmentEnum_;
+          : ddo1.attrs.test(
+                evaluate::characteristics::DummyDataObject::Attr::Allocatable)
+          ? scalarAllocatableAssignmentEnum_
+          : ddo1.attrs.test(
+                evaluate::characteristics::DummyDataObject::Attr::Pointer)
+          ? scalarPointerAssignmentEnum_
+          : scalarAssignmentEnum_;
       if (binding && binding->passName() &&
           *binding->passName() == proc->dummyArguments[1].name) {
         argThatMightBeDescriptor = 1;
diff --git a/flang/module/__fortran_type_info.f90 b/flang/module/__fortran_type_info.f90
index 5f2273de1e3d1e..7dfcfe71fcb321 100644
--- a/flang/module/__fortran_type_info.f90
+++ b/flang/module/__fortran_type_info.f90
@@ -106,11 +106,14 @@
   end type
 
   enum, bind(c) ! SpecialBinding::Which
-    enumerator :: ScalarAssignment = 1, ElementalAssignment = 2
-    enumerator :: ReadFormatted = 3, ReadUnformatted = 4
-    enumerator :: WriteFormatted = 5, WriteUnformatted = 6
-    enumerator :: ElementalFinal = 7, AssumedRankFinal = 8
-    enumerator :: ScalarFinal = 9 ! higher-rank final procedures follow
+    enumerator :: ScalarAssignment = 1
+    enumerator :: ScalarAllocatableAssignment = 2
+    enumerator :: ScalarPointerAssignment = 3
+    enumerator :: ElementalAssignment = 4
+    enumerator :: ReadFormatted = 5, ReadUnformatted = 6
+    enumerator :: WriteFormatted = 7, WriteUnformatted = 8
+    enumerator :: ElementalFinal = 9, AssumedRankFinal = 10
+    enumerator :: ScalarFinal = 11 ! higher-rank final procedures follow
   end enum
 
   type, bind(c) :: SpecialBinding
diff --git a/flang/runtime/assign.cpp b/flang/runtime/assign.cpp
index d558ada51cd21a..166cf547789211 100644
--- a/flang/runtime/assign.cpp
+++ b/flang/runtime/assign.cpp
@@ -352,6 +352,17 @@ RT_API_ATTRS static void Assign(
     // the Assign() is invoked recursively for component-per-component
     // assignments.
     if (to.rank() == 0) {
+      if (to.IsAllocatable()) {
+        if (const auto *special{toDerived->FindSpecialBinding(typeInfo::
+                    SpecialBinding::Which::ScalarAllocatableAssignment)}) {
+          return DoScalarDefinedAssignment(to, from, *special);
+        }
+      } else if (to.IsPointer()) {
+        if (const auto *special{toDerived->FindSpecialBinding(
+                typeInfo::SpecialBinding::Which::ScalarPointerAssignment)}) {
+          return DoScalarDefinedAssignment(to, from, *special);
+        }
+      }
       if (const auto *special{toDerived->FindSpecialBinding(
               typeInfo::SpecialBinding::Which::ScalarAssignment)}) {
         return DoScalarDefinedAssignment(to, from, *special);
@@ -417,9 +428,8 @@ RT_API_ATTRS static void Assign(
             StaticDescriptor<maxRank, true, 10 /*?*/> statDesc[2];
             Descriptor &toCompDesc{statDesc[0].descriptor()};
             Descriptor &fromCompDesc{statDesc[1].descriptor()};
-            comp.CreatePointerDescriptor(toCompDesc, to, terminator, toAt);
-            comp.CreatePointerDescriptor(
-                fromCompDesc, from, terminator, fromAt);
+            comp.CreateTargetDescriptor(toCompDesc, to, terminator, toAt);
+            comp.CreateTargetDescriptor(fromCompDesc, from, terminator, fromAt);
             Assign(toCompDesc, fromCompDesc, terminator, nestedFlags);
           } else { // Component has intrinsic type; simply copy raw bytes
             std::size_t componentByteSize{comp.SizeInBytes(to)};
diff --git a/flang/runtime/descriptor-io.h b/flang/runtime/descriptor-io.h
index ff5f683c6da52f..66158b4076164f 100644
--- a/flang/runtime/descriptor-io.h
+++ b/flang/runtime/descriptor-io.h
@@ -255,7 +255,7 @@ static RT_API_ATTRS bool DefaultComponentIO(IoStatementState &io,
     // Create a descriptor for the component
     StaticDescriptor<maxRank, true, 16 /*?*/> statDesc;
     Descriptor &desc{statDesc.descriptor()};
-    component.CreatePointerDescriptor(
+    component.CreateTargetDescriptor(
         desc, origDescriptor, terminator, origSubscripts);
     return DescriptorIO<DIR>(io, desc, table);
   } else {
diff --git a/flang/runtime/namelist.cpp b/flang/runtime/namelist.cpp
index af092de70f7819..fe26a0d3a6e895 100644
--- a/flang/runtime/namelist.cpp
+++ b/flang/runtime/namelist.cpp
@@ -362,7 +362,7 @@ static RT_API_ATTRS bool HandleComponent(IoStatementState &io, Descriptor &desc,
             io.HandleRelativePosition(byteCount); // skip over '('
             StaticDescriptor<maxRank, true, 16> staticDesc;
             Descriptor &tmpDesc{staticDesc.descriptor()};
-            comp->CreatePointerDescriptor(tmpDesc, source, handler);
+            comp->CreateTargetDescriptor(tmpDesc, source, handler);
             if (!HandleSubscripts(io, desc, tmpDesc, compName)) {
               return false;
             }
@@ -370,7 +370,7 @@ static RT_API_ATTRS bool HandleComponent(IoStatementState &io, Descriptor &desc,
           }
         }
         if (!createdDesc) {
-          comp->CreatePointerDescriptor(desc, source, handler);
+          comp->CreateTargetDescriptor(desc, source, handler);
         }
         if (source.rank() > 0) {
           if (desc.rank() > 0) {
diff --git a/flang/runtime/type-info.cpp b/flang/runtime/type-info.cpp
index cb18c5669b5ffc..531944086c7f74 100644
--- a/flang/runtime/type-info.cpp
+++ b/flang/runtime/type-info.cpp
@@ -134,7 +134,7 @@ RT_API_ATTRS void Component::EstablishDescriptor(Descriptor &descriptor,
   }
 }
 
-RT_API_ATTRS void Component::CreatePointerDescriptor(Descriptor &descriptor,
+RT_API_ATTRS void Component::CreateTargetDescriptor(Descriptor &descriptor,
     const Descriptor &container, Terminator &terminator,
     const SubscriptValue *subscripts) const {
   RUNTIME_CHECK(terminator, genre_ == Genre::Data);
@@ -144,7 +144,6 @@ RT_API_ATTRS void Component::CreatePointerDescriptor(Descriptor &descriptor,
   } else {
     descriptor.set_base_addr(container.OffsetElement<char>() + offset_);
   }
-  descriptor.raw().attribute = CFI_attribute_pointer;
 }
 
 RT_API_ATTRS const DerivedType *DerivedType::GetParentType() const {
@@ -297,6 +296,12 @@ FILE *SpecialBinding::Dump(FILE *f) const {
   case Which::ScalarAssignment:
     std::fputs("    ScalarAssignment", f);
     break;
+  case Which::ScalarAllocatableAssignment:
+    std::fputs("    ScalarAllocatableAssignment", f);
+    break;
+  case Which::ScalarPointerAssignment:
+    std::fputs("    ScalarPointerAssignment", f);
+    break;
   case Which::ElementalAssignment:
     std::fputs("    ElementalAssignment", f);
     break;
diff --git a/flang/runtime/type-info.h b/flang/runtime/type-info.h
index c3f3595e32ef28..51e360cc20b5c8 100644
--- a/flang/runtime/type-info.h
+++ b/flang/runtime/type-info.h
@@ -91,7 +91,7 @@ class Component {
 
   // Creates a pointer descriptor from this component description, possibly
   // with subscripts
-  RT_API_ATTRS void CreatePointerDescriptor(Descriptor &,
+  RT_API_ATTRS void CreateTargetDescriptor(Descriptor &,
       const Descriptor &container, Terminator &,
       const SubscriptValue * = nullptr) const;
 
@@ -126,14 +126,16 @@ class SpecialBinding {
   enum class Which : std::uint8_t {
     None = 0,
     ScalarAssignment = 1,
-    ElementalAssignment = 2,
-    ReadFormatted = 3,
-    ReadUnformatted = 4,
-    WriteFormatted = 5,
-    WriteUnformatted = 6,
-    ElementalFinal = 7,
-    AssumedRankFinal = 8,
-    ScalarFinal = 9,
+    ScalarAllocatableAssignment = 2,
+    ScalarPointerAssignment = 3,
+    ElementalAssignment = 4,
+    ReadFormatted = 5,
+    ReadUnformatted = 6,
+    WriteFormatted = 7,
+    WriteUnformatted = 8,
+    ElementalFinal = 9,
+    AssumedRankFinal = 10,
+    ScalarFinal = 11,
     // higher-ranked final procedures follow
   };
 
diff --git a/flang/test/Semantics/typeinfo01.f90 b/flang/test/Semantics/typeinfo01.f90
index 0d381f10b04831..b6f0e2e12ff6fe 100644
--- a/flang/test/Semantics/typeinfo01.f90
+++ b/flang/test/Semantics/typeinfo01.f90
@@ -102,8 +102,8 @@ impure elemental subroutine s1(x, y)
     class(t), intent(out) :: x
     class(t), intent(in) :: y
   end subroutine
-!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=4_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
-!CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=2_1,isargdescriptorset=3_1,istypebound=1_1,isargcontiguousset=0_1,proc=s1)]
+!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=16_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
+!CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=4_1,isargdescriptorset=3_1,istypebound=1_1,isargcontiguousset=0_1,proc=s1)]
 !CHECK: .v.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(binding) shape: 0_8:0_8 init:[binding::binding(proc=s1,name=.n.s1)]
 end module
 
@@ -125,8 +125,8 @@ impure elemental subroutine s3(x)
   subroutine s4(x)
     type(t), contiguous :: x(:,:,:)
   end subroutine
-!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=7296_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=0_1,nofinalizationneeded=0_1)
-!CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=7_1,isargdescriptorset=0_1,istypebound=1_1,isargcontiguousset=0_1,proc=s3),specialbinding(which=10_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=s1),specialbinding(which=11_1,isargdescriptorset=0_1,istypebound=1_1,isargcontiguousset=1_1,proc=s2),specialbinding(which=12_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=1_1,proc=s4)]
+!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=29184_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=0_1,nofinalizationneeded=0_1)
+!CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=9_1,isargdescriptorset=0_1,istypebound=1_1,isargcontiguousset=0_1,proc=s3),specialbinding(which=12_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=s1),specialbinding(which=13_1,isargdescriptorset=0_1,istypebound=1_1,isargcontiguousset=1_1,proc=s2),specialbinding(which=14_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=1_1,proc=s4)]
 end module
 
 module m09
@@ -167,8 +167,8 @@ subroutine wu(x,u,iostat,iomsg)
     integer, intent(out) :: iostat
     character(len=*), intent(inout) :: iomsg
   end subroutine
-!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=120_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
-!CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=3_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=rf),specialbinding(which=4_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=ru),specialbinding(which=5_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=wf),specialbinding(which=6_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=wu)]
+!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=480_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
+!CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=5_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=rf),specialbinding(which=6_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=ru),specialbinding(which=7_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=wf),specialbinding(which=8_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=wu)]
 !CHECK: .v.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(binding) shape: 0_8:3_8 init:[binding::binding(proc=rf,name=.n.rf),binding(proc=ru,name=.n.ru),binding(proc=wf,name=.n.wf),binding(proc=wu,name=.n.wu)]
 end module
 
@@ -216,8 +216,8 @@ subroutine wu(x,u,iostat,iomsg)
     integer, intent(out) :: iostat
     character(len=*), intent(inout) :: iomsg
   end subroutine
-!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=120_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
-!CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=3_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=rf),specialbinding(which=4_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=ru),specialbinding(which=5_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=wf),specialbinding(which=6_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=wu)]
+!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=480_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
+!CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=5_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=rf),specialbinding(which=6_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=ru),specialbinding(which=7_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=wf),specialbinding(which=8_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=wu)]
 end module
 
 module m11
@@ -260,7 +260,7 @@ module m13
    contains
     procedure :: assign1, assign2
     generic :: assignment(=) => assign1, assign2
-    ! CHECK: .s.t1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=2_1,isargdescriptorset=3_1,istypebound=1_1,isargcontiguousset=0_1,proc=assign1)]
+    ! CHECK: .s.t1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=4_1,isargdescriptorset=3_1,istypebound=1_1,isargcontiguousset=0_1,proc=assign1)]
   end type
  contains
   impure elemental subroutine assign1(to, from)
diff --git a/flang/test/Semantics/typeinfo02.f90 b/flang/test/Semantics/typeinfo02.f90
index 29d14c7a0f196b..2b911e7238f881 100644
--- a/flang/test/Semantics/typeinfo02.f90
+++ b/flang/test/Semantics/typeinfo02.f90
@@ -29,5 +29,5 @@ subroutine wf2(x,u,iot,v,iostat,iomsg)
     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,istypebound=1_1,isargcontiguousset=0_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,istypebound=1_1,isargcontiguousset=0_1,proc=wf2)]
+!CHECK: .s.base, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=7_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=wf1)]
+!CHECK: .s.extended, SAVE, TARGET (CompilerCreated, ReadOnly...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Sep 8, 2024

@llvm/pr-subscribers-flang-semantics

Author: Peter Klausler (klausler)

Changes

A defined assignment generic interface for a given LHS/RHS type & rank combination may have a specific procedure with LHS dummy argument that is neither allocatable nor pointer, or specific procedure(s) whose LHS dummy arguments are allocatable or pointer. It is possible to have two specific procedures if one's LHS dummy argument is allocatable and the other's is pointer.

However, the runtime doesn't work with LHS dummy arguments that are allocatable, and will crash with a mysterious "invalid descriptor" error message.

Extend the list of special bindings to include ScalarAllocatableAssignment and ScalarPointerAssignment, use them when appropriate in the runtime type information tables, and handle them in Assign() in the runtime support library.


Patch is 24.50 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/107785.diff

12 Files Affected:

  • (modified) flang/lib/Semantics/expression.cpp (+2-1)
  • (modified) flang/lib/Semantics/runtime-type-info.cpp (+17-4)
  • (modified) flang/module/__fortran_type_info.f90 (+8-5)
  • (modified) flang/runtime/assign.cpp (+13-3)
  • (modified) flang/runtime/descriptor-io.h (+1-1)
  • (modified) flang/runtime/namelist.cpp (+2-2)
  • (modified) flang/runtime/type-info.cpp (+7-2)
  • (modified) flang/runtime/type-info.h (+11-9)
  • (modified) flang/test/Semantics/typeinfo01.f90 (+9-9)
  • (modified) flang/test/Semantics/typeinfo02.f90 (+2-2)
  • (modified) flang/test/Semantics/typeinfo04.f90 (+1-1)
  • (added) flang/test/Semantics/typeinfo12.f90 (+52)
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index 3684839c187e68..50f5cd7f8b2e76 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -4605,7 +4605,8 @@ std::optional<ProcedureRef> ArgumentAnalyzer::GetDefinedAssignmentProc() {
     }
     for (std::size_t i{0}; !proc && i < actuals_.size(); ++i) {
       const Symbol *generic{nullptr};
-      if (const Symbol *binding{FindBoundOp(oprName, i, generic, true)}) {
+      if (const Symbol *
+          binding{FindBoundOp(oprName, i, generic, /*isSubroutine=*/true)}) {
         if (CheckAccessibleSymbol(scope, DEREF(generic))) {
           // ignore inaccessible type-bound ASSIGNMENT(=) generic
         } else if (const Symbol *
diff --git a/flang/lib/Semantics/runtime-type-info.cpp b/flang/lib/Semantics/runtime-type-info.cpp
index 9f3eb5fbe11a15..427a8421aeaf9d 100644
--- a/flang/lib/Semantics/runtime-type-info.cpp
+++ b/flang/lib/Semantics/runtime-type-info.cpp
@@ -149,6 +149,10 @@ class RuntimeTableBuilder {
   SomeExpr explicitEnum_; // Value::Genre::Explicit
   SomeExpr lenParameterEnum_; // Value::Genre::LenParameter
   SomeExpr scalarAssignmentEnum_; // SpecialBinding::Which::ScalarAssignment
+  SomeExpr
+      scalarAllocatableAssignmentEnum_; // SpecialBinding::Which::ScalarAllocatableAssignment
+  SomeExpr
+      scalarPointerAssignmentEnum_; // SpecialBinding::Which::ScalarPointerAssignment
   SomeExpr
       elementalAssignmentEnum_; // SpecialBinding::Which::ElementalAssignment
   SomeExpr readFormattedEnum_; // SpecialBinding::Which::ReadFormatted
@@ -174,6 +178,9 @@ RuntimeTableBuilder::RuntimeTableBuilder(
       explicitEnum_{GetEnumValue("explicit")},
       lenParameterEnum_{GetEnumValue("lenparameter")},
       scalarAssignmentEnum_{GetEnumValue("scalarassignment")},
+      scalarAllocatableAssignmentEnum_{
+          GetEnumValue("scalarallocatableassignment")},
+      scalarPointerAssignmentEnum_{GetEnumValue("scalarpointerassignment")},
       elementalAssignmentEnum_{GetEnumValue("elementalassignment")},
       readFormattedEnum_{GetEnumValue("readformatted")},
       readUnformattedEnum_{GetEnumValue("readunformatted")},
@@ -1122,10 +1129,10 @@ void RuntimeTableBuilder::DescribeSpecialProc(
       // Non-type-bound generic INTERFACEs and assignments from distinct
       // types must not be used for component intrinsic assignment.
       CHECK(proc->dummyArguments.size() == 2);
-      const auto t1{
+      const auto &ddo1{
           DEREF(std::get_if<evaluate::characteristics::DummyDataObject>(
-                    &proc->dummyArguments[0].u))
-              .type.type()};
+              &proc->dummyArguments[0].u))};
+      const auto t1{ddo1.type.type()};
       const auto t2{
           DEREF(std::get_if<evaluate::characteristics::DummyDataObject>(
                     &proc->dummyArguments[1].u))
@@ -1137,7 +1144,13 @@ void RuntimeTableBuilder::DescribeSpecialProc(
         return;
       }
       which = proc->IsElemental() ? elementalAssignmentEnum_
-                                  : scalarAssignmentEnum_;
+          : ddo1.attrs.test(
+                evaluate::characteristics::DummyDataObject::Attr::Allocatable)
+          ? scalarAllocatableAssignmentEnum_
+          : ddo1.attrs.test(
+                evaluate::characteristics::DummyDataObject::Attr::Pointer)
+          ? scalarPointerAssignmentEnum_
+          : scalarAssignmentEnum_;
       if (binding && binding->passName() &&
           *binding->passName() == proc->dummyArguments[1].name) {
         argThatMightBeDescriptor = 1;
diff --git a/flang/module/__fortran_type_info.f90 b/flang/module/__fortran_type_info.f90
index 5f2273de1e3d1e..7dfcfe71fcb321 100644
--- a/flang/module/__fortran_type_info.f90
+++ b/flang/module/__fortran_type_info.f90
@@ -106,11 +106,14 @@
   end type
 
   enum, bind(c) ! SpecialBinding::Which
-    enumerator :: ScalarAssignment = 1, ElementalAssignment = 2
-    enumerator :: ReadFormatted = 3, ReadUnformatted = 4
-    enumerator :: WriteFormatted = 5, WriteUnformatted = 6
-    enumerator :: ElementalFinal = 7, AssumedRankFinal = 8
-    enumerator :: ScalarFinal = 9 ! higher-rank final procedures follow
+    enumerator :: ScalarAssignment = 1
+    enumerator :: ScalarAllocatableAssignment = 2
+    enumerator :: ScalarPointerAssignment = 3
+    enumerator :: ElementalAssignment = 4
+    enumerator :: ReadFormatted = 5, ReadUnformatted = 6
+    enumerator :: WriteFormatted = 7, WriteUnformatted = 8
+    enumerator :: ElementalFinal = 9, AssumedRankFinal = 10
+    enumerator :: ScalarFinal = 11 ! higher-rank final procedures follow
   end enum
 
   type, bind(c) :: SpecialBinding
diff --git a/flang/runtime/assign.cpp b/flang/runtime/assign.cpp
index d558ada51cd21a..166cf547789211 100644
--- a/flang/runtime/assign.cpp
+++ b/flang/runtime/assign.cpp
@@ -352,6 +352,17 @@ RT_API_ATTRS static void Assign(
     // the Assign() is invoked recursively for component-per-component
     // assignments.
     if (to.rank() == 0) {
+      if (to.IsAllocatable()) {
+        if (const auto *special{toDerived->FindSpecialBinding(typeInfo::
+                    SpecialBinding::Which::ScalarAllocatableAssignment)}) {
+          return DoScalarDefinedAssignment(to, from, *special);
+        }
+      } else if (to.IsPointer()) {
+        if (const auto *special{toDerived->FindSpecialBinding(
+                typeInfo::SpecialBinding::Which::ScalarPointerAssignment)}) {
+          return DoScalarDefinedAssignment(to, from, *special);
+        }
+      }
       if (const auto *special{toDerived->FindSpecialBinding(
               typeInfo::SpecialBinding::Which::ScalarAssignment)}) {
         return DoScalarDefinedAssignment(to, from, *special);
@@ -417,9 +428,8 @@ RT_API_ATTRS static void Assign(
             StaticDescriptor<maxRank, true, 10 /*?*/> statDesc[2];
             Descriptor &toCompDesc{statDesc[0].descriptor()};
             Descriptor &fromCompDesc{statDesc[1].descriptor()};
-            comp.CreatePointerDescriptor(toCompDesc, to, terminator, toAt);
-            comp.CreatePointerDescriptor(
-                fromCompDesc, from, terminator, fromAt);
+            comp.CreateTargetDescriptor(toCompDesc, to, terminator, toAt);
+            comp.CreateTargetDescriptor(fromCompDesc, from, terminator, fromAt);
             Assign(toCompDesc, fromCompDesc, terminator, nestedFlags);
           } else { // Component has intrinsic type; simply copy raw bytes
             std::size_t componentByteSize{comp.SizeInBytes(to)};
diff --git a/flang/runtime/descriptor-io.h b/flang/runtime/descriptor-io.h
index ff5f683c6da52f..66158b4076164f 100644
--- a/flang/runtime/descriptor-io.h
+++ b/flang/runtime/descriptor-io.h
@@ -255,7 +255,7 @@ static RT_API_ATTRS bool DefaultComponentIO(IoStatementState &io,
     // Create a descriptor for the component
     StaticDescriptor<maxRank, true, 16 /*?*/> statDesc;
     Descriptor &desc{statDesc.descriptor()};
-    component.CreatePointerDescriptor(
+    component.CreateTargetDescriptor(
         desc, origDescriptor, terminator, origSubscripts);
     return DescriptorIO<DIR>(io, desc, table);
   } else {
diff --git a/flang/runtime/namelist.cpp b/flang/runtime/namelist.cpp
index af092de70f7819..fe26a0d3a6e895 100644
--- a/flang/runtime/namelist.cpp
+++ b/flang/runtime/namelist.cpp
@@ -362,7 +362,7 @@ static RT_API_ATTRS bool HandleComponent(IoStatementState &io, Descriptor &desc,
             io.HandleRelativePosition(byteCount); // skip over '('
             StaticDescriptor<maxRank, true, 16> staticDesc;
             Descriptor &tmpDesc{staticDesc.descriptor()};
-            comp->CreatePointerDescriptor(tmpDesc, source, handler);
+            comp->CreateTargetDescriptor(tmpDesc, source, handler);
             if (!HandleSubscripts(io, desc, tmpDesc, compName)) {
               return false;
             }
@@ -370,7 +370,7 @@ static RT_API_ATTRS bool HandleComponent(IoStatementState &io, Descriptor &desc,
           }
         }
         if (!createdDesc) {
-          comp->CreatePointerDescriptor(desc, source, handler);
+          comp->CreateTargetDescriptor(desc, source, handler);
         }
         if (source.rank() > 0) {
           if (desc.rank() > 0) {
diff --git a/flang/runtime/type-info.cpp b/flang/runtime/type-info.cpp
index cb18c5669b5ffc..531944086c7f74 100644
--- a/flang/runtime/type-info.cpp
+++ b/flang/runtime/type-info.cpp
@@ -134,7 +134,7 @@ RT_API_ATTRS void Component::EstablishDescriptor(Descriptor &descriptor,
   }
 }
 
-RT_API_ATTRS void Component::CreatePointerDescriptor(Descriptor &descriptor,
+RT_API_ATTRS void Component::CreateTargetDescriptor(Descriptor &descriptor,
     const Descriptor &container, Terminator &terminator,
     const SubscriptValue *subscripts) const {
   RUNTIME_CHECK(terminator, genre_ == Genre::Data);
@@ -144,7 +144,6 @@ RT_API_ATTRS void Component::CreatePointerDescriptor(Descriptor &descriptor,
   } else {
     descriptor.set_base_addr(container.OffsetElement<char>() + offset_);
   }
-  descriptor.raw().attribute = CFI_attribute_pointer;
 }
 
 RT_API_ATTRS const DerivedType *DerivedType::GetParentType() const {
@@ -297,6 +296,12 @@ FILE *SpecialBinding::Dump(FILE *f) const {
   case Which::ScalarAssignment:
     std::fputs("    ScalarAssignment", f);
     break;
+  case Which::ScalarAllocatableAssignment:
+    std::fputs("    ScalarAllocatableAssignment", f);
+    break;
+  case Which::ScalarPointerAssignment:
+    std::fputs("    ScalarPointerAssignment", f);
+    break;
   case Which::ElementalAssignment:
     std::fputs("    ElementalAssignment", f);
     break;
diff --git a/flang/runtime/type-info.h b/flang/runtime/type-info.h
index c3f3595e32ef28..51e360cc20b5c8 100644
--- a/flang/runtime/type-info.h
+++ b/flang/runtime/type-info.h
@@ -91,7 +91,7 @@ class Component {
 
   // Creates a pointer descriptor from this component description, possibly
   // with subscripts
-  RT_API_ATTRS void CreatePointerDescriptor(Descriptor &,
+  RT_API_ATTRS void CreateTargetDescriptor(Descriptor &,
       const Descriptor &container, Terminator &,
       const SubscriptValue * = nullptr) const;
 
@@ -126,14 +126,16 @@ class SpecialBinding {
   enum class Which : std::uint8_t {
     None = 0,
     ScalarAssignment = 1,
-    ElementalAssignment = 2,
-    ReadFormatted = 3,
-    ReadUnformatted = 4,
-    WriteFormatted = 5,
-    WriteUnformatted = 6,
-    ElementalFinal = 7,
-    AssumedRankFinal = 8,
-    ScalarFinal = 9,
+    ScalarAllocatableAssignment = 2,
+    ScalarPointerAssignment = 3,
+    ElementalAssignment = 4,
+    ReadFormatted = 5,
+    ReadUnformatted = 6,
+    WriteFormatted = 7,
+    WriteUnformatted = 8,
+    ElementalFinal = 9,
+    AssumedRankFinal = 10,
+    ScalarFinal = 11,
     // higher-ranked final procedures follow
   };
 
diff --git a/flang/test/Semantics/typeinfo01.f90 b/flang/test/Semantics/typeinfo01.f90
index 0d381f10b04831..b6f0e2e12ff6fe 100644
--- a/flang/test/Semantics/typeinfo01.f90
+++ b/flang/test/Semantics/typeinfo01.f90
@@ -102,8 +102,8 @@ impure elemental subroutine s1(x, y)
     class(t), intent(out) :: x
     class(t), intent(in) :: y
   end subroutine
-!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=4_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
-!CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=2_1,isargdescriptorset=3_1,istypebound=1_1,isargcontiguousset=0_1,proc=s1)]
+!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=16_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
+!CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=4_1,isargdescriptorset=3_1,istypebound=1_1,isargcontiguousset=0_1,proc=s1)]
 !CHECK: .v.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(binding) shape: 0_8:0_8 init:[binding::binding(proc=s1,name=.n.s1)]
 end module
 
@@ -125,8 +125,8 @@ impure elemental subroutine s3(x)
   subroutine s4(x)
     type(t), contiguous :: x(:,:,:)
   end subroutine
-!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=7296_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=0_1,nofinalizationneeded=0_1)
-!CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=7_1,isargdescriptorset=0_1,istypebound=1_1,isargcontiguousset=0_1,proc=s3),specialbinding(which=10_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=s1),specialbinding(which=11_1,isargdescriptorset=0_1,istypebound=1_1,isargcontiguousset=1_1,proc=s2),specialbinding(which=12_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=1_1,proc=s4)]
+!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=29184_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=0_1,nofinalizationneeded=0_1)
+!CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=9_1,isargdescriptorset=0_1,istypebound=1_1,isargcontiguousset=0_1,proc=s3),specialbinding(which=12_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=s1),specialbinding(which=13_1,isargdescriptorset=0_1,istypebound=1_1,isargcontiguousset=1_1,proc=s2),specialbinding(which=14_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=1_1,proc=s4)]
 end module
 
 module m09
@@ -167,8 +167,8 @@ subroutine wu(x,u,iostat,iomsg)
     integer, intent(out) :: iostat
     character(len=*), intent(inout) :: iomsg
   end subroutine
-!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=120_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
-!CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=3_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=rf),specialbinding(which=4_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=ru),specialbinding(which=5_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=wf),specialbinding(which=6_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=wu)]
+!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=.v.t,name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=480_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
+!CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=5_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=rf),specialbinding(which=6_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=ru),specialbinding(which=7_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=wf),specialbinding(which=8_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=wu)]
 !CHECK: .v.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(binding) shape: 0_8:3_8 init:[binding::binding(proc=rf,name=.n.rf),binding(proc=ru,name=.n.ru),binding(proc=wf,name=.n.wf),binding(proc=wu,name=.n.wu)]
 end module
 
@@ -216,8 +216,8 @@ subroutine wu(x,u,iostat,iomsg)
     integer, intent(out) :: iostat
     character(len=*), intent(inout) :: iomsg
   end subroutine
-!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=120_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
-!CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=3_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=rf),specialbinding(which=4_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=ru),specialbinding(which=5_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=wf),specialbinding(which=6_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=wu)]
+!CHECK: .dt.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(derivedtype) init:derivedtype(binding=NULL(),name=.n.t,sizeinbytes=0_8,uninstantiated=NULL(),kindparameter=NULL(),lenparameterkind=NULL(),component=NULL(),procptr=NULL(),special=.s.t,specialbitset=480_4,hasparent=0_1,noinitializationneeded=1_1,nodestructionneeded=1_1,nofinalizationneeded=1_1)
+!CHECK: .s.t, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:3_8 init:[specialbinding::specialbinding(which=5_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=rf),specialbinding(which=6_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=ru),specialbinding(which=7_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=wf),specialbinding(which=8_1,isargdescriptorset=0_1,istypebound=0_1,isargcontiguousset=0_1,proc=wu)]
 end module
 
 module m11
@@ -260,7 +260,7 @@ module m13
    contains
     procedure :: assign1, assign2
     generic :: assignment(=) => assign1, assign2
-    ! CHECK: .s.t1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=2_1,isargdescriptorset=3_1,istypebound=1_1,isargcontiguousset=0_1,proc=assign1)]
+    ! CHECK: .s.t1, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=4_1,isargdescriptorset=3_1,istypebound=1_1,isargcontiguousset=0_1,proc=assign1)]
   end type
  contains
   impure elemental subroutine assign1(to, from)
diff --git a/flang/test/Semantics/typeinfo02.f90 b/flang/test/Semantics/typeinfo02.f90
index 29d14c7a0f196b..2b911e7238f881 100644
--- a/flang/test/Semantics/typeinfo02.f90
+++ b/flang/test/Semantics/typeinfo02.f90
@@ -29,5 +29,5 @@ subroutine wf2(x,u,iot,v,iostat,iomsg)
     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,istypebound=1_1,isargcontiguousset=0_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,istypebound=1_1,isargcontiguousset=0_1,proc=wf2)]
+!CHECK: .s.base, SAVE, TARGET (CompilerCreated, ReadOnly): ObjectEntity type: TYPE(specialbinding) shape: 0_8:0_8 init:[specialbinding::specialbinding(which=7_1,isargdescriptorset=1_1,istypebound=1_1,isargcontiguousset=0_1,proc=wf1)]
+!CHECK: .s.extended, SAVE, TARGET (CompilerCreated, ReadOnly...
[truncated]

Copy link
Contributor

@vzakhari vzakhari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

!RUN: %flang_fc1 -fdebug-dump-symbols %s | FileCheck %s

! Test defined assignment with allocatable / pointer LHS arguments.
! The special bindings for the defined assignmnts must reflect that
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: assignmnts

@@ -91,7 +91,7 @@ class Component {

// Creates a pointer descriptor from this component description, possibly
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: maybe remove pointer word here.

A defined assignment generic interface for a given LHS/RHS type & rank
combination may have a specific procedure with LHS dummy argument
that is neither allocatable nor pointer, or specific procedure(s)
whose LHS dummy arguments are allocatable or pointer.  It is possible
to have two specific procedures if one's LHS dummy argument is allocatable
and the other's is pointer.

However, the runtime doesn't work with LHS dummy arguments that
are allocatable, and will crash with a mysterious "invalid descriptor"
error message.

Extend the list of special bindings to include ScalarAllocatableAssignment
and ScalarPointerAssignment, use them when appropriate in the runtime
type information tables, and handle them in Assign() in the runtime
support library.
Copy link
Contributor

@clementval clementval left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@klausler klausler merged commit 15106c2 into llvm:main Sep 10, 2024
8 checks passed
@klausler klausler deleted the fs19118 branch September 10, 2024 21:14
@llvm-ci
Copy link
Collaborator

llvm-ci commented Sep 11, 2024

LLVM Buildbot has detected a new failure on builder premerge-monolithic-linux running on premerge-linux-1 while building flang at step 6 "build-unified-tree".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/153/builds/8451

Here is the relevant piece of the build log for the reference
Step 6 (build-unified-tree) failure: build (failure)
...
129.322 [25/6/3099] Generating ../../../../include/flang/ieee_features.mod
129.324 [25/5/3100] Generating ../../../../include/flang/__cuda_builtins.mod
129.325 [24/5/3101] Generating ../../../../include/flang/iso_c_binding.mod
129.326 [24/4/3102] Generating ../../../../include/flang/__fortran_ieee_exceptions.mod
129.356 [22/5/3103] Generating ../../../../include/flang/cudadevice.mod
129.363 [22/4/3104] Generating ../../../../include/flang/iso_fortran_env_impl.mod, iso_fortran_env_impl.o
129.376 [21/4/3105] Generating ../../../../include/flang/ieee_exceptions.mod
129.396 [21/3/3106] Generating ../../../../include/flang/ieee_arithmetic.mod
129.412 [21/2/3107] Generating ../../../../include/flang/iso_fortran_env.mod
129.689 [21/1/3108] Generating ../../../../include/flang/__ppc_types.mod
FAILED: include/flang/__ppc_types.mod /build/buildbot/premerge-monolithic-linux/build/include/flang/__ppc_types.mod 
cd /build/buildbot/premerge-monolithic-linux/build/tools/flang/tools/f18 && /etc/cmake/bin/cmake -E make_directory /build/buildbot/premerge-monolithic-linux/build/include/flang && /build/buildbot/premerge-monolithic-linux/build/bin/flang-new -cpp -fsyntax-only -module-dir /build/buildbot/premerge-monolithic-linux/build/include/flang /build/buildbot/premerge-monolithic-linux/llvm-project/flang/module/__ppc_types.f90

fatal internal error: CHECK(iter != schemata.end()) failed at /build/buildbot/premerge-monolithic-linux/llvm-project/flang/lib/Semantics/runtime-type-info.cpp(676)
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: /build/buildbot/premerge-monolithic-linux/build/bin/flang-new -fc1 -triple x86_64-unknown-linux-gnu -fsyntax-only -cpp -mrelocation-model pic -pic-level 2 -pic-is-pie -target-cpu x86-64 -module-dir /build/buildbot/premerge-monolithic-linux/build/include/flang -resource-dir /build/buildbot/premerge-monolithic-linux/build/lib/clang/20 -mframe-pointer=all -x f95-cpp-input /build/buildbot/premerge-monolithic-linux/llvm-project/flang/module/__ppc_types.f90
 #0 0x0000583b49c21b18 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) /build/buildbot/premerge-monolithic-linux/llvm-project/llvm/lib/Support/Unix/Signals.inc:723:13
 #1 0x0000583b49c1f64e llvm::sys::RunSignalHandlers() /build/buildbot/premerge-monolithic-linux/llvm-project/llvm/lib/Support/Signals.cpp:106:18
 #2 0x0000583b49c222f8 SignalHandler(int) /build/buildbot/premerge-monolithic-linux/llvm-project/llvm/lib/Support/Unix/Signals.inc:413:1
 #3 0x00007d27b6e7c520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
 #4 0x00007d27b6ed09fc pthread_kill (/lib/x86_64-linux-gnu/libc.so.6+0x969fc)
 #5 0x00007d27b6e7c476 gsignal (/lib/x86_64-linux-gnu/libc.so.6+0x42476)
 #6 0x00007d27b6e627f3 abort (/lib/x86_64-linux-gnu/libc.so.6+0x287f3)
 #7 0x0000583b4b2c61d6 (/build/buildbot/premerge-monolithic-linux/build/bin/flang-new+0x7c731d6)
 #8 0x0000583b4a61ac77 get<Fortran::semantics::ObjectEntityDetails> /build/buildbot/premerge-monolithic-linux/llvm-project/flang/include/flang/Semantics/symbol.h:800:5
 #9 0x0000583b4a61ac77 Fortran::semantics::RuntimeTableBuilder::GetEnumValue(char const*) const /build/buildbot/premerge-monolithic-linux/llvm-project/flang/lib/Semantics/runtime-type-info.cpp:715:39
#10 0x0000583b4a61a6bc Fortran::semantics::RuntimeTableBuilder::RuntimeTableBuilder(Fortran::semantics::SemanticsContext&, Fortran::semantics::RuntimeDerivedTypeTables&) /build/buildbot/premerge-monolithic-linux/llvm-project/flang/lib/Semantics/runtime-type-info.cpp:183:7
#11 0x0000583b4a626613 globalScope /build/buildbot/premerge-monolithic-linux/llvm-project/flang/include/flang/Semantics/semantics.h:107:33
#12 0x0000583b4a626613 Fortran::semantics::BuildRuntimeDerivedTypeTables(Fortran::semantics::SemanticsContext&) /build/buildbot/premerge-monolithic-linux/llvm-project/flang/lib/Semantics/runtime-type-info.cpp:1287:35
#13 0x0000583b49c6c170 make_unique<Fortran::semantics::RuntimeDerivedTypeTables, Fortran::semantics::RuntimeDerivedTypeTables> /usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/unique_ptr.h:962:30
#14 0x0000583b49c6c170 Fortran::frontend::FrontendAction::generateRtTypeTables() /build/buildbot/premerge-monolithic-linux/llvm-project/flang/lib/Frontend/FrontendAction.cpp:207:7
#15 0x0000583b49c6b16c Fortran::frontend::FrontendAction::beginSourceFile(Fortran::frontend::CompilerInstance&, Fortran::frontend::FrontendInputFile const&) /build/buildbot/premerge-monolithic-linux/llvm-project/flang/lib/Frontend/FrontendAction.cpp:0:8
#16 0x0000583b49c53ee3 Fortran::frontend::CompilerInstance::executeAction(Fortran::frontend::FrontendAction&) /build/buildbot/premerge-monolithic-linux/llvm-project/flang/lib/Frontend/CompilerInstance.cpp:172:9
#17 0x0000583b49c6f7f8 Fortran::frontend::executeCompilerInvocation(Fortran::frontend::CompilerInstance*) /build/buildbot/premerge-monolithic-linux/llvm-project/flang/lib/FrontendTool/ExecuteCompilerInvocation.cpp:223:25
#18 0x0000583b48512cc1 fc1_main(llvm::ArrayRef<char const*>, char const*) /build/buildbot/premerge-monolithic-linux/llvm-project/flang/tools/flang-driver/fc1_main.cpp:67:13
#19 0x0000583b4851134b executeFC1Tool /build/buildbot/premerge-monolithic-linux/llvm-project/flang/tools/flang-driver/driver.cpp:66:12
#20 0x0000583b4851134b main /build/buildbot/premerge-monolithic-linux/llvm-project/flang/tools/flang-driver/driver.cpp:109:14
#21 0x00007d27b6e63d90 (/lib/x86_64-linux-gnu/libc.so.6+0x29d90)
#22 0x00007d27b6e63e40 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x29e40)
#23 0x0000583b48510d65 _start (/build/buildbot/premerge-monolithic-linux/build/bin/flang-new+0x4ebdd65)
flang-new: error: unable to execute command: Aborted
flang-new: error: flang frontend command failed due to signal (use -v to see invocation)
flang-new version 20.0.0git (https://github.com/llvm/llvm-project.git 15106c26662a573df31e8dfdd9350c313b8bfd84)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /build/buildbot/premerge-monolithic-linux/build/bin
Build config: +assertions
flang-new: note: diagnostic msg: 

preames added a commit that referenced this pull request Sep 11, 2024
…107785)"

This reverts commit 15106c2.  Commit does
not pass check-flang on x86 host.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:runtime flang:semantics flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants