Hi All,

Harald has pointed out that I attached the ChangeLog twice and the patch
not at all :-(

Please find the patch duly attached.

Paul


On Sat, 13 Jul 2024 at 10:58, Paul Richard Thomas <
paul.richard.tho...@gmail.com> wrote:

> Hi All,
>
> After messing around with argument mapping, where I found and fixed
> another bug, I realised that the problem lay with simplification of
> len_trim with an argument that is the element of a parameter array. The fix
> was then a straightforward lift of existing code in expr.cc. The mapping
> bug is also fixed by supplying the se string length when building character
> typespecs.
>
> Regtests just fine. OK for mainline? I believe that this is safe for
> backporting to 14-branch before the 14.2 release - thoughts?
>
> Regards
>
> Paul
>
diff --git a/gcc/fortran/simplify.cc b/gcc/fortran/simplify.cc
index 7a5d31c01a6..5199ede98fe 100644
--- a/gcc/fortran/simplify.cc
+++ b/gcc/fortran/simplify.cc
@@ -4637,6 +4637,76 @@ gfc_simplify_len_trim (gfc_expr *e, gfc_expr *kind)
   if (k == -1)
     return &gfc_bad_expr;
 
+  if (e->expr_type == EXPR_VARIABLE
+      && e->ts.type == BT_CHARACTER
+      && e->symtree->n.sym->attr.flavor == FL_PARAMETER
+      && e->ref && e->ref->type == REF_ARRAY
+      && e->ref->u.ar.dimen_type[0] == DIMEN_ELEMENT
+      && e->symtree->n.sym->value)
+    {
+      char name[GFC_MAX_SYMBOL_LEN + 10];
+      gfc_namespace *ns = e->symtree->n.sym->ns;
+      gfc_symtree *st;
+      gfc_expr *expr;
+      gfc_expr *p;
+      gfc_constructor *c;
+      int cnt = 0;
+
+      sprintf (name, "_len_trim_%s", e->symtree->n.sym->name);
+      st = gfc_find_symtree (ns->sym_root, name);
+      if (st)
+	goto already_built;
+
+      /* Recursively call this fcn to simplify the constructor elements.  */
+      expr = gfc_copy_expr (e->symtree->n.sym->value);
+      expr->ts.type = BT_INTEGER;
+      expr->ts.kind = k;
+      expr->ts.u.cl = NULL;
+      expr->rank = 1;
+      c = gfc_constructor_first (expr->value.constructor);
+      for (; c; c = gfc_constructor_next (c))
+	{
+	  if (c->iterator)
+	    continue;
+
+	  if (c->expr && c->expr->ts.type == BT_CHARACTER)
+	    {
+	      p = gfc_simplify_len_trim (c->expr, kind);
+	      if (p == NULL)
+		goto clean_up;
+	      gfc_replace_expr (c->expr, p);
+	      cnt++;
+	    }
+	}
+
+      if (cnt)
+	{
+	  /* Build a new parameter to take the result.  */
+	  st = gfc_new_symtree (&ns->sym_root, name);
+	  st->n.sym = gfc_new_symbol (st->name, ns);
+	  st->n.sym->value = expr;
+	  st->n.sym->ts = expr->ts;
+	  st->n.sym->attr.dimension = 1;
+	  st->n.sym->attr.save = SAVE_IMPLICIT;
+	  st->n.sym->attr.flavor = FL_PARAMETER;
+	  st->n.sym->as = gfc_copy_array_spec (e->symtree->n.sym->as);
+	  gfc_set_sym_referenced (st->n.sym);
+	  st->n.sym->refs++;
+
+already_built:
+	  /* Build a return expression.  */
+	  expr = gfc_copy_expr (e);
+	  expr->ts = st->n.sym->ts;
+	  expr->symtree = st;
+	  expr->rank = 0;
+	  return expr;
+	}
+
+clean_up:
+      gfc_free_expr (expr);
+      return NULL;
+    }
+
   if (e->expr_type != EXPR_CONSTANT)
     return NULL;
 
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 477c2720187..fe872a661ec 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -4490,12 +4490,15 @@ gfc_get_interface_mapping_charlen (gfc_interface_mapping * mapping,
 
 static tree
 gfc_get_interface_mapping_array (stmtblock_t * block, gfc_symbol * sym,
-				 gfc_packed packed, tree data)
+				 gfc_packed packed, tree data, tree len)
 {
   tree type;
   tree var;
 
-  type = gfc_typenode_for_spec (&sym->ts);
+  if (len != NULL_TREE && (TREE_CONSTANT (len) || VAR_P (len)))
+    type = gfc_get_character_type_len (sym->ts.kind, len);
+  else
+    type = gfc_typenode_for_spec (&sym->ts);
   type = gfc_get_nodesc_array_type (type, sym->as, packed,
 				    !sym->attr.target && !sym->attr.pointer
 				    && !sym->attr.proc_pointer);
@@ -4642,7 +4645,8 @@ gfc_add_interface_mapping (gfc_interface_mapping * mapping,
      convert it to a boundless character type.  */
   else if (!sym->attr.dimension && sym->ts.type == BT_CHARACTER)
     {
-      tmp = gfc_get_character_type_len (sym->ts.kind, NULL);
+      se->string_length = gfc_evaluate_now (se->string_length, &se->pre);
+      tmp = gfc_get_character_type_len (sym->ts.kind, se->string_length);
       tmp = build_pointer_type (tmp);
       if (sym->attr.pointer)
         value = build_fold_indirect_ref_loc (input_location,
@@ -4661,7 +4665,7 @@ gfc_add_interface_mapping (gfc_interface_mapping * mapping,
   /* For character(*), use the actual argument's descriptor.  */
   else if (sym->ts.type == BT_CHARACTER && !new_sym->ts.u.cl->length)
     value = build_fold_indirect_ref_loc (input_location,
-				     se->expr);
+					 se->expr);
 
   /* If the argument is an array descriptor, use it to determine
      information about the actual argument's shape.  */
@@ -4675,7 +4679,8 @@ gfc_add_interface_mapping (gfc_interface_mapping * mapping,
       /* Create the replacement variable.  */
       tmp = gfc_conv_descriptor_data_get (desc);
       value = gfc_get_interface_mapping_array (&se->pre, sym,
-					       PACKED_NO, tmp);
+					       PACKED_NO, tmp,
+					       se->string_length);
 
       /* Use DESC to work out the upper bounds, strides and offset.  */
       gfc_set_interface_mapping_bounds (&se->pre, TREE_TYPE (value), desc);
@@ -4683,7 +4688,8 @@ gfc_add_interface_mapping (gfc_interface_mapping * mapping,
   else
     /* Otherwise we have a packed array.  */
     value = gfc_get_interface_mapping_array (&se->pre, sym,
-					     PACKED_FULL, se->expr);
+					     PACKED_FULL, se->expr,
+					     se->string_length);
 
   new_sym->backend_decl = value;
 }
diff --git a/gcc/testsuite/gfortran.dg/pr84868.f90 b/gcc/testsuite/gfortran.dg/pr84868.f90
new file mode 100644
index 00000000000..eb9cb67e14a
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr84868.f90
@@ -0,0 +1,60 @@
+! { dg-do run }
+!
+! Test the fix for PR84868. Module 'orig' and the call to 'f_orig' is the
+! original bug. The rest tests variants and the fix for a gimplifier ICE.
+!
+! Contributed by Gerhard Steinmetx  <gs...@t-online.de>
+!
+module orig
+   character(:), allocatable :: c
+contains
+   function f_orig(n) result(z)
+      character(2), parameter :: c(3) = ['x1', 'y ', 'z2']
+      integer, intent(in) :: n
+      character(len_trim(c(n))) :: z
+      z = c(n)
+   end
+end module orig
+
+module m
+   character(:), allocatable :: c
+contains
+   function f(n, c) result(z)
+      character (2) :: c(:)
+      integer, intent(in) :: n
+      character(len_trim(c(n))) :: z
+      z = c(n)
+   end
+   subroutine foo (pc)
+     character(2) :: pc(:)
+     if (any ([(len (f(i, pc)), i = 1,3)] .ne. [2,1,2])) stop 1
+   end
+end
+program p
+   use m
+   use orig
+   character (2) :: pc(3) = ['x1', 'y ', 'z2']
+   integer :: i
+
+   if (any ([(len (f_orig(i)), i = 1,3)] .ne. [2,1,2])) stop 2 ! ICE
+
+   call foo (pc)
+   if (any ([(len (g(i, pc)), i = 1,3)] .ne. [2,1,2])) stop 3
+   if (any ([(bar1(i), i = 1,3)] .ne. [2,1,2])) stop 4
+   if (any ([(bar2(i), i = 1,3)] .ne. [2,1,2])) stop 5
+contains
+   function g(n, c) result(z)
+      character (2) :: c(:)
+      integer, intent(in) :: n
+      character(len_trim(c(n))) :: z
+      z = c(n)
+   end
+   integer function bar1 (i)
+     integer :: i
+     bar1 = len (f(i, pc))  ! ICE in is_gimple_min_invariant
+   end
+   integer function bar2 (i)
+     integer :: i
+     bar2 = len (g(i, pc))
+   end
+end

Reply via email to