Le 05/07/2023 à 22:36, Harald Anlauf a écrit :
Hi Mikael,
Am 05.07.23 um 16:54 schrieb Mikael Morin:
Here is an example, admittedly artificial. Fails with the above change,
but fails with master as well.
program p
implicit none
type t
integer :: i
end type t
type u
class(t), allocatable :: ta(:)
end type u
type(u), allocatable, target :: c(:)
c = [u([t(1), t(3)]), u([t(4), t(9)])]
call bar (allocated (c(c(1)%ta(1)%i)%ta), c(c(1)%ta(1)%i)%ta,
allocated (c(c(1)%ta(1)%i)%ta))
if (allocated(c(1)%ta)) stop 11
if (.not. allocated(c(2)%ta)) stop 12
contains
subroutine bar (alloc, x, alloc2)
logical :: alloc, alloc2
class(t), allocatable, intent(out) :: x(:)
if (allocated (x)) stop 1
if (.not. alloc) stop 2
if (.not. alloc2) stop 3
end subroutine bar
end
while it looks artificial, it is valid, and IMHO it is a beast...
I've played around and added another argument gfc_se *convse to
gfc_conv_class_to_class in an attempt to implement what I thought
you suggested (to get the .pre/.post separately), but in the end
this did not lead to working code. And the tree-dump for your
example above is beyond what I can grasp.
I've noticed that my attempt does not properly handle the
parmse.post; at least this is what the above example shows:
there is a small part after the call to bar that should have
been executed before that call, which I attribute to .post.
But my attempts in moving that part regresses on a couple
of testcases with class and intent(out). I am at a loss now.
All that I can see after the call is a reassignment of the original data
and vptr pointers from the temporary class container. They seem at
their right place there. But part of the expression seems to be
evaluated again, instead of being picked up from parmse.expr.
I am attaching the latest version of my patch to give you or
Paul or others the opportunity to see what is wrong or add the
missing pieces.
I'm attaching what I have (lightly) tested so far, which doesn't work.
It seems gfc_conv_class_to_class reevaluates part of the original
expression, which is not correct after deallocation.
Will have a look again tonight.
Mikael
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index ebef1a36577..54249c9c615 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -6819,9 +6819,13 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
defer_to_dealloc_blk = true;
}
+ gfc_se class_se = parmse;
+ gfc_init_block (&class_se.pre);
+ gfc_init_block (&class_se.post);
+
/* The conversion does not repackage the reference to a class
array - _data descriptor. */
- gfc_conv_class_to_class (&parmse, e, fsym->ts, false,
+ 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),
@@ -6831,9 +6835,10 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
CLASS_DATA (fsym)->attr.class_pointer
|| CLASS_DATA (fsym)->attr.allocatable);
- /* Defer repackaging after deallocation. */
- if (defer_to_dealloc_blk)
- gfc_add_block_to_block (&dealloc_blk, &parmse.pre);
+ 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);
}
else
{