Bug 92050 - internal compiler error: in gfc_conv_procedure_call
Summary: internal compiler error: in gfc_conv_procedure_call
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: fortran (show other bugs)
Version: 9.2.1
: P4 normal
Target Milestone: 10.0
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-10-10 13:54 UTC by Rémi
Modified: 2019-10-11 13:42 UTC (History)
4 users (show)

See Also:
Host:
Target:
Build:
Known to work: 5.5.0, 6.5.0
Known to fail: 7.4.0, 8.3.0, 9.2.1
Last reconfirmed: 2019-10-11 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Rémi 2019-10-10 13:54:46 UTC
The module in the minimal working example below triggers an internal compiler error when compiled with gfortran -fcheck=all.

- System: Ubuntu 18.04.3 LTS, 4.15.0-65-generic x86_64
- Command line that triggers the bug: gfortran -fcheck=all -c buggy.f95
- Regression: the bug is triggered when the code is compiled with gfortran versions 9, 8, 7, but not with versions 5 and 6.

A few observations:
- Calling the function fun_par() directly rather than the binding "fun" does not trigger the bug: 
      write(*,*) fun_par(this%m(1)%p, x)
- Defining "p" in "comp" using "type(par)" instead of "class(par)" does not trigger the bug.
- Same bug when "p" is specified to be a pointer instead of an allocatable vector.
- When the dimension of the result y in fun_par() is a scalar (y instead of y(size(x))), the bug is not triggered.

============================================================
MINIMAL WORKING EXAMPLE: buggy.f95

module buggy
  implicit none

  type :: par
  contains
    procedure, public :: fun => fun_par
  end type par

  type comp
    class(par), allocatable :: p
  end type comp

  type foo
    type(comp), allocatable :: m(:)
  end type foo

contains

  function fun_par(this)
    class(par) :: this
    integer    :: fun_par(1)
    fun_par = 0
  end function fun_par

  subroutine update_foo(this)
    class(foo) :: this
    write(*,*) this%m(1)%p%fun()
  end subroutine update_foo

end module buggy

============================================================
COMPILER OUTPUTS

The code was tested using gfortran versions 9, 8, 7, 6, and 5:

GNU Fortran (Ubuntu 9.2.1-8ubuntu1~18.04.york0) 9.2.1 20190909
GNU Fortran (Ubuntu 8.3.0-6ubuntu1~18.04.1) 8.3.0
GNU Fortran (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
GNU Fortran (Ubuntu 6.5.0-2ubuntu1~18.04) 6.5.0 20181026
GNU Fortran (Ubuntu 5.5.0-12ubuntu1) 5.5.0 20171010

using gfortran 5 and 6: no errors.

using gfortran 9, 8, and 7:

$ gfortran-9 -fcheck=all -c buggy.f95 
buggy.f95:27:0:

   27 |     write(*,*) this%m(1)%p%fun()
      | 
internal compiler error: in gfc_conv_procedure_call, at fortran/trans-expr.c:6785
Please submit a full bug report,
with preprocessed source if appropriate.
See <file:///usr/share/doc/gcc-9/README.Bugs> for instructions.

$ gfortran-8 -fcheck=all -c buggy.f95 
buggy.f95:27:0:

     write(*,*) this%m(1)%p%fun()
 
internal compiler error: in gfc_conv_procedure_call, at fortran/trans-expr.c:6410
Please submit a full bug report,
with preprocessed source if appropriate.
See <file:///usr/share/doc/gcc-8/README.Bugs> for instructions.

$ gfortran-7 -fcheck=all -c buggy.f95 
buggy.f95:27:0:

     write(*,*) this%m(1)%p%fun()
 
internal compiler error: in gfc_conv_procedure_call, at fortran/trans-expr.c:6290
Please submit a full bug report,
with preprocessed source if appropriate.
See <file:///usr/share/doc/gcc-7/README.Bugs> for instructions.
Comment 1 kargl 2019-10-10 16:59:40 UTC
The ICE is caused by an assert() in the code.  Lines 7020-7035 in
trans-expr.c are the following:

  if (args && args->expr && args->expr->ts.type == BT_CLASS
      && sym->ts.type == BT_CLASS && result != NULL_TREE && DECL_P (result)
      && !GFC_CLASS_TYPE_P (TREE_TYPE (result)))
    {
      gfc_se parmse;
      gfc_expr *class_expr = gfc_find_and_cut_at_last_class_ref (args->expr);

      gfc_init_se (&parmse, NULL);
      gfc_conv_expr (&parmse, class_expr);
      if (!DECL_LANG_SPECIFIC (result))
	gfc_allocate_lang_decl (result);
      GFC_DECL_SAVED_DESCRIPTOR (result) = parmse.expr;
      gfc_free_expr (class_expr);
//      gcc_assert (parmse.pre.head == NULL_TREE
//		  && parmse.post.head == NULL_TREE);
    }

Commenting out the assert allows the code to compile with
-fcheck=bounds.  The code was added in revision 241439 by
Andre Vehreschild on 2016-10-22.  Andre, the assert be 
removed or hidden behind flag_bounds_check?
Comment 2 Steve Kargl 2019-10-10 17:25:10 UTC
This patch allows the code to compile, but I have no idea
if it is correct.

Index: trans-expr.c
===================================================================
--- trans-expr.c        (revision 276837)
+++ trans-expr.c        (working copy)
@@ -7031,8 +7031,10 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym
        gfc_allocate_lang_decl (result);
       GFC_DECL_SAVED_DESCRIPTOR (result) = parmse.expr;
       gfc_free_expr (class_expr);
-      gcc_assert (parmse.pre.head == NULL_TREE
-                 && parmse.post.head == NULL_TREE);
+      if ((gfc_option.rtcheck & GFC_RTCHECK_BOUNDS)
+         && parmse.pre.head == NULL_TREE)
+       gcc_unreachable ();
+      gcc_assert (parmse.post.head == NULL_TREE);
     }
 
   /* Follow the function call with the argument post block.  */
Comment 3 Steve Kargl 2019-10-10 17:45:28 UTC
On Thu, Oct 10, 2019 at 05:25:10PM +0000, sgk at troutmask dot apl.washington.edu wrote:
> --- Comment #2 from Steve Kargl <sgk at troutmask dot apl.washington.edu> ---
> This patch allows the code to compile, but I have no idea
> if it is correct.
> 
> Index: trans-expr.c
> ===================================================================
> --- trans-expr.c        (revision 276837)
> +++ trans-expr.c        (working copy)
> @@ -7031,8 +7031,10 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym
>         gfc_allocate_lang_decl (result);
>        GFC_DECL_SAVED_DESCRIPTOR (result) = parmse.expr;
>        gfc_free_expr (class_expr);
> -      gcc_assert (parmse.pre.head == NULL_TREE
> -                 && parmse.post.head == NULL_TREE);
> +      if ((gfc_option.rtcheck & GFC_RTCHECK_BOUNDS)
> +         && parmse.pre.head == NULL_TREE)
> +       gcc_unreachable ();
> +      gcc_assert (parmse.post.head == NULL_TREE);
>      }

Bummer patch causes regression.  The only fix seems to
be to remove the assert that parmse.pre.head == NULL_TREE.
Comment 4 Tobias Burnus 2019-10-11 07:53:00 UTC
I think something like the following should work:

diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index 965ab7786a1..65238ff623d 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -7031,8 +7031,11 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 	gfc_allocate_lang_decl (result);
       GFC_DECL_SAVED_DESCRIPTOR (result) = parmse.expr;
       gfc_free_expr (class_expr);
-      gcc_assert (parmse.pre.head == NULL_TREE
-		  && parmse.post.head == NULL_TREE);
+      /* -fcheck= can add diagnostic code, which has to be placed before
+	 the call. */
+      if (parmse.pre.head != NULL)
+	  gfc_add_expr_to_block (&se->pre, parmse.pre.head);
+      gcc_assert (parmse.post.head == NULL_TREE);
     }
 
   /* Follow the function call with the argument post block.  */
Comment 5 Tobias Burnus 2019-10-11 13:41:45 UTC
Author: burnus
Date: Fri Oct 11 13:41:13 2019
New Revision: 276885

URL: https://gcc.gnu.org/viewcvs?rev=276885&root=gcc&view=rev
Log:
Fortran] PR 92050 - fix ICE with -fcheck=all

        gcc/fortran/
        PR fortran/92050
        * trans-expr.c (gfc_conv_procedure_call): Handle code generated
        by -fcheck=all.

        gcc/testsuite/
        PR fortran/92050
        * gfortran.dg/pr92050.f90: New.


Added:
    trunk/gcc/testsuite/gfortran.dg/pr92050.f90
Modified:
    trunk/gcc/fortran/ChangeLog
    trunk/gcc/fortran/trans-expr.c
    trunk/gcc/testsuite/ChangeLog
Comment 6 Tobias Burnus 2019-10-11 13:42:32 UTC
FIXED on the trunk (GCC 10).

Thanks for the report!