Dear All,

when a type-spec was provided with a character array constructor,
it seemed to get "lost" when passing the array constructor to
a procedure, even to the LEN() intrinsic.

The attached patch fixes this, enables simplification of LEN()
when passed an array constructor with type-spec, and also adds
the type-spec to the fortran dump.

Regtested on x86_64-pc-linux-gnu.  OK for mainline?

Thanks,
Harald

From 6774eb3fd3762a663c82d5a8c0993d033e87f67d Mon Sep 17 00:00:00 2001
From: Harald Anlauf <[email protected]>
Date: Mon, 5 Jan 2026 21:20:11 +0100
Subject: [PATCH] Fortran: fix string length for array constructors with
 type-spec [PR85547]

	PR fortran/85547

gcc/fortran/ChangeLog:

	* decl.cc (gfc_match_volatile): Fix frontend memleak.
	(gfc_match_asynchronous): Likewise.
	* dump-parse-tree.cc (show_expr): Show type-spec for character
	array constructor when given.
	* simplify.cc (gfc_simplify_len): Simplify LEN() when type-spec
	is provided for character array constructor.
	* trans-array.cc (get_array_charlen): If there is an explicit
	type-spec, use it.
	(gfc_conv_array_parameter): Likewise.
	* trans-intrinsic.cc (gfc_conv_intrinsic_len): Likewise.

gcc/testsuite/ChangeLog:

	* gfortran.dg/string_length_5.f90: New test.
---
 gcc/fortran/decl.cc                           |  4 +-
 gcc/fortran/dump-parse-tree.cc                |  8 ++
 gcc/fortran/simplify.cc                       | 15 ++++
 gcc/fortran/trans-array.cc                    | 22 ++++-
 gcc/fortran/trans-intrinsic.cc                |  8 ++
 gcc/testsuite/gfortran.dg/string_length_5.f90 | 82 +++++++++++++++++++
 6 files changed, 135 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/string_length_5.f90

diff --git a/gcc/fortran/decl.cc b/gcc/fortran/decl.cc
index 3d0410501b6..72e202f5a8a 100644
--- a/gcc/fortran/decl.cc
+++ b/gcc/fortran/decl.cc
@@ -10385,7 +10385,7 @@ gfc_match_volatile (void)
       switch (m)
 	{
 	case MATCH_YES:
-	  name = XCNEWVAR (char, strlen (sym->name) + 1);
+	  name = XALLOCAVAR (char, strlen (sym->name) + 1);
 	  strcpy (name, sym->name);
 	  if (!check_function_name (name))
 	    return MATCH_ERROR;
@@ -10449,7 +10449,7 @@ gfc_match_asynchronous (void)
       switch (m)
 	{
 	case MATCH_YES:
-	  name = XCNEWVAR (char, strlen (sym->name) + 1);
+	  name = XALLOCAVAR (char, strlen (sym->name) + 1);
 	  strcpy (name, sym->name);
 	  if (!check_function_name (name))
 	    return MATCH_ERROR;
diff --git a/gcc/fortran/dump-parse-tree.cc b/gcc/fortran/dump-parse-tree.cc
index b51414c13e2..028c946d2d9 100644
--- a/gcc/fortran/dump-parse-tree.cc
+++ b/gcc/fortran/dump-parse-tree.cc
@@ -545,6 +545,14 @@ show_expr (gfc_expr *p)
 
     case EXPR_ARRAY:
       fputs ("(/ ", dumpfile);
+      if (p->ts.type == BT_CHARACTER
+	  && p->ts.u.cl
+	  && p->ts.u.cl->length_from_typespec
+	  && p->ts.u.cl->length)
+	{
+	  show_typespec (&p->ts);
+	  fputs (" :: ", dumpfile);
+	}
       show_constructor (p->value.constructor);
       fputs (" /)", dumpfile);
 
diff --git a/gcc/fortran/simplify.cc b/gcc/fortran/simplify.cc
index a3af457b5de..c6291d7ea1d 100644
--- a/gcc/fortran/simplify.cc
+++ b/gcc/fortran/simplify.cc
@@ -5083,6 +5083,21 @@ gfc_simplify_len (gfc_expr *e, gfc_expr *kind)
 	    }
 	}
     }
