diff options
author | Andre Vehreschild <vehre@gcc.gnu.org> | 2016-10-22 14:33:38 +0200 |
---|---|---|
committer | Andre Vehreschild <vehre@gcc.gnu.org> | 2016-10-22 14:33:38 +0200 |
commit | 574284e9c49687d8bcc039165964602311decd2b (patch) | |
tree | 8ad33cbaa398ee285a2936428641861d6df822e1 /gcc/fortran/trans-expr.c | |
parent | 4e04812da209203a10fbb7197502dd5b8a00459c (diff) | |
download | gcc-574284e9c49687d8bcc039165964602311decd2b.zip gcc-574284e9c49687d8bcc039165964602311decd2b.tar.gz gcc-574284e9c49687d8bcc039165964602311decd2b.tar.bz2 |
re PR fortran/43366 ([OOP][F08] Intrinsic assign to polymorphic variable)
gcc/fortran/ChangeLog:
2016-10-22 Andre Vehreschild <vehre@gcc.gnu.org>
PR fortran/43366
PR fortran/51864
PR fortran/57117
PR fortran/61337
PR fortran/61376
* primary.c (gfc_expr_attr): For transformational functions on classes
get the attrs from the class argument.
* resolve.c (resolve_ordinary_assign): Remove error message due to
feature implementation. Rewrite POINTER_ASSIGNS to ordinary ones when
the right-hand side is scalar class object (with some restrictions).
* trans-array.c (trans_array_constructor): Create the temporary from
class' inner type, i.e., the derived type.
(build_class_array_ref): Add support for class array's storage of the
class object or the array descriptor in the decl saved descriptor.
(gfc_conv_expr_descriptor): When creating temporaries for class objects
add the class object's handle into the decl saved descriptor.
(structure_alloc_comps): Use the common way to get the _data component.
(gfc_is_reallocatable_lhs): Add notion of allocatable class objects.
* trans-expr.c (gfc_find_and_cut_at_last_class_ref): Remove the only ref
only when the expression's type is BT_CLASS.
(gfc_trans_class_init_assign): Correctly handle class arrays.
(gfc_trans_class_assign): Joined into gfc_trans_assignment_1.
(gfc_conv_procedure_call): Support for class types as arguments.
(trans_get_upoly_len): For unlimited polymorphics retrieve the _len
component's tree.
(trans_class_vptr_len_assignment): Catch all ways to assign the _vptr
and _len components of a class object correctly.
(pointer_assignment_is_proc_pointer): Identify assignments of
procedure pointers.
(gfc_trans_pointer_assignment): Enhance support for class object pointer
assignments.
(gfc_trans_scalar_assign): Removed assert.
(trans_class_assignment): Assign to a class object.
(gfc_trans_assignment_1): Treat class objects correctly.
(gfc_trans_assignment): Propagate flags to trans_assignment_1.
* trans-stmt.c (gfc_trans_allocate): Use gfc_trans_assignment now
instead of copy_class_to_class.
* trans-stmt.h: Function prototype removed.
* trans.c (trans_code): Less special casing for class objects.
* trans.h: Added flags to gfc_trans_assignment () prototype.
gcc/testsuite/ChangeLog:
2016-10-22 Andre Vehreschild <vehre@gcc.gnu.org>
Forgot to add on original commit.
* gfortran.dg/coarray_alloc_comp_2.f08: New test.
2016-10-22 Andre Vehreschild <vehre@gcc.gnu.org>
PR fortran/43366
PR fortran/57117
PR fortran/61337
* gfortran.dg/alloc_comp_class_5.f03: New test.
* gfortran.dg/class_allocate_21.f90: New test.
* gfortran.dg/class_allocate_22.f90: New test.
* gfortran.dg/realloc_on_assign_27.f08: New test.
From-SVN: r241439
Diffstat (limited to 'gcc/fortran/trans-expr.c')
-rw-r--r-- | gcc/fortran/trans-expr.c | 562 |
1 files changed, 392 insertions, 170 deletions
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index 2f8ea22..fc03a23 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -350,7 +350,7 @@ gfc_expr * gfc_find_and_cut_at_last_class_ref (gfc_expr *e) { gfc_expr *base_expr; - gfc_ref *ref, *class_ref, *tail, *array_ref; + gfc_ref *ref, *class_ref, *tail = NULL, *array_ref; /* Find the last class reference. */ class_ref = NULL; @@ -383,7 +383,7 @@ gfc_find_and_cut_at_last_class_ref (gfc_expr *e) tail = class_ref->next; class_ref->next = NULL; } - else + else if (e->symtree && e->symtree->n.sym->ts.type == BT_CLASS) { tail = e->ref; e->ref = NULL; @@ -397,7 +397,7 @@ gfc_find_and_cut_at_last_class_ref (gfc_expr *e) gfc_free_ref_list (class_ref->next); class_ref->next = tail; } - else + else if (e->symtree && e->symtree->n.sym->ts.type == BT_CLASS) { gfc_free_ref_list (e->ref); e->ref = tail; @@ -1458,7 +1458,12 @@ gfc_trans_class_init_assign (gfc_code *code) if (code->expr1->ts.type == BT_CLASS && CLASS_DATA (code->expr1)->attr.dimension) - tmp = gfc_trans_class_array_init_assign (rhs, lhs, code->expr1); + { + gfc_array_spec *tmparr = gfc_get_array_spec (); + *tmparr = *CLASS_DATA (code->expr1)->as; + gfc_add_full_array_ref (lhs, tmparr); + tmp = gfc_trans_class_array_init_assign (rhs, lhs, code->expr1); + } else { sz = gfc_copy_expr (code->expr1); @@ -1503,114 +1508,6 @@ gfc_trans_class_init_assign (gfc_code *code) } -/* Translate an assignment to a CLASS object - (pointer or ordinary assignment). */ - -tree -gfc_trans_class_assign (gfc_expr *expr1, gfc_expr *expr2, gfc_exec_op op) -{ - stmtblock_t block; - tree tmp; - gfc_expr *lhs; - gfc_expr *rhs; - gfc_ref *ref; - - gfc_start_block (&block); - - ref = expr1->ref; - while (ref && ref->next) - ref = ref->next; - - /* Class valued proc_pointer assignments do not need any further - preparation. */ - if (ref && ref->type == REF_COMPONENT - && ref->u.c.component->attr.proc_pointer - && expr2->expr_type == EXPR_VARIABLE - && expr2->symtree->n.sym->attr.flavor == FL_PROCEDURE - && op == EXEC_POINTER_ASSIGN) - goto assign; - - if (expr2->ts.type != BT_CLASS) - { - /* Insert an additional assignment which sets the '_vptr' field. */ - gfc_symbol *vtab = NULL; - gfc_symtree *st; - - lhs = gfc_copy_expr (expr1); - gfc_add_vptr_component (lhs); - - if (UNLIMITED_POLY (expr1) - && expr2->expr_type == EXPR_NULL && expr2->ts.type == BT_UNKNOWN) - { - rhs = gfc_get_null_expr (&expr2->where); - goto assign_vptr; - } - - if (expr2->expr_type == EXPR_NULL) - vtab = gfc_find_vtab (&expr1->ts); - else - vtab = gfc_find_vtab (&expr2->ts); - gcc_assert (vtab); - - rhs = gfc_get_expr (); - rhs->expr_type = EXPR_VARIABLE; - gfc_find_sym_tree (vtab->name, vtab->ns, 1, &st); - rhs->symtree = st; - rhs->ts = vtab->ts; -assign_vptr: - tmp = gfc_trans_pointer_assignment (lhs, rhs); - gfc_add_expr_to_block (&block, tmp); - - gfc_free_expr (lhs); - gfc_free_expr (rhs); - } - else if (expr1->ts.type == BT_DERIVED && UNLIMITED_POLY (expr2)) - { - /* F2003:C717 only sequence and bind-C types can come here. */ - gcc_assert (expr1->ts.u.derived->attr.sequence - || expr1->ts.u.derived->attr.is_bind_c); - gfc_add_data_component (expr2); - goto assign; - } - else if (CLASS_DATA (expr2)->attr.dimension && expr2->expr_type != EXPR_FUNCTION) - { - /* Insert an additional assignment which sets the '_vptr' field. */ - lhs = gfc_copy_expr (expr1); - gfc_add_vptr_component (lhs); - - rhs = gfc_copy_expr (expr2); - gfc_add_vptr_component (rhs); - - tmp = gfc_trans_pointer_assignment (lhs, rhs); - gfc_add_expr_to_block (&block, tmp); - - gfc_free_expr (lhs); - gfc_free_expr (rhs); - } - - /* Do the actual CLASS assignment. */ - if (expr2->ts.type == BT_CLASS - && !CLASS_DATA (expr2)->attr.dimension) - op = EXEC_ASSIGN; - else if (expr2->expr_type != EXPR_FUNCTION || expr2->ts.type != BT_CLASS - || !CLASS_DATA (expr2)->attr.dimension) - gfc_add_data_component (expr1); - -assign: - - if (op == EXEC_ASSIGN) - tmp = gfc_trans_assignment (expr1, expr2, false, true); - else if (op == EXEC_POINTER_ASSIGN) - tmp = gfc_trans_pointer_assignment (expr1, expr2); - else - gcc_unreachable(); - - gfc_add_expr_to_block (&block, tmp); - - return gfc_finish_block (&block); -} - - /* End of prototype trans-class.c */ @@ -5908,6 +5805,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, if (comp) ts = comp->ts; + else if (sym->ts.type == BT_CLASS) + ts = CLASS_DATA (sym)->ts; else ts = sym->ts; @@ -5978,7 +5877,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (TREE_TYPE (TREE_TYPE (se->expr))))) se->expr = build_fold_indirect_ref_loc (input_location, - se->expr); + se->expr); /* If the lhs of an assignment x = f(..) is allocatable and f2003 is allowed, we must do the automatic reallocation. @@ -6264,6 +6163,26 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, } } + /* Associate the rhs class object's meta-data with the result, when the + result is a temporary. */ + if (args && args->expr && args->expr->ts.type == BT_CLASS + && sym->ts.type == BT_CLASS && result != NULL_TREE && DECL_P (result) + && !GFC_CLASS_TYPE_P (TREE_TYPE (result))) + { + gfc_se parmse; + gfc_expr *class_expr = gfc_find_and_cut_at_last_class_ref (args->expr); + + gfc_init_se (&parmse, NULL); + parmse.data_not_needed = 1; + gfc_conv_expr (&parmse, class_expr); + if (!DECL_LANG_SPECIFIC (result)) + gfc_allocate_lang_decl (result); + GFC_DECL_SAVED_DESCRIPTOR (result) = parmse.expr; + gfc_free_expr (class_expr); + gcc_assert (parmse.pre.head == NULL_TREE + && parmse.post.head == NULL_TREE); + } + /* Follow the function call with the argument post block. */ if (byref) { @@ -7886,6 +7805,201 @@ gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr) } +/* Get the _len component for an unlimited polymorphic expression. */ + +static tree +trans_get_upoly_len (stmtblock_t *block, gfc_expr *expr) +{ + gfc_se se; + gfc_ref *ref = expr->ref; + + gfc_init_se (&se, NULL); + while (ref && ref->next) + ref = ref->next; + gfc_add_len_component (expr); + gfc_conv_expr (&se, expr); + gfc_add_block_to_block (block, &se.pre); + gcc_assert (se.post.head == NULL_TREE); + if (ref) + { + gfc_free_ref_list (ref->next); + ref->next = NULL; + } + else + { + gfc_free_ref_list (expr->ref); + expr->ref = NULL; + } + return se.expr; +} + + +/* Assign _vptr and _len components as appropriate. BLOCK should be a + statement-list outside of the scalarizer-loop. When code is generated, that + depends on the scalarized expression, it is added to RSE.PRE. + Returns le's _vptr tree and when set the len expressions in to_lenp and + from_lenp to form a le%_vptr%_copy (re, le, [from_lenp, to_lenp]) + expression. */ + +static tree +trans_class_vptr_len_assignment (stmtblock_t *block, gfc_expr * le, + gfc_expr * re, gfc_se *rse, + tree * to_lenp, tree * from_lenp) +{ + gfc_se se; + gfc_expr * vptr_expr; + tree tmp, to_len = NULL_TREE, from_len = NULL_TREE, lhs_vptr; + bool set_vptr = false, temp_rhs = false; + stmtblock_t *pre = block; + + /* Create a temporary for complicated expressions. */ + if (re->expr_type != EXPR_VARIABLE && re->expr_type != EXPR_NULL + && rse->expr != NULL_TREE && !DECL_P (rse->expr)) + { + tmp = gfc_create_var (TREE_TYPE (rse->expr), "rhs"); + pre = &rse->pre; + gfc_add_modify (&rse->pre, tmp, rse->expr); + rse->expr = tmp; + temp_rhs = true; + } + + /* Get the _vptr for the left-hand side expression. */ + gfc_init_se (&se, NULL); + vptr_expr = gfc_find_and_cut_at_last_class_ref (le); + if (vptr_expr != NULL && gfc_expr_attr (vptr_expr).class_ok) + { + /* Care about _len for unlimited polymorphic entities. */ + if (UNLIMITED_POLY (vptr_expr) + || (vptr_expr->ts.type == BT_DERIVED + && vptr_expr->ts.u.derived->attr.unlimited_polymorphic)) + to_len = trans_get_upoly_len (block, vptr_expr); + gfc_add_vptr_component (vptr_expr); + set_vptr = true; + } + else + vptr_expr = gfc_lval_expr_from_sym (gfc_find_vtab (&le->ts)); + se.want_pointer = 1; + gfc_conv_expr (&se, vptr_expr); + gfc_free_expr (vptr_expr); + gfc_add_block_to_block (block, &se.pre); + gcc_assert (se.post.head == NULL_TREE); + lhs_vptr = se.expr; + STRIP_NOPS (lhs_vptr); + + /* Set the _vptr only when the left-hand side of the assignment is a + class-object. */ + if (set_vptr) + { + /* Get the vptr from the rhs expression only, when it is variable. + Functions are expected to be assigned to a temporary beforehand. */ + vptr_expr = re->expr_type == EXPR_VARIABLE + ? gfc_find_and_cut_at_last_class_ref (re) + : NULL; + if (vptr_expr != NULL && vptr_expr->ts.type == BT_CLASS) + { + if (to_len != NULL_TREE) + { + /* Get the _len information from the rhs. */ + if (UNLIMITED_POLY (vptr_expr) + || (vptr_expr->ts.type == BT_DERIVED + && vptr_expr->ts.u.derived->attr.unlimited_polymorphic)) + from_len = trans_get_upoly_len (block, vptr_expr); + } + gfc_add_vptr_component (vptr_expr); + } + else + { + if (re->expr_type == EXPR_VARIABLE + && DECL_P (re->symtree->n.sym->backend_decl) + && DECL_LANG_SPECIFIC (re->symtree->n.sym->backend_decl) + && GFC_DECL_SAVED_DESCRIPTOR (re->symtree->n.sym->backend_decl) + && GFC_CLASS_TYPE_P (TREE_TYPE (GFC_DECL_SAVED_DESCRIPTOR ( + re->symtree->n.sym->backend_decl)))) + { + vptr_expr = NULL; + se.expr = gfc_class_vptr_get (GFC_DECL_SAVED_DESCRIPTOR ( + re->symtree->n.sym->backend_decl)); + if (to_len) + from_len = gfc_class_len_get (GFC_DECL_SAVED_DESCRIPTOR ( + re->symtree->n.sym->backend_decl)); + } + else if (temp_rhs && re->ts.type == BT_CLASS) + { + vptr_expr = NULL; + se.expr = gfc_class_vptr_get (rse->expr); + } + else if (re->expr_type != EXPR_NULL) + /* Only when rhs is non-NULL use its declared type for vptr + initialisation. */ + vptr_expr = gfc_lval_expr_from_sym (gfc_find_vtab (&re->ts)); + else + /* When the rhs is NULL use the vtab of lhs' declared type. */ + vptr_expr = gfc_lval_expr_from_sym (gfc_find_vtab (&le->ts)); + } + + if (vptr_expr) + { + gfc_init_se (&se, NULL); + se.want_pointer = 1; + gfc_conv_expr (&se, vptr_expr); + gfc_free_expr (vptr_expr); + gfc_add_block_to_block (block, &se.pre); + gcc_assert (se.post.head == NULL_TREE); + } + gfc_add_modify (pre, lhs_vptr, fold_convert (TREE_TYPE (lhs_vptr), + se.expr)); + + if (to_len != NULL_TREE) + { + /* The _len component needs to be set. Figure how to get the + value of the right-hand side. */ + if (from_len == NULL_TREE) + { + if (rse->string_length != NULL_TREE) + from_len = rse->string_length; + else if (re->ts.type == BT_CHARACTER && re->ts.u.cl->length) + { + from_len = gfc_get_expr_charlen (re); + gfc_init_se (&se, NULL); + gfc_conv_expr (&se, re->ts.u.cl->length); + gfc_add_block_to_block (block, &se.pre); + gcc_assert (se.post.head == NULL_TREE); + from_len = gfc_evaluate_now (se.expr, block); + } + else + from_len = integer_zero_node; + } + gfc_add_modify (pre, to_len, fold_convert (TREE_TYPE (to_len), + from_len)); + } + } + + /* Return the _len trees only, when requested. */ + if (to_lenp) + *to_lenp = to_len; + if (from_lenp) + *from_lenp = from_len; + return lhs_vptr; +} + +/* Indentify class valued proc_pointer assignments. */ + +static bool +pointer_assignment_is_proc_pointer (gfc_expr * expr1, gfc_expr * expr2) +{ + gfc_ref * ref; + + ref = expr1->ref; + while (ref && ref->next) + ref = ref->next; + + return ref && ref->type == REF_COMPONENT + && ref->u.c.component->attr.proc_pointer + && expr2->expr_type == EXPR_VARIABLE + && expr2->symtree->n.sym->attr.flavor == FL_PROCEDURE; +} + + tree gfc_trans_pointer_assign (gfc_code * code) { @@ -7898,20 +8012,22 @@ gfc_trans_pointer_assign (gfc_code * code) tree gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2) { - gfc_expr *expr1_vptr = NULL; gfc_se lse; gfc_se rse; stmtblock_t block; tree desc; tree tmp; tree decl; - bool scalar; + bool scalar, non_proc_pointer_assign; gfc_ss *ss; gfc_start_block (&block); gfc_init_se (&lse, NULL); + /* Usually testing whether this is not a proc pointer assignment. */ + non_proc_pointer_assign = !pointer_assignment_is_proc_pointer (expr1, expr2); + /* Check whether the expression is a scalar or not; we cannot use expr1->rank as it can be nonzero for proc pointers. */ ss = gfc_walk_expr (expr1); @@ -7920,7 +8036,7 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2) gfc_free_ss_chain (ss); if (expr1->ts.type == BT_DERIVED && expr2->ts.type == BT_CLASS - && expr2->expr_type != EXPR_FUNCTION) + && expr2->expr_type != EXPR_FUNCTION && non_proc_pointer_assign) { gfc_add_data_component (expr2); /* The following is required as gfc_add_data_component doesn't @@ -7937,6 +8053,13 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2) rse.want_pointer = 1; gfc_conv_expr (&rse, expr2); + if (non_proc_pointer_assign && expr1->ts.type == BT_CLASS) + { + trans_class_vptr_len_assignment (&block, expr1, expr2, &rse, NULL, + NULL); + lse.expr = gfc_class_data_get (lse.expr); + } + if (expr1->symtree->n.sym->attr.proc_pointer && expr1->symtree->n.sym->attr.dummy) lse.expr = build_fold_indirect_ref_loc (input_location, @@ -7950,27 +8073,6 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2) gfc_add_block_to_block (&block, &lse.pre); gfc_add_block_to_block (&block, &rse.pre); - /* For string assignments to unlimited polymorphic pointers add an - assignment of the string_length to the _len component of the - pointer. */ - if ((expr1->ts.type == BT_CLASS || expr1->ts.type == BT_DERIVED) - && expr1->ts.u.derived->attr.unlimited_polymorphic - && (expr2->ts.type == BT_CHARACTER || - ((expr2->ts.type == BT_DERIVED || expr2->ts.type == BT_CLASS) - && expr2->ts.u.derived->attr.unlimited_polymorphic))) - { - gfc_expr *len_comp; - gfc_se se; - len_comp = gfc_get_len_component (expr1); - gfc_init_se (&se, NULL); - gfc_conv_expr (&se, len_comp); - - /* ptr % _len = len (str) */ - gfc_add_modify (&block, se.expr, rse.string_length); - lse.string_length = se.expr; - gfc_free_expr (len_comp); - } - /* Check character lengths if character expression. The test is only really added if -fbounds-check is enabled. Exclude deferred character length lefthand sides. */ @@ -7997,9 +8099,6 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2) build_int_cst (gfc_charlen_type_node, 0)); } - if (expr1->ts.type == BT_DERIVED && expr2->ts.type == BT_CLASS) - rse.expr = gfc_class_data_get (rse.expr); - gfc_add_modify (&block, lse.expr, fold_convert (TREE_TYPE (lse.expr), rse.expr)); @@ -8010,6 +8109,7 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2) { gfc_ref* remap; bool rank_remap; + tree expr1_vptr = NULL_TREE; tree strlen_lhs; tree strlen_rhs = NULL_TREE; @@ -8026,9 +8126,6 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2) gfc_init_se (&lse, NULL); if (remap) lse.descriptor_only = 1; - if (expr2->expr_type == EXPR_FUNCTION && expr2->ts.type == BT_CLASS - && expr1->ts.type == BT_CLASS) - expr1_vptr = gfc_copy_expr (expr1); gfc_conv_expr_descriptor (&lse, expr1); strlen_lhs = lse.string_length; desc = lse.expr; @@ -8054,16 +8151,15 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2) rse.expr = gfc_class_data_get (rse.expr); else { + expr1_vptr = trans_class_vptr_len_assignment (&block, expr1, + expr2, &rse, + NULL, NULL); gfc_add_block_to_block (&block, &rse.pre); tmp = gfc_create_var (TREE_TYPE (rse.expr), "ptrtemp"); gfc_add_modify (&lse.pre, tmp, rse.expr); - gfc_add_vptr_component (expr1_vptr); - gfc_init_se (&rse, NULL); - rse.want_pointer = 1; - gfc_conv_expr (&rse, expr1_vptr); - gfc_add_modify (&lse.pre, rse.expr, - fold_convert (TREE_TYPE (rse.expr), + gfc_add_modify (&lse.pre, expr1_vptr, + fold_convert (TREE_TYPE (expr1_vptr), gfc_class_vptr_get (tmp))); rse.expr = gfc_class_data_get (tmp); } @@ -8091,6 +8187,10 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2) { gfc_conv_expr_descriptor (&rse, expr2); strlen_rhs = rse.string_length; + if (expr1->ts.type == BT_CLASS) + expr1_vptr = trans_class_vptr_len_assignment (&block, expr1, + expr2, &rse, + NULL, NULL); } } else if (expr2->expr_type == EXPR_VARIABLE) @@ -8109,12 +8209,22 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2) gfc_init_se (&rse, NULL); rse.descriptor_only = 1; gfc_conv_expr (&rse, expr2); + if (expr1->ts.type == BT_CLASS) + trans_class_vptr_len_assignment (&block, expr1, expr2, &rse, + NULL, NULL); tmp = gfc_get_element_type (TREE_TYPE (rse.expr)); tmp = fold_convert (gfc_array_index_type, size_in_bytes (tmp)); if (!INTEGER_CST_P (tmp)) gfc_add_block_to_block (&lse.post, &rse.pre); gfc_add_modify (&lse.post, GFC_DECL_SPAN(decl), tmp); } + else if (expr1->ts.type == BT_CLASS) + { + rse.expr = NULL_TREE; + rse.string_length = NULL_TREE; + trans_class_vptr_len_assignment (&block, expr1, expr2, &rse, + NULL, NULL); + } } else if (expr2->expr_type == EXPR_FUNCTION && expr2->ts.type == BT_CLASS) { @@ -8128,16 +8238,15 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2) } else { + expr1_vptr = trans_class_vptr_len_assignment (&block, expr1, + expr2, &rse, NULL, + NULL); gfc_add_block_to_block (&block, &rse.pre); tmp = gfc_create_var (TREE_TYPE (rse.expr), "ptrtemp"); gfc_add_modify (&lse.pre, tmp, rse.expr); - gfc_add_vptr_component (expr1_vptr); - gfc_init_se (&rse, NULL); - rse.want_pointer = 1; - gfc_conv_expr (&rse, expr1_vptr); - gfc_add_modify (&lse.pre, rse.expr, - fold_convert (TREE_TYPE (rse.expr), + gfc_add_modify (&lse.pre, expr1_vptr, + fold_convert (TREE_TYPE (expr1_vptr), gfc_class_vptr_get (tmp))); rse.expr = gfc_class_data_get (tmp); gfc_add_modify (&lse.pre, desc, rse.expr); @@ -8156,9 +8265,6 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2) gfc_add_modify (&lse.pre, desc, tmp); } - if (expr1_vptr) - gfc_free_expr (expr1_vptr); - gfc_add_block_to_block (&block, &lse.pre); if (rank_remap) gfc_add_block_to_block (&block, &rse.pre); @@ -8408,7 +8514,6 @@ gfc_trans_scalar_assign (gfc_se * lse, gfc_se * rse, gfc_typespec ts, if (rse->string_length != NULL_TREE) { - gcc_assert (rse->string_length != NULL_TREE); gfc_conv_string_parameter (rse); gfc_add_block_to_block (&block, &rse->pre); rlen = rse->string_length; @@ -9364,14 +9469,101 @@ is_runtime_conformable (gfc_expr *expr1, gfc_expr *expr2) return false; } + +static tree +trans_class_assignment (stmtblock_t *block, gfc_expr *lhs, gfc_expr *rhs, + gfc_se *lse, gfc_se *rse, bool use_vptr_copy) +{ + tree tmp; + tree fcn; + tree stdcopy, to_len, from_len; + vec<tree, va_gc> *args = NULL; + + tmp = trans_class_vptr_len_assignment (block, lhs, rhs, rse, &to_len, + &from_len); + + fcn = gfc_vptr_copy_get (tmp); + + tmp = GFC_CLASS_TYPE_P (TREE_TYPE (rse->expr)) + ? gfc_class_data_get (rse->expr) : rse->expr; + if (use_vptr_copy) + { + if (!POINTER_TYPE_P (TREE_TYPE (tmp)) + || INDIRECT_REF_P (tmp) + || (rhs->ts.type == BT_DERIVED + && rhs->ts.u.derived->attr.unlimited_polymorphic + && !rhs->ts.u.derived->attr.pointer + && !rhs->ts.u.derived->attr.allocatable) + || (UNLIMITED_POLY (rhs) + && !CLASS_DATA (rhs)->attr.pointer + && !CLASS_DATA (rhs)->attr.allocatable)) + vec_safe_push (args, gfc_build_addr_expr (NULL_TREE, tmp)); + else + vec_safe_push (args, tmp); + tmp = GFC_CLASS_TYPE_P (TREE_TYPE (lse->expr)) + ? gfc_class_data_get (lse->expr) : lse->expr; + if (!POINTER_TYPE_P (TREE_TYPE (tmp)) + || INDIRECT_REF_P (tmp) + || (lhs->ts.type == BT_DERIVED + && lhs->ts.u.derived->attr.unlimited_polymorphic + && !lhs->ts.u.derived->attr.pointer + && !lhs->ts.u.derived->attr.allocatable) + || (UNLIMITED_POLY (lhs) + && !CLASS_DATA (lhs)->attr.pointer + && !CLASS_DATA (lhs)->attr.allocatable)) + vec_safe_push (args, gfc_build_addr_expr (NULL_TREE, tmp)); + else + vec_safe_push (args, tmp); + + stdcopy = build_call_vec (TREE_TYPE (TREE_TYPE (fcn)), fcn, args); + + if (to_len != NULL_TREE && !integer_zerop (from_len)) + { + tree extcopy; + vec_safe_push (args, from_len); + vec_safe_push (args, to_len); + extcopy = build_call_vec (TREE_TYPE (TREE_TYPE (fcn)), fcn, args); + + tmp = fold_build2_loc (input_location, GT_EXPR, + boolean_type_node, from_len, + integer_zero_node); + return fold_build3_loc (input_location, COND_EXPR, + void_type_node, tmp, + extcopy, stdcopy); + } + else + return stdcopy; + } + else + { + tree rhst = GFC_CLASS_TYPE_P (TREE_TYPE (lse->expr)) + ? gfc_class_data_get (lse->expr) : lse->expr; + stmtblock_t tblock; + gfc_init_block (&tblock); + if (!POINTER_TYPE_P (TREE_TYPE (tmp))) + tmp = gfc_build_addr_expr (NULL_TREE, tmp); + if (!POINTER_TYPE_P (TREE_TYPE (rhst))) + rhst = gfc_build_addr_expr (NULL_TREE, rhst); + /* When coming from a ptr_copy lhs and rhs are swapped. */ + gfc_add_modify_loc (input_location, &tblock, rhst, + fold_convert (TREE_TYPE (rhst), tmp)); + return gfc_finish_block (&tblock); + } +} + /* Subroutine of gfc_trans_assignment that actually scalarizes the assignment. EXPR1 is the destination/LHS and EXPR2 is the source/RHS. init_flag indicates initialization expressions and dealloc that no - deallocate prior assignment is needed (if in doubt, set true). */ + deallocate prior assignment is needed (if in doubt, set true). + When PTR_COPY is set and expr1 is a class type, then use the _vptr-copy + routine instead of a pointer assignment. Alias resolution is only done, + when MAY_ALIAS is set (the default). This flag is used by ALLOCATE() + where it is known, that newly allocated memory on the lhs can never be + an alias of the rhs. */ static tree gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag, - bool dealloc) + bool dealloc, bool use_vptr_copy, bool may_alias) { gfc_se lse; gfc_se rse; @@ -9387,7 +9579,7 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag, tree string_length; int n; bool maybe_workshare = false; - symbol_attribute lhs_caf_attr, rhs_caf_attr; + symbol_attribute lhs_caf_attr, rhs_caf_attr, lhs_attr; /* Assignment of the form lhs = rhs. */ gfc_start_block (&block); @@ -9408,8 +9600,13 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag, || gfc_is_alloc_class_scalar_function (expr2))) expr2->must_finalize = 1; - lhs_caf_attr = gfc_caf_attr (expr1); - rhs_caf_attr = gfc_caf_attr (expr2); + /* Only analyze the expressions for coarray properties, when in coarray-lib + mode. */ + if (flag_coarray == GFC_FCOARRAY_LIB) + { + lhs_caf_attr = gfc_caf_attr (expr1); + rhs_caf_attr = gfc_caf_attr (expr2); + } if (lss != gfc_ss_terminator) { @@ -9442,7 +9639,8 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag, for (n = 0; n < GFC_MAX_DIMENSIONS; n++) loop.reverse[n] = GFC_ENABLE_REVERSE; /* Resolve any data dependencies in the statement. */ - gfc_conv_resolve_dependencies (&loop, lss, rss); + if (may_alias) + gfc_conv_resolve_dependencies (&loop, lss, rss); /* Setup the scalarizing loops. */ gfc_conv_loop_setup (&loop, &expr2->where); @@ -9589,9 +9787,26 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag, gfc_add_block_to_block (&loop.post, &rse.post); } - if (flag_coarray == GFC_FCOARRAY_LIB - && lhs_caf_attr.codimension && rhs_caf_attr.codimension - && lhs_caf_attr.alloc_comp && rhs_caf_attr.alloc_comp) + lhs_attr = gfc_expr_attr (expr1); + if ((use_vptr_copy || lhs_attr.pointer + || (lhs_attr.allocatable && !lhs_attr.dimension)) + && (expr1->ts.type == BT_CLASS + || (gfc_is_class_array_ref (expr1, NULL) + || gfc_is_class_scalar_expr (expr1)) + || (gfc_is_class_array_ref (expr2, NULL) + || gfc_is_class_scalar_expr (expr2)))) + { + tmp = trans_class_assignment (&body, expr1, expr2, &lse, &rse, + use_vptr_copy || (lhs_attr.allocatable + && !lhs_attr.dimension)); + /* Modify the expr1 after the assignment, to allow the realloc below. + Therefore only needed, when realloc_lhs is enabled. */ + if (flag_realloc_lhs && !lhs_attr.pointer) + gfc_add_data_component (expr1); + } + else if (flag_coarray == GFC_FCOARRAY_LIB + && lhs_caf_attr.codimension && rhs_caf_attr.codimension + && lhs_caf_attr.alloc_comp && rhs_caf_attr.alloc_comp) { gfc_code code; gfc_actual_arglist a1, a2; @@ -9609,7 +9824,13 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag, || scalar_to_array || expr2->expr_type == EXPR_ARRAY, !(l_is_temp || init_flag) && dealloc); + /* Add the pre blocks to the body. */ + gfc_add_block_to_block (&body, &rse.pre); + gfc_add_block_to_block (&body, &lse.pre); gfc_add_expr_to_block (&body, tmp); + /* Add the post blocks to the body. */ + gfc_add_block_to_block (&body, &rse.post); + gfc_add_block_to_block (&body, &lse.post); if (lss == gfc_ss_terminator) { @@ -9724,7 +9945,7 @@ copyable_array_p (gfc_expr * expr) tree gfc_trans_assignment (gfc_expr * expr1, gfc_expr * expr2, bool init_flag, - bool dealloc) + bool dealloc, bool use_vptr_copy, bool may_alias) { tree tmp; @@ -9767,7 +9988,8 @@ gfc_trans_assignment (gfc_expr * expr1, gfc_expr * expr2, bool init_flag, } /* Fallback to the scalarizer to generate explicit loops. */ - return gfc_trans_assignment_1 (expr1, expr2, init_flag, dealloc); + return gfc_trans_assignment_1 (expr1, expr2, init_flag, dealloc, + use_vptr_copy, may_alias); } tree |