Description
Description
A runtime error occurs when assigning bitset_large
type variables to oneself. Such a situation arises when extending stdlib_sorting
to support sorting arrays of bitset_large
type. The error message is Fortran runtime error: Allocatable argument 'set2' is not allocated
. set2
is defined in the procedure assign_large
as the variable on the right-hand side of the assignment operator.
This phenomenon can be reproduced with the following code.
program main
use, intrinsic :: iso_fortran_env
use :: stdlib_bitsets
implicit none
type(bitset_large) :: bitsetl(0:16**3 - 1)
integer(int32) :: i
character(32) :: bin
do i = 0, size(bitsetl, kind=int32) - 1
write (bin, '(b32.32)') i
call bitsetl(i)%from_string(bin)
end do
bitsetl(0) = bitsetl(0)
end program main
The details are described in the Additional Information section. For simplicity, gfortran 11.2.0 was used as the compiler, and -Wall -Wextra -Wimplicit-interface -fPIC -g -fcheck=all -fbacktrace
was used as the compile option. The options are specified in the actions defined in ci_windows.yml.
Expected Behaviour
I expected the bitsetl(0)
value to remain unchanged in the above code.
Version of stdlib
Platform and Architecture
Windows 10 22H2 64bit, gfortran 11.2 bundled with quickstart Fortran on Windows
Additional Information
Here I describe how I identified the issue.
The directory structure was
D:\
├─bitset_test
└─stdlib
Cloned stdlib and built it with compiler options used in the actions defined in ci_windows.yml.
D:\>git clone https://github.com/fortran-lang/stdlib.git
D:\>cd stdlib
D:\stdlib>cmake -Wdev -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_Fortran_FLAGS_DEBUG="-Wall -Wextra -Wimplicit-interface -fPIC -g -fcheck=all -fbacktrace" -DCMAKE_MAXIMUM_RANK:String=4 -DCMAKE_Fortran_COMPILER=gfortran -G "Unix Makefiles"
D:\stdlib>cmake --build build
Then install it in the bitset_test
directory.
D:\stdlib>cmake --install build --prefix ../bitset_test
D:\stdlib>cd ..\bitset_test
In the bitset_test
directory, I compiled main.f90
using gfortran. The main.f90
is shown the Description section.
>gfortran main.f90 -Wall -Wextra -Wimplicit-interface -fPIC -g -fcheck=all -fbacktrace -Iinclude\fortran_stdlib\GNU-11.2.0 -Llib -lfortran_stdlib
When running the generated executable file a.exe
, a runtime error occurred, and the error message was displayed:
D:\bitset_test>a
At line 97 of file D:/stdlib/build/src/stdlib_bitsets_large.f90
Fortran runtime error: Allocatable argument 'set2' is not allocated
Error termination. Backtrace:
Could not print backtrace: libbacktrace could not find executable to open
...
The line specified by the message is in the procedure assign_large
that performs the assignment operation of bitset_large
type.
pure module subroutine assign_large( set1, set2 )
! Used to define assignment for bitset_large
type(bitset_large), intent(out) :: set1
type(bitset_large), intent(in) :: set2
set1 % num_bits = set2 % num_bits
allocate( set1 % blocks( size( set2 % blocks, kind=bits_kind ) ) )
set1 % blocks(:) = set2 % blocks(:)
end subroutine assign_large
The error may be due to the deallocation of the component blocks
of set2
caused by the intent(out)
attribute for set1
since set1
and set2
are the same variable.
I changed the attribute of set1
, the argument specifying the left-hand side of the assignment operator, from out
to inout
and re-run the executable again, followed by the above procedures. An error still occurred, but the message has changed to Attempting to allocate already allocated variable 'set1'
.
D:\bitset_test>a
At line 97 of file D:/stdlib/build/src/stdlib_bitsets_large.f90
Fortran runtime error: Attempting to allocate already allocated variable 'set1'
Error termination. Backtrace:
Could not print backtrace: libbacktrace could not find executable to open
...
Since the same variables are specified on both sides of the assignment operator, it is natural that the variable on the left side is already allocated. But no error should occur in this situation.
The solutions I am trying to are:
- change the intent of
set1
fromout
toinout
and use the automatic array allocation for the componentblocks
:
set1 % num_bits = set2 % num_bits
- allocate( set1 % blocks( size( set2 % blocks, kind=bits_kind ) ) )
- set1 % blocks(:) = set2 % blocks(:)
+ set1 % blocks = set2 % blocks(:)
- Or eliminate the user-defined assignment procedure and use Fortran's intrinsic assignment operation of use-defined type.