diff options
author | Paul Thomas <pault@gcc.gnu.org> | 2006-10-08 16:21:55 +0000 |
---|---|---|
committer | Paul Thomas <pault@gcc.gnu.org> | 2006-10-08 16:21:55 +0000 |
commit | 5046aff56bbd9b2911799ad1e26b7c538fcc513e (patch) | |
tree | fdb6be945aa00dac05524839d5b40aa79575f789 /gcc/fortran/trans-array.c | |
parent | 4afa41f130aad8e6b78d825b99abcd0b36faa0c4 (diff) | |
download | gcc-5046aff56bbd9b2911799ad1e26b7c538fcc513e.zip gcc-5046aff56bbd9b2911799ad1e26b7c538fcc513e.tar.gz gcc-5046aff56bbd9b2911799ad1e26b7c538fcc513e.tar.bz2 |
[multiple changes]
2006-10-05 Erik Edelmann <edelmann@gcc.gnu.org>
Paul Thomas <pault@gcc.gnu.org>
PR fortran/20541
* interface.c (gfc_compare_derived_types): Add comparison of
the allocatable field.
* intrinsic.c (add_subroutines): Add MOVE_ALLOC.
* trans-expr.c (gfc_conv_aliased_arg, gfc_trans_subarray_assign,
gfc_trans_subcomponent_assign, gfc_conv_string_parameter,
gfc_trans_scalar_assign): Add extra arguments l_is_temp
and r_is_var to references to latter function.
(gfc_conv_function_call): Add enum for types of argument and
an associated variable parm_kind. Deallocate components of
INTENT(OUT) and non-variable arrays.
(gfc_trans_subcomponent_assign): Add block to assign arrays
to allocatable components.
(gfc_trans_scalar_assign): Add block to handle assignments of
derived types with allocatable components, using the above new
arguments to control allocation/deallocation of memory and the
copying of allocated arrays.
* trans-array.c (gfc_array_allocate): Remove old identification
of pointer and replace with that of an allocatable array. Add
nullify of structures with allocatable components.
(gfc_conv_array_initializer): Treat EXPR_NULL.
(gfc_conv_array_parameter): Deallocate allocatable components
of non-variable structures.
(gfc_trans_dealloc_allocated): Use second argument of library
deallocate to inhibit, without error, freeing NULL pointers.
(get_full_array_size): New function to return the size of a
full array.
(gfc_duplicate_allocatable): New function to allocate and copy
allocated data.
(structure_alloc_comps): New recursive function to deallocate,
nullify or copy allocatable components.
(gfc_nullify_alloc_comp, gfc_deallocate_alloc_comp,
gfc_copy_alloc_comp): New interface functions to call previous.
(gfc_trans_deferred_array): Add the code to nullify allocatable
components, when entering scope, and to deallocate them on
leaving. Do not call gfc_trans_static_array_pointer and return
for structures with allocatable components and default
initializers.
* symbol.c (gfc_set_component_attr): Set allocatable field.
(gfc_get_component_attr): Set the allocatable attribute.
* intrinsic.h : Prototype for gfc_check_move_alloc.
* decl.c (build_struct): Apply TR15581 constraints for
allocatable components.
(variable_decl): Default initializer is always NULL for
allocatable components.
(match_attr_spec): Allow, or not, allocatable components,
according to the standard in force.
* trans-array.h : Prototypes for gfc_nullify_alloc_comp,
gfc_deallocate_alloc_comp, gfc_copy_alloc_comp and
gfc_duplicate_allocatable.
* gfortran.texi : Add mention of TR15581 extensions.
* gfortran.h : Add attribute alloc_comp, add
gfc_components field allocatable and add the prototype
for gfc_expr_to_initialize.
* trans-stmt.c (generate_loop_for_temp_to_lhs,
generate_loop_for_rhs_to_temp, gfc_trans_where_assign,
gfc_trans_where_3): Add extra arguments to calls to
gfc_trans_scalar_assign and set appropriately.
(gfc_trans_allocate): Nullify allocatable components.
(gfc_trans_deallocate): Deallocate to ultimate allocatable
components but stop at ultimate pointer components.
* module.c (mio_symbol_attribute, mio_symbol_attribute,
mio_component): Add module support for allocatable
components.
* trans-types.c (gfc_get_derived_type): Treat allocatable
components.
* trans.h : Add two boolean arguments to
gfc_trans_scalar_assign.
* resolve.c (resolve_structure_cons): Check conformance of
constructor element and the component.
(resolve_allocate_expr): Add expression to nullify the
constructor expression for allocatable components.
(resolve_transfer): Inhibit I/O of derived types with
allocatable components.
(resolve_fl_derived): Skip check of bounds of allocatable
components.
* trans-decl.c (gfc_get_symbol_decl): Add derived types
with allocatable components to deferred variable.
(gfc_trans_deferred_vars): Make calls for derived types
with allocatable components to gfc_trans_deferred_array.
(gfc_generate_function_code): Nullify allocatable
component function result on entry.
* parse.c (parse_derived): Set symbol attr.allocatable if
allocatable components are present.
* check.c (gfc_check_allocated): Enforce attr.allocatable
for intrinsic arguments.
(gfc_check_move_alloc): Check arguments of move_alloc.
* primary.c (gfc_variable_attr): Set allocatable attribute.
* intrinsic.texi : Add index entry and section for
for move_alloc.
PR fortran/29115
* resolve.c (resolve_structure_cons): It is an error if the
pointer component elements of a derived type constructor are
not pointer or target.
PR fortran/29211
* trans-stmt.c (generate_loop_for_temp_to_lhs,
generate_loop_for_rhs_to_temp): Provide a string length for
the temporary by copying that of the other side of the scalar
assignment.
2006-10-05 Paul Thomas <pault@gcc.gnu.org>
Erik Edelmann <edelmann@gcc.gnu.org>
PR libgfortran/20541
* Makefile.in : Add move_alloc.
* intrinsics/move_alloc.c: New function.
* Makefile.am : Add move_alloc.
2006-10-05 Erik Edelmann <edelmann@gcc.gnu.org>
Paul Thomas <pault@gcc.gnu.org>
PR fortran/20541
* gfortran.dg/alloc_comp_basics_1.f90: New test.
* gfortran.dg/alloc_comp_basics_2.f90: New test.
* gfortran.dg/alloc_comp_assign_1.f90: New test.
* gfortran.dg/alloc_comp_assign_2.f90: New test.
* gfortran.dg/alloc_comp_assign_3.f90: New test.
* gfortran.dg/alloc_comp_assign_4.f90: New test.
* gfortran.dg/alloc_comp_constraint_1.f90: New test.
* gfortran.dg/alloc_comp_constraint_2.f90: New test.
* gfortran.dg/alloc_comp_constraint_3.f90: New test.
* gfortran.dg/alloc_comp_constructor_1.f90: New test.
* gfortran.dg/alloc_comp_constructor_2.f90: New test.
* gfortran.dg/alloc_comp_initializer_1.f90: New test.
* gfortran.dg/alloc_comp_std.f90: New test.
* gfortran.dg/move_alloc.f90: New test.
PR fortran/29115
* gfortran.dg/derived_constructor_comps_2.f90: New test.
PR fortran/29211
* gfortran.dg/forall_char_dependencies_1.f90: New test.
From-SVN: r117558
Diffstat (limited to 'gcc/fortran/trans-array.c')
-rw-r--r-- | gcc/fortran/trans-array.c | 408 |
1 files changed, 372 insertions, 36 deletions
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index bf8e687..f4d7ba5 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -3236,32 +3236,27 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree pstat) tree size; gfc_expr **lower; gfc_expr **upper; - gfc_ref *ref; - int allocatable_array; - int must_be_pointer; + gfc_ref *ref, *prev_ref = NULL; + bool allocatable_array; ref = expr->ref; - /* In Fortran 95, components can only contain pointers, so that, - in ALLOCATE (foo%bar(2)), bar must be a pointer component. - We test this by checking for ref->next. - An implementation of TR 15581 would need to change this. */ - - if (ref) - must_be_pointer = ref->next != NULL; - else - must_be_pointer = 0; - /* Find the last reference in the chain. */ while (ref && ref->next != NULL) { gcc_assert (ref->type != REF_ARRAY || ref->u.ar.type == AR_ELEMENT); + prev_ref = ref; ref = ref->next; } if (ref == NULL || ref->type != REF_ARRAY) return false; + if (!prev_ref) + allocatable_array = expr->symtree->n.sym->attr.allocatable; + else + allocatable_array = prev_ref->u.c.component->allocatable; + /* Figure out the size of the array. */ switch (ref->u.ar.type) { @@ -3294,11 +3289,6 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree pstat) tmp = gfc_conv_descriptor_data_addr (se->expr); pointer = gfc_evaluate_now (tmp, &se->pre); - if (must_be_pointer) - allocatable_array = 0; - else - allocatable_array = expr->symtree->n.sym->attr.allocatable; - if (TYPE_PRECISION (gfc_array_index_type) == 32) { if (allocatable_array) @@ -3325,6 +3315,14 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree pstat) tmp = gfc_conv_descriptor_offset (se->expr); gfc_add_modify_expr (&se->pre, tmp, offset); + if (expr->ts.type == BT_DERIVED + && expr->ts.derived->attr.alloc_comp) + { + tmp = gfc_nullify_alloc_comp (expr->ts.derived, se->expr, + ref->u.ar.as->rank); + gfc_add_expr_to_block (&se->pre, tmp); + } + return true; } @@ -3465,6 +3463,9 @@ gfc_conv_array_initializer (tree type, gfc_expr * expr) } break; + case EXPR_NULL: + return gfc_build_null_descriptor (type); + default: gcc_unreachable (); } @@ -4547,6 +4548,17 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, gfc_ss * ss, int g77) se->want_pointer = 1; gfc_conv_expr_descriptor (se, expr, ss); + /* Deallocate the allocatable components of structures that are + not variable. */ + if (expr->ts.type == BT_DERIVED + && expr->ts.derived->attr.alloc_comp + && expr->expr_type != EXPR_VARIABLE) + { + tmp = build_fold_indirect_ref (se->expr); + tmp = gfc_deallocate_alloc_comp (expr->ts.derived, tmp, expr->rank); + gfc_add_expr_to_block (&se->post, tmp); + } + if (g77) { desc = se->expr; @@ -4595,25 +4607,322 @@ tree gfc_trans_dealloc_allocated (tree descriptor) { tree tmp; - tree deallocate; + tree ptr; + tree var; stmtblock_t block; gfc_start_block (&block); - deallocate = gfc_array_deallocate (descriptor, null_pointer_node); - tmp = gfc_conv_descriptor_data_get (descriptor); - tmp = build2 (NE_EXPR, boolean_type_node, tmp, - build_int_cst (TREE_TYPE (tmp), 0)); - tmp = build3_v (COND_EXPR, tmp, deallocate, build_empty_stmt ()); + tmp = gfc_conv_descriptor_data_addr (descriptor); + var = gfc_evaluate_now (tmp, &block); + tmp = gfc_create_var (gfc_array_index_type, NULL); + ptr = build_fold_addr_expr (tmp); + + /* Call array_deallocate with an int* present in the second argument. + Although it is ignored here, it's presence ensures that arrays that + are already deallocated are ignored. */ + tmp = gfc_chainon_list (NULL_TREE, var); + tmp = gfc_chainon_list (tmp, ptr); + tmp = build_function_call_expr (gfor_fndecl_deallocate, tmp); gfc_add_expr_to_block (&block, tmp); + return gfc_finish_block (&block); +} + + +/* This helper function calculates the size in words of a full array. */ + +static tree +get_full_array_size (stmtblock_t *block, tree decl, int rank) +{ + tree idx; + tree nelems; + tree tmp; + idx = gfc_rank_cst[rank - 1]; + nelems = gfc_conv_descriptor_ubound (decl, idx); + tmp = gfc_conv_descriptor_lbound (decl, idx); + tmp = build2 (MINUS_EXPR, gfc_array_index_type, nelems, tmp); + tmp = build2 (PLUS_EXPR, gfc_array_index_type, + tmp, gfc_index_one_node); + tmp = gfc_evaluate_now (tmp, block); + + nelems = gfc_conv_descriptor_stride (decl, idx); + tmp = build2 (MULT_EXPR, gfc_array_index_type, nelems, tmp); + return gfc_evaluate_now (tmp, block); +} + + +/* Allocate dest to the same size as src, and copy src -> dest. */ + +tree +gfc_duplicate_allocatable(tree dest, tree src, tree type, int rank) +{ + tree tmp; + tree size; + tree nelems; + tree args; + tree null_cond; + tree null_data; + stmtblock_t block; + + /* If the source is null, set the destination to null. */ + gfc_init_block (&block); + gfc_conv_descriptor_data_set (&block, dest, null_pointer_node); + null_data = gfc_finish_block (&block); + + gfc_init_block (&block); + + nelems = get_full_array_size (&block, src, rank); + size = fold_build2 (MULT_EXPR, gfc_array_index_type, nelems, + TYPE_SIZE_UNIT (gfc_get_element_type (type))); + /* Allocate memory to the destination. */ + tmp = gfc_chainon_list (NULL_TREE, size); + if (gfc_index_integer_kind == 4) + tmp = build_function_call_expr (gfor_fndecl_internal_malloc, tmp); + else if (gfc_index_integer_kind == 8) + tmp = build_function_call_expr (gfor_fndecl_internal_malloc64, tmp); + else + gcc_unreachable (); + tmp = fold (convert (TREE_TYPE (gfc_conv_descriptor_data_get (src)), + tmp)); + gfc_conv_descriptor_data_set (&block, dest, tmp); + + /* We know the temporary and the value will be the same length, + so can use memcpy. */ + tmp = gfc_conv_descriptor_data_get (dest); + args = gfc_chainon_list (NULL_TREE, tmp); + tmp = gfc_conv_descriptor_data_get (src); + args = gfc_chainon_list (args, tmp); + args = gfc_chainon_list (args, size); + tmp = built_in_decls[BUILT_IN_MEMCPY]; + tmp = build_function_call_expr (tmp, args); + gfc_add_expr_to_block (&block, tmp); tmp = gfc_finish_block (&block); - return tmp; + /* Null the destination if the source is null; otherwise do + the allocate and copy. */ + null_cond = gfc_conv_descriptor_data_get (src); + null_cond = convert (pvoid_type_node, null_cond); + null_cond = build2 (NE_EXPR, boolean_type_node, null_cond, + null_pointer_node); + return build3_v (COND_EXPR, null_cond, tmp, null_data); } -/* NULLIFY an allocatable/pointer array on function entry, free it on exit. */ +/* Recursively traverse an object of derived type, generating code to + deallocate, nullify or copy allocatable components. This is the work horse + function for the functions named in this enum. */ + +enum {DEALLOCATE_ALLOC_COMP = 1, NULLIFY_ALLOC_COMP, COPY_ALLOC_COMP}; + +static tree +structure_alloc_comps (gfc_symbol * der_type, tree decl, + tree dest, int rank, int purpose) +{ + gfc_component *c; + gfc_loopinfo loop; + stmtblock_t fnblock; + stmtblock_t loopbody; + tree tmp; + tree comp; + tree dcmp; + tree nelems; + tree index; + tree var; + tree cdecl; + tree ctype; + tree vref, dref; + tree null_cond = NULL_TREE; + + gfc_init_block (&fnblock); + + /* If this an array of derived types with allocatable components + build a loop and recursively call this function. */ + if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE + || GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl))) + { + tmp = gfc_conv_array_data (decl); + var = build_fold_indirect_ref (tmp); + + /* Get the number of elements - 1 and set the counter. */ + if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (decl))) + { + /* Use the descriptor for an allocatable array. Since this + is a full array reference, we only need the descriptor + information from dimension = rank. */ + tmp = get_full_array_size (&fnblock, decl, rank); + tmp = build2 (MINUS_EXPR, gfc_array_index_type, + tmp, gfc_index_one_node); + + null_cond = gfc_conv_descriptor_data_get (decl); + null_cond = build2 (NE_EXPR, boolean_type_node, null_cond, + build_int_cst (TREE_TYPE (tmp), 0)); + } + else + { + /* Otherwise use the TYPE_DOMAIN information. */ + tmp = array_type_nelts (TREE_TYPE (decl)); + tmp = fold_convert (gfc_array_index_type, tmp); + } + + /* Remember that this is, in fact, the no. of elements - 1. */ + nelems = gfc_evaluate_now (tmp, &fnblock); + index = gfc_create_var (gfc_array_index_type, "S"); + + /* Build the body of the loop. */ + gfc_init_block (&loopbody); + + vref = gfc_build_array_ref (var, index); + + if (purpose == COPY_ALLOC_COMP) + { + tmp = gfc_duplicate_allocatable (dest, decl, TREE_TYPE(decl), rank); + gfc_add_expr_to_block (&fnblock, tmp); + + tmp = build_fold_indirect_ref (gfc_conv_descriptor_data_get (dest)); + dref = gfc_build_array_ref (tmp, index); + tmp = structure_alloc_comps (der_type, vref, dref, rank, purpose); + } + else + tmp = structure_alloc_comps (der_type, vref, NULL_TREE, rank, purpose); + + gfc_add_expr_to_block (&loopbody, tmp); + + /* Build the loop and return. */ + gfc_init_loopinfo (&loop); + loop.dimen = 1; + loop.from[0] = gfc_index_zero_node; + loop.loopvar[0] = index; + loop.to[0] = nelems; + gfc_trans_scalarizing_loops (&loop, &loopbody); + gfc_add_block_to_block (&fnblock, &loop.pre); + + tmp = gfc_finish_block (&fnblock); + if (null_cond != NULL_TREE) + tmp = build3_v (COND_EXPR, null_cond, tmp, build_empty_stmt ()); + + return tmp; + } + + /* Otherwise, act on the components or recursively call self to + act on a chain of components. */ + for (c = der_type->components; c; c = c->next) + { + bool cmp_has_alloc_comps = (c->ts.type == BT_DERIVED) + && c->ts.derived->attr.alloc_comp; + cdecl = c->backend_decl; + ctype = TREE_TYPE (cdecl); + + switch (purpose) + { + case DEALLOCATE_ALLOC_COMP: + /* Do not deallocate the components of ultimate pointer + components. */ + if (cmp_has_alloc_comps && !c->pointer) + { + comp = build3 (COMPONENT_REF, ctype, decl, cdecl, NULL_TREE); + rank = c->as ? c->as->rank : 0; + tmp = structure_alloc_comps (c->ts.derived, comp, NULL_TREE, + rank, purpose); + gfc_add_expr_to_block (&fnblock, tmp); + } + + if (c->allocatable) + { + comp = build3 (COMPONENT_REF, ctype, decl, cdecl, NULL_TREE); + tmp = gfc_trans_dealloc_allocated (comp); + gfc_add_expr_to_block (&fnblock, tmp); + } + break; + + case NULLIFY_ALLOC_COMP: + if (c->pointer) + continue; + else if (c->allocatable) + { + comp = build3 (COMPONENT_REF, ctype, decl, cdecl, NULL_TREE); + gfc_conv_descriptor_data_set (&fnblock, comp, null_pointer_node); + } + else if (cmp_has_alloc_comps) + { + comp = build3 (COMPONENT_REF, ctype, decl, cdecl, NULL_TREE); + rank = c->as ? c->as->rank : 0; + tmp = structure_alloc_comps (c->ts.derived, comp, NULL_TREE, + rank, purpose); + gfc_add_expr_to_block (&fnblock, tmp); + } + break; + + case COPY_ALLOC_COMP: + if (c->pointer) + continue; + + /* We need source and destination components. */ + comp = build3 (COMPONENT_REF, ctype, decl, cdecl, NULL_TREE); + dcmp = build3 (COMPONENT_REF, ctype, dest, cdecl, NULL_TREE); + dcmp = fold_convert (TREE_TYPE (comp), dcmp); + + if (c->allocatable && !cmp_has_alloc_comps) + { + tmp = gfc_duplicate_allocatable(dcmp, comp, ctype, c->as->rank); + gfc_add_expr_to_block (&fnblock, tmp); + } + + if (cmp_has_alloc_comps) + { + rank = c->as ? c->as->rank : 0; + tmp = fold_convert (TREE_TYPE (dcmp), comp); + gfc_add_modify_expr (&fnblock, dcmp, tmp); + tmp = structure_alloc_comps (c->ts.derived, comp, dcmp, + rank, purpose); + gfc_add_expr_to_block (&fnblock, tmp); + } + break; + + default: + gcc_unreachable (); + break; + } + } + + return gfc_finish_block (&fnblock); +} + +/* Recursively traverse an object of derived type, generating code to + nullify allocatable components. */ + +tree +gfc_nullify_alloc_comp (gfc_symbol * der_type, tree decl, int rank) +{ + return structure_alloc_comps (der_type, decl, NULL_TREE, rank, + NULLIFY_ALLOC_COMP); +} + + +/* Recursively traverse an object of derived type, generating code to + deallocate allocatable components. */ + +tree +gfc_deallocate_alloc_comp (gfc_symbol * der_type, tree decl, int rank) +{ + return structure_alloc_comps (der_type, decl, NULL_TREE, rank, + DEALLOCATE_ALLOC_COMP); +} + + +/* Recursively traverse an object of derived type, generating code to + copy its allocatable components. */ + +tree +gfc_copy_alloc_comp (gfc_symbol * der_type, tree decl, tree dest, int rank) +{ + return structure_alloc_comps (der_type, decl, dest, rank, COPY_ALLOC_COMP); +} + + +/* NULLIFY an allocatable/pointer array on function entry, free it on exit. + Do likewise, recursively if necessary, with the allocatable components of + derived types. */ tree gfc_trans_deferred_array (gfc_symbol * sym, tree body) @@ -4623,16 +4932,22 @@ gfc_trans_deferred_array (gfc_symbol * sym, tree body) tree descriptor; stmtblock_t fnblock; locus loc; + int rank; + bool sym_has_alloc_comp; + + sym_has_alloc_comp = (sym->ts.type == BT_DERIVED) + && sym->ts.derived->attr.alloc_comp; /* Make sure the frontend gets these right. */ - if (!(sym->attr.pointer || sym->attr.allocatable)) - fatal_error - ("Possible frontend bug: Deferred array size without pointer or allocatable attribute."); + if (!(sym->attr.pointer || sym->attr.allocatable || sym_has_alloc_comp)) + fatal_error ("Possible frontend bug: Deferred array size without pointer, " + "allocatable attribute or derived type without allocatable " + "components."); gfc_init_block (&fnblock); gcc_assert (TREE_CODE (sym->backend_decl) == VAR_DECL - || TREE_CODE (sym->backend_decl) == PARM_DECL); + || TREE_CODE (sym->backend_decl) == PARM_DECL); if (sym->ts.type == BT_CHARACTER && !INTEGER_CST_P (sym->ts.cl->backend_decl)) @@ -4653,7 +4968,10 @@ gfc_trans_deferred_array (gfc_symbol * sym, tree body) gfc_set_backend_locus (&sym->declared_at); descriptor = sym->backend_decl; - if (TREE_STATIC (descriptor)) + /* Although static, derived types with deafult initializers and + allocatable components must not be nulled wholesale; instead they + are treated component by component. */ + if (TREE_STATIC (descriptor) && !sym_has_alloc_comp) { /* SAVEd variables are not freed on exit. */ gfc_trans_static_array_pointer (sym); @@ -4662,22 +4980,40 @@ gfc_trans_deferred_array (gfc_symbol * sym, tree body) /* Get the descriptor type. */ type = TREE_TYPE (sym->backend_decl); - if (!GFC_DESCRIPTOR_TYPE_P (type)) + + if (sym_has_alloc_comp && !(sym->attr.pointer || sym->attr.allocatable)) + { + rank = sym->as ? sym->as->rank : 0; + tmp = gfc_nullify_alloc_comp (sym->ts.derived, descriptor, rank); + gfc_add_expr_to_block (&fnblock, tmp); + } + else if (!GFC_DESCRIPTOR_TYPE_P (type)) { /* If the backend_decl is not a descriptor, we must have a pointer to one. */ descriptor = build_fold_indirect_ref (sym->backend_decl); type = TREE_TYPE (descriptor); - gcc_assert (GFC_DESCRIPTOR_TYPE_P (type)); } - + /* NULLIFY the data pointer. */ - gfc_conv_descriptor_data_set (&fnblock, descriptor, null_pointer_node); + if (GFC_DESCRIPTOR_TYPE_P (type)) + gfc_conv_descriptor_data_set (&fnblock, descriptor, null_pointer_node); gfc_add_expr_to_block (&fnblock, body); gfc_set_backend_locus (&loc); - /* Allocatable arrays need to be freed when they go out of scope. */ + + /* Allocatable arrays need to be freed when they go out of scope. + The allocatable components of pointers must not be touched. */ + if (sym_has_alloc_comp && !(sym->attr.function || sym->attr.result) + && !sym->attr.pointer) + { + int rank; + rank = sym->as ? sym->as->rank : 0; + tmp = gfc_deallocate_alloc_comp (sym->ts.derived, descriptor, rank); + gfc_add_expr_to_block (&fnblock, tmp); + } + if (sym->attr.allocatable) { tmp = gfc_trans_dealloc_allocated (sym->backend_decl); |