Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
Announcements
FPGA community forums and blogs on community.intel.com are migrating to the new Altera Community and are read-only. For urgent support needs during this transition, please visit the FPGA Design Resources page or contact an Altera Authorized Distributor.
29285 Discussions

Can't use intrinsic MAX with more than 9 arguments

Andrew_D_5
Beginner
2,107 Views

I've found that if I have overloaded the intrinsic MAX function with any arbitrary function, I am no longer able to use the intrinsic MAX function with 10 or more arguments, but it still works for 2 to 9 arguments.

For a simple example consider a program that simply attempts to call the intrinsic MAX function twice, once with 9 arguments and once with 10 arguments. Now, assume we have a module max_mod that overloads the intrinsic MAX function with a dummy function that accepts a single integer input and returns it. If I modify the original program to add a USE max_mod statement it will no longer compile. Code for this example is below:

program prog1
    implicit none
    real :: a
    a = max(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0)
    write (*, *) 'max of 9 numbers, expecting 9: ', a
    a = max(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)
    write (*, *) 'max of 10 numbers, expecting 10: ', a
end program

This program compiles and works as expected. Next the module and the program using it:

module max_mod
    implicit none
    interface max
        module procedure max_dummy
    end interface max
contains
    function max_dummy (i)
        integer, intent(in) :: i
        integer :: max_dummy
        max_dummy = i
    end function max_dummy
end module max_mod

program prog2
    use max_mod
    implicit none
    real :: a
    a = max(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0)
    write (*, *) 'max of 9 numbers, expecting 9: ', a
    a = max(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)
    write (*, *) 'max of 10 numbers, expecting 10: ', a
end program

This program will not compile, giving the error message

prog2.f90(20): error #6284: There is no matching specific function for this generic function reference.   [MAX]
    a = max(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)
--------^
compilation aborted for prog2.f90 (code 1)

I found it odd that there is no error when only 9 arguments are specified, but for 10 or more I see this compilation error. I had expected this to compile. Am I misunderstanding something or is this a bug?

I'm using Intel Fortran ifort (IFORT) 15.0.2 20150121. I have also tested with 14.0.0 20130728 and 12.0.0 20101006.

0 Kudos
12 Replies
Steven_L_Intel1
Employee
2,107 Views

Looks like a bug to me. I will let the developers know - thanks. Issue ID DPD200379258. Affects MIN as well.

0 Kudos
Andrew_D_5
Beginner
2,107 Views

Thanks Steve. I forgot to mention MIN has this problem too, glad you spotted that.

0 Kudos
Steven_L_Intel1
Employee
2,107 Views

I know that the compiler has to "stand on its head" to support MAX and MIN with their variable argument lists - especially if you use the keyword form. The language doesn't have anything like this elsewhere.  If I recall correctly, there's a bit of a separate code path for 10 or more arguments and this is probably where the issue lies. When I get any info on a fix I will let you know here.

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,107 Views

Steve, Andrew,

This is entering an area that I have yet to explore...

Can you clarify what you expect to happen in light of the fact that your interface max, which appears to be a generic interface to an interface max_dummy taking a single integer argument is to work with a max(...) statement taking multiple real arguments? (as used in your sample program)

IOW does the declaration in your code extend the intrinsic max function such that max(123) calls your function, max(123 ,456) calls the default max function (two args not specified in your definition), max(123.0) calls the default max function,...

Then, follow-up, how does one define a Fortran interface containing a variable number of arguments? (an argument equivalent to ellipsis in other languages)

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
2,107 Views

Andrew's extension would come into effect only if one called MAX with a single integer argument. Since his program always calls MAX with multiple real arguments the calls are not "consistent with" the extension.

Section 12.5 of F2008 covers how name resolution works, and 12.5.5.2 in particular. There is an order to the consideration:

  1. Nonelemental reference to a specific interface of the generic
  2. Elemental reference to a specific interface of the generic
  3. If declared INTRINSIC in this scoping unit or USE makes accessible the name declared INTRINSIC, then that intrinsic
  4. Apply these rules to the next outer scoping unit (with a condition about whether the current and host scoping unit agree as to whether the name is a subroutine or a function - remember that you can't mix these in a generic (except that we sort-of allow this as a limited extension.))
  5. Otherwise, if it's an intrinsic, that intrinsic

How do you define a Fortran interface like MAX or MIN? You can't - that's why it's so weird.

0 Kudos
FortranFan
Honored Contributor III
2,107 Views

jimdempseyatthecove wrote:

.. how does one define a Fortran interface containing a variable number of arguments? (an argument equivalent to ellipsis in other languages) ..

Jim,

Fyi, you'll see a note along the following lines in Fortran standard documents, the particular text below from draft Fortran 2015:

The C language allows specification of a C function that can take a variable number of arguments (ISO/IEC
9899:2011, 7.16). This part of ISO/IEC 1539 does not provide a mechanism for Fortran procedures to
interoperate with such C functions.

As mentioned in another thread a while ago (by R.O.?), one might be able to get the variadic argument stuff o work with !DEC$ ATTRIBUTE VARYING.

 

0 Kudos
Steven_L_Intel1
Employee
2,107 Views

I am fairly certain that ATTRIBUTES VARYING is not of help here. Variadic functions typically pass the address of a list as corresponding to the "...". Regardless, there is no syntax for declaring a Fortran procedure that takes an unspecified number of arguments.

0 Kudos
FortranFan
Honored Contributor III
2,107 Views

Steve Lionel (Intel) wrote:

I am fairly certain that ATTRIBUTES VARYING is not of help here. Variadic functions typically pass the address of a list as corresponding to the "...". Regardless, there is no syntax for declaring a Fortran procedure that takes an unspecified number of arguments.

Steve,

See this thread, especially Message #18 where R.O. shows a working example:

https://software.intel.com/en-us/forums/intel-fortran-compiler-for-linux-and-mac-os-x/topic/544720

0 Kudos
Steven_L_Intel1
Employee
2,107 Views

I saw that, but I am still uncertain how well this works with variadic functions, or maybe my understanding of how they work is wrong. ATTRIBUTES VARYING can be used in an interface, as RO showed, to be able to pass "extra" arguments, but you had better get the types right.

0 Kudos
FortranFan
Honored Contributor III
2,107 Views

Steve Lionel (Intel) wrote:

I saw that, but I am still uncertain how well this works with variadic functions, or maybe my understanding of how they work is wrong. ATTRIBUTES VARYING can be used in an interface, as RO showed, to be able to pass "extra" arguments, but you had better get the types right.

Makes sense - I personally prefer to avoid compiler directives for anything other with the necessary interfaces for OS-specific APIs and when it comes to variadic functions in C/C++, wrapper functions with a fixed set of arguments for interoperation with Fortran seems to keep it simple enough for me. 

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,107 Views

For varying number of like arguments you could use an array constructor

!  max_dummy.f90 
module max_mod
    implicit none
    interface max
        module procedure max_dummy1
        module procedure max_dummy2
        module procedure max_dummyn
    end interface max
contains
    function max_dummy1 (i)
        integer, intent(in) :: i
        integer :: max_dummy1
        max_dummy1 = i
    end function max_dummy1
    function max_dummy2 (i,j)
        integer, intent(in) :: i,j
        integer :: max_dummy2
     if ( i .ge. j ) then
         max_dummy2 = i
     else
      max_dummy2 = j
     endif
    end function max_dummy2
    recursive function max_dummyn (ia)
        integer, intent(in) :: ia(:)
        integer :: max_dummyn
     if( size(ia) .eq. 1 ) then
      max_dummyn = ia(lbound(ia,1))
     else
      max_dummyn = max_dummy2(ia(lbound(ia,1)), max_dummyn(ia(lbound(ia,1)+1:ubound(ia,1))))
        endif
    end function max_dummyn
end module max_mod

program prog2
    use max_mod
    implicit none
    integer :: a
    a = max([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
    write (*, *) 'max of 10 numbers, expecting 10: ', a
end program

Jim Dempsey

0 Kudos
jimdempseyatthecove
Honored Contributor III
2,107 Views

BTW line 30 can also read

 max_dummyn = max(ia(lbound(ia,1)), max(ia(lbound(ia,1)+1:ubound(ia,1))))

Jim Dempsey

0 Kudos
Reply