diff options
author | mikael <mikael@138bc75d-0d04-0410-961f-82ee72b054a4> | 2015-07-17 09:40:29 +0000 |
---|---|---|
committer | mikael <mikael@138bc75d-0d04-0410-961f-82ee72b054a4> | 2015-07-17 09:40:29 +0000 |
commit | ac189a3f8e7ca7d76cf23f787db086247d1b92f5 (patch) | |
tree | 7078210f7a994805cf1f64553e2404f73464f23c /gcc/fortran/trans-expr.c | |
parent | 5ee742c436320e28bd6d977f0f734d65830bca46 (diff) |
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_components_6.f90: New file.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@225926 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/fortran/trans-expr.c')
-rw-r--r-- | gcc/fortran/trans-expr.c | 137 |
1 files changed, 95 insertions, 42 deletions
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index adc5c0aabe88..caafe7672e82 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -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. If se->direct_byref is set then se->expr contains the return parameter. 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); + bool elemental_proc = (comp + && comp->ts.interface + && comp->ts.interface->attr.elemental) + || (comp && comp->attr.elemental) + || sym->attr.elemental; + if (se->ss != NULL) { - if (!sym->attr.elemental && !(comp && comp->attr.elemental)) + if (!elemental_proc) { gcc_assert (se->ss->info->type == GFC_SS_FUNCTION); if (se->ss->info->useflags) @@ -4639,6 +4701,23 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, fsym = formal ? formal->sym : NULL; 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 with either arrayspec or _data component. Correct that here. OOP-TODO: Move this to the frontend. */ @@ -5165,22 +5244,6 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, } 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 a temporary for the result, we have to check that we 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 is converted to a temporary, which is passed and then 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.pointer); 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 the same as the declared type, copy-in/copy-out does 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.pointer); @@ -5248,12 +5311,13 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, intent in. */ { e->must_finalize = 1; - gfc_conv_subref_array_arg (&parmse, e, f, + gfc_conv_subref_array_arg (&parmse, e, nodesc_arg, INTENT_IN, fsym && fsym->attr.pointer); } 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 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. */ if (e->expr_type == EXPR_VARIABLE && 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->rank != 0 && (fsym == NULL @@ -5330,13 +5394,16 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, gfc_add_block_to_block (&post, &parmse.post); /* Allocated allocatable components of derived types must be - deallocated for non-variable scalars. Non-variable arrays are - dealt with in trans-array.c(gfc_conv_array_parameter). */ + deallocated for non-variable scalars, array arguments to elemental + 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) && e->ts.u.derived->attr.alloc_comp - && !(e->symtree && e->symtree->n.sym->attr.pointer) - && e->expr_type != EXPR_VARIABLE && !e->rank) - { + && (e->rank == 0 || elemental_proc || !nodesc_arg) + && !expr_may_alias_variables (e, elemental_proc)) + { int parm_rank; /* It is known the e returns a structure type with at least one allocatable component. When e is a function, ensure that the @@ -6674,7 +6741,7 @@ gfc_trans_subarray_assign (tree dest, gfc_component * cm, gfc_expr * 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); 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. */ 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); - } } |