public inbox for fortran@gcc.gnu.org
 help / color / mirror / Atom feed
From: Mikael Morin <morin-mikael@orange.fr>
To: Harald Anlauf <anlauf@gmx.de>, fortran <fortran@gcc.gnu.org>,
	gcc-patches <gcc-patches@gcc.gnu.org>
Subject: Re: [PATCH] Fortran: fixes for procedures with ALLOCATABLE,INTENT(OUT) arguments [PR92178]
Date: Mon, 3 Jul 2023 13:46:21 +0200	[thread overview]
Message-ID: <5a5306ae-0db1-c7e2-e744-a3beced17636@orange.fr> (raw)
In-Reply-To: <trinity-fe43f0e9-8051-4903-8088-e099f9f12528-1688330335546@3c-app-gmx-bs45>

Hello,

Le 02/07/2023 à 22:38, Harald Anlauf via Fortran a écrit :
> Dear all,
> 
> the attached patch fixes a long-standing issue with the
> order of evaluation of procedure argument expressions and
> deallocation of allocatable actual arguments passed to
> allocatable dummies with intent(out) attribute.
> 
> It is based on an initial patch by Steve, handles issues
> pointed out by Tobias, and includes a suggestion by Tobias
> to scan the procedure arguments first to decide whether the
> creation of temporaries is needed.
> 
> There is one unresolved issue left that might be more
> general: it appears to affect character arguments (only)
> in that quite often there still is no temporary generated.
> I haven't found the reason why and would like to defer this,
> unless someone has a good suggestion.
> 
No problem, let's fix the easier parts first.

> Regtested on x86_64-pc-linux-gnu. OK for mainline?
> 
A few thing to double check below.

> pr92178.diff
> 
> From 609ba636927811cddc74fb815cb18809c7d33565 Mon Sep 17 00:00:00 2001
> From: Harald Anlauf <anlauf@gmx.de>
> Date: Sun, 2 Jul 2023 22:14:19 +0200
> Subject: [PATCH] Fortran: fixes for procedures with ALLOCATABLE,INTENT(OUT)
>  arguments [PR92178]
> 
> gcc/fortran/ChangeLog:
> 
> 	PR fortran/92178
> 	* trans-expr.cc (gfc_conv_procedure_call): Check procedures for
> 	allocatable dummy arguments with INTENT(OUT) and move deallocation
> 	of actual arguments after evaluation of argument expressions before
> 	the procedure is executed.
> 
> gcc/testsuite/ChangeLog:
> 
> 	PR fortran/92178
> 	* gfortran.dg/pr92178.f90: New test.
> 	* gfortran.dg/pr92178_2.f90: New test.
> 
> Co-authored-by: Steven G. Kargl <kargl@gcc.gnu.org>
> ---
>  gcc/fortran/trans-expr.cc               | 52 ++++++++++++++--
>  gcc/testsuite/gfortran.dg/pr92178.f90   | 83 +++++++++++++++++++++++++
>  gcc/testsuite/gfortran.dg/pr92178_2.f90 | 46 ++++++++++++++
>  3 files changed, 177 insertions(+), 4 deletions(-)
>  create mode 100644 gcc/testsuite/gfortran.dg/pr92178.f90
>  create mode 100644 gcc/testsuite/gfortran.dg/pr92178_2.f90
> 
> diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
> index 30946ba3f63..16e8f037cfc 100644
> --- a/gcc/fortran/trans-expr.cc
> +++ b/gcc/fortran/trans-expr.cc
(...)
> @@ -6117,6 +6118,33 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
>  	       && UNLIMITED_POLY (sym)
>  	       && comp && (strcmp ("_copy", comp->name) == 0);
> 
> +  /* First scan argument list for allocatable actual arguments passed to
> +     allocatable dummy arguments with INTENT(OUT).  As the corresponding
> +     actual arguments are deallocated before execution of the procedure, we
> +     evaluate actual argument expressions to avoid problems with possible
> +     dependencies.  */
> +  bool force_eval_args = false;
> +  gfc_formal_arglist *tmp_formal;
> +  for (arg = args, tmp_formal = formal; arg != NULL;
> +       arg = arg->next, tmp_formal = tmp_formal ? tmp_formal->next : NULL)
> +    {
> +      e = arg->expr;
> +      fsym = tmp_formal ? tmp_formal->sym : NULL;
> +      if (e && fsym
> +	  && e->expr_type == EXPR_VARIABLE
> +	  && fsym->attr.intent == INTENT_OUT
> +	  && (fsym->ts.type == BT_CLASS && fsym->attr.class_ok
> +	      ? CLASS_DATA (fsym)->attr.allocatable
> +	      : fsym->attr.allocatable)
> +	  && e->symtree
> +	  && e->symtree->n.sym
> +	  && gfc_variable_attr (e, NULL).allocatable)
> +	{
> +	  force_eval_args = true;
> +	  break;
> +	}
> +    }
> +
The function is already big enough, would you mind outlining this to its 
own function?

