Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

function-stmt in interface bodies may have a declaration-type-spec in their prefix that contains a use/host-associated variable #1565

Open
rofirrim opened this issue Apr 4, 2022 · 3 comments

Comments

@rofirrim
Copy link

rofirrim commented Apr 4, 2022

Hi,

Sorry for the confusing name of the issue, I tried to be a bit precise, so I hope the testcase below is clearer.

module test
  implicit none
  integer, parameter :: my_kind = 4
end module test

module moo
  use test, only : my_kind
  implicit none
  interface
    integer(my_kind) function foo(a)
       import :: my_kind !! flang considers this as not accessible
                         !! probably due to the earlier occurrence of my_kind 
       implicit none
       integer(kind=my_kind) :: a
    end function foo
  end interface
contains
end module moo

This is rejected by flang:

error: Semantic errors in prefix-import.f90
./prefix-import.f90:10:13: error: Must be a constant value
      integer(my_kind) function foo(a)
              ^^^^^^^
./prefix-import.f90:11:18: error: 'my_kind' from host is not accessible
         import :: my_kind !! flang considers this as not accessible
                   ^^^^^^^
./prefix-import.f90:10:13: 'my_kind' is hidden by this entity
      integer(my_kind) function foo(a)
              ^^^^^^^
./prefix-import.f90:14:21: error: Must be a constant value
         integer(kind=my_kind) :: a
                      ^^^^^^^

I am aware this is a Fortran 2003 feature.

A similar problem happens with use-association.

module test
  implicit none
  integer, parameter :: my_kind = 4
end module test

module moo
  implicit none
  interface
    integer(my_kind) function foo(a)
       use test, only : my_kind    ! use-association
       implicit none
       integer(kind=my_kind) :: a
    end function foo
  end interface
contains
end module moo
error: Semantic errors in prefix-use.f90
./prefix-use.f90:9:13: error: Must be a constant value
      integer(my_kind) function foo(a)
              ^^^^^^^
./prefix-use.f90:10:25: error: Cannot use-associate 'my_kind'; it is already declared in this scope
         use test, only : my_kind    ! use-association
                          ^^^^^^^
./prefix-use.f90:9:13: Previous declaration of 'my_kind'
      integer(my_kind) function foo(a)
              ^^^^^^^

I admit I'm not 100% sure about the validity of this (but all compilers I could test on https://fortran.godbolt.org were OK with this code).
My reading of the spec is such that this should be accepted.

According to my draft of Fortran 2018, the constraints associated to the type-param-value of a declaration-type-spec (such like the one appearing in the prefix of a function-stmt) (R703) forces them to be specification-expr.

A variable in a specification expression shall have its type and type parameters, if any, specified by a previous declaration in the same scoping unit, by the implicit typing rules in effect for the scoping unit, or by host or use association.

(I understand here "previous" binds to the "declaration in the same scoping" and not the following cases: implicit, host, use).

As a workaround, the code can be rewritten to use a result(r) and then declare integer(my_kind) :: r, like below

module moo
  use test, only : my_kind
  implicit none
  interface
    function foo() result(r)
       import :: my_kind
       implicit none
       integer(kind=my_kind) :: r, a
    end function foo
  end interface
contains
end module moo
@rofirrim
Copy link
Author

rofirrim commented Apr 4, 2022

Looking at the code, there is a method called FinishFunctionResult in flang/lib/Semantics/resolve-names.cpp. It is called at the end of processing the function-stmt when the return type is an intrinsic type. Derived types are deferred at the end of the specification part. A comment says that this early process happens in order to be able to resolve specification queries, like the one below.

module moo
  implicit none
  integer, parameter :: my_kind = 4
end module moo

real(kind = my_kind) function square(x)
    use moo
    implicit none  !! (A)
    real(kind = my_kind) :: x
    real(kind = kind(square)) :: y  !! Here we need to know the kind of square
    
    square = x * x
end function square

Deferring this case like derived types (at the end of the specification part) would be too late for the y above. So perhaps one thing that we can do is to defer this case of intrinsic types to the point no more USE or IMPORT can appear (in the example above that would be right after (A)). Maybe there is a facility to know that already.

@jeanPerier
Copy link
Collaborator

Hi @rofirrim , thanks for the bug report. Lowering does not claim F2003 support, but semantics should be able to deal with up to F2018, so that is definitely a bug.

@klausler is working on a similar issue (deferring intrinsic function type resolution, this is actually required to handle things like real(kind(x)) function foo(x)). Maybe this will also fix this issue.

@rofirrim
Copy link
Author

rofirrim commented Apr 5, 2022

Just in case this is useful for @klausler, delaying the evaluation of a derived type at the end of the specification part might fail in this case.

type(my_type(kind(x))) function foo(x)
  implicit none
  real :: x
  type my_type(k)
    integer, kind :: k = kind(0.0)
    integer(kind = k) :: x
  end type !! Finishing the function type for derived types might have to happen here?
  integer(kind = foo % k) :: y
  
end function foo

Not 100% sure if this is valid as some commercial compilers are struggling with this case already.

Also the use of x inside kind is a bit questionable because it forces it to be the default real even when we stated an implicit none though all compilers seem coherent with this one, I assume this part of the testcase is OK.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants