This patch is a bit more complicated than some of the previous posts.
However, the ChangeLog explains the story pretty clearly.

Bootstraps and regtests on FC21/x86_64 - OK for trunk and 8-branch?

Again, better names for the testcases will be determined before committing.

Paul


2018-09-25  Paul Thomas  <pa...@gcc.gnu.org>

    PR fortran/70752
    PR fortran/72709
    * trans-array.c (gfc_conv_scalarized_array_ref): If this is a
    deferred type and the info->descriptor is present, use the
    info->descriptor
    (gfc_conv_array_ref): Is the se expr is a descriptor type, pass
    it as 'decl' rather than the symbol backend_decl.
    (gfc_array_allocate): If the se string_length is a component
    reference, fix it and use it for the expression string length.
    Make use of component ref string lengths to set the descriptor
    'span'.
    (gfc_conv_expr_descriptor): For pointer assignment, do not set
    the span field if gfc_get_array_span returns zero.
    * trans.c (get_array_span): If the upper bound a character type
    is zero, use the descriptor span if available.


2018-09-25  Paul Thomas  <pa...@gcc.gnu.org>

    PR fortran/70752
    * gfortran.dg/pr70752.f90 : New test.

    PR fortran/72709
    * gfortran.dg/pr72709.f90 : New test.
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index 9e00eb0..1feba5e 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -3423,7 +3423,9 @@ gfc_conv_scalarized_array_ref (gfc_se * se, gfc_array_ref * ar)
   /* A pointer array component can be detected from its field decl. Fix
      the descriptor, mark the resulting variable decl and pass it to
      gfc_build_array_ref.  */
-  if (is_pointer_array (info->descriptor))
+  if (is_pointer_array (info->descriptor)
+      || (expr && expr->ts.deferred && info->descriptor
+	  && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (info->descriptor))))
     {
       if (TREE_CODE (info->descriptor) == COMPONENT_REF)
 	decl = info->descriptor;
@@ -3676,7 +3678,12 @@ gfc_conv_array_ref (gfc_se * se, gfc_array_ref * ar, gfc_expr *expr,
   else if (expr->ts.deferred
 	   || (sym->ts.type == BT_CHARACTER
 	       && sym->attr.select_type_temporary))
-    decl = sym->backend_decl;
+    {
+      if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (se->expr)))
+	decl = se->expr;
+      else
+	decl = sym->backend_decl;
+    }
   else if (sym->ts.type == BT_CLASS)
     decl = NULL_TREE;

@@ -5761,6 +5768,12 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree status, tree errmsg,

   overflow = integer_zero_node;

+  if (expr->ts.type == BT_CHARACTER
+      && TREE_CODE (se->string_length) == COMPONENT_REF
+      && expr->ts.u.cl->backend_decl != se->string_length)
+    expr->ts.u.cl->backend_decl = gfc_evaluate_now (se->string_length,
+						    &se->pre);
+
   gfc_init_block (&set_descriptor_block);
   /* Take the corank only from the actual ref and not from the coref.  The
      later will mislead the generation of the array dimensions for allocatable/
@@ -5850,10 +5863,25 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree status, tree errmsg,
   /* Pointer arrays need the span field to be set.  */
   if (is_pointer_array (se->expr)
       || (expr->ts.type == BT_CLASS
-	  && CLASS_DATA (expr)->attr.class_pointer))
+	  && CLASS_DATA (expr)->attr.class_pointer)
+      || (expr->ts.type == BT_CHARACTER
+	  && TREE_CODE (se->string_length) == COMPONENT_REF))
     {
       if (expr3 && expr3_elem_size != NULL_TREE)
 	tmp = expr3_elem_size;
+      else if (se->string_length
+	       && TREE_CODE (se->string_length) == COMPONENT_REF)
+	{
+	  if (expr->ts.kind != 1)
+	    {
+	      tmp = build_int_cst (gfc_array_index_type, expr->ts.kind);
+	      tmp = fold_build2_loc (input_location, MULT_EXPR,
+				    gfc_array_index_type,
+				    se->string_length, tmp);
+	    }
+	  else
+	    tmp = se->string_length;
+	}
       else
 	tmp = TYPE_SIZE_UNIT (gfc_get_element_type (TREE_TYPE (se->expr)));
       tmp = fold_convert (gfc_array_index_type, tmp);
@@ -7086,7 +7114,7 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr)

 	      /* ....and set the span field.  */
 	      tmp = gfc_get_array_span (desc, expr);
