aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/fortran/ChangeLog5
-rw-r--r--gcc/fortran/trans-expr.c35
2 files changed, 34 insertions, 6 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 6309b5a..587a010 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,5 +1,10 @@
2012-08-14 Mikael Morin <mikael@gcc.gnu.org>
+ * trans-expr.c (gfc_trans_scalar_assign): Rename argument,
+ extend comment.
+
+2012-08-14 Mikael Morin <mikael@gcc.gnu.org>
+
* gfortran.h (gfc_get_proc_ptr_comp): New prototype.
(gfc_is_proc_ptr_comp): Update prototype.
* expr.c (gfc_get_proc_ptr_comp): New function based on the old
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index 12a75d0..53fdf45 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -6307,11 +6307,34 @@ gfc_conv_string_parameter (gfc_se * se)
/* Generate code for assignment of scalar variables. Includes character
strings and derived types with allocatable components.
- If you know that the LHS has no allocations, set dealloc to false. */
+ If you know that the LHS has no allocations, set dealloc to false.
+
+ DEEP_COPY has no effect if the typespec TS is not a derived type with
+ allocatable components. Otherwise, if it is set, an explicit copy of each
+ allocatable component is made. This is necessary as a simple copy of the
+ whole object would copy array descriptors as is, so that the lhs's
+ allocatable components would point to the rhs's after the assignment.
+ Typically, setting DEEP_COPY is necessary if the rhs is a variable, and not
+ necessary if the rhs is a non-pointer function, as the allocatable components
+ are not accessible by other means than the function's result after the
+ function has returned. It is even more subtle when temporaries are involved,
+ as the two following examples show:
+ 1. When we evaluate an array constructor, a temporary is created. Thus
+ there is theoretically no alias possible. However, no deep copy is
+ made for this temporary, so that if the constructor is made of one or
+ more variable with allocatable components, those components still point
+ to the variable's: DEEP_COPY should be set for the assignment from the
+ temporary to the lhs in that case.
+ 2. When assigning a scalar to an array, we evaluate the scalar value out
+ of the loop, store it into a temporary variable, and assign from that.
+ In that case, deep copying when assigning to the temporary would be a
+ waste of resources; however deep copies should happen when assigning from
+ the temporary to each array element: again DEEP_COPY should be set for
+ the assignment from the temporary to the lhs. */
tree
gfc_trans_scalar_assign (gfc_se * lse, gfc_se * rse, gfc_typespec ts,
- bool l_is_temp, bool r_is_var, bool dealloc)
+ bool l_is_temp, bool deep_copy, bool dealloc)
{
stmtblock_t block;
tree tmp;
@@ -6345,9 +6368,9 @@ gfc_trans_scalar_assign (gfc_se * lse, gfc_se * rse, gfc_typespec ts,
else if (ts.type == BT_DERIVED && ts.u.derived->attr.alloc_comp)
{
cond = NULL_TREE;
-
+
/* Are the rhs and the lhs the same? */
- if (r_is_var)
+ if (deep_copy)
{
cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node,
gfc_build_addr_expr (NULL_TREE, lse->expr),
@@ -6363,7 +6386,7 @@ gfc_trans_scalar_assign (gfc_se * lse, gfc_se * rse, gfc_typespec ts,
{
tmp = gfc_evaluate_now (lse->expr, &lse->pre);
tmp = gfc_deallocate_alloc_comp (ts.u.derived, tmp, 0);
- if (r_is_var)
+ if (deep_copy)
tmp = build3_v (COND_EXPR, cond, build_empty_stmt (input_location),
tmp);
gfc_add_expr_to_block (&lse->post, tmp);
@@ -6377,7 +6400,7 @@ gfc_trans_scalar_assign (gfc_se * lse, gfc_se * rse, gfc_typespec ts,
/* Do a deep copy if the rhs is a variable, if it is not the
same as the lhs. */
- if (r_is_var)
+ if (deep_copy)
{
tmp = gfc_copy_alloc_comp (ts.u.derived, rse->expr, lse->expr, 0);
tmp = build3_v (COND_EXPR, cond, build_empty_stmt (input_location),