Skip to content

Commit c2f642d

Browse files
authored
[flang] Derived type structural equivalence (#69376)
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.
1 parent 784a2cd commit c2f642d

File tree

6 files changed

+124
-10
lines changed

6 files changed

+124
-10
lines changed

flang/include/flang/Evaluate/type.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,10 @@ class DynamicType {
208208
// SAME_TYPE_AS (16.9.165); ignores type parameter values
209209
std::optional<bool> SameTypeAs(const DynamicType &) const;
210210

211+
// 7.5.2.4 type equivalence; like operator==(), but SEQUENCE/BIND(C)
212+
// derived types can be structurally equivalent.
213+
bool IsEquivalentTo(const DynamicType &) const;
214+
211215
// Result will be missing when a symbol is absent or
212216
// has an erroneous type, e.g., REAL(KIND=666).
213217
static std::optional<DynamicType> From(const semantics::DeclTypeSpec &);

flang/lib/Evaluate/type.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ const semantics::DerivedTypeSpec *GetParentTypeSpec(
293293
}
294294

295295
// Compares two derived type representations to see whether they both
296-
// represent the "same type" in the sense of section 7.5.2.4.
296+
// represent the "same type" in the sense of section F'2023 7.5.2.4.
297297
using SetOfDerivedTypePairs =
298298
std::set<std::pair<const semantics::DerivedTypeSpec *,
299299
const semantics::DerivedTypeSpec *>>;
@@ -513,6 +513,19 @@ bool AreSameDerivedType(
513513
return AreSameDerivedType(x, y, false, false, inProgress);
514514
}
515515

516+
bool AreSameDerivedType(
517+
const semantics::DerivedTypeSpec *x, const semantics::DerivedTypeSpec *y) {
518+
return x == y || (x && y && AreSameDerivedType(*x, *y));
519+
}
520+
521+
bool DynamicType::IsEquivalentTo(const DynamicType &that) const {
522+
return category_ == that.category_ && kind_ == that.kind_ &&
523+
PointeeComparison(charLengthParamValue_, that.charLengthParamValue_) &&
524+
knownLength().has_value() == that.knownLength().has_value() &&
525+
(!knownLength() || *knownLength() == *that.knownLength()) &&
526+
AreSameDerivedType(derived_, that.derived_);
527+
}
528+
516529
static bool AreCompatibleDerivedTypes(const semantics::DerivedTypeSpec *x,
517530
const semantics::DerivedTypeSpec *y, bool isPolymorphic,
518531
bool ignoreTypeParameterValues, bool ignoreLenTypeParameters) {

flang/lib/Semantics/check-declarations.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3354,10 +3354,9 @@ void SubprogramMatchHelper::CheckDummyDataObject(const Symbol &symbol1,
33543354
const DummyDataObject &obj2) {
33553355
if (!CheckSameIntent(symbol1, symbol2, obj1.intent, obj2.intent)) {
33563356
} else if (!CheckSameAttrs(symbol1, symbol2, obj1.attrs, obj2.attrs)) {
3357-
} else if (obj1.type.type() != obj2.type.type()) {
3357+
} else if (!obj1.type.type().IsEquivalentTo(obj2.type.type())) {
33583358
Say(symbol1, symbol2,
3359-
"Dummy argument '%s' has type %s; the corresponding argument in the"
3360-
" interface body has type %s"_err_en_US,
3359+
"Dummy argument '%s' has type %s; the corresponding argument in the interface body has distinct type %s"_err_en_US,
33613360
obj1.type.type().AsFortran(), obj2.type.type().AsFortran());
33623361
} else if (!ShapesAreCompatible(obj1, obj2)) {
33633362
Say(symbol1, symbol2,

flang/test/Semantics/separate-mp02.f90

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ module subroutine s5(x, y)
5151
real :: y
5252
end
5353
module subroutine s6(x, y)
54-
!ERROR: Dummy argument 'x' has type INTEGER(4); the corresponding argument in the interface body has type REAL(4)
54+
!ERROR: Dummy argument 'x' has type INTEGER(4); the corresponding argument in the interface body has distinct type REAL(4)
5555
integer :: x
56-
!ERROR: Dummy argument 'y' has type REAL(8); the corresponding argument in the interface body has type REAL(4)
56+
!ERROR: Dummy argument 'y' has type REAL(8); the corresponding argument in the interface body has distinct type REAL(4)
5757
real(8) :: y
5858
end
5959
module subroutine s7(x, y, z)
@@ -72,10 +72,10 @@ module subroutine s8(x, y, z)
7272
end
7373
module subroutine s9(x, y, z, w)
7474
character(len=4) :: x
75-
!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)
75+
!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)
7676
character(len=5) :: y
7777
character(len=*) :: z
78-
!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=*)
78+
!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=*)
7979
character(len=4) :: w
8080
end
8181
end
@@ -330,7 +330,7 @@ module subroutine sub1(s)
330330
character(len=-1) s ! ok
331331
end subroutine
332332
module subroutine sub2(s)
333-
!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)
333+
!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)
334334
character(len=1) s
335335
end subroutine
336336
end submodule

