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