diff mbox series

[fortran] PR87477 - (associate) - [meta-bug] [F03] issues concerning the ASSOCIATE statement

Message ID CAGkQGiKOzc=DcdTNpTFO2MZeRiMSOhZZTJ2zKvq0+SDjZvwCyg@mail.gmail.com
State New
Headers show
Series [fortran] PR87477 - (associate) - [meta-bug] [F03] issues concerning the ASSOCIATE statement | expand

Commit Message

Paul Richard Thomas June 7, 2023, 4:10 p.m. UTC
Hi All,

Three more fixes for PR87477. Please note that PR99350 was a blocker
but, as pointed out in comment #5 of the PR, this has nothing to do
with the associate construct.

All three fixes are straight forward and the .diff + ChangeLog suffice
to explain them. 'rankguessed' was made redundant by the last PR87477
fix.

Regtests on x86_64 - good for mainline?

Paul

Fortran: Fix some more blockers in associate meta-bug [PR87477]

2023-06-07  Paul Thomas  <pault@gcc.gnu.org>

gcc/fortran
PR fortran/99350
* decl.cc (char_len_param_value): Simplify a copy of the expr
and replace the original if there is no error.
* gfortran.h : Remove the redundant field 'rankguessed' from
'gfc_association_list'.
* resolve.cc (resolve_assoc_var): Remove refs to 'rankguessed'.

PR fortran/107281
* resolve.cc (resolve_variable): Associate names with constant
or structure constructor targets cannot have array refs.

PR fortran/109451
* trans-array.cc (gfc_conv_expr_descriptor): Guard expression
character length backend decl before using it. Suppress the
assignment if lhs equals rhs.
* trans-io.cc (gfc_trans_transfer): Scalarize transfer of
associate variables pointing to a variable. Add comment.
* trans-stmt.cc (trans_associate_var): Remove requirement that
the character length be deferred before assigning the value
returned by gfc_conv_expr_descriptor. Also, guard the backend
decl before testing with VAR_P.

gcc/testsuite/
PR fortran/99350
* gfortran.dg/pr99350.f90 : New test.

PR fortran/107281
* gfortran.dg/associate_5.f03 : Changed error message.
* gfortran.dg/pr107281.f90 : New test.

PR fortran/109451
* gfortran.dg/associate_61.f90 : New test

Comments

Harald Anlauf June 7, 2023, 6:38 p.m. UTC | #1
Hi Paul!

On 6/7/23 18:10, Paul Richard Thomas via Gcc-patches wrote:
> Hi All,
>
> Three more fixes for PR87477. Please note that PR99350 was a blocker
> but, as pointed out in comment #5 of the PR, this has nothing to do
> with the associate construct.
>
> All three fixes are straight forward and the .diff + ChangeLog suffice
> to explain them. 'rankguessed' was made redundant by the last PR87477
> fix.
>
> Regtests on x86_64 - good for mainline?
>
> Paul
>
> Fortran: Fix some more blockers in associate meta-bug [PR87477]
>
> 2023-06-07  Paul Thomas  <pault@gcc.gnu.org>
>
> gcc/fortran
> PR fortran/99350
> * decl.cc (char_len_param_value): Simplify a copy of the expr
> and replace the original if there is no error.

This seems to lack a gfc_free_expr (p) in case the gfc_replace_expr
is not executed, leading to a possible memleak.  Can you check?

@@ -1081,10 +1082,10 @@ char_len_param_value (gfc_expr **expr, bool
*deferred)
    if (!gfc_expr_check_typed (*expr, gfc_current_ns, false))
      return MATCH_ERROR;

-  /* If gfortran gets an EXPR_OP, try to simplify it.  This catches things
-     like CHARACTER(([1])).   */
-  if ((*expr)->expr_type == EXPR_OP)
-    gfc_simplify_expr (*expr, 1);
+  /* Try to simplify the expression to catch things like
CHARACTER(([1])).   */
+  p = gfc_copy_expr (*expr);
+  if (gfc_is_constant_expr (p) && gfc_simplify_expr (p, 1))
+    gfc_replace_expr (*expr, p);
    else
      gfc_free_expr (p);

