https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95868

            Bug ID: 95868
           Summary: Derived-type deferred-length character component
                    handling broken
           Product: gcc
           Version: 10.0
            Status: UNCONFIRMED
          Keywords: ice-on-valid-code, wrong-code
          Severity: normal
          Priority: P3
         Component: fortran
          Assignee: unassigned at gcc dot gnu.org
          Reporter: burnus at gcc dot gnu.org
  Target Milestone: ---

The following program fails with an ICE or a segfault.

Issues I observed:

* For the ICE, the issue seems to be:
  gfc_conv_loop_setup() calls
    gfc_add_loop_ss_code (loop, loop->ss, false, where)
      expr = ss_info->expr;
         case GFC_SS_SCALAR:
          gfc_conv_expr (&se, expr);
  → The ICE occur because expr == NULL and expr is dereferenced.

  I am not sure whether it is the following code, but it sets
  ss-info->expr and I bet ss.end == NULL in my testcase, but I
  have not check it: 
    gfc_walk_array_ref()
      if (ref->type == REF_SUBSTRING)
        {
          ss = gfc_get_scalar_ss (ss, ref->u.ss.start);
          ss = gfc_get_scalar_ss (ss, ref->u.ss.end);
        }
    and the second argument is the 'expr'.


* For derived-type deferred strings, one often has the intcst "0" in the tree.
  for gfc_conv_expr_descriptor, for the simple case, that's handled
  (search: deferred_array_component).
  However, for the complicated case, one might end up with
    "0 = 0;"
  which the gimplifier does not like.
  I am not sure whether the patch is correct, but it fixes one testcase
  for me (not shown, OpenMP one) and looks more sensible. I am not sure
  whether VAR_P(se->string_length) makes sense and when it gets set or
  defined. 

diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index 54e1107c711..6da8c6d5595 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -7551,15 +7551,14 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr)
       /* Set the string_length for a character array.  */
       if (expr->ts.type == BT_CHARACTER)
        {
-         se->string_length =  gfc_get_expr_charlen (expr);
-         if (VAR_P (se->string_length)
-             && expr->ts.u.cl->backend_decl == se->string_length)
-           tmp = ss_info->string_length;
-         else
-           tmp = se->string_length;
-
-         if (expr->ts.deferred)
-           gfc_add_modify (&se->pre, expr->ts.u.cl->backend_decl, tmp);
+         tmp = gfc_get_expr_charlen (expr);
+         if (!VAR_P (expr->ts.u.cl->backend_decl))
+           se->string_length = (expr->ts.deferred ? ss_info->string_length
+                                                  : tmp);
+         else if (expr->ts.deferred
+                  && se->string_length != expr->ts.u.cl->backend_decl)
+           gfc_add_modify (&se->pre, expr->ts.u.cl->backend_decl,
+                           ss_info->string_length);
        }

       /* If we have an array section, are assigning  or passing an array

--------------
implicit none
type t
  character(len=:), allocatable :: str(:)
end type t
type (t) :: var
character(len=:), allocatable :: str(:)
integer :: i

allocate(character(len=3) :: str(3))
str(:) = ["abc", "def", "ghi"]
!call dummy(str)        ! OK
!call dummy(str(2:))    ! OK
!call dummy(str(:)(2:)) ! (1) ICE

!call sub1(str)         ! OK
!call sub2(str(2:))     ! (2) Segfault at runtime
!call sub3(str(:)(2:))  ! (3) ICE

var%str = ["abc", "def", "ghi"]
!call sub1(var%str)        ! (4) Fails at runtime ('stop 1')
!call sub2(var%str(2:))    ! (5) Fails at runtime ('stop 1')
!call sub3(var%str(:)(2:)) ! ICE
deallocate(str,var%str)
contains
  subroutine dummy(x)
    character(len=1), dimension(*) :: x
  end
  subroutine sub1(x)
    character(len=*), dimension(*) :: x
    if (len(x) /= 3) stop 1
    if (any (x(1:3) /= ["abc", "def", "ghi"])) stop 2
  end
  subroutine sub2(x)
    character(len=*), dimension(*) :: x
    if (len(x) /= 3) stop 3
    if (any (x(1:2) /= ["def", "ghi"])) stop 4
  end
  subroutine sub3(x)
    character(len=*), dimension(*) :: x
    if (len(x) /= 2) stop 5
    if (any (x(1:3) /= ["bc", "ef", "hi"])) stop 6
  end
end

Reply via email to