Skip to content

Type with allocatables

Types with allocatables are handled differently by compilers when using OpenACC. In C this would be equivalent to a struct with a pointer inside. According to the OpenACC specification it should not be possbile to write a type with allocatables to the gpu in one go. However, we noticed that it worked sometimes and thus we have listed the differences here

OpenACC 3.3 section 2.6.4
When a data object is copied to device memory, the values are copied exactly. If the data is a data
structure that includes a pointer, or is just a pointer, the pointer value copied to device memory
will be the host pointer value. If the pointer target object is also allocated in or copied to device
memory, the pointer itself needs to be updated with the device address of the target object before
dereferencing the pointer in device memory

In the tables below, the Correctness column states whether each compiler's observed behaviour conforms to the OpenACC specification.

Container with "declare create"

Code
program main
  implicit none
  type container_type
      real, dimension(:), allocatable :: values
  end type

  real, dimension(:) :: host_mem(2) = (/4,2/), res(2)
  integer :: i

  type(container_type) :: container
  !$acc declare create(container)

  allocate(container%values(2))
  container%values = host_mem

  write(*,*) "Checking if allocatable values are copied to device after declare create ..."
  !$acc parallel loop 
  do i=1,2 
    res(i) = container%values(i)
  enddo
  write(*,*) "Success", res
end program
Compiler Result Correctness Notes
Cray Fortran 19.0.0 ❌ Crash Per spec — copying the container does not attach values Compiler warning (Variable "(?)" is used before it is defined); memory access fault at runtime.
nvfortran 25.3-0 ❌ Crash Per spec — copying the container does not attach values No warning; CUDA_ERROR_ILLEGAL_ADDRESS at runtime.

Container with "enter data"

Code with local variable
program main
  use openacc
  implicit none
  type container_type
      real, dimension(:), allocatable :: values
  end type

  real, dimension(:) :: host_mem(2) = (/4,2/), res(2)
  integer :: i

  type(container_type) :: container
  !$acc enter data create(container)

  allocate(container%values(2))
  container%values = host_mem

  write(*,*) "Checking if allocatable values are copied to device after enter data create ..."
  !$acc parallel loop 
  do i=1,2 
    res(i) = container%values(i)
  enddo
  write(*,*) "Success", res
end program
Compiler Result Correctness Notes
Cray Fortran 19.0.0 ❌ Crash Per spec — values is never attached Memory access fault at runtime.
nvfortran 25.3-0 ✅ OK Not per spec — relies on a non-portable automatic deep copy Prints Success 4.000000 2.000000.
Code with module variable
module static
  type container_type
      real, dimension(:), allocatable :: values
  end type

  type(container_type) :: container
end module

program main
  use static, only: container
  implicit none

  real, dimension(:) :: host_mem(2) = (/4,2/), res(2)
  integer :: i

  !$acc enter data create(container)

  allocate(container%values(2))
  container%values = host_mem

  write(*,*) "Checking if allocatable values are copied to device after enter data create of a module variable ..."
  !$acc parallel loop 
  do i=1,2 
    res(i) = container%values(i)
  enddo
  write(*,*) "Success", res
end program
Compiler Result Correctness Notes
Cray Fortran 19.0.0 ❌ Crash Per spec — values is never attached Memory access fault at runtime.
nvfortran 25.3-0 🟡 Wrong result Not per spec — relies on a non-portable automatic deep copy Prints Success 4.000000 0.000000; the second element should be 2.0. The module variable case silently produces an incorrect value.
Code with enter data for member variable
program main
  use openacc
  implicit none
  type container_type
      real, dimension(:), allocatable :: values
  end type

  real, dimension(:) :: host_mem(2) = (/4,2/), res(2)
  integer :: i

  type(container_type) :: container
  !$acc enter data create(container)

  allocate(container%values(2))
  !$acc enter data create(container%values)
  container%values = host_mem
  !$acc update device(container%values)

  write(*,*) "Checking if allocatable values are copied to device after enter data create ..."
  !$acc parallel loop 
  do i=1,2 
    res(i) = container%values(i)
  enddo
  write(*,*) "Success", res
end program
Compiler Result Correctness Notes
Cray Fortran 19.0.0 ✅ OK Per spec — values is allocated, explicitly attached, and copied with update device Prints Success 4. 2. (correct).
nvfortran 25.3-0 ✅ OK Per spec — values is allocated, explicitly attached, and copied with update device Prints Success 4.000000 2.000000 (correct).

Container with no data/declare statement

Code
program main
  implicit none
  type pointer_type
      real, dimension(:), allocatable :: values
  end type
  real, dimension(:) :: host_mem(2) = (/4,2/), res(2)
  integer :: i
  type(pointer_type) :: indirect
  allocate(indirect%values(2))

  indirect%values = host_mem

  write(*,*) "Checking if allocatable values are copied to device with !$acc parallel loop ..."
  !$acc parallel loop
  do i=1,2 
    res(i) = indirect%values(i)
  enddo
  write(*,*) "Success", res

end program
Compiler Result Correctness Notes
Cray Fortran 19.0.0 ❌ Crash Per spec — values is never attached No warning at compile time; memory access fault at runtime.
nvfortran 25.3-0 ✅ OK Not per spec — relies on a non-portable automatic deep copy Prints Success 4.000000 2.000000.