> * gfortran.h : Remove the redundant field 'rankguessed' from
> 'gfc_association_list'.
> * resolve.cc (resolve_assoc_var): Remove refs to 'rankguessed'.
>
> PR fortran/107281
> * resolve.cc (resolve_variable): Associate names with constant
> or structure constructor targets cannot have array refs.
>
> PR fortran/109451
> * trans-array.cc (gfc_conv_expr_descriptor): Guard expression
> character length backend decl before using it. Suppress the
> assignment if lhs equals rhs.
> * trans-io.cc (gfc_trans_transfer): Scalarize transfer of
> associate variables pointing to a variable. Add comment.
> * trans-stmt.cc (trans_associate_var): Remove requirement that
> the character length be deferred before assigning the value
> returned by gfc_conv_expr_descriptor. Also, guard the backend
> decl before testing with VAR_P.
>
> gcc/testsuite/
> PR fortran/99350
> * gfortran.dg/pr99350.f90 : New test.
>
> PR fortran/107281
> * gfortran.dg/associate_5.f03 : Changed error message.
> * gfortran.dg/pr107281.f90 : New test.
>
> PR fortran/109451
> * gfortran.dg/associate_61.f90 : New test

Otherwise LGTM.

Thanks for the patch!

Harald
Paul Richard Thomas June 8, 2023, 5:57 a.m. UTC | #2
Hi Harald,

In answer to your question:
void
gfc_replace_expr (gfc_expr *dest, gfc_expr *src)
{
  free_expr0 (dest);
  *dest = *src;
  free (src);
}
So it does indeed do the job.

I should perhaps have remarked that, following the divide error,
gfc_simplify_expr was returning a mutilated version of the expression
and this was somehow connected with successfully simplifying the
parentheses. Copying and replacing on no errors deals with the
problem.

Thanks

Paul

On Wed, 7 Jun 2023 at 19:38, Harald Anlauf <anlauf@gmx.de> wrote:
>
> Hi Paul!
>
> On 6/7/23 18:10, Paul Richard Thomas via Gcc-patches wrote:
> > Hi All,
> >
> > Three more fixes for PR87477. Please note that PR99350 was a blocker
> > but, as pointed out in comment #5 of the PR, this has nothing to do
> > with the associate construct.
> >
> > All three fixes are straight forward and the .diff + ChangeLog suffice
> > to explain them. 'rankguessed' was made redundant by the last PR87477
> > fix.
> >
> > Regtests on x86_64 - good for mainline?
> >
> > Paul
> >
> > Fortran: Fix some more blockers in associate meta-bug [PR87477]
> >
> > 2023-06-07  Paul Thomas  <pault@gcc.gnu.org>
> >
> > gcc/fortran
> > PR fortran/99350
> > * decl.cc (char_len_param_value): Simplify a copy of the expr
> > and replace the original if there is no error.
>
> This seems to lack a gfc_free_expr (p) in case the gfc_replace_expr
> is not executed, leading to a possible memleak.  Can you check?
>
> @@ -1081,10 +1082,10 @@ char_len_param_value (gfc_expr **expr, bool
> *deferred)
>     if (!gfc_expr_check_typed (*expr, gfc_current_ns, false))
>       return MATCH_ERROR;
>
> -  /* If gfortran gets an EXPR_OP, try to simplify it.  This catches things
> -     like CHARACTER(([1])).   */
> -  if ((*expr)->expr_type == EXPR_OP)
> -    gfc_simplify_expr (*expr, 1);
> +  /* Try to simplify the expression to catch things like
> CHARACTER(([1])).   */
> +  p = gfc_copy_expr (*expr);
> +  if (gfc_is_constant_expr (p) && gfc_simplify_expr (p, 1))
> +    gfc_replace_expr (*expr, p);
>     else
>       gfc_free_expr (p);
>
> > * gfortran.h : Remove the redundant field 'rankguessed' from
> > 'gfc_association_list'.
> > * resolve.cc (resolve_assoc_var): Remove refs to 'rankguessed'.
> >
> > PR fortran/107281
> > * resolve.cc (resolve_variable): Associate names with constant
> > or structure constructor targets cannot have array refs.
> >
> > PR fortran/109451
> > * trans-array.cc (gfc_conv_expr_descriptor): Guard expression
> > character length backend decl before using it. Suppress the
> > assignment if lhs equals rhs.
> > * trans-io.cc (gfc_trans_transfer): Scalarize transfer of
> > associate variables pointing to a variable. Add comment.
> > * trans-stmt.cc (trans_associate_var): Remove requirement that
> > the character length be deferred before assigning the value
> > returned by gfc_conv_expr_descriptor. Also, guard the backend
> > decl before testing with VAR_P.
> >
> > gcc/testsuite/
> > PR fortran/99350
> > * gfortran.dg/pr99350.f90 : New test.
> >
> > PR fortran/107281
> > * gfortran.dg/associate_5.f03 : Changed error message.
> > * gfortran.dg/pr107281.f90 : New test.
> >
> > PR fortran/109451
> > * gfortran.dg/associate_61.f90 : New test
>
> Otherwise LGTM.
>
> Thanks for the patch!
>
> Harald
>
>
Mikael Morin June 8, 2023, 7:46 a.m. UTC | #3
Le 08/06/2023 à 07:57, Paul Richard Thomas via Fortran a écrit :
> Hi Harald,
> 
> In answer to your question:
> void
> gfc_replace_expr (gfc_expr *dest, gfc_expr *src)
> {
>    free_expr0 (dest);
>    *dest = *src;
>    free (src);
> }
> So it does indeed do the job.
> 
Sure, but his comment was about the case gfc_replace_expr is *not* executed.

