diff options
Diffstat (limited to 'gcc/fortran/trans-intrinsic.c')
-rw-r--r-- | gcc/fortran/trans-intrinsic.c | 77 |
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; } } |