Bug or undefined behaviour in passing zero-sized arrays as optional argument?

Here’s a little toy example:

  subroutine print_present(opt, name)
    implicit none
    real, intent(in), dimension(:), optional :: opt
    character(len=*), intent(in) :: name
    print*,name, present(opt)
  end subroutine print_present

Passing a zero-sized array seems to result in what looks like either undefined behaviour or a bug:

call print_present([real::], "Literal zero-sized array")

Gfortran mostly says this is not present, but sometimes it does evaluate to true. Intel seems to always evaluate to true.

Passing an unallocated array does seem to always evaluate to false, on both gfortran and Intel compilers. Passing an allocatable array that’s zero-sized does seem to evaluate to true for both compilers. It seems to only be zero-sized literal arrays and unallocated arrays that have issues.

Here’s a godbolt reproducer to have a play around with:

Does anybody know what the standard says here? This definitely feels like a bug to me.

1 Like

Looks like a gfortran bug. According to the F2018 standard interpretation document (J3/18-007r1), section 15.5.2.12 it should be “present”, no matter whether zero or non-zero sized.

Interestingly (regarding your snippet on goldbolt.org), the presence of an unallocated array being passed as an optional argument depends on whether the dummy optional arg has allocatable attribute. If it does have it, the argument is considered as present, otherwise non-present.

program main

  real, allocatable :: t(:)
  print *, allocated(t)
  call print_present("Unallocated, allocatable dummy", opt1=t)
  call print_present("Unallocated", opt2=t)
  
  contains

    subroutine print_present(name, opt1, opt2)
      implicit none
      real, intent(in), dimension(:), allocatable, optional :: opt1
      real, intent(in), dimension(:), optional :: opt2
      character(len=*), intent(in) :: name
      print*,name, present(opt1), present(opt2)
    end subroutine print_present

end program main

gives

 F
 Unallocated, allocatable dummy T F
 Unallocated F F

consistently both in gfortran and ifort.

Please see the thread An unallocated variable passed as an argument is not PRESENT .

Well that is a bit of a pain with the unallocated variables, because it also means type information is not passed along, or you need another overload to make the dummy argument allocatable. I’m not sure that that is a good feature.

Looks like the zero-sized literal is definitely a bug though, thanks! I’ll report it to gfortran.