> I should perhaps have remarked that, following the divide error,
> gfc_simplify_expr was returning a mutilated version of the expression
> and this was somehow connected with successfully simplifying the
> parentheses. Copying and replacing on no errors deals with the
> problem.
> 
Is the expression mutilated enough that it can't be safely freed?
Harald Anlauf June 8, 2023, 8:30 a.m. UTC | #4
On 6/8/23 09:46, Mikael Morin wrote:
> Le 08/06/2023 à 07:57, Paul Richard Thomas via Fortran a écrit :
>> Hi Harald,
>>
>> In answer to your question:
>> void
>> gfc_replace_expr (gfc_expr *dest, gfc_expr *src)
>> {
>>    free_expr0 (dest);
>>    *dest = *src;
>>    free (src);
>> }
>> So it does indeed do the job.
>>
> Sure, but his comment was about the case gfc_replace_expr is *not* 
> executed.

Right.  The following legal code exhibits the leak, pointing
to the gfc_copy_expr:

subroutine paul (n)
   integer      :: n
   character(n) :: c
end

>> I should perhaps have remarked that, following the divide error,
>> gfc_simplify_expr was returning a mutilated version of the expression
>> and this was somehow connected with successfully simplifying the
>> parentheses. Copying and replacing on no errors deals with the
>> problem.
>>
> Is the expression mutilated enough that it can't be safely freed?
> 
> 
>
Paul Richard Thomas June 8, 2023, 9:11 a.m. UTC | #5
Thanks Gents!

The solution is to gfc_free_expr (p) if the replacement is not made.

I am regtesting a patch for PR107900. I'll include the fix for the
memory leak in the patch for that.

Cheers

Paul


On Thu, 8 Jun 2023 at 09:30, Harald Anlauf <anlauf@gmx.de> wrote:
>
> On 6/8/23 09:46, Mikael Morin wrote:
> > Le 08/06/2023 à 07:57, Paul Richard Thomas via Fortran a écrit :
> >> Hi Harald,
> >>
> >> In answer to your question:
> >> void
> >> gfc_replace_expr (gfc_expr *dest, gfc_expr *src)
> >> {
> >>    free_expr0 (dest);
> >>    *dest = *src;
> >>    free (src);
> >> }
> >> So it does indeed do the job.
> >>
> > Sure, but his comment was about the case gfc_replace_expr is *not*
> > executed.
>
> Right.  The following legal code exhibits the leak, pointing
> to the gfc_copy_expr:
>
> subroutine paul (n)
>    integer      :: n
>    character(n) :: c
> end
>
> >> I should perhaps have remarked that, following the divide error,
> >> gfc_simplify_expr was returning a mutilated version of the expression
> >> and this was somehow connected with successfully simplifying the
> >> parentheses. Copying and replacing on no errors deals with the
> >> problem.
> >>
> > Is the expression mutilated enough that it can't be safely freed?
> >
> >
> >
>
diff mbox series