flang/test/Semantics/separate-mp03.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ pure module subroutine s2
7474
end interface
7575
contains
7676
integer module function f1(x)
77-
!ERROR: Dummy argument 'x' has type INTEGER(4); the corresponding argument in the interface body has type REAL(4)
77+
!ERROR: Dummy argument 'x' has type INTEGER(4); the corresponding argument in the interface body has distinct type REAL(4)
7878
integer, intent(in) :: x
7979
f1 = x
8080
end function
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
! RUN: %python %S/test_errors.py %s %flang_fc1
2+
! Structural equivalence of derived type definitions
3+
module m
4+
interface
5+
module subroutine s1(x)
6+
type :: nonseq
7+
integer :: n
8+
end type
9+
type(nonseq), intent(in) :: x
10+
end subroutine
11+
module subroutine s2(x)
12+
type :: seq
13+
sequence
14+
integer :: n
15+
end type
16+
type(seq), intent(in) :: x
17+
end subroutine
18+
module subroutine s3(x)
19+
type :: chlen
20+
sequence
21+
character(2) :: s
22+
end type
23+
type(chlen), intent(in) :: x
24+
end subroutine
25+
module subroutine s4(x)
26+
!ERROR: A sequence type may not have type parameters
27+
type :: pdt(k)
28+
integer, kind :: k
29+
sequence
30+
real(k) :: a
31+
end type
32+
type(pdt(4)), intent(in) :: x
33+
end subroutine
34+
end interface
35+
end module
36+
37+
submodule(m) sm
38+
contains
39+
module subroutine s1(x)
40+
type :: nonseq
41+
integer :: n
42+
end type
43+
!ERROR: Dummy argument 'x' has type nonseq; the corresponding argument in the interface body has distinct type nonseq
44+
type(nonseq), intent(in) :: x
45+
end subroutine
46+
module subroutine s2(x) ! ok
47+
type :: seq
48+
sequence
49+
integer :: n
50+
end type
51+
type(seq), intent(in) :: x
52+
end subroutine
53+
module subroutine s3(x)
54+
type :: chlen
55+
sequence
56+
character(3) :: s ! note: length is 3, not 2
57+
end type
58+
!ERROR: Dummy argument 'x' has type chlen; the corresponding argument in the interface body has distinct type chlen
59+
type(chlen), intent(in) :: x
60+
end subroutine
61+
module subroutine s4(x)
62+
!ERROR: A sequence type may not have type parameters
63+
type :: pdt(k)
64+
integer, kind :: k
65+
sequence
66+
real(k) :: a
67+
end type
68+
!ERROR: Dummy argument 'x' has type pdt(k=4_4); the corresponding argument in the interface body has distinct type pdt(k=4_4)
69+
type(pdt(4)), intent(in) :: x
70+
end subroutine
71+
end submodule
72+
73+
program main
74+
use m
75+
type :: nonseq
76+
integer :: n
77+
end type
78+
type :: seq
79+
sequence
80+
integer :: n
81+
end type
82+
type :: chlen
83+
sequence
84+
character(2) :: s
85+
end type
86+
!ERROR: A sequence type may not have type parameters
87+
type :: pdt(k)
88+
integer, kind :: k
89+
sequence
90+
real(k) :: a
91+
end type
92+
!ERROR: Actual argument type 'nonseq' is not compatible with dummy argument type 'nonseq'
93+
call s1(nonseq(1))
94+
call s2(seq(1)) ! ok
95+
call s3(chlen('ab')) ! ok, matches interface
96+
!ERROR: Actual argument type 'pdt(k=4_4)' is not compatible with dummy argument type 'pdt(k=4_4)'
97+
call s4(pdt(4)(3.14159))
98+
end program

0 commit comments

Comments
 (0)