aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/trans-array.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fortran/trans-array.c')
-rw-r--r--gcc/fortran/trans-array.c298
1 files changed, 297 insertions, 1 deletions
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index 9efb531..2b06903 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -8073,7 +8073,10 @@ gfc_caf_is_dealloc_only (int caf_mode)
function for the functions named in this enum. */
enum {DEALLOCATE_ALLOC_COMP = 1, NULLIFY_ALLOC_COMP,
- COPY_ALLOC_COMP, COPY_ONLY_ALLOC_COMP, REASSIGN_CAF_COMP};
+ COPY_ALLOC_COMP, COPY_ONLY_ALLOC_COMP, REASSIGN_CAF_COMP,
+ ALLOCATE_PDT_COMP, DEALLOCATE_PDT_COMP, CHECK_PDT_DUMMY};
+
+static gfc_actual_arglist *pdt_param_list;
static tree
structure_alloc_comps (gfc_symbol * der_type, tree decl,
@@ -8735,6 +8738,255 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl,
break;
+ case ALLOCATE_PDT_COMP:
+
+ comp = fold_build3_loc (input_location, COMPONENT_REF, ctype,
+ decl, cdecl, NULL_TREE);
+
+ /* Set the PDT KIND and LEN fields. */
+ if (c->attr.pdt_kind || c->attr.pdt_len)
+ {
+ gfc_se tse;
+ gfc_expr *c_expr = NULL;
+ gfc_actual_arglist *param = pdt_param_list;
+ gfc_init_se (&tse, NULL);
+ for (; param; param = param->next)
+ if (!strcmp (c->name, param->name))
+ c_expr = param->expr;
+
+ if (!c_expr)
+ c_expr = c->initializer;
+
+ if (c_expr)
+ {
+ gfc_conv_expr_type (&tse, c_expr, TREE_TYPE (comp));
+ gfc_add_modify (&fnblock, comp, tse.expr);
+ }
+ }
+
+ if (c->attr.pdt_string)
+ {
+ gfc_se tse;
+ gfc_init_se (&tse, NULL);
+ tree strlen;
+ /* Convert the parameterized string length to its value. The
+ string length is stored in a hidden field in the same way as
+ deferred string lengths. */
+ gfc_insert_parameter_exprs (c->ts.u.cl->length, pdt_param_list);
+ if (gfc_deferred_strlen (c, &strlen) && strlen != NULL_TREE)
+ {
+ gfc_conv_expr_type (&tse, c->ts.u.cl->length,
+ TREE_TYPE (strlen));
+ strlen = fold_build3_loc (input_location, COMPONENT_REF,
+ TREE_TYPE (strlen),
+ decl, strlen, NULL_TREE);
+ gfc_add_modify (&fnblock, strlen, tse.expr);
+ c->ts.u.cl->backend_decl = strlen;
+ }
+ /* Scalar parameterizied strings can be allocated now. */
+ if (!c->as)
+ {
+ tmp = fold_convert (gfc_array_index_type, strlen);
+ tmp = size_of_string_in_bytes (c->ts.kind, tmp);
+ tmp = gfc_evaluate_now (tmp, &fnblock);
+ tmp = gfc_call_malloc (&fnblock, TREE_TYPE (comp), tmp);
+ gfc_add_modify (&fnblock, comp, tmp);
+ }
+ }
+
+ /* Allocate paramterized arrays of parameterized derived types. */
+ if (!(c->attr.pdt_array && c->as && c->as->type == AS_EXPLICIT)
+ && !((c->ts.type == BT_DERIVED || c->ts.type == BT_CLASS)
+ && (c->ts.u.derived && c->ts.u.derived->attr.pdt_type)))
+ continue;
+
+ if (c->ts.type == BT_CLASS)
+ comp = gfc_class_data_get (comp);
+
+ if (c->attr.pdt_array)
+ {
+ gfc_se tse;
+ int i;
+ tree size = gfc_index_one_node;
+ tree offset = gfc_index_zero_node;
+ tree lower, upper;
+ gfc_expr *e;
+
+ /* This chunk takes the expressions for 'lower' and 'upper'
+ in the arrayspec and substitutes in the expressions for
+ the parameters from 'pdt_param_list'. The descriptor
+ fields can then be filled from the values so obtained. */
+ gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (comp)));
+ for (i = 0; i < c->as->rank; i++)
+ {
+ gfc_init_se (&tse, NULL);
+ e = gfc_copy_expr (c->as->lower[i]);
+ gfc_insert_parameter_exprs (e, pdt_param_list);
+ gfc_conv_expr_type (&tse, e, gfc_array_index_type);
+ gfc_free_expr (e);
+ lower = tse.expr;
+ gfc_conv_descriptor_lbound_set (&fnblock, comp,
+ gfc_rank_cst[i],
+ lower);
+ e = gfc_copy_expr (c->as->upper[i]);
+ gfc_insert_parameter_exprs (e, pdt_param_list);
+ gfc_conv_expr_type (&tse, e, gfc_array_index_type);
+ gfc_free_expr (e);
+ upper = tse.expr;
+ gfc_conv_descriptor_ubound_set (&fnblock, comp,
+ gfc_rank_cst[i],
+ upper);
+ gfc_conv_descriptor_stride_set (&fnblock, comp,
+ gfc_rank_cst[i],
+ size);
+ size = gfc_evaluate_now (size, &fnblock);
+ offset = fold_build2_loc (input_location,
+ MINUS_EXPR,
+ gfc_array_index_type,
+ offset, size);
+ offset = gfc_evaluate_now (offset, &fnblock);
+ tmp = fold_build2_loc (input_location, MINUS_EXPR,
+ gfc_array_index_type,
+ upper, lower);
+ tmp = fold_build2_loc (input_location, PLUS_EXPR,
+ gfc_array_index_type,
+ tmp, gfc_index_one_node);
+ size = fold_build2_loc (input_location, MULT_EXPR,
+ gfc_array_index_type, size, tmp);
+ }
+ gfc_conv_descriptor_offset_set (&fnblock, comp, offset);
+ if (c->ts.type == BT_CLASS)
+ {
+ tmp = gfc_get_vptr_from_expr (comp);
+ if (POINTER_TYPE_P (TREE_TYPE (tmp)))
+ tmp = build_fold_indirect_ref_loc (input_location, tmp);
+ tmp = gfc_vptr_size_get (tmp);
+ }
+ else
+ tmp = TYPE_SIZE_UNIT (gfc_get_element_type (ctype));
+ tmp = fold_convert (gfc_array_index_type, tmp);
+ size = fold_build2_loc (input_location, MULT_EXPR,
+ gfc_array_index_type, size, tmp);
+ size = gfc_evaluate_now (size, &fnblock);
+ tmp = gfc_call_malloc (&fnblock, NULL, size);
+ gfc_conv_descriptor_data_set (&fnblock, comp, tmp);
+ tmp = gfc_conv_descriptor_dtype (comp);
+ gfc_add_modify (&fnblock, tmp, gfc_get_dtype (ctype));
+ }
+
+ /* Recurse in to PDT components. */
+ if ((c->ts.type == BT_DERIVED || c->ts.type == BT_CLASS)
+ && c->ts.u.derived && c->ts.u.derived->attr.pdt_type)
+ {
+ bool is_deferred = false;
+ gfc_actual_arglist *tail = c->param_list;
+
+ for (; tail; tail = tail->next)
+ if (!tail->expr)
+ is_deferred = true;
+
+ tail = is_deferred ? pdt_param_list : c->param_list;
+ tmp = gfc_allocate_pdt_comp (c->ts.u.derived, comp,
+ c->as ? c->as->rank : 0,
+ tail);
+ gfc_add_expr_to_block (&fnblock, tmp);
+ }
+
+ break;
+
+ case DEALLOCATE_PDT_COMP:
+ /* Deallocate array or parameterized string length components
+ of parameterized derived types. */
+ if (!(c->attr.pdt_array && c->as && c->as->type == AS_EXPLICIT)
+ && !c->attr.pdt_string
+ && !((c->ts.type == BT_DERIVED || c->ts.type == BT_CLASS)
+ && (c->ts.u.derived && c->ts.u.derived->attr.pdt_type)))
+ continue;
+
+ comp = fold_build3_loc (input_location, COMPONENT_REF, ctype,
+ decl, cdecl, NULL_TREE);
+ if (c->ts.type == BT_CLASS)
+ comp = gfc_class_data_get (comp);
+
+ /* Recurse in to PDT components. */
+ if ((c->ts.type == BT_DERIVED || c->ts.type == BT_CLASS)
+ && c->ts.u.derived && c->ts.u.derived->attr.pdt_type)
+ {
+ tmp = gfc_deallocate_pdt_comp (c->ts.u.derived, comp,
+ c->as ? c->as->rank : 0);
+ gfc_add_expr_to_block (&fnblock, tmp);
+ }
+
+ if (c->attr.pdt_array)
+ {
+ tmp = gfc_conv_descriptor_data_get (comp);
+ tmp = gfc_call_free (tmp);
+ gfc_add_expr_to_block (&fnblock, tmp);
+ gfc_conv_descriptor_data_set (&fnblock, comp, null_pointer_node);
+ }
+ else if (c->attr.pdt_string)
+ {
+ tmp = gfc_call_free (comp);
+ gfc_add_expr_to_block (&fnblock, tmp);
+ tmp = fold_convert (TREE_TYPE (comp), null_pointer_node);
+ gfc_add_modify (&fnblock, comp, tmp);
+ }
+
+ break;
+
+ case CHECK_PDT_DUMMY:
+
+ comp = fold_build3_loc (input_location, COMPONENT_REF, ctype,
+ decl, cdecl, NULL_TREE);
+ if (c->ts.type == BT_CLASS)
+ comp = gfc_class_data_get (comp);
+
+ /* Recurse in to PDT components. */
+ if ((c->ts.type == BT_DERIVED || c->ts.type == BT_CLASS)
+ && c->ts.u.derived && c->ts.u.derived->attr.pdt_type)
+ {
+ tmp = gfc_check_pdt_dummy (c->ts.u.derived, comp,
+ c->as ? c->as->rank : 0,
+ pdt_param_list);
+ gfc_add_expr_to_block (&fnblock, tmp);
+ }
+
+ if (!c->attr.pdt_len)
+ continue;
+ else
+ {
+ gfc_se tse;
+ gfc_expr *c_expr = NULL;
+ gfc_actual_arglist *param = pdt_param_list;
+
+ gfc_init_se (&tse, NULL);
+ for (; param; param = param->next)
+ if (!strcmp (c->name, param->name))
+ c_expr = param->expr;
+
+ if (c_expr)
+ {
+ tree error, cond, cname;
+ gfc_conv_expr_type (&tse, c_expr, TREE_TYPE (comp));
+ cond = fold_build2_loc (input_location, NE_EXPR,
+ boolean_type_node,
+ comp, tse.expr);
+ cname = gfc_build_cstring_const (c->name);
+ cname = gfc_build_addr_expr (pchar_type_node, cname);
+ error = gfc_trans_runtime_error (true, NULL,
+ "The value of the PDT LEN "
+ "parameter '%s' does not "
+ "agree with that in the "
+ "dummy declaration",
+ cname);
+ tmp = fold_build3_loc (input_location, COND_EXPR,
+ void_type_node, cond, error,
+ build_empty_stmt (input_location));
+ gfc_add_expr_to_block (&fnblock, tmp);
+ }
+ }
+ break;
+
default:
gcc_unreachable ();
break;
@@ -8814,6 +9066,50 @@ gfc_copy_only_alloc_comp (gfc_symbol * der_type, tree decl, tree dest, int rank)
}
+/* Recursively traverse an object of paramterized derived type, generating
+ code to allocate parameterized components. */
+
+tree
+gfc_allocate_pdt_comp (gfc_symbol * der_type, tree decl, int rank,
+ gfc_actual_arglist *param_list)
+{
+ tree res;
+ gfc_actual_arglist *old_param_list = pdt_param_list;
+ pdt_param_list = param_list;
+ res = structure_alloc_comps (der_type, decl, NULL_TREE, rank,
+ ALLOCATE_PDT_COMP, 0);
+ pdt_param_list = old_param_list;
+ return res;
+}
+
+/* Recursively traverse an object of paramterized derived type, generating
+ code to deallocate parameterized components. */
+
+tree
+gfc_deallocate_pdt_comp (gfc_symbol * der_type, tree decl, int rank)
+{
+ return structure_alloc_comps (der_type, decl, NULL_TREE, rank,
+ DEALLOCATE_PDT_COMP, 0);
+}
+
+
+/* Recursively traverse a dummy of paramterized derived type to check the
+ values of LEN parameters. */
+
+tree
+gfc_check_pdt_dummy (gfc_symbol * der_type, tree decl, int rank,
+ gfc_actual_arglist *param_list)
+{
+ tree res;
+ gfc_actual_arglist *old_param_list = pdt_param_list;
+ pdt_param_list = param_list;
+ res = structure_alloc_comps (der_type, decl, NULL_TREE, rank,
+ CHECK_PDT_DUMMY, 0);
+ pdt_param_list = old_param_list;
+ return res;
+}
+
+
/* Returns the value of LBOUND for an expression. This could be broken out
from gfc_conv_intrinsic_bound but this seemed to be simpler. This is
called by gfc_alloc_allocatable_for_assignment. */