Bug 42418 - PROCEDURE: Rejects interface which is both specific and generic procedure
Summary: PROCEDURE: Rejects interface which is both specific and generic procedure
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: fortran (show other bugs)
Version: 4.5.0
: P3 normal
Target Milestone: ---
Assignee: janus
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2009-12-17 22:51 UTC by Tobias Burnus
Modified: 2012-07-31 18:39 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2011-01-09 18:55:46


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Tobias Burnus 2009-12-17 22:51:01 UTC
(found when going through the link of PR 

gfortran rejects the following program where "gen" is both a generic and a specific procedure name as interface argument to PROCEDURE. I cannot find a reason why it should be invalid and thus I think it is valid.


    procedure(gen) :: f
                 1
Error: Interface 'gen' at (1) may not be generic


module mod
  interface gen
    module procedure gen
  end interface gen
contains
  pure subroutine gen(a)
    integer,intent(in) :: a
  end subroutine gen
  subroutine test(f)
    procedure(gen) :: f
  end subroutine test
end module mod
Comment 1 Tobias Burnus 2009-12-17 23:02:43 UTC
The following program is also rejected, unless the marked line is removed/comment out. At a glance, it looks OK - and ifort, NAG f95 and g95 accept it. The error message is:


   print *, fun(enisoc, [0.0])
                1
Error: ELEMENTAL non-INTRINSIC procedure 'enisoc' is not allowed as an actual argument at (1)


 module cos_mod
   implicit none
   interface enisoc
      module procedure element, enisoc
   end interface enisoc
   contains
      pure function enisoc(x)
         real, intent(in) :: x(:)
         real enisoc(size(x))

         enisoc = 2
      end function enisoc

      elemental function element(x)
         real, intent(in) :: x
         real element

         element = cos(x)
      end function element
end module cos_mod

program main
   use cos_mod
   implicit none
   interface
      function fun(f,x)
         implicit none
         interface
            pure function f(x)
               real, intent(in) :: x(:)
               real f(size(x))
            end function f
         end interface
         real x(:)
         real fun(size(x))
      end function fun
   end interface

   print *, enisoc(0.0)  ! <<< Works without this line
   print *, fun(enisoc, [0.0])
end program main

!function fun(f,x)
!   implicit none
!   interface
!      pure function f(x)
!         real, intent(in) :: x(:)
!         real f(size(x))
!      end function f
!   end interface
!   real x(:)
!   real fun(size(f(x)))
!
!   fun = f(x)
!end function fun
Comment 2 janus 2009-12-19 20:27:41 UTC
(In reply to comment #1)
> The following program is also rejected, unless the marked line is
> removed/comment out. At a glance, it looks OK - and ifort, NAG f95 and g95
> accept it. The error message is:
> 
> 
>    print *, fun(enisoc, [0.0])
>                 1
> Error: ELEMENTAL non-INTRINSIC procedure 'enisoc' is not allowed as an actual
> argument at (1)

This one I can not confirm. With a clean trunk at r155303 I do not see the error message on x86_64-unknown-linux-gnu.
Comment 3 janus 2011-01-09 18:55:46 UTC
(In reply to comment #0)
> gfortran rejects the following program where "gen" is both a generic and a
> specific procedure name as interface argument to PROCEDURE. I cannot find a
> reason why it should be invalid and thus I think it is valid.
> 
> 
>     procedure(gen) :: f
>                  1
> Error: Interface 'gen' at (1) may not be generic


The behavior in comment #0 I can confirm. And I agree that it is valid. Chapter 16.3.1 of F08 says:

"Within its scope, a local identifier of one class shall not be the same as another local identifier of the same class, except that a generic name may be the same as the name of a procedure as explained in 12.4.3.4 [...]"

In 12.4.3.4.1 we find:

"A generic name is a generic identifier that refers to all of the procedure names in the interface block. A generic name may be the same as any one of the procedure names in the interface block, or the same as any accessible generic name."
Comment 4 janus 2011-01-09 21:32:14 UTC
cf. also PR 39427 (generic names can be the same as derived type names)
Comment 5 Dominique d'Humieres 2012-01-28 23:07:49 UTC
With gfortran 4.4.6, 4.5.3, 4.6.2, and trunk, the test in comment #0 gives the error while the test in comment #1 with the 'function fun(f,x)' block uncommented compiles and runs to give

[macbook] f90/bug% a.out
   1.00000000    
   2.00000000    

with no error when run through valgrind.
Comment 6 janus 2012-07-21 09:51:57 UTC
The error in comment #0 should be fixable by something like the following:


Index: gcc/fortran/decl.c
===================================================================
--- gcc/fortran/decl.c	(revision 189711)
+++ gcc/fortran/decl.c	(working copy)
@@ -4807,9 +4807,17 @@ match_procedure_interface (gfc_symbol **proc_if)
 
       if ((*proc_if)->generic)
 	{
-	  gfc_error ("Interface '%s' at %C may not be generic",
-		     (*proc_if)->name);
-	  return MATCH_ERROR;
+	  /* For generic interfaces, check if there is
+	     a specific procedure with the same name.  */
+	  gfc_interface *gen = (*proc_if)->generic;
+	  while (gen && strcmp (gen->sym->name, (*proc_if)->name) != 0)
+	    gen = gen->next;
+	  if (!gen)
+	    {
+	      gfc_error ("Interface '%s' at %C may not be generic",
+			  (*proc_if)->name);
+	      return MATCH_ERROR;
+	    }
 	}
       if ((*proc_if)->attr.proc == PROC_ST_FUNCTION)
 	{


However, I wonder whether this whole generic check does not come to early. If the generic interface is declared after the PROCEDURE statement, it will not be triggered. It should probably be moved to resolve.c
Comment 7 janus 2012-07-21 17:10:32 UTC
(In reply to comment #6)
> However, I wonder whether this whole generic check does not come to early. If
> the generic interface is declared after the PROCEDURE statement, it will not be
> triggered. It should probably be moved to resolve.c

Along this line:

module mod
  procedure(gen) :: f
  interface gen
    module procedure spec
  end interface gen
contains
  subroutine spec()
  end subroutine
end module

This is rejected with:

  procedure(gen) :: f
                     1   
Error: Interface 'gen' of procedure 'f' at (1) must be explicit


I'm not sure if this error message is correct. In any case, it is accepted if 'spec' is used as an interface in the PROCEDURE declaration (which seems inconsistent).
Comment 8 janus 2012-07-31 18:32:46 UTC
Author: janus
Date: Tue Jul 31 18:32:41 2012
New Revision: 190017

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

	PR fortran/42418
	* decl.c (match_procedure_interface): Move some checks to
	'resolve_procedure_interface'. Set flavor if appropriate.
	* expr.c (gfc_check_pointer_assign): Cleanup of 'gfc_is_intrinsic'.
	* intrinsic.c (gfc_is_intrinsic): Additional checks for attributes which
	identify a procedure as being non-intrinsic.
	* resolve.c (resolve_procedure_interface): Checks moved here from
	'match_procedure_interface'. Minor cleanup.
	(resolve_formal_arglist,resolve_symbol): Cleanup of
	'resolve_procedure_interface'
	(resolve_actual_arglist,is_external_proc): Cleanup of
	'gfc_is_intrinsic'.

2012-07-31  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/42418
	* gfortran.dg/proc_decl_29.f90: New.

Added:
    trunk/gcc/testsuite/gfortran.dg/proc_decl_29.f90
Modified:
    trunk/gcc/fortran/ChangeLog
    trunk/gcc/fortran/decl.c
    trunk/gcc/fortran/expr.c
    trunk/gcc/fortran/intrinsic.c
    trunk/gcc/fortran/resolve.c
    trunk/gcc/testsuite/ChangeLog
Comment 9 janus 2012-07-31 18:39:42 UTC
Fixed with r190017. Closing.