summaryrefslogtreecommitdiffstats
path: root/gcc/fortran/trans-expr.c
diff options
context:
space:
mode:
authorjanus <janus@138bc75d-0d04-0410-961f-82ee72b054a4>2009-10-13 16:12:24 +0000
committerjanus <janus@138bc75d-0d04-0410-961f-82ee72b054a4>2009-10-13 16:12:24 +0000
commit39f3dea01a12406705751179d795b548b7393289 (patch)
tree0ad66bf731ba1ac3e83d8ded18791c03cb46d62a /gcc/fortran/trans-expr.c
parent0de338e58429293b03914c193911fa56a2d8b665 (diff)
downloadppe42-gcc-39f3dea01a12406705751179d795b548b7393289.tar.gz
ppe42-gcc-39f3dea01a12406705751179d795b548b7393289.zip
2009-10-13 Janus Weil <janus@gcc.gnu.org>
PR fortran/41581 * decl.c (encapsulate_class_symbol): Add new component '$size'. * resolve.c (resolve_allocate_expr): Move CLASS handling to gfc_trans_allocate. (resolve_class_assign): Replaced by gfc_trans_class_assign. (resolve_code): Remove calls to resolve_class_assign. * trans.c (gfc_trans_code): Use new function gfc_trans_class_assign. * trans-expr.c (get_proc_ptr_comp): Fix a memory leak. (gfc_conv_procedure_call): For CLASS dummies, set the $size component. (gfc_trans_class_assign): New function, replacing resolve_class_assign. * trans-stmt.h (gfc_trans_class_assign): New prototype. * trans-stmt.c (gfc_trans_allocate): Use correct size when allocating CLASS variables. Do proper initialization. Move some code here from resolve_allocate_expr. 2009-10-13 Janus Weil <janus@gcc.gnu.org> PR fortran/41581 * gfortran.dg/class_allocate_2.f03: Modified. * gfortran.dg/class_allocate_3.f03: New test case. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@152715 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/fortran/trans-expr.c')
-rw-r--r--gcc/fortran/trans-expr.c85
1 files changed, 83 insertions, 2 deletions
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index 77953c8e15f..65f13ad8a8d 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -1519,6 +1519,7 @@ get_proc_ptr_comp (gfc_expr *e)
e2 = gfc_copy_expr (e);
e2->expr_type = EXPR_VARIABLE;
gfc_conv_expr (&comp_se, e2);
+ gfc_free_expr (e2);
return build_fold_addr_expr_loc (input_location, comp_se.expr);
}
@@ -2775,6 +2776,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
{
tree data;
tree vindex;
+ tree size;
/* The derived type needs to be converted to a temporary
CLASS object. */
@@ -2788,13 +2790,20 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
var, tmp, NULL_TREE);
tmp = fsym->ts.u.derived->components->next->backend_decl;
vindex = fold_build3 (COMPONENT_REF, TREE_TYPE (tmp),
+ var, tmp, NULL_TREE);
+ tmp = fsym->ts.u.derived->components->next->next->backend_decl;
+ size = fold_build3 (COMPONENT_REF, TREE_TYPE (tmp),
var, tmp, NULL_TREE);
/* Set the vindex. */
- tmp = build_int_cst (TREE_TYPE (vindex),
- e->ts.u.derived->vindex);
+ tmp = build_int_cst (TREE_TYPE (vindex), e->ts.u.derived->vindex);
gfc_add_modify (&parmse.pre, vindex, tmp);
+ /* Set the size. */
+ tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&e->ts));
+ gfc_add_modify (&parmse.pre, size,
+ fold_convert (TREE_TYPE (size), tmp));
+
/* Now set the data field. */
argss = gfc_walk_expr (e);
if (argss == gfc_ss_terminator)
@@ -5261,3 +5270,75 @@ gfc_trans_assign (gfc_code * code)
{
return gfc_trans_assignment (code->expr1, code->expr2, false);
}
+
+
+/* Translate an assignment to a CLASS object
+ (pointer or ordinary assignment). */
+
+tree
+gfc_trans_class_assign (gfc_code *code)
+{
+ stmtblock_t block;
+ tree tmp;
+
+ gfc_start_block (&block);
+
+ if (code->expr2->ts.type != BT_CLASS)
+ {
+ /* Insert an additional assignment which sets the '$vindex' field. */
+ gfc_expr *lhs,*rhs;
+ lhs = gfc_copy_expr (code->expr1);
+ gfc_add_component_ref (lhs, "$vindex");
+ if (code->expr2->ts.type == BT_DERIVED)
+ /* vindex is constant, determined at compile time. */
+ rhs = gfc_int_expr (code->expr2->ts.u.derived->vindex);
+ else if (code->expr2->expr_type == EXPR_NULL)
+ rhs = gfc_int_expr (0);
+ else
+ gcc_unreachable ();
+ tmp = gfc_trans_assignment (lhs, rhs, false);
+ gfc_add_expr_to_block (&block, tmp);
+
+ /* Insert another assignment which sets the '$size' field. */
+ lhs = gfc_copy_expr (code->expr1);
+ gfc_add_component_ref (lhs, "$size");
+ if (code->expr2->ts.type == BT_DERIVED)
+ {
+ /* Size is fixed at compile time. */
+ gfc_se lse;
+ gfc_init_se (&lse, NULL);
+ gfc_conv_expr (&lse, lhs);
+ tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&code->expr2->ts));
+ gfc_add_modify (&block, lse.expr,
+ fold_convert (TREE_TYPE (lse.expr), tmp));
+ }
+ else if (code->expr2->expr_type == EXPR_NULL)
+ {
+ rhs = gfc_int_expr (0);
+ tmp = gfc_trans_assignment (lhs, rhs, false);
+ gfc_add_expr_to_block (&block, tmp);
+ }
+ else
+ gcc_unreachable ();
+
+ gfc_free_expr (lhs);
+ gfc_free_expr (rhs);
+ }
+
+ /* Do the actual CLASS assignment. */
+ if (code->expr2->ts.type == BT_CLASS)
+ code->op = EXEC_ASSIGN;
+ else
+ gfc_add_component_ref (code->expr1, "$data");
+
+ if (code->op == EXEC_ASSIGN)
+ tmp = gfc_trans_assign (code);
+ else if (code->op == EXEC_POINTER_ASSIGN)
+ tmp = gfc_trans_pointer_assign (code);
+ else
+ gcc_unreachable();
+
+ gfc_add_expr_to_block (&block, tmp);
+
+ return gfc_finish_block (&block);
+}
OpenPOWER on IntegriCloud