4

I have some legacy Fortran 77 code which I'm trying to at least compile without warnings (without disabling warnings). There are subroutine calls that pass a scalar where subroutine expects an array, since the scalar is used as a size-1 array, this causes no problems. But with the Intel compiler, if I enable interface warnings I get this error:

error #8284: If the actual argument is scalar, the dummy argument shall be scalar unless the actual argument is of type character or is an element of an array that is not assumed shape, pointer, or polymorphic.

In some cases, I've tried to solve this by overloading the subroutine with array and scalar variants, but then I face a problem when the argument passed is an "an element of an array", which is detected as a scalar. Consider the following sample (tested with gfortran):

program a
  integer n,dum(3)
  interface readn
    subroutine readn_s(n,m)
      integer m,n
    end subroutine
    subroutine readn_a(n,m)
      integer m,n(*)
    end subroutine
  end interface
  call readn(n,1)
  write(6,*) 'n=',n
  call readn(dum,3)
  write(6,*) 'dum=',dum
  call readn(dum(2),2)
  write(6,*) 'dum=',dum
end program

subroutine readn_s(n,m)
  integer i,m,n
  n=2
end subroutine

subroutine readn_a(n,m)
  integer i,m,n(*)
  do i=1,m
    n(i)=1
  end do
end subroutine

The readn(dum,3) call correctly uses readn_a, while the second one uses readn_s. The intended behaviour is that both should use readn_a. Indeed, if I replace both calls with readn_a everything is as expected.

Is it possible to have this working properly and use the "array" version of the overloaded routine when the actual argument is an array element? I've found out it works if I call the subroutine with readn(dum(2:),2), but I'm afraid that creates a temporary copy of the array...

Original problem:

file.f90

program a
  integer n,dum(3)
  call readn_a(n,1)
  write(6,*) 'n=',n
  call readn_a(dum,3)
  write(6,*) 'dum=',dum
  dum=3
  call readn_a(dum(2),2)
  write(6,*) 'dum=',dum
end program

file2.f90

subroutine readn_a(n,m)
  integer i,m,n(*)
  do i=1,m
    n(i)=1
  end do
end subroutine

Compile with gfortran -Wall file.f90 file2.f90 or ifort file.f90 file2.f90, all is fine and the output is the intended:

 n=           1
 dum=           1           1           1
 dum=           3           1           1

Compile with ifort -warn all file.f90 file2.f90 and I get the error #8284 above. So that's why I wanted a version of the subroutine that would work with scalars or arrays... but would give the array version with an array element.

Jellby
  • 2,360
  • 3
  • 27
  • 56
  • 2
    dum(2:) is what you need here. It might create a copy, but as it is contiguous, we would hope the compiler doesn't do that. Otherwise, I guess you would need to stick with implicit interfaces. – haraldkl Jan 13 '17 at 08:49
  • It would be nice to see the example of the code where the warning is triggered. Notice *"actual argument ... is an element of an array that is not assumed shape, pointer, or polymorphic."*, that should not be hard to fulfill. Especially in Fortran 77 which has no *assumed shape, pointer, or polymorphic*. – Vladimir F Героям слава Jan 13 '17 at 09:30
  • @VladimirF To get the error (not warning, even though it's enabled as a warning), comment out all the ``interface`` block and replace all calls with ``readn_a``. ``ifort file.f90`` compiles and runs fine, ``ifort -warn all file.f90`` gives the error for ``readn_a(n,1)``. With gfortran, the code compiles (no interface-related warning) when program and subroutines are in separate files. – Jellby Jan 13 '17 at 09:58
  • @HighPerformanceMark that could work for this simple example, but I'm pretty sure not every subroutine could be converted to elemental (like those whose behaviour depend on the length of the array/scalar). – Jellby Jan 13 '17 at 11:47
  • I tried the first program above with ifort-16, and it seems changing dum(2) to dum(2:) simply works, as @haraldkl suggested (i.e., the former selects readn_s while the latter selects readn_a). We can also check whether array temporaries are created by attaching "-check arg_temp_created". If we pass data as readn( dum(1:3:2), 2 ), then the above option gives run-time warning that "an array temporary created". So maybe no worry with using dum(2:) ? – roygvib Jan 13 '17 at 13:11
  • @roygvib There is no reason to worry about a temporary for `dum(2:)`, no sane compiler would use it for a contiguous array. – Vladimir F Героям слава Jan 13 '17 at 13:30
  • @VladimirF I also think so, but OP seems afraid about that...(in the question). Btw, on my computer + ifort-16, passing [n] seems not work (copy-in works, but copy-back from a temporary does not occur to n on the caller side). Does it work in your environment? – roygvib Jan 13 '17 at 14:06
  • @roygvib No, [n] may not be modified, that would be illegal. – Vladimir F Героям слава Jan 13 '17 at 14:08

1 Answers1

4

In your attempted solution the type-kind-rank generic resolution will delegate all array elements to the scalar version of the subroutine and that will not do the intended work on the part of the array. So "The intended behaviour is that both should use readn_a." is not really possible with the approach you chose.

Well, it is possible when you rewrite the code to pass array sections as you noted yourself. But we are again at the same problem as we were before, you example is simplified. We can be certain there there is no temporary array in the example you have shown, we definitely can't say that about your real code. If you use some 2D subsections starting at some random place, you will have temporary arrays for sure and it might be difficult to make the correct subsection at all.

The original warning should be reasonably easy to avoid in your original legacy code. FORTRAN 77 has no non-contiguous arrays so if you keep your arguments to be integer :: a(*) instead of integer :: a and pass that further. If your original variable is scalar, that is a problem.


The problem is that an integer scalar does not constitute an element sequence:

F2008 12.5.2.11 1 An actual argument represents an element sequence if it is an array expression, an array element designator, a default character scalar, or a scalar of type character with the C character kind (15.2.2). ...

An array element designator a(2) is an element sequence but the scalar n is not.

So it is not allowed for sequence association which is used when an array element is passed:

F2008 12.5.2.11 4 An actual argument that represents an element sequence and corresponds to a dummy argument that is an array is sequence associated with the dummy argument if the dummy argument is an explicit-shape or assumed-size array. ...

Your code is not strictly standard Fortran conforming, but very likely to work as expected if you manage to compile it.


Possible solutions:

  • You can pass the argument as an array expression, but the argument may not be modified inside the subroutine

    call readn_a([n],1)

  • You can just disable the warnings about interface matching

    ifort -warn nointerfaces

  • You can create separate subroutines which only work for scalars and call it under some different name.

  • You can also disable argument checking for that dummy argument by an Intel Compiler directive

    !DEC$ ATTRIBUTES NO_ARG_CHECK :: dummy-arg-name

  • I've included the "original problem" in the question. I don't understand your ``a(*)`` suggestion. I already have an assumed-size dummy argument, and I can't declare ``n(*)`` in the main program. Of course, I could declare ``n(1)``, but that would need cumbersome, extensive rewriting in a real program. – Jellby Jan 13 '17 at 10:45
  • The first "possible solution" only works for input arguments, it would be a nice way to promote a scalar to a size-1 array, though. Ignoring the warning is not an option, because it's an **error**, not a warning, but I can indeed disable it, at the cost of not getting other checks (like wrong number of arguments). – Jellby Jan 13 '17 at 11:49
  • Yes, it is only for input arguments. The simplest is probable the last one, but you will not get any error if you do something bad when calling that argument. – Vladimir F Героям слава Jan 13 '17 at 11:57
  • @Jellby Yes, it is an error, but you can disable that warning and it will not trigger the error, see the edit. – Vladimir F Героям слава Jan 13 '17 at 12:00
  • If the original code relied on sequence association, then I don't think there can be complicated array sections (or those complicated array sections have to already exist in the code). Personally I would simply create the separately named, "thin wrapper" scalar subroutine variants, once the compiler is aware of the interface of the called procedure it will even tell you which procedure references need to be renamed. Suppressing the diagnostic would make me nervous about optimisation/alignment issues in the future. – IanH Jan 13 '17 at 19:31