aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/trans-stmt.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fortran/trans-stmt.c')
-rw-r--r--gcc/fortran/trans-stmt.c135
1 files changed, 121 insertions, 14 deletions
diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c
index 110534d2a5e..7dc7405c67f 100644
--- a/gcc/fortran/trans-stmt.c
+++ b/gcc/fortran/trans-stmt.c
@@ -3976,7 +3976,7 @@ tree
gfc_trans_allocate (gfc_code * code)
{
gfc_alloc *al;
- gfc_expr *expr, *init_e, *rhs;
+ gfc_expr *expr, *init_e;
gfc_se se;
tree tmp;
tree parm;
@@ -4006,7 +4006,10 @@ gfc_trans_allocate (gfc_code * code)
for (al = code->ext.alloc.list; al != NULL; al = al->next)
{
- expr = al->expr;
+ expr = gfc_copy_expr (al->expr);
+
+ if (expr->ts.type == BT_CLASS)
+ gfc_add_component_ref (expr, "$data");
gfc_init_se (&se, NULL);
gfc_start_block (&se.pre);
@@ -4022,13 +4025,14 @@ gfc_trans_allocate (gfc_code * code)
/* Determine allocate size. */
if (code->expr3 && code->expr3->ts.type == BT_CLASS)
{
- gfc_typespec *ts;
- /* TODO: Size must be determined at run time, since it must equal
- the size of the dynamic type of SOURCE, not the declared type. */
- gfc_error ("Using SOURCE= with a class variable at %L not "
- "supported yet", &code->loc);
- ts = &code->expr3->ts.u.derived->components->ts;
- tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (ts));
+ gfc_expr *sz;
+ gfc_se se_sz;
+ sz = gfc_copy_expr (code->expr3);
+ gfc_add_component_ref (sz, "$size");
+ gfc_init_se (&se_sz, NULL);
+ gfc_conv_expr (&se_sz, sz);
+ gfc_free_expr (sz);
+ tmp = se_sz.expr;
}
else if (code->expr3 && code->expr3->ts.type != BT_CLASS)
tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&code->expr3->ts));
@@ -4070,17 +4074,120 @@ gfc_trans_allocate (gfc_code * code)
/* Initialization via SOURCE block. */
if (code->expr3)
{
- rhs = gfc_copy_expr (code->expr3);
+ gfc_expr *rhs = gfc_copy_expr (code->expr3);
if (rhs->ts.type == BT_CLASS)
- gfc_add_component_ref (rhs, "$data");
- tmp = gfc_trans_assignment (gfc_expr_to_initialize (expr), rhs, false);
+ {
+ gfc_se dst,src,len;
+ gfc_expr *sz;
+ gfc_add_component_ref (rhs, "$data");
+ sz = gfc_copy_expr (code->expr3);
+ gfc_add_component_ref (sz, "$size");
+ gfc_init_se (&dst, NULL);
+ gfc_init_se (&src, NULL);
+ gfc_init_se (&len, NULL);
+ gfc_conv_expr (&dst, expr);
+ gfc_conv_expr (&src, rhs);
+ gfc_conv_expr (&len, sz);
+ gfc_free_expr (sz);
+ tmp = gfc_build_memcpy_call (dst.expr, src.expr, len.expr);
+ }
+ else
+ tmp = gfc_trans_assignment (gfc_expr_to_initialize (expr),
+ rhs, false);
+ gfc_free_expr (rhs);
+ gfc_add_expr_to_block (&block, tmp);
+ }
+ /* Default initializer for CLASS variables. */
+ else if (al->expr->ts.type == BT_CLASS
+ && code->ext.alloc.ts.type == BT_DERIVED
+ && (init_e = gfc_default_initializer (&code->ext.alloc.ts)))
+ {
+ gfc_se dst,src;
+ gfc_init_se (&dst, NULL);
+ gfc_init_se (&src, NULL);
+ gfc_conv_expr (&dst, expr);
+ gfc_conv_expr (&src, init_e);
+ gfc_add_block_to_block (&block, &src.pre);
+ tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&code->ext.alloc.ts));
+ tmp = gfc_build_memcpy_call (dst.expr, src.expr, tmp);
gfc_add_expr_to_block (&block, tmp);
}
/* Add default initializer for those derived types that need them. */
- else if (expr->ts.type == BT_DERIVED && (init_e = gfc_default_initializer (&expr->ts)))
+ else if (expr->ts.type == BT_DERIVED
+ && (init_e = gfc_default_initializer (&expr->ts)))
+ {
+ tmp = gfc_trans_assignment (gfc_expr_to_initialize (expr),
+ init_e, true);
+ gfc_add_expr_to_block (&block, tmp);
+ }
+
+ /* Allocation of CLASS entities. */
+ gfc_free_expr (expr);
+ expr = al->expr;
+ if (expr->ts.type == BT_CLASS)
{
- tmp = gfc_trans_assignment (gfc_expr_to_initialize (expr), init_e, true);
+ gfc_expr *lhs,*rhs;
+ /* Initialize VINDEX for CLASS objects. */
+ lhs = gfc_expr_to_initialize (expr);
+ gfc_add_component_ref (lhs, "$vindex");
+ if (code->expr3 && code->expr3->ts.type == BT_CLASS)
+ {
+ /* vindex must be determined at run time. */
+ rhs = gfc_copy_expr (code->expr3);
+ gfc_add_component_ref (rhs, "$vindex");
+ }
+ else
+ {
+ /* vindex is fixed at compile time. */
+ int vindex;
+ if (code->expr3)
+ vindex = code->expr3->ts.u.derived->vindex;
+ else if (code->ext.alloc.ts.type == BT_DERIVED)
+ vindex = code->ext.alloc.ts.u.derived->vindex;
+ else if (expr->ts.type == BT_CLASS)
+ vindex = expr->ts.u.derived->components->ts.u.derived->vindex;
+ else
+ vindex = expr->ts.u.derived->vindex;
+ rhs = gfc_int_expr (vindex);
+ }
+ tmp = gfc_trans_assignment (lhs, rhs, false);
+ gfc_free_expr (lhs);
+ gfc_free_expr (rhs);
gfc_add_expr_to_block (&block, tmp);
+
+ /* Initialize SIZE for CLASS objects. */
+ lhs = gfc_expr_to_initialize (expr);
+ gfc_add_component_ref (lhs, "$size");
+ rhs = NULL;
+ if (code->expr3 && code->expr3->ts.type == BT_CLASS)
+ {
+ /* Size must be determined at run time. */
+ rhs = gfc_copy_expr (code->expr3);
+ gfc_add_component_ref (rhs, "$size");
+ tmp = gfc_trans_assignment (lhs, rhs, false);
+ gfc_add_expr_to_block (&block, tmp);
+ }
+ else
+ {
+ /* Size is fixed at compile time. */
+ gfc_typespec *ts;
+ gfc_se lse;
+ gfc_init_se (&lse, NULL);
+ gfc_conv_expr (&lse, lhs);
+ if (code->expr3)
+ ts = &code->expr3->ts;
+ else if (code->ext.alloc.ts.type == BT_DERIVED)
+ ts = &code->ext.alloc.ts;
+ else if (expr->ts.type == BT_CLASS)
+ ts = &expr->ts.u.derived->components->ts;
+ else
+ ts = &expr->ts;
+ tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (ts));
+ gfc_add_modify (&block, lse.expr,
+ fold_convert (TREE_TYPE (lse.expr), tmp));
+ }
+ gfc_free_expr (lhs);
+ gfc_free_expr (rhs);
}
}