https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85975
Bug ID: 85975 Summary: Incorrect size for spread array Product: gcc Version: 8.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libfortran Assignee: unassigned at gcc dot gnu.org Reporter: stephan.kramer at imperial dot ac.uk Target Milestone: --- With the following program program foo implicit none call bar(2, 3, 5, 7) contains subroutine bar(k, l, m, n) integer, intent(in) :: k, l, m, n real, dimension(k) :: a real, dimension(k,l):: b real, dimension(k,l,m):: c real, dimension(k,l,m,n):: d print *, size(spread(A, 1, 1)) print *, size(spread(b, 1, 1)) print *, size(spread(c, 1, 1)) print *, size(spread(d, 1, 1)) end subroutine end program I get the following result: $ gfortran test2.f90 skramer@gyre:~/tst/gfortran8$ ./a.out 2 6 0 210 skramer@gyre:~/tst/gfortran8$ ./a.out 0 6 754395868 210 i.e. the results for the A and c arrrays are incorrect (and vary between subsequent reruns). After some digging in the libfortran source I think this is due to a bug in the GFC_DTYPE_COPY_SETRANK macro introduced in https://gcc.gnu.org/ml/gcc-patches/2018-01/msg00369.html, where line 421 of libgfortran/libgfortran.h changed from (a)->dtype = (((b)->dtype & ~GFC_DTYPE_RANK_MASK) | n ); \ to (a)->dtype.rank = ((b)->dtype.rank | n ); \ The thing is that the "| n" makes sense in the previous case where the relevant bits that store the previous rank have been zeroed out first. Now that rank is a separate field, I think it should just be: (a)->dtype.rank = n Note that in the example above the even ranked arrays (B and D) do get the correct result. This is because in those cases it happens to be that new_rank==(old_rank | new_rank) (3 == 2 | 3 and 5 == 4 | 5). In the case of arrays A and C however, we get 1 | 2 == 3 and 3 | 4 == 7, so that the rank of the resulting spread array is too big, and the size calculations uses spurious uninitialised array extents. I have found, what I think are, related issues, when passing the result of spread of a rank-3 array into a subroutine, where in the "internal pack" routine would sometimes try to allocate a temporary that is way too big and cause an out of memory error (similar to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85816). Unfortunately this one seems a little harder to reproduce in a small program.