Strange result with polymorphic variables
Arjen Markus
arjen.markus895@gmail.com
Mon Aug 29 11:43:00 GMT 2011
Hi Janus,
thanks for looking into this. I will try and reduce to something smaller.
By the way, I used no particular flags.
Regards,
Arjen
2011/8/29 Janus Weil <janus@gcc.gnu.org>:
> Hi Arjen,
>
>> the program below produces the following unexpected result:
>
> well, for me the program you posted directly produces a segfault with
> all gfortran versions I tried (4.5-4.7):
>
>
> jweil@manzanita:~/fort> gfortran-4.7 -fcheck=all -Wall -g3 -O0 random_walk.f90
> jweil@manzanita:~/fort> ./a.out
> Two-dimensional walk:
>
> Backtrace for this error:
> #0 /usr/lib64/libgfortran.so.3(+0x1ab67)[0x7f75c305fb67]
> #1 /usr/lib64/libgfortran.so.3(+0x1b52f)[0x7f75c306052f]
> #2 /lib64/libc.so.6(+0x32b30)[0x7f75c2667b30]
> #3 /lib64/libc.so.6(cfree+0x19)[0x7f75c26ad289]
> #4 /home/jweil/fort/a.out[0x400C00] in
> __points2d3d_MOD_scale_by_factor_2d at random_walk.f90:139
> #5 /home/jweil/fort/a.out[0x401835] in random_walk at random_walk.f90:207
>
>
> Line 139 is the DEALLOCATE statement in scale_by_factor_2d. However,
> since this is guarded by an ALLOCATED(...), it does not really look
> like a user error, but more like a compiler bug. I think it would be
> helpful to reduce the program a bit, in order to nail down the error.
>
> Cheers,
> Janus
>
>
>
>
>> ------------
>> ! random_walk.f90 --
>> ! Simulate a random walk in two and three dimensions
>> !
>> module points2d3d
>>
>> implicit none
>>
>> type point2d
>> real :: x, y
>> contains
>> procedure :: print => print_2d
>> procedure :: random_vector => random_vector_2d
>> procedure :: add_vector => add_vector_2d
>> procedure, pass(vector) :: scale_by_factor => scale_by_factor_2d
>> procedure :: assign => assign_2d
>> generic :: operator(+) => add_vector
>> generic :: operator(*) => scale_by_factor
>> generic :: assignment(=) => assign
>> end type point2d
>>
>> type, extends(point2d) :: point3d
>> real :: z
>> contains
>> procedure :: print => print_3d
>> procedure :: random_vector => random_vector_3d
>> procedure :: add_vector => add_vector_3d
>> procedure, pass(vector) :: scale_by_factor => scale_by_factor_3d
>> procedure :: assign => assign_3d
>> end type point3d
>>
>> contains
>>
>> !
>> ! Auxiliary routine to convert from class to point
>> !
>> subroutine assign_2d( point1, point2 )
>> class(point2d), intent(inout) :: point1
>> class(point2d), intent(in) :: point2
>>
>> point1%x = point2%x
>> point1%y = point2%y
>>
>> end subroutine assign_2d
>>
>> subroutine assign_3d( point1, point2 )
>> class(point3d), intent(inout) :: point1
>> class(point2d), intent(in) :: point2
>>
>> point1%x = point2%x
>> point1%y = point2%y
>> point1%z = 0.0
>>
>> select type (point2)
>> class is (point3d)
>> point1%z = point2%z
>> end select
>>
>> end subroutine assign_3d
>>
>> subroutine print_2d( point )
>> class(point2d) :: point
>>
>> write(*,'(2f10.4)') point%x, point%y
>> end subroutine print_2d
>>
>> subroutine print_3d( point )
>> class(point3d) :: point
>>
>> write(*,'(3f10.4)') point%x, point%y, point%z
>> end subroutine print_3d
>>
>> subroutine random_vector_2d( point )
>> class(point2d) :: point
>>
>> call random_number( point%x )
>> call random_number( point%y )
>>
>> point%x = 2.0 * (point%x - 0.5)
>> point%y = 2.0 * (point%y - 0.5)
>>
>> end subroutine random_vector_2d
>>
>> subroutine random_vector_3d( point )
>> class(point3d) :: point
>>
>> call point%point2d%random_vector
>> call random_number( point%z )
>>
>> point%z = 2.0 * (point%z - 0.5)
>>
>> end subroutine random_vector_3d
>>
>> function add_vector_2d( point, vector )
>> class(point2d), intent(in) :: point, vector
>> class(point2d), allocatable :: add_vector_2d
>>
>> ! Workaround for gfortran 4.6
>> if ( allocated( add_vector_2d ) ) then
>> deallocate( add_vector_2d )
>> endif
>>
>> allocate( add_vector_2d )
>> add_vector_2d%x = point%x + vector%x
>> add_vector_2d%y = point%y + vector%y
>>
>> end function add_vector_2d
>>
>> function add_vector_3d( point, vector )
>> class(point3d), intent(in) :: point
>> class(point2d), intent(in) :: vector
>>
>> class(point2d), allocatable :: add_vector_3d
>> class(point3d), allocatable :: add_result
>>
>> allocate( add_result )
>>
>> select type (vector)
>> class is (point3d)
>> !add_result%point2d = point%point2d + vector%point2d
>> add_result%point2d = point%point2d%add_vector( vector%point2d )
>> add_result%z = point%z + vector%z
>>
>> class default
>> add_result%point2d = point%point2d + vector
>> add_result%z = 0.0
>> end select
>>
>> call move_alloc( add_result, add_vector_3d )
>>
>> end function add_vector_3d
>>
>> function scale_by_factor_2d( factor, vector )
>> real, intent(in) :: factor
>> class(point2d), intent(in) :: vector
>> class(point2d), allocatable :: scale_by_factor_2d
>>
>> ! Workaround for gfortran 4.6
>> if ( allocated( scale_by_factor_2d ) ) then
>> deallocate( scale_by_factor_2d )
>> endif
>>
>> allocate( scale_by_factor_2d )
>>
>> scale_by_factor_2d%x = factor * vector%x
>> scale_by_factor_2d%y = factor * vector%y
>>
>> end function scale_by_factor_2d
>>
>> function scale_by_factor_3d( factor, vector )
>> real, intent(in) :: factor
>> class(point3d), intent(in) :: vector
>>
>> class(point2d), allocatable :: scale_by_factor_3d
>> class(point3d), allocatable :: scale_result
>>
>> allocate( scale_result )
>>
>> scale_result%point2d = factor * vector%point2d
>> scale_result%z = factor * vector%z
>>
>> call move_alloc( scale_result, scale_by_factor_3d )
>>
>> end function scale_by_factor_3d
>>
>> end module points2d3d
>>
>> program random_walk
>>
>> use points2d3d ! Both 2D and 3D points available
>>
>> type(point2d), target :: point_2d
>> type(point3d), target :: point_3d
>> type(point2d), target :: vector_2d
>> type(point3d), target :: vector_3d
>>
>> !
>> ! A variable of class point2d can point to point_2d but
>> ! also to point_3d
>> !
>> class(point2d), pointer :: point
>> class(point2d), pointer :: vector
>>
>> integer :: nsteps = 10
>> integer :: i
>> integer :: trial
>> real :: deltt = 0.1
>>
>> do trial = 1,2
>>
>> ! Select what type of point ...
>>
>> if ( trial == 1 ) then
>> point => point_2d
>> vector => vector_2d
>> write(*,*) 'Two-dimensional walk:'
>> else
>> point => point_3d
>> vector => vector_3d
>> write(*,*) 'Three-dimensional walk:'
>> endif
>>
>> call point%random_vector
>>
>> do i = 1,nsteps
>> call vector%random_vector
>>
>> point = point + deltt * vector
>>
>> call point%print
>> enddo
>> enddo
>> end program random_walk
>>
>
More information about the Fortran
mailing list