Hi Chris!

Am 30.11.25 um 15:57 schrieb Christopher Albert:
When an array constructor has an explicit type-spec, all elements must
be converted to that type and character elements must be
padded/truncated to the specified length.  This was working for simple
cases but failing when:

1. Elements were parenthesized: [integer :: ([1.0])]
2. Constructors were nested: [[integer :: [1.0]]]
3. Character constructors were used with concatenation operators:
    [character(16) :: 'a', 'b'] // '|'
4. Nested character constructors with concatenation:
    [character(16) :: ['a', 'b']] // '|'
5. Outer constructor without type-spec wrapping inner with type-spec:
    [[character(16) :: ['a', 'b']]] // '|'
6. Nested character constructors with different type-specs:
    [character(16) :: [character(2) :: 'abcd']]

The root cause was twofold:

First, parenthesized expressions like ([1.0]) create EXPR_OP nodes that
were not being simplified before type conversion in
check_constructor_type(), so type conversion was applied to the EXPR_OP
rather than its contents.

Second, character array constructors with explicit type-spec were not
being resolved before CONCAT operations in eval_intrinsic(), so
elements retained their original lengths instead of being padded to the
type-spec length. Additionally, nested array constructors needed their
type-spec propagated from the outer constructor.

The fix adds:
- Simplification of non-constant expressions in check_constructor_type()
   before attempting type conversion
- Call to gfc_check_constructor_type() in eval_intrinsic() to ensure
   type-spec conversion happens before any operations on array
constructors
- Character array constructor resolution before CONCAT operations
- Recursive type-spec propagation for nested array constructors.
   When a nested array constructor has its own explicit type-spec, it is
   resolved first to enforce its own length (truncation/padding) before
   propagating the outer type-spec and resolving again.
- Detection of nested character constructors with explicit type-spec
   (via length_from_typespec) when the outer constructor has no type-spec

        PR fortran/107721
        PR fortran/102417

gcc/fortran/ChangeLog:

        * arith.cc (eval_intrinsic): Call gfc_check_constructor_type on
        array constructor operands with explicit type-spec to ensure
        element type conversion before operations.  Resolve character
        array constructors before CONCAT operations.
        (reduce_binary_ac, reduce_binary_ca, reduce_binary_aa): Preserve
        character length info in result arrays.
        * array.cc (check_constructor_type): Simplify non-constant
        expressions before type checking to handle parenthesized
          elements. Handle nested character array constructors with
          explicit type-spec when outer constructor has no type-spec.
        (gfc_resolve_character_array_constructor): Recursively propagate
        type-spec to nested array constructors.  If the nested
          constructor has an explicit type-spec, resolve it first
          before propagating the outer type-spec.

gcc/testsuite/ChangeLog:

        * gfortran.dg/array_constructor_typespec_1.f90: New test.

First of all thanks for your stamina to work on these PRs,
and to incorporating all feedback during the evolution of
this patch!

The gfortran changes look good to me.  There are several white-space
issues with indentation (<SPACE> vs. <TAB>) that should be fixed.

The testcase seems to exercise everything discussed.  There is only
one thing that you may want to (re)consider: when the result of
expressions involving array constructors of type character,
checking for correct length as written may not work as desired.
E.g., the declaration (with constant length)

    character(17), dimension(2) :: charr17

when used in

    ! CHARACTER concatenation after constructor - verify length 17
    charr17 = [character(16) :: 'a' // 'c', 'b' // 'de'] // '|'
    if (len(charr17) /= 17) stop 107
    if (charr17(1) /= 'ac              |') stop 108
    if (charr17(2) /= 'bde             |') stop 109

the expression with len(charr17) will get optimized out, so
you don't any useful information.  If you really want to check
the length of the r.h.s. after evaluation, you could have used

    character(:), dimension(:), allocatable :: charr17

etc., which is likely better, as array-bounds/string-length
checking in assignments to static l.h.s. does not always trigger.

So OK from my side with the above fixed, unless there are
comments from others.

Thanks,
Harald

Reply via email to