-	      if (tmp != NULL_TREE)
+	      if (tmp != NULL_TREE && !integer_zerop (tmp))
 		gfc_conv_descriptor_span_set (&se->pre, se->expr, tmp);
 	    }
 	  else if (se->want_pointer)
diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c
index 153bab6..ac583a0 100644
--- a/gcc/fortran/trans.c
+++ b/gcc/fortran/trans.c
@@ -327,6 +327,15 @@ get_array_span (tree type, tree decl)
 					TYPE_SIZE_UNIT (TREE_TYPE (type))),
 			  span);
     }
+  else if (type && TREE_CODE (type) == ARRAY_TYPE
+	   && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != NULL_TREE
+	   && integer_zerop (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
+    {
+      if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl)))
+	span = gfc_conv_descriptor_span_get (decl);
+      else
+	span = NULL_TREE;
+    }
   /* Likewise for class array or pointer array references.  */
   else if (TREE_CODE (decl) == FIELD_DECL
 	   || VAR_OR_FUNCTION_DECL_P (decl)
! { dg-do run }
!
! Test the fix for PR70752 in which the type of the component 'c' is cast
! as character[1:0], which makes it slightly more difficult than usual to
! obtain the element length.  This is one and the same bug as PR72709.
!
! Contributed by Gilbert Scott  <gilbert.sc...@easynet.co.uk>
!
PROGRAM TEST
  IMPLICIT NONE
  INTEGER, PARAMETER :: I = 3
  character (len = i), parameter :: str(5) = ['abc','cde','fgh','ijk','lmn']

  TYPE T
    CHARACTER(LEN=:), ALLOCATABLE :: C(:)
  END TYPE T
  TYPE(T), TARGET :: S
  CHARACTER (LEN=I), POINTER :: P(:)

  ALLOCATE ( CHARACTER(LEN=I) :: S%C(5) )
  s%c = str

! This PR uncovered several problems associated with determining the
! element length and indexing. Test fairly thoroughly!
  if (SIZE(S%C, 1) .ne. 5) stop 1
  if (LEN(S%C) .ne. 3) stop 2
  if (any (s%c .ne. str)) stop 3
  if (s%c(3) .ne. str(3)) stop 4
  P => S%C
  if (SIZE(p, 1) .ne. 5) stop 5
  if (LEN(p) .ne. 3) stop 6
  if (any (p .ne. str)) stop 7
  if (p(5) .ne. str(5)) stop 8
END PROGRAM TEST
! { dg-do run }
!
! Test the fix for PR72709 in which the type of the component 'header' is cast
! as character[1:0], which makes it slightly more difficult than usual to
! obtain the element length. This is one and the same bug as PR70752.
!
! Contributed by 'zmi'  <zmi...@gmail.com>
!
program    read_exp_data
   implicit none

   type experimental_data_t
      integer :: nh = 0
      character(len=:), dimension(:), allocatable :: header

   end type experimental_data_t

   character(*), parameter :: str(3) = ["#Generated by X      ", &
                                        "#from file 'Y'       ", &
                                        "# Experimental 4 mg/g"]
   type(experimental_data_t) :: ex
   integer :: nh_len
   integer :: i


   nh_len = 255
   ex % nh = 3
   allocate(character(len=nh_len) :: ex % header(ex % nh))

   ex % header(1) = str(1)
   ex % header(2) = str(2)
   ex % header(3) = str(3)

! Test that the string length is OK
   if (len (ex%header) .ne. nh_len) stop 1

! Test the array indexing
   do i = 1, ex % nh
      if (trim (ex%header(i)) .ne. trim (str(i))) stop i + 1
   enddo

end program read_exp_data

Reply via email to