+  else if (e->expr_type == EXPR_ARRAY && e->ts.type == BT_CHARACTER
+	   && e->ts.u.cl
+	   && e->ts.u.cl->length_from_typespec
+	   && e->ts.u.cl->length
+	   && e->ts.u.cl->length->ts.type == BT_INTEGER)
+    {
+      gfc_typespec ts;
+      gfc_clear_ts (&ts);
+      ts.type = BT_INTEGER;
+      ts.kind = k;
+      result = gfc_copy_expr (e->ts.u.cl->length);
+      gfc_convert_type_warn (result, &ts, 2, 0);
+      return result;
+    }
+
   return NULL;
 }
 
diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 0b0d50263e9..d2ba00c37f2 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -8081,6 +8081,14 @@ get_array_charlen (gfc_expr *expr, gfc_se *se)
       return;
     }
 
+  /* If there is an explicit type-spec, use it.  */
+  if (expr->ts.u.cl->length && expr->ts.u.cl->length_from_typespec)
+    {
+      if (!expr->ts.u.cl->backend_decl)
+	gfc_conv_string_length (expr->ts.u.cl, expr, &se->pre);
+      return;
+    }
+
   switch (expr->expr_type)
     {
     case EXPR_ARRAY:
@@ -9211,8 +9219,18 @@ gfc_conv_array_parameter (gfc_se *se, gfc_expr *expr, bool g77,
 
   if (expr->expr_type == EXPR_ARRAY && expr->ts.type == BT_CHARACTER)
     {
-      get_array_ctor_strlen (&se->pre, expr->value.constructor, &tmp);
-      expr->ts.u.cl->backend_decl = tmp;
+      /* If there is an explicit type-spec, use it.  Otherwise obtain the
+	 string length from the constructor.  */
+      if (expr->ts.u.cl->length && expr->ts.u.cl->length_from_typespec)
+	{
+	  gfc_conv_string_length (expr->ts.u.cl, expr, &se->pre);
+	  tmp = expr->ts.u.cl->backend_decl;
+	}
+      else
+	{
+	  get_array_ctor_strlen (&se->pre, expr->value.constructor, &tmp);
+	  expr->ts.u.cl->backend_decl = tmp;
+	}
       se->string_length = tmp;
     }
 
diff --git a/gcc/fortran/trans-intrinsic.cc b/gcc/fortran/trans-intrinsic.cc
index 722ea933249..01a662520e0 100644
--- a/gcc/fortran/trans-intrinsic.cc
+++ b/gcc/fortran/trans-intrinsic.cc
@@ -7647,6 +7647,14 @@ gfc_conv_intrinsic_len (gfc_se * se, gfc_expr * expr)
       break;
 
     case EXPR_ARRAY:
+      /* If there is an explicit type-spec, use it.  */
+      if (arg->ts.u.cl->length && arg->ts.u.cl->length_from_typespec)
+	{
+	  gfc_conv_string_length (arg->ts.u.cl, arg, &se->pre);
+	  len = arg->ts.u.cl->backend_decl;
+	  break;
+	}
+
       /* Obtain the string length from the function used by
          trans-array.cc(gfc_trans_array_constructor).  */
       len = NULL_TREE;
diff --git a/gcc/testsuite/gfortran.dg/string_length_5.f90 b/gcc/testsuite/gfortran.dg/string_length_5.f90
new file mode 100644
index 00000000000..96a6b9189e1
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/string_length_5.f90
@@ -0,0 +1,82 @@
+! { dg-do run }
+! PR fortran/85547 - string length for array constructors with type-spec
+!
+! Reported by Walter Spector
+
+program p
+  implicit none
+  integer, parameter :: k = 16
+  integer            :: m = k
+  integer, volatile  :: n = k
+  character(10)      :: path  = 'xyz/'
+  character(8)       :: path2 = 'abc/'
+  if (k /= len ( [ character(k) :: path ]        )) stop 1
+  if (k /= len ( [ character(m) :: path ]        )) stop 2
+  if (k /= len ( [ character(n) :: path ]        )) stop 3
+  if (k /= len ( [ character(k) :: path ] ,kind=2)) stop 4
+  if (k /= len ( [ character(m) :: path ] ,kind=2)) stop 5
+  if (k /= len ( [ character(n) :: path ] ,kind=2)) stop 6
+
+  if (k /= len ( [ character(k) ::      ]        )) stop 7
+  if (k /= len ( [ character(m) ::      ]        )) stop 8
+  if (k /= len ( [ character(n) ::      ]        )) stop 9
+  if (k /= len ( [ character(k) ::      ] ,kind=2)) stop 10
+  if (k /= len ( [ character(m) ::      ] ,kind=2)) stop 11
+  if (k /= len ( [ character(n) ::      ] ,kind=2)) stop 12
+  if (k /= len ( [ character(2*n/2) ::  ]        )) stop 13
+  if (k /= len ( [ character(2*n/2) ::  ] ,kind=2)) stop 14
+  if (k /= len ( [ character((m+n)/2) ::] ,kind=2)) stop 15
+  if (k /= len ( [ character((m+n)/2) ::] ,kind=2)) stop 16
+  if (k /= len ([[ character(k) ::      ]],kind=2)) stop 17
+  if (k /= len ([[ character(m) ::      ]],kind=2)) stop 18
+  if (k /= len ([[ character(n) ::      ]],kind=2)) stop 19
+  if (k /= len ([[ character((m+n)/2) ::]],kind=2)) stop 20
+
+  if (k /= len ( [ character(k)       :: path,path2 ] ,kind=2)) stop 21
+  if (k /= len ( [ character(m)       :: path,path2 ] ,kind=2)) stop 22
+  if (k /= len ( [ character(n)       :: path,path2 ] ,kind=2)) stop 23
+  if (k /= len ( [ character((m+n)/2) :: path,path2 ] ,kind=2)) stop 24
+  if (k /= len ([[ character(k)       :: path,path2 ]],kind=2)) stop 25
+  if (k /= len ([[ character(m)       :: path,path2 ]],kind=2)) stop 26
+  if (k /= len ([[ character(n)       :: path,path2 ]],kind=2)) stop 27
+  if (k /= len ([[ character((m+n)/2) :: path,path2 ]],kind=2)) stop 28
+
+  call sub ()
+contains
+  subroutine sub ()
+    call print_string (31, [ character(k)       :: ] )
+    call print_string (32, [ character(m)       :: ] )
+    call print_string (33, [ character(n)       :: ] )
+    call print_string (34, [ character((m+n)/2) :: ] )
+    call print_string (35, [ character(k)       :: path ] )
+    call print_string (36, [ character(m)       :: path ] )
+    call print_string (37, [ character(n)       :: path ] )
+    call print_string (38, [ character((m+n)/2) :: path ] )
+    call print_string (39, [ character(k)       :: path,path2 ] )
+    call print_string (40, [ character(m)       :: path,path2 ] )
+    call print_string (41, [ character(n)       :: path,path2 ] )
+    call print_string (42, [ character((m+n)/2) :: path,path2 ] )
+
+    call print_string (51,[[ character(k)       :: ]])
+    call print_string (52,[[ character(m)       :: ]])
+    call print_string (53,[[ character(n)       :: ]])
+    call print_string (54,[[ character((m+n)/2) :: ]])
+    call print_string (55,[[ character(k)       :: path ]])
+    call print_string (56,[[ character(m)       :: path ]])
+    call print_string (57,[[ character(n)       :: path ]])
+    call print_string (58,[[ character((m+n)/2) :: path ]])
+    call print_string (59,[[ character(k)       :: path,path2 ]])
+    call print_string (60,[[ character(m)       :: path,path2 ]])
+    call print_string (61,[[ character(n)       :: path,path2 ]])
+    call print_string (62,[[ character((m+n)/2) :: path,path2 ]])
+  end subroutine sub
+
+  subroutine print_string (i, s)
+    integer,      intent(in) :: i
+    character(*), intent(in) :: s(:)
+    if (len(s) /= k) then
+       print *, i, len(s), len(s)==k, size (s), s(:)
+       stop i
+    end if
+  end subroutine
+end program
-- 
2.51.0

Reply via email to