Patch

diff --git a/gcc/fortran/decl.cc b/gcc/fortran/decl.cc
index f5d39e2a3d8..d09c8bc97d9 100644
--- a/gcc/fortran/decl.cc
+++ b/gcc/fortran/decl.cc
@@ -1056,6 +1056,7 @@  static match
 char_len_param_value (gfc_expr **expr, bool *deferred)
 {
   match m;
+  gfc_expr *p;
 
   *expr = NULL;
   *deferred = false;
@@ -1081,10 +1082,10 @@  char_len_param_value (gfc_expr **expr, bool *deferred)
   if (!gfc_expr_check_typed (*expr, gfc_current_ns, false))
     return MATCH_ERROR;
 
-  /* If gfortran gets an EXPR_OP, try to simplify it.  This catches things
-     like CHARACTER(([1])).   */
-  if ((*expr)->expr_type == EXPR_OP)
-    gfc_simplify_expr (*expr, 1);
+  /* Try to simplify the expression to catch things like CHARACTER(([1])).   */
+  p = gfc_copy_expr (*expr);
+  if (gfc_is_constant_expr (p) && gfc_simplify_expr (p, 1))
+    gfc_replace_expr (*expr, p);
 
   if ((*expr)->expr_type == EXPR_FUNCTION)
     {
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 3e5f942d7fd..a65dd571591 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -2914,9 +2914,6 @@  typedef struct gfc_association_list
      for memory handling.  */
   unsigned dangling:1;
 
-  /* True when the rank of the target expression is guessed during parsing.  */
-  unsigned rankguessed:1;
-
   char name[GFC_MAX_SYMBOL_LEN + 1];
   gfc_symtree *st; /* Symtree corresponding to name.  */
   locus where;
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index 2ba3101f1fe..f2604314570 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -5872,7 +5872,15 @@  resolve_variable (gfc_expr *e)
       if (sym->ts.type == BT_CLASS)
 	gfc_fix_class_refs (e);
       if (!sym->attr.dimension && e->ref && e->ref->type == REF_ARRAY)
-	return false;
+	{
+	  /* Unambiguously scalar!  */
+	  if (sym->assoc->target
+	      && (sym->assoc->target->expr_type == EXPR_CONSTANT
+		  || sym->assoc->target->expr_type == EXPR_STRUCTURE))
+	    gfc_error ("Scalar variable %qs has an array reference at %L",
+		       sym->name, &e->where);
+	  return false;
+	}
       else if (sym->attr.dimension && (!e->ref || e->ref->type != REF_ARRAY))
 	{
 	  /* This can happen because the parser did not detect that the
@@ -9279,7 +9287,7 @@  resolve_assoc_var (gfc_symbol* sym, bool resolve_target)
       gfc_array_spec *as;
       /* The rank may be incorrectly guessed at parsing, therefore make sure
 	 it is corrected now.  */
-      if (sym->ts.type != BT_CLASS && (!sym->as || sym->assoc->rankguessed))
+      if (sym->ts.type != BT_CLASS && !sym->as)
 	{
 	  if (!sym->as)
 	    sym->as = gfc_get_array_spec ();
@@ -9292,8 +9300,7 @@  resolve_assoc_var (gfc_symbol* sym, bool resolve_target)
 	    sym->attr.codimension = 1;
 	}
       else if (sym->ts.type == BT_CLASS
-	       && CLASS_DATA (sym)
-	       && (!CLASS_DATA (sym)->as || sym->assoc->rankguessed))
+	       && CLASS_DATA (sym) && !CLASS_DATA (sym)->as)
 	{
 	  if (!CLASS_DATA (sym)->as)
 	    CLASS_DATA (sym)->as = gfc_get_array_spec ();
diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 1c7ea900ea1..e1c75e9fe02 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -7934,7 +7934,8 @@  gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr)
 	  else
 	    tmp = se->string_length;
 
-	  if (expr->ts.deferred && VAR_P (expr->ts.u.cl->backend_decl))
+	  if (expr->ts.deferred && expr->ts.u.cl->backend_decl
+	      && VAR_P (expr->ts.u.cl->backend_decl))
 	    gfc_add_modify (&se->pre, expr->ts.u.cl->backend_decl, tmp);
 	  else
 	    expr->ts.u.cl->backend_decl = tmp;
@@ -7999,6 +8000,15 @@  gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr)
 	    }
 	}
 
