module my_ModC
  use, intrinsic :: iso_fortran_env, only: int32, int64
  use iso_fortran_env, only: output_unit

  private
  public :: ModC

  type :: ModC
    integer(int32), allocatable :: first_arr(:)
    integer(int32), pointer :: first_ptr(:) => null()

    contains
      procedure, public :: run
      procedure, private :: set_ptr

  end type

  interface ModC
    !! ModC constructor
    module procedure :: constructor_ModC_1
  end interface

  contains
    function constructor_ModC_1() result(this)
      implicit none
      type(ModC) :: this

      integer(int64) :: addr

      write(output_unit, *) '---- in ModC%constructor() ----'

      allocate(this%first_arr(1000))
      this%first_arr = 0

      addr = loc(this%first_arr)
      write(output_unit, *) '  this%first_arr address: ', addr

      call this%set_ptr(this%first_arr)
      write(output_unit, *) '  ---- after ModC%set_ptr() call ----'
      addr = loc(this%first_ptr)
      write(output_unit, *) '  this%first_ptr address: ', addr
    end function

    subroutine run(this)
      implicit none

      class(ModC), intent(inout) :: this

      integer(int64) :: addr

      write(output_unit, *) '---- in ModC%run() ----'
      addr = loc(this%first_arr)
      write(output_unit, *) '  this%first_arr address: ', addr

      write(output_unit, *) '  this%first_arr(1:20):'
      write(output_unit, *) this%first_arr(1:20)

      write(output_unit, *) '  this%first_ptr(1:20):'
      write(output_unit, *) this%first_ptr(1:20)

      write(output_unit, *) '  Update this%first_arr(1:20) = 100'
      this%first_arr(1:20) = 100

      write(output_unit, *) '  this%first_arr(1:20):'
      write(output_unit, *) this%first_arr(1:20)

      write(output_unit, *) '  this%first_ptr(1:20):'
      write(output_unit, *) this%first_ptr(1:20)
    end subroutine

    subroutine set_ptr(this, arr)
      class(ModC), intent(inout) :: this
      integer(int32), target, intent(in) :: arr(:)

      integer(int64) :: addr

      write(output_unit, *) '  ---- in ModC%set_ptr() ----'
      addr = loc(arr)
      write(output_unit, *) '    arr address: ', addr
      this%first_ptr => arr

      addr = loc(this%first_ptr)
      write(output_unit, *) '    this%first_ptr address: ', addr
    end subroutine
end module


! For ifort the compile flags are:
!     -g -stand f08 -O0 -g -traceback -debug extended -check all -warn all -nostandard-realloc-lhs
! For gfortran the compile flags are:
!     -std=f2008 -ffree-line-length-none -fno-common -fall-intrinsics -fno-underscoring -g -pg -fbacktrace -fcheck=all -Wall

program myMain
  use, intrinsic :: iso_fortran_env, only: int32, int64
  use iso_fortran_env, only: output_unit
  use my_ModC, only: ModC
  implicit none

  type(ModC) :: module_c

  integer(int64) :: addr

  module_c = ModC()

  addr = loc(module_c%first_arr)
  write(output_unit, *) '---- back in main program ----'
  write(output_unit, *) '  module_c%first_arr after init(): ', addr
  write(output_unit, *) '  module_c%first_arr is allocated: ', allocated(module_c%first_arr)

  call module_c%run()
end program