Dear great Intel Fortran Developers team,
I would like to report a possible bug in ifort 15.0.3.
I am trying to develop an OOP library that takes advantage of Abstract Calculus Pattern by means of an abstract type definition. In a very few words, the library defines an abstract type with some operators overloading deferred and it provides a procedure that operates on the abstract type. The concrete extensions of the abstract type implement only the type bound procedures deferred whereas the overloaded operators are defined by the abstract type. The real code is here https://github.com/Fortran-FOSS-Programmers/FOODiE/blob/master/src/lib/type_integrand.f90.
A minimal example raising the possible bug is reported below. There are 3 modules and 1 main program: 1) type_abstract_buggy provides the abstract type, 2) lib_abstract_buggy provides a procedure working on the abstract type that raises the possible bug, 3) type_buggy implements a concrete extension of the abstract type defining only the procedures for the operators overloading and 4) is the main program using the last 2 modules.
The expected results are:
Array:
1.00000000
2.00000000
3.00000000
Scalar: 3
Array:
2.00000000
4.00000000
6.00000000
Scalar: 3
Array:
4.00000000
8.00000000
12.0000000
Scalar: 3
but when compiling with ifort 15.0.3 complains with following errors.
ifort-bug.f90(58): error #6633: The type of the actual argument differs from the type of the dum
my argument. [BUG]
bug = scalar * bug
-----------------^
ifort-bug.f90(146): error #7013: This module file was not generated by any release of this compi
ler. [LIB_ABSTRACT_BUGGY]
use lib_abstract_buggy, only : raise_bug
----^
ifort-bug.f90(149): error #6457: This derived type name has not been declared. [BUGGY]
type(buggy) :: bug
-----^
ifort-bug.f90(151): error #6404: This name does not have a type, and must have an explicit type.
[BUG]
bug = buggy(array=[1., 2., 3.], scalar=3)
^
ifort-bug.f90(151): error #6632: Keyword arguments are invalid without an explicit interface.
[ARRAY]
bug = buggy(array=[1., 2., 3.], scalar=3)
------------^
ifort-bug.f90(151): error #6632: Keyword arguments are invalid without an explicit interface.
[SCALAR]
bug = buggy(array=[1., 2., 3.], scalar=3)
--------------------------------^
ifort-bug.f90(152): error #6406: Conflicting attributes or multiple declaration of name. [RAIS
E_BUG]
call raise_bug(bug=bug, scalar=2)
-----^
ifort-bug.f90(146): error #6580: Name in only-list does not exist. [RAISE_BUG]
use lib_abstract_buggy, only : raise_bug
-------------------------------^
ifort-bug.f90(147): error #6580: Name in only-list does not exist. [BUGGY]
use type_buggy, only : buggy
-----------------------^
compilation aborted for ifort-bug.f90 (code 1)
The compilation is done by: ifort -O0 -debug all -check all -warn all -traceback -assume realloc_lhs -std08 ifort-bug.f90
Note that the correct result is obtained by GNU gfortran 5.2.
Minimal example raising the possible compiler bug
module type_abstract_buggy
implicit none
private
public :: abstract_buggy
type, abstract :: abstract_buggy
contains
! public methods
procedure(abstract_printf), public, deferred :: printf
generic, public :: operator(*) => buggy_multiply_scalar, scalar_multiply_buggy
generic, public :: assignment(=) => buggy_assign_buggy
! private methods
procedure(abstract_buggy_multiply_scalar), pass(lhs), private, deferred :: buggy_multiply_scalar
procedure(scalar_multiply_abstract_buggy), pass(rhs), private, deferred :: scalar_multiply_buggy
procedure(abstract_buggy_assign_abstract_buggy), pass(lhs), private, deferred :: buggy_assign_buggy
endtype abstract_buggy
abstract interface
subroutine abstract_printf(self)
import :: abstract_buggy
class(abstract_buggy), intent(IN) :: self
endsubroutine abstract_printf
function abstract_buggy_multiply_scalar(lhs, rhs) result(multy)
import :: abstract_buggy
class(abstract_buggy), intent(IN) :: lhs
integer, intent(IN) :: rhs
class(abstract_buggy), allocatable :: multy
endfunction abstract_buggy_multiply_scalar
function scalar_multiply_abstract_buggy(lhs, rhs) result(multy)
import :: abstract_buggy
integer, intent(IN) :: lhs
class(abstract_buggy), intent(IN) :: rhs
class(abstract_buggy), allocatable :: multy
endfunction scalar_multiply_abstract_buggy
pure subroutine abstract_buggy_assign_abstract_buggy(lhs, rhs)
import :: abstract_buggy
class(abstract_buggy), intent(INOUT) :: lhs
class(abstract_buggy), intent(IN) :: rhs
endsubroutine abstract_buggy_assign_abstract_buggy
endinterface
endmodule type_abstract_buggy
module lib_abstract_buggy
use type_abstract_buggy, only : abstract_buggy
implicit none
private
public :: raise_bug
contains
subroutine raise_bug(bug, scalar)
class(abstract_buggy), intent(INOUT) :: bug
integer, intent(IN) :: scalar
call bug%printf()
bug = bug * scalar
call bug%printf()
bug = scalar * bug
call bug%printf()
endsubroutine raise_bug
endmodule lib_abstract_buggy
module type_buggy
use type_abstract_buggy, only : abstract_buggy
implicit none
private
public :: buggy
type, extends(abstract_buggy) :: buggy
private
real, dimension(:), allocatable :: array
integer :: scalar=0
contains
! public methods
procedure, pass(self), public :: printf
! private methods
procedure, pass(lhs), private :: buggy_multiply_scalar
procedure, pass(rhs), private :: scalar_multiply_buggy
procedure, pass(lhs), private :: buggy_assign_buggy
endtype buggy
interface buggy
procedure create_buggy
endinterface
contains
pure function create_buggy(array, scalar) result(bug)
real, dimension(:), intent(IN) :: array
integer, intent(IN) :: scalar
type(buggy) :: bug
bug%array = array
bug%scalar = scalar
return
endfunction create_buggy
subroutine printf(self)
class(buggy), intent(IN) :: self
integer :: i
print "(A)", "Array:"
do i=1, size(self%array)
print*, self%array(i)
enddo
print "(A,I5)", "Scalar: ", self%scalar
endsubroutine printf
function buggy_multiply_scalar(lhs, rhs) result(multy)
class(buggy), intent(IN) :: lhs
integer, intent(IN) :: rhs
class(abstract_buggy), allocatable :: multy
type(buggy), allocatable :: multy_tmp
allocate(buggy :: multy_tmp)
multy_tmp%array = lhs%array * rhs
multy_tmp%scalar = lhs%scalar
call move_alloc(multy_tmp, multy)
return
endfunction buggy_multiply_scalar
pure function scalar_multiply_buggy(lhs, rhs) result(multy)
integer, intent(IN) :: lhs
class(buggy), intent(IN) :: rhs
class(abstract_buggy), allocatable :: multy
type(buggy), allocatable :: multy_tmp
allocate(buggy :: multy_tmp)
multy_tmp%array = rhs%array * lhs
multy_tmp%scalar = rhs%scalar
call move_alloc(multy_tmp, multy)
return
endfunction scalar_multiply_buggy
pure subroutine buggy_assign_buggy(lhs, rhs)
class(buggy), intent(INOUT) :: lhs
class(abstract_buggy), intent(IN) :: rhs
select type(rhs)
class is(buggy)
if (allocated(rhs%array)) lhs%array = rhs%array
lhs%scalar = rhs%scalar
endselect
return
endsubroutine buggy_assign_buggy
endmodule type_buggy
program ifort_bug
use lib_abstract_buggy, only : raise_bug
use type_buggy, only : buggy
implicit none
type(buggy) :: bug
bug = buggy(array=[1., 2., 3.], scalar=3)
call raise_bug(bug=bug, scalar=2)
stop
endprogram ifort_bug