https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125427
Jerry DeLisle <jvdelisle at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |jvdelisle at gcc dot gnu.org
--- Comment #1 from Jerry DeLisle <jvdelisle at gcc dot gnu.org> ---
Here is a draft patch. It appears to fix pr125428 as well.
diff --git a/gcc/fortran/trans.cc b/gcc/fortran/trans.cc
index c366d7f4dbf..90a88cd0b05 100644
--- a/gcc/fortran/trans.cc
+++ b/gcc/fortran/trans.cc
@@ -1546,7 +1546,56 @@ gfc_assignment_finalizer_call (gfc_se *lse, gfc_expr
*expr1, bool init_flag)
return false;
gfc_init_block (&final_block);
- bool finalizable = gfc_add_finalizer_call (&final_block, finalize_expr);
+ bool finalizable;
+
+ /* When the LHS has already been evaluated (lse->expr is set) and is a
+ scalar finalizable derived-type element, build the finalization call
+ directly from lse->expr rather than re-evaluating finalize_expr.
+ Re-evaluation would execute side-effect-bearing subscript expressions
+ (e.g. function calls) a second time, violating F2018 10.2.1.2 which
+ requires each subscript expression to be evaluated only once.
+ PR fortran/125427. */
+ if (lse->expr != NULL_TREE && expr1->rank == 0
+ && expr1->ts.type == BT_DERIVED)
+ {
+ /* Evaluate the element address once if lse->expr still has side
+ effects, so that both finalization and the subsequent assignment
+ reference the same pre-computed element. */
+ if (TREE_SIDE_EFFECTS (lse->expr))
+ {
+ tree ptr = gfc_build_addr_expr (NULL_TREE, lse->expr);
+ ptr = gfc_evaluate_now (ptr, &lse->pre);
+ lse->expr = build_fold_indirect_ref_loc (input_location, ptr);
+ }
+
+ gfc_se fin_se, size_se, desc_se;
+ gfc_init_se (&fin_se, NULL);
+ get_final_proc_ref (&fin_se, finalize_expr, NULL_TREE);
+ gfc_add_block_to_block (&final_block, &fin_se.pre);
+
+ gfc_init_se (&size_se, NULL);
+ get_elem_size (&size_se, finalize_expr, NULL_TREE);
+ gfc_add_block_to_block (&final_block, &size_se.pre);
+
+ gfc_init_se (&desc_se, NULL);
+ symbol_attribute attr;
+ gfc_clear_attr (&attr);
+ tree desc = gfc_conv_scalar_to_descriptor (&desc_se, lse->expr, attr);
+ gfc_add_block_to_block (&final_block, &desc_se.pre);
+ if (!POINTER_TYPE_P (TREE_TYPE (desc)))
+ desc = gfc_build_addr_expr (NULL_TREE, desc);
+
+ tree fcall = build_call_expr_loc (input_location, fin_se.expr, 3,
+ desc, size_se.expr,
+ boolean_false_node);
+ gfc_add_expr_to_block (&final_block, fcall);
+ gfc_add_block_to_block (&final_block, &desc_se.post);
+ gfc_add_block_to_block (&final_block, &size_se.post);
+ finalizable = true;
+ }
+ else
+ finalizable = gfc_add_finalizer_call (&final_block, finalize_expr);
+
gfc_free_expr (finalize_expr);
if (!finalizable)