wavebitscientific / datetime-fortran

Date and time manipulation for modern Fortran
MIT License
137 stars 50 forks source link

User-defined constructor issues with Intel Fortran #39

Closed milancurcic closed 4 years ago

milancurcic commented 8 years ago

Noticed this behavior some time ago but haven't had the chance to look deeper into it. Currently, the datetime-fortran builds and passes tests when built with gfortran (here with 5.2.0 but I think 4.9 and later should work):

FC=gfortran ./configure
make check

However with ifort (15.0.0 here, same behavior with 16.0.0):

FC=ifort ./configure
make check

The library itself builds successfully but building tests fails with a lot of errors. First few are:

ifort -c -g -I../lib datetime_tests.f90
datetime_tests.f90(155): error #6355: This binary operation is invalid for this data type.
  tests(n) = assert(datetime() == datetime(1,1,1),&
--------------------^
datetime_tests.f90(155): error #6355: This binary operation is invalid for this data type.
  tests(n) = assert(datetime() == datetime(1,1,1),&
----------------------------------^

It looks like ifort does not recognize the == operator for datetime types (overloaded by function eq in mod_datetime.f90). Why not? I tried to minimize the error-reproducing test code:

use datetime_module,only:datetime

implicit none

type(datetime) :: a,b

a = datetime()
write(*,*)a % isoformat()

b = datetime(1,1,1)
write(*,*)b % isoformat()

! This compiles and works with both gfortran and ifort:
write(*,*)a == b

! This compiles and works with gfortran; does not compile with ifort:
write(*,*)datetime() == datetime(1,1,1)

end

See, if I first assign datetime instances to variables a and b, then ifort knows how to make the a == b comparison. But somehow, it cannot do it "on the fly", i.e. datetime() == datetime(1,1,1). To test this, I make the minimal example in which I define a simple type, overload it's constructor with a function, and overload the == operator with the function eq:

module test
implicit none

type :: mytype

  private
  integer :: a

  contains

  procedure,private :: eq
  generic :: operator(==) => eq

endtype mytype

interface mytype
  module procedure :: mytype_constructor
endinterface mytype

contains

type(mytype) function mytype_constructor(a)
  integer,intent(in),optional :: a
  if(present(a))then
    mytype_constructor % a = a
  else
    mytype_constructor % a = 0
  endif
endfunction mytype_constructor

logical function eq(m0,m1)
  class(mytype),intent(in) :: m0,m1
  eq = m0 % a == m1 % a
endfunction eq

endmodule test

program testprog
use test
implicit none 

write(*,*)mytype() == mytype(0)

endprogram testprog

However, this minimal example works with ifort, and mytype() == mytype(0) evaluates as expected. So perhaps this is not the issue, but something else is. What am I missing?

Thanks!!

milancurcic commented 8 years ago

It seems that replacing the specific use statements from the parent module, i.e.:

use mod_datetime, only:datetime,date2num,datetimeRange,daysInMonth,&
                       daysInYear,isLeapYear,num2date,strptime,tm2date
use mod_timedelta,only:timedelta
use mod_clock,    only:clock
use mod_strftime, only:tm_struct,c_strftime,c_strptime

with the general all-inclusive statements like:

use mod_datetime
use mod_timedelta
use mod_clock
use mod_strftime

makes ifort not complain anymore about binary operators not being defined. So, for some reason, when importing the datetime type from mod_datetime, ifort is unable to import the overloaded operators as well. I do not understand why. Happens with both v16 and v17. gfortran reports no issue at all. for the time being, will use the all-inclusive use statements because ifort needs them.

I am still not able to reproduce this behavior with a simpler example. Stay tuned.

milancurcic commented 8 years ago

The above issue can be reproduced with the following example:

module mymod
implicit none

type :: mytype
  private
  integer :: a
  contains
  procedure,private :: eq
  generic :: operator(==) => eq
endtype mytype

interface mytype
  module procedure :: constructor
endinterface mytype

contains

type(mytype) function constructor(a)
  integer,intent(in),optional :: a
  if(present(a))then
    constructor % a = a
  else
    constructor % a = 0
  endif
endfunction constructor

logical function eq(m0,m1)
  class(mytype),intent(in) :: m0
  class(mytype),intent(in) :: m1
  eq = m0 % a == m1 % a
endfunction eq

endmodule mymod

module wrapper_module
use mymod,only:mytype
endmodule wrapper_module

program test
use wrapper_module
implicit none

write(*,*)mytype() == mytype(0)

endprogram test

The code compiles and executes as expected if only:mytype is omitted from the use statement in the wrapper_module, but not otherwise. Filed this on Intel Fortran forums, currently pending.

zbeekman commented 8 years ago

Filed this on Intel Fortran forums, currently pending.

Link?

milancurcic commented 8 years ago

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

milancurcic commented 5 years ago

The issue remains as of 19.0.1.144 Build 20181018 on 64-bit Linux.

milancurcic commented 4 years ago

This issue should be resolved thanks to switching to single-module library in #69. Needs to be confirmed.

milancurcic commented 4 years ago

No issue with ifort 2021.1 Beta 20200602. Closing.