summaryrefslogtreecommitdiff
path: root/gcc/fortran/trans-intrinsic.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fortran/trans-intrinsic.c')
-rw-r--r--gcc/fortran/trans-intrinsic.c77
1 files changed, 60 insertions, 17 deletions
diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c
index 4b268b34ba7..b101cb46728 100644
--- a/gcc/fortran/trans-intrinsic.c
+++ b/gcc/fortran/trans-intrinsic.c
@@ -5348,6 +5348,7 @@ gfc_conv_intrinsic_transfer (gfc_se * se, gfc_expr * expr)
stmtblock_t block;
int n;
bool scalar_mold;
+ gfc_expr *source_expr, *mold_expr;
info = NULL;
if (se->loop)
@@ -5357,6 +5358,7 @@ gfc_conv_intrinsic_transfer (gfc_se * se, gfc_expr * expr)
source_bytes = length of the source in bytes
source = pointer to the source data. */
arg = expr->value.function.actual;
+ source_expr = arg->expr;
/* Ensure double transfer through LOGICAL preserves all
the needed bits. */
@@ -5376,18 +5378,28 @@ gfc_conv_intrinsic_transfer (gfc_se * se, gfc_expr * expr)
if (arg->expr->rank == 0)
{
gfc_conv_expr_reference (&argse, arg->expr);
- source = argse.expr;
-
- source_type = TREE_TYPE (build_fold_indirect_ref_loc (input_location,
- argse.expr));
+ if (arg->expr->ts.type == BT_CLASS)
+ source = gfc_class_data_get (argse.expr);
+ else
+ source = argse.expr;
/* Obtain the source word length. */
- if (arg->expr->ts.type == BT_CHARACTER)
- tmp = size_of_string_in_bytes (arg->expr->ts.kind,
- argse.string_length);
- else
- tmp = fold_convert (gfc_array_index_type,
- size_in_bytes (source_type));
+ switch (arg->expr->ts.type)
+ {
+ case BT_CHARACTER:
+ tmp = size_of_string_in_bytes (arg->expr->ts.kind,
+ argse.string_length);
+ break;
+ case BT_CLASS:
+ tmp = gfc_vtable_size_get (argse.expr);
+ break;
+ default:
+ source_type = TREE_TYPE (build_fold_indirect_ref_loc (input_location,
+ source));
+ tmp = fold_convert (gfc_array_index_type,
+ size_in_bytes (source_type));
+ break;
+ }
}
else
{
@@ -5464,6 +5476,7 @@ gfc_conv_intrinsic_transfer (gfc_se * se, gfc_expr * expr)
mold_type = the TREE type of MOLD
dest_word_len = destination word length in bytes. */
arg = arg->next;
+ mold_expr = arg->expr;
gfc_init_se (&argse, NULL);
@@ -5473,7 +5486,7 @@ gfc_conv_intrinsic_transfer (gfc_se * se, gfc_expr * expr)
{
gfc_conv_expr_reference (&argse, arg->expr);
mold_type = TREE_TYPE (build_fold_indirect_ref_loc (input_location,
- argse.expr));
+ argse.expr));
}
else
{
@@ -5494,15 +5507,20 @@ gfc_conv_intrinsic_transfer (gfc_se * se, gfc_expr * expr)
mold_type = gfc_get_int_type (arg->expr->ts.kind);
}
- if (arg->expr->ts.type == BT_CHARACTER)
+ /* Obtain the destination word length. */
+ switch (arg->expr->ts.type)
{
+ case BT_CHARACTER:
tmp = size_of_string_in_bytes (arg->expr->ts.kind, argse.string_length);
mold_type = gfc_get_character_type_len (arg->expr->ts.kind, tmp);
+ break;
+ case BT_CLASS:
+ tmp = gfc_vtable_size_get (argse.expr);
+ break;
+ default:
+ tmp = fold_convert (gfc_array_index_type, size_in_bytes (mold_type));
+ break;
}
- else
- tmp = fold_convert (gfc_array_index_type,
- size_in_bytes (mold_type));
-
dest_word_len = gfc_create_var (gfc_array_index_type, NULL);
gfc_add_modify (&se->pre, dest_word_len, tmp);
@@ -5650,8 +5668,21 @@ scalar_transfer:
ptr = convert (build_pointer_type (mold_type), source);
+ /* For CLASS results, allocate the needed memory first. */
+ if (mold_expr->ts.type == BT_CLASS)
+ {
+ tree cdata;
+ cdata = gfc_class_data_get (tmpdecl);
+ tmp = gfc_call_malloc (&se->pre, TREE_TYPE (cdata), dest_word_len);
+ gfc_add_modify (&se->pre, cdata, tmp);
+ }
+
/* Use memcpy to do the transfer. */
- tmp = gfc_build_addr_expr (NULL_TREE, tmpdecl);
+ if (mold_expr->ts.type == BT_CLASS)
+ tmp = gfc_class_data_get (tmpdecl);
+ else
+ tmp = gfc_build_addr_expr (NULL_TREE, tmpdecl);
+
tmp = build_call_expr_loc (input_location,
builtin_decl_explicit (BUILT_IN_MEMCPY), 3,
fold_convert (pvoid_type_node, tmp),
@@ -5659,6 +5690,18 @@ scalar_transfer:
extent);
gfc_add_expr_to_block (&se->pre, tmp);
+ /* For CLASS results, set the _vptr. */
+ if (mold_expr->ts.type == BT_CLASS)
+ {
+ tree vptr;
+ gfc_symbol *vtab;
+ vptr = gfc_class_vptr_get (tmpdecl);
+ vtab = gfc_find_derived_vtab (source_expr->ts.u.derived);
+ gcc_assert (vtab);
+ tmp = gfc_build_addr_expr (NULL_TREE, gfc_get_symbol_decl (vtab));
+ gfc_add_modify (&se->pre, vptr, fold_convert (TREE_TYPE (vptr), tmp));
+ }
+
se->expr = tmpdecl;
}
}