Dear All, I had promised to get the 5-branch up to date in respect of deferred character patches after then had been in place on trunk for "a few weeks". Well, I got pulled away by PR69423 and have only now come back to the earlier patch.
The attached patch corresponds to trunk revisions 232450 and 233589. They did not apply cleanly 5-branch in one or two places but it was no big deal to put them right. Bootstrapped and regtested on FC21/x86_64 - OK for 5-branch? Best regards Paul 2016-03-07 Paul Thomas <pa...@gcc.gnu.org> Backport from trunk. PR fortran/69423 * trans-decl.c (create_function_arglist): Deferred character length functions, with and without declared results, address the passed reference type as '.result' and the local string length as '..result'. (gfc_null_and_pass_deferred_len): Helper function to null and return deferred string lengths, as needed. (gfc_trans_deferred_vars): Call it, thereby reducing repeated code, add call for deferred arrays and reroute pointer function results. Avoid using 'tmp' for anything other that a temporary tree by introducing 'type_of_array' for the arrayspec type. 2016-03-07 Paul Thomas <pa...@gcc.gnu.org> Backport from trunk. PR fortran/64324 * resolve.c (check_uop_procedure): Prevent deferred length characters from being trapped by assumed length error. Backport from trunk. PR fortran/49630 PR fortran/54070 PR fortran/60593 PR fortran/60795 PR fortran/61147 PR fortran/64324 * trans-array.c (gfc_conv_scalarized_array_ref): Pass decl for function as well as variable expressions. (gfc_array_init_size): Add 'expr' as an argument. Use this to correctly set the descriptor dtype for deferred characters. (gfc_array_allocate): Add 'expr' to the call to 'gfc_array_init_size'. * trans.c (gfc_build_array_ref): Expand logic for setting span to include indirect references to character lengths. * trans-decl.c (gfc_get_symbol_decl): Ensure that deferred result char lengths that are PARM_DECLs are indirectly referenced both for directly passed and by reference. (create_function_arglist): If the length type is a pointer type then store the length as the 'passed_length' and make the char length an indirect reference to it. (gfc_trans_deferred_vars): If a character length has escaped being set as an indirect reference, return it via the 'passed length'. * trans-expr.c (gfc_conv_procedure_call): The length of deferred character length results is set TREE_STATIC and set to zero. (gfc_trans_assignment_1): Do not fix the rse string_length if it is a variable, a parameter or an indirect reference. Add the code to trap assignment of scalars to unallocated arrays. * trans-stmt.c (gfc_trans_allocate): Remove 'def_str_len' and all references to it. Instead, replicate the code to obtain a explicitly defined string length and provide a value before array allocation so that the dtype is correctly set. trans-types.c (gfc_get_character_type): If the character length is a pointer, use the indirect reference. 2016-03-07 Paul Thomas <pa...@gcc.gnu.org> Backport from trunk. PR fortran/69423 * gfortran.dg/deferred_character_15.f90 : New test. 2016-03-07 Paul Thomas <pa...@gcc.gnu.org> Backport from trunk. PR fortran/49630 * gfortran.dg/deferred_character_13.f90: New test for the fix of comment 3 of the PR. Backport from trunk. PR fortran/54070 * gfortran.dg/deferred_character_8.f90: New test * gfortran.dg/allocate_error_5.f90: New test Backport from trunk. PR fortran/60593 * gfortran.dg/deferred_character_10.f90: New test Backport from trunk. PR fortran/60795 * gfortran.dg/deferred_character_14.f90: New test Backport from trunk. PR fortran/61147 * gfortran.dg/deferred_character_11.f90: New test Backport from trunk. PR fortran/64324 * gfortran.dg/deferred_character_9.f90: New test -- The difference between genius and stupidity is; genius has its limits. Albert Einstein
Index: gcc/fortran/resolve.c =================================================================== *** gcc/fortran/resolve.c (revision 232481) --- gcc/fortran/resolve.c (working copy) *************** check_uop_procedure (gfc_symbol *sym, lo *** 14904,14912 **** } if (sym->ts.type == BT_CHARACTER ! && !(sym->ts.u.cl && sym->ts.u.cl->length) ! && !(sym->result && sym->result->ts.u.cl ! && sym->result->ts.u.cl->length)) { gfc_error ("User operator procedure %qs at %L cannot be assumed " "character length", sym->name, &where); --- 14904,14912 ---- } if (sym->ts.type == BT_CHARACTER ! && !((sym->ts.u.cl && sym->ts.u.cl->length) || sym->ts.deferred) ! && !(sym->result && ((sym->result->ts.u.cl ! && sym->result->ts.u.cl->length) || sym->result->ts.deferred))) { gfc_error ("User operator procedure %qs at %L cannot be assumed " "character length", sym->name, &where); Index: gcc/fortran/trans-array.c =================================================================== *** gcc/fortran/trans-array.c (revision 232482) --- gcc/fortran/trans-array.c (working copy) *************** gfc_conv_scalarized_array_ref (gfc_se * *** 3113,3119 **** index, info->offset); if (expr && (is_subref_array (expr) ! || (expr->ts.deferred && expr->expr_type == EXPR_VARIABLE))) decl = expr->symtree->n.sym->backend_decl; tmp = build_fold_indirect_ref_loc (input_location, info->data); --- 3113,3120 ---- index, info->offset); if (expr && (is_subref_array (expr) ! || (expr->ts.deferred && (expr->expr_type == EXPR_VARIABLE ! || expr->expr_type == EXPR_FUNCTION)))) decl = expr->symtree->n.sym->backend_decl; tmp = build_fold_indirect_ref_loc (input_location, info->data); *************** static tree *** 4957,4963 **** gfc_array_init_size (tree descriptor, int rank, int corank, tree * poffset, gfc_expr ** lower, gfc_expr ** upper, stmtblock_t * pblock, stmtblock_t * descriptor_block, tree * overflow, ! tree expr3_elem_size, tree *nelems, gfc_expr *expr3) { tree type; tree tmp; --- 4958,4965 ---- gfc_array_init_size (tree descriptor, int rank, int corank, tree * poffset, gfc_expr ** lower, gfc_expr ** upper, stmtblock_t * pblock, stmtblock_t * descriptor_block, tree * overflow, ! tree expr3_elem_size, tree *nelems, gfc_expr *expr3, ! gfc_expr *expr) { tree type; tree tmp; *************** gfc_array_init_size (tree descriptor, in *** 4982,4989 **** --- 4984,5002 ---- 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) + { + 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)); + } + else + { tmp = gfc_conv_descriptor_dtype (descriptor); gfc_add_modify (descriptor_block, tmp, gfc_get_dtype (type)); + } or_expr = boolean_false_node; *************** gfc_array_allocate (gfc_se * se, gfc_exp *** 5295,5301 **** size = gfc_array_init_size (se->expr, ref->u.ar.as->rank, ref->u.ar.as->corank, &offset, lower, upper, &se->pre, &set_descriptor_block, &overflow, ! expr3_elem_size, nelems, expr3); if (dimension) { --- 5308,5314 ---- size = gfc_array_init_size (se->expr, ref->u.ar.as->rank, ref->u.ar.as->corank, &offset, lower, upper, &se->pre, &set_descriptor_block, &overflow, ! expr3_elem_size, nelems, expr3, expr); if (dimension) { Index: gcc/fortran/trans-decl.c =================================================================== *** gcc/fortran/trans-decl.c (revision 232481) --- gcc/fortran/trans-decl.c (working copy) *************** gfc_get_symbol_decl (gfc_symbol * sym) *** 1340,1347 **** && TREE_CODE (sym->ts.u.cl->backend_decl) == PARM_DECL) { sym->ts.u.cl->passed_length = sym->ts.u.cl->backend_decl; ! sym->ts.u.cl->backend_decl = NULL_TREE; ! length = gfc_create_string_length (sym); } fun_or_res = byref && (sym->attr.result --- 1340,1347 ---- && TREE_CODE (sym->ts.u.cl->backend_decl) == PARM_DECL) { sym->ts.u.cl->passed_length = sym->ts.u.cl->backend_decl; ! gcc_assert (POINTER_TYPE_P (TREE_TYPE (sym->ts.u.cl->passed_length))); ! sym->ts.u.cl->backend_decl = build_fold_indirect_ref (sym->ts.u.cl->backend_decl); } fun_or_res = byref && (sym->attr.result *************** gfc_get_symbol_decl (gfc_symbol * sym) *** 1383,1391 **** --- 1383,1394 ---- /* We need to insert a indirect ref for param decls. */ if (sym->ts.u.cl->backend_decl && TREE_CODE (sym->ts.u.cl->backend_decl) == PARM_DECL) + { + sym->ts.u.cl->passed_length = sym->ts.u.cl->backend_decl; sym->ts.u.cl->backend_decl = build_fold_indirect_ref (sym->ts.u.cl->backend_decl); } + } /* For all other parameters make sure, that they are copied so that the value and any modifications are local to the routine by generating a temporary variable. */ *************** gfc_get_symbol_decl (gfc_symbol * sym) *** 1394,1399 **** --- 1397,1406 ---- && sym->ts.u.cl->backend_decl) { sym->ts.u.cl->passed_length = sym->ts.u.cl->backend_decl; + if (POINTER_TYPE_P (TREE_TYPE (sym->ts.u.cl->passed_length))) + sym->ts.u.cl->backend_decl + = build_fold_indirect_ref (sym->ts.u.cl->backend_decl); + else sym->ts.u.cl->backend_decl = NULL_TREE; } } *************** create_function_arglist (gfc_symbol * sy *** 2170,2176 **** PARM_DECL, get_identifier (".__result"), len_type); ! if (!sym->ts.u.cl->length) { sym->ts.u.cl->backend_decl = length; TREE_USED (length) = 1; --- 2177,2188 ---- PARM_DECL, get_identifier (".__result"), len_type); ! if (POINTER_TYPE_P (len_type)) ! { ! sym->ts.u.cl->passed_length = length; ! TREE_USED (length) = 1; ! } ! else if (!sym->ts.u.cl->length) { sym->ts.u.cl->backend_decl = length; TREE_USED (length) = 1; *************** create_function_arglist (gfc_symbol * sy *** 2290,2296 **** if (f->sym->ts.u.cl->backend_decl == NULL || f->sym->ts.u.cl->backend_decl == length) { ! if (f->sym->ts.u.cl->backend_decl == NULL) gfc_create_string_length (f->sym); /* Make sure PARM_DECL type doesn't point to incomplete type. */ --- 2302,2311 ---- if (f->sym->ts.u.cl->backend_decl == NULL || f->sym->ts.u.cl->backend_decl == length) { ! if (POINTER_TYPE_P (len_type)) ! f->sym->ts.u.cl->backend_decl = ! build_fold_indirect_ref_loc (input_location, length); ! else if (f->sym->ts.u.cl->backend_decl == NULL) gfc_create_string_length (f->sym); /* Make sure PARM_DECL type doesn't point to incomplete type. */ *************** init_intent_out_dt (gfc_symbol * proc_sy *** 3828,3833 **** --- 3843,3904 ---- } + /* Helper function to manage deferred string lengths. */ + + static tree + gfc_null_and_pass_deferred_len (gfc_symbol *sym, stmtblock_t *init, + locus *loc) + { + tree tmp; + + /* Character length passed by reference. */ + tmp = sym->ts.u.cl->passed_length; + tmp = build_fold_indirect_ref_loc (input_location, tmp); + tmp = fold_convert (gfc_charlen_type_node, tmp); + + if (!sym->attr.dummy || sym->attr.intent == INTENT_OUT) + /* Zero the string length when entering the scope. */ + gfc_add_modify (init, sym->ts.u.cl->backend_decl, + build_int_cst (gfc_charlen_type_node, 0)); + else + { + tree tmp2; + + tmp2 = fold_build2_loc (input_location, MODIFY_EXPR, + gfc_charlen_type_node, + sym->ts.u.cl->backend_decl, tmp); + if (sym->attr.optional) + { + tree present = gfc_conv_expr_present (sym); + tmp2 = build3_loc (input_location, COND_EXPR, + void_type_node, present, tmp2, + build_empty_stmt (input_location)); + } + gfc_add_expr_to_block (init, tmp2); + } + + gfc_restore_backend_locus (loc); + + /* Pass the final character length back. */ + if (sym->attr.intent != INTENT_IN) + { + tmp = fold_build2_loc (input_location, MODIFY_EXPR, + gfc_charlen_type_node, tmp, + sym->ts.u.cl->backend_decl); + if (sym->attr.optional) + { + tree present = gfc_conv_expr_present (sym); + tmp = build3_loc (input_location, COND_EXPR, + void_type_node, present, tmp, + build_empty_stmt (input_location)); + } + } + else + tmp = NULL_TREE; + + return tmp; + } + /* Generate function entry and exit code, and add it to the function body. This includes: Allocation and initialization of array variables. *************** gfc_trans_deferred_vars (gfc_symbol * pr *** 3877,3884 **** --- 3948,3967 ---- /* An automatic character length, pointer array result. */ if (proc_sym->ts.type == BT_CHARACTER && TREE_CODE (proc_sym->ts.u.cl->backend_decl) == VAR_DECL) + { + tmp = NULL; + if (proc_sym->ts.deferred) + { + gfc_save_backend_locus (&loc); + gfc_set_backend_locus (&proc_sym->declared_at); + gfc_start_block (&init); + tmp = gfc_null_and_pass_deferred_len (proc_sym, &init, &loc); + gfc_add_init_cleanup (block, gfc_finish_block (&init), tmp); + } + else gfc_trans_dummy_character (proc_sym, proc_sym->ts.u.cl, block); } + } else if (proc_sym->ts.type == BT_CHARACTER) { if (proc_sym->ts.deferred) *************** gfc_trans_deferred_vars (gfc_symbol * pr *** 3903,3914 **** --- 3986,4005 ---- gfc_restore_backend_locus (&loc); /* Pass back the string length on exit. */ + tmp = proc_sym->ts.u.cl->backend_decl; + if (TREE_CODE (tmp) != INDIRECT_REF + && proc_sym->ts.u.cl->passed_length) + { tmp = proc_sym->ts.u.cl->passed_length; tmp = build_fold_indirect_ref_loc (input_location, tmp); tmp = fold_convert (gfc_charlen_type_node, tmp); tmp = fold_build2_loc (input_location, MODIFY_EXPR, gfc_charlen_type_node, tmp, proc_sym->ts.u.cl->backend_decl); + } + else + tmp = NULL_TREE; + gfc_add_init_cleanup (block, gfc_finish_block (&init), tmp); } else if (TREE_CODE (proc_sym->ts.u.cl->backend_decl) == VAR_DECL) *************** gfc_trans_deferred_vars (gfc_symbol * pr *** 3979,3988 **** else if (sym->attr.dimension || sym->attr.codimension) { /* Assumed-size Cray pointees need to be treated as AS_EXPLICIT. */ ! array_type tmp = sym->as->type; ! if (tmp == AS_ASSUMED_SIZE && sym->as->cp_was_assumed) ! tmp = AS_EXPLICIT; ! switch (tmp) { case AS_EXPLICIT: if (sym->attr.dummy || sym->attr.result) --- 4070,4079 ---- else if (sym->attr.dimension || sym->attr.codimension) { /* Assumed-size Cray pointees need to be treated as AS_EXPLICIT. */ ! array_type type_of_array = sym->as->type; ! if (type_of_array == AS_ASSUMED_SIZE && sym->as->cp_was_assumed) ! type_of_array = AS_EXPLICIT; ! switch (type_of_array) { case AS_EXPLICIT: if (sym->attr.dummy || sym->attr.result) *************** gfc_trans_deferred_vars (gfc_symbol * pr *** 4059,4064 **** --- 4150,4164 ---- case AS_DEFERRED: seen_trans_deferred_array = true; gfc_trans_deferred_array (sym, block); + if (sym->ts.type == BT_CHARACTER && sym->ts.deferred + && sym->attr.result) + { + gfc_start_block (&init); + gfc_save_backend_locus (&loc); + gfc_set_backend_locus (&sym->declared_at); + tmp = gfc_null_and_pass_deferred_len (sym, &init, &loc); + gfc_add_init_cleanup (block, gfc_finish_block (&init), tmp); + } break; default: *************** gfc_trans_deferred_vars (gfc_symbol * pr *** 4073,4078 **** --- 4173,4179 ---- continue; else if ((!sym->attr.dummy || sym->ts.deferred) && (sym->attr.allocatable + || (sym->attr.pointer && sym->attr.result) || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.allocatable))) { *************** gfc_trans_deferred_vars (gfc_symbol * pr *** 4080,4085 **** --- 4181,4192 ---- { tree descriptor = NULL_TREE; + gfc_save_backend_locus (&loc); + gfc_set_backend_locus (&sym->declared_at); + gfc_start_block (&init); + + if (!sym->attr.pointer) + { /* Nullify and automatic deallocation of allocatable scalars. */ e = gfc_lval_expr_from_sym (sym); *************** gfc_trans_deferred_vars (gfc_symbol * pr *** 4103,4108 **** --- 4210,4216 ---- } else { + se.descriptor_only = 1; gfc_conv_expr (&se, e); descriptor = se.expr; se.expr = gfc_conv_descriptor_data_addr (se.expr); *************** gfc_trans_deferred_vars (gfc_symbol * pr *** 4110,4119 **** } gfc_free_expr (e); - gfc_save_backend_locus (&loc); - gfc_set_backend_locus (&sym->declared_at); - gfc_start_block (&init); - if (!sym->attr.dummy || sym->attr.intent == INTENT_OUT) { /* Nullify when entering the scope. */ --- 4218,4223 ---- *************** gfc_trans_deferred_vars (gfc_symbol * pr *** 4130,4191 **** } gfc_add_expr_to_block (&init, tmp); } if ((sym->attr.dummy || sym->attr.result) && sym->ts.type == BT_CHARACTER ! && sym->ts.deferred) ! { ! /* Character length passed by reference. */ ! tmp = sym->ts.u.cl->passed_length; ! tmp = build_fold_indirect_ref_loc (input_location, tmp); ! tmp = fold_convert (gfc_charlen_type_node, tmp); ! ! if (!sym->attr.dummy || sym->attr.intent == INTENT_OUT) ! /* Zero the string length when entering the scope. */ ! gfc_add_modify (&init, sym->ts.u.cl->backend_decl, ! build_int_cst (gfc_charlen_type_node, 0)); ! else ! { ! tree tmp2; ! ! tmp2 = fold_build2_loc (input_location, MODIFY_EXPR, ! gfc_charlen_type_node, ! sym->ts.u.cl->backend_decl, tmp); ! if (sym->attr.optional) ! { ! tree present = gfc_conv_expr_present (sym); ! tmp2 = build3_loc (input_location, COND_EXPR, ! void_type_node, present, tmp2, ! build_empty_stmt (input_location)); ! } ! gfc_add_expr_to_block (&init, tmp2); ! } ! ! gfc_restore_backend_locus (&loc); ! ! /* Pass the final character length back. */ ! if (sym->attr.intent != INTENT_IN) ! { ! tmp = fold_build2_loc (input_location, MODIFY_EXPR, ! gfc_charlen_type_node, tmp, ! sym->ts.u.cl->backend_decl); ! if (sym->attr.optional) ! { ! tree present = gfc_conv_expr_present (sym); ! tmp = build3_loc (input_location, COND_EXPR, ! void_type_node, present, tmp, ! build_empty_stmt (input_location)); ! } ! } ! else ! tmp = NULL_TREE; ! } else gfc_restore_backend_locus (&loc); /* Deallocate when leaving the scope. Nullifying is not needed. */ ! if (!sym->attr.result && !sym->attr.dummy && !sym->ns->proc_name->attr.is_main_program) { if (sym->ts.type == BT_CLASS --- 4234,4252 ---- } gfc_add_expr_to_block (&init, tmp); } + } if ((sym->attr.dummy || sym->attr.result) && sym->ts.type == BT_CHARACTER ! && sym->ts.deferred ! && sym->ts.u.cl->passed_length) ! tmp = gfc_null_and_pass_deferred_len (sym, &init, &loc); else gfc_restore_backend_locus (&loc); /* Deallocate when leaving the scope. Nullifying is not needed. */ ! if (!sym->attr.result && !sym->attr.dummy && !sym->attr.pointer && !sym->ns->proc_name->attr.is_main_program) { if (sym->ts.type == BT_CLASS *************** gfc_trans_deferred_vars (gfc_symbol * pr *** 4202,4207 **** --- 4263,4269 ---- gfc_free_expr (expr); } } + if (sym->ts.type == BT_CLASS) { /* Initialize _vptr to declared type. */ *************** gfc_trans_deferred_vars (gfc_symbol * pr *** 4242,4260 **** if (sym->attr.dummy) { gfc_start_block (&init); ! ! /* Character length passed by reference. */ ! tmp = sym->ts.u.cl->passed_length; ! tmp = build_fold_indirect_ref_loc (input_location, tmp); ! tmp = fold_convert (gfc_charlen_type_node, tmp); ! gfc_add_modify (&init, sym->ts.u.cl->backend_decl, tmp); ! /* Pass the final character length back. */ ! if (sym->attr.intent != INTENT_IN) ! tmp = fold_build2_loc (input_location, MODIFY_EXPR, ! gfc_charlen_type_node, tmp, ! sym->ts.u.cl->backend_decl); ! else ! tmp = NULL_TREE; gfc_add_init_cleanup (block, gfc_finish_block (&init), tmp); } } --- 4304,4312 ---- if (sym->attr.dummy) { gfc_start_block (&init); ! gfc_save_backend_locus (&loc); ! gfc_set_backend_locus (&sym->declared_at); ! tmp = gfc_null_and_pass_deferred_len (sym, &init, &loc); gfc_add_init_cleanup (block, gfc_finish_block (&init), tmp); } } Index: gcc/fortran/trans-expr.c =================================================================== *** gcc/fortran/trans-expr.c (revision 232482) --- gcc/fortran/trans-expr.c (working copy) *************** gfc_conv_procedure_call (gfc_se * se, gf *** 5752,5757 **** --- 5752,5760 ---- tmp = len; if (TREE_CODE (tmp) != VAR_DECL) tmp = gfc_evaluate_now (len, &se->pre); + TREE_STATIC (tmp) = 1; + gfc_add_modify (&se->pre, tmp, + build_int_cst (TREE_TYPE (tmp), 0)); tmp = gfc_build_addr_expr (NULL_TREE, tmp); vec_safe_push (retargs, tmp); } *************** gfc_trans_assignment_1 (gfc_expr * expr1 *** 9052,9058 **** } /* Stabilize a string length for temporaries. */ ! if (expr2->ts.type == BT_CHARACTER && !expr2->ts.deferred) string_length = gfc_evaluate_now (rse.string_length, &rse.pre); else if (expr2->ts.type == BT_CHARACTER) string_length = rse.string_length; --- 9055,9064 ---- } /* Stabilize a string length for temporaries. */ ! if (expr2->ts.type == BT_CHARACTER && !expr1->ts.deferred ! && !(TREE_CODE (rse.string_length) == VAR_DECL ! || TREE_CODE (rse.string_length) == PARM_DECL ! || TREE_CODE (rse.string_length) == INDIRECT_REF)) string_length = gfc_evaluate_now (rse.string_length, &rse.pre); else if (expr2->ts.type == BT_CHARACTER) string_length = rse.string_length; *************** gfc_trans_assignment_1 (gfc_expr * expr1 *** 9066,9072 **** --- 9072,9103 ---- lse.string_length = string_length; } else + { gfc_conv_expr (&lse, expr1); + if (gfc_option.rtcheck & GFC_RTCHECK_MEM + && gfc_expr_attr (expr1).allocatable + && expr1->rank + && !expr2->rank) + { + tree cond; + const char* msg; + + tmp = expr1->symtree->n.sym->backend_decl; + if (POINTER_TYPE_P (TREE_TYPE (tmp))) + tmp = build_fold_indirect_ref_loc (input_location, tmp); + + if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (tmp))) + tmp = gfc_conv_descriptor_data_get (tmp); + else + tmp = TREE_OPERAND (lse.expr, 0); + + cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node, + tmp, build_int_cst (TREE_TYPE (tmp), 0)); + msg = _("Assignment of scalar to unallocated array"); + gfc_trans_runtime_check (true, false, cond, &loop.pre, + &expr1->where, msg); + } + } /* Assignments of scalar derived types with allocatable components to arrays must be done with a deep copy and the rhs temporary Index: gcc/fortran/trans-stmt.c =================================================================== *** gcc/fortran/trans-stmt.c (revision 232481) --- gcc/fortran/trans-stmt.c (working copy) *************** gfc_trans_allocate (gfc_code * code) *** 5119,5125 **** tree label_finish; tree memsz; tree al_vptr, al_len; ! tree def_str_len = NULL_TREE; /* If an expr3 is present, then store the tree for accessing its _vptr, and _len components in the variables, respectively. The element size, i.e. _vptr%size, is stored in expr3_esize. Any of --- 5119,5125 ---- tree label_finish; tree memsz; tree al_vptr, al_len; ! /* If an expr3 is present, then store the tree for accessing its _vptr, and _len components in the variables, respectively. The element size, i.e. _vptr%size, is stored in expr3_esize. Any of *************** gfc_trans_allocate (gfc_code * code) *** 5382,5388 **** expr3_esize = fold_build2_loc (input_location, MULT_EXPR, TREE_TYPE (se_sz.expr), tmp, se_sz.expr); - def_str_len = gfc_evaluate_now (se_sz.expr, &block); } } --- 5382,5387 ---- *************** gfc_trans_allocate (gfc_code * code) *** 5435,5450 **** se.want_pointer = 1; se.descriptor_only = 1; - if (expr->ts.type == BT_CHARACTER - && expr->ts.deferred - && TREE_CODE (expr->ts.u.cl->backend_decl) == VAR_DECL - && def_str_len != NULL_TREE) - { - tmp = expr->ts.u.cl->backend_decl; - gfc_add_modify (&block, tmp, - fold_convert (TREE_TYPE (tmp), def_str_len)); - } - gfc_conv_expr (&se, expr); if (expr->ts.type == BT_CHARACTER && expr->ts.deferred) /* se.string_length now stores the .string_length variable of expr --- 5434,5439 ---- *************** gfc_trans_allocate (gfc_code * code) *** 5578,5583 **** --- 5567,5586 ---- /* Prevent setting the length twice. */ al_len_needs_set = false; } + else if (expr->ts.type == BT_CHARACTER && al_len != NULL_TREE + && code->ext.alloc.ts.u.cl->length) + { + /* Cover the cases where a string length is explicitly + specified by a type spec for deferred length character + arrays or unlimited polymorphic objects without a + source= or mold= expression. */ + gfc_init_se (&se_sz, NULL); + gfc_conv_expr (&se_sz, code->ext.alloc.ts.u.cl->length); + gfc_add_modify (&block, al_len, + fold_convert (TREE_TYPE (al_len), + se_sz.expr)); + al_len_needs_set = false; + } } gfc_add_block_to_block (&block, &se.pre); Index: gcc/fortran/trans-types.c =================================================================== *** gcc/fortran/trans-types.c (revision 232481) --- gcc/fortran/trans-types.c (working copy) *************** gfc_get_character_type (int kind, gfc_ch *** 1067,1072 **** --- 1067,1074 ---- tree len; len = (cl == NULL) ? NULL_TREE : cl->backend_decl; + if (len && POINTER_TYPE_P (TREE_TYPE (len))) + len = build_fold_indirect_ref (len); return gfc_get_character_type_len (kind, len); } Index: gcc/fortran/trans.c =================================================================== *** gcc/fortran/trans.c (revision 232481) --- gcc/fortran/trans.c (working copy) *************** gfc_build_array_ref (tree base, tree off *** 348,357 **** references. */ if (type && TREE_CODE (type) == ARRAY_TYPE && TYPE_MAXVAL (TYPE_DOMAIN (type)) != NULL_TREE ! && TREE_CODE (TYPE_MAXVAL (TYPE_DOMAIN (type))) == VAR_DECL && decl ! && DECL_CONTEXT (TYPE_MAXVAL (TYPE_DOMAIN (type))) ! == DECL_CONTEXT (decl)) span = TYPE_MAXVAL (TYPE_DOMAIN (type)); else span = NULL_TREE; --- 348,360 ---- references. */ if (type && TREE_CODE (type) == ARRAY_TYPE && TYPE_MAXVAL (TYPE_DOMAIN (type)) != NULL_TREE ! && (TREE_CODE (TYPE_MAXVAL (TYPE_DOMAIN (type))) == VAR_DECL ! || TREE_CODE (TYPE_MAXVAL (TYPE_DOMAIN (type))) == INDIRECT_REF) && decl ! && (TREE_CODE (TYPE_MAXVAL (TYPE_DOMAIN (type))) == INDIRECT_REF ! || TREE_CODE (decl) == FUNCTION_DECL ! || DECL_CONTEXT (TYPE_MAXVAL (TYPE_DOMAIN (type))) ! == DECL_CONTEXT (decl))) span = TYPE_MAXVAL (TYPE_DOMAIN (type)); else span = NULL_TREE; *************** gfc_build_array_ref (tree base, tree off *** 367,373 **** and reference the element with pointer arithmetic. */ if (decl && (TREE_CODE (decl) == FIELD_DECL || TREE_CODE (decl) == VAR_DECL ! || TREE_CODE (decl) == PARM_DECL) && ((GFC_DECL_SUBREF_ARRAY_P (decl) && !integer_zerop (GFC_DECL_SPAN(decl))) || GFC_DECL_CLASS (decl) --- 370,377 ---- and reference the element with pointer arithmetic. */ if (decl && (TREE_CODE (decl) == FIELD_DECL || TREE_CODE (decl) == VAR_DECL ! || TREE_CODE (decl) == PARM_DECL ! || TREE_CODE (decl) == FUNCTION_DECL) && ((GFC_DECL_SUBREF_ARRAY_P (decl) && !integer_zerop (GFC_DECL_SPAN(decl))) || GFC_DECL_CLASS (decl) Index: gcc/testsuite/gfortran.dg/allocate_error_5.f90 =================================================================== *** gcc/testsuite/gfortran.dg/allocate_error_5.f90 (revision 0) --- gcc/testsuite/gfortran.dg/allocate_error_5.f90 (working copy) *************** *** 0 **** --- 1,23 ---- + ! { dg-do run } + ! { dg-additional-options "-fcheck=mem" } + ! { dg-shouldfail "Fortran runtime error: Assignment of scalar to unallocated array" } + ! + ! This omission was encountered in the course of fixing PR54070. Whilst this is a + ! very specific case, others such as allocatable components have been tested. + ! + ! Contributed by Tobias Burnus <bur...@gcc.gnu.org> + ! + function g(a) result (res) + character(len=*) :: a + character(len=:),allocatable :: res(:) + res = a ! Since 'res' is not allocated, a runtime error should occur. + end function + + interface + function g(a) result(res) + character(len=*) :: a + character(len=:),allocatable :: res(:) + end function + end interface + print *, g("ABC") + end Index: gcc/testsuite/gfortran.dg/deferred_character_10.f90 =================================================================== *** gcc/testsuite/gfortran.dg/deferred_character_10.f90 (revision 0) --- gcc/testsuite/gfortran.dg/deferred_character_10.f90 (working copy) *************** *** 0 **** --- 1,52 ---- + ! { dg-do run } + ! + ! Checks that PR60593 is fixed (Revision: 214757) + ! + ! Contributed by Steve Kargl <ka...@gcc.gnu.org> + ! + ! Main program added for this test. + ! + module stringhelper_m + + implicit none + + type :: string_t + character(:), allocatable :: string + end type + + interface len + function strlen(s) bind(c,name='strlen') + use iso_c_binding + implicit none + type(c_ptr), intent(in), value :: s + integer(c_size_t) :: strlen + end function + end interface + + contains + + function C2FChar(c_charptr) result(res) + use iso_c_binding + type(c_ptr), intent(in) :: c_charptr + character(:), allocatable :: res + character(kind=c_char,len=1), pointer :: string_p(:) + integer i, c_str_len + c_str_len = int(len(c_charptr)) + call c_f_pointer(c_charptr, string_p, [c_str_len]) + allocate(character(c_str_len) :: res) + forall (i = 1:c_str_len) res(i:i) = string_p(i) + end function + + end module + + use stringhelper_m + use iso_c_binding + implicit none + type(c_ptr) :: cptr + character(20), target :: str + + str = "abcdefghij"//char(0) + cptr = c_loc (str) + if (len (C2FChar (cptr)) .ne. 10) call abort + if (C2FChar (cptr) .ne. "abcdefghij") call abort + end Index: gcc/testsuite/gfortran.dg/deferred_character_11.f90 =================================================================== *** gcc/testsuite/gfortran.dg/deferred_character_11.f90 (revision 0) --- gcc/testsuite/gfortran.dg/deferred_character_11.f90 (working copy) *************** *** 0 **** --- 1,39 ---- + ! { dg-do run } + ! + ! Test the fix for PR61147. + ! + ! Contributed by Thomas Clune <thomas.l.cl...@nasa.gov> + ! + module B_mod + + type :: B + character(:), allocatable :: string + end type B + + contains + + function toPointer(this) result(ptr) + character(:), pointer :: ptr + class (B), intent(in), target :: this + + ptr => this%string + + end function toPointer + + end module B_mod + + program main + use B_mod + + type (B) :: obj + character(:), pointer :: p + + obj%string = 'foo' + p => toPointer(obj) + + If (len (p) .ne. 3) call abort + If (p .ne. "foo") call abort + + end program main + + Index: gcc/testsuite/gfortran.dg/deferred_character_12.f90 =================================================================== *** gcc/testsuite/gfortran.dg/deferred_character_12.f90 (revision 0) --- gcc/testsuite/gfortran.dg/deferred_character_12.f90 (working copy) *************** *** 0 **** --- 1,37 ---- + ! { dg-do run } + ! + ! Tests the fix for PR63232 + ! + ! Contributed by Balint Aradi <barad...@gmail.com> + ! + module mymod + implicit none + + type :: wrapper + character(:), allocatable :: string + end type wrapper + + contains + + + subroutine sub2(mystring) + character(:), allocatable, intent(out) :: mystring + + mystring = "test" + + end subroutine sub2 + + end module mymod + + + program test + use mymod + implicit none + + type(wrapper) :: mywrapper + + call sub2(mywrapper%string) + if (.not. allocated(mywrapper%string)) call abort + if (trim(mywrapper%string) .ne. "test") call abort + + end program test Index: gcc/testsuite/gfortran.dg/deferred_character_13.f90 =================================================================== *** gcc/testsuite/gfortran.dg/deferred_character_13.f90 (revision 0) --- gcc/testsuite/gfortran.dg/deferred_character_13.f90 (working copy) *************** *** 0 **** --- 1,34 ---- + ! { dg-do run } + ! + ! Tests the fix for PR49630 comment #3. + ! + ! Contributed by Janus Weil <ja...@gcc.gnu.org> + ! + module abc + implicit none + + type::abc_type + contains + procedure::abc_function + end type abc_type + + contains + + function abc_function(this) + class(abc_type),intent(in)::this + character(:),allocatable::abc_function + allocate(abc_function,source="hello") + end function abc_function + + subroutine do_something(this) + class(abc_type),intent(in)::this + if (this%abc_function() .ne. "hello") call abort + end subroutine do_something + + end module abc + + + use abc + type(abc_type) :: a + call do_something(a) + end Index: gcc/testsuite/gfortran.dg/deferred_character_14.f90 =================================================================== *** gcc/testsuite/gfortran.dg/deferred_character_14.f90 (revision 0) --- gcc/testsuite/gfortran.dg/deferred_character_14.f90 (working copy) *************** *** 0 **** --- 1,30 ---- + ! { dg-do run } + ! + ! Test fix for PR60795 comments #1 and #4 + ! + ! Contributed by Kergonath <kergon...@me.com> + ! + module m + contains + subroutine allocate_array(s_array) + character(:), dimension(:), allocatable, intent(out) :: s_array + + allocate(character(2) :: s_array(2)) + s_array = ["ab","cd"] + end subroutine + end module + + program stringtest + use m + character(:), dimension(:), allocatable :: s4 + character(:), dimension(:), allocatable :: s + ! Comment #1 + allocate(character(1) :: s(10)) + if (size (s) .ne. 10) call abort + if (len (s) .ne. 1) call abort + ! Comment #4 + call allocate_array(s4) + if (size (s4) .ne. 2) call abort + if (len (s4) .ne. 2) call abort + if (any (s4 .ne. ["ab", "cd"])) call abort + end program Index: gcc/testsuite/gfortran.dg/deferred_character_15.f90 =================================================================== *** gcc/testsuite/gfortran.dg/deferred_character_15.f90 (revision 0) --- gcc/testsuite/gfortran.dg/deferred_character_15.f90 (working copy) *************** *** 0 **** --- 1,44 ---- + ! { dg-do run } + ! + ! Test the fix for PR69423. + ! + ! Contributed by Antony Lewis <ant...@cosmologist.info> + ! + program tester + character(LEN=:), allocatable :: S + S= test(2) + if (len(S) .ne. 4) call abort + if (S .ne. "test") call abort + if (allocated (S)) deallocate (S) + + S= test2(2) + if (len(S) .ne. 4) call abort + if (S .ne. "test") call abort + if (allocated (S)) deallocate (S) + contains + function test(alen) + character(LEN=:), allocatable :: test + integer alen, i + do i = alen, 1, -1 + test = 'test' + exit + end do + ! This line would print nothing when compiled with -O1 and higher. + ! print *, len(test),test + if (len(test) .ne. 4) call abort + if (test .ne. "test") call abort + end function test + + function test2(alen) result (test) + character(LEN=:), allocatable :: test + integer alen, i + do i = alen, 1, -1 + test = 'test' + exit + end do + ! This worked before the fix. + ! print *, len(test),test + if (len(test) .ne. 4) call abort + if (test .ne. "test") call abort + end function test2 + end program tester Index: gcc/testsuite/gfortran.dg/deferred_character_8.f90 =================================================================== *** gcc/testsuite/gfortran.dg/deferred_character_8.f90 (revision 0) --- gcc/testsuite/gfortran.dg/deferred_character_8.f90 (working copy) *************** *** 0 **** --- 1,84 ---- + ! { dg-do run } + ! + ! Test the fix for all the remaining issues in PR54070. These were all + ! concerned with deferred length characters being returned as function results, + ! except for comment #23 where the descriptor dtype was not correctly set and + ! array IO failed in consequence. + ! + ! Contributed by Tobias Burnus <bur...@gcc.gnu.org> + ! + ! The original comment #1 with an allocate statement. + ! Allocatable, deferred length scalar resul. + function f() + character(len=:),allocatable :: f + allocate (f, source = "abc") + f ="ABC" + end function + ! + ! Allocatable, deferred length, explicit, array result + function g(a) result (res) + character(len=*) :: a(:) + character(len (a)) :: b(size (a)) + character(len=:),allocatable :: res(:) + integer :: i + allocate (character(len(a)) :: res(2*size(a))) + do i = 1, len (a) + b(:)(i:i) = char (ichar (a(:)(i:i)) + 4) + end do + res = [a, b] + end function + ! + ! Allocatable, deferred length, array result + function h(a) + character(len=*) :: a(:) + character(len(a)) :: b (size(a)) + character(len=:),allocatable :: h(:) + integer :: i + allocate (character(len(a)) :: h(size(a))) + do i = 1, len (a) + b(:)(i:i) = char (ichar (a(:)(i:i)) + 32) + end do + h = b + end function + + module deferred_length_char_array + contains + function return_string(argument) + character(*) :: argument + character(:), dimension(:), allocatable :: return_string + allocate (character (len(argument)) :: return_string(2)) + return_string = argument + end function + end module + + use deferred_length_char_array + character(len=3) :: chr(3) + character(:), pointer :: s(:) + character(6) :: buffer + interface + function f() + character(len=:),allocatable :: f + end function + function g(a) result(res) + character(len=*) :: a(:) + character(len=:),allocatable :: res(:) + end function + function h(a) + character(len=*) :: a(:) + character(len=:),allocatable :: h(:) + end function + end interface + + if (f () .ne. "ABC") call abort + if (any (g (["ab","cd"]) .ne. ["ab","cd","ef","gh"])) call abort + chr = h (["ABC","DEF","GHI"]) + if (any (chr .ne. ["abc","def","ghi"])) call abort + if (any (return_string ("abcdefg") .ne. ["abcdefg","abcdefg"])) call abort + + ! Comment #23 + allocate(character(3)::s(2)) + s(1) = 'foo' + s(2) = 'bar' + write (buffer, '(2A3)') s + if (buffer .ne. 'foobar') call abort + end Index: gcc/testsuite/gfortran.dg/deferred_character_9.f90 =================================================================== *** gcc/testsuite/gfortran.dg/deferred_character_9.f90 (revision 0) --- gcc/testsuite/gfortran.dg/deferred_character_9.f90 (working copy) *************** *** 0 **** --- 1,28 ---- + ! { dg-do run } + ! + ! Test the fix for PR64324 in which deferred length user ops + ! were being mistaken as assumed length and so rejected. + ! + ! Contributed by Ian Harvey <ian_har...@bigpond.com> + ! + MODULE m + IMPLICIT NONE + INTERFACE OPERATOR(.ToString.) + MODULE PROCEDURE tostring + END INTERFACE OPERATOR(.ToString.) + CONTAINS + FUNCTION tostring(arg) + INTEGER, INTENT(IN) :: arg + CHARACTER(:), ALLOCATABLE :: tostring + allocate (character(5) :: tostring) + write (tostring, "(I5)") arg + END FUNCTION tostring + END MODULE m + + use m + character(:), allocatable :: str + integer :: i = 999 + str = .ToString. i + if (str .ne. " 999") call abort + end +