>    /* Evaluate the arguments.  */
>    for (arg = args, argc = 0; arg != NULL;
>         arg = arg->next, formal = formal ? formal->next : NULL, ++argc)
> @@ -6680,7 +6708,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
>  		      else
>  			tmp = gfc_finish_block (&block);
> 
> -		      gfc_add_expr_to_block (&se->pre, tmp);
> +		      gfc_add_expr_to_block (&dealloc_blk, tmp);
>  		    }
> 
>  		  /* A class array element needs converting back to be a
> @@ -6980,7 +7008,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
>  					build_empty_stmt (input_location));
>  		      }
>  		    if (tmp != NULL_TREE)
> -		      gfc_add_expr_to_block (&se->pre, tmp);
> +		      gfc_add_expr_to_block (&dealloc_blk, tmp);
>  		  }
> 
>  		  tmp = parmse.expr;
> @@ -7004,7 +7032,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
>  				     void_type_node,
>  				     gfc_conv_expr_present (e->symtree->n.sym),
>  				       tmp, build_empty_stmt (input_location));
> -		  gfc_add_expr_to_block (&se->pre, tmp);
> +		  gfc_add_expr_to_block (&dealloc_blk, tmp);
>  		}
>  	    }
>  	}
These look good, but I'm surprised that there is no similar change at 
the 6819 line.
This is the class array actual vs class array dummy case.
It seems to be checked by the "bar" subroutine in your testcase, except 
that the intent(out) argument comes last there, whereas it was coming 
first with the original testcases in the PR.
Can you double check?

> @@ -7101,6 +7129,21 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
>  	    }
>  	}
> 
> +      /* If any actual argument of the procedure is allocatable and passed
> +	 to an allocatable dummy with INTENT(OUT), we conservatively
> +	 evaluate all actual argument expressions before deallocations are
> +	 performed and the procedure is executed.  This ensures we conform
> +	 to F2023:15.5.3, 15.5.4.  Create temporaries except for constants,
> +	 variables, and functions returning pointers that can appear in a
> +	 variable definition context.  */
> +      if (e && fsym && force_eval_args
> +	  && e->expr_type != EXPR_VARIABLE
> +	  && !gfc_is_constant_expr (e)
> +	  && (e->expr_type != EXPR_FUNCTION
> +	      || !(gfc_expr_attr (e).pointer
> +		   || gfc_expr_attr (e).proc_pointer)))
> +	parmse.expr = gfc_evaluate_now (parmse.expr, &parmse.pre);
> +
I'm not sure about the guarding condition.
It looks like it may miss evaluation in some cases (one testcase below).
With a value dummy, it is always safe to evaluate to a temporary 
variable, and with a non-value dummy, parmse.expr contains a pointer, so 
it is safe as well to evaluate that to a temporary pointer?
At least a || fsym->attr.value condition is missing somewhere, but I 
think the condition can be reduced to this:
       if (e && fsym && force_eval_args
	  && !gfc_is_constant_expr (e))
Were there failures that drove to your above guarding conditions?


Mikael

PS: The testcase (as promised):

program p
   implicit none
   type t
     integer :: i
     integer, pointer :: pi
   end type t
   integer, target :: j
   type(t), allocatable :: ta
   j = 1
   ta = t(2, j)
   call assign(ta, id(ta%pi))
   if (ta%i /= 1) stop 1
   if (associated(ta%pi)) stop 2
contains
   subroutine assign(a, b)
     type(t), intent(out), allocatable :: a
     integer, intent(in) , value       :: b
     allocate(a)
     a%i = b
     a%pi => null()
   end subroutine assign
   function id(a)
     integer, pointer :: id, a
     id => a
   end function id
end program p





  reply	other threads:[~2023-07-03 11:46 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-07-02 20:38 Harald Anlauf
2023-07-03 11:46 ` Mikael Morin [this message]
2023-07-03 20:49   ` Harald Anlauf
2023-07-03 23:56     ` Steve Kargl
2023-07-04  9:26       ` Mikael Morin
2023-07-04 15:50         ` Steve Kargl
2023-07-04 13:35     ` Mikael Morin
2023-07-04 19:00       ` Harald Anlauf
2023-07-04 19:37         ` Mikael Morin
2023-07-05 14:54           ` Mikael Morin
2023-07-05 20:36             ` Harald Anlauf
2023-07-07 12:21               ` Mikael Morin
2023-07-07 18:23                 ` Harald Anlauf
2023-07-08 12:07                   ` Mikael Morin
2023-07-08 14:20                     ` Harald Anlauf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5a5306ae-0db1-c7e2-e744-a3beced17636@orange.fr \
    --to=morin-mikael@orange.fr \
    --cc=anlauf@gmx.de \
    --cc=fortran@gcc.gnu.org \
    --cc=gcc-patches@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).