Error: Pointer bounds remapping target must have rank 1 or be simply contiguous

I would like to ask your help regarding the fortran code presented at the bottom of this post.

With gfortran, the code compiles and works as intended. In contrast, with flang (new), the following error is raised.

error: Semantic errors in test/test.f90
./test/test.f90:58:17: error: Pointer bounds remapping target must have rank 1 or be simply contiguous
        rank (2); wt_(1:ldwt, 1:ld2wt, 1:m) => wt
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
./test/test.f90:59:17: error: Pointer bounds remapping target must have rank 1 or be simply contiguous
        rank (3); wt_(1:ldwt, 1:ld2wt, 1:m) => wt
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
./test/test.f90:65:17: error: Pointer bounds remapping target must have rank 1 or be simply contiguous
        rank (2); t_(1:n, 1:m) => t
                  ^^^^^^^^^^^^^^^^^
./test/test.f90:71:17: error: Pointer bounds remapping target must have rank 1 or be simply contiguous
        rank (2); wtt_(1:n, 1:m) => wtt

Questions:

  1. Is my use of select rank and/or pointer assignment non-conform, or is this a flang bug/limitation?
  2. Is there a more elegant way to achieve the same result? I need to carry out this scaling operation at various points of the calling code, and the argument arrays are quite often in the “wrong” shape.
program test

  implicit none

  integer :: n, m, ldwt, ld2wt
  real, allocatable :: wt1(:), t1(:), wtt1(:)
  real, allocatable :: wt2(:,:,:), t2(:,:), wtt2(:,:)

  n = 3
  m = 2
  ldwt = n
  ld2wt = m
  
  ! rank-1 arrays
  allocate(wt1(ldwt*ld2wt*m), t1(n*m), wtt1(n*m))
  t1 = 1.0
  wt1 = 2.0
  call scale_mat(n, m, wt1, ldwt, ld2wt, t1, wtt1)
  print *, "wtt1=", wtt1

  ! high-rank arrays
  allocate(wt2(ldwt, ld2wt, m), t2(n, m), wtt2(n, m))
  t2 = 1.0
  wt2 = 2.0
  call scale_mat(n, m, wt2, ldwt, ld2wt, t2, wtt2)
  print *, "wtt2=", wtt2

  contains

    pure subroutine scale_mat(n, m, wt, ldwt, ld2wt, t, wtt)
      !! Scale matrix `t` using `wt`, i.e., compute `wtt = wt*t`.

      integer, intent(in) :: n
        !! Number of rows of data in `t`.
      integer, intent(in) :: m
        !! Number of columns of data in `t`.
      real, intent(in), target :: wt(..)
        !! Array of shape conformable to `(ldwt,ld2wt,m)` holding the weights.
      integer, intent(in) :: ldwt
        !! Leading dimension of array `wt`.
      integer, intent(in) :: ld2wt
        !! Second dimension of array `wt`.
      real, intent(in), target :: t(..)
        !! Array of shape conformable to `(n,m)` being scaled by `wt`.
      real, intent(out), target :: wtt(..)
        !! Array of shape conformable to `(n,m)` holding the result of weighting array `t` by
        !! array `wt`. Array `wtt` can be the same as `t` only if the arrays in `wt` are upper
        !! triangular with zeros below the diagonal.

      ! Local scalars
      integer :: i, j
      real, pointer :: wt_(:, :, :), t_(:, :), wtt_(:, :)

      if (n == 0 .or. m == 0) return

      select rank (wt)
      rank (1); wt_(1:ldwt, 1:ld2wt, 1:m) => wt
      rank (2); wt_(1:ldwt, 1:ld2wt, 1:m) => wt
      rank (3); wt_(1:ldwt, 1:ld2wt, 1:m) => wt
      rank default; error stop "Invalid rank of `wt`."
      end select

      select rank (t)
      rank (1); t_(1:n, 1:m) => t
      rank (2); t_(1:n, 1:m) => t
      rank default; error stop "Invalid rank of `t`."
      end select

      select rank (wtt)
      rank (1); wtt_(1:n, 1:m) => wtt
      rank (2); wtt_(1:n, 1:m) => wtt
      rank default; error stop "Invalid rank of `wtt`."
      end select

      if (wt_(1, 1, 1) >= 0.0) then
          if (ldwt >= n) then
            if (ld2wt >= m) then
                ! WT is an N-array of M by M matrices
                do j = 1, m
                  do i = 1, n
                      wtt_(i, j) = dot_product(wt_(i, j, :), t_(i, :))
                  end do
                end do
            else
                ! WT is an N-array of diagonal matrices
                do j = 1, m
                  wtt_(:, j) = wt_(:, 1, j)*t_(:, j)
                end do
            end if
          else
            if (ld2wt >= m) then
                ! WT is an M by M matrix
                do j = 1, m
                  do i = 1, n
                      wtt_(i, j) = dot_product(wt_(1, j, :), t_(i, :))
                  end do
                end do
            else
                ! WT is a diagonal matrix
                do j = 1, m
                  wtt_(:, j) = wt_(1, 1, j)*t_(:, j)
                end do
            end if
          end if
      else
          ! WT is a scalar
          wtt_ = abs(wt_(1, 1, 1))*t_
      end if

    end subroutine scale_mat

end program test

So the issue is that you are doing an equivalent of:

wt_(1:ldwt, 1:ld2wt, 1:m) => wt(:, :)

And the question is whether this is allowed in Fortran.

I think Flang is correct according to the standard.

To fix it, make it contiguous, like this:

real, intent(in), target, contiguous :: wt(..)

This might work.

Thanks, that solved it indeed! :slight_smile:

2 Likes