mirror of git://gcc.gnu.org/git/gcc.git
Fix PR61831: Side-effect variable component deallocation
gcc/fortran/ 2015-07-17 Mikael Morin <mikael@gcc.gnu.org> Dominique d'Humieres <dominiq@lps.ens.fr> PR fortran/61831 * trans-array.c (gfc_conv_array_parameter): Guard allocatable component deallocation code generation with descriptorless calling convention flag. * trans-expr.c (gfc_conv_expr_reference): Remove allocatable component deallocation code generation from revision 212329. (expr_may_alias_variables): New function. (gfc_conv_procedure_call): New boolean elemental_proc to factor check for procedure elemental-ness. Rename boolean f to nodesc_arg and declare it in the outer scope. Use expr_may_alias_variables, elemental_proc and nodesc_arg to decide whether generate allocatable component deallocation code. (gfc_trans_subarray_assign): Set deep copy flag. gcc/testsuite/ 2015-07-17 Mikael Morin <mikael@gcc.gnu.org> PR fortran/61831 * gfortran.dg/alloc_comp_auto_array_3.f90: Count the number of generated while loops in the tree dump. * gfortran.dg/derived_constructor_comps_6.f90: New file. Co-Authored-By: Dominique d'Humieres <dominiq@lps.ens.fr> From-SVN: r225926
This commit is contained in:
parent
a6c51a1293
commit
0e1f8c6a90
|
|
@ -1,3 +1,20 @@
|
||||||
|
2015-07-17 Mikael Morin <mikael@gcc.gnu.org>
|
||||||
|
Dominique d'Humieres <dominiq@lps.ens.fr>
|
||||||
|
|
||||||
|
PR fortran/61831
|
||||||
|
* trans-array.c (gfc_conv_array_parameter): Guard allocatable
|
||||||
|
component deallocation code generation with descriptorless
|
||||||
|
calling convention flag.
|
||||||
|
* trans-expr.c (gfc_conv_expr_reference): Remove allocatable
|
||||||
|
component deallocation code generation from revision 212329.
|
||||||
|
(expr_may_alias_variables): New function.
|
||||||
|
(gfc_conv_procedure_call): New boolean elemental_proc to factor
|
||||||
|
check for procedure elemental-ness. Rename boolean f to nodesc_arg
|
||||||
|
and declare it in the outer scope. Use expr_may_alias_variables,
|
||||||
|
elemental_proc and nodesc_arg to decide whether generate allocatable
|
||||||
|
component deallocation code.
|
||||||
|
(gfc_trans_subarray_assign): Set deep copy flag.
|
||||||
|
|
||||||
2015-07-16 Steven G. Kargl <kargl@gcc.gnu.org>
|
2015-07-16 Steven G. Kargl <kargl@gcc.gnu.org>
|
||||||
|
|
||||||
PR fortran/66724
|
PR fortran/66724
|
||||||
|
|
|
||||||
|
|
@ -7395,8 +7395,9 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, bool g77,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Deallocate the allocatable components of structures that are
|
/* Deallocate the allocatable components of structures that are
|
||||||
not variable. */
|
not variable, for descriptorless arguments.
|
||||||
if ((expr->ts.type == BT_DERIVED || expr->ts.type == BT_CLASS)
|
Arguments with a descriptor are handled in gfc_conv_procedure_call. */
|
||||||
|
if (g77 && (expr->ts.type == BT_DERIVED || expr->ts.type == BT_CLASS)
|
||||||
&& expr->ts.u.derived->attr.alloc_comp
|
&& expr->ts.u.derived->attr.alloc_comp
|
||||||
&& expr->expr_type != EXPR_VARIABLE)
|
&& expr->expr_type != EXPR_VARIABLE)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -4528,6 +4528,62 @@ conv_arglist_function (gfc_se *se, gfc_expr *expr, const char *name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This function tells whether the middle-end representation of the expression
|
||||||
|
E given as input may point to data otherwise accessible through a variable
|
||||||
|
(sub-)reference.
|
||||||
|
It is assumed that the only expressions that may alias are variables,
|
||||||
|
and array constructors if ARRAY_MAY_ALIAS is true and some of its elements
|
||||||
|
may alias.
|
||||||
|
This function is used to decide whether freeing an expression's allocatable
|
||||||
|
components is safe or should be avoided.
|
||||||
|
|
||||||
|
If ARRAY_MAY_ALIAS is true, an array constructor may alias if some of
|
||||||
|
its elements are copied from a variable. This ARRAY_MAY_ALIAS trick
|
||||||
|
is necessary because for array constructors, aliasing depends on how
|
||||||
|
the array is used:
|
||||||
|
- If E is an array constructor used as argument to an elemental procedure,
|
||||||
|
the array, which is generated through shallow copy by the scalarizer,
|
||||||
|
is used directly and can alias the expressions it was copied from.
|
||||||
|
- If E is an array constructor used as argument to a non-elemental
|
||||||
|
procedure,the scalarizer is used in gfc_conv_expr_descriptor to generate
|
||||||
|
the array as in the previous case, but then that array is used
|
||||||
|
to initialize a new descriptor through deep copy. There is no alias
|
||||||
|
possible in that case.
|
||||||
|
Thus, the ARRAY_MAY_ALIAS flag is necessary to distinguish the two cases
|
||||||
|
above. */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
expr_may_alias_variables (gfc_expr *e, bool array_may_alias)
|
||||||
|
{
|
||||||
|
gfc_constructor *c;
|
||||||
|
|
||||||
|
if (e->expr_type == EXPR_VARIABLE)
|
||||||
|
return true;
|
||||||
|
else if (e->expr_type == EXPR_FUNCTION)
|
||||||
|
{
|
||||||
|
gfc_symbol *proc_ifc = gfc_get_proc_ifc_for_expr (e);
|
||||||
|
|
||||||
|
if ((proc_ifc->result->ts.type == BT_CLASS
|
||||||
|
&& proc_ifc->result->ts.u.derived->attr.is_class
|
||||||
|
&& CLASS_DATA (proc_ifc->result)->attr.class_pointer)
|
||||||
|
|| proc_ifc->result->attr.pointer)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (e->expr_type != EXPR_ARRAY || !array_may_alias)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (c = gfc_constructor_first (e->value.constructor);
|
||||||
|
c; c = gfc_constructor_next (c))
|
||||||
|
if (c->expr
|
||||||
|
&& expr_may_alias_variables (c->expr, array_may_alias))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Generate code for a procedure call. Note can return se->post != NULL.
|
/* Generate code for a procedure call. Note can return se->post != NULL.
|
||||||
If se->direct_byref is set then se->expr contains the return parameter.
|
If se->direct_byref is set then se->expr contains the return parameter.
|
||||||
Return nonzero, if the call has alternate specifiers.
|
Return nonzero, if the call has alternate specifiers.
|
||||||
|
|
@ -4580,9 +4636,15 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
|
||||||
|
|
||||||
comp = gfc_get_proc_ptr_comp (expr);
|
comp = gfc_get_proc_ptr_comp (expr);
|
||||||
|
|
||||||
|
bool elemental_proc = (comp
|
||||||
|
&& comp->ts.interface
|
||||||
|
&& comp->ts.interface->attr.elemental)
|
||||||
|
|| (comp && comp->attr.elemental)
|
||||||
|
|| sym->attr.elemental;
|
||||||
|
|
||||||
if (se->ss != NULL)
|
if (se->ss != NULL)
|
||||||
{
|
{
|
||||||
if (!sym->attr.elemental && !(comp && comp->attr.elemental))
|
if (!elemental_proc)
|
||||||
{
|
{
|
||||||
gcc_assert (se->ss->info->type == GFC_SS_FUNCTION);
|
gcc_assert (se->ss->info->type == GFC_SS_FUNCTION);
|
||||||
if (se->ss->info->useflags)
|
if (se->ss->info->useflags)
|
||||||
|
|
@ -4639,6 +4701,23 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
|
||||||
fsym = formal ? formal->sym : NULL;
|
fsym = formal ? formal->sym : NULL;
|
||||||
parm_kind = MISSING;
|
parm_kind = MISSING;
|
||||||
|
|
||||||
|
/* If the procedure requires an explicit interface, the actual
|
||||||
|
argument is passed according to the corresponding formal
|
||||||
|
argument. If the corresponding formal argument is a POINTER,
|
||||||
|
ALLOCATABLE or assumed shape, we do not use g77's calling
|
||||||
|
convention, and pass the address of the array descriptor
|
||||||
|
instead. Otherwise we use g77's calling convention, in other words
|
||||||
|
pass the array data pointer without descriptor. */
|
||||||
|
bool nodesc_arg = fsym != NULL
|
||||||
|
&& !(fsym->attr.pointer || fsym->attr.allocatable)
|
||||||
|
&& fsym->as
|
||||||
|
&& fsym->as->type != AS_ASSUMED_SHAPE
|
||||||
|
&& fsym->as->type != AS_ASSUMED_RANK;
|
||||||
|
if (comp)
|
||||||
|
nodesc_arg = nodesc_arg || !comp->attr.always_explicit;
|
||||||
|
else
|
||||||
|
nodesc_arg = nodesc_arg || !sym->attr.always_explicit;
|
||||||
|
|
||||||
/* Class array expressions are sometimes coming completely unadorned
|
/* Class array expressions are sometimes coming completely unadorned
|
||||||
with either arrayspec or _data component. Correct that here.
|
with either arrayspec or _data component. Correct that here.
|
||||||
OOP-TODO: Move this to the frontend. */
|
OOP-TODO: Move this to the frontend. */
|
||||||
|
|
@ -5165,22 +5244,6 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* If the procedure requires an explicit interface, the actual
|
|
||||||
argument is passed according to the corresponding formal
|
|
||||||
argument. If the corresponding formal argument is a POINTER,
|
|
||||||
ALLOCATABLE or assumed shape, we do not use g77's calling
|
|
||||||
convention, and pass the address of the array descriptor
|
|
||||||
instead. Otherwise we use g77's calling convention. */
|
|
||||||
bool f;
|
|
||||||
f = (fsym != NULL)
|
|
||||||
&& !(fsym->attr.pointer || fsym->attr.allocatable)
|
|
||||||
&& fsym->as && fsym->as->type != AS_ASSUMED_SHAPE
|
|
||||||
&& fsym->as->type != AS_ASSUMED_RANK;
|
|
||||||
if (comp)
|
|
||||||
f = f || !comp->attr.always_explicit;
|
|
||||||
else
|
|
||||||
f = f || !sym->attr.always_explicit;
|
|
||||||
|
|
||||||
/* If the argument is a function call that may not create
|
/* If the argument is a function call that may not create
|
||||||
a temporary for the result, we have to check that we
|
a temporary for the result, we have to check that we
|
||||||
can do it, i.e. that there is no alias between this
|
can do it, i.e. that there is no alias between this
|
||||||
|
|
@ -5225,7 +5288,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
|
||||||
array of derived types. In this case, the argument
|
array of derived types. In this case, the argument
|
||||||
is converted to a temporary, which is passed and then
|
is converted to a temporary, which is passed and then
|
||||||
written back after the procedure call. */
|
written back after the procedure call. */
|
||||||
gfc_conv_subref_array_arg (&parmse, e, f,
|
gfc_conv_subref_array_arg (&parmse, e, nodesc_arg,
|
||||||
fsym ? fsym->attr.intent : INTENT_INOUT,
|
fsym ? fsym->attr.intent : INTENT_INOUT,
|
||||||
fsym && fsym->attr.pointer);
|
fsym && fsym->attr.pointer);
|
||||||
else if (gfc_is_class_array_ref (e, NULL)
|
else if (gfc_is_class_array_ref (e, NULL)
|
||||||
|
|
@ -5237,7 +5300,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
|
||||||
OOP-TODO: Insert code so that if the dynamic type is
|
OOP-TODO: Insert code so that if the dynamic type is
|
||||||
the same as the declared type, copy-in/copy-out does
|
the same as the declared type, copy-in/copy-out does
|
||||||
not occur. */
|
not occur. */
|
||||||
gfc_conv_subref_array_arg (&parmse, e, f,
|
gfc_conv_subref_array_arg (&parmse, e, nodesc_arg,
|
||||||
fsym ? fsym->attr.intent : INTENT_INOUT,
|
fsym ? fsym->attr.intent : INTENT_INOUT,
|
||||||
fsym && fsym->attr.pointer);
|
fsym && fsym->attr.pointer);
|
||||||
|
|
||||||
|
|
@ -5248,12 +5311,13 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
|
||||||
intent in. */
|
intent in. */
|
||||||
{
|
{
|
||||||
e->must_finalize = 1;
|
e->must_finalize = 1;
|
||||||
gfc_conv_subref_array_arg (&parmse, e, f,
|
gfc_conv_subref_array_arg (&parmse, e, nodesc_arg,
|
||||||
INTENT_IN,
|
INTENT_IN,
|
||||||
fsym && fsym->attr.pointer);
|
fsym && fsym->attr.pointer);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
gfc_conv_array_parameter (&parmse, e, f, fsym, sym->name, NULL);
|
gfc_conv_array_parameter (&parmse, e, nodesc_arg, fsym,
|
||||||
|
sym->name, NULL);
|
||||||
|
|
||||||
/* If an ALLOCATABLE dummy argument has INTENT(OUT) and is
|
/* If an ALLOCATABLE dummy argument has INTENT(OUT) and is
|
||||||
allocated on entry, it must be deallocated. */
|
allocated on entry, it must be deallocated. */
|
||||||
|
|
@ -5295,7 +5359,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
|
||||||
but do not always set fsym. */
|
but do not always set fsym. */
|
||||||
if (e->expr_type == EXPR_VARIABLE
|
if (e->expr_type == EXPR_VARIABLE
|
||||||
&& e->symtree->n.sym->attr.optional
|
&& e->symtree->n.sym->attr.optional
|
||||||
&& ((e->rank != 0 && sym->attr.elemental)
|
&& ((e->rank != 0 && elemental_proc)
|
||||||
|| e->representation.length || e->ts.type == BT_CHARACTER
|
|| e->representation.length || e->ts.type == BT_CHARACTER
|
||||||
|| (e->rank != 0
|
|| (e->rank != 0
|
||||||
&& (fsym == NULL
|
&& (fsym == NULL
|
||||||
|
|
@ -5330,12 +5394,15 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
|
||||||
gfc_add_block_to_block (&post, &parmse.post);
|
gfc_add_block_to_block (&post, &parmse.post);
|
||||||
|
|
||||||
/* Allocated allocatable components of derived types must be
|
/* Allocated allocatable components of derived types must be
|
||||||
deallocated for non-variable scalars. Non-variable arrays are
|
deallocated for non-variable scalars, array arguments to elemental
|
||||||
dealt with in trans-array.c(gfc_conv_array_parameter). */
|
procedures, and array arguments with descriptor to non-elemental
|
||||||
|
procedures. As bounds information for descriptorless arrays is no
|
||||||
|
longer available here, they are dealt with in trans-array.c
|
||||||
|
(gfc_conv_array_parameter). */
|
||||||
if (e && (e->ts.type == BT_DERIVED || e->ts.type == BT_CLASS)
|
if (e && (e->ts.type == BT_DERIVED || e->ts.type == BT_CLASS)
|
||||||
&& e->ts.u.derived->attr.alloc_comp
|
&& e->ts.u.derived->attr.alloc_comp
|
||||||
&& !(e->symtree && e->symtree->n.sym->attr.pointer)
|
&& (e->rank == 0 || elemental_proc || !nodesc_arg)
|
||||||
&& e->expr_type != EXPR_VARIABLE && !e->rank)
|
&& !expr_may_alias_variables (e, elemental_proc))
|
||||||
{
|
{
|
||||||
int parm_rank;
|
int parm_rank;
|
||||||
/* It is known the e returns a structure type with at least one
|
/* It is known the e returns a structure type with at least one
|
||||||
|
|
@ -6674,7 +6741,7 @@ gfc_trans_subarray_assign (tree dest, gfc_component * cm, gfc_expr * expr)
|
||||||
|
|
||||||
gfc_conv_expr (&rse, expr);
|
gfc_conv_expr (&rse, expr);
|
||||||
|
|
||||||
tmp = gfc_trans_scalar_assign (&lse, &rse, cm->ts, true, false, true);
|
tmp = gfc_trans_scalar_assign (&lse, &rse, cm->ts, true, true, true);
|
||||||
gfc_add_expr_to_block (&body, tmp);
|
gfc_add_expr_to_block (&body, tmp);
|
||||||
|
|
||||||
gcc_assert (rse.ss == gfc_ss_terminator);
|
gcc_assert (rse.ss == gfc_ss_terminator);
|
||||||
|
|
@ -7545,20 +7612,6 @@ gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr)
|
||||||
|
|
||||||
/* Take the address of that value. */
|
/* Take the address of that value. */
|
||||||
se->expr = gfc_build_addr_expr (NULL_TREE, var);
|
se->expr = gfc_build_addr_expr (NULL_TREE, var);
|
||||||
if (expr->ts.type == BT_DERIVED && expr->rank
|
|
||||||
&& !gfc_is_finalizable (expr->ts.u.derived, NULL)
|
|
||||||
&& expr->ts.u.derived->attr.alloc_comp
|
|
||||||
&& expr->expr_type != EXPR_VARIABLE)
|
|
||||||
{
|
|
||||||
tree tmp;
|
|
||||||
|
|
||||||
tmp = build_fold_indirect_ref_loc (input_location, se->expr);
|
|
||||||
tmp = gfc_deallocate_alloc_comp (expr->ts.u.derived, tmp, expr->rank);
|
|
||||||
|
|
||||||
/* The components shall be deallocated before
|
|
||||||
their containing entity. */
|
|
||||||
gfc_prepend_expr_to_block (&se->post, tmp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,10 @@
|
||||||
|
2015-07-17 Mikael Morin <mikael@gcc.gnu.org>
|
||||||
|
|
||||||
|
PR fortran/61831
|
||||||
|
* gfortran.dg/alloc_comp_auto_array_3.f90: Count the number
|
||||||
|
of generated while loops in the tree dump.
|
||||||
|
* gfortran.dg/derived_constructor_components_6.f90: New file.
|
||||||
|
|
||||||
2015-07-17 Yuri Rumyantsev <ysrumyan@gmail.com>
|
2015-07-17 Yuri Rumyantsev <ysrumyan@gmail.com>
|
||||||
|
|
||||||
* gcc.dg/vect/vect-outer-simd-2.c: New test.
|
* gcc.dg/vect/vect-outer-simd-2.c: New test.
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,4 @@ contains
|
||||||
end
|
end
|
||||||
! { dg-final { scan-tree-dump-times "builtin_malloc" 3 "original" } }
|
! { dg-final { scan-tree-dump-times "builtin_malloc" 3 "original" } }
|
||||||
! { dg-final { scan-tree-dump-times "builtin_free" 4 "original" } }
|
! { dg-final { scan-tree-dump-times "builtin_free" 4 "original" } }
|
||||||
|
! { dg-final { scan-tree-dump-times "while \\(1\\)" 4 "original" } }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,133 @@
|
||||||
|
! { dg-do run }
|
||||||
|
! { dg-additional-options "-fsanitize=address -fdump-tree-original"
|
||||||
|
!
|
||||||
|
! PR fortran/61831
|
||||||
|
! The deallocation of components of array constructor elements
|
||||||
|
! used to have the side effect of also deallocating some other
|
||||||
|
! variable's components from which they were copied.
|
||||||
|
|
||||||
|
program main
|
||||||
|
implicit none
|
||||||
|
|
||||||
|
integer, parameter :: n = 2
|
||||||
|
|
||||||
|
type :: string_t
|
||||||
|
character(LEN=1), dimension(:), allocatable :: chars
|
||||||
|
end type string_t
|
||||||
|
|
||||||
|
type :: string_container_t
|
||||||
|
type(string_t) :: comp
|
||||||
|
end type string_container_t
|
||||||
|
|
||||||
|
type :: string_array_container_t
|
||||||
|
type(string_t) :: comp(n)
|
||||||
|
end type string_array_container_t
|
||||||
|
|
||||||
|
type(string_t) :: prt_in, tmp, tmpa(n)
|
||||||
|
type(string_container_t) :: tmpc, tmpca(n)
|
||||||
|
type(string_array_container_t) :: tmpac, tmpaca(n)
|
||||||
|
integer :: i, j, k
|
||||||
|
|
||||||
|
do i=1,16
|
||||||
|
|
||||||
|
! Test without intermediary function
|
||||||
|
prt_in = string_t(["A"])
|
||||||
|
if (.not. allocated(prt_in%chars)) call abort
|
||||||
|
if (any(prt_in%chars .ne. "A")) call abort
|
||||||
|
deallocate (prt_in%chars)
|
||||||
|
|
||||||
|
! scalar elemental function
|
||||||
|
prt_in = string_t(["B"])
|
||||||
|
if (.not. allocated(prt_in%chars)) call abort
|
||||||
|
if (any(prt_in%chars .ne. "B")) call abort
|
||||||
|
tmp = new_prt_spec (prt_in)
|
||||||
|
if (.not. allocated(prt_in%chars)) call abort
|
||||||
|
if (any(prt_in%chars .ne. "B")) call abort
|
||||||
|
deallocate (prt_in%chars)
|
||||||
|
deallocate (tmp%chars)
|
||||||
|
|
||||||
|
! array elemental function with array constructor
|
||||||
|
prt_in = string_t(["C"])
|
||||||
|
if (.not. allocated(prt_in%chars)) call abort
|
||||||
|
if (any(prt_in%chars .ne. "C")) call abort
|
||||||
|
tmpa = new_prt_spec ([(prt_in, i=1,2)])
|
||||||
|
if (.not. allocated(prt_in%chars)) call abort
|
||||||
|
if (any(prt_in%chars .ne. "C")) call abort
|
||||||
|
deallocate (prt_in%chars)
|
||||||
|
do j=1,n
|
||||||
|
deallocate (tmpa(j)%chars)
|
||||||
|
end do
|
||||||
|
|
||||||
|
! scalar elemental function with structure constructor
|
||||||
|
prt_in = string_t(["D"])
|
||||||
|
if (.not. allocated(prt_in%chars)) call abort
|
||||||
|
if (any(prt_in%chars .ne. "D")) call abort
|
||||||
|
tmpc = new_prt_spec2 (string_container_t(prt_in))
|
||||||
|
if (.not. allocated(prt_in%chars)) call abort
|
||||||
|
if (any(prt_in%chars .ne. "D")) call abort
|
||||||
|
deallocate (prt_in%chars)
|
||||||
|
deallocate(tmpc%comp%chars)
|
||||||
|
|
||||||
|
! array elemental function of an array constructor of structure constructors
|
||||||
|
prt_in = string_t(["E"])
|
||||||
|
if (.not. allocated(prt_in%chars)) call abort
|
||||||
|
if (any(prt_in%chars .ne. "E")) call abort
|
||||||
|
tmpca = new_prt_spec2 ([ (string_container_t(prt_in), i=1,2) ])
|
||||||
|
if (.not. allocated(prt_in%chars)) call abort
|
||||||
|
if (any(prt_in%chars .ne. "E")) call abort
|
||||||
|
deallocate (prt_in%chars)
|
||||||
|
do j=1,n
|
||||||
|
deallocate (tmpca(j)%comp%chars)
|
||||||
|
end do
|
||||||
|
|
||||||
|
! scalar elemental function with a structure constructor and a nested array constructor
|
||||||
|
prt_in = string_t(["F"])
|
||||||
|
if (.not. allocated(prt_in%chars)) call abort
|
||||||
|
if (any(prt_in%chars .ne. "F")) call abort
|
||||||
|
tmpac = new_prt_spec3 (string_array_container_t([ (prt_in, i=1,2) ]))
|
||||||
|
if (.not. allocated(prt_in%chars)) call abort
|
||||||
|
if (any(prt_in%chars .ne. "F")) call abort
|
||||||
|
deallocate (prt_in%chars)
|
||||||
|
do j=1,n
|
||||||
|
deallocate (tmpac%comp(j)%chars)
|
||||||
|
end do
|
||||||
|
|
||||||
|
! array elemental function with an array constructor nested inside
|
||||||
|
! a structure constructor nested inside an array constructor
|
||||||
|
prt_in = string_t(["G"])
|
||||||
|
if (.not. allocated(prt_in%chars)) call abort
|
||||||
|
if (any(prt_in%chars .ne. "G")) call abort
|
||||||
|
tmpaca = new_prt_spec3 ([ (string_array_container_t([ (prt_in, i=1,2) ]), j=1,2) ])
|
||||||
|
if (.not. allocated(prt_in%chars)) call abort
|
||||||
|
if (any(prt_in%chars .ne. "G")) call abort
|
||||||
|
deallocate (prt_in%chars)
|
||||||
|
do j=1,n
|
||||||
|
do k=1,n
|
||||||
|
deallocate (tmpaca(j)%comp(k)%chars)
|
||||||
|
end do
|
||||||
|
end do
|
||||||
|
|
||||||
|
end do
|
||||||
|
|
||||||
|
contains
|
||||||
|
|
||||||
|
elemental function new_prt_spec (name) result (prt_spec)
|
||||||
|
type(string_t), intent(in) :: name
|
||||||
|
type(string_t) :: prt_spec
|
||||||
|
prt_spec = name
|
||||||
|
end function new_prt_spec
|
||||||
|
|
||||||
|
elemental function new_prt_spec2 (name) result (prt_spec)
|
||||||
|
type(string_container_t), intent(in) :: name
|
||||||
|
type(string_container_t) :: prt_spec
|
||||||
|
prt_spec = name
|
||||||
|
end function new_prt_spec2
|
||||||
|
|
||||||
|
elemental function new_prt_spec3 (name) result (prt_spec)
|
||||||
|
type(string_array_container_t), intent(in) :: name
|
||||||
|
type(string_array_container_t) :: prt_spec
|
||||||
|
prt_spec = name
|
||||||
|
end function new_prt_spec3
|
||||||
|
end program main
|
||||||
|
! { dg-final { scan-tree-dump-times "__builtin_malloc" 15 "original" } }
|
||||||
|
! { dg-final { scan-tree-dump-times "__builtin_free" 33 "original" } }
|
||||||
Loading…
Reference in New Issue