[gcc r17-2625] fortran: [PR53296] Fix character array-ctor function called twice
Jerry DeLisle via Gcc-cvs <[email protected]>
| Newsgroups | gmane.comp.gcc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://gcc.gnu.org/g:f764d7111a29d8323e49a87a8321072295c73244 commit r17-2625-gf764d7111a29d8323e49a87a8321072295c73244 Author: Jerry DeLisle <[email protected]> Date: Tue Jul 21 09:15:50 2026 -0700 fortran: [PR53296] Fix character array-ctor function called twice Avoid the redundant generated call to the pre chain when no_function_call is set. Also fix a related stack-buffer-overflow: gfc_conv_array_parameter wrote over the array constructor's. The specified length was to short. Use the explicit character type-spec length instead. PR fortran/53296 gcc/fortran/ChangeLog: * trans-expr.cc (gfc_conv_procedure_call): Skip the redundant function call added to the pre chain when no_function_call is set and the character result length was already determined without running the callee. * trans-array.cc (gfc_conv_array_parameter): Convert an array constructor's explicit character type-spec length directly instead of using the first elements length. gcc/testsuite/ChangeLog: * gfortran.dg/array_constructor_59.f90: New test. Diff: --- gcc/fortran/trans-array.cc | 15 +++++++++++++- gcc/fortran/trans-expr.cc | 9 ++++++++- gcc/testsuite/gfortran.dg/array_constructor_59.f90 | 23 ++++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc index 6d73b2370e90..91fa43b26831 100644 --- a/gcc/fortran/trans-array.cc +++ b/gcc/fortran/trans-array.cc @@ -8892,7 +8892,20 @@ gfc_conv_array_parameter (gfc_se *se, gfc_expr *expr, bool g77, if (expr->expr_type == EXPR_ARRAY && expr->ts.type == BT_CHARACTER) { - get_array_ctor_strlen (&se->pre, expr->value.constructor, &tmp); + if (expr->ts.u.cl->length_from_typespec && expr->ts.u.cl->length) + { + /* The constructor has an explicit character type-spec length + so convert it directly. */ + gfc_se cse; + gfc_init_se (&cse, NULL); + gfc_conv_expr_type (&cse, expr->ts.u.cl->length, + gfc_charlen_type_node); + gfc_add_block_to_block (&se->pre, &cse.pre); + tmp = cse.expr; + } + else + get_array_ctor_strlen (&se->pre, expr->value.constructor, &tmp); + expr->ts.u.cl->backend_decl = tmp; se->string_length = tmp; } diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index 1083ea3fbbd2..33b7838f74ac 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -6996,6 +6996,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, int arglen; unsigned int argc; tree arg1_cntnr = NULL_TREE; + bool call_needed_for_length = true; arglist = NULL; retargs = NULL; stringargs = NULL; @@ -8695,6 +8696,10 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, fold_convert (gfc_charlen_type_node, tmp), build_zero_cst (gfc_charlen_type_node)); cl.backend_decl = tmp; + + /* The length was fully computed above from the specification + expression, without needing the callee to actually run. */ + call_needed_for_length = false; } /* Set up a charlen structure for it. */ @@ -9004,7 +9009,9 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, if (byref) { /* Add the function call to the pre chain. There is no expression. */ - gfc_add_expr_to_block (&se->pre, se->expr); + if (!se->no_function_call || call_needed_for_length) + gfc_add_expr_to_block (&se->pre, se->expr); + se->expr = NULL_TREE; if (!se->direct_byref) diff --git a/gcc/testsuite/gfortran.dg/array_constructor_59.f90 b/gcc/testsuite/gfortran.dg/array_constructor_59.f90 new file mode 100644 index 000000000000..31169163a3e4 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/array_constructor_59.f90 @@ -0,0 +1,23 @@ +! { dg-do run } +! PR fortran/53296 +! Test case based on the test case from Steve Kargl +program pr53296 + implicit none + character(len=128) :: str(2) + integer :: ncalls = 0 + + str = [ucase("abcde"), ucase("ghij")] + if (ncalls /= 2) stop 1 + if (trim (str(1)) /= "abcde") stop 2 + if (trim (str(2)) /= "ghij") stop 3 + +contains + + function ucase(s) + character(*), intent(in) :: s + character(len(s)) :: ucase + ncalls = ncalls + 1 + ucase = s + end function ucase + +end program pr53296