Bug 45521

Summary: [F08] GENERIC resolution with ALLOCATABLE/POINTER and PROCEDURE
Product: gcc Reporter: Tobias Burnus <burnus>
Component: fortranAssignee: janus
Status: ASSIGNED ---    
Severity: normal CC: gcc-bugs, janus, wangmianzhi1
Priority: P3    
Version: 4.8.0   
Target Milestone: ---   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2012-04-19 00:00:00
Bug Depends on:    
Bug Blocks: 39627    

Description Tobias Burnus 2010-09-03 15:04:19 UTC
As the introduction of Fortran 2008 mentions:
- ALLOCATABLE and POINTER attributes are used in generic resolution.
- Procedureness of a dummy argument is used in generic resolution.

Or as "The new features of Fortran 2008" puts it:
"A pair of specific procedures in a generic interface are permitted to be distinguishable by virtue of a pointer argument without intent in of one corresponding to an allocatable argument of the other or a data argument of one corresponding to a procedure argument of the other."


Fortran 2008's "12.4.3.4.5 Restrictions on generic declarations" has"

"Two dummy arguments are distinguishable if
- one is a procedure and the other is a data object,
- they are both data objects or known to be functions, and neither is TKR compatible with the other,
- one has the ALLOCATABLE attribute and the other has the POINTER attribute, or
- one is a function with nonzero rank and the other is not known to be a function."

Interpretation request F08/0001 / 10-145 changes this ("EDITS to 10-007")"

'[286:4] In 12.4.3.4.5p3, after "the other has the POINTER attribute",
Insert "and not the INTENT(IN) attribute".'
Cf. http://j3-fortran.org/doc/meeting/193/10-199.txt

Fortran 2003 just had ("16.2.3 Restrictions on generic declarations"):

"Two dummy arguments are distinguishable if neither is a subroutine and neither is TKR compatible (5.1.1.2) with the other."
Comment 1 Tobias Burnus 2012-01-02 22:38:29 UTC
*** Bug 51736 has been marked as a duplicate of this bug. ***
Comment 2 janus 2012-04-18 19:16:59 UTC
(In reply to comment #1)
> *** Bug 51736 has been marked as a duplicate of this bug. ***

carrying over test case:

module a
  interface testAlloc
    module procedure::testAlloc1
    module procedure::testAlloc2
  end interface
contains
  function testAlloc1(obj)
    integer,allocatable,intent(in)::obj(:)
    logical testAlloc1
    testAlloc1=allocated(obj)
  end function
  function testAlloc2(obj)
    integer,pointer,intent(in)::obj(:)
    logical testAlloc2
    testAlloc2=associated(obj)
  end function
end module

program test
  use a
  integer,pointer::a1(:)=>null()
  integer,allocatable::a2(:)
  write(*,*),testAlloc(a1),testAlloc(a2)
end program


With current trunk one gets:

    module procedure::testAlloc2
                                1   
Error: Ambiguous interfaces 'testalloc2' and 'testalloc1' in generic interface 'testalloc' at (1)
Comment 3 janus 2012-04-18 19:38:10 UTC
To implement this, we'll presumably need to modify 'gfc_compare_interfaces' in interface.c (for the case of generic_flag=1 and strict_flag=0). Possibly the changes should go directly into 'generic_correspondence'.
Comment 4 janus 2012-04-19 12:45:28 UTC
Here is a preliminary patch which makes gfortran accept the code in comment #2:

Index: gcc/fortran/interface.c
===================================================================
--- gcc/fortran/interface.c	(revision 186485)
+++ gcc/fortran/interface.c	(working copy)
@@ -955,7 +955,9 @@ generic_correspondence (gfc_formal_arglist *f1, gf
 	goto next;
 
       if (f2 != NULL && (compare_type_rank (f1->sym, f2->sym)
-			 || compare_type_rank (f2->sym, f1->sym)))
+			 || compare_type_rank (f2->sym, f1->sym))
+	  && !((f1->sym->attr.allocatable && f2->sym->attr.pointer)
+	       || (f2->sym->attr.allocatable && f1->sym->attr.pointer)))
 	goto next;
 
       /* Now search for a disambiguating keyword argument starting at
@@ -966,7 +968,9 @@ generic_correspondence (gfc_formal_arglist *f1, gf
 	    continue;
 
 	  sym = find_keyword_arg (g->sym->name, f2_save);
-	  if (sym == NULL || !compare_type_rank (g->sym, sym))
+	  if (sym == NULL || !compare_type_rank (g->sym, sym)
+	      || (sym->attr.allocatable && g->sym->attr.pointer)
+	      || (sym->attr.pointer && g->sym->attr.allocatable))
 	    return 1;
 	}
Comment 5 janus 2012-04-19 12:53:05 UTC
(In reply to comment #4)
> Here is a preliminary patch which makes gfortran accept the code in comment #2:

Of course we need to do more. As quoted in comment #0:

"Two dummy arguments are distinguishable if
- one is a procedure and the other is a data object,
- they are both data objects or known to be functions, and neither is TKR
compatible with the other,
- one has the ALLOCATABLE attribute and the other has the POINTER attribute, or
- one is a function with nonzero rank and the other is not known to be a
function."

The patch above only handles the third item, and the second item works already.
Items #1 and #4 are still missing (I think).
Comment 6 janus 2012-04-19 13:04:18 UTC
(In reply to comment #5)
> "Two dummy arguments are distinguishable if
> - one is a procedure and the other is a data object,

Here is a test case for this item:


module m
  interface testIF
    module procedure :: test1
    module procedure :: test2
  end interface
contains
  real function test1 (obj)
    real :: obj
    test1 = obj
  end function
  real function test2 (obj)
    procedure(real) :: pr
    test2 = pr(0.)
  end function
end module

program test
  use m
  print *,testIF(2.0),testIF(cos)
end program



... which is currently rejected with:


    module procedure :: test2
                             1
Error: Ambiguous interfaces 'test2' and 'test1' in generic interface 'testif' at (1)
Comment 7 Tobias Burnus 2012-04-19 13:15:27 UTC
(In reply to comment #4)
> Here is a preliminary patch which makes gfortran accept the code in
> comment #2:

Don't forget to add -std=f2003 diagnostic - either by simply marking it as ambiguous or fancier by telling that it is invalid but would be valid in Fortran 2008.
Comment 8 Mianzhi Wang 2012-04-19 13:20:57 UTC
if replace the input argument for test2() with pr, the program will 
compile but gives seg fault at run time.



于 2012年04月19日 09:04, janus at gcc dot gnu.org 写道:
> http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45521
>
> --- Comment #6 from janus at gcc dot gnu.org 2012-04-19 13:04:18 UTC ---
> (In reply to comment #5)
>> "Two dummy arguments are distinguishable if
>> - one is a procedure and the other is a data object,
> Here is a test case for this item:
>
>
> module m
>    interface testIF
>      module procedure :: test1
>      module procedure :: test2
>    end interface
> contains
>    real function test1 (obj)
>      real :: obj
>      test1 = obj
>    end function
>    real function test2 (obj)
>      procedure(real) :: pr
>      test2 = pr(0.)
>    end function
> end module
>
> program test
>    use m
>    print *,testIF(2.0),testIF(cos)
> end program
>
>
>
> ... which is currently rejected with:
>
>
>      module procedure :: test2
>                               1
> Error: Ambiguous interfaces 'test2' and 'test1' in generic interface 'testif'
> at (1)
>
Comment 9 Mianzhi Wang 2012-04-19 13:22:24 UTC
if replace the input argument for test2() with pr, the program will compile but gives seg fault at run time.
Comment 10 janus 2012-04-19 13:36:46 UTC
(In reply to comment #6)
> (In reply to comment #5)
> > "Two dummy arguments are distinguishable if
> > - one is a procedure and the other is a data object,
> 
> Here is a test case for this item:

Sorry, I messed up the declaration of 'test2' (by not using 'implicit none'). Therefore gfortran is correct in rejecting it. It should have been:


module m
  implicit none
  interface testIF
    module procedure test1
    module procedure test2
  end interface
contains
  real function test1 (obj)
    real :: obj
    test1 = obj
  end function
  real function test2 (pr)
    procedure(real) :: pr
    test2 = pr(0.)
  end function
end module

program test
  use m
  implicit none
  intrinsic :: cos
  print *,testIF(2.0)
  print *,testIF(cos)
end program


This is actually accepted by all gfortran versions I tried (4.3,4.6,4.7,trunk). However, it yields a segfault at runtime (-fdump-tree-original shows that 'test2' is used in both calls).
Comment 11 janus 2012-04-20 12:29:34 UTC
(In reply to comment #10)
> However, it yields a segfault at runtime (-fdump-tree-original shows that
> 'test2' is used in both calls).

Related to this, it also shows that the specific call

  print *,test2(2.0)

is not being rejected, while

  print *,test1(cos)

is. For for former, we clearly need to add a check in 'compare_parameter' to reject it (which should also solve the segfault in comment #10 by selecting the correct specific function for the generic call).
Comment 12 janus 2012-04-20 12:58:24 UTC
(In reply to comment #11)
> For for former, we clearly need to add a check in 'compare_parameter' to
> reject it


Something like:

Index: gcc/fortran/interface.c
===================================================================
--- gcc/fortran/interface.c	(revision 186596)
+++ gcc/fortran/interface.c	(working copy)
@@ -1663,6 +1667,13 @@ compare_parameter (gfc_symbol *formal, gfc_expr *a
        the module variables are generated.  */
     gfc_find_derived_vtab (actual->ts.u.derived);
 
+  if (formal->attr.flavor == FL_PROCEDURE && actual->ts.type != BT_PROCEDURE)
+    {
+      if (where)
+	gfc_error ("Procedure argument expected at %L", &actual->where);
+      return 0;
+    }
+  
   if (actual->ts.type == BT_PROCEDURE)
     {
       char err[200];


This correctly rejects the invalid code in comment #11 and makes the valid code in comment #10 give the expected output (without segfaulting).
Comment 13 janus 2012-04-25 12:29:55 UTC
(In reply to comment #12)
> > For for former, we clearly need to add a check in 'compare_parameter' to
> > reject it

Actually, we do have a check for this already, which is just not working in some cases. Therefore the patch in comment #12 is not the right thing to do. Here is a better one (which is actually free of testsuite regressions):

Index: gcc/fortran/interface.c
===================================================================
--- gcc/fortran/interface.c	(revision 186596)
+++ gcc/fortran/interface.c	(working copy)
@@ -2393,9 +2397,8 @@ compare_actual_formal (gfc_actual_arglist **ap, gf
 
       /* Satisfy 12.4.1.2 by ensuring that a procedure actual argument is
 	 provided for a procedure formal argument.  */
-      if (a->expr->ts.type != BT_PROCEDURE && !gfc_is_proc_ptr_comp (a->expr, NULL)
-	  && a->expr->expr_type == EXPR_VARIABLE
-	  && f->sym->attr.flavor == FL_PROCEDURE)
+      if (f->sym->attr.flavor == FL_PROCEDURE
+	  && gfc_expr_attr (a->expr).flavor != FL_PROCEDURE)
 	{
 	  if (where)
 	    gfc_error ("Expected a procedure for argument '%s' at %L",



Cleanup side note: A lot of the stuff in 'compare_actual_formal' could probably be moved into 'compare_parameter'. It does not really make a difference, but the distinction of what goes where seems completely arbitrary right now.
Comment 14 janus 2012-10-06 12:20:17 UTC
Author: janus
Date: Sat Oct  6 12:20:09 2012
New Revision: 192157

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=192157
Log:
2012-10-06  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/45521
	* interface.c (generic_correspondence): Implement additional
	distinguishability criteria of F08.
	(compare_actual_formal): Reject data object as actual argument for
	procedure formal argument.

2012-10-06  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/45521
	* gfortran.dg/generic_25.f90: New.
	* gfortran.dg/generic_26.f90: New.
	* gfortran.dg/generic_27.f90: New.

Added:
    trunk/gcc/testsuite/gfortran.dg/generic_25.f90
    trunk/gcc/testsuite/gfortran.dg/generic_26.f90
    trunk/gcc/testsuite/gfortran.dg/generic_27.f90
Modified:
    trunk/gcc/fortran/ChangeLog
    trunk/gcc/fortran/interface.c
    trunk/gcc/testsuite/ChangeLog
Comment 15 janus 2012-10-06 12:35:26 UTC
(In reply to comment #0)
> Fortran 2008's "12.4.3.4.5 Restrictions on generic declarations" has"
> 
> "Two dummy arguments are distinguishable if
> - one is a procedure and the other is a data object,
> - they are both data objects or known to be functions, and neither is TKR
> compatible with the other,
> - one has the ALLOCATABLE attribute and the other has the POINTER attribute, or
> - one is a function with nonzero rank and the other is not known to be a
> function."

r192157 implements item 3 and contains a bugfix for item 1, so that items 1-3 should be handled correctly.

About item 4 I'm not completely sure, but possibly we still miss that.



> Interpretation request F08/0001 / 10-145 changes this ("EDITS to 10-007")"
> 
> '[286:4] In 12.4.3.4.5p3, after "the other has the POINTER attribute",
> Insert "and not the INTENT(IN) attribute".'
> Cf. http://j3-fortran.org/doc/meeting/193/10-199.txt

Unfortunately this was forgotten in the above commit. To do!