Skip to content

[flang] Derived type structural equivalence #69376

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
Oct 30, 2023
Merged

Conversation

klausler
Copy link
Contributor

F'202X 7.5.2.4 describes conditions under which two derived type definitions are to be considered equivalent. These rules are already implemented in Evaluate/type.cpp but not exposed for general use; rearrange the code a little so that the compatibility checking of separate module procedure interfaces and explicit definitions can use it to avoid emitting a bogus error message.

Fixes #67946.

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

@llvmbot
Copy link
Member

llvmbot commented Oct 17, 2023

@llvm/pr-subscribers-flang-semantics

Author: Peter Klausler (klausler)

Changes

F'202X 7.5.2.4 describes conditions under which two derived type definitions are to be considered equivalent. These rules are already implemented in Evaluate/type.cpp but not exposed for general use; rearrange the code a little so that the compatibility checking of separate module procedure interfaces and explicit definitions can use it to avoid emitting a bogus error message.

Fixes #67946.


Full diff: https://github.com/llvm/llvm-project/pull/69376.diff

6 Files Affected:

  • (modified) flang/include/flang/Evaluate/type.h (+4)
  • (modified) flang/lib/Evaluate/type.cpp (+14-1)
  • (modified) flang/lib/Semantics/check-declarations.cpp (+2-3)
  • (modified) flang/test/Semantics/separate-mp02.f90 (+5-5)
  • (modified) flang/test/Semantics/separate-mp03.f90 (+1-1)
  • (added) flang/test/Semantics/separate-mp06.f90 (+98)
diff --git a/flang/include/flang/Evaluate/type.h b/flang/include/flang/Evaluate/type.h
index 13060e42e47adbf..33b94ed31843cf6 100644
--- a/flang/include/flang/Evaluate/type.h
+++ b/flang/include/flang/Evaluate/type.h
@@ -207,6 +207,10 @@ class DynamicType {
   // SAME_TYPE_AS (16.9.165); ignores type parameter values
   std::optional<bool> SameTypeAs(const DynamicType &) const;
 
+  // 7.5.2.4 type equivalence; like operator==(), but SEQUENCE/BIND(C)
+  // derived types can be structurally equivalent.
+  bool IsEquivalentTo(const DynamicType &) const;
+
   // Result will be missing when a symbol is absent or
   // has an erroneous type, e.g., REAL(KIND=666).
   static std::optional<DynamicType> From(const semantics::DeclTypeSpec &);
diff --git a/flang/lib/Evaluate/type.cpp b/flang/lib/Evaluate/type.cpp
index e5d9851e2496aeb..967a933375940e0 100644
--- a/flang/lib/Evaluate/type.cpp
+++ b/flang/lib/Evaluate/type.cpp
@@ -288,7 +288,7 @@ const semantics::DerivedTypeSpec *GetParentTypeSpec(
 }
 
 // Compares two derived type representations to see whether they both
-// represent the "same type" in the sense of section 7.5.2.4.
+// represent the "same type" in the sense of section F'2023 7.5.2.4.
 using SetOfDerivedTypePairs =
     std::set<std::pair<const semantics::DerivedTypeSpec *,
         const semantics::DerivedTypeSpec *>>;
@@ -508,6 +508,19 @@ bool AreSameDerivedType(
   return AreSameDerivedType(x, y, false, false, inProgress);
 }
 
+bool AreSameDerivedType(
+    const semantics::DerivedTypeSpec *x, const semantics::DerivedTypeSpec *y) {
+  return x == y || (x && y && AreSameDerivedType(*x, *y));
+}
+
+bool DynamicType::IsEquivalentTo(const DynamicType &that) const {
+  return category_ == that.category_ && kind_ == that.kind_ &&
+      PointeeComparison(charLengthParamValue_, that.charLengthParamValue_) &&
+      knownLength().has_value() == that.knownLength().has_value() &&
+      (!knownLength() || *knownLength() == *that.knownLength()) &&
+      AreSameDerivedType(derived_, that.derived_);
+}
+
 static bool AreCompatibleDerivedTypes(const semantics::DerivedTypeSpec *x,
     const semantics::DerivedTypeSpec *y, bool isPolymorphic,
     bool ignoreTypeParameterValues, bool ignoreLenTypeParameters) {
diff --git a/flang/lib/Semantics/check-declarations.cpp b/flang/lib/Semantics/check-declarations.cpp
index 2c2866d590ae5a4..ce16b2df54b050f 100644
--- a/flang/lib/Semantics/check-declarations.cpp
+++ b/flang/lib/Semantics/check-declarations.cpp
@@ -3354,10 +3354,9 @@ void SubprogramMatchHelper::CheckDummyDataObject(const Symbol &symbol1,
     const DummyDataObject &obj2) {
   if (!CheckSameIntent(symbol1, symbol2, obj1.intent, obj2.intent)) {
   } else if (!CheckSameAttrs(symbol1, symbol2, obj1.attrs, obj2.attrs)) {
-  } else if (obj1.type.type() != obj2.type.type()) {
+  } else if (!obj1.type.type().IsEquivalentTo(obj2.type.type())) {
     Say(symbol1, symbol2,
-        "Dummy argument '%s' has type %s; the corresponding argument in the"
-        " interface body has type %s"_err_en_US,
+        "Dummy argument '%s' has type %s; the corresponding argument in the interface body has distinct type %s"_err_en_US,
         obj1.type.type().AsFortran(), obj2.type.type().AsFortran());
   } else if (!ShapesAreCompatible(obj1, obj2)) {
     Say(symbol1, symbol2,
diff --git a/flang/test/Semantics/separate-mp02.f90 b/flang/test/Semantics/separate-mp02.f90
index fd9c4c3cc18f98b..39a469b6ccc09e8 100644
--- a/flang/test/Semantics/separate-mp02.f90
+++ b/flang/test/Semantics/separate-mp02.f90
@@ -51,9 +51,9 @@ module subroutine s5(x, y)
     real :: y
   end
   module subroutine s6(x, y)
-    !ERROR: Dummy argument 'x' has type INTEGER(4); the corresponding argument in the interface body has type REAL(4)
+    !ERROR: Dummy argument 'x' has type INTEGER(4); the corresponding argument in the interface body has distinct type REAL(4)
     integer :: x
-    !ERROR: Dummy argument 'y' has type REAL(8); the corresponding argument in the interface body has type REAL(4)
+    !ERROR: Dummy argument 'y' has type REAL(8); the corresponding argument in the interface body has distinct type REAL(4)
     real(8) :: y
   end
   module subroutine s7(x, y, z)
@@ -72,10 +72,10 @@ module subroutine s8(x, y, z)
   end
   module subroutine s9(x, y, z, w)
     character(len=4) :: x
-    !ERROR: Dummy argument 'y' has type CHARACTER(KIND=1,LEN=5_8); the corresponding argument in the interface body has type CHARACTER(KIND=1,LEN=4_8)
+    !ERROR: Dummy argument 'y' has type CHARACTER(KIND=1,LEN=5_8); the corresponding argument in the interface body has distinct type CHARACTER(KIND=1,LEN=4_8)
     character(len=5) :: y
     character(len=*) :: z
-    !ERROR: Dummy argument 'w' has type CHARACTER(KIND=1,LEN=4_8); the corresponding argument in the interface body has type CHARACTER(KIND=1,LEN=*)
+    !ERROR: Dummy argument 'w' has type CHARACTER(KIND=1,LEN=4_8); the corresponding argument in the interface body has distinct type CHARACTER(KIND=1,LEN=*)
     character(len=4) :: w
   end
 end
@@ -330,7 +330,7 @@ module subroutine sub1(s)
     character(len=-1) s ! ok
   end subroutine
   module subroutine sub2(s)
-    !ERROR: Dummy argument 's' has type CHARACTER(KIND=1,LEN=1_8); the corresponding argument in the interface body has type CHARACTER(KIND=1,LEN=0_8)
+    !ERROR: Dummy argument 's' has type CHARACTER(KIND=1,LEN=1_8); the corresponding argument in the interface body has distinct type CHARACTER(KIND=1,LEN=0_8)
     character(len=1) s
   end subroutine
 end submodule
diff --git a/flang/test/Semantics/separate-mp03.f90 b/flang/test/Semantics/separate-mp03.f90
index 33bf1cf8e414fd5..1bbeced44a4f7a2 100644
--- a/flang/test/Semantics/separate-mp03.f90
+++ b/flang/test/Semantics/separate-mp03.f90
@@ -74,7 +74,7 @@ pure module subroutine s2
   end interface
  contains
   integer module function f1(x)
-    !ERROR: Dummy argument 'x' has type INTEGER(4); the corresponding argument in the interface body has type REAL(4)
+    !ERROR: Dummy argument 'x' has type INTEGER(4); the corresponding argument in the interface body has distinct type REAL(4)
     integer, intent(in) :: x
     f1 = x
   end function
diff --git a/flang/test/Semantics/separate-mp06.f90 b/flang/test/Semantics/separate-mp06.f90
new file mode 100644
index 000000000000000..9c76466d726dc63
--- /dev/null
+++ b/flang/test/Semantics/separate-mp06.f90
@@ -0,0 +1,98 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1
+! Structural equivalence of derived type definitions
+module m
+  interface
+    module subroutine s1(x)
+      type :: nonseq
+        integer :: n
+      end type
+      type(nonseq), intent(in) :: x
+    end subroutine
+    module subroutine s2(x)
+      type :: seq
+        sequence
+        integer :: n
+      end type
+      type(seq), intent(in) :: x
+    end subroutine
+    module subroutine s3(x)
+      type :: chlen
+        sequence
+        character(2) :: s
+      end type
+      type(chlen), intent(in) :: x
+    end subroutine
+    module subroutine s4(x)
+      !ERROR: A sequence type may not have type parameters
+      type :: pdt(k)
+        integer, kind :: k
+        sequence
+        real(k) :: a
+      end type
+      type(pdt(4)), intent(in) :: x
+    end subroutine
+  end interface
+end module
+
+submodule(m) sm
+ contains
+  module subroutine s1(x)
+    type :: nonseq
+      integer :: n
+    end type
+    !ERROR: Dummy argument 'x' has type nonseq; the corresponding argument in the interface body has distinct type nonseq
+    type(nonseq), intent(in) :: x
+  end subroutine
+  module subroutine s2(x) ! ok
+    type :: seq
+      sequence
+      integer :: n
+    end type
+    type(seq), intent(in) :: x
+  end subroutine
+  module subroutine s3(x)
+    type :: chlen
+      sequence
+      character(3) :: s ! note: length is 3, not 2
+    end type
+    !ERROR: Dummy argument 'x' has type chlen; the corresponding argument in the interface body has distinct type chlen
+    type(chlen), intent(in) :: x
+  end subroutine
+  module subroutine s4(x)
+    !ERROR: A sequence type may not have type parameters
+    type :: pdt(k)
+      integer, kind :: k
+      sequence
+      real(k) :: a
+    end type
+    !ERROR: Dummy argument 'x' has type pdt(k=4_4); the corresponding argument in the interface body has distinct type pdt(k=4_4)
+    type(pdt(4)), intent(in) :: x
+  end subroutine
+end submodule
+
+program main
+  use m
+  type :: nonseq
+    integer :: n
+  end type
+  type :: seq
+    sequence
+    integer :: n
+  end type
+  type :: chlen
+    sequence
+    character(2) :: s
+  end type
+  !ERROR: A sequence type may not have type parameters
+  type :: pdt(k)
+    integer, kind :: k
+    sequence
+    real(k) :: a
+  end type
+  !ERROR: Actual argument type 'nonseq' is not compatible with dummy argument type 'nonseq'
+  call s1(nonseq(1))
+  call s2(seq(1)) ! ok
+  call s3(chlen('ab')) ! ok, matches interface
+  !ERROR: Actual argument type 'pdt(k=4_4)' is not compatible with dummy argument type 'pdt(k=4_4)'
+  call s4(pdt(4)(3.14159))
+end program

F'202X 7.5.2.4 describes conditions under which two derived type
definitions are to be considered equivalent.  These rules are
already implemented in Evaluate/type.cpp but not exposed for
general use; rearrange the code a little so that the compatibility
checking of separate module procedure interfaces and explicit
definitions can use it to avoid emitting a bogus error message.

Fixes llvm#67946.
@klausler klausler merged commit c2f642d into llvm:main Oct 30, 2023
@klausler klausler deleted the bug67946 branch October 30, 2023 23:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:semantics flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Flang] Compilation error of a dummy argument of Derived Types used in MODULE PROCEDURE subprogram statement
3 participants