aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/trans-expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fortran/trans-expr.c')
-rw-r--r--gcc/fortran/trans-expr.c265
1 files changed, 207 insertions, 58 deletions
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index fd3dd8c2..9bf976a 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -166,72 +166,85 @@ gfc_class_len_get (tree decl)
if (POINTER_TYPE_P (TREE_TYPE (decl)))
decl = build_fold_indirect_ref_loc (input_location, decl);
len = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (decl)),
- CLASS_LEN_FIELD);
+ CLASS_LEN_FIELD);
return fold_build3_loc (input_location, COMPONENT_REF,
TREE_TYPE (len), decl, len,
NULL_TREE);
}
+/* Get the specified FIELD from the VPTR. */
+
static tree
-gfc_vtable_field_get (tree decl, int field)
+vptr_field_get (tree vptr, int fieldno)
{
- tree size;
- tree vptr;
- vptr = gfc_class_vptr_get (decl);
+ tree field;
vptr = build_fold_indirect_ref_loc (input_location, vptr);
- size = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (vptr)),
- field);
- size = fold_build3_loc (input_location, COMPONENT_REF,
- TREE_TYPE (size), vptr, size,
- NULL_TREE);
- /* Always return size as an array index type. */
- if (field == VTABLE_SIZE_FIELD)
- size = fold_convert (gfc_array_index_type, size);
- gcc_assert (size);
- return size;
+ field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (vptr)),
+ fieldno);
+ field = fold_build3_loc (input_location, COMPONENT_REF,
+ TREE_TYPE (field), vptr, field,
+ NULL_TREE);
+ gcc_assert (field);
+ return field;
}
-tree
-gfc_vtable_hash_get (tree decl)
-{
- return gfc_vtable_field_get (decl, VTABLE_HASH_FIELD);
-}
-
+/* Get the field from the class' vptr. */
-tree
-gfc_vtable_size_get (tree decl)
+static tree
+class_vtab_field_get (tree decl, int fieldno)
{
- return gfc_vtable_field_get (decl, VTABLE_SIZE_FIELD);
+ tree vptr;
+ vptr = gfc_class_vptr_get (decl);
+ return vptr_field_get (vptr, fieldno);
}
-tree
-gfc_vtable_extends_get (tree decl)
-{
- return gfc_vtable_field_get (decl, VTABLE_EXTENDS_FIELD);
+/* Define a macro for creating the class_vtab_* and vptr_* accessors in
+ unison. */
+#define VTAB_GET_FIELD_GEN(name, field) tree \
+gfc_class_vtab_## name ##_get (tree cl) \
+{ \
+ return class_vtab_field_get (cl, field); \
+} \
+ \
+tree \
+gfc_vptr_## name ##_get (tree vptr) \
+{ \
+ return vptr_field_get (vptr, field); \
}
+VTAB_GET_FIELD_GEN (hash, VTABLE_HASH_FIELD)
+VTAB_GET_FIELD_GEN (extends, VTABLE_EXTENDS_FIELD)
+VTAB_GET_FIELD_GEN (def_init, VTABLE_DEF_INIT_FIELD)
+VTAB_GET_FIELD_GEN (copy, VTABLE_COPY_FIELD)
+VTAB_GET_FIELD_GEN (final, VTABLE_FINAL_FIELD)
-tree
-gfc_vtable_def_init_get (tree decl)
-{
- return gfc_vtable_field_get (decl, VTABLE_DEF_INIT_FIELD);
-}
+/* The size field is returned as an array index type. Therefore treat
+ it and only it specially. */
tree
-gfc_vtable_copy_get (tree decl)
+gfc_class_vtab_size_get (tree cl)
{
- return gfc_vtable_field_get (decl, VTABLE_COPY_FIELD);
+ tree size;
+ size = class_vtab_field_get (cl, VTABLE_SIZE_FIELD);
+ /* Always return size as an array index type. */
+ size = fold_convert (gfc_array_index_type, size);
+ gcc_assert (size);
+ return size;
}
-
tree
-gfc_vtable_final_get (tree decl)
+gfc_vptr_size_get (tree vptr)
{
- return gfc_vtable_field_get (decl, VTABLE_FINAL_FIELD);
+ tree size;
+ size = vptr_field_get (vptr, VTABLE_SIZE_FIELD);
+ /* Always return size as an array index type. */
+ size = fold_convert (gfc_array_index_type, size);
+ gcc_assert (size);
+ return size;
}
@@ -245,6 +258,61 @@ gfc_vtable_final_get (tree decl)
#undef VTABLE_FINAL_FIELD
+/* Search for the last _class ref in the chain of references of this
+ expression and cut the chain there. Albeit this routine is similiar
+ to class.c::gfc_add_component_ref (), is there a significant
+ difference: gfc_add_component_ref () concentrates on an array ref to
+ be the last ref in the chain. This routine is oblivious to the kind
+ of refs following. */
+
+gfc_expr *
+gfc_find_and_cut_at_last_class_ref (gfc_expr *e)
+{
+ gfc_expr *base_expr;
+ gfc_ref *ref, *class_ref, *tail;
+
+ /* Find the last class reference. */
+ class_ref = NULL;
+ for (ref = e->ref; ref; ref = ref->next)
+ {
+ if (ref->type == REF_COMPONENT
+ && ref->u.c.component->ts.type == BT_CLASS)
+ class_ref = ref;
+
+ if (ref->next == NULL)
+ break;
+ }
+
+ /* Remove and store all subsequent references after the
+ CLASS reference. */
+ if (class_ref)
+ {
+ tail = class_ref->next;
+ class_ref->next = NULL;
+ }
+ else
+ {
+ tail = e->ref;
+ e->ref = NULL;
+ }
+
+ base_expr = gfc_expr_to_initialize (e);
+
+ /* Restore the original tail expression. */
+ if (class_ref)
+ {
+ gfc_free_ref_list (class_ref->next);
+ class_ref->next = tail;
+ }
+ else
+ {
+ gfc_free_ref_list (e->ref);
+ e->ref = tail;
+ }
+ return base_expr;
+}
+
+
/* Reset the vptr to the declared type, e.g. after deallocation. */
void
@@ -294,6 +362,23 @@ gfc_reset_vptr (stmtblock_t *block, gfc_expr *e)
}
+/* Reset the len for unlimited polymorphic objects. */
+
+void
+gfc_reset_len (stmtblock_t *block, gfc_expr *expr)
+{
+ gfc_expr *e;
+ gfc_se se_len;
+ e = gfc_find_and_cut_at_last_class_ref (expr);
+ gfc_add_len_component (e);
+ gfc_init_se (&se_len, NULL);
+ gfc_conv_expr (&se_len, e);
+ gfc_add_modify (block, se_len.expr,
+ fold_convert (TREE_TYPE (se_len.expr), integer_zero_node));
+ gfc_free_expr (e);
+}
+
+
/* Obtain the vptr of the last class reference in an expression.
Return NULL_TREE if no class reference is found. */
@@ -873,7 +958,7 @@ tree
gfc_get_class_array_ref (tree index, tree class_decl)
{
tree data = gfc_class_data_get (class_decl);
- tree size = gfc_vtable_size_get (class_decl);
+ tree size = gfc_class_vtab_size_get (class_decl);
tree offset = fold_build2_loc (input_location, MULT_EXPR,
gfc_array_index_type,
index, size);
@@ -891,39 +976,57 @@ gfc_get_class_array_ref (tree index, tree class_decl)
that the _vptr is set. */
tree
-gfc_copy_class_to_class (tree from, tree to, tree nelems)
+gfc_copy_class_to_class (tree from, tree to, tree nelems, bool unlimited)
{
tree fcn;
tree fcn_type;
tree from_data;
+ tree from_len;
tree to_data;
+ tree to_len;
tree to_ref;
tree from_ref;
vec<tree, va_gc> *args;
tree tmp;
+ tree stdcopy;
+ tree extcopy;
tree index;
- stmtblock_t loopbody;
- stmtblock_t body;
- gfc_loopinfo loop;
args = NULL;
+ /* To prevent warnings on uninitialized variables. */
+ from_len = to_len = NULL_TREE;
if (from != NULL_TREE)
- fcn = gfc_vtable_copy_get (from);
+ fcn = gfc_class_vtab_copy_get (from);
else
- fcn = gfc_vtable_copy_get (to);
+ fcn = gfc_class_vtab_copy_get (to);
fcn_type = TREE_TYPE (TREE_TYPE (fcn));
if (from != NULL_TREE)
- from_data = gfc_class_data_get (from);
+ from_data = gfc_class_data_get (from);
else
- from_data = gfc_vtable_def_init_get (to);
+ from_data = gfc_class_vtab_def_init_get (to);
+
+ if (unlimited)
+ {
+ if (from != NULL_TREE && unlimited)
+ from_len = gfc_class_len_get (from);
+ else
+ from_len = integer_zero_node;
+ }
to_data = gfc_class_data_get (to);
+ if (unlimited)
+ to_len = gfc_class_len_get (to);
if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (to_data)))
{
+ stmtblock_t loopbody;
+ stmtblock_t body;
+ stmtblock_t ifbody;
+ gfc_loopinfo loop;
+
gfc_init_block (&body);
tmp = fold_build2_loc (input_location, MINUS_EXPR,
gfc_array_index_type, nelems,
@@ -955,8 +1058,42 @@ gfc_copy_class_to_class (tree from, tree to, tree nelems)
loop.loopvar[0] = index;
loop.to[0] = nelems;
gfc_trans_scalarizing_loops (&loop, &loopbody);
- gfc_add_block_to_block (&body, &loop.pre);
- tmp = gfc_finish_block (&body);
+ gfc_init_block (&ifbody);
+ gfc_add_block_to_block (&ifbody, &loop.pre);
+ stdcopy = gfc_finish_block (&ifbody);
+ if (unlimited)
+ {
+ vec_safe_push (args, from_len);
+ vec_safe_push (args, to_len);
+ tmp = build_call_vec (fcn_type, fcn, args);
+ /* Build the body of the loop. */
+ gfc_init_block (&loopbody);
+ gfc_add_expr_to_block (&loopbody, tmp);
+
+ /* Build the loop and return. */
+ gfc_init_loopinfo (&loop);
+ loop.dimen = 1;
+ loop.from[0] = gfc_index_zero_node;
+ loop.loopvar[0] = index;
+ loop.to[0] = nelems;
+ gfc_trans_scalarizing_loops (&loop, &loopbody);
+ gfc_init_block (&ifbody);
+ gfc_add_block_to_block (&ifbody, &loop.pre);
+ extcopy = gfc_finish_block (&ifbody);
+
+ tmp = fold_build2_loc (input_location, GT_EXPR,
+ boolean_type_node, from_len,
+ integer_zero_node);
+ tmp = fold_build3_loc (input_location, COND_EXPR,
+ void_type_node, tmp, extcopy, stdcopy);
+ gfc_add_expr_to_block (&body, tmp);
+ tmp = gfc_finish_block (&body);
+ }
+ else
+ {
+ gfc_add_expr_to_block (&body, stdcopy);
+ tmp = gfc_finish_block (&body);
+ }
gfc_cleanup_loop (&loop);
}
else
@@ -964,12 +1101,27 @@ gfc_copy_class_to_class (tree from, tree to, tree nelems)
gcc_assert (!GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (from_data)));
vec_safe_push (args, from_data);
vec_safe_push (args, to_data);
- tmp = build_call_vec (fcn_type, fcn, args);
+ stdcopy = build_call_vec (fcn_type, fcn, args);
+
+ if (unlimited)
+ {
+ vec_safe_push (args, from_len);
+ vec_safe_push (args, to_len);
+ extcopy = build_call_vec (fcn_type, fcn, args);
+ tmp = fold_build2_loc (input_location, GT_EXPR,
+ boolean_type_node, from_len,
+ integer_zero_node);
+ tmp = fold_build3_loc (input_location, COND_EXPR,
+ void_type_node, tmp, extcopy, stdcopy);
+ }
+ else
+ tmp = stdcopy;
}
return tmp;
}
+
static tree
gfc_trans_class_array_init_assign (gfc_expr *rhs, gfc_expr *lhs, gfc_expr *obj)
{
@@ -5693,7 +5845,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
CLASS_DATA (expr->value.function.esym->result)->attr);
}
- final_fndecl = gfc_vtable_final_get (se->expr);
+ final_fndecl = gfc_class_vtab_final_get (se->expr);
is_final = fold_build2_loc (input_location, NE_EXPR,
boolean_type_node,
final_fndecl,
@@ -5704,7 +5856,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
tmp = build_call_expr_loc (input_location,
final_fndecl, 3,
gfc_build_addr_expr (NULL, tmp),
- gfc_vtable_size_get (se->expr),
+ gfc_class_vtab_size_get (se->expr),
boolean_false_node);
tmp = fold_build3_loc (input_location, COND_EXPR,
void_type_node, is_final, tmp,
@@ -8529,7 +8681,7 @@ alloc_scalar_allocatable_for_assignment (stmtblock_t *block,
if (expr1->ts.type == BT_CHARACTER && expr1->ts.deferred)
{
cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node,
- expr1->ts.u.cl->backend_decl, size);
+ lse.string_length, size);
/* Jump past the realloc if the lengths are the same. */
tmp = build3_v (COND_EXPR, cond,
build1_v (GOTO_EXPR, jump_label2),
@@ -8546,10 +8698,7 @@ alloc_scalar_allocatable_for_assignment (stmtblock_t *block,
/* Update the lhs character length. */
size = string_length;
- if (TREE_CODE (expr1->ts.u.cl->backend_decl) == VAR_DECL)
- gfc_add_modify (block, expr1->ts.u.cl->backend_decl, size);
- else
- gfc_add_modify (block, lse.string_length, size);
+ gfc_add_modify (block, lse.string_length, size);
}
}
@@ -8839,7 +8988,7 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
{
/* F2003: Add the code for reallocation on assignment. */
if (flag_realloc_lhs && is_scalar_reallocatable_lhs (expr1))
- alloc_scalar_allocatable_for_assignment (&block, rse.string_length,
+ alloc_scalar_allocatable_for_assignment (&block, string_length,
expr1, expr2);
/* Use the scalar assignment as is. */