Dear all,

here's a quite obvious fix for an ICE when processing an array constructor
where the first element is of deferred length, and at least four constant
elements followed, or an iterator with at least four elements.  There
is a code path that then tries to combine these constant elements and
take the element size of the first (variable length) element in the
constructor.

(For gcc with checking=release, no ICE occured; wrong code was generated
instead.)

Obvious fix: if we see that the element size is not constant, falls back
to the case handling the constructor element-wise.

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

Thanks,
Harald

From 5b264e77b54e211c7781d2c2e5dc324846a774a1 Mon Sep 17 00:00:00 2001
From: Harald Anlauf <anl...@gmx.de>
Date: Thu, 18 Jul 2024 21:15:48 +0200
Subject: [PATCH] Fortran: character array constructor with >= 4 constant
 elements [PR103115]

gcc/fortran/ChangeLog:

	PR fortran/103115
	* trans-array.cc (gfc_trans_array_constructor_value): If the first
	element of an array constructor is deferred-length character and
	therefore does not have an element size known at compile time, do
	not try to collect subsequent constant elements into a constructor
	for optimization.

gcc/testsuite/ChangeLog:

	PR fortran/103115
	* gfortran.dg/string_array_constructor_4.f90: New test.
---
 gcc/fortran/trans-array.cc                    |  4 +-
 .../string_array_constructor_4.f90            | 59 +++++++++++++++++++
 2 files changed, 62 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gfortran.dg/string_array_constructor_4.f90

diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index dc3de6c3b14..c93a5f1e754 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -2147,7 +2147,9 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock,
 	      p = gfc_constructor_next (p);
 	      n++;
 	    }
-	  if (n < 4)
+	  /* Constructor with few constant elements, or element size not
+	     known at compile time (e.g. deferred-length character).  */
+	  if (n < 4 || !INTEGER_CST_P (TYPE_SIZE_UNIT (type)))
 	    {
 	      /* Scalar values.  */
 	      gfc_init_se (&se, NULL);
diff --git a/gcc/testsuite/gfortran.dg/string_array_constructor_4.f90 b/gcc/testsuite/gfortran.dg/string_array_constructor_4.f90
new file mode 100644
index 00000000000..b5b81f07395
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/string_array_constructor_4.f90
@@ -0,0 +1,59 @@
+! { dg-do run }
+! PR fortran/103115 - character array constructor with >= 4 constant elements
+!
+! This used to ICE when the first element is deferred-length character
+! or could lead to wrong results.
+
+program pr103115
+  implicit none
+  integer :: i
+  character(*), parameter :: expect(*) = [ "1","2","3","4","5" ]
+  character(5)            :: abc = "12345"
+  character(5), parameter :: def = "12345"
+  character(:), dimension(:), allocatable :: list
+  character(:), dimension(:), allocatable :: titles
+  titles = ["1"]
+  titles = [ titles&
+            ,"2"&
+            ,"3"&
+            ,"4"&
+            ,"5"&  ! used to ICE
+            ]
+  if (len (titles) /= 1 .or. size (titles) /= 5) stop 1
+  if (any (titles  /= expect))                   stop 2
+  titles = ["1"]
+  titles = [ titles, (char(48+i),i=2,5) ]
+  if (len (titles) /= 1 .or. size (titles) /= 5) stop 3
+  if (any (titles  /= expect))                   stop 4
+  titles = ["1"]
+  titles = [ titles, ("2345"(i:i),i=1,4) ]
+  if (len (titles) /= 1 .or. size (titles) /= 5) stop 5
+  if (any (titles  /= expect))                   stop 6
+  titles = ["1"]
+  titles = [ titles, (def(i:i),i=2,5) ]
+  if (len (titles) /= 1 .or. size (titles) /= 5) stop 7
+  if (any (titles  /= expect))                   stop 8
+  list = [ (char(48+i),i=1,5) ]
+  titles = [ list(1), (char(48+i),i=2,5) ]
+  if (len (titles) /= 1 .or. size (titles) /= 5) stop 9
+  if (any (titles  /= expect))                   stop 10
+  titles = ["1"]
+  titles = [ titles, (abc(i:i),i=2,5) ]
+  if (len (titles) /= 1 .or. size (titles) /= 5) stop 11
+  if (any (titles  /= expect))                   stop 12
+
+  ! with typespec:
+  list = [ (char(48+i),i=1,5) ]
+  titles = [ character(2) :: list(1), (char(48+i),i=2,5) ]
+  if (len (titles) /= 2 .or. size (titles) /= 5) stop 13
+  if (any (titles  /= expect))                   stop 14
+  titles = ["1"]
+  titles = [ character(2) :: titles, (char(48+i),i=2,5) ]
+  if (len (titles) /= 2 .or. size (titles) /= 5) stop 15
+  if (any (titles  /= expect))                   stop 16
+  titles = ["1"]
+  titles = [ character(2) :: titles, (def(i:i),i=2,5) ]
+  if (len (titles) /= 2 .or. size (titles) /= 5) stop 17
+  if (any (titles  /= expect))                   stop 18
+  deallocate (titles, list)
+end
--
2.35.3

Reply via email to