https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128349
Bug ID: 128349
Summary: Copy to temporary doesn't use polymorphic assignment
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Keywords: wrong-code
Severity: normal
Priority: P3
Component: fortran
Assignee: unassigned at gcc dot gnu.org
Reporter: mikael at gcc dot gnu.org
Target Milestone: ---
Testcase:
program prog
implicit none
integer, parameter :: n = 5
type :: t1
integer :: c1, c2, c3
end type
type :: t2
integer :: c1, c2, c3
end type
type(t1) :: a(n)
integer :: i
a = [ (t1(2*i+1, 3*i*i+2, 5*i*i+3), i=1, n) ]
call sub(a)
contains
subroutine sub(x)
class(*), intent(in) :: x(:)
type(t2) :: y(n)
call check_t2(transfer(x, y))
end subroutine
subroutine check_t2(x)
type(t2), target, intent(in) :: x(:)
call check(x%c1, [3, 5, 7, 9, 11], 1)
call check(x%c2, [5, 14, 29, 50, 77], 2)
call check(x%c3, [8, 23, 48, 83, 128], 3)
end subroutine
subroutine check(x, y, e)
integer, intent(in) :: x(:), y(:), e
if (size(x) /= size(y)) error stop e*10+8
do i=1,size(x)
print *, e*10+i, (x(i) == y(i) ? "PASS" : "FAIL"), x(i), y(i)
end do
!if (any(x /= y)) error stop e*10+9
end subroutine
end program
It has been created using the analysis at:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128345#c2
It produces failures on a broader set of platforms than the testsuite's
transfer_class_5.f90 of PR128345.
When executed, it produces as output:
11 PASS 3 3
12 PASS 5 5
13 PASS 7 7
14 PASS 9 9
15 PASS 11 11
21 PASS 5 5
22 PASS 14 14
23 PASS 29 29
24 PASS 50 50
25 PASS 77 77
31 FAIL 0 8
32 FAIL 0 23
33 FAIL 0 48
34 FAIL 0 83
35 FAIL 0 128
showing that only part of the value is copied and made available as input
argument to check_t2.
The problem is triggered by the TRANSFER intrinsic, but that is only useful to
force the creation of a temporary:
8851 bool simply_contiguous = gfc_is_simply_contiguous (arg->expr,
8852 false, true);
8853 argse.want_pointer = 0;
8854 /* A non-contiguous SOURCE needs packing. */
8855 if (!simply_contiguous)
8856 argse.force_tmp = 1;
8857 gfc_conv_expr_descriptor (&argse, arg->expr);
The problem is an assignment to a temporary that is not done using the
polymorphic copy function, and falls back to normal assignment of void pointer
values, which only copies the size of a pointer:
> D.5053 = ctmp.37._data.dim[0].stride;
> D.5054 = stride.33;
> S.38 = 0;
> while (1)
> {
> if (S.38 > D.5039) goto L.10;
> {
> (...)
> D.5059 = x->_vptr;
> D.5060 = x->_vptr->_size;
> D.5061 = x->_len;
> D.5062 = D.5061 > 0 ? D.5060 * D.5061 : D.5060;
> D.5055 = ctmp.37._vptr;
> D.5056 = ctmp.37._vptr->_size;
> D.5057 = ctmp.37._len;
> D.5058 = D.5057 > 0 ? D.5056 * D.5057 : D.5056;
> *(void * *) (ctmp.37._data.data + (sizetype) ((S.38 * D.5053) *
> D.5058)) = *((void * *) D.5032 + (sizetype) (((S.38 + 1) * D.5054 + D.5033) *
> D.5062));
> }
> S.38 = S.38 + 1;
> }
> L.10:;
In trans_scalar_class_assign:
1965 /* Fix the class expression and the class data of the rhs. */
1966 if (!GFC_CLASS_TYPE_P (TREE_TYPE (rse->expr))
1967 || not_call_expr)
1968 {
1969 tmp = gfc_get_class_from_expr (rse->expr);
1970 if (tmp == NULL_TREE)
1971 return false;
1972 rse_expr = gfc_evaluate_now (tmp, block);
1973 }
1974 else
1975 rse_expr = gfc_evaluate_now (rse->expr, block);
as gfc_get_class_from_expr is unable to find the reference to the class
container from the rhs expression, false is returned and the non-polymorphic
fall back assignment is used.