Dear all, the attached patch is the third part of a series to fix the handling of NULL() passed to pointer dummy arguments. This one addresses character dummy arguments (scalar, assumed-shape, assumed-rank) for various uses in the caller.
The patch is a little larger than I expected, due to corner cases (MOLD present or not, assumed-rank or other). If someone finds a more clever version, I would be happy to learn about it. Especially the treatment of assumed-rank dummy could certainly be done differently. Regtested on x86_64-pc-linux-gnu. OK for mainline? As this fixes wrong code on the one hand, and is very localized, I would like to backport this to 14-branch after some waiting. Is this ok? Thanks, Harald
From 3c7877fd4a20b6681dab6737f5d5be0d77241709 Mon Sep 17 00:00:00 2001 From: Harald Anlauf <anl...@gmx.de> Date: Wed, 13 Nov 2024 23:03:47 +0100 Subject: [PATCH] Fortran: fix passing of NULL() actual argument to character dummy [PR104819] Ensure that character length is set and passed by the call to a procedure when its dummy argument is NULL() with MOLD argument present, or set length to either 0 or the callee's expected character length. For assumed-rank dummies, use the rank of the MOLD argument. Generate temporaries for passed arguments when needed. PR fortran/104819 gcc/fortran/ChangeLog: * trans-expr.cc (gfc_conv_procedure_call): Handle passing of NULL() to non-optional dummy arguments of non-bind(c) procedures. gcc/testsuite/ChangeLog: * gfortran.dg/null_actual_6.f90: New test. --- gcc/fortran/trans-expr.cc | 69 ++++++ gcc/testsuite/gfortran.dg/null_actual_6.f90 | 221 ++++++++++++++++++++ 2 files changed, 290 insertions(+) create mode 100644 gcc/testsuite/gfortran.dg/null_actual_6.f90 diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc index ddbb5ecf068..f9a6f8fb16f 100644 --- a/gcc/fortran/trans-expr.cc +++ b/gcc/fortran/trans-expr.cc @@ -7542,6 +7542,75 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, gfc_conv_const_charlen (e->symtree->n.sym->ts.u.cl); parmse.string_length = e->symtree->n.sym->ts.u.cl->backend_decl; } + + /* Obtain the character length for a NULL() actual with a character + MOLD argument. Otherwise substitute a suitable dummy length. + Here we handle non-optional dummies of non-bind(c) procedures. */ + if (e->expr_type == EXPR_NULL + && fsym->ts.type == BT_CHARACTER + && !fsym->attr.optional + && !(sym->attr.is_bind_c && is_CFI_desc (fsym, NULL))) + { + if (e->ts.type == BT_CHARACTER + && e->symtree->n.sym->ts.type == BT_CHARACTER) + { + /* MOLD is present. Substitute a temporary character NULL + pointer. For assumed-rank dummy we need a descriptor that + passes the correct rank. */ + if (fsym->as && fsym->as->type == AS_ASSUMED_RANK) + { + tree rank; + tree tmp = parmse.expr; + tmp = gfc_conv_scalar_to_descriptor (&parmse, tmp, + fsym->attr); + rank = gfc_conv_descriptor_rank (tmp); + gfc_add_modify (&parmse.pre, rank, + build_int_cst (TREE_TYPE (rank), + e->rank)); + parmse.expr = gfc_build_addr_expr (NULL_TREE, tmp); + } + else + { + tree tmp = gfc_create_var (TREE_TYPE (parmse.expr), + "null"); + gfc_add_modify (&se->pre, tmp, + build_zero_cst (TREE_TYPE (tmp))); + parmse.expr = gfc_build_addr_expr (NULL_TREE, tmp); + } + + /* Ensure that a usable length is available. */ + if (parmse.string_length == NULL_TREE) + { + gfc_typespec *ts = &e->symtree->n.sym->ts; + + if (ts->u.cl->length != NULL + && ts->u.cl->length->expr_type == EXPR_CONSTANT) + gfc_conv_const_charlen (ts->u.cl); + + if (ts->u.cl->backend_decl) + parmse.string_length = ts->u.cl->backend_decl; + } + } + else if (e->ts.type == BT_UNKNOWN + && parmse.string_length == NULL_TREE) + { + /* MOLD is not present. Pass length of associated dummy + character argument if constant, or zero. */ + if (fsym->ts.u.cl->length != NULL + && fsym->ts.u.cl->length->expr_type == EXPR_CONSTANT) + { + gfc_conv_const_charlen (fsym->ts.u.cl); + parmse.string_length = fsym->ts.u.cl->backend_decl; + } + else + { + parmse.string_length + = gfc_create_var (gfc_charlen_type_node, "slen"); + gfc_add_modify (&se->pre, parmse.string_length, + build_zero_cst (gfc_charlen_type_node)); + } + } + } } /* If any actual argument of the procedure is allocatable and passed diff --git a/gcc/testsuite/gfortran.dg/null_actual_6.f90 b/gcc/testsuite/gfortran.dg/null_actual_6.f90 new file mode 100644 index 00000000000..e6745311bee --- /dev/null +++ b/gcc/testsuite/gfortran.dg/null_actual_6.f90 @@ -0,0 +1,221 @@ +! { dg-do run } +! { dg-additional-options "-fcheck=bounds" } +! +! PR fortran/104819 - passing of NULL() actual argument to character dummy + +program p + implicit none + character(kind=1,len=10), pointer :: c => NULL() + character(kind=1,len=:), pointer :: d => NULL() + character(kind=1,len=10), pointer :: c1(:) => NULL() + character(kind=1,len=:), pointer :: d1(:) => NULL() + character(kind=4,len=10), pointer :: c4(:) => NULL() + character(kind=4,len=:), pointer :: d4(:) => NULL() + + ! scalar character variables: + ! kind=1, assumed length + call rank0_al (null(c)) + call rank0_al (c) + call arank_al (null(c)) + call arank_al (c) + call rank0_alb(null(c)) + call rank0_alb (c) + + ! kind=1, fixed length + call rank0_fl (null(c)) + call rank0_fl (null()) + call rank0_fl (c) + call arank_fl (null(c)) + call arank_fl (c) + call rank0_flb(null(c)) + call rank0_flb (c) + + ! kind=1, deferred length + call rank0_dl (null(d)) + call rank0_dl (null()) + call rank0_dl (d) + call arank_dl (null(d)) ! <- this crashes nagfor 7.2 + call arank_dl (d) + call rank0_dlb(null(d)) + call rank0_dlb(null()) + + ! rank-1 character variables: + ! kind=1, assumed length + call rank1_al (null(c1)) + call rank1_al (c1) + call arank_al (null(c1)) + call arank_al (c1) + call rank1_alb(null(c1)) + call rank1_alb (c1) + + ! kind=1, fixed length + call rank1_fl (null(c1)) + call rank1_fl (null()) + call rank1_fl (c1) + call arank_fl (null(c1)) + call arank_fl (c1) + call rank1_flb(null(c1)) + call rank1_flb (c1) + + ! kind=1, deferred length + call rank1_dl (null(d1)) + call rank1_dl (null()) + call rank1_dl (d1) + call arank_dl (null(d1)) + call arank_dl (d1) + call rank1_dlb(null(d1)) + call rank1_dlb(null()) + + ! kind=4, assumed length + call rank1_al_4 (null(c4)) + call rank1_al_4 (c4) + call arank_al_4 (null(c4)) + call arank_al_4 (c4) + call rank1_al_4b(null(c4)) + call rank1_al_4b (c4) + + ! kind=4, fixed length + call rank1_fl_4 (null(c4)) + call rank1_fl_4 (null()) + call rank1_fl_4 (c4) + call arank_fl_4 (null(c4)) + call arank_fl_4 (c4) + call rank1_fl_4b(null(c4)) + call rank1_fl_4b (c4) + + ! kind=4, deferred length + call rank1_dl_4 (null(d4)) + call rank1_dl_4 (null()) + call rank1_dl_4 (d4) + call arank_dl_4 (null(d4)) + call arank_dl_4 (d4) + call rank1_dl_4b(null(d4)) + call rank1_dl_4b(null()) + +contains + + ! kind=4, rank=1 + subroutine rank1_al_4 (x) + character(kind=4,len=*), pointer, intent(in) :: x(:) + if (associated (x)) stop 41 + end + subroutine rank1_fl_4 (x) + character(kind=4,len=10), pointer, intent(in) :: x(:) + if (associated (x)) stop 42 + end + subroutine rank1_dl_4 (x) + character(kind=4,len=:), pointer, intent(in) :: x(:) + if (associated (x)) stop 43 + end + + subroutine rank1_al_4b (y) + character(kind=4,len=*), pointer, intent(in) :: y(:) + call rank1_al_4 (y) + if (associated (y)) stop 44 + end + subroutine rank1_fl_4b (y) + character(kind=4,len=10), pointer, intent(in) :: y(:) + call rank1_fl_4 (y) + if (associated (y)) stop 45 + end + subroutine rank1_dl_4b (y) + character(kind=4,len=:), pointer, intent(in) :: y(:) + call rank1_dl_4 (y) + if (associated (y)) stop 46 + end + + ! kind=4, assumed-rank versions + subroutine arank_al_4 (x) + character(kind=4,len=*), pointer, intent(in) :: x(..) + if (associated (x)) stop 47 + ! this testcase assumes that we call this subroutine only with rank=1 + if (rank (x) /= 1) stop 57 + end + subroutine arank_fl_4 (x) + character(kind=4,len=10), pointer, intent(in) :: x(..) + if (associated (x)) stop 48 + ! this testcase assumes that we call this subroutine only with rank=1 + if (rank (x) /= 1) stop 58 + end + subroutine arank_dl_4 (x) + character(kind=4,len=:), pointer, intent(in) :: x(..) + if (associated (x)) stop 49 + ! this testcase assumes that we call this subroutine only with rank=1 + if (rank (x) /= 1) stop 59 + end + + ! kind=1, rank=1 + subroutine rank1_al (x) + character(kind=1,len=*), pointer, intent(in) :: x(:) + if (associated (x)) stop 11 + end + subroutine rank1_fl (x) + character(kind=1,len=10), pointer, intent(in) :: x(:) + if (associated (x)) stop 12 + end + subroutine rank1_dl (x) + character(kind=1,len=:), pointer, intent(in) :: x(:) + if (associated (x)) stop 13 + end + + subroutine rank1_alb (y) + character(kind=1,len=*), pointer, intent(in) :: y(:) + call rank1_al (y) + if (associated (y)) stop 14 + end + subroutine rank1_flb (y) + character(kind=1,len=10), pointer, intent(in) :: y(:) + call rank1_fl (y) + if (associated (y)) stop 15 + end + subroutine rank1_dlb (y) + character(kind=1,len=:), pointer, intent(in) :: y(:) + call rank1_dl (y) + if (associated (y)) stop 16 + end + + ! kind=1, assumed-rank versions + subroutine arank_al (x) + character(kind=1,len=*), pointer, intent(in) :: x(..) + if (associated (x)) stop 17 + end + subroutine arank_fl (x) + character(kind=1,len=10), pointer, intent(in) :: x(..) + if (associated (x)) stop 18 + end + subroutine arank_dl (x) + character(kind=1,len=:), pointer, intent(in) :: x(..) + if (associated (x)) stop 19 + end + + ! kind=1, scalar + subroutine rank0_al (x) + character(kind=1,len=*), pointer, intent(in) :: x + if (associated (x)) stop 1 + end + subroutine rank0_fl (x) + character(kind=1,len=10), pointer, intent(in) :: x + if (associated (x)) stop 2 + end + subroutine rank0_dl (x) + character(kind=1,len=:), pointer, intent(in) :: x + if (associated (x)) stop 3 + end + + subroutine rank0_alb (y) + character(kind=1,len=*), pointer, intent(in) :: y + call rank0_al (y) + if (associated (y)) stop 4 + end + subroutine rank0_flb (y) + character(kind=1,len=10), pointer, intent(in) :: y + call rank0_fl (y) + if (associated (y)) stop 5 + end + subroutine rank0_dlb (y) + character(kind=1,len=:), pointer, intent(in) :: y + call rank0_dl (y) + if (associated (y)) stop 6 + end + +end -- 2.35.3