{
gfc_expr *e;
gfc_ref *ref;
+ gfc_was_finalized *f;
if (!comp_is_finalizable (comp))
return;
- if (expr->finalized)
- return;
+ /* If this expression with this component has been finalized
+ already in this namespace, there is nothing to do. */
+ for (f = sub_ns->was_finalized; f; f = f->next)
+ {
+ if (f->e == expr && f->c == comp)
+ return;
+ }
e = gfc_copy_expr (expr);
if (!e->ref)
sub_ns);
gfc_free_expr (e);
}
- expr->finalized = 1;
+
+ /* Record that this was finalized already in this namespace. */
+ f = sub_ns->was_finalized;
+ sub_ns->was_finalized = XCNEW (gfc_was_finalized);
+ sub_ns->was_finalized->e = expr;
+ sub_ns->was_finalized->c = comp;
+ sub_ns->was_finalized->next = f;
}
#define gfc_get_oacc_routine_name() XCNEW (gfc_oacc_routine_name)
+/* Node in linked list to see what has already been finalized
+ earlier. */
+
+typedef struct gfc_was_finalized {
+ gfc_expr *e;
+ gfc_component *c;
+ struct gfc_was_finalized *next;
+}
+gfc_was_finalized;
+
/* A namespace describes the contents of procedure, module, interface block
or BLOCK construct. */
/* ??? Anything else use these? */
/* Linked list of !$omp declare simd constructs. */
struct gfc_omp_declare_simd *omp_declare_simd;
+ /* A hash set for the the gfc expressions that have already
+ been finalized in this namespace. */
+
+ gfc_was_finalized *was_finalized;
+
/* Set to 1 if namespace is a BLOCK DATA program unit. */
unsigned is_block_data:1;
/* Set this if the expression came from expanding an array constructor. */
unsigned int from_constructor : 1;
- /* Set this if the expression has already been finalized. */
- unsigned int finalized : 1;
-
/* If an expression comes from a Hollerith constant or compile-time
evaluation of a transfer statement, it may have a prescribed target-
memory representation, and these cannot always be backformed from
{
gfc_namespace *p, *q;
int i;
+ gfc_was_finalized *f;
if (ns == NULL)
return;
gfc_free_interface (ns->op[i]);
gfc_free_data (ns->data);
+
+ /* Free all the expr + component combinations that have been
+ finalized. */
+ f = ns->was_finalized;
+ while (f)
+ {
+ gfc_was_finalized* current = f;
+ f = f->next;
+ free (current);
+ }
+
p = ns->contained;
free (ns);
use testmodule
type(evtlist_type), dimension(10) :: a
end program main
-! { dg-final { scan-tree-dump-times "__builtin_free" 12 "original" } }
+! { dg-final { scan-tree-dump-times "__builtin_free" 24 "original" } }
--- /dev/null
+! { dg-do run }
+! { dg-additional-options "-fdump-tree-original" }
+! PR 94109
+! This used to leak memory. Test case by Antony Lewis.
+ module debug
+ implicit none
+
+ Type Tester
+ real, dimension(:), allocatable :: Dat, Dat2
+ end Type
+
+ Type TestType2
+ Type(Tester) :: T
+ end type TestType2
+
+ contains
+
+ subroutine Leaker
+ class(TestType2), pointer :: ActiveState
+ Type(Tester) :: Temp
+
+ allocate(Temp%Dat2(10000))
+
+ allocate(TestType2::ActiveState)
+ ActiveState%T = Temp
+ deallocate(ActiveState)
+
+ end subroutine
+
+ end module
+
+
+ program run
+ use debug
+
+ call Leaker()
+
+ end program
+! { dg-final { scan-tree-dump-times "__builtin_free\\ \\(ptr2" 4 "original" } }