diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-05-02 14:43:35 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-05-02 14:43:35 +0000 |
commit | 34efdaf078b01a7387007c4e6bde6db86384c4b7 (patch) | |
tree | d503eaf41d085669d1481bb46ec038bc866fece6 /gcc/fortran/trans-array.c | |
parent | f733cf303bcdc952c92b81dd62199a40a1f555ec (diff) | |
download | gcc-tarball-master.tar.gz |
gcc-7.1.0gcc-7.1.0
Diffstat (limited to 'gcc/fortran/trans-array.c')
-rw-r--r-- | gcc/fortran/trans-array.c | 1120 |
1 files changed, 795 insertions, 325 deletions
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index 0882a3a0e7..47e8c091a9 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -1,5 +1,5 @@ /* Array translation routines - Copyright (C) 2002-2016 Free Software Foundation, Inc. + Copyright (C) 2002-2017 Free Software Foundation, Inc. Contributed by Paul Brook <paul@nowt.org> and Steven Bosscher <s.bosscher@student.tudelft.nl> @@ -1094,6 +1094,16 @@ gfc_trans_create_temp_array (stmtblock_t * pre, stmtblock_t * post, gfc_ss * ss, info->descriptor = desc; size = gfc_index_one_node; + /* Emit a DECL_EXPR for the variable sized array type in + GFC_TYPE_ARRAY_DATAPTR_TYPE so the gimplification of its type + sizes works correctly. */ + tree arraytype = TREE_TYPE (GFC_TYPE_ARRAY_DATAPTR_TYPE (type)); + if (! TYPE_NAME (arraytype)) + TYPE_NAME (arraytype) = build_decl (UNKNOWN_LOCATION, TYPE_DECL, + NULL_TREE, arraytype); + gfc_add_expr_to_block (pre, build1 (DECL_EXPR, + arraytype, TYPE_NAME (arraytype))); + /* Fill in the array dtype. */ tmp = gfc_conv_descriptor_dtype (desc); gfc_add_modify (pre, tmp, gfc_get_dtype (TREE_TYPE (desc))); @@ -2216,6 +2226,8 @@ trans_array_constructor (gfc_ss * ss, locus * where) gfc_ss_info *ss_info; gfc_expr *expr; gfc_ss *s; + tree neg_len; + char *msg; /* Save the old values for nested checking. */ old_first_len = first_len; @@ -2229,7 +2241,8 @@ trans_array_constructor (gfc_ss * ss, locus * where) /* Do bounds-checking here and in gfc_trans_array_ctor_element only if no typespec was given for the array constructor. */ - typespec_chararray_ctor = (expr->ts.u.cl + typespec_chararray_ctor = (expr->ts.type == BT_CHARACTER + && expr->ts.u.cl && expr->ts.u.cl->length_from_typespec); if ((gfc_option.rtcheck & GFC_RTCHECK_BOUNDS) @@ -2260,6 +2273,29 @@ trans_array_constructor (gfc_ss * ss, locus * where) gfc_conv_expr_type (&length_se, expr->ts.u.cl->length, gfc_charlen_type_node); ss_info->string_length = length_se.expr; + + /* Check if the character length is negative. If it is, then + set LEN = 0. */ + neg_len = fold_build2_loc (input_location, LT_EXPR, + boolean_type_node, ss_info->string_length, + build_int_cst (gfc_charlen_type_node, 0)); + /* Print a warning if bounds checking is enabled. */ + if (gfc_option.rtcheck & GFC_RTCHECK_BOUNDS) + { + msg = xasprintf ("Negative character length treated as LEN = 0"); + gfc_trans_runtime_check (false, true, neg_len, &length_se.pre, + where, msg); + free (msg); + } + + ss_info->string_length + = fold_build3_loc (input_location, COND_EXPR, + gfc_charlen_type_node, neg_len, + build_int_cst (gfc_charlen_type_node, 0), + ss_info->string_length); + ss_info->string_length = gfc_evaluate_now (ss_info->string_length, + &length_se.pre); + gfc_add_block_to_block (&outer_loop->pre, &length_se.pre); gfc_add_block_to_block (&outer_loop->post, &length_se.post); } @@ -2281,7 +2317,8 @@ trans_array_constructor (gfc_ss * ss, locus * where) type = build_pointer_type (type); } else - type = gfc_typenode_for_spec (&expr->ts); + type = gfc_typenode_for_spec (expr->ts.type == BT_CLASS + ? &CLASS_DATA (expr)->ts : &expr->ts); /* See if the constructor determines the loop bounds. */ dynamic = false; @@ -2361,7 +2398,7 @@ trans_array_constructor (gfc_ss * ss, locus * where) offsetvar, gfc_index_one_node); tmp = gfc_evaluate_now (tmp, &outer_loop->pre); gfc_conv_descriptor_ubound_set (&loop->pre, desc, gfc_rank_cst[0], tmp); - if (*loop_ubound0 && TREE_CODE (*loop_ubound0) == VAR_DECL) + if (*loop_ubound0 && VAR_P (*loop_ubound0)) gfc_add_modify (&outer_loop->pre, *loop_ubound0, tmp); else *loop_ubound0 = tmp; @@ -2669,6 +2706,20 @@ gfc_conv_ss_descriptor (stmtblock_t * block, gfc_ss * ss, int base) if (base) { + if (ss_info->expr->ts.type == BT_CHARACTER && !ss_info->expr->ts.deferred + && ss_info->expr->ts.u.cl->length == NULL) + { + /* Emit a DECL_EXPR for the variable sized array type in + GFC_TYPE_ARRAY_DATAPTR_TYPE so the gimplification of its type + sizes works correctly. */ + tree arraytype = TREE_TYPE ( + GFC_TYPE_ARRAY_DATAPTR_TYPE (TREE_TYPE (info->descriptor))); + if (! TYPE_NAME (arraytype)) + TYPE_NAME (arraytype) = build_decl (UNKNOWN_LOCATION, TYPE_DECL, + NULL_TREE, arraytype); + gfc_add_expr_to_block (block, build1 (DECL_EXPR, arraytype, + TYPE_NAME (arraytype))); + } /* Also the data pointer. */ tmp = gfc_conv_array_data (se.expr); /* If this is a variable or address of a variable we use it directly. @@ -2848,7 +2899,7 @@ trans_array_bound_check (gfc_se * se, gfc_ss *ss, tree index, int n, name = ss->info->expr->symtree->n.sym->name; gcc_assert (name != NULL); - if (TREE_CODE (descriptor) == VAR_DECL) + if (VAR_P (descriptor)) name = IDENTIFIER_POINTER (DECL_NAME (descriptor)); /* If upper bound is present, include both bounds in the error message. */ @@ -3025,50 +3076,57 @@ build_class_array_ref (gfc_se *se, tree base, tree index) tree type; tree size; tree offset; - tree decl; + tree decl = NULL_TREE; tree tmp; gfc_expr *expr = se->ss->info->expr; gfc_ref *ref; - gfc_ref *class_ref; + gfc_ref *class_ref = NULL; gfc_typespec *ts; - if (expr == NULL - || (expr->ts.type != BT_CLASS - && !gfc_is_alloc_class_array_function (expr))) - return false; - - if (expr->symtree && expr->symtree->n.sym->ts.type == BT_CLASS) - ts = &expr->symtree->n.sym->ts; + if (se->expr && DECL_P (se->expr) && DECL_LANG_SPECIFIC (se->expr) + && GFC_DECL_SAVED_DESCRIPTOR (se->expr) + && GFC_CLASS_TYPE_P (TREE_TYPE (GFC_DECL_SAVED_DESCRIPTOR (se->expr)))) + decl = se->expr; else - ts = NULL; - class_ref = NULL; - - for (ref = expr->ref; ref; ref = ref->next) { - if (ref->type == REF_COMPONENT - && ref->u.c.component->ts.type == BT_CLASS - && ref->next && ref->next->type == REF_COMPONENT - && strcmp (ref->next->u.c.component->name, "_data") == 0 - && ref->next->next - && ref->next->next->type == REF_ARRAY - && ref->next->next->u.ar.type != AR_ELEMENT) + if (expr == NULL + || (expr->ts.type != BT_CLASS + && !gfc_is_alloc_class_array_function (expr) + && !gfc_is_class_array_ref (expr, NULL))) + return false; + + if (expr->symtree && expr->symtree->n.sym->ts.type == BT_CLASS) + ts = &expr->symtree->n.sym->ts; + else + ts = NULL; + + for (ref = expr->ref; ref; ref = ref->next) { - ts = &ref->u.c.component->ts; - class_ref = ref; - break; + if (ref->type == REF_COMPONENT + && ref->u.c.component->ts.type == BT_CLASS + && ref->next && ref->next->type == REF_COMPONENT + && strcmp (ref->next->u.c.component->name, "_data") == 0 + && ref->next->next + && ref->next->next->type == REF_ARRAY + && ref->next->next->u.ar.type != AR_ELEMENT) + { + ts = &ref->u.c.component->ts; + class_ref = ref; + break; + } } - } - if (ts == NULL) - return false; + if (ts == NULL) + return false; + } - if (class_ref == NULL && expr->symtree->n.sym->attr.function + if (class_ref == NULL && expr && expr->symtree->n.sym->attr.function && expr->symtree->n.sym == expr->symtree->n.sym->result) { gcc_assert (expr->symtree->n.sym->backend_decl == current_function_decl); decl = gfc_get_fake_result_decl (expr->symtree->n.sym, 0); } - else if (gfc_is_alloc_class_array_function (expr)) + else if (expr && gfc_is_alloc_class_array_function (expr)) { size = NULL_TREE; decl = NULL_TREE; @@ -3085,7 +3143,7 @@ build_class_array_ref (gfc_se *se, tree base, tree index) else type = NULL_TREE; } - if (TREE_CODE (tmp) == VAR_DECL) + if (VAR_P (tmp)) break; } @@ -3094,7 +3152,8 @@ build_class_array_ref (gfc_se *se, tree base, tree index) } else if (class_ref == NULL) { - decl = expr->symtree->n.sym->backend_decl; + if (decl == NULL_TREE) + decl = expr->symtree->n.sym->backend_decl; /* For class arrays the tree containing the class is stored in GFC_DECL_SAVED_DESCRIPTOR of the sym's backend_decl. For all others it's sym's backend_decl directly. */ @@ -3110,6 +3169,7 @@ build_class_array_ref (gfc_se *se, tree base, tree index) class_ref->next = NULL; gfc_init_se (&tmpse, NULL); gfc_conv_expr (&tmpse, expr); + gfc_add_block_to_block (&se->pre, &tmpse.pre); decl = tmpse.expr; class_ref->next = ref; } @@ -3122,9 +3182,22 @@ build_class_array_ref (gfc_se *se, tree base, tree index) size = gfc_class_vtab_size_get (decl); + /* For unlimited polymorphic entities then _len component needs to be + multiplied with the size. If no _len component is present, then + gfc_class_len_or_zero_get () return a zero_node. */ + tmp = gfc_class_len_or_zero_get (decl); + if (!integer_zerop (tmp)) + size = fold_build2 (MULT_EXPR, TREE_TYPE (index), + fold_convert (TREE_TYPE (index), size), + fold_build2 (MAX_EXPR, TREE_TYPE (index), + fold_convert (TREE_TYPE (index), tmp), + fold_convert (TREE_TYPE (index), + integer_one_node))); + else + size = fold_convert (TREE_TYPE (index), size); + /* Build the address of the element. */ type = TREE_TYPE (TREE_TYPE (base)); - size = fold_convert (TREE_TYPE (index), size); offset = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type, index, size); @@ -3322,7 +3395,7 @@ gfc_conv_array_ref (gfc_se * se, gfc_array_ref * ar, gfc_expr *expr, if (ref->type == REF_ARRAY && &ref->u.ar == ar) break; if (ref->type == REF_COMPONENT) - len += 1 + strlen (ref->u.c.component->name); + len += 2 + strlen (ref->u.c.component->name); } var_name = XALLOCAVEC (char, len); @@ -4021,6 +4094,7 @@ done: continue; } /* Otherwise fall through GFC_SS_FUNCTION. */ + gcc_fallthrough (); } case GFC_ISYM_LCOBOUND: case GFC_ISYM_UCOBOUND: @@ -4031,6 +4105,7 @@ done: continue; } + /* FALLTHRU */ case GFC_SS_CONSTRUCTOR: case GFC_SS_FUNCTION: for (n = 0; n < ss->dimen; n++) @@ -5071,19 +5146,20 @@ gfc_array_init_size (tree descriptor, int rank, int corank, tree * poffset, stride = gfc_index_one_node; offset = gfc_index_zero_node; - /* Set the dtype. */ - if (expr->ts.type == BT_CHARACTER && expr->ts.deferred - && TREE_CODE (expr->ts.u.cl->backend_decl) == VAR_DECL) + /* Set the dtype before the alloc, because registration of coarrays needs + it initialized. */ + if (expr->ts.type == BT_CHARACTER + && expr->ts.deferred + && VAR_P (expr->ts.u.cl->backend_decl)) { type = gfc_typenode_for_spec (&expr->ts); tmp = gfc_conv_descriptor_dtype (descriptor); - gfc_add_modify (descriptor_block, tmp, - gfc_get_dtype_rank_type (rank, type)); + gfc_add_modify (pblock, tmp, gfc_get_dtype_rank_type (rank, type)); } else { tmp = gfc_conv_descriptor_dtype (descriptor); - gfc_add_modify (descriptor_block, tmp, gfc_get_dtype (type)); + gfc_add_modify (pblock, tmp, gfc_get_dtype (type)); } or_expr = boolean_false_node; @@ -5392,8 +5468,9 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree status, tree errmsg, stmtblock_t elseblock; gfc_expr **lower; gfc_expr **upper; - gfc_ref *ref, *prev_ref = NULL; - bool allocatable, coarray, dimension, alloc_w_e3_arr_spec = false; + gfc_ref *ref, *prev_ref = NULL, *coref; + bool allocatable, coarray, dimension, alloc_w_e3_arr_spec = false, + non_ulimate_coarray_ptr_comp; ref = expr->ref; @@ -5406,16 +5483,32 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree status, tree errmsg, if (!prev_ref) { allocatable = expr->symtree->n.sym->attr.allocatable; - coarray = expr->symtree->n.sym->attr.codimension; dimension = expr->symtree->n.sym->attr.dimension; + non_ulimate_coarray_ptr_comp = false; } else { allocatable = prev_ref->u.c.component->attr.allocatable; - coarray = prev_ref->u.c.component->attr.codimension; + /* Pointer components in coarrayed derived types must be treated + specially in that they are registered without a check if the are + already associated. This does not hold for ultimate coarray + pointers. */ + non_ulimate_coarray_ptr_comp = (prev_ref->u.c.component->attr.pointer + && !prev_ref->u.c.component->attr.codimension); dimension = prev_ref->u.c.component->attr.dimension; } + /* For allocatable/pointer arrays in derived types, one of the refs has to be + a coarray. In this case it does not matter whether we are on this_image + or not. */ + coarray = false; + for (coref = expr->ref; coref; coref = coref->next) + if (coref->type == REF_ARRAY && coref->u.ar.codimen > 0) + { + coarray = true; + break; + } + if (!dimension) gcc_assert (coarray); @@ -5470,6 +5563,9 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree status, tree errmsg, overflow = integer_zero_node; gfc_init_block (&set_descriptor_block); + /* Take the corank only from the actual ref and not from the coref. The + later will mislead the generation of the array dimensions for allocatable/ + pointer components in derived types. */ size = gfc_array_init_size (se->expr, alloc_w_e3_arr_spec ? expr->rank : ref->u.ar.as->rank, coarray ? ref->u.ar.as->corank : 0, @@ -5511,17 +5607,27 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree status, tree errmsg, if (POINTER_TYPE_P (TREE_TYPE (se->expr))) se->expr = build_fold_indirect_ref_loc (input_location, se->expr); - pointer = gfc_conv_descriptor_data_get (se->expr); - STRIP_NOPS (pointer); - if (coarray && flag_coarray == GFC_FCOARRAY_LIB) - token = gfc_build_addr_expr (NULL_TREE, - gfc_conv_descriptor_token (se->expr)); + { + pointer = non_ulimate_coarray_ptr_comp ? se->expr + : gfc_conv_descriptor_data_get (se->expr); + token = gfc_conv_descriptor_token (se->expr); + token = gfc_build_addr_expr (NULL_TREE, token); + } + else + pointer = gfc_conv_descriptor_data_get (se->expr); + STRIP_NOPS (pointer); /* The allocatable variant takes the old pointer as first argument. */ if (allocatable) gfc_allocate_allocatable (&elseblock, pointer, size, token, - status, errmsg, errlen, label_finish, expr); + status, errmsg, errlen, label_finish, expr, + coref != NULL ? coref->u.ar.as->corank : 0); + else if (non_ulimate_coarray_ptr_comp && token) + /* The token is set only for GFC_FCOARRAY_LIB mode. */ + gfc_allocate_using_caf_lib (&elseblock, pointer, size, token, status, + errmsg, errlen, + GFC_CAF_COARRAY_ALLOC_ALLOCATE_ONLY); else gfc_allocate_using_malloc (&elseblock, pointer, size, status); @@ -5550,70 +5656,17 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree status, tree errmsg, build_int_cst (TREE_TYPE (status), 0)); gfc_add_expr_to_block (&se->pre, fold_build3_loc (input_location, COND_EXPR, void_type_node, - gfc_likely (cond, PRED_FORTRAN_FAIL_ALLOC), + cond, set_descriptor, build_empty_stmt (input_location))); } else gfc_add_expr_to_block (&se->pre, set_descriptor); - if (expr->ts.type == BT_DERIVED && expr->ts.u.derived->attr.alloc_comp - && !coarray) - { - tmp = gfc_nullify_alloc_comp (expr->ts.u.derived, se->expr, - ref->u.ar.as->rank); - gfc_add_expr_to_block (&se->pre, tmp); - } - return true; } -/* Deallocate an array variable. Also used when an allocated variable goes - out of scope. */ -/*GCC ARRAYS*/ - -tree -gfc_array_deallocate (tree descriptor, tree pstat, tree errmsg, tree errlen, - tree label_finish, gfc_expr* expr) -{ - tree var; - tree tmp; - stmtblock_t block; - bool coarray = gfc_is_coarray (expr); - - gfc_start_block (&block); - - /* Get a pointer to the data. */ - var = gfc_conv_descriptor_data_get (descriptor); - STRIP_NOPS (var); - - /* Parameter is the address of the data component. */ - tmp = gfc_deallocate_with_status (coarray ? descriptor : var, pstat, errmsg, - errlen, label_finish, false, expr, coarray); - gfc_add_expr_to_block (&block, tmp); - - /* Zero the data pointer; only for coarrays an error can occur and then - the allocation status may not be changed. */ - tmp = fold_build2_loc (input_location, MODIFY_EXPR, void_type_node, - var, build_int_cst (TREE_TYPE (var), 0)); - if (pstat != NULL_TREE && coarray && flag_coarray == GFC_FCOARRAY_LIB) - { - tree cond; - tree stat = build_fold_indirect_ref_loc (input_location, pstat); - - cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, - stat, build_int_cst (TREE_TYPE (stat), 0)); - tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, - cond, tmp, build_empty_stmt (input_location)); - } - - gfc_add_expr_to_block (&block, tmp); - - return gfc_finish_block (&block); -} - - /* Create an array constructor from an initialization expression. We assume the frontend already did any expansions and conversions. */ @@ -5930,7 +5983,7 @@ gfc_trans_auto_array_allocation (tree decl, gfc_symbol * sym, /* Don't actually allocate space for Cray Pointees. */ if (sym->attr.cray_pointee) { - if (TREE_CODE (GFC_TYPE_ARRAY_OFFSET (type)) == VAR_DECL) + if (VAR_P (GFC_TYPE_ARRAY_OFFSET (type))) gfc_add_modify (&init, GFC_TYPE_ARRAY_OFFSET (type), offset); gfc_add_init_cleanup (block, gfc_finish_block (&init), NULL_TREE); @@ -5963,7 +6016,7 @@ gfc_trans_auto_array_allocation (tree decl, gfc_symbol * sym, } /* Set offset of the array. */ - if (TREE_CODE (GFC_TYPE_ARRAY_OFFSET (type)) == VAR_DECL) + if (VAR_P (GFC_TYPE_ARRAY_OFFSET (type))) gfc_add_modify (&init, GFC_TYPE_ARRAY_OFFSET (type), offset); /* Automatic arrays should not have initializers. */ @@ -6016,14 +6069,14 @@ gfc_trans_g77_array (gfc_symbol * sym, gfc_wrapped_block * block) gfc_start_block (&init); if (sym->ts.type == BT_CHARACTER - && TREE_CODE (sym->ts.u.cl->backend_decl) == VAR_DECL) + && VAR_P (sym->ts.u.cl->backend_decl)) gfc_conv_string_length (sym->ts.u.cl, NULL, &init); /* Evaluate the bounds of the array. */ gfc_trans_array_bounds (type, sym, &offset, &init); /* Set the offset. */ - if (TREE_CODE (GFC_TYPE_ARRAY_OFFSET (type)) == VAR_DECL) + if (VAR_P (GFC_TYPE_ARRAY_OFFSET (type))) gfc_add_modify (&init, GFC_TYPE_ARRAY_OFFSET (type), offset); /* Set the pointer itself if we aren't using the parameter directly. */ @@ -6122,7 +6175,7 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, gfc_start_block (&init); if (sym->ts.type == BT_CHARACTER - && TREE_CODE (sym->ts.u.cl->backend_decl) == VAR_DECL) + && VAR_P (sym->ts.u.cl->backend_decl)) gfc_conv_string_length (sym->ts.u.cl, NULL, &init); checkparm = (as->type == AS_EXPLICIT @@ -6346,7 +6399,7 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, gfc_trans_array_cobounds (type, &init, sym); /* Set the offset. */ - if (TREE_CODE (GFC_TYPE_ARRAY_OFFSET (type)) == VAR_DECL) + if (VAR_P (GFC_TYPE_ARRAY_OFFSET (type))) gfc_add_modify (&init, GFC_TYPE_ARRAY_OFFSET (type), offset); gfc_trans_vla_type_sizes (sym, &init); @@ -6935,6 +6988,7 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr) /* TODO: Optimize passing function return values. */ gfc_se lse; gfc_se rse; + bool deep_copy; /* Start the copying loops. */ gfc_mark_ss_chain_used (loop.temp_ss, 1); @@ -6965,9 +7019,12 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr) gfc_add_block_to_block (&block, &lse.pre); lse.string_length = rse.string_length; + + deep_copy = !se->data_not_needed + && (expr->expr_type == EXPR_VARIABLE + || expr->expr_type == EXPR_ARRAY); tmp = gfc_trans_scalar_assign (&lse, &rse, expr->ts, - expr->expr_type == EXPR_VARIABLE - || expr->expr_type == EXPR_ARRAY, false); + deep_copy, false); gfc_add_expr_to_block (&block, tmp); /* Finish the copying loops. */ @@ -7062,6 +7119,28 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr) loop.from, loop.to, 0, GFC_ARRAY_UNKNOWN, false); parm = gfc_create_var (parmtype, "parm"); + + /* When expression is a class object, then add the class' handle to + the parm_decl. */ + if (expr->ts.type == BT_CLASS && expr->expr_type == EXPR_VARIABLE) + { + gfc_expr *class_expr = gfc_find_and_cut_at_last_class_ref (expr); + gfc_se classse; + + /* class_expr can be NULL, when no _class ref is in expr. + We must not fix this here with a gfc_fix_class_ref (). */ + if (class_expr) + { + gfc_init_se (&classse, NULL); + gfc_conv_expr (&classse, class_expr); + gfc_free_expr (class_expr); + + gcc_assert (classse.pre.head == NULL_TREE + && classse.post.head == NULL_TREE); + gfc_allocate_lang_decl (parm); + GFC_DECL_SAVED_DESCRIPTOR (parm) = classse.expr; + } + } } offset = gfc_index_zero_node; @@ -7223,6 +7302,13 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr) : base; gfc_conv_descriptor_offset_set (&loop.pre, parm, tmp); } + else if (IS_CLASS_ARRAY (expr) && !se->data_not_needed + && (!rank_remap || se->use_offset) + && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc))) + { + gfc_conv_descriptor_offset_set (&loop.pre, parm, + gfc_conv_descriptor_offset_get (desc)); + } else if (onebased && (!rank_remap || se->use_offset) && expr->symtree && !(expr->symtree->n.sym && expr->symtree->n.sym->ts.type == BT_CLASS @@ -7258,6 +7344,18 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr) GFC_DECL_SAVED_DESCRIPTOR (expr->symtree->n.sym->backend_decl) : expr->symtree->n.sym->backend_decl; } + else if (expr->expr_type == EXPR_ARRAY && VAR_P (desc) + && IS_CLASS_ARRAY (expr)) + { + tree vtype; + gfc_allocate_lang_decl (desc); + tmp = gfc_create_var (expr->ts.u.derived->backend_decl, "class"); + GFC_DECL_SAVED_DESCRIPTOR (desc) = tmp; + vtype = gfc_class_vptr_get (tmp); + gfc_add_modify (&se->pre, vtype, + gfc_build_addr_expr (TREE_TYPE (vtype), + gfc_find_vtab (&expr->ts)->backend_decl)); + } if (!se->direct_byref || se->byref_noassign) { /* Get a pointer to the new descriptor. */ @@ -7676,37 +7774,6 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, bool g77, } -/* Generate code to deallocate an array, if it is allocated. */ - -tree -gfc_trans_dealloc_allocated (tree descriptor, bool coarray, gfc_expr *expr) -{ - tree tmp; - tree var; - stmtblock_t block; - - gfc_start_block (&block); - - var = gfc_conv_descriptor_data_get (descriptor); - STRIP_NOPS (var); - - /* Call array_deallocate with an int * present in the second argument. - Although it is ignored here, it's presence ensures that arrays that - are already deallocated are ignored. */ - tmp = gfc_deallocate_with_status (coarray ? descriptor : var, NULL_TREE, - NULL_TREE, NULL_TREE, NULL_TREE, true, - expr, coarray); - gfc_add_expr_to_block (&block, tmp); - - /* Zero the data pointer. */ - tmp = fold_build2_loc (input_location, MODIFY_EXPR, void_type_node, - var, build_int_cst (TREE_TYPE (var), 0)); - gfc_add_expr_to_block (&block, tmp); - - return gfc_finish_block (&block); -} - - /* This helper function calculates the size in words of a full array. */ tree @@ -7752,9 +7819,7 @@ duplicate_allocatable (tree dest, tree src, tree type, int rank, if (!GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (dest))) { - tmp = null_pointer_node; - tmp = fold_build2_loc (input_location, MODIFY_EXPR, type, dest, tmp); - gfc_add_expr_to_block (&block, tmp); + gfc_add_modify (&block, dest, fold_convert (type, null_pointer_node)); null_data = gfc_finish_block (&block); gfc_init_block (&block); @@ -7766,9 +7831,7 @@ duplicate_allocatable (tree dest, tree src, tree type, int rank, if (!no_malloc) { tmp = gfc_call_malloc (&block, type, size); - tmp = fold_build2_loc (input_location, MODIFY_EXPR, void_type_node, - dest, fold_convert (type, tmp)); - gfc_add_expr_to_block (&block, tmp); + gfc_add_modify (&block, dest, fold_convert (type, tmp)); } if (!no_memcpy) @@ -7864,17 +7927,154 @@ gfc_duplicate_allocatable_nocopy (tree dest, tree src, tree type, int rank) } +static tree +duplicate_allocatable_coarray (tree dest, tree dest_tok, tree src, + tree type, int rank) +{ + tree tmp; + tree size; + tree nelems; + tree null_cond; + tree null_data; + stmtblock_t block, globalblock; + + /* If the source is null, set the destination to null. Then, + allocate memory to the destination. */ + gfc_init_block (&block); + gfc_init_block (&globalblock); + + if (!GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (dest))) + { + gfc_se se; + symbol_attribute attr; + tree dummy_desc; + + gfc_init_se (&se, NULL); + gfc_clear_attr (&attr); + attr.allocatable = 1; + dummy_desc = gfc_conv_scalar_to_descriptor (&se, dest, attr); + gfc_add_block_to_block (&globalblock, &se.pre); + size = TYPE_SIZE_UNIT (TREE_TYPE (type)); + + gfc_add_modify (&block, dest, fold_convert (type, null_pointer_node)); + gfc_allocate_using_caf_lib (&block, dummy_desc, size, + gfc_build_addr_expr (NULL_TREE, dest_tok), + NULL_TREE, NULL_TREE, NULL_TREE, + GFC_CAF_COARRAY_ALLOC_REGISTER_ONLY); + null_data = gfc_finish_block (&block); + + gfc_init_block (&block); + + gfc_allocate_using_caf_lib (&block, dummy_desc, + fold_convert (size_type_node, size), + gfc_build_addr_expr (NULL_TREE, dest_tok), + NULL_TREE, NULL_TREE, NULL_TREE, + GFC_CAF_COARRAY_ALLOC); + + tmp = builtin_decl_explicit (BUILT_IN_MEMCPY); + tmp = build_call_expr_loc (input_location, tmp, 3, dest, src, + fold_convert (size_type_node, size)); + gfc_add_expr_to_block (&block, tmp); + } + else + { + /* Set the rank or unitialized memory access may be reported. */ + tmp = gfc_conv_descriptor_dtype (dest); + gfc_add_modify (&globalblock, tmp, build_int_cst (TREE_TYPE (tmp), rank)); + + if (rank) + nelems = gfc_full_array_size (&block, src, rank); + else + nelems = integer_one_node; + + tmp = fold_convert (size_type_node, + TYPE_SIZE_UNIT (gfc_get_element_type (type))); + size = fold_build2_loc (input_location, MULT_EXPR, size_type_node, + fold_convert (size_type_node, nelems), tmp); + + gfc_conv_descriptor_data_set (&block, dest, null_pointer_node); + gfc_allocate_using_caf_lib (&block, dest, fold_convert (size_type_node, + size), + gfc_build_addr_expr (NULL_TREE, dest_tok), + NULL_TREE, NULL_TREE, NULL_TREE, + GFC_CAF_COARRAY_ALLOC_REGISTER_ONLY); + null_data = gfc_finish_block (&block); + + gfc_init_block (&block); + gfc_allocate_using_caf_lib (&block, dest, + fold_convert (size_type_node, size), + gfc_build_addr_expr (NULL_TREE, dest_tok), + NULL_TREE, NULL_TREE, NULL_TREE, + GFC_CAF_COARRAY_ALLOC); + + tmp = builtin_decl_explicit (BUILT_IN_MEMCPY); + tmp = build_call_expr_loc (input_location, tmp, 3, + gfc_conv_descriptor_data_get (dest), + gfc_conv_descriptor_data_get (src), + fold_convert (size_type_node, size)); + gfc_add_expr_to_block (&block, tmp); + } + + tmp = gfc_finish_block (&block); + + /* Null the destination if the source is null; otherwise do + the register and copy. */ + if (!GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (src))) + null_cond = src; + else + null_cond = gfc_conv_descriptor_data_get (src); + + null_cond = convert (pvoid_type_node, null_cond); + null_cond = fold_build2_loc (input_location, NE_EXPR, boolean_type_node, + null_cond, null_pointer_node); + gfc_add_expr_to_block (&globalblock, build3_v (COND_EXPR, null_cond, tmp, + null_data)); + return gfc_finish_block (&globalblock); +} + + +/* Helper function to abstract whether coarray processing is enabled. */ + +static bool +caf_enabled (int caf_mode) +{ + return (caf_mode & GFC_STRUCTURE_CAF_MODE_ENABLE_COARRAY) + == GFC_STRUCTURE_CAF_MODE_ENABLE_COARRAY; +} + + +/* Helper function to abstract whether coarray processing is enabled + and we are in a derived type coarray. */ + +static bool +caf_in_coarray (int caf_mode) +{ + static const int pat = GFC_STRUCTURE_CAF_MODE_ENABLE_COARRAY + | GFC_STRUCTURE_CAF_MODE_IN_COARRAY; + return (caf_mode & pat) == pat; +} + + +/* Helper function to abstract whether coarray is to deallocate only. */ + +bool +gfc_caf_is_dealloc_only (int caf_mode) +{ + return (caf_mode & GFC_STRUCTURE_CAF_MODE_DEALLOC_ONLY) + == GFC_STRUCTURE_CAF_MODE_DEALLOC_ONLY; +} + + /* Recursively traverse an object of derived type, generating code to deallocate, nullify or copy allocatable components. This is the work horse function for the functions named in this enum. */ -enum {DEALLOCATE_ALLOC_COMP = 1, DEALLOCATE_ALLOC_COMP_NO_CAF, - NULLIFY_ALLOC_COMP, COPY_ALLOC_COMP, COPY_ONLY_ALLOC_COMP, - COPY_ALLOC_COMP_CAF}; +enum {DEALLOCATE_ALLOC_COMP = 1, NULLIFY_ALLOC_COMP, + COPY_ALLOC_COMP, COPY_ONLY_ALLOC_COMP, REASSIGN_CAF_COMP}; static tree structure_alloc_comps (gfc_symbol * der_type, tree decl, - tree dest, int rank, int purpose) + tree dest, int rank, int purpose, int caf_mode) { gfc_component *c; gfc_loopinfo loop; @@ -7893,7 +8093,12 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, tree vref, dref; tree null_cond = NULL_TREE; tree add_when_allocated; - bool called_dealloc_with_status; + tree dealloc_fndecl; + tree caf_token; + gfc_symbol *vtab; + int caf_dereg_mode; + symbol_attribute *attr; + bool deallocate_called; gfc_init_block (&fnblock); @@ -7906,10 +8111,10 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, /* Deref dest in sync with decl, but only when it is not NULL. */ if (dest) dest = build_fold_indirect_ref_loc (input_location, dest); - } - /* Just in case it gets dereferenced. */ - decl_type = TREE_TYPE (decl); + /* Update the decl_type because it got dereferenced. */ + decl_type = TREE_TYPE (decl); + } /* If this is an array of derived types with allocatable components build a loop and recursively call this function. */ @@ -7951,16 +8156,18 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, vref = gfc_build_array_ref (var, index, NULL); - if (purpose == COPY_ALLOC_COMP || purpose == COPY_ONLY_ALLOC_COMP) - { + if ((purpose == COPY_ALLOC_COMP || purpose == COPY_ONLY_ALLOC_COMP) + && !caf_enabled (caf_mode)) + { tmp = build_fold_indirect_ref_loc (input_location, gfc_conv_array_data (dest)); dref = gfc_build_array_ref (tmp, index, NULL); tmp = structure_alloc_comps (der_type, vref, dref, rank, - COPY_ALLOC_COMP); + COPY_ALLOC_COMP, 0); } else - tmp = structure_alloc_comps (der_type, vref, NULL_TREE, rank, purpose); + tmp = structure_alloc_comps (der_type, vref, NULL_TREE, rank, purpose, + caf_mode); gfc_add_expr_to_block (&loopbody, tmp); @@ -7998,96 +8205,206 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, bool cmp_has_alloc_comps = (c->ts.type == BT_DERIVED || c->ts.type == BT_CLASS) && c->ts.u.derived->attr.alloc_comp; + bool same_type = (c->ts.type == BT_DERIVED && der_type == c->ts.u.derived) + || (c->ts.type == BT_CLASS && der_type == CLASS_DATA (c)->ts.u.derived); + cdecl = c->backend_decl; ctype = TREE_TYPE (cdecl); switch (purpose) { case DEALLOCATE_ALLOC_COMP: - case DEALLOCATE_ALLOC_COMP_NO_CAF: - /* gfc_deallocate_scalar_with_status calls gfc_deallocate_alloc_comp - (i.e. this function) so generate all the calls and suppress the - recursion from here, if necessary. */ - called_dealloc_with_status = false; gfc_init_block (&tmpblock); - if ((c->ts.type == BT_DERIVED && !c->attr.pointer) - || (c->ts.type == BT_CLASS && !CLASS_DATA (c)->attr.class_pointer)) - { - comp = fold_build3_loc (input_location, COMPONENT_REF, ctype, - decl, cdecl, NULL_TREE); + comp = fold_build3_loc (input_location, COMPONENT_REF, ctype, + decl, cdecl, NULL_TREE); - /* The finalizer frees allocatable components. */ - called_dealloc_with_status - = gfc_add_comp_finalizer_call (&tmpblock, comp, c, - purpose == DEALLOCATE_ALLOC_COMP); + /* Shortcut to get the attributes of the component. */ + if (c->ts.type == BT_CLASS) + { + attr = &CLASS_DATA (c)->attr; + if (attr->class_pointer) + continue; + } + else + { + attr = &c->attr; + if (attr->pointer) + continue; } + + if ((c->ts.type == BT_DERIVED && !c->attr.pointer) + || (c->ts.type == BT_CLASS && !CLASS_DATA (c)->attr.class_pointer)) + /* Call the finalizer, which will free the memory and nullify the + pointer of an array. */ + deallocate_called = gfc_add_comp_finalizer_call (&tmpblock, comp, c, + caf_enabled (caf_mode)) + && attr->dimension; else - comp = NULL_TREE; + deallocate_called = false; - if (c->attr.allocatable && !c->attr.proc_pointer - && (c->attr.dimension - || (c->attr.codimension - && purpose != DEALLOCATE_ALLOC_COMP_NO_CAF))) + /* Add the _class ref for classes. */ + if (c->ts.type == BT_CLASS && attr->allocatable) + comp = gfc_class_data_get (comp); + + add_when_allocated = NULL_TREE; + if (cmp_has_alloc_comps + && !c->attr.pointer && !c->attr.proc_pointer + && !same_type + && !deallocate_called) { - if (comp == NULL_TREE) - comp = fold_build3_loc (input_location, COMPONENT_REF, ctype, - decl, cdecl, NULL_TREE); - tmp = gfc_trans_dealloc_allocated (comp, c->attr.codimension, NULL); - gfc_add_expr_to_block (&tmpblock, tmp); + /* Add checked deallocation of the components. This code is + obviously added because the finalizer is not trusted to free + all memory. */ + if (c->ts.type == BT_CLASS) + { + rank = CLASS_DATA (c)->as ? CLASS_DATA (c)->as->rank : 0; + add_when_allocated + = structure_alloc_comps (CLASS_DATA (c)->ts.u.derived, + comp, NULL_TREE, rank, purpose, + caf_mode); + } + else + { + rank = c->as ? c->as->rank : 0; + add_when_allocated = structure_alloc_comps (c->ts.u.derived, + comp, NULL_TREE, + rank, purpose, + caf_mode); + } } - else if (c->attr.allocatable && !c->attr.codimension) + + if (attr->allocatable && !same_type + && (!attr->codimension || caf_enabled (caf_mode))) { - /* Allocatable scalar components. */ - if (comp == NULL_TREE) - comp = fold_build3_loc (input_location, COMPONENT_REF, ctype, - decl, cdecl, NULL_TREE); + /* Handle all types of components besides components of the + same_type as the current one, because those would create an + endless loop. */ + caf_dereg_mode + = (caf_in_coarray (caf_mode) || attr->codimension) + ? (gfc_caf_is_dealloc_only (caf_mode) + ? GFC_CAF_COARRAY_DEALLOCATE_ONLY + : GFC_CAF_COARRAY_DEREGISTER) + : GFC_CAF_COARRAY_NOCOARRAY; + + caf_token = NULL_TREE; + /* Coarray components are handled directly by + deallocate_with_status. */ + if (!attr->codimension + && caf_dereg_mode != GFC_CAF_COARRAY_NOCOARRAY) + { + if (c->caf_token) + caf_token = fold_build3_loc (input_location, COMPONENT_REF, + TREE_TYPE (c->caf_token), + decl, c->caf_token, NULL_TREE); + else if (attr->dimension && !attr->proc_pointer) + caf_token = gfc_conv_descriptor_token (comp); + } + if (attr->dimension && !attr->codimension && !attr->proc_pointer) + /* When this is an array but not in conjunction with a coarray + then add the data-ref. For coarray'ed arrays the data-ref + is added by deallocate_with_status. */ + comp = gfc_conv_descriptor_data_get (comp); - tmp = gfc_deallocate_scalar_with_status (comp, NULL, true, NULL, - c->ts); - gfc_add_expr_to_block (&tmpblock, tmp); - called_dealloc_with_status = true; + tmp = gfc_deallocate_with_status (comp, NULL_TREE, NULL_TREE, + NULL_TREE, NULL_TREE, true, + NULL, caf_dereg_mode, + add_when_allocated, caf_token); - tmp = fold_build2_loc (input_location, MODIFY_EXPR, - void_type_node, comp, - build_int_cst (TREE_TYPE (comp), 0)); gfc_add_expr_to_block (&tmpblock, tmp); } - else if (c->ts.type == BT_CLASS && CLASS_DATA (c)->attr.allocatable - && (!CLASS_DATA (c)->attr.codimension - || purpose != DEALLOCATE_ALLOC_COMP_NO_CAF)) + else if (attr->allocatable && !attr->codimension + && !deallocate_called) { - /* Allocatable CLASS components. */ - - /* Add reference to '_data' component. */ - tmp = CLASS_DATA (c)->backend_decl; - comp = fold_build3_loc (input_location, COMPONENT_REF, - TREE_TYPE (tmp), comp, tmp, NULL_TREE); - - if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (comp))) - tmp = gfc_trans_dealloc_allocated (comp, - CLASS_DATA (c)->attr.codimension, NULL); + /* Case of recursive allocatable derived types. */ + tree is_allocated; + tree ubound; + tree cdesc; + stmtblock_t dealloc_block; + + gfc_init_block (&dealloc_block); + if (add_when_allocated) + gfc_add_expr_to_block (&dealloc_block, add_when_allocated); + + /* Convert the component into a rank 1 descriptor type. */ + if (attr->dimension) + { + tmp = gfc_get_element_type (TREE_TYPE (comp)); + ubound = gfc_full_array_size (&dealloc_block, comp, + c->ts.type == BT_CLASS + ? CLASS_DATA (c)->as->rank + : c->as->rank); + } else { - tmp = gfc_deallocate_scalar_with_status (comp, NULL_TREE, true, NULL, - CLASS_DATA (c)->ts); - gfc_add_expr_to_block (&tmpblock, tmp); - called_dealloc_with_status = true; - - tmp = fold_build2_loc (input_location, MODIFY_EXPR, - void_type_node, comp, - build_int_cst (TREE_TYPE (comp), 0)); + tmp = TREE_TYPE (comp); + ubound = build_int_cst (gfc_array_index_type, 1); } + + cdesc = gfc_get_array_type_bounds (tmp, 1, 0, &gfc_index_one_node, + &ubound, 1, + GFC_ARRAY_ALLOCATABLE, false); + + cdesc = gfc_create_var (cdesc, "cdesc"); + DECL_ARTIFICIAL (cdesc) = 1; + + gfc_add_modify (&dealloc_block, gfc_conv_descriptor_dtype (cdesc), + gfc_get_dtype_rank_type (1, tmp)); + gfc_conv_descriptor_lbound_set (&dealloc_block, cdesc, + gfc_index_zero_node, + gfc_index_one_node); + gfc_conv_descriptor_stride_set (&dealloc_block, cdesc, + gfc_index_zero_node, + gfc_index_one_node); + gfc_conv_descriptor_ubound_set (&dealloc_block, cdesc, + gfc_index_zero_node, ubound); + + if (attr->dimension) + comp = gfc_conv_descriptor_data_get (comp); + + gfc_conv_descriptor_data_set (&dealloc_block, cdesc, comp); + + /* Now call the deallocator. */ + vtab = gfc_find_vtab (&c->ts); + if (vtab->backend_decl == NULL) + gfc_get_symbol_decl (vtab); + tmp = gfc_build_addr_expr (NULL_TREE, vtab->backend_decl); + dealloc_fndecl = gfc_vptr_deallocate_get (tmp); + dealloc_fndecl = build_fold_indirect_ref_loc (input_location, + dealloc_fndecl); + tmp = build_int_cst (TREE_TYPE (comp), 0); + is_allocated = fold_build2_loc (input_location, NE_EXPR, + boolean_type_node, tmp, + comp); + cdesc = gfc_build_addr_expr (NULL_TREE, cdesc); + + tmp = build_call_expr_loc (input_location, + dealloc_fndecl, 1, + cdesc); + gfc_add_expr_to_block (&dealloc_block, tmp); + + tmp = gfc_finish_block (&dealloc_block); + + tmp = fold_build3_loc (input_location, COND_EXPR, + void_type_node, is_allocated, tmp, + build_empty_stmt (input_location)); + gfc_add_expr_to_block (&tmpblock, tmp); + } + else if (add_when_allocated) + gfc_add_expr_to_block (&tmpblock, add_when_allocated); + if (c->ts.type == BT_CLASS && attr->allocatable + && (!attr->codimension || !caf_enabled (caf_mode))) + { /* Finally, reset the vptr to the declared type vtable and, if necessary reset the _len field. First recover the reference to the component and obtain the vptr. */ comp = fold_build3_loc (input_location, COMPONENT_REF, ctype, - decl, cdecl, NULL_TREE); + decl, cdecl, NULL_TREE); tmp = gfc_class_vptr_get (comp); if (UNLIMITED_POLY (c)) @@ -8114,44 +8431,62 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, } } - if (cmp_has_alloc_comps - && !c->attr.pointer && !c->attr.proc_pointer - && !called_dealloc_with_status) - { - /* Do not deallocate the components of ultimate pointer - components or iteratively call self if call has been made - to gfc_trans_dealloc_allocated */ - comp = fold_build3_loc (input_location, COMPONENT_REF, ctype, - decl, cdecl, NULL_TREE); - rank = c->as ? c->as->rank : 0; - tmp = structure_alloc_comps (c->ts.u.derived, comp, NULL_TREE, - rank, purpose); - gfc_add_expr_to_block (&fnblock, tmp); - } - /* Now add the deallocation of this component. */ gfc_add_block_to_block (&fnblock, &tmpblock); break; case NULLIFY_ALLOC_COMP: - if (c->attr.pointer || c->attr.proc_pointer) + /* Nullify + - allocatable components (regular or in class) + - components that have allocatable components + - pointer components when in a coarray. + Skip everything else especially proc_pointers, which may come + coupled with the regular pointer attribute. */ + if (c->attr.proc_pointer + || !(c->attr.allocatable || (c->ts.type == BT_CLASS + && CLASS_DATA (c)->attr.allocatable) + || (cmp_has_alloc_comps + && ((c->ts.type == BT_DERIVED && !c->attr.pointer) + || (c->ts.type == BT_CLASS + && !CLASS_DATA (c)->attr.class_pointer))) + || (caf_in_coarray (caf_mode) && c->attr.pointer))) continue; - else if (c->attr.allocatable - && (c->attr.dimension|| c->attr.codimension)) + + /* Process class components first, because they always have the + pointer-attribute set which would be caught wrong else. */ + if (c->ts.type == BT_CLASS + && (CLASS_DATA (c)->attr.allocatable + || CLASS_DATA (c)->attr.class_pointer)) { + /* Allocatable CLASS components. */ comp = fold_build3_loc (input_location, COMPONENT_REF, ctype, decl, cdecl, NULL_TREE); - gfc_conv_descriptor_data_set (&fnblock, comp, null_pointer_node); + + comp = gfc_class_data_get (comp); + if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (comp))) + gfc_conv_descriptor_data_set (&fnblock, comp, + null_pointer_node); + else + { + tmp = fold_build2_loc (input_location, MODIFY_EXPR, + void_type_node, comp, + build_int_cst (TREE_TYPE (comp), 0)); + gfc_add_expr_to_block (&fnblock, tmp); + } + cmp_has_alloc_comps = false; } - else if (c->attr.allocatable) + /* Coarrays need the component to be nulled before the api-call + is made. */ + else if (c->attr.pointer || c->attr.allocatable) { - /* Allocatable scalar components. */ comp = fold_build3_loc (input_location, COMPONENT_REF, ctype, decl, cdecl, NULL_TREE); - tmp = fold_build2_loc (input_location, MODIFY_EXPR, - void_type_node, comp, - build_int_cst (TREE_TYPE (comp), 0)); - gfc_add_expr_to_block (&fnblock, tmp); + if (c->attr.dimension || c->attr.codimension) + gfc_conv_descriptor_data_set (&fnblock, comp, + null_pointer_node); + else + gfc_add_modify (&fnblock, comp, + build_int_cst (TREE_TYPE (comp), 0)); if (gfc_deferred_strlen (c, &comp)) { comp = fold_build3_loc (input_location, COMPONENT_REF, @@ -8162,65 +8497,92 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, build_int_cst (TREE_TYPE (comp), 0)); gfc_add_expr_to_block (&fnblock, tmp); } + cmp_has_alloc_comps = false; } - else if (c->ts.type == BT_CLASS && CLASS_DATA (c)->attr.allocatable) + + if (flag_coarray == GFC_FCOARRAY_LIB + && (caf_in_coarray (caf_mode) || c->attr.codimension)) { - /* Allocatable CLASS components. */ + /* Register the component with the coarray library. */ + tree token; + comp = fold_build3_loc (input_location, COMPONENT_REF, ctype, decl, cdecl, NULL_TREE); - /* Add reference to '_data' component. */ - tmp = CLASS_DATA (c)->backend_decl; - comp = fold_build3_loc (input_location, COMPONENT_REF, - TREE_TYPE (tmp), comp, tmp, NULL_TREE); - if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (comp))) - gfc_conv_descriptor_data_set (&fnblock, comp, null_pointer_node); + if (c->attr.dimension || c->attr.codimension) + { + /* Set the dtype, because caf_register needs it. */ + gfc_add_modify (&fnblock, gfc_conv_descriptor_dtype (comp), + gfc_get_dtype (TREE_TYPE (comp))); + tmp = fold_build3_loc (input_location, COMPONENT_REF, ctype, + decl, cdecl, NULL_TREE); + token = gfc_conv_descriptor_token (tmp); + } else { - tmp = fold_build2_loc (input_location, MODIFY_EXPR, - void_type_node, comp, - build_int_cst (TREE_TYPE (comp), 0)); - gfc_add_expr_to_block (&fnblock, tmp); + gfc_se se; + + gfc_init_se (&se, NULL); + token = fold_build3_loc (input_location, COMPONENT_REF, + pvoid_type_node, decl, c->caf_token, + NULL_TREE); + comp = gfc_conv_scalar_to_descriptor (&se, comp, + c->ts.type == BT_CLASS + ? CLASS_DATA (c)->attr + : c->attr); + gfc_add_block_to_block (&fnblock, &se.pre); } + + gfc_allocate_using_caf_lib (&fnblock, comp, size_zero_node, + gfc_build_addr_expr (NULL_TREE, + token), + NULL_TREE, NULL_TREE, NULL_TREE, + GFC_CAF_COARRAY_ALLOC_REGISTER_ONLY); } - else if (cmp_has_alloc_comps) + + if (cmp_has_alloc_comps) { comp = fold_build3_loc (input_location, COMPONENT_REF, ctype, decl, cdecl, NULL_TREE); rank = c->as ? c->as->rank : 0; tmp = structure_alloc_comps (c->ts.u.derived, comp, NULL_TREE, - rank, purpose); + rank, purpose, caf_mode); gfc_add_expr_to_block (&fnblock, tmp); } break; - case COPY_ALLOC_COMP_CAF: - if (!c->attr.codimension - && (c->ts.type != BT_CLASS || CLASS_DATA (c)->attr.coarray_comp) - && (c->ts.type != BT_DERIVED - || !c->ts.u.derived->attr.coarray_comp)) - continue; - - comp = fold_build3_loc (input_location, COMPONENT_REF, ctype, decl, - cdecl, NULL_TREE); - dcmp = fold_build3_loc (input_location, COMPONENT_REF, ctype, dest, - cdecl, NULL_TREE); - - if (c->attr.codimension) + case REASSIGN_CAF_COMP: + if (caf_enabled (caf_mode) + && (c->attr.codimension + || (c->ts.type == BT_CLASS + && (CLASS_DATA (c)->attr.coarray_comp + || caf_in_coarray (caf_mode))) + || (c->ts.type == BT_DERIVED + && (c->ts.u.derived->attr.coarray_comp + || caf_in_coarray (caf_mode)))) + && !same_type) { - if (c->ts.type == BT_CLASS) + comp = fold_build3_loc (input_location, COMPONENT_REF, ctype, + decl, cdecl, NULL_TREE); + dcmp = fold_build3_loc (input_location, COMPONENT_REF, ctype, + dest, cdecl, NULL_TREE); + + if (c->attr.codimension) { - comp = gfc_class_data_get (comp); - dcmp = gfc_class_data_get (dcmp); - } - gfc_conv_descriptor_data_set (&fnblock, dcmp, + if (c->ts.type == BT_CLASS) + { + comp = gfc_class_data_get (comp); + dcmp = gfc_class_data_get (dcmp); + } + gfc_conv_descriptor_data_set (&fnblock, dcmp, gfc_conv_descriptor_data_get (comp)); - } - else - { - tmp = structure_alloc_comps (c->ts.u.derived, comp, dcmp, - rank, purpose); - gfc_add_expr_to_block (&fnblock, tmp); - + } + else + { + tmp = structure_alloc_comps (c->ts.u.derived, comp, dcmp, + rank, purpose, caf_mode + | GFC_STRUCTURE_CAF_MODE_IN_COARRAY); + gfc_add_expr_to_block (&fnblock, tmp); + } } break; @@ -8305,15 +8667,16 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, components that are really allocated, the deep copy code has to be generated first and then added to the if-block in gfc_duplicate_allocatable (). */ - if (cmp_has_alloc_comps - && !c->attr.proc_pointer) + if (cmp_has_alloc_comps && !c->attr.proc_pointer + && !same_type) { rank = c->as ? c->as->rank : 0; tmp = fold_convert (TREE_TYPE (dcmp), comp); gfc_add_modify (&fnblock, dcmp, tmp); add_when_allocated = structure_alloc_comps (c->ts.u.derived, comp, dcmp, - rank, purpose); + rank, purpose, + caf_mode); } else add_when_allocated = NULL_TREE; @@ -8339,13 +8702,25 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, false, false, size, NULL_TREE); gfc_add_expr_to_block (&fnblock, tmp); } - else if (c->attr.allocatable && !c->attr.proc_pointer - && (!(cmp_has_alloc_comps && c->as) - || c->attr.codimension)) + else if (c->attr.allocatable && !c->attr.proc_pointer && !same_type + && (!(cmp_has_alloc_comps && c->as) || c->attr.codimension + || caf_in_coarray (caf_mode))) { rank = c->as ? c->as->rank : 0; if (c->attr.codimension) tmp = gfc_copy_allocatable_data (dcmp, comp, ctype, rank); + else if (flag_coarray == GFC_FCOARRAY_LIB + && caf_in_coarray (caf_mode)) + { + tree dst_tok = c->as ? gfc_conv_descriptor_token (dcmp) + : fold_build3_loc (input_location, + COMPONENT_REF, + pvoid_type_node, dest, + c->caf_token, + NULL_TREE); + tmp = duplicate_allocatable_coarray (dcmp, dst_tok, comp, + ctype, rank); + } else tmp = gfc_duplicate_allocatable (dcmp, comp, ctype, rank, add_when_allocated); @@ -8370,10 +8745,12 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, nullify allocatable components. */ tree -gfc_nullify_alloc_comp (gfc_symbol * der_type, tree decl, int rank) +gfc_nullify_alloc_comp (gfc_symbol * der_type, tree decl, int rank, + int caf_mode) { return structure_alloc_comps (der_type, decl, NULL_TREE, rank, - NULLIFY_ALLOC_COMP); + NULLIFY_ALLOC_COMP, + GFC_STRUCTURE_CAF_MODE_ENABLE_COARRAY | caf_mode); } @@ -8381,10 +8758,12 @@ gfc_nullify_alloc_comp (gfc_symbol * der_type, tree decl, int rank) deallocate allocatable components. */ tree -gfc_deallocate_alloc_comp (gfc_symbol * der_type, tree decl, int rank) +gfc_deallocate_alloc_comp (gfc_symbol * der_type, tree decl, int rank, + int caf_mode) { return structure_alloc_comps (der_type, decl, NULL_TREE, rank, - DEALLOCATE_ALLOC_COMP); + DEALLOCATE_ALLOC_COMP, + GFC_STRUCTURE_CAF_MODE_ENABLE_COARRAY | caf_mode); } @@ -8397,14 +8776,15 @@ tree gfc_deallocate_alloc_comp_no_caf (gfc_symbol * der_type, tree decl, int rank) { return structure_alloc_comps (der_type, decl, NULL_TREE, rank, - DEALLOCATE_ALLOC_COMP_NO_CAF); + DEALLOCATE_ALLOC_COMP, 0); } tree gfc_reassign_alloc_comp_caf (gfc_symbol *der_type, tree decl, tree dest) { - return structure_alloc_comps (der_type, decl, dest, 0, COPY_ALLOC_COMP_CAF); + return structure_alloc_comps (der_type, decl, dest, 0, REASSIGN_CAF_COMP, + GFC_STRUCTURE_CAF_MODE_ENABLE_COARRAY); } @@ -8412,9 +8792,11 @@ gfc_reassign_alloc_comp_caf (gfc_symbol *der_type, tree decl, tree dest) copy it and its allocatable components. */ tree -gfc_copy_alloc_comp (gfc_symbol * der_type, tree decl, tree dest, int rank) +gfc_copy_alloc_comp (gfc_symbol * der_type, tree decl, tree dest, int rank, + int caf_mode) { - return structure_alloc_comps (der_type, decl, dest, rank, COPY_ALLOC_COMP); + return structure_alloc_comps (der_type, decl, dest, rank, COPY_ALLOC_COMP, + caf_mode); } @@ -8424,7 +8806,8 @@ gfc_copy_alloc_comp (gfc_symbol * der_type, tree decl, tree dest, int rank) tree gfc_copy_only_alloc_comp (gfc_symbol * der_type, tree decl, tree dest, int rank) { - return structure_alloc_comps (der_type, decl, dest, rank, COPY_ONLY_ALLOC_COMP); + return structure_alloc_comps (der_type, decl, dest, rank, + COPY_ONLY_ALLOC_COMP, 0); } @@ -8509,6 +8892,14 @@ gfc_is_reallocatable_lhs (gfc_expr *expr) if (!expr->ref) return false; + /* An allocatable class variable with no reference. */ + if (expr->symtree->n.sym->ts.type == BT_CLASS + && CLASS_DATA (expr->symtree->n.sym)->attr.allocatable + && expr->ref && expr->ref->type == REF_COMPONENT + && strcmp (expr->ref->u.c.component->name, "_data") == 0 + && expr->ref->next == NULL) + return true; + /* An allocatable variable. */ if (expr->symtree->n.sym->attr.allocatable && expr->ref @@ -8647,6 +9038,10 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop, int n; int dim; gfc_array_spec * as; + bool coarray = (flag_coarray == GFC_FCOARRAY_LIB + && gfc_caf_attr (expr1, true).codimension); + tree token; + gfc_se caf_se; /* x = f(...) with x allocatable. In this case, expr1 is the rhs. Find the lhs expression in the loop chain and set expr1 and @@ -8884,7 +9279,7 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop, tmp = gfc_conv_descriptor_offset (desc); gfc_add_modify (&fblock, tmp, offset); if (linfo->saved_offset - && TREE_CODE (linfo->saved_offset) == VAR_DECL) + && VAR_P (linfo->saved_offset)) gfc_add_modify (&fblock, linfo->saved_offset, tmp); /* Now set the deltas for the lhs. */ @@ -8895,8 +9290,7 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop, tmp = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type, tmp, loop->from[dim]); - if (linfo->delta[dim] - && TREE_CODE (linfo->delta[dim]) == VAR_DECL) + if (linfo->delta[dim] && VAR_P (linfo->delta[dim])) gfc_add_modify (&fblock, linfo->delta[dim], tmp); } @@ -8905,7 +9299,7 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop, { if (expr2->ts.deferred) { - if (TREE_CODE (expr2->ts.u.cl->backend_decl) == VAR_DECL) + if (VAR_P (expr2->ts.u.cl->backend_decl)) tmp = expr2->ts.u.cl->backend_decl; else tmp = rss->info->string_length; @@ -8923,7 +9317,7 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop, } if (expr1->ts.u.cl->backend_decl - && TREE_CODE (expr1->ts.u.cl->backend_decl) == VAR_DECL) + && VAR_P (expr1->ts.u.cl->backend_decl)) gfc_add_modify (&fblock, expr1->ts.u.cl->backend_decl, tmp); else gfc_add_modify (&fblock, lss->info->string_length, tmp); @@ -8961,11 +9355,32 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop, gfc_add_modify (&fblock, tmp, gfc_get_dtype_rank_type (expr1->rank,type)); } + else if (coarray && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc))) + { + gfc_add_modify (&fblock, gfc_conv_descriptor_dtype (desc), + gfc_get_dtype (TREE_TYPE (desc))); + } /* Realloc expression. Note that the scalarizer uses desc.data in the array reference - (*desc.data)[<element>]. */ gfc_init_block (&realloc_block); + gfc_init_se (&caf_se, NULL); + + if (coarray) + { + token = gfc_get_ultimate_alloc_ptr_comps_caf_token (&caf_se, expr1); + if (token == NULL_TREE) + { + tmp = gfc_get_tree_for_caf_expr (expr1); + if (POINTER_TYPE_P (TREE_TYPE (tmp))) + tmp = build_fold_indirect_ref (tmp); + gfc_get_caf_token_offset (&caf_se, &token, NULL, tmp, NULL_TREE, + expr1); + token = gfc_build_addr_expr (NULL_TREE, token); + } + gfc_add_block_to_block (&realloc_block, &caf_se.pre); + } if ((expr1->ts.type == BT_DERIVED) && expr1->ts.u.derived->attr.alloc_comp) { @@ -8974,12 +9389,34 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop, gfc_add_expr_to_block (&realloc_block, tmp); } - tmp = build_call_expr_loc (input_location, - builtin_decl_explicit (BUILT_IN_REALLOC), 2, - fold_convert (pvoid_type_node, array1), - size2); - gfc_conv_descriptor_data_set (&realloc_block, - desc, tmp); + if (!coarray) + { + tmp = build_call_expr_loc (input_location, + builtin_decl_explicit (BUILT_IN_REALLOC), 2, + fold_convert (pvoid_type_node, array1), + size2); + gfc_conv_descriptor_data_set (&realloc_block, + desc, tmp); + } + else + { + tmp = build_call_expr_loc (input_location, + gfor_fndecl_caf_deregister, 5, token, + build_int_cst (integer_type_node, + GFC_CAF_COARRAY_DEALLOCATE_ONLY), + null_pointer_node, null_pointer_node, + integer_zero_node); + gfc_add_expr_to_block (&realloc_block, tmp); + tmp = build_call_expr_loc (input_location, + gfor_fndecl_caf_register, + 7, size2, + build_int_cst (integer_type_node, + GFC_CAF_COARRAY_ALLOC_ALLOCATE_ONLY), + token, gfc_build_addr_expr (NULL_TREE, desc), + null_pointer_node, null_pointer_node, + integer_zero_node); + gfc_add_expr_to_block (&realloc_block, tmp); + } if ((expr1->ts.type == BT_DERIVED) && expr1->ts.u.derived->attr.alloc_comp) @@ -8989,6 +9426,7 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop, gfc_add_expr_to_block (&realloc_block, tmp); } + gfc_add_block_to_block (&realloc_block, &caf_se.post); realloc_expr = gfc_finish_block (&realloc_block); /* Only reallocate if sizes are different. */ @@ -8999,16 +9437,33 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop, /* Malloc expression. */ gfc_init_block (&alloc_block); - tmp = build_call_expr_loc (input_location, - builtin_decl_explicit (BUILT_IN_MALLOC), - 1, size2); - gfc_conv_descriptor_data_set (&alloc_block, - desc, tmp); + if (!coarray) + { + tmp = build_call_expr_loc (input_location, + builtin_decl_explicit (BUILT_IN_MALLOC), + 1, size2); + gfc_conv_descriptor_data_set (&alloc_block, + desc, tmp); + } + else + { + tmp = build_call_expr_loc (input_location, + gfor_fndecl_caf_register, + 7, size2, + build_int_cst (integer_type_node, + GFC_CAF_COARRAY_ALLOC), + token, gfc_build_addr_expr (NULL_TREE, desc), + null_pointer_node, null_pointer_node, + integer_zero_node); + gfc_add_expr_to_block (&alloc_block, tmp); + } + /* We already set the dtype in the case of deferred character length arrays. */ if (!(GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)) - && expr1->ts.type == BT_CHARACTER && expr1->ts.deferred)) + && ((expr1->ts.type == BT_CHARACTER && expr1->ts.deferred) + || coarray))) { tmp = gfc_conv_descriptor_dtype (desc); gfc_add_modify (&alloc_block, tmp, gfc_get_dtype (TREE_TYPE (desc))); @@ -9032,8 +9487,7 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop, gfc_add_expr_to_block (&fblock, tmp); /* Make sure that the scalarizer data pointer is updated. */ - if (linfo->data - && TREE_CODE (linfo->data) == VAR_DECL) + if (linfo->data && VAR_P (linfo->data)) { tmp = gfc_conv_descriptor_data_get (desc); gfc_add_modify (&fblock, linfo->data, tmp); @@ -9077,8 +9531,8 @@ gfc_trans_deferred_array (gfc_symbol * sym, gfc_wrapped_block * block) gfc_set_backend_locus (&sym->declared_at); gfc_init_block (&init); - gcc_assert (TREE_CODE (sym->backend_decl) == VAR_DECL - || TREE_CODE (sym->backend_decl) == PARM_DECL); + gcc_assert (VAR_P (sym->backend_decl) + || TREE_CODE (sym->backend_decl) == PARM_DECL); if (sym->ts.type == BT_CHARACTER && !INTEGER_CST_P (sym->ts.u.cl->backend_decl)) @@ -9142,7 +9596,20 @@ gfc_trans_deferred_array (gfc_symbol * sym, gfc_wrapped_block * block) /* NULLIFY the data pointer, for non-saved allocatables. */ if (GFC_DESCRIPTOR_TYPE_P (type) && !sym->attr.save && sym->attr.allocatable) - gfc_conv_descriptor_data_set (&init, descriptor, null_pointer_node); + { + gfc_conv_descriptor_data_set (&init, descriptor, null_pointer_node); + if (flag_coarray == GFC_FCOARRAY_LIB && sym->attr.codimension) + { + /* Declare the variable static so its array descriptor stays present + after leaving the scope. It may still be accessed through another + image. This may happen, for example, with the caf_mpi + implementation. */ + TREE_STATIC (descriptor) = 1; + tmp = gfc_conv_descriptor_token (descriptor); + gfc_add_modify (&init, tmp, fold_convert (TREE_TYPE (tmp), + null_pointer_node)); + } + } gfc_restore_backend_locus (&loc); gfc_init_block (&cleanup); @@ -9176,8 +9643,11 @@ gfc_trans_deferred_array (gfc_symbol * sym, gfc_wrapped_block * block) { gfc_expr *e; e = has_finalizer ? gfc_lval_expr_from_sym (sym) : NULL; - tmp = gfc_trans_dealloc_allocated (sym->backend_decl, - sym->attr.codimension, e); + tmp = gfc_deallocate_with_status (sym->backend_decl, NULL_TREE, NULL_TREE, + NULL_TREE, NULL_TREE, true, e, + sym->attr.codimension + ? GFC_CAF_COARRAY_DEREGISTER + : GFC_CAF_COARRAY_NOCOARRAY); if (e) gfc_free_expr (e); gfc_add_expr_to_block (&cleanup, tmp); |