Reformatted and minor changes On Sun, 30 Nov 2025 15:57:51 +0100 Christopher Albert <[email protected]> wrote:
> 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.
>From 7c91cc5ab8a3529fdd62335d7c0464bdd9bf00ca Mon Sep 17 00:00:00 2001 From: Christopher Albert <[email protected]> Date: Tue, 25 Nov 2025 00:13:03 +0100 Subject: [PATCH] fortran: Honor array constructor type-spec during folding [PR107721] 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. Co-authored-by: Harald Anlauf <[email protected]> Signed-off-by: Christopher Albert <[email protected]> --- gcc/fortran/arith.cc | 35 ++ gcc/fortran/array.cc | 100 ++++-- .../array_constructor_typespec_1.f90 | 324 ++++++++++++++++++ 3 files changed, 438 insertions(+), 21 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/array_constructor_typespec_1.f90 diff --git a/gcc/fortran/arith.cc b/gcc/fortran/arith.cc index 82a8b6fb995..142f1b09284 100644 --- a/gcc/fortran/arith.cc +++ b/gcc/fortran/arith.cc @@ -1565,6 +1565,8 @@ reduce_binary_ac (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **), r = gfc_get_array_expr (c->expr->ts.type, c->expr->ts.kind, &op1->where); r->shape = gfc_copy_shape (op1->shape, op1->rank); + if (c->expr->ts.type == BT_CHARACTER) + r->ts.u.cl = c->expr->ts.u.cl; } else { @@ -1572,6 +1574,8 @@ reduce_binary_ac (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **), r = gfc_get_array_expr (op1->ts.type, op1->ts.kind, &op1->where); r->shape = gfc_get_shape (op1->rank); + if (op1->ts.type == BT_CHARACTER) + r->ts.u.cl = op1->ts.u.cl; } r->rank = op1->rank; r->corank = op1->corank; @@ -1629,6 +1633,8 @@ reduce_binary_ca (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **), r = gfc_get_array_expr (c->expr->ts.type, c->expr->ts.kind, &op2->where); r->shape = gfc_copy_shape (op2->shape, op2->rank); + if (c->expr->ts.type == BT_CHARACTER) + r->ts.u.cl = c->expr->ts.u.cl; } else { @@ -1636,6 +1642,8 @@ reduce_binary_ca (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **), r = gfc_get_array_expr (op2->ts.type, op2->ts.kind, &op2->where); r->shape = gfc_get_shape (op2->rank); + if (op2->ts.type == BT_CHARACTER) + r->ts.u.cl = op2->ts.u.cl; } r->rank = op2->rank; r->corank = op2->corank; @@ -1697,11 +1705,15 @@ reduce_binary_aa (arith (*eval) (gfc_expr *, gfc_expr *, gfc_expr **), { /* Handle zero-sized arrays. */ r = gfc_get_array_expr (op1->ts.type, op1->ts.kind, &op1->where); + if (op1->ts.type == BT_CHARACTER) + r->ts.u.cl = op1->ts.u.cl; } else { r = gfc_get_array_expr (c->expr->ts.type, c->expr->ts.kind, &op1->where); + if (c->expr->ts.type == BT_CHARACTER) + r->ts.u.cl = c->expr->ts.u.cl; } r->shape = gfc_copy_shape (op1->shape, op1->rank); r->rank = op1->rank; @@ -1921,6 +1933,29 @@ eval_intrinsic (gfc_intrinsic_op op, || !gfc_is_constant_expr (op2) || !gfc_expanded_ac (op2))) goto runtime; + /* For array constructors with explicit type-spec, ensure elements are + converted to the specified type before any operations. This handles + cases like [integer :: ([1.0])] ** 2 where parentheses would otherwise + cause the type-spec to be lost during constant folding. */ + if (op1->expr_type == EXPR_ARRAY && op1->ts.type != BT_UNKNOWN) + gfc_check_constructor_type (op1); + if (op2 != NULL && op2->expr_type == EXPR_ARRAY && op2->ts.type != BT_UNKNOWN) + gfc_check_constructor_type (op2); + + /* For CONCAT operations, also resolve character array constructors to + ensure elements are padded to the specified length before concatenation. + This ensures [character(16):: 'a','b'] // '|' pads to 16 chars first. */ + if (op == INTRINSIC_CONCAT) + { + if (op1->expr_type == EXPR_ARRAY && op1->ts.type == BT_CHARACTER + && op1->ts.u.cl && op1->ts.u.cl->length_from_typespec) + gfc_resolve_character_array_constructor (op1); + if (op2 != NULL && op2->expr_type == EXPR_ARRAY + && op2->ts.type == BT_CHARACTER + && op2->ts.u.cl && op2->ts.u.cl->length_from_typespec) + gfc_resolve_character_array_constructor (op2); + } + if (unary) rc = reduce_unary (eval.f2, op1, &result); else diff --git a/gcc/fortran/array.cc b/gcc/fortran/array.cc index 57a7b134e4c..7df7394cac6 100644 --- a/gcc/fortran/array.cc +++ b/gcc/fortran/array.cc @@ -1549,10 +1549,37 @@ check_constructor_type (gfc_constructor_base base, bool convert) { e = c->expr; + /* Simplify non-constant expressions (like parenthesized arrays) so type + conversion can work on the simplified result. This handles cases like + [integer :: ([1.0])] where ([1.0]) is an EXPR_OP that needs to be + simplified to an EXPR_ARRAY before type conversion. */ + if (convert && e->expr_type != EXPR_CONSTANT + && e->expr_type != EXPR_ARRAY) + gfc_simplify_expr (e, 0); + if (e->expr_type == EXPR_ARRAY) { - if (!check_constructor_type (e->value.constructor, convert)) - return false; + /* If the outer constructor has no type-spec (convert=false) and + the nested array has an explicit type-spec, process it separately + so its elements get converted according to its type-spec. This + handles cases like [[character(16) :: ['a','b']]] where the outer + constructor has no type-spec but the inner one does. + gfc_check_constructor_type will also update the global + constructor_ts and cons_state which propagates the type info + to the outer constructor. + For character types, length_from_typespec indicates an explicit + type-spec was provided. */ + if (!convert && e->ts.type == BT_CHARACTER + && e->ts.u.cl && e->ts.u.cl->length_from_typespec) + { + if (!gfc_check_constructor_type (e)) + return false; + } + else + { + if (!check_constructor_type (e->value.constructor, convert)) + return false; + } continue; } @@ -2261,10 +2288,14 @@ gfc_resolve_character_array_constructor (gfc_expr *expr) { gfc_constructor *p; HOST_WIDE_INT found_length; + bool has_ts; gcc_assert (expr->expr_type == EXPR_ARRAY); gcc_assert (expr->ts.type == BT_CHARACTER); + /* Check if we have an explicit type-spec with length. */ + has_ts = expr->ts.u.cl && expr->ts.u.cl->length_from_typespec; + if (expr->ts.u.cl == NULL) { for (p = gfc_constructor_first (expr->value.constructor); @@ -2367,28 +2398,55 @@ got_charlen: if (found_length != -1) for (p = gfc_constructor_first (expr->value.constructor); p; p = gfc_constructor_next (p)) - if (p->expr->expr_type == EXPR_CONSTANT) - { - gfc_expr *cl = NULL; - HOST_WIDE_INT current_length = -1; - bool has_ts; + { + /* For non-constant expressions (like EXPR_OP from concatenation), + try to simplify them first so we can then pad/truncate. */ + if (p->expr->expr_type != EXPR_CONSTANT + && p->expr->ts.type == BT_CHARACTER) + gfc_simplify_expr (p->expr, 0); - if (p->expr->ts.u.cl && p->expr->ts.u.cl->length) + if (p->expr->expr_type == EXPR_CONSTANT) { - cl = p->expr->ts.u.cl->length; - gfc_extract_hwi (cl, ¤t_length); + gfc_expr *cl = NULL; + HOST_WIDE_INT current_length = -1; + + if (p->expr->ts.u.cl && p->expr->ts.u.cl->length) + { + cl = p->expr->ts.u.cl->length; + gfc_extract_hwi (cl, ¤t_length); + } + + /* If gfc_extract_int above set current_length, we implicitly + know the type is BT_INTEGER and it's EXPR_CONSTANT. */ + + if (! cl + || (current_length != -1 && current_length != found_length)) + gfc_set_constant_character_len (found_length, p->expr, + has_ts ? -1 : found_length); } - - /* If gfc_extract_int above set current_length, we implicitly - know the type is BT_INTEGER and it's EXPR_CONSTANT. */ - - has_ts = expr->ts.u.cl->length_from_typespec; - - if (! cl - || (current_length != -1 && current_length != found_length)) - gfc_set_constant_character_len (found_length, p->expr, - has_ts ? -1 : found_length); - } + else if (p->expr->expr_type == EXPR_ARRAY) + { + /* For nested array constructors, propagate the type-spec and + recursively resolve. This handles cases like + [character(16) :: ['a','b']] // "|". The inner constructor + may have BT_UNKNOWN type initially. */ + if (p->expr->ts.type == BT_UNKNOWN + || p->expr->ts.type == BT_CHARACTER) + { + if (p->expr->ts.type == BT_CHARACTER + && p->expr->ts.u.cl + && p->expr->ts.u.cl->length_from_typespec) + { + /* If the inner array has an explicit type-spec, we must + honor it first (e.g. truncate/pad to its length), + before coercing it to the outer length. */ + gfc_resolve_character_array_constructor (p->expr); + } + + p->expr->ts = expr->ts; + gfc_resolve_character_array_constructor (p->expr); + } + } } return true; diff --git a/gcc/testsuite/gfortran.dg/array_constructor_typespec_1.f90 b/gcc/testsuite/gfortran.dg/array_constructor_typespec_1.f90 new file mode 100644 index 00000000000..90840b5587c --- /dev/null +++ b/gcc/testsuite/gfortran.dg/array_constructor_typespec_1.f90 @@ -0,0 +1,324 @@ +! { dg-do run } +! PR fortran/107721 - array constructor type-spec lost with parentheses +! PR fortran/102417 - character array constructor type-spec lost +! +! Tests type-spec preservation in array constructors with parentheses, +! nested constructors, and CLASS(*) type verification for all intrinsic types. + +program array_constructor_typespec_1 + implicit none + integer :: i, iscalar + integer, dimension(2) :: iarr + real, dimension(2) :: rarr + real :: rscalar + complex, dimension(2) :: carr + complex :: cscalar + logical, dimension(2) :: larr + character(4), dimension(3) :: charr + character(8), dimension(2) :: charr8 + character(16), dimension(3) :: charr16 + character(16), dimension(2) :: charr16_2 + character(:), allocatable :: charr17(:) + character :: x = 'a', y = 'b' + class(*), allocatable :: res(:) + character(10), dimension(1) :: charr10 + character(4), dimension(1) :: charr4_1 + character(:), allocatable :: charr0(:) + character(4), dimension(0) :: empty4 + + ! INTEGER - runtime value checks + iarr = [integer :: [1.0], [2.0]] + if (any(iarr /= [1, 2])) stop 1 + iarr = [integer :: ([1.0]), ([2.0])] + if (any(iarr /= [1, 2])) stop 2 + iarr = [integer :: ((([1.0]))), [2.0]] + if (any(iarr /= [1, 2])) stop 3 + + ! REAL - runtime value checks + rarr = [real :: [2], [3]] + if (any(rarr /= [2.0, 3.0])) stop 4 + rarr = [real :: ([2]), ([3])] + if (any(rarr /= [2.0, 3.0])) stop 5 + rarr = [real :: ((([2]))), [3]] + if (any(rarr /= [2.0, 3.0])) stop 6 + + ! COMPLEX - runtime value checks + carr = [complex :: [3], [4]] + if (any(carr /= [(3.0, 0.0), (4.0, 0.0)])) stop 7 + carr = [complex :: ([3]), ([4])] + if (any(carr /= [(3.0, 0.0), (4.0, 0.0)])) stop 8 + carr = [complex :: ((([3]))), [4]] + if (any(carr /= [(3.0, 0.0), (4.0, 0.0)])) stop 9 + + ! LOGICAL - runtime value checks + larr = [logical :: [.true.], [.false.]] + if (any(larr .neqv. [.true., .false.])) stop 10 + larr = [logical :: ([.true.]), ([.false.])] + if (any(larr .neqv. [.true., .false.])) stop 11 + + ! CHARACTER - runtime value checks (PR 102417) + charr = [character(4) :: 'a', 'b', 'c'] + if (any(charr /= ['a ', 'b ', 'c '])) stop 12 + charr = [character(4) :: ('a'), 'b', 'c'] + if (any(charr /= ['a ', 'b ', 'c '])) stop 13 + charr = [[character(4) :: 'a', 'b', 'c']] + if (any(charr /= ['a ', 'b ', 'c '])) stop 14 + + ! CHARACTER with nested constructors - length 8 + charr8 = [character(8) :: 'x', 'y'] + if (charr8(1) /= 'x ') stop 15 + if (charr8(2) /= 'y ') stop 16 + + charr8 = [character(8) :: ['a', 'b']] + if (charr8(1) /= 'a ') stop 17 + if (charr8(2) /= 'b ') stop 18 + + ! Outer constructor without type-spec, inner with type-spec. + ! With proper type-spec propagation, no length mismatch warning is needed. + charr8 = [[character(8) :: ['a', 'b']]] + if (charr8(1) /= 'a ') stop 19 + if (charr8(2) /= 'b ') stop 20 + + ! Triple-nested constructor with type-spec in middle. + charr8 = [[[character(8) :: ['a', 'b']]]] + if (charr8(1) /= 'a ') stop 21 + if (charr8(2) /= 'b ') stop 22 + + charr8 = [character(8) :: (x), (y)] + if (charr8(1) /= 'a ') stop 23 + if (charr8(2) /= 'b ') stop 24 + + charr8 = [[character(8) :: (x), (y)]] + if (charr8(1) /= 'a ') stop 25 + if (charr8(2) /= 'b ') stop 26 + + ! CHARACTER concatenation with parentheses (PR 107721 comment 14) + charr16_2 = [character(16) :: 'a' // 'c', 'b' // 'de'] + if (charr16_2(1) /= 'ac ') stop 101 + if (charr16_2(2) /= 'bde ') stop 102 + + charr16_2 = [character(16) :: 'a' // 'c', ('b' // 'de')] + if (charr16_2(1) /= 'ac ') stop 103 + if (charr16_2(2) /= 'bde ') stop 104 + + charr16_2 = [character(16) :: ('a' // 'c'), 'b' // 'de'] + if (charr16_2(1) /= 'ac ') stop 105 + if (charr16_2(2) /= 'bde ') stop 106 + + ! 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 + + charr17 = [character(16) :: 'a' // 'c', ('b' // 'de')] // '|' + if (len(charr17) /= 17) stop 110 + if (charr17(1) /= 'ac |') stop 111 + if (charr17(2) /= 'bde |') stop 112 + + charr17 = [character(16) :: ('a' // 'c'), 'b' // 'de'] // '|' + if (len(charr17) /= 17) stop 113 + if (charr17(1) /= 'ac |') stop 114 + if (charr17(2) /= 'bde |') stop 115 + + ! CHARACTER - longer length 16 + charr16 = [character(16) :: 'a', 'b', 'c'] + if (charr16(1) /= 'a ') stop 27 + if (charr16(2) /= 'b ') stop 28 + if (charr16(3) /= 'c ') stop 29 + + charr16 = [[character(16) :: 'a', 'b', 'c']] + if (charr16(1) /= 'a ') stop 30 + if (charr16(2) /= 'b ') stop 31 + if (charr16(3) /= 'c ') stop 32 + + ! CHARACTER - truncation cases + charr8 = [character(8) :: 'abcdefghij', 'klmnopqrst'] + if (charr8(1) /= 'abcdefgh') stop 33 + if (charr8(2) /= 'klmnopqr') stop 34 + + charr8 = [[character(8) :: 'abcdefghij', 'klmnopqrst']] + if (charr8(1) /= 'abcdefgh') stop 35 + if (charr8(2) /= 'klmnopqr') stop 36 + + ! Implied-do with parentheses + iarr = [integer :: (/(1.0*i, i=1, 2)/)] + if (any(iarr /= [1, 2])) stop 37 + iarr = [integer :: ((/(1.0*i, i=1, 2)/))] + if (any(iarr /= [1, 2])) stop 38 + + ! Type verification with CLASS(*) - ensure types are actually converted + res = [integer :: ([1.0])] + call verify_integer (res, 42) + deallocate (res) + + res = [integer :: ([1.0]), ([2.0])] + call verify_integer (res, 43) + deallocate (res) + + res = [real :: ([2]), [3]] + call verify_real (res, 44) + deallocate (res) + + res = [complex :: ([3])] + call verify_complex (res, 45) + deallocate (res) + + res = [logical :: ([.true.]), [.false.]] + call verify_logical (res, 46) + deallocate (res) + + ! Parenthesized constructors - verify result TYPE not just value + res = [integer :: ([1.0])] ** 2 + call verify_integer (res, 47) + deallocate (res) + + res = [real :: ([2]), [3]] ** 2 + call verify_real (res, 48) + deallocate (res) + + res = [complex :: ([3])] ** 2 + call verify_complex (res, 49) + deallocate (res) + + ! Harald's test cases from Comment #17 - scalar // constructor patterns + charr17 = '|' // [character(16) :: 'a' // 'c', 'b' // 'de'] + if (len(charr17) /= 17) stop 116 + if (charr17(1) /= '|ac ') stop 117 + if (charr17(2) /= '|bde ') stop 118 + + charr17 = '|' // [character(16) :: 'a' // 'c', ('b' // 'de')] + if (len(charr17) /= 17) stop 119 + if (charr17(1) /= '|ac ') stop 120 + if (charr17(2) /= '|bde ') stop 121 + + charr17 = '|' // [character(16) :: ('a' // 'c'), 'b' // 'de'] + if (len(charr17) /= 17) stop 122 + if (charr17(1) /= '|ac ') stop 123 + if (charr17(2) /= '|bde ') stop 124 + + ! Comment #11: Nested array constructor with concatenation + ! The inner ['a','b'] must be padded to length 16 before concat + charr17 = [character(16) :: ['a', 'b']] // '|' + if (len(charr17) /= 17) stop 125 + if (charr17(1) /= 'a |') stop 126 + if (charr17(2) /= 'b |') stop 127 + + ! Comment #18: Outer constructor without type-spec wrapping inner with + ! type-spec. The type-spec must be propagated when flattening. + charr17 = [[character(16) :: ['a', 'b']]] // '|' + if (len(charr17) /= 17) stop 128 + if (charr17(1) /= 'a |') stop 129 + if (charr17(2) /= 'b |') stop 130 + + charr17 = '|' // [[character(16) :: ['a', 'b']]] + if (len(charr17) /= 17) stop 131 + if (charr17(1) /= '|a ') stop 132 + if (charr17(2) /= '|b ') stop 133 + + ! Harald's new test cases from Comment #22 - nested truncation and padding + ! [ character(2) :: ['abcd','efgh'] ] should truncate to 'ab', 'ef' + ! Then [ character(16) :: ... ] should pad to 'ab ', 'ef ' + + charr16_2 = [ character(16) :: [ character(2) :: ['abcd','efgh'] ] ] + if (charr16_2(1) /= 'ab ') stop 134 + if (charr16_2(2) /= 'ef ') stop 135 + + charr17 = [ character(16) :: [ character(2) :: ['abcd','efgh'] ] ] // "|" + if (len(charr17) /= 17) stop 136 + if (charr17(1) /= 'ab |') stop 137 + if (charr17(2) /= 'ef |') stop 138 + + charr17 = "|" // [ character(16) :: [ character(2) :: ['abcd','efgh'] ] ] + if (len(charr17) /= 17) stop 139 + if (charr17(1) /= '|ab ') stop 140 + if (charr17(2) /= '|ef ') stop 141 + + charr16_2 = [ character(16) :: ([ character(2) :: ['abcd','efgh'] ])] + if (charr16_2(1) /= 'ab ') stop 142 + if (charr16_2(2) /= 'ef ') stop 143 + + charr17 = [ character(16) :: ([ character(2) :: ['abcd','efgh'] ])] // "|" + if (len(charr17) /= 17) stop 144 + if (charr17(1) /= 'ab |') stop 145 + if (charr17(2) /= 'ef |') stop 146 + + charr17 = "|" // [ character(16) :: ([ character(2) :: ['abcd','efgh'] ])] + if (len(charr17) /= 17) stop 147 + if (charr17(1) /= '|ab ') stop 148 + if (charr17(2) /= '|ef ') stop 149 + + ! Additional torture tests + ! Triple nesting with explicit types: 'abcde'(5) -> 'ab'(2) -> 'ab '(10) + charr10 = [character(10) :: [character(2) :: [character(5) :: 'abcde']]] + if (charr10(1) /= 'ab ') stop 150 + + ! Concatenation of constructors + ! 'a'(2) // 'b'(3) -> 'a b '(5) -> 'a b '(4) + charr4_1 = [character(4) :: [character(2) :: 'a'] // [character(3) :: 'b']] + if (charr4_1(1) /= 'a b ') stop 151 + + ! Zero length strings + ! Inner zero length: 'abc' -> ''(0) -> ' '(4) + charr4_1 = [character(4) :: [character(0) :: 'abc']] + if (charr4_1(1) /= ' ') stop 152 + + ! Outer zero length: 'abc' -> 'abc '(4) -> ''(0) + charr0 = [character(0) :: [character(4) :: 'abc']] + if (len(charr0) /= 0) stop 153 + if (charr0(1) /= '') stop 154 + + ! Empty array constructors + empty4 = [character(4) :: ] + if (size(empty4) /= 0) stop 155 + + empty4 = [character(4) :: [character(2) :: ]] + if (size(empty4) /= 0) stop 156 + +contains + + subroutine verify_integer (x, stopcode) + class(*), intent(in) :: x(:) + integer, intent(in) :: stopcode + select type (x) + type is (integer) + ! Correct type + class default + stop stopcode + end select + end subroutine verify_integer + + subroutine verify_real (x, stopcode) + class(*), intent(in) :: x(:) + integer, intent(in) :: stopcode + select type (x) + type is (real) + ! Correct type + class default + stop stopcode + end select + end subroutine verify_real + + subroutine verify_complex (x, stopcode) + class(*), intent(in) :: x(:) + integer, intent(in) :: stopcode + select type (x) + type is (complex) + ! Correct type + class default + stop stopcode + end select + end subroutine verify_complex + + subroutine verify_logical (x, stopcode) + class(*), intent(in) :: x(:) + integer, intent(in) :: stopcode + select type (x) + type is (logical) + ! Correct type + class default + stop stopcode + end select + end subroutine verify_logical + +end program array_constructor_typespec_1 -- 2.52.0
