fortrangfortranflang

Default value for components of Fortran parameterized derived types


Here is a minimal program to reproduce my problem:

program test

  use iso_fortran_env, only: REAL32

  implicit none

  type :: matrix (rows, cols, kind)
     integer, len                             :: rows
     integer, len                             :: cols
     integer, kind                            :: kind = REAL32
     real (kind=kind), dimension (rows, cols) :: values
     real (kind=kind)                         :: small = 1.0e-9
  end type matrix

end program test

When I compiled this program with gfortran 14.1, I got this error:

test.f90:12:56:

   12 |      real (kind=kind)                         :: small = 0.0e-9
      |                                                        1
Error: Cannot convert REAL(4) to REAL(0) at (1)

When I remove = 0.0e-9, then code compiles successfully.

  1. Did I miss something? or this is a gfortran bug?
  2. If it is possible to initialize components of parameterized derived types like above code, how I can set type of the literal in initialization assignment (like small = 1.0e-9_kind when kind came from derived type parameters)?

EDIT:

It works with AOCC 4.1 (flang 16.0)! So I think it is gfortran bug (similar to this bug).

So without removing the original question, I changed it to:

Considering the following parameterized derived type:

program test

  use iso_fortran_env, only: REAL32, REAL64, REAL128

  implicit none

  type :: mytype (kind)
     integer, kind    :: kind = REAL32
     real (kind=kind) :: small = 1.0e-9
  end type mytype

  type (mytype (kind=REAL32))  :: s
  type (mytype (kind=REAL64))  :: d
  type (mytype (kind=REAL128)) :: q

end program test

Here, for all real kinds (except the default real kind), the 1.0e-9 literal assigned to the small component of mytype will lose accuracy. How I can use the kind parameter in the small = 1.0e-9 default value assignment (something like small = 1.0e-9_kind)?


Solution

  • In a literal real constant like 1.0e-9_kind the kind parameter must be a named constant.

    In contrast, some other specifications of kind parameter merely require a constant expression.

    Within a derived type definition like

    type t(kind)
       integer, kind :: kind
       real(kind) :: x=1._kind
    end type
    

    the kind parameter for the type declaration (real(kind)) is the "constant expression" requirement whereas 1._kind is the "named constant" requirement.

    Within the derived type definition a kind parameter of the derived type can be used in a constant expression, but it's not a named constant. That is, we can have real(kind), but not 1._kind.

    kind being a constant expression means we can, however, have

    type t(kind)
       integer, kind :: kind
       real(kind) :: x=TINY(REAL(1., kind))  ! Not TINY(1._kind)
    end type
    

    You can specify the "most precise" literal constant and use kind to convert it:

    type t(kind)
       integer, kind :: kind
       real(kind) :: x=REAL(1._real128, kind)
    end type
    

    but that's just

    type t(kind)
       integer, kind :: kind
       real(kind) :: x=1._real128
    end type
    

    except for cases where compilers have bugs.

    Note that this isn't portable: there's no guarantee that real128 is the most precise real. You're assuming it's a valid kind number, though, so whatever process you used to guarantee that you can use to guarantee it's the most precise or desirable.