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