aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/trans-array.c
diff options
context:
space:
mode:
authorPaul Thomas <pault@gcc.gnu.org>2015-11-15 14:07:52 +0000
committerPaul Thomas <pault@gcc.gnu.org>2015-11-15 14:07:52 +0000
commit78ab5260a105594362d0fc96c0b455844b6accd4 (patch)
tree68e0ae5b8618edca499acc51ced992350c7d50fa /gcc/fortran/trans-array.c
parent356510acd94c858b610a9cc4012880f5ba810c44 (diff)
downloadgcc-78ab5260a105594362d0fc96c0b455844b6accd4.zip
gcc-78ab5260a105594362d0fc96c0b455844b6accd4.tar.gz
gcc-78ab5260a105594362d0fc96c0b455844b6accd4.tar.bz2
re PR fortran/50221 (Allocatable string length fails with array assignment)
2015-11-15 Paul Thomas <pault@gcc.gnu.org> PR fortran/50221 PR fortran/68216 PR fortran/63932 PR fortran/66408 * trans_array.c (gfc_conv_scalarized_array_ref): Pass the symbol decl for deferred character length array references. * trans-stmt.c (gfc_trans_allocate): Keep the string lengths to update deferred length character string lengths. * trans-types.c (gfc_get_dtype_rank_type); Use the string length of deferred character types for the dtype size. * trans.c (gfc_build_array_ref): For references to deferred character arrays, use the domain max value, if it is a variable to set the 'span' and use pointer arithmetic for acces to the element. (trans_code): Set gfc_current_locus for diagnostic purposes. PR fortran/67674 * trans-expr.c (gfc_conv_procedure_call): Do not fix deferred string lengths of components. PR fortran/49954 * resolve.c (deferred_op_assign): New function. (gfc_resolve_code): Call it. * trans-array.c (concat_str_length): New function. (gfc_alloc_allocatable_for_assignment): Jump directly to alloc/ realloc blocks for deferred character length arrays because the string length might change, even if the shape is the same. Call concat_str_length to obtain the string length for concatenation since it is needed to compute the lhs string length. Set the descriptor dtype appropriately for the new string length. * trans-expr.c (gfc_trans_assignment_1): Use the rse string length for all characters, other than deferred types. For concatenation operators, push the rse.pre block to the inner most loop so that the temporary pointer and the assignments are properly placed. 2015-11-15 Paul Thomas <pault@gcc.gnu.org> PR fortran/50221 * gfortran.dg/deferred_character_1.f90: New test. * gfortran.dg/deferred_character_4.f90: New test for comment #4 of the PR. PR fortran/68216 * gfortran.dg/deferred_character_2.f90: New test. PR fortran/67674 * gfortran.dg/deferred_character_3.f90: New test. PR fortran/63932 * gfortran.dg/deferred_character_5.f90: New test. PR fortran/66408 * gfortran.dg/deferred_character_6.f90: New test. PR fortran/49954 * gfortran.dg/deferred_character_7.f90: New test. From-SVN: r230396
Diffstat (limited to 'gcc/fortran/trans-array.c')
-rw-r--r--gcc/fortran/trans-array.c120
1 files changed, 116 insertions, 4 deletions
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index c294516..69f6e19 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -3164,7 +3164,8 @@ gfc_conv_scalarized_array_ref (gfc_se * se, gfc_array_ref * ar)
index = fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type,
index, info->offset);
- if (expr && is_subref_array (expr))
+ if (expr && (is_subref_array (expr)
+ || (expr->ts.deferred && expr->expr_type == EXPR_VARIABLE)))
decl = expr->symtree->n.sym->backend_decl;
tmp = build_fold_indirect_ref_loc (input_location, info->data);
@@ -8499,6 +8500,75 @@ gfc_is_reallocatable_lhs (gfc_expr *expr)
}
+static tree
+concat_str_length (gfc_expr* expr)
+{
+ tree type;
+ tree len1;
+ tree len2;
+ gfc_se se;
+
+ type = gfc_typenode_for_spec (&expr->value.op.op1->ts);
+ len1 = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
+ if (len1 == NULL_TREE)
+ {
+ if (expr->value.op.op1->expr_type == EXPR_OP)
+ len1 = concat_str_length (expr->value.op.op1);
+ else if (expr->value.op.op1->expr_type == EXPR_CONSTANT)
+ len1 = build_int_cst (gfc_charlen_type_node,
+ expr->value.op.op1->value.character.length);
+ else if (expr->value.op.op1->ts.u.cl->length)
+ {
+ gfc_init_se (&se, NULL);
+ gfc_conv_expr (&se, expr->value.op.op1->ts.u.cl->length);
+ len1 = se.expr;
+ }
+ else
+ {
+ /* Last resort! */
+ gfc_init_se (&se, NULL);
+ se.want_pointer = 1;
+ se.descriptor_only = 1;
+ gfc_conv_expr (&se, expr->value.op.op1);
+ len1 = se.string_length;
+ }
+ }
+
+ type = gfc_typenode_for_spec (&expr->value.op.op2->ts);
+ len2 = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
+ if (len2 == NULL_TREE)
+ {
+ if (expr->value.op.op2->expr_type == EXPR_OP)
+ len2 = concat_str_length (expr->value.op.op2);
+ else if (expr->value.op.op2->expr_type == EXPR_CONSTANT)
+ len2 = build_int_cst (gfc_charlen_type_node,
+ expr->value.op.op2->value.character.length);
+ else if (expr->value.op.op2->ts.u.cl->length)
+ {
+ gfc_init_se (&se, NULL);
+ gfc_conv_expr (&se, expr->value.op.op2->ts.u.cl->length);
+ len2 = se.expr;
+ }
+ else
+ {
+ /* Last resort! */
+ gfc_init_se (&se, NULL);
+ se.want_pointer = 1;
+ se.descriptor_only = 1;
+ gfc_conv_expr (&se, expr->value.op.op2);
+ len2 = se.string_length;
+ }
+ }
+
+ gcc_assert(len1 && len2);
+ len1 = fold_convert (gfc_charlen_type_node, len1);
+ len2 = fold_convert (gfc_charlen_type_node, len2);
+
+ return fold_build2_loc (input_location, PLUS_EXPR,
+ gfc_charlen_type_node, len1, len2);
+}
+
+
/* Allocate the lhs of an assignment to an allocatable array, otherwise
reallocate it. */
@@ -8596,6 +8666,12 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop,
/* Allocate if data is NULL. */
cond_null = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node,
array1, build_int_cst (TREE_TYPE (array1), 0));
+
+ if (expr1->ts.deferred)
+ cond_null = gfc_evaluate_now (boolean_true_node, &fblock);
+ else
+ cond_null= gfc_evaluate_now (cond_null, &fblock);
+
tmp = build3_v (COND_EXPR, cond_null,
build1_v (GOTO_EXPR, jump_label1),
build_empty_stmt (input_location));
@@ -8684,7 +8760,13 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop,
cond = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
size1, size2);
- neq_size = gfc_evaluate_now (cond, &fblock);
+
+ /* If the lhs is deferred length, assume that the element size
+ changes and force a reallocation. */
+ if (expr1->ts.deferred)
+ neq_size = gfc_evaluate_now (boolean_true_node, &fblock);
+ else
+ neq_size = gfc_evaluate_now (cond, &fblock);
/* Deallocation of allocatable components will have to occur on
reallocation. Fix the old descriptor now. */
@@ -8789,6 +8871,12 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop,
else
{
tmp = expr2->ts.u.cl->backend_decl;
+ if (!tmp && expr2->expr_type == EXPR_OP
+ && expr2->value.op.op == INTRINSIC_CONCAT)
+ {
+ tmp = concat_str_length (expr2);
+ expr2->ts.u.cl->backend_decl = gfc_evaluate_now (tmp, &fblock);
+ }
tmp = fold_convert (TREE_TYPE (expr1->ts.u.cl->backend_decl), tmp);
}
@@ -8816,6 +8904,22 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop,
size2, size_one_node);
size2 = gfc_evaluate_now (size2, &fblock);
+ /* For deferred character length, the 'size' field of the dtype might
+ have changed so set the dtype. */
+ if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc))
+ && expr1->ts.type == BT_CHARACTER && expr1->ts.deferred)
+ {
+ tree type;
+ tmp = gfc_conv_descriptor_dtype (desc);
+ if (expr2->ts.u.cl->backend_decl)
+ type = gfc_typenode_for_spec (&expr2->ts);
+ else
+ type = gfc_typenode_for_spec (&expr1->ts);
+
+ gfc_add_modify (&fblock, tmp,
+ gfc_get_dtype_rank_type (expr1->rank,type));
+ }
+
/* Realloc expression. Note that the scalarizer uses desc.data
in the array reference - (*desc.data)[<element>]. */
gfc_init_block (&realloc_block);
@@ -8858,8 +8962,16 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop,
1, size2);
gfc_conv_descriptor_data_set (&alloc_block,
desc, tmp);
- tmp = gfc_conv_descriptor_dtype (desc);
- gfc_add_modify (&alloc_block, tmp, gfc_get_dtype (TREE_TYPE (desc)));
+
+ /* We already set the dtype in the case of deferred character
+ length arrays. */
+ if (!(GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc))
+ && expr1->ts.type == BT_CHARACTER && expr1->ts.deferred))
+ {
+ tmp = gfc_conv_descriptor_dtype (desc);
+ gfc_add_modify (&alloc_block, tmp, gfc_get_dtype (TREE_TYPE (desc)));
+ }
+
if ((expr1->ts.type == BT_DERIVED)
&& expr1->ts.u.derived->attr.alloc_comp)
{