! { dg-do compile }
!
! PR fortran/45125
!
! Contributed by Salvatore Filippone and Dominique d'Humieres.
!

module const_mod
  ! This is the default integer
  integer, parameter  :: ndig=8
  integer, parameter  :: int_k_ = selected_int_kind(ndig)
  ! This is an 8-byte  integer, and normally different from default integer. 
  integer, parameter  :: longndig=12
  integer, parameter  :: long_int_k_ = selected_int_kind(longndig)
  !
  ! These must be the kind parameter corresponding to MPI_DOUBLE_PRECISION
  ! and MPI_REAL
  !
  integer, parameter  :: dpk_ = kind(1.d0)
  integer, parameter  :: spk_ = kind(1.e0)
  integer, save       :: sizeof_dp, sizeof_sp
  integer, save       :: sizeof_int, sizeof_long_int
  integer, save       :: mpi_integer

  integer, parameter :: invalid_ = -1 
  integer, parameter :: spmat_null_=0, spmat_bld_=1
  integer, parameter :: spmat_asb_=2, spmat_upd_=4

  !
  ! 
  !     Error constants
  integer, parameter, public :: success_=0
  integer, parameter, public :: err_iarg_neg_=10
end module const_mod
module base_mat_mod
  
  use const_mod 


  type  :: base_sparse_mat
    integer, private     :: m, n
    integer, private     :: state, duplicate 
    logical, private     :: triangle, unitd, upper, sorted
  contains 

    procedure, pass(a) :: get_fmt => base_get_fmt
    procedure, pass(a) :: set_null => base_set_null
    procedure, pass(a) :: allocate_mnnz => base_allocate_mnnz
    generic,   public  :: allocate => allocate_mnnz
  end type base_sparse_mat

  interface 
    subroutine  base_allocate_mnnz(m,n,a,nz) 
      import base_sparse_mat, long_int_k_
      integer, intent(in) :: m,n
      class(base_sparse_mat), intent(inout) :: a
      integer, intent(in), optional  :: nz
    end subroutine base_allocate_mnnz
  end interface

contains

  function base_get_fmt(a) result(res)
    implicit none 
    class(base_sparse_mat), intent(in) :: a
    character(len=5) :: res
    res = 'NULL'
  end function base_get_fmt

  subroutine  base_set_null(a) 
    implicit none 
    class(base_sparse_mat), intent(inout) :: a

    a%state = spmat_null_
  end subroutine base_set_null


end module base_mat_mod

module d_base_mat_mod
  
  use base_mat_mod

  type, extends(base_sparse_mat) :: d_base_sparse_mat
  contains
  end type d_base_sparse_mat
  
  
  
  type, extends(d_base_sparse_mat) :: d_coo_sparse_mat
    
    integer              :: nnz
    integer, allocatable :: ia(:), ja(:)
    real(dpk_), allocatable :: val(:)
    
  contains
    
    procedure, pass(a) :: get_fmt      => d_coo_get_fmt
    procedure, pass(a) :: allocate_mnnz => d_coo_allocate_mnnz
    
  end type d_coo_sparse_mat
  
  
  interface
    subroutine  d_coo_allocate_mnnz(m,n,a,nz) 
      import d_coo_sparse_mat
      integer, intent(in) :: m,n
      class(d_coo_sparse_mat), intent(inout) :: a
      integer, intent(in), optional :: nz
    end subroutine d_coo_allocate_mnnz
  end interface
  
contains 
  
  function d_coo_get_fmt(a) result(res)
    implicit none 
    class(d_coo_sparse_mat), intent(in) :: a
    character(len=5) :: res
    res = 'COO'
  end function d_coo_get_fmt
  
end module d_base_mat_mod

subroutine  base_allocate_mnnz(m,n,a,nz) 
  use base_mat_mod, protect_name => base_allocate_mnnz
  implicit none 
  integer, intent(in) :: m,n
  class(base_sparse_mat), intent(inout) :: a
  integer, intent(in), optional  :: nz
  Integer :: err_act
  character(len=20)  :: name='allocate_mnz', errfmt
  logical, parameter :: debug=.false.

  ! This is the base version. If we get here
  ! it means the derived class is incomplete,
  ! so we throw an error.
  errfmt=a%get_fmt()
  write(0,*) 'Error: Missing ovverriding impl for allocate in class ',errfmt

  return

end subroutine base_allocate_mnnz

subroutine  d_coo_allocate_mnnz(m,n,a,nz) 
  use d_base_mat_mod, protect_name => d_coo_allocate_mnnz
  implicit none 
  integer, intent(in) :: m,n
  class(d_coo_sparse_mat), intent(inout) :: a
  integer, intent(in), optional :: nz
  Integer :: err_act, info, nz_
  character(len=20)  :: name='allocate_mnz'
  logical, parameter :: debug=.false.

  info = success_
  if (m < 0) then 
    info = err_iarg_neg_
  endif
  if (n < 0) then 
    info = err_iarg_neg_
  endif
  if (present(nz)) then 
    nz_ = nz
  else
    nz_ = max(7*m,7*n,1)
  end if
  if (nz_ < 0) then 
    info = err_iarg_neg_
  endif
! !$  if (info == success_) call realloc(nz_,a%ia,info)
! !$  if (info == success_) call realloc(nz_,a%ja,info)
! !$  if (info == success_) call realloc(nz_,a%val,info)
  if (info == success_) then 
! !$    call a%set_nrows(m)
! !$    call a%set_ncols(n)
! !$    call a%set_nzeros(0)
! !$    call a%set_bld()
! !$    call a%set_triangle(.false.)
! !$    call a%set_unit(.false.)
! !$    call a%set_dupl(dupl_def_)
    write(0,*) 'Allocated COO succesfully, should now set components'
  else 
    write(0,*) 'COO allocation failed somehow. Go figure'
  end if
  return

end subroutine d_coo_allocate_mnnz


program d_coo_err
  use d_base_mat_mod
  implicit none

  integer            :: ictxt, iam, np

  ! solver parameters
  type(d_coo_sparse_mat) :: acoo
  
  ! other variables
  integer nnz, n

  n   = 32
  nnz = n*9
  
  call acoo%set_null()
  call acoo%allocate(n,n,nz=nnz)

  stop
end program d_coo_err