+      if (expr->ts.type == BT_CHARACTER
+	  && VAR_P (TYPE_SIZE_UNIT (gfc_get_element_type (TREE_TYPE (parm)))))
+	{
+	  tree elem_len = TYPE_SIZE_UNIT (gfc_get_element_type (TREE_TYPE (parm)));
+	  gfc_add_modify (&loop.pre, elem_len,
+			  fold_convert (TREE_TYPE (elem_len),
+			  gfc_get_array_span (desc, expr)));
+	}
+
       /* Set the span field.  */
       tmp = NULL_TREE;
       if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)))
diff --git a/gcc/fortran/trans-io.cc b/gcc/fortran/trans-io.cc
index 0c0e3332778..e36ad0e3db4 100644
--- a/gcc/fortran/trans-io.cc
+++ b/gcc/fortran/trans-io.cc
@@ -2620,9 +2620,13 @@  gfc_trans_transfer (gfc_code * code)
 	  gcc_assert (ref && ref->type == REF_ARRAY);
 	}
 
+      /* These expressions don't always have the dtype element length set
+	 correctly, rendering them useless for array transfer.  */
       if (expr->ts.type != BT_CLASS
 	 && expr->expr_type == EXPR_VARIABLE
 	 && ((expr->symtree->n.sym->ts.type == BT_DERIVED && expr->ts.deferred)
+	     || (expr->symtree->n.sym->assoc
+		 && expr->symtree->n.sym->assoc->variable)
 	     || gfc_expr_attr (expr).pointer))
 	goto scalarize;
 
diff --git a/gcc/fortran/trans-stmt.cc b/gcc/fortran/trans-stmt.cc
index b5b82941b41..dcabeca0078 100644
--- a/gcc/fortran/trans-stmt.cc
+++ b/gcc/fortran/trans-stmt.cc
@@ -1930,15 +1930,13 @@  trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block)
       gfc_conv_expr_descriptor (&se, e);
 
       if (sym->ts.type == BT_CHARACTER
-	  && sym->ts.deferred
 	  && !sym->attr.select_type_temporary
+	  && sym->ts.u.cl->backend_decl
 	  && VAR_P (sym->ts.u.cl->backend_decl)
 	  && se.string_length != sym->ts.u.cl->backend_decl)
-	{
-	  gfc_add_modify (&se.pre, sym->ts.u.cl->backend_decl,
+	gfc_add_modify (&se.pre, sym->ts.u.cl->backend_decl,
 			  fold_convert (TREE_TYPE (sym->ts.u.cl->backend_decl),
 					se.string_length));
-	}
 
       /* If we didn't already do the pointer assignment, set associate-name
 	 descriptor to the one generated for the temporary.  */
diff --git a/gcc/testsuite/gfortran.dg/associate_5.f03 b/gcc/testsuite/gfortran.dg/associate_5.f03
index 64345d323f3..c91f88f4e12 100644
--- a/gcc/testsuite/gfortran.dg/associate_5.f03
+++ b/gcc/testsuite/gfortran.dg/associate_5.f03
@@ -11,7 +11,7 @@  PROGRAM main
   INTEGER, POINTER :: ptr
 
   ASSOCIATE (a => 5) ! { dg-error "is used as array" }
-    PRINT *, a(3)
+    PRINT *, a(3) ! { dg-error "has an array reference" }
   END ASSOCIATE
 
   ASSOCIATE (a => nontarget)