[PATCH 1/3] fortran: defer class wrapper initialization after deallocation [PR92178]

2023-07-11 Thread Mikael Morin via Fortran
If an actual argument is associated with an INTENT(OUT) dummy, and code
to deallocate it is generated, generate the class wrapper initialization
after the actual argument deallocation.

This is achieved by passing a cleaned up expression to
gfc_conv_class_to_class, so that the class wrapper initialization code
can be isolated and moved independently after the deallocation.

PR fortran/92178

gcc/fortran/ChangeLog:

* trans-expr.cc (gfc_conv_procedure_call): Use a separate gfc_se
struct, initalized from parmse, to generate the class wrapper.
After the class wrapper code has been generated, copy it back
depending on whether parameter deallocation code has been
generated.

gcc/testsuite/ChangeLog:

* gfortran.dg/intent_out_19.f90: New test.
---
 gcc/fortran/trans-expr.cc   | 18 -
 gcc/testsuite/gfortran.dg/intent_out_19.f90 | 22 +
 2 files changed, 39 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gfortran.dg/intent_out_19.f90

diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 7017b652d6e..b7e95e6d04d 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -6500,6 +6500,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 
  else
{
+ bool defer_to_dealloc_blk = false;
  if (e->ts.type == BT_CLASS && fsym
  && fsym->ts.type == BT_CLASS
  && (!CLASS_DATA (fsym)->as
@@ -6661,6 +6662,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
  stmtblock_t block;
  tree ptr;
 
+ defer_to_dealloc_blk = true;
+
  gfc_init_block  (&block);
  ptr = parmse.expr;
  if (e->ts.type == BT_CLASS)
@@ -6717,7 +6720,12 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
&& ((CLASS_DATA (fsym)->as
 && CLASS_DATA (fsym)->as->type == AS_ASSUMED_RANK)
|| CLASS_DATA (e)->attr.dimension))
-   gfc_conv_class_to_class (&parmse, e, fsym->ts, false,
+   {
+ gfc_se class_se = parmse;
+ gfc_init_block (&class_se.pre);
+ gfc_init_block (&class_se.post);
+
+ gfc_conv_class_to_class (&class_se, e, fsym->ts, false,
 fsym->attr.intent != INTENT_IN
 && (CLASS_DATA (fsym)->attr.class_pointer
 || CLASS_DATA 
(fsym)->attr.allocatable),
@@ -6727,6 +6735,14 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 CLASS_DATA (fsym)->attr.class_pointer
 || CLASS_DATA (fsym)->attr.allocatable);
 
+ parmse.expr = class_se.expr;
+ stmtblock_t *class_pre_block = defer_to_dealloc_blk
+? &dealloc_blk
+: &parmse.pre;
+ gfc_add_block_to_block (class_pre_block, &class_se.pre);
+ gfc_add_block_to_block (&parmse.post, &class_se.post);
+   }
+
  if (fsym && (fsym->ts.type == BT_DERIVED
   || fsym->ts.type == BT_ASSUMED)
  && e->ts.type == BT_CLASS
diff --git a/gcc/testsuite/gfortran.dg/intent_out_19.f90 
b/gcc/testsuite/gfortran.dg/intent_out_19.f90
new file mode 100644
index 000..03036ed382a
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/intent_out_19.f90
@@ -0,0 +1,22 @@
+! { dg-do run }
+!
+! PR fortran/92178
+! Check that if a data reference passed is as actual argument whose dummy
+! has INTENT(OUT) attribute, any other argument depending on the
+! same data reference is evaluated before the data reference deallocation.
+
+program p
+  implicit none
+  class(*),  allocatable :: c
+  c = 3
+  call bar (allocated(c), c, allocated (c))
+  if (allocated (c)) stop 14
+contains
+  subroutine bar (alloc, x, alloc2)
+logical :: alloc, alloc2
+class(*), allocatable, intent(out) :: x(..)
+if (allocated (x)) stop 5
+if (.not. alloc)   stop 6
+if (.not. alloc2)  stop 16
+  end subroutine bar
+end
-- 
2.40.1



[PATCH 0/3] Fix argument evaluation order [PR92178]

2023-07-11 Thread Mikael Morin via Fortran
Hello,

this is a followup to Harald's recent work [1] on the evaluation order
of arguments, when one of them is passed to an intent(out) allocatable
dummy and is deallocated before the call.
This extends Harald's fix to support:
 - scalars passed to assumed rank dummies (patch 1),
 - scalars passed to assumed rank dummies with the data reference
 depending on its own content (patch 2),
 - arrays with the data reference depending on its own content
 (patch 3).

There is one (last?) case which is not supported, for which I have opened
a separate PR [2].

Regression tested on x86_64-pc-linux-gnu. OK for master?

[1] https://gcc.gnu.org/pipermail/fortran/2023-July/059562.html 
[2] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110618

Mikael Morin (3):
  fortran: defer class wrapper initialization after deallocation
[PR92178]
  fortran: Factor data references for scalar class argument wrapping
[PR92178]
  fortran: Reorder array argument evaluation parts [PR92178]

 gcc/fortran/trans-array.cc  |   3 +
 gcc/fortran/trans-expr.cc   | 130 +---
 gcc/fortran/trans.cc|  28 +
 gcc/fortran/trans.h |   8 +-
 gcc/testsuite/gfortran.dg/intent_out_19.f90 |  22 
 gcc/testsuite/gfortran.dg/intent_out_20.f90 |  33 +
 gcc/testsuite/gfortran.dg/intent_out_21.f90 |  33 +
 7 files changed, 236 insertions(+), 21 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/intent_out_19.f90
 create mode 100644 gcc/testsuite/gfortran.dg/intent_out_20.f90
 create mode 100644 gcc/testsuite/gfortran.dg/intent_out_21.f90

-- 
2.40.1



[PATCH 2/3] fortran: Factor data references for scalar class argument wrapping [PR92178]

2023-07-11 Thread Mikael Morin via Fortran
In the case of a scalar actual arg passed to a polymorphic assumed-rank
dummy with INTENT(OUT) attribute, avoid repeatedly evaluating the actual
argument reference by saving a pointer to it.  This is non-optimal, but
may also be invalid, because the data reference may depend on its own
content.  In that case the expression can't be evaluated after the data
has been deallocated.

There are two ways redundant expressions are generated:
 - parmse.expr, which contains the actual argument expression, is
   reused to get or set subfields in gfc_conv_class_to_class.
 - gfc_conv_class_to_class, to get the virtual table pointer associated
   with the argument, generates a new expression from scratch starting
   with the frontend expression.

The first part is fixed by saving parmse.expr to a pointer and using
the pointer instead of the original expression.

The second part is fixed by adding a separate field to gfc_se that
is set to the class container expression  when the expression to
evaluate is polymorphic.  This needs the same field in gfc_ss_info
so that its value can be propagated to gfc_conv_class_to_class which
is modified to use that value.  Finally gfc_conv_procedure saves the
expression in that field to a pointer in between to avoid the same
problem as for the first part.

PR fortran/92178

gcc/fortran/ChangeLog:

* trans.h (struct gfc_se): New field class_container.
(struct gfc_ss_info): Ditto.
(gfc_evaluate_data_ref_now): New prototype.
* trans.cc (gfc_evaluate_data_ref_now):  Implement it.
* trans-array.cc (gfc_conv_ss_descriptor): Copy class_container
field from gfc_se struct to gfc_ss_info struct.
(gfc_conv_expr_descriptor): Copy class_container field from
gfc_ss_info struct to gfc_se struct.
* trans-expr.cc (gfc_conv_class_to_class): Use class container
set in class_container field if available.
(gfc_conv_variable): Set class_container field on encountering
class variables or components, clear it on encountering
non-class components.
(gfc_conv_procedure_call): Evaluate data ref to a pointer now,
and replace later references by usage of the pointer.

gcc/testsuite/ChangeLog:

* gfortran.dg/intent_out_20.f90: New test.
---
 gcc/fortran/trans-array.cc  |  3 ++
 gcc/fortran/trans-expr.cc   | 26 
 gcc/fortran/trans.cc| 28 +
 gcc/fortran/trans.h |  6 
 gcc/testsuite/gfortran.dg/intent_out_20.f90 | 33 +
 5 files changed, 96 insertions(+)
 create mode 100644 gcc/testsuite/gfortran.dg/intent_out_20.f90

diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index e7c51bae052..1c2af55d436 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -3271,6 +3271,7 @@ gfc_conv_ss_descriptor (stmtblock_t * block, gfc_ss * ss, 
int base)
   gfc_add_block_to_block (block, &se.pre);
   info->descriptor = se.expr;
   ss_info->string_length = se.string_length;
+  ss_info->class_container = se.class_container;
 
   if (base)
 {
@@ -7687,6 +7688,8 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr)
  else if (deferred_array_component)
se->string_length = ss_info->string_length;
 
+ se->class_container = ss_info->class_container;
+
  gfc_free_ss_chain (ss);
  return;
}
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index b7e95e6d04d..5169fbcd974 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -1266,6 +1266,10 @@ gfc_conv_class_to_class (gfc_se *parmse, gfc_expr *e, 
gfc_typespec class_ts,
 
   slen = build_zero_cst (size_type_node);
 }
+  else if (parmse->class_container != NULL_TREE)
+/* Don't redundantly evaluate the expression if the required information
+   is already available.  */
+tmp = parmse->class_container;
   else
 {
   /* Remove everything after the last class reference, convert the
@@ -3078,6 +3082,11 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr)
  return;
}
 
+  if (sym->ts.type == BT_CLASS
+ && sym->attr.class_ok
+ && sym->ts.u.derived->attr.is_class)
+   se->class_container = se->expr;
+
   /* Dereference the expression, where needed.  */
   se->expr = gfc_maybe_dereference_var (sym, se->expr, se->descriptor_only,
is_classarray);
@@ -3135,6 +3144,15 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr)
conv_parent_component_references (se, ref);
 
  gfc_conv_component_ref (se, ref);
+
+ if (ref->u.c.component->ts.type == BT_CLASS
+ && ref->u.c.component->attr.class_ok
+ && ref->u.c.component->ts.u.derived->attr.is_class)
+   se->class_container = se->expr;
+ else if (!(ref->u.c.sym->attr.flavor == FL_DERIVED
+  

[PATCH 3/3] fortran: Reorder array argument evaluation parts [PR92178]

2023-07-11 Thread Mikael Morin via Fortran
In the case of an array actual arg passed to a polymorphic array dummy
with INTENT(OUT) attribute, reorder the argument evaluation code to
the following:
 - first evaluate arguments' values, and data references,
 - deallocate data references associated with an allocatable,
   intent(out) dummy,
 - create a class container using the freed data references.

The ordering used to be incorrect between the first two items,
when one argument was deallocated before a later argument evaluated
its expression depending on the former argument.
r14-2395-gb1079fc88f082d3c5b583c8822c08c5647810259 fixed it by treating
arguments associated with an allocatable, intent(out) dummy in a
separate, later block.  This, however, wasn't working either if the data
reference of such an argument was depending on its own content, as
the class container initialization was trying to use deallocated
content.

This change generates class container initialization code in a separate
block, so that it is moved after the deallocation block without moving
the rest of the argument evaluation code.

This alone is not sufficient to fix the problem, because the class
container generation code repeatedly uses the full expression of
the argument at a place where deallocation might have happened
already.  This is non-optimal, but may also be invalid, because the data
reference may depend on its own content.  In that case the expression
can't be evaluated after the data has been deallocated.

As in the scalar case previously treated, this is fixed by saving
the data reference to a pointer before any deallocation happens,
and then only refering to the pointer.  gfc_reset_vptr is updated
to take into account the already evaluated class container if it's
available.

Contrary to the scalar case, one hunk is needed to wrap the parameter
evaluation in a conditional, to avoid regressing in
optional_class_2.f90.  This used to be handled by the class wrapper
construction which wrapped the whole code in a conditional.  With
this change the class wrapper construction can't see the parameter
evaluation code, so the latter is updated with an additional handling
for optional arguments.

PR fortran/92178

gcc/fortran/ChangeLog:

* trans.h (gfc_reset_vptr): Add class_container argument.
* trans-expr.cc (gfc_reset_vptr): Ditto.  If a valid vptr can
be obtained through class_container argument, bypass evaluation
of e.
(gfc_conv_procedure_call):  Wrap the argument evaluation code
in a conditional if the associated dummy is optional.  Evaluate
the data reference to a pointer now, and replace later
references with usage of the pointer.

gcc/testsuite/ChangeLog:

* gfortran.dg/intent_out_21.f90: New test.
---
 gcc/fortran/trans-expr.cc   | 86 -
 gcc/fortran/trans.h |  2 +-
 gcc/testsuite/gfortran.dg/intent_out_21.f90 | 33 
 3 files changed, 101 insertions(+), 20 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/intent_out_21.f90

diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 5169fbcd974..dbb04f8c434 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -529,24 +529,32 @@ gfc_find_and_cut_at_last_class_ref (gfc_expr *e, bool 
is_mold,
 }
 
 
-/* Reset the vptr to the declared type, e.g. after deallocation.  */
+/* Reset the vptr to the declared type, e.g. after deallocation.
+   Use the variable in CLASS_CONTAINER if available.  Otherwise, recreate
+   one with E.  The generated assignment code is added at the end of BLOCK.  */
 
 void
-gfc_reset_vptr (stmtblock_t *block, gfc_expr *e)
+gfc_reset_vptr (stmtblock_t *block, gfc_expr *e, tree class_container)
 {
-  gfc_symbol *vtab;
-  tree vptr;
-  tree vtable;
-  gfc_se se;
+  tree vptr = NULL_TREE;
 
-  /* Evaluate the expression and obtain the vptr from it.  */
-  gfc_init_se (&se, NULL);
-  if (e->rank)
-gfc_conv_expr_descriptor (&se, e);
-  else
-gfc_conv_expr (&se, e);
-  gfc_add_block_to_block (block, &se.pre);
-  vptr = gfc_get_vptr_from_expr (se.expr);
+  if (class_container != NULL_TREE)
+vptr = gfc_get_vptr_from_expr (class_container);
+
+  if (vptr == NULL_TREE)
+{
+  gfc_se se;
+
+  /* Evaluate the expression and obtain the vptr from it.  */
+  gfc_init_se (&se, NULL);
+  if (e->rank)
+   gfc_conv_expr_descriptor (&se, e);
+  else
+   gfc_conv_expr (&se, e);
+  gfc_add_block_to_block (block, &se.pre);
+
+  vptr = gfc_get_vptr_from_expr (se.expr);
+}
 
   /* If a vptr is not found, we can do nothing more.  */
   if (vptr == NULL_TREE)
@@ -556,6 +564,9 @@ gfc_reset_vptr (stmtblock_t *block, gfc_expr *e)
 gfc_add_modify (block, vptr, build_int_cst (TREE_TYPE (vptr), 0));
   else
 {
+  gfc_symbol *vtab;
+  tree vtable;
+
   /* Return the vptr to the address of the declared type.  */
   vtab = gfc_find_derived_vtab (e->ts.u.derived);
   

[PATCH] fortran: Release symbols in reversed order [PR106050]

2023-07-11 Thread Mikael Morin via Fortran
Hello,

I saw the light regarding this PR after Paul posted a comment yesterday.

Regression test in progress on x86_64-pc-linux-gnu.
I plan to push in the next hours.

Mikael

-- >8 --

Release symbols in reversed order wrt the order they were allocated.
This fixes an error recovery ICE in the case of a misplaced
derived type declaration.  Such a declaration creates nested
symbols, one for the derived type and one for each type parameter,
which should be immediately released as the declaration is
rejected.  This breaks if the derived type is released first.
As the type parameter symbols are in the namespace of the derived
type, releasing the derived type releases the type parameters, so
one can't access them after that, even to release them.  Hence,
the type parameters should be released first.

PR fortran/106050

gcc/fortran/ChangeLog:

* symbol.cc (gfc_restore_last_undo_checkpoint): Release symbols
in reverse order.

gcc/testsuite/ChangeLog:

* gfortran.dg/pdt_33.f90: New test.
---
 gcc/fortran/symbol.cc|  2 +-
 gcc/testsuite/gfortran.dg/pdt_33.f90 | 15 +++
 2 files changed, 16 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gfortran.dg/pdt_33.f90

diff --git a/gcc/fortran/symbol.cc b/gcc/fortran/symbol.cc
index 37a9e8fa0ae..4a71d84b3fe 100644
--- a/gcc/fortran/symbol.cc
+++ b/gcc/fortran/symbol.cc
@@ -3661,7 +3661,7 @@ gfc_restore_last_undo_checkpoint (void)
   gfc_symbol *p;
   unsigned i;
 
-  FOR_EACH_VEC_ELT (latest_undo_chgset->syms, i, p)
+  FOR_EACH_VEC_ELT_REVERSE (latest_undo_chgset->syms, i, p)
 {
   /* Symbol in a common block was new. Or was old and just put in common */
   if (p->common_block
diff --git a/gcc/testsuite/gfortran.dg/pdt_33.f90 
b/gcc/testsuite/gfortran.dg/pdt_33.f90
new file mode 100644
index 000..0521513f2f8
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pdt_33.f90
@@ -0,0 +1,15 @@
+! { dg-do compile }
+!
+! PR fortran/106050
+! The following used to trigger an error recovery ICE by releasing
+! the symbol T before the symbol K which was leading to releasing
+! K twice as it's in T's namespace.
+!
+! Contributed by G. Steinmetz 
+
+program p
+   a = 1
+   type t(k)  ! { dg-error "Unexpected derived type 
declaration" }
+  integer, kind :: k = 4  ! { dg-error "not allowed outside a TYPE 
definition" }
+   end type   ! { dg-error "Expecting END PROGRAM" }
+end
-- 
2.40.1



Re: [PATCH] fortran: Release symbols in reversed order [PR106050]

2023-07-11 Thread Paul Richard Thomas via Fortran
Hi Mikhail,

That's more than OK by me.

Thanks for attacking this PR.

I have a couple more of Steve's orphans waiting to be packaged up -
91960 and 104649. I'll submit them this evening.100607 is closed-fixed
and 103796 seems to be fixed.

Regards

Paul

On Tue, 11 Jul 2023 at 13:08, Mikael Morin via Fortran
 wrote:
>
> Hello,
>
> I saw the light regarding this PR after Paul posted a comment yesterday.
>
> Regression test in progress on x86_64-pc-linux-gnu.
> I plan to push in the next hours.
>
> Mikael
>
> -- >8 --
>
> Release symbols in reversed order wrt the order they were allocated.
> This fixes an error recovery ICE in the case of a misplaced
> derived type declaration.  Such a declaration creates nested
> symbols, one for the derived type and one for each type parameter,
> which should be immediately released as the declaration is
> rejected.  This breaks if the derived type is released first.
> As the type parameter symbols are in the namespace of the derived
> type, releasing the derived type releases the type parameters, so
> one can't access them after that, even to release them.  Hence,
> the type parameters should be released first.
>
> PR fortran/106050
>
> gcc/fortran/ChangeLog:
>
> * symbol.cc (gfc_restore_last_undo_checkpoint): Release symbols
> in reverse order.
>
> gcc/testsuite/ChangeLog:
>
> * gfortran.dg/pdt_33.f90: New test.
> ---
>  gcc/fortran/symbol.cc|  2 +-
>  gcc/testsuite/gfortran.dg/pdt_33.f90 | 15 +++
>  2 files changed, 16 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/gfortran.dg/pdt_33.f90
>
> diff --git a/gcc/fortran/symbol.cc b/gcc/fortran/symbol.cc
> index 37a9e8fa0ae..4a71d84b3fe 100644
> --- a/gcc/fortran/symbol.cc
> +++ b/gcc/fortran/symbol.cc
> @@ -3661,7 +3661,7 @@ gfc_restore_last_undo_checkpoint (void)
>gfc_symbol *p;
>unsigned i;
>
> -  FOR_EACH_VEC_ELT (latest_undo_chgset->syms, i, p)
> +  FOR_EACH_VEC_ELT_REVERSE (latest_undo_chgset->syms, i, p)
>  {
>/* Symbol in a common block was new. Or was old and just put in common 
> */
>if (p->common_block
> diff --git a/gcc/testsuite/gfortran.dg/pdt_33.f90 
> b/gcc/testsuite/gfortran.dg/pdt_33.f90
> new file mode 100644
> index 000..0521513f2f8
> --- /dev/null
> +++ b/gcc/testsuite/gfortran.dg/pdt_33.f90
> @@ -0,0 +1,15 @@
> +! { dg-do compile }
> +!
> +! PR fortran/106050
> +! The following used to trigger an error recovery ICE by releasing
> +! the symbol T before the symbol K which was leading to releasing
> +! K twice as it's in T's namespace.
> +!
> +! Contributed by G. Steinmetz 
> +
> +program p
> +   a = 1
> +   type t(k)  ! { dg-error "Unexpected derived type 
> declaration" }
> +  integer, kind :: k = 4  ! { dg-error "not allowed outside a TYPE 
> definition" }
> +   end type   ! { dg-error "Expecting END PROGRAM" }
> +end
> --
> 2.40.1
>


--
"If you can't explain it simply, you don't understand it well enough"
- Albert Einstein


Re: [Patch, Fortran] Allow ref'ing PDT's len() in parameter-initializer [PR102003]

2023-07-11 Thread Andre Vehreschild via Fortran
Hi Harald,

attached is a new version of the patch. This now also respects inquiry-LEN.
Btw, there is a potential memory leak in the simplify for inquiry functions. I
have added a note into the code.

I tried to use a pdt within a derived type as a component. Is that not allowed
by the standard? I know, I could hunt in the standard for it, but when someone
knows out of his head, he could greatly help me out.

Regtests ok on x86_64-linux-gnu/F37.

Regards,
Andre

On Mon, 10 Jul 2023 20:55:29 +0200
Harald Anlauf  wrote:

> Hi Andre,
>
> thanks for looking into this!
>
> While it fixes the original PR, here is a minor extension of the
> testcase that ICEs here with your patch:
>
> program pr102003
>type pdt(n)
>   integer, len :: n = 8
>   character(len=n) :: c
>end type pdt
>type(pdt(42)) :: p
>integer, parameter :: m = len (p% c)
>integer, parameter :: n = p% c% len
>
>if (m /= 42) stop 1
>if (len (p% c) /= 42) stop 2
>print *, p% c% len   ! OK
>if (p% c% len  /= 42) stop 3 ! OK
>print *, n   ! ICE
> end
>
> I get:
>
> pdt_33.f03:14:27:
>
> 14 |   integer, parameter :: n = p% c% len
>|   1
> Error: non-constant initialization expression at (1)
> pdt_33.f03:20:31:
>
> 20 |   print *, n   ! ICE
>|   1
> internal compiler error: tree check: expected record_type or union_type
> or qual_union_type, have integer_type in gfc_conv_component_ref, at
> fortran/trans-expr.cc:2757
> 0x84286c tree_check_failed(tree_node const*, char const*, int, char
> const*, ...)
>  ../../gcc-trunk/gcc/tree.cc:8899
> 0xa6d6fb tree_check3(tree_node*, char const*, int, char const*,
> tree_code, tree_code, tree_code)
>  ../../gcc-trunk/gcc/tree.h:3617
> 0xa90847 gfc_conv_component_ref(gfc_se*, gfc_ref*)
>  ../../gcc-trunk/gcc/fortran/trans-expr.cc:2757
> 0xa91bbc gfc_conv_variable
>  ../../gcc-trunk/gcc/fortran/trans-expr.cc:3137
> 0xaa8e9c gfc_conv_expr(gfc_se*, gfc_expr*)
>  ../../gcc-trunk/gcc/fortran/trans-expr.cc:9594
> 0xaa92ae gfc_conv_expr_reference(gfc_se*, gfc_expr*)
>  ../../gcc-trunk/gcc/fortran/trans-expr.cc:9713
> 0xad67f6 gfc_trans_transfer(gfc_code*)
>  ../../gcc-trunk/gcc/fortran/trans-io.cc:2607
> 0xa43cb7 trans_code
>  ../../gcc-trunk/gcc/fortran/trans.cc:2449
> 0xad37c6 build_dt
>  ../../gcc-trunk/gcc/fortran/trans-io.cc:2051
> 0xa43cd7 trans_code
>  ../../gcc-trunk/gcc/fortran/trans.cc:2421
> 0xa84711 gfc_generate_function_code(gfc_namespace*)
>  ../../gcc-trunk/gcc/fortran/trans-decl.cc:7762
> 0x9d9ca7 translate_all_program_units
>  ../../gcc-trunk/gcc/fortran/parse.cc:6929
> 0x9d9ca7 gfc_parse_file()
>  ../../gcc-trunk/gcc/fortran/parse.cc:7235
> 0xa40a1f gfc_be_parse_file
>  ../../gcc-trunk/gcc/fortran/f95-lang.cc:229
>
> The fortran-dump confirms that n is not simplified to a constant.
> So while you're at it, do you also see a solution to this variant?
>
> Harald
>
>
> Am 10.07.23 um 17:48 schrieb Andre Vehreschild via Gcc-patches:
> > Hi all,
> >
> > while browsing the pdt meta-bug I came across 102003 and thought to myself:
> > Well, that one is easy. How foolish of me...
> >
> > Anyway, the solution attached prevents a pdt_len (or pdt_kind) expression
> > in a function call (e.g. len() or kind()) to mark the whole expression as a
> > pdt one. The second part of the patch in simplify.cc then takes care of
> > either generating the correct component ref or when a constant expression
> > (i.e. gfc_init_expr_flag is set) is required to look this up from the
> > actual symbol (not from the type, because there the default value is
> > stored).
> >
> > Regtested ok on x86_64-linux-gnu/Fedora 37.
> >
> > Regards,
> > Andre
> > --
> > Andre Vehreschild * Email: vehre ad gmx dot de
>


--
Andre Vehreschild * Email: vehre ad gmx dot de
gcc/fortran/ChangeLog:

* expr.cc (find_inquiry_ref): Replace len of pdt_string by
constant.
(gfc_match_init_expr): Prevent PDT analysis for function calls.
(gfc_pdt_find_component_copy_initializer): Get the initializer
value for given component.
* gfortran.h (gfc_pdt_find_component_copy_initializer): New
function.
* simplify.cc (gfc_simplify_len): Replace len() of PDT with pdt
component ref or constant.

gcc/testsuite/ChangeLog:

* gfortran.dg/pdt_33.f03: New test.

diff --git a/gcc/fortran/expr.cc b/gcc/fortran/expr.cc
index e418f1f3301..23324517ff2 100644
--- a/gcc/fortran/expr.cc
+++ b/gcc/fortran/expr.cc
@@ -1862,6 +1862,13 @@ find_inquiry_ref (gfc_expr *p, gfc_expr **newp)
 	  else if (tmp->expr_type == EXPR_CONSTANT)
 	*newp = gfc_get_int_expr (gfc_default_integer_kind,
   NULL, tmp->value.character.length);
+	  else if (gfc_init_expr_flag
+		   && tmp->ts.u.cl->length->symtree->n.sym->attr.pdt_len)
+	   

[PATCH] Fortran: formal symbol attributes for intrinsic procedures [PR110288]

2023-07-11 Thread Harald Anlauf via Fortran
Dear all,

for intrinsic procedures we derive the typespec of the formal symbol
attributes from the actual arguments.  This can have an undesired
effect for character actual arguments, as the argument passing
conventions differ for deferred-length (length is passed by reference)
and otherwise (length is passed by value).

The testcase in the PR nicely demonstrates the issue for
FINDLOC(array,value,...), when either array or value are deferred-length.

We therefore need take care that we do not copy ts.deferred, but
rather set it to false if the formal argument is neither allocatable
or pointer.

Regtested on x86_64-pc-linux-gnu.  OK for mainline?

This is actually a 11/12/13/14 regression (and I found a potential
"culprit" in 11-development that touched the call chain in question),
so the patch might finally need backporting as far as seems reasonable.

Thanks,
Harald

From 3b2c523ae31b68fc3b8363b458a55eec53a44365 Mon Sep 17 00:00:00 2001
From: Harald Anlauf 
Date: Tue, 11 Jul 2023 21:21:25 +0200
Subject: [PATCH] Fortran: formal symbol attributes for intrinsic procedures
 [PR110288]

gcc/fortran/ChangeLog:

	PR fortran/110288
	* symbol.cc (gfc_copy_formal_args_intr): When deriving the formal
	argument attributes from the actual ones for intrinsic procedure
	calls, take special care of CHARACTER arguments that we do not
	wrongly treat them formally as deferred-length.

gcc/testsuite/ChangeLog:

	PR fortran/110288
	* gfortran.dg/findloc_10.f90: New test.
---
 gcc/fortran/symbol.cc|  7 +++
 gcc/testsuite/gfortran.dg/findloc_10.f90 | 13 +
 2 files changed, 20 insertions(+)
 create mode 100644 gcc/testsuite/gfortran.dg/findloc_10.f90

diff --git a/gcc/fortran/symbol.cc b/gcc/fortran/symbol.cc
index 37a9e8fa0ae..90023f0ad73 100644
--- a/gcc/fortran/symbol.cc
+++ b/gcc/fortran/symbol.cc
@@ -4725,6 +4725,13 @@ gfc_copy_formal_args_intr (gfc_symbol *dest, gfc_intrinsic_sym *src,
   formal_arg->sym->attr.flavor = FL_VARIABLE;
   formal_arg->sym->attr.dummy = 1;

+  /* Do not treat an actual deferred-length character argument wrongly
+	 as template for the formal argument.  */
+  if (formal_arg->sym->ts.type == BT_CHARACTER
+	  && !(formal_arg->sym->attr.allocatable
+	   || formal_arg->sym->attr.pointer))
+	formal_arg->sym->ts.deferred = false;
+
   if (formal_arg->sym->ts.type == BT_CHARACTER)
 	formal_arg->sym->ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL);

diff --git a/gcc/testsuite/gfortran.dg/findloc_10.f90 b/gcc/testsuite/gfortran.dg/findloc_10.f90
new file mode 100644
index 000..4d5ecd2306a
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/findloc_10.f90
@@ -0,0 +1,13 @@
+! { dg-do run }
+! { dg-options "-fdump-tree-original" }
+! PR fortran/110288 - FINDLOC and deferred-length character arguments
+
+program test
+  character(len=:), allocatable :: array(:)
+  character(len=:), allocatable :: value
+  array = ["bb", "aa"]
+  value = "aa"
+  if (findloc (array, value, dim=1) /= 2) stop 1
+end program test
+
+! { dg-final { scan-tree-dump "_gfortran_findloc2_s1 \\(.*, \\.array, \\.value\\)" "original" } }
--
2.35.3



Re: [PATCH] Fortran: formal symbol attributes for intrinsic procedures [PR110288]

2023-07-11 Thread Steve Kargl via Fortran
On Tue, Jul 11, 2023 at 09:39:31PM +0200, Harald Anlauf via Fortran wrote:
> Dear all,
> 
> for intrinsic procedures we derive the typespec of the formal symbol
> attributes from the actual arguments.  This can have an undesired
> effect for character actual arguments, as the argument passing
> conventions differ for deferred-length (length is passed by reference)
> and otherwise (length is passed by value).
> 
> The testcase in the PR nicely demonstrates the issue for
> FINDLOC(array,value,...), when either array or value are deferred-length.
> 
> We therefore need take care that we do not copy ts.deferred, but
> rather set it to false if the formal argument is neither allocatable
> or pointer.
> 
> Regtested on x86_64-pc-linux-gnu.  OK for mainline?
> 
> This is actually a 11/12/13/14 regression (and I found a potential
> "culprit" in 11-development that touched the call chain in question),
> so the patch might finally need backporting as far as seems reasonable.
> 

OK.  Backports are OK as well.

-- 
Steve


Re: [Patch, Fortran] Allow ref'ing PDT's len() in parameter-initializer [PR102003]

2023-07-11 Thread Harald Anlauf via Fortran

Hi Andre,

this looks much better now!

This looks mostly good to me, except for a typo in the testcase:

+  if (p% ci% len /= 42) stop 4

There is no component "ci", only "c".  The testsuite would fail.

Regarding the memleak: replacing

  // TODO: Fix leaking expr tmp, when simplify is done twice.
  tmp = gfc_copy_expr (*newp);

by

  if (inquiry->next)
{
  gfc_free_expr (tmp);
  tmp = gfc_copy_expr (*newp);
}

or rather

  if (inquiry->next)
gfc_replace_expr (tmp, *newp);

at least shrinks the leak a bit.  (Untested otherwise).

OK with one of the above changes (provided it survives regtesting).

Thanks for the patch!

Harald


Am 11.07.23 um 18:23 schrieb Andre Vehreschild via Gcc-patches:

Hi Harald,

attached is a new version of the patch. This now also respects inquiry-LEN.
Btw, there is a potential memory leak in the simplify for inquiry functions. I
have added a note into the code.

I tried to use a pdt within a derived type as a component. Is that not allowed
by the standard? I know, I could hunt in the standard for it, but when someone
knows out of his head, he could greatly help me out.

Regtests ok on x86_64-linux-gnu/F37.

Regards,
Andre

On Mon, 10 Jul 2023 20:55:29 +0200
Harald Anlauf  wrote:


Hi Andre,

thanks for looking into this!

While it fixes the original PR, here is a minor extension of the
testcase that ICEs here with your patch:

program pr102003
type pdt(n)
   integer, len :: n = 8
   character(len=n) :: c
end type pdt
type(pdt(42)) :: p
integer, parameter :: m = len (p% c)
integer, parameter :: n = p% c% len

if (m /= 42) stop 1
if (len (p% c) /= 42) stop 2
print *, p% c% len   ! OK
if (p% c% len  /= 42) stop 3 ! OK
print *, n   ! ICE
end

I get:

pdt_33.f03:14:27:

 14 |   integer, parameter :: n = p% c% len
|   1
Error: non-constant initialization expression at (1)
pdt_33.f03:20:31:

 20 |   print *, n   ! ICE
|   1
internal compiler error: tree check: expected record_type or union_type
or qual_union_type, have integer_type in gfc_conv_component_ref, at
fortran/trans-expr.cc:2757
0x84286c tree_check_failed(tree_node const*, char const*, int, char
const*, ...)
  ../../gcc-trunk/gcc/tree.cc:8899
0xa6d6fb tree_check3(tree_node*, char const*, int, char const*,
tree_code, tree_code, tree_code)
  ../../gcc-trunk/gcc/tree.h:3617
0xa90847 gfc_conv_component_ref(gfc_se*, gfc_ref*)
  ../../gcc-trunk/gcc/fortran/trans-expr.cc:2757
0xa91bbc gfc_conv_variable
  ../../gcc-trunk/gcc/fortran/trans-expr.cc:3137
0xaa8e9c gfc_conv_expr(gfc_se*, gfc_expr*)
  ../../gcc-trunk/gcc/fortran/trans-expr.cc:9594
0xaa92ae gfc_conv_expr_reference(gfc_se*, gfc_expr*)
  ../../gcc-trunk/gcc/fortran/trans-expr.cc:9713
0xad67f6 gfc_trans_transfer(gfc_code*)
  ../../gcc-trunk/gcc/fortran/trans-io.cc:2607
0xa43cb7 trans_code
  ../../gcc-trunk/gcc/fortran/trans.cc:2449
0xad37c6 build_dt
  ../../gcc-trunk/gcc/fortran/trans-io.cc:2051
0xa43cd7 trans_code
  ../../gcc-trunk/gcc/fortran/trans.cc:2421
0xa84711 gfc_generate_function_code(gfc_namespace*)
  ../../gcc-trunk/gcc/fortran/trans-decl.cc:7762
0x9d9ca7 translate_all_program_units
  ../../gcc-trunk/gcc/fortran/parse.cc:6929
0x9d9ca7 gfc_parse_file()
  ../../gcc-trunk/gcc/fortran/parse.cc:7235
0xa40a1f gfc_be_parse_file
  ../../gcc-trunk/gcc/fortran/f95-lang.cc:229

The fortran-dump confirms that n is not simplified to a constant.
So while you're at it, do you also see a solution to this variant?

Harald


Am 10.07.23 um 17:48 schrieb Andre Vehreschild via Gcc-patches:

Hi all,

while browsing the pdt meta-bug I came across 102003 and thought to myself:
Well, that one is easy. How foolish of me...

Anyway, the solution attached prevents a pdt_len (or pdt_kind) expression
in a function call (e.g. len() or kind()) to mark the whole expression as a
pdt one. The second part of the patch in simplify.cc then takes care of
either generating the correct component ref or when a constant expression
(i.e. gfc_init_expr_flag is set) is required to look this up from the
actual symbol (not from the type, because there the default value is
stored).

Regtested ok on x86_64-linux-gnu/Fedora 37.

Regards,
Andre
--
Andre Vehreschild * Email: vehre ad gmx dot de





--
Andre Vehreschild * Email: vehre ad gmx dot de




Re: [Patch, Fortran] Allow ref'ing PDT's len() in parameter-initializer [PR102003]

2023-07-11 Thread Harald Anlauf via Fortran

Hi Andre,

I forgot to answer your other question:

Am 11.07.23 um 18:23 schrieb Andre Vehreschild via Gcc-patches:

I tried to use a pdt within a derived type as a component. Is that not allowed
by the standard? I know, I could hunt in the standard for it, but when someone
knows out of his head, he could greatly help me out.


You mean something like the following is rejected with a strange error:

 type pdt(n)
 integer, len :: n = 8
 character(len=n) :: c
  end type pdt
  type t
 type(pdt(42)) :: q
  end type t
  type(t) :: u
end


pr102003.f90:1:10:

1 |   type pdt(n)
  |  1
Error: Cannot convert TYPE(Pdtpdt) to TYPE(pdt) at (1)


ISTR that there is an existing PR...