{
tree efield;
- /* Evaluate arguments just once. */
- if (e->expr_type != EXPR_VARIABLE)
- parmse.expr = save_expr (parmse.expr);
+ /* Evaluate arguments just once, when they have
+ side effects. */
+ if (TREE_SIDE_EFFECTS (parmse.expr))
+ {
+ tree cldata, zero;
+
+ parmse.expr = gfc_evaluate_now (parmse.expr,
+ &parmse.pre);
+
+ /* Prevent memory leak, when old component
+ was allocated already. */
+ cldata = gfc_class_data_get (parmse.expr);
+ zero = build_int_cst (TREE_TYPE (cldata),
+ 0);
+ tmp = fold_build2_loc (input_location, NE_EXPR,
+ logical_type_node,
+ cldata, zero);
+ tmp = build3_v (COND_EXPR, tmp,
+ gfc_call_free (cldata),
+ build_empty_stmt (
+ input_location));
+ gfc_add_expr_to_block (&parmse.finalblock,
+ tmp);
+ gfc_add_modify (&parmse.finalblock,
+ cldata, zero);
+ }
/* Set the _data field. */
tmp = gfc_class_data_get (var);
--- /dev/null
+! { dg-do compile }
+! { dg-additional-options "-fdump-tree-original" }
+!
+! PR fortran/90069
+!
+! Contributed by Brad Richardson <everythingfunctional@protonmail.com>
+!
+
+program returned_memory_leak
+ implicit none
+
+ type, abstract :: base
+ end type base
+
+ type, extends(base) :: extended
+ end type extended
+
+ type :: container
+ class(*), allocatable :: thing
+ end type
+
+ call run()
+contains
+ subroutine run()
+ type(container) :: a_container
+
+ a_container = theRightWay()
+ a_container = theWrongWay()
+ end subroutine
+
+ function theRightWay()
+ type(container) :: theRightWay
+
+ class(base), allocatable :: thing
+
+ allocate(thing, source = newAbstract())
+ theRightWay = newContainer(thing)
+ end function theRightWay
+
+ function theWrongWay()
+ type(container) :: theWrongWay
+
+ theWrongWay = newContainer(newAbstract())
+ end function theWrongWay
+
+ function newAbstract()
+ class(base), allocatable :: newAbstract
+
+ allocate(newAbstract, source = newExtended())
+ end function newAbstract
+
+ function newExtended()
+ type(extended) :: newExtended
+ end function newExtended
+
+ function newContainer(thing)
+ class(*), intent(in) :: thing
+ type(container) :: newContainer
+
+ allocate(newContainer%thing, source = thing)
+ end function newContainer
+end program returned_memory_leak
+
+! { dg-final { scan-tree-dump-times "newabstract" 14 "original" } }
+! { dg-final { scan-tree-dump-times "__builtin_free" 8 "original" } }
+