Skip to content

Commit deb2861

Browse files
authored
[flang] Allow for equivalent types in non-TBP defined I/O (#158755)
Non-extensible derived type -- those with SEQUENCE or BIND(C) -- are allowed as monomorphic "dtv" dummy arguments to defined I/O subroutines. Fortran's type rules admit structural equivalence for these types, and it's possible that I/O might be attempted in a scope using a non-extensible type that's equivalent to a non-type-bound generic interface's specific procedure's "dtv" dummy argument's type, but not defined in the same place. Fixes #158673. This is an IBM Fortran test case that doesn't need to be duplicated in LLVM.
1 parent 8fb02fa commit deb2861

File tree

1 file changed

+25
-5
lines changed

1 file changed

+25
-5
lines changed

flang/lib/Semantics/runtime-type-info.cpp

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,12 +1385,31 @@ CollectNonTbpDefinedIoGenericInterfaces(
13851385
if (const DeclTypeSpec *
13861386
declType{GetDefinedIoSpecificArgType(*specific)}) {
13871387
const DerivedTypeSpec &derived{DEREF(declType->AsDerived())};
1388-
if (const Symbol *
1389-
dtDesc{derived.scope()
1390-
? derived.scope()->runtimeDerivedTypeDescription()
1388+
const Scope *derivedScope{derived.scope()};
1389+
if (!declType->IsPolymorphic()) {
1390+
// A defined I/O subroutine with a monomorphic "dtv" dummy
1391+
// argument implies a non-extensible sequence or BIND(C) derived
1392+
// type. Such types may be defined more than once in the program
1393+
// so long as they are structurally equivalent. If the current
1394+
// scope has an equivalent type, use it for the table rather
1395+
// than the "dtv" argument's type.
1396+
if (const Symbol *inScope{scope.FindSymbol(derived.name())}) {
1397+
const Symbol &ultimate{inScope->GetUltimate()};
1398+
DerivedTypeSpec localDerivedType{inScope->name(), ultimate};
1399+
if (ultimate.has<DerivedTypeDetails>() &&
1400+
evaluate::DynamicType{derived, /*isPolymorphic=*/false}
1401+
.IsTkCompatibleWith(evaluate::DynamicType{
1402+
localDerivedType, /*iP=*/false})) {
1403+
derivedScope = ultimate.scope();
1404+
}
1405+
}
1406+
}
1407+
if (const Symbol *dtDesc{derivedScope
1408+
? derivedScope->runtimeDerivedTypeDescription()
13911409
: nullptr}) {
13921410
if (useRuntimeTypeInfoEntries &&
1393-
&derived.scope()->parent() == &generic->owner()) {
1411+
derivedScope == derived.scope() &&
1412+
&derivedScope->parent() == &generic->owner()) {
13941413
// This non-TBP defined I/O generic was defined in the
13951414
// same scope as the derived type, and it will be
13961415
// included in the derived type's special bindings
@@ -1454,7 +1473,8 @@ static const Symbol *FindSpecificDefinedIo(const Scope &scope,
14541473
const Symbol &specific{*ref};
14551474
if (const DeclTypeSpec *
14561475
thisType{GetDefinedIoSpecificArgType(specific)}) {
1457-
if (evaluate::DynamicType{DEREF(thisType->AsDerived()), true}
1476+
if (evaluate::DynamicType{
1477+
DEREF(thisType->AsDerived()), thisType->IsPolymorphic()}
14581478
.IsTkCompatibleWith(derived)) {
14591479
return &specific.GetUltimate();
14601480
}

0 commit comments

Comments
 (0)