fortran: Detect duplicate unlimited polymorphic types [PR103662]

This fixes a type-based alias analysis issue with unlimited polymorphic
class descriptors (types behind class(*)) causing data initialisation to
be removed by optimization.

The fortran front-end may create multiple declarations for types, for
example if a type is redeclared in each program unit it is used in.
To avoid optimization seeing them as non-aliasing, a list of derived
types is created at resolution time, and used at translation to set
the same TYPE_CANONICAL type for each duplicate type declaration.

This mechanism didn’t work for unlimited polymorphic descriptors types,
as there is a short-circuit return skipping all the resolution handling
for them, including the type registration.

This change adds type registration at the short-circuit return, and
updates type comparison to handle specifically unlimited polymorphic
fake symbols, class descriptor types and virtual table types.

The test, which exhibited mismatching dynamic types had to be fixed as
well.

	PR fortran/103662

gcc/fortran/ChangeLog:

	* interface.cc (gfc_compare_derived_types): Support comparing
	unlimited polymorphic fake symbols.  Recursively compare class
	descriptor types and virtual table types.
	* resolve.cc (resolve_fl_derived): Add type to the types list
	on unlimited polymorphic short-circuit return.

gcc/testsuite/ChangeLog:

	* gfortran.dg/unlimited_polymorphic_3.f03 (foo): Separate
	bind(c) and sequence checks to...
	(foo_bc, foo_sq): ... two different procedures.
	(main, foo*): Change type declarations so that type name,
	component name, and either bind(c) or sequence attribute match
	between the main type declarations and the procedure type
	declarations.
	(toplevel): Add optimization dump checks.

Co-Authored-By: Jakub Jelinek <jakub@redhat.com>
This commit is contained in:
Mikael Morin 2022-04-24 15:05:41 +02:00
parent afe0b5b7ce
commit fa5cd7102d
3 changed files with 58 additions and 22 deletions

View File

@ -618,6 +618,14 @@ gfc_compare_derived_types (gfc_symbol *derived1, gfc_symbol *derived2)
if (!derived1 || !derived2)
gfc_internal_error ("gfc_compare_derived_types: invalid derived type");
if (derived1->attr.unlimited_polymorphic
&& derived2->attr.unlimited_polymorphic)
return true;
if (derived1->attr.unlimited_polymorphic
!= derived2->attr.unlimited_polymorphic)
return false;
/* Compare UNION types specially. */
if (derived1->attr.flavor == FL_UNION || derived2->attr.flavor == FL_UNION)
return compare_union_types (derived1, derived2);
@ -630,10 +638,11 @@ gfc_compare_derived_types (gfc_symbol *derived1, gfc_symbol *derived2)
&& strcmp (derived1->module, derived2->module) == 0)
return true;
/* Compare type via the rules of the standard. Both types must have
the SEQUENCE or BIND(C) attribute to be equal. STRUCTUREs are special
because they can be anonymous; therefore two structures with different
names may be equal. */
/* Compare type via the rules of the standard. Both types must have the
SEQUENCE or BIND(C) attribute to be equal. We also compare types
recursively if they are class descriptors types or virtual tables types.
STRUCTUREs are special because they can be anonymous; therefore two
structures with different names may be equal. */
/* Compare names, but not for anonymous types such as UNION or MAP. */
if (!is_anonymous_dt (derived1) && !is_anonymous_dt (derived2)
@ -646,6 +655,8 @@ gfc_compare_derived_types (gfc_symbol *derived1, gfc_symbol *derived2)
if (!(derived1->attr.sequence && derived2->attr.sequence)
&& !(derived1->attr.is_bind_c && derived2->attr.is_bind_c)
&& !(derived1->attr.is_class && derived2->attr.is_class)
&& !(derived1->attr.vtype && derived2->attr.vtype)
&& !(derived1->attr.pdt_type && derived2->attr.pdt_type))
return false;

View File

@ -15151,7 +15151,10 @@ resolve_fl_derived (gfc_symbol *sym)
/* Nothing more to do for unlimited polymorphic entities. */
if (data->ts.u.derived->attr.unlimited_polymorphic)
return true;
{
add_dt_to_dt_list (sym);
return true;
}
else if (vptr->ts.u.derived == NULL)
{
gfc_symbol *vtab = gfc_find_derived_vtab (data->ts.u.derived);

View File

@ -1,4 +1,5 @@
! { dg-do run }
! { dg-additional-options "-fdump-tree-dse-details" }
!
! Check that pointer assignments allowed by F2003:C717
! work and check null initialization of CLASS(*) pointers.
@ -7,20 +8,31 @@
!
program main
interface
subroutine foo(z)
subroutine foo_bc(z)
class(*), pointer, intent(in) :: z
end subroutine foo
end subroutine foo_bc
subroutine foo_sq(z)
class(*), pointer, intent(in) :: z
end subroutine foo_sq
end interface
type, bind(c) :: bc
integer :: i
end type bc
type sq
sequence
integer :: i
integer :: k
end type sq
type(bc), target :: w
type(sq), target :: x
class(*), pointer :: y, z
x%i = 42
w%i = 23
y => w
z => y ! unlimited => unlimited allowed
call foo_bc(z)
x%k = 42
y => x
z => y ! unlimited => unlimited allowed
call foo (z)
call foo_sq(z)
call bar
contains
subroutine bar
@ -33,21 +45,31 @@ contains
end program main
subroutine foo(tgt)
subroutine foo_bc(tgt)
use iso_c_binding
class(*), pointer, intent(in) :: tgt
type, bind(c) :: s
integer (c_int) :: k
end type s
type t
type, bind(c) :: bc
integer (c_int) :: i
end type bc
type(bc), pointer :: ptr1
ptr1 => tgt ! bind(c) => unlimited allowed
if (ptr1%i .ne. 23) STOP 2
end subroutine foo_bc
subroutine foo_sq(tgt)
class(*), pointer, intent(in) :: tgt
type sq
sequence
integer :: k
end type t
type(s), pointer :: ptr1
type(t), pointer :: ptr2
ptr1 => tgt ! bind(c) => unlimited allowed
if (ptr1%k .ne. 42) STOP 2
end type sq
type(sq), pointer :: ptr2
ptr2 => tgt ! sequence type => unlimited allowed
if (ptr2%k .ne. 42) STOP 3
end subroutine foo
end subroutine foo_sq
! PR fortran/103662
! We used to produce multiple independant types for the unlimited polymorphic
! descriptors (types for class(*)) which caused stores to them to be seen as
! useless.
! { dg-final { scan-tree-dump-not "Deleted dead store: z._data = &w" "dse1" } }
! { dg-final { scan-tree-dump-not "Deleted dead store: z._data = &x" "dse1" } }