This is the mail archive of the fortran@gcc.gnu.org mailing list for the GNU Fortran project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Possible bug found handling of elemental overloaded array operations


This is my first attempt at filing a bug report for gfortran, so this seemed like a good place to
start.

I have noticed that elemental overloaded operators do not behave the same as intrinsic operators
when it comes to array assignment. The difference can be seen in the following code snippets:

	subroutine test_member
		type(polar_t),dimension(3)::b

		b = polar_t(1.0,0.5)

		write(*,*) 'test_member'
		write(*,*) b
		b(:) = b(:)/b(1)
		write(*,*) b
		write(*,*) ''
	end subroutine test_member

	subroutine test_real
		real,dimension(3)::b

		b = 2.0

		write(*,*) 'test_real'
		write(*,*) b
		b(:) = b(:)/b(1)
		write(*,*) b
		write(*,*) ''
	end subroutine test_real

The type polar_t is just a reimplementation of a complex number which uses the polar representation 
internally.  The divide operator is overloaded for the type, and the expected result from the first 
subroutine is that of the second; they should both write 3 elements of 'one' in the datatype used.  The 
real subroutine does this, but the polar subroutine only returns 'one' for the first element.  Upon 
experimenting, I found that when changed to the following, the behavior goes away.

	subroutine test_member
		type(polar_t),dimension(3)::b

		b = polar_t(1.0,0.5)

		write(*,*) 'test_member'
		write(*,*) b
		b(:) = b(:)/b(3)
		write(*,*) b
		write(*,*) ''
	end subroutine test_member

This leads me to believe that the first element if b is actually assigned before the second element is 
assigned, which is not the case for real arrays.  I suspect that without array notation what is happening 
in the first test_member subroutine is more like the following:

	subroutine test_member
		type(polar_t),dimension(3)::b
		integer::k
		b = polar_t(1.0,0.5)

		write(*,*) 'test_member'
		write(*,*) b
		do k=1,3
			b(k) = b(k)/b(1)
		end do
		write(*,*) b
		write(*,*) ''
	end subroutine test_member

The behavior should, however be this:

	subroutine test_member
		type(polar_t),dimension(3)::b
		integer::k
		type(polar_t)::temp
		b = polar_t(1.0,0.5)

		write(*,*) 'test_member'
		write(*,*) b
		temp = b(1)
		do k=1,3
			b(k) = b(k)/temp
		end do
		write(*,*) b
		write(*,*) ''
	end subroutine test_member

I have tested the same code using g95 (--version = "G95 (GCC 4.1.2 (g95 0.92!) Jun 18 2009)") and ifort"
(--version = "ifort (IFORT) 11.1 20100203") and they do not suffer from this bug, but rather provide the 
expected result of 'one'.

So I have the following questions:

	1) Does this seem like a bug in gfortran?
	2) If it is, how do I report it, or fix it myself?

I have a good amount of experience in C and Fortran, so I am not afraid of looking for the problem in 
gfortran's source, but I have never worked with the gcc codebase before and understand that it can take 
some getting used to.

I am attaching the source files that I have used to produce these results.

I noticed this behavior on gfortran --version =
"GNU Fortran (Debian 4.4.2-9) 4.4.3 20100108 (prerelease)"

Thank you in advance for your time

Kyle Horne
 program main
	use polar_mod
	implicit none

	call test_member
	call test_other
	call test_scalar

	call test_real
contains

	subroutine test_member
		type(polar_t),dimension(3)::b

		b = polar_t(1.0,0.5)

		write(*,*) 'test_member'
		write(*,*) b
		b(:) = b(:)/b(1)
		write(*,*) b
		write(*,*) ''
	end subroutine test_member

	subroutine test_other
		type(polar_t),dimension(3)::b
		type(polar_t),dimension(3)::c

		b = polar_t(1.0,0.5)
		c = polar_t(1.0,0.5)

		write(*,*) 'test_other'
		write(*,*) b
		b(:) = b(:)/c(1)
		write(*,*) b
		write(*,*) ''
	end subroutine test_other

	subroutine test_scalar
		type(polar_t),dimension(3)::b
		type(polar_t)::c

		b = polar_t(1.0,0.5)
		c = b(1)

		write(*,*) 'test_scalar'
		write(*,*) b
		b(:) = b(:)/c
		write(*,*) b
		write(*,*) ''
	end subroutine test_scalar

	subroutine test_real
		real,dimension(3)::b

		b = 2.0

		write(*,*) 'test_real'
		write(*,*) b
		b(:) = b(:)/b(1)
		write(*,*) b
		write(*,*) ''
	end subroutine test_real
end program main
module polar_mod
	implicit none

	complex,parameter::i = (0.0,1.0)
	real,parameter::pi = 3.14159265359
	real,parameter::e = exp(1.0)

	type::polar_t
		real::l,th
	end type

	interface operator(+)
		module procedure add_pp
	end interface

	interface operator(-)
		module procedure sub_pp
	end interface

	interface operator(*)
		module procedure mul_pp
	end interface

	interface operator(/)
		module procedure div_pp
	end interface

contains

	elemental function add_pp(u,v) result(o)
		type(polar_t),intent(in)::u,v
		type(polar_t)::o

		complex::a,b,c

		a = u%l*exp(i*u%th*pi)
		b = v%l*exp(i*v%th*pi)

		c = a+b

		o%l = abs(c)
		o%th = atan2(imag(c),real(c))/pi
	end function add_pp

	elemental function sub_pp(u,v) result(o)
		type(polar_t),intent(in)::u,v
		type(polar_t)::o

		complex::a,b,c

		a = u%l*exp(i*u%th*pi)
		b = v%l*exp(i*v%th*pi)

		c = a-b

		o%l = abs(c)
		o%th = atan2(imag(c),real(c))/pi
	end function sub_pp

	elemental function mul_pp(u,v) result(o)
		type(polar_t),intent(in)::u,v
		type(polar_t)::o

		complex::a,b,c

		a = u%l*exp(i*u%th*pi)
		b = v%l*exp(i*v%th*pi)

		c = a*b

		o%l = abs(c)
		o%th = atan2(imag(c),real(c))/pi
	end function mul_pp

	elemental function div_pp(u,v) result(o)
		type(polar_t),intent(in)::u,v
		type(polar_t)::o

		complex::a,b,c

		a = u%l*exp(i*u%th*pi)
		b = v%l*exp(i*v%th*pi)

		c = a/b

		o%l = abs(c)
		o%th = atan2(imag(c),real(c))/pi
	end function div_pp
end module polar_mod

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]