Bug 40054

Summary: [F08] Pointer functions as lvalue
Product: gcc Reporter: janus
Component: fortranAssignee: Not yet assigned to anyone <unassigned>
Status: NEW ---    
Severity: normal CC: d, gcc-bugs, kargl, quantheory
Priority: P3 Keywords: rejects-valid
Version: 4.5.0   
Target Milestone: ---   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2009-05-07 08:07:58
Bug Depends on:    
Bug Blocks: 39627, 52994    

Description janus 2009-05-07 07:54:47 UTC
See section 6.2 in ftp://ftp.nag.co.uk/sc22wg5/N1701-N1750/N1729.pdf.

In principle functions which return a pointer work already (even with procedure pointers). AFAICS, the only thing missing is using these functions as lvalue, as in this example:


real, dimension(1:100), target :: array
real, pointer :: p

array(5) = 0.7
print *,storage(5)

p => storage(3)
p = 0.5
print *,p

storage(5) = 0.5  ! Error: 'storage' at (1) is not a variable

contains

  function storage(key) result(loc)
    integer, intent(in) :: key
    real, pointer :: loc
    loc => array(key)
  end function

end
Comment 1 Tobias Burnus 2009-05-07 08:07:58 UTC
In the standard:

   R602 variable  is  designator
                  or  expr
   C602 (R602) expr shall be a reference to a function that has a pointer
               result."

Which can then be used in assignment statements:

   R732 assignment-stmt  is  variable = expr

   If the variable is a pointer, it shall be associated with a definable
   target such that the type, type parameters, and shape of the target
   and expr conform.
Comment 2 Tobias Burnus 2010-10-20 18:05:23 UTC
Another example (from PR 46100):

two() = 7
contains
  function two ()
    integer, pointer  :: two
    allocate(two)
  end function two
end



Fails with:

  function two ()
              1
two() = 7
   2
Error: Procedure 'two' at (1) is already defined at (2)

  function two ()
  1
Error: INTERNAL-PROC procedure at (1) is already declared as STATEMENT-PROC procedure
Comment 3 Tobias Burnus 2010-11-15 16:17:54 UTC
Remember also to update check.c's variable_check.
Comment 4 janus 2011-06-28 15:49:54 UTC
cf. also PR 49562
Comment 5 janus 2011-07-03 11:27:55 UTC
(In reply to comment #4)
> cf. also PR 49562

after PR49562 is fixed on trunk, type-bound pointer functions already work (in contrast to ordinary, non-type-bound pointer functions)
Comment 6 janus 2011-07-03 11:32:42 UTC
(In reply to comment #2)
> 
> two() = 7
> contains
>   function two ()
>     integer, pointer  :: two
>     allocate(two)
>   end function two
> end
> 
> Fails with:
> 
>   function two ()
>               1
> two() = 7
>    2
> Error: Procedure 'two' at (1) is already defined at (2)

Huh. Since "two() = 7" is in fact a valid statement function declaration, gfortran might even be right to reject this, right?

However, the following (valid?) variant is currently rejected:

print *,"hello"
two() = 7
contains
  function two ()
    integer, pointer  :: two
    allocate(two)
  end function two
end


two() = 7
         1
Error: Unexpected STATEMENT FUNCTION statement at (1)
Comment 7 janus 2011-07-03 15:43:39 UTC
I think it will be very hard (if not impossible) to implement this, while maintaining support for statement functions at the same time. In particular, how is one supposed to interpret a statement like:

f (x) = x + 1

Is this a statement function declaration? Or rather an assignment to the result of a pointer-valued function f, which is defined further down the road? In many situations this seems to be indistinguishable (or one can only decide it at resolution stage, where the function f has been parsed already, if it is there). Or am I missing some restriction in the standard?

In any case, statement functions are obsolescent since F95, so would it be an option to not support them with -std=f2008?
Comment 8 kargl 2011-07-03 16:19:24 UTC
(In reply to comment #7)
> I think it will be very hard (if not impossible) to implement this, while
> maintaining support for statement functions at the same time. In particular,
> how is one supposed to interpret a statement like:
> 
> f (x) = x + 1
> 
> Is this a statement function declaration? Or rather an assignment to the result
> of a pointer-valued function f, which is defined further down the road? In many
> situations this seems to be indistinguishable (or one can only decide it at
> resolution stage, where the function f has been parsed already, if it is
> there). Or am I missing some restriction in the standard?
> 
> In any case, statement functions are obsolescent since F95, so would it be an
> option to not support them with -std=f2008?

Obsolescent does not mean deleted.  Unfortunately, statement functions
are still valid Fortran.
Comment 9 janus 2011-07-03 16:24:53 UTC
(In reply to comment #8)
> > In any case, statement functions are obsolescent since F95, so would it be an
> > option to not support them with -std=f2008?
> 
> Obsolescent does not mean deleted.  Unfortunately, statement functions
> are still valid Fortran.

Yes, I am aware of that. Do you have an idea how to implement both features at the same time, Steve?
Comment 10 Tobias Burnus 2011-07-03 16:29:01 UTC
(In reply to comment #7)
> I think it will be very hard (if not impossible) to implement this, while
> maintaining support for statement functions at the same time. In particular,
> how is one supposed to interpret a statement like:
> f (x) = x + 1

That depends on the context. The function "f(x)" is only a variable if "f" returns a pointer - and those functions are required to have an explicit interface (cf. "12.4.2.2 Explicit interface").

Thus, the ambiguity can only occur if one host-associates an explicit interface of "f". But the following makes clear how to interpret the program in that case (from "12.6.4 Statement function"):

"The definition of a statement function with the same name as an accessible entity from the host shall be preceded by the declaration of its type in a type declaration statement."


> In any case, statement functions are obsolescent since F95, so would it be an
> option to not support them with -std=f2008?

No. They are just obsolescent - not deleted:

"Better methods existed in Fortran 90 and Fortran 95 for each obsolescent feature. It is recommended that programmers use these better methods in new programs and convert existing code to these methods. [...]  A future revision of this part of ISO/IEC 1539 might delete an obsolescent feature if its use has become insignificant." (From "1.7.3 Nature of obsolescent features")

Besides, with -std=gnu, we want to support both old and Fortran 2008 conform programs ...
Comment 11 Steve Kargl 2011-07-03 17:12:15 UTC
On Sun, Jul 03, 2011 at 04:25:39PM +0000, janus at gcc dot gnu.org wrote:
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=40054
> 
> --- Comment #9 from janus at gcc dot gnu.org 2011-07-03 16:24:53 UTC ---
> (In reply to comment #8)
> > > In any case, statement functions are obsolescent since F95, so would it be an
> > > option to not support them with -std=f2008?
> > 
> > Obsolescent does not mean deleted.  Unfortunately, statement functions
> > are still valid Fortran.
> 
> Yes, I am aware of that. Do you have an idea how to implement both features at
> the same time, Steve?
> 

With your first example,

two() = 7
contains
  function two ()
    integer, pointer  :: two
    allocate(two)
  end function two
end

I think two() should be treated as a pointer function because
the standard states:

   The definition of a statement function with the same name
   as an accessible entity from the host shall be preceded by the
   declaration of its type in a type declaration statement.

For two() to be a statement function one would need to have
for example,

real two
two() = 7
contains
  !
  ! Is this now an error due to a redefinition of two() ???
  !
  function two ()  
    integer, pointer  :: two
    allocate(two)
  end function two
end

Also, as Tobias' noted an explicit interface is needed for a
pointer function.
Comment 12 Sean Santos 2013-10-25 07:09:12 UTC
I think Tobias already has this figured, but my view of this was as follows.

These define statement functions yielding 7:

--- Example 1 ---

two() = 7
end

--- Example 2 ---

module foo
contains
  function two()
    integer, pointer  :: two
    allocate(two)
  end function two

  subroutine bar()
    ! Fortran 2008 (12.6.4) says that this is necessary to hide
    ! the host-associated declaration
    integer :: two
    two() = 7
  end subroutine bar
end module foo

These refer to the pointer function:

--- Example 1 ---

two() = 7
contains
  function two ()
    integer, pointer  :: two
    allocate(two)
  end function two
end

--- Example 2 ---

module foo
contains
  function two ()
    integer, pointer  :: two
    allocate(two)
  end function two
end module

program
use foo
two() = 7
end program

--- Example 3 ---

module foo
contains
  function two()
    integer, pointer  :: two
    allocate(two)
  end function two

  subroutine bar()
    two() = 7
  end subroutine bar
end module foo

And these are not allowed at all based on 11.2.2.8 and 16.3.1.3, because they result in a name clash:

--- Example 1 ---

integer :: two
two() = 7
contains
  function two ()
    integer, pointer  :: two
    allocate(two)
  end function two
end

--- Example 2 ---

module foo
contains
  function two ()
    integer, pointer  :: two
    allocate(two)
  end function two
end module

program
use foo
integer :: two
two() = 7
end program