Bug 46952 - [OOP] Spurious "recursive call" error with type bound procedure
Summary: [OOP] Spurious "recursive call" error with type bound procedure
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: fortran (show other bugs)
Version: 4.6.0
: P3 normal
Target Milestone: ---
Assignee: janus
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2010-12-15 02:46 UTC by Ian Harvey
Modified: 2013-02-12 12:21 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2010-12-15 08:25:18


Attachments
Example that generate the error (528 bytes, text/plain)
2010-12-15 02:46 UTC, Ian Harvey
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Ian Harvey 2010-12-15 02:46:18 UTC
Created attachment 22759 [details]
Example that generate the error

The attached, using a gfortran 4.6 from November 3 on i686-pc-mingw32, generates the error "SUBROUTINE 'relay_proc' ... cannot be called recursively".  But I don't think the call is recursive - relay_proc is just the interface for what gets called, not the actual procedure.

But Intel Fortran 12.0.1.127 also complains, so maybe I'm wrong.
Comment 1 Tobias Burnus 2010-12-15 08:25:18 UTC
At a glance it looks valid to me. The crucial part seems to be:

  PROCEDURE(relay_proc), DEFERRED :: TwoProc
...
  SUBROUTINE relay_proc(obj)
    CALL obj%TwoProc
                    1
Error: SUBROUTINE 'relay_proc' at (1) cannot be called recursively, as it is not RECURSIVE

  *  *  *

I managed to create an ICE-on-invalid-code: The following program segfaults w/o printing any error/warning message at

==31463== Invalid read of size 1
==31463==    at 0x50871E: gfc_match_varspec (primary.c:1771)
==31463==    by 0x4F06A3: gfc_match_call (match.c:3442)
==31463==    by 0x501622: match_word (parse.c:65)


The following program is invalid for several reasons: the ICE seems to be due to "bar" having no dummy argument. If one adds one, one gets the bogus "recursive" error; fixing that one gets the correct error that the argument must be of type CLASS(t2) and not of CLASS(t).

module m
  type, abstract :: t
  contains
    procedure(bar), pass, deferred :: foo
    procedure(bar), pass, deferred :: bar
  end type
  type,extends(t) :: t2
  contains
    procedure, pass :: bar => bar
    procedure, pass :: foo => foo
  end type t2
contains
  subroutine foo(this)
    class(t) :: this
  end subroutine foo
  subroutine bar()   ! pass but "this" argument is missing; no error only ICE
    class(t) :: this
    call this%foo()
  end subroutine
end module m
Comment 2 Tobias Burnus 2010-12-15 08:37:42 UTC
Reduced test case. Crucial seems to be that "inter" and "bar" call "foo" and that foo and bar are defined via the interface "inter".

Similarly to gfortran and ifort also Crayftn rejects the following program. However, I do no see any possibility how one could create a recursive call. Thus, I do not see the need for a RECURSIVE attribute ("The RECURSIVE prefix-spec shall appear if any procedure defined by the subprogram directly or indirectly invokes itself or any other procedure defined by the subprogram.")

module m
  type, abstract :: t
  contains
    procedure(inter), pass, deferred :: foo
    procedure(inter), pass, deferred :: bar
  end type
  type,extends(t) :: t2
  contains
    procedure, pass :: bar => bar
    procedure, pass :: foo => foo
  end type t2
contains
  subroutine inter(this)
    class(t) :: this
    call this%foo()
  end subroutine inter
  subroutine foo(this)
    class(t2) :: this
  end subroutine foo
  subroutine bar(this)
    class(t2) :: this
    call this%foo()
  end subroutine
end module m
Comment 3 janus 2013-01-10 08:50:51 UTC
Further reducing the test case:


module m

  type, abstract :: t
  contains
    procedure(inter), pass, deferred :: foo
  end type

contains

  subroutine inter(this)
    class(t) :: this
    call this%foo()
  end subroutine inter

end module m
Comment 4 janus 2013-01-10 11:48:54 UTC
I think the following patch makes sense:

Index: gcc/fortran/resolve.c
===================================================================
--- gcc/fortran/resolve.c	(revision 194927)
+++ gcc/fortran/resolve.c	(working copy)
@@ -3803,7 +3803,7 @@ resolve_call (gfc_code *c)
 
   /* Subroutines without the RECURSIVE attribution are not allowed to
    * call themselves.  */
-  if (csym && is_illegal_recursion (csym, gfc_current_ns))
+  if (!c->expr1 && csym && is_illegal_recursion (csym, gfc_current_ns))
     {
       if (csym->attr.entry && csym->ns->entries)
 	gfc_error ("ENTRY '%s' at %L cannot be called recursively, as"


This is the same workaround that we use in resolve_call for deferred TBPs with abstract interfaces.
Comment 5 janus 2013-01-10 14:09:54 UTC
The following patch is equivalent in functionality to the one in comment 4, but includes some minor cleanup (and regtests cleanly):


Index: gcc/fortran/resolve.c
===================================================================
--- gcc/fortran/resolve.c	(revision 194927)
+++ gcc/fortran/resolve.c	(working copy)
@@ -3792,28 +3792,30 @@ resolve_call (gfc_code *c)
 	}
     }
 
-  /* If this ia a deferred TBP with an abstract interface
-     (which may of course be referenced), c->expr1 will be set.  */
-  if (csym && csym->attr.abstract && !c->expr1)
+  /* If this ia a deferred TBP, c->expr1 will be set.  */
+  if (!c->expr1 && csym)
     {
-      gfc_error ("ABSTRACT INTERFACE '%s' must not be referenced at %L",
-		 csym->name, &c->loc);
-      return FAILURE;
-    }
+      if (csym->attr.abstract)
+	{
+	  gfc_error ("ABSTRACT INTERFACE '%s' must not be referenced at %L",
+		    csym->name, &c->loc);
+	  return FAILURE;
+	}
 
-  /* Subroutines without the RECURSIVE attribution are not allowed to
-   * call themselves.  */
-  if (csym && is_illegal_recursion (csym, gfc_current_ns))
-    {
-      if (csym->attr.entry && csym->ns->entries)
-	gfc_error ("ENTRY '%s' at %L cannot be called recursively, as"
-		   " subroutine '%s' is not RECURSIVE",
-		   csym->name, &c->loc, csym->ns->entries->sym->name);
-      else
-	gfc_error ("SUBROUTINE '%s' at %L cannot be called recursively, as it"
-		   " is not RECURSIVE", csym->name, &c->loc);
+      /* Subroutines without the RECURSIVE attribution are not allowed to
+	 call themselves.  */
+      if (is_illegal_recursion (csym, gfc_current_ns))
+	{
+	  if (csym->attr.entry && csym->ns->entries)
+	    gfc_error ("ENTRY '%s' at %L cannot be called recursively, "
+		       "as subroutine '%s' is not RECURSIVE",
+		       csym->name, &c->loc, csym->ns->entries->sym->name);
+	  else
+	    gfc_error ("SUBROUTINE '%s' at %L cannot be called recursively, "
+		       "as it is not RECURSIVE", csym->name, &c->loc);
 
-      t = FAILURE;
+	  t = FAILURE;
+	}
     }
 
   /* Switch off assumed size checking and do this again for certain kinds
Comment 6 janus 2013-01-18 21:29:42 UTC
(In reply to comment #1) 
> I managed to create an ICE-on-invalid-code: The following program segfaults w/o
> printing any error/warning message at

I don't see the ICE with any of 4.6, 4.7 and trunk.
Comment 7 janus 2013-02-12 12:15:40 UTC
Author: janus
Date: Tue Feb 12 12:15:26 2013
New Revision: 195975

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=195975
Log:
2013-02-12  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/46952
	* resolve.c (resolve_call): Do not check deferred procedures for
	recursiveness.


2013-02-12  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/46952
	* gfortran.dg/typebound_deferred_1.f90: New.

Added:
    trunk/gcc/testsuite/gfortran.dg/typebound_deferred_1.f90
Modified:
    trunk/gcc/fortran/ChangeLog
    trunk/gcc/fortran/resolve.c
    trunk/gcc/testsuite/ChangeLog
Comment 8 janus 2013-02-12 12:21:01 UTC
Fixed with r195975. Closing.