mirror of git://gcc.gnu.org/git/gcc.git
re PR fortran/43366 ([OOP][F08] Intrinsic assign to polymorphic variable)
gcc/fortran/ChangeLog:
2016-10-22 Andre Vehreschild <vehre@gcc.gnu.org>
PR fortran/43366
PR fortran/51864
PR fortran/57117
PR fortran/61337
PR fortran/61376
* primary.c (gfc_expr_attr): For transformational functions on classes
get the attrs from the class argument.
* resolve.c (resolve_ordinary_assign): Remove error message due to
feature implementation. Rewrite POINTER_ASSIGNS to ordinary ones when
the right-hand side is scalar class object (with some restrictions).
* trans-array.c (trans_array_constructor): Create the temporary from
class' inner type, i.e., the derived type.
(build_class_array_ref): Add support for class array's storage of the
class object or the array descriptor in the decl saved descriptor.
(gfc_conv_expr_descriptor): When creating temporaries for class objects
add the class object's handle into the decl saved descriptor.
(structure_alloc_comps): Use the common way to get the _data component.
(gfc_is_reallocatable_lhs): Add notion of allocatable class objects.
* trans-expr.c (gfc_find_and_cut_at_last_class_ref): Remove the only ref
only when the expression's type is BT_CLASS.
(gfc_trans_class_init_assign): Correctly handle class arrays.
(gfc_trans_class_assign): Joined into gfc_trans_assignment_1.
(gfc_conv_procedure_call): Support for class types as arguments.
(trans_get_upoly_len): For unlimited polymorphics retrieve the _len
component's tree.
(trans_class_vptr_len_assignment): Catch all ways to assign the _vptr
and _len components of a class object correctly.
(pointer_assignment_is_proc_pointer): Identify assignments of
procedure pointers.
(gfc_trans_pointer_assignment): Enhance support for class object pointer
assignments.
(gfc_trans_scalar_assign): Removed assert.
(trans_class_assignment): Assign to a class object.
(gfc_trans_assignment_1): Treat class objects correctly.
(gfc_trans_assignment): Propagate flags to trans_assignment_1.
* trans-stmt.c (gfc_trans_allocate): Use gfc_trans_assignment now
instead of copy_class_to_class.
* trans-stmt.h: Function prototype removed.
* trans.c (trans_code): Less special casing for class objects.
* trans.h: Added flags to gfc_trans_assignment () prototype.
gcc/testsuite/ChangeLog:
2016-10-22 Andre Vehreschild <vehre@gcc.gnu.org>
Forgot to add on original commit.
* gfortran.dg/coarray_alloc_comp_2.f08: New test.
2016-10-22 Andre Vehreschild <vehre@gcc.gnu.org>
PR fortran/43366
PR fortran/57117
PR fortran/61337
* gfortran.dg/alloc_comp_class_5.f03: New test.
* gfortran.dg/class_allocate_21.f90: New test.
* gfortran.dg/class_allocate_22.f90: New test.
* gfortran.dg/realloc_on_assign_27.f08: New test.
From-SVN: r241439
This commit is contained in:
parent
4e04812da2
commit
574284e9c4
|
|
@ -1,3 +1,46 @@
|
||||||
|
2016-10-22 Andre Vehreschild <vehre@gcc.gnu.org>
|
||||||
|
|
||||||
|
PR fortran/43366
|
||||||
|
PR fortran/51864
|
||||||
|
PR fortran/57117
|
||||||
|
PR fortran/61337
|
||||||
|
PR fortran/61376
|
||||||
|
* primary.c (gfc_expr_attr): For transformational functions on classes
|
||||||
|
get the attrs from the class argument.
|
||||||
|
* resolve.c (resolve_ordinary_assign): Remove error message due to
|
||||||
|
feature implementation. Rewrite POINTER_ASSIGNS to ordinary ones when
|
||||||
|
the right-hand side is scalar class object (with some restrictions).
|
||||||
|
* trans-array.c (trans_array_constructor): Create the temporary from
|
||||||
|
class' inner type, i.e., the derived type.
|
||||||
|
(build_class_array_ref): Add support for class array's storage of the
|
||||||
|
class object or the array descriptor in the decl saved descriptor.
|
||||||
|
(gfc_conv_expr_descriptor): When creating temporaries for class objects
|
||||||
|
add the class object's handle into the decl saved descriptor.
|
||||||
|
(structure_alloc_comps): Use the common way to get the _data component.
|
||||||
|
(gfc_is_reallocatable_lhs): Add notion of allocatable class objects.
|
||||||
|
* trans-expr.c (gfc_find_and_cut_at_last_class_ref): Remove the only ref
|
||||||
|
only when the expression's type is BT_CLASS.
|
||||||
|
(gfc_trans_class_init_assign): Correctly handle class arrays.
|
||||||
|
(gfc_trans_class_assign): Joined into gfc_trans_assignment_1.
|
||||||
|
(gfc_conv_procedure_call): Support for class types as arguments.
|
||||||
|
(trans_get_upoly_len): For unlimited polymorphics retrieve the _len
|
||||||
|
component's tree.
|
||||||
|
(trans_class_vptr_len_assignment): Catch all ways to assign the _vptr
|
||||||
|
and _len components of a class object correctly.
|
||||||
|
(pointer_assignment_is_proc_pointer): Identify assignments of
|
||||||
|
procedure pointers.
|
||||||
|
(gfc_trans_pointer_assignment): Enhance support for class object pointer
|
||||||
|
assignments.
|
||||||
|
(gfc_trans_scalar_assign): Removed assert.
|
||||||
|
(trans_class_assignment): Assign to a class object.
|
||||||
|
(gfc_trans_assignment_1): Treat class objects correctly.
|
||||||
|
(gfc_trans_assignment): Propagate flags to trans_assignment_1.
|
||||||
|
* trans-stmt.c (gfc_trans_allocate): Use gfc_trans_assignment now
|
||||||
|
instead of copy_class_to_class.
|
||||||
|
* trans-stmt.h: Function prototype removed.
|
||||||
|
* trans.c (trans_code): Less special casing for class objects.
|
||||||
|
* trans.h: Added flags to gfc_trans_assignment () prototype.
|
||||||
|
|
||||||
2016-10-21 Paul Thomas <pault@gcc.gnu.org>
|
2016-10-21 Paul Thomas <pault@gcc.gnu.org>
|
||||||
|
|
||||||
PR fortran/69566
|
PR fortran/69566
|
||||||
|
|
|
||||||
|
|
@ -2359,6 +2359,10 @@ gfc_expr_attr (gfc_expr *e)
|
||||||
attr.allocatable = CLASS_DATA (sym)->attr.allocatable;
|
attr.allocatable = CLASS_DATA (sym)->attr.allocatable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (e->value.function.isym
|
||||||
|
&& e->value.function.isym->transformational
|
||||||
|
&& e->ts.type == BT_CLASS)
|
||||||
|
attr = CLASS_DATA (e)->attr;
|
||||||
else
|
else
|
||||||
attr = gfc_variable_attr (e, NULL);
|
attr = gfc_variable_attr (e, NULL);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9911,10 +9911,6 @@ resolve_ordinary_assign (gfc_code *code, gfc_namespace *ns)
|
||||||
"requires %<-frealloc-lhs%>", &lhs->where);
|
"requires %<-frealloc-lhs%>", &lhs->where);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/* See PR 43366. */
|
|
||||||
gfc_error ("Assignment to an allocatable polymorphic variable at %L "
|
|
||||||
"is not yet supported", &lhs->where);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
else if (lhs->ts.type == BT_CLASS)
|
else if (lhs->ts.type == BT_CLASS)
|
||||||
{
|
{
|
||||||
|
|
@ -10817,6 +10813,19 @@ start:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
gfc_check_pointer_assign (code->expr1, code->expr2);
|
gfc_check_pointer_assign (code->expr1, code->expr2);
|
||||||
|
|
||||||
|
/* Assigning a class object always is a regular assign. */
|
||||||
|
if (code->expr2->ts.type == BT_CLASS
|
||||||
|
&& !CLASS_DATA (code->expr2)->attr.dimension
|
||||||
|
&& !(UNLIMITED_POLY (code->expr2)
|
||||||
|
&& code->expr1->ts.type == BT_DERIVED
|
||||||
|
&& (code->expr1->ts.u.derived->attr.sequence
|
||||||
|
|| code->expr1->ts.u.derived->attr.is_bind_c))
|
||||||
|
&& !(gfc_expr_attr (code->expr1).proc_pointer
|
||||||
|
&& code->expr2->expr_type == EXPR_VARIABLE
|
||||||
|
&& code->expr2->symtree->n.sym->attr.flavor
|
||||||
|
== FL_PROCEDURE))
|
||||||
|
code->op = EXEC_ASSIGN;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2292,7 +2292,8 @@ trans_array_constructor (gfc_ss * ss, locus * where)
|
||||||
type = build_pointer_type (type);
|
type = build_pointer_type (type);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
type = gfc_typenode_for_spec (&expr->ts);
|
type = gfc_typenode_for_spec (expr->ts.type == BT_CLASS
|
||||||
|
? &CLASS_DATA (expr)->ts : &expr->ts);
|
||||||
|
|
||||||
/* See if the constructor determines the loop bounds. */
|
/* See if the constructor determines the loop bounds. */
|
||||||
dynamic = false;
|
dynamic = false;
|
||||||
|
|
@ -3036,50 +3037,57 @@ build_class_array_ref (gfc_se *se, tree base, tree index)
|
||||||
tree type;
|
tree type;
|
||||||
tree size;
|
tree size;
|
||||||
tree offset;
|
tree offset;
|
||||||
tree decl;
|
tree decl = NULL_TREE;
|
||||||
tree tmp;
|
tree tmp;
|
||||||
gfc_expr *expr = se->ss->info->expr;
|
gfc_expr *expr = se->ss->info->expr;
|
||||||
gfc_ref *ref;
|
gfc_ref *ref;
|
||||||
gfc_ref *class_ref;
|
gfc_ref *class_ref = NULL;
|
||||||
gfc_typespec *ts;
|
gfc_typespec *ts;
|
||||||
|
|
||||||
if (expr == NULL
|
if (se->expr && DECL_P (se->expr) && DECL_LANG_SPECIFIC (se->expr)
|
||||||
|| (expr->ts.type != BT_CLASS
|
&& GFC_DECL_SAVED_DESCRIPTOR (se->expr)
|
||||||
&& !gfc_is_alloc_class_array_function (expr)))
|
&& GFC_CLASS_TYPE_P (TREE_TYPE (GFC_DECL_SAVED_DESCRIPTOR (se->expr))))
|
||||||
return false;
|
decl = se->expr;
|
||||||
|
|
||||||
if (expr->symtree && expr->symtree->n.sym->ts.type == BT_CLASS)
|
|
||||||
ts = &expr->symtree->n.sym->ts;
|
|
||||||
else
|
else
|
||||||
ts = NULL;
|
|
||||||
class_ref = NULL;
|
|
||||||
|
|
||||||
for (ref = expr->ref; ref; ref = ref->next)
|
|
||||||
{
|
{
|
||||||
if (ref->type == REF_COMPONENT
|
if (expr == NULL
|
||||||
&& ref->u.c.component->ts.type == BT_CLASS
|
|| (expr->ts.type != BT_CLASS
|
||||||
&& ref->next && ref->next->type == REF_COMPONENT
|
&& !gfc_is_alloc_class_array_function (expr)
|
||||||
&& strcmp (ref->next->u.c.component->name, "_data") == 0
|
&& !gfc_is_class_array_ref (expr, NULL)))
|
||||||
&& ref->next->next
|
return false;
|
||||||
&& ref->next->next->type == REF_ARRAY
|
|
||||||
&& ref->next->next->u.ar.type != AR_ELEMENT)
|
if (expr->symtree && expr->symtree->n.sym->ts.type == BT_CLASS)
|
||||||
|
ts = &expr->symtree->n.sym->ts;
|
||||||
|
else
|
||||||
|
ts = NULL;
|
||||||
|
|
||||||
|
for (ref = expr->ref; ref; ref = ref->next)
|
||||||
{
|
{
|
||||||
ts = &ref->u.c.component->ts;
|
if (ref->type == REF_COMPONENT
|
||||||
class_ref = ref;
|
&& ref->u.c.component->ts.type == BT_CLASS
|
||||||
break;
|
&& ref->next && ref->next->type == REF_COMPONENT
|
||||||
|
&& strcmp (ref->next->u.c.component->name, "_data") == 0
|
||||||
|
&& ref->next->next
|
||||||
|
&& ref->next->next->type == REF_ARRAY
|
||||||
|
&& ref->next->next->u.ar.type != AR_ELEMENT)
|
||||||
|
{
|
||||||
|
ts = &ref->u.c.component->ts;
|
||||||
|
class_ref = ref;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ts == NULL)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ts == NULL)
|
if (class_ref == NULL && expr && expr->symtree->n.sym->attr.function
|
||||||
return false;
|
|
||||||
|
|
||||||
if (class_ref == NULL && expr->symtree->n.sym->attr.function
|
|
||||||
&& expr->symtree->n.sym == expr->symtree->n.sym->result)
|
&& expr->symtree->n.sym == expr->symtree->n.sym->result)
|
||||||
{
|
{
|
||||||
gcc_assert (expr->symtree->n.sym->backend_decl == current_function_decl);
|
gcc_assert (expr->symtree->n.sym->backend_decl == current_function_decl);
|
||||||
decl = gfc_get_fake_result_decl (expr->symtree->n.sym, 0);
|
decl = gfc_get_fake_result_decl (expr->symtree->n.sym, 0);
|
||||||
}
|
}
|
||||||
else if (gfc_is_alloc_class_array_function (expr))
|
else if (expr && gfc_is_alloc_class_array_function (expr))
|
||||||
{
|
{
|
||||||
size = NULL_TREE;
|
size = NULL_TREE;
|
||||||
decl = NULL_TREE;
|
decl = NULL_TREE;
|
||||||
|
|
@ -3105,7 +3113,8 @@ build_class_array_ref (gfc_se *se, tree base, tree index)
|
||||||
}
|
}
|
||||||
else if (class_ref == NULL)
|
else if (class_ref == NULL)
|
||||||
{
|
{
|
||||||
decl = expr->symtree->n.sym->backend_decl;
|
if (decl == NULL_TREE)
|
||||||
|
decl = expr->symtree->n.sym->backend_decl;
|
||||||
/* For class arrays the tree containing the class is stored in
|
/* For class arrays the tree containing the class is stored in
|
||||||
GFC_DECL_SAVED_DESCRIPTOR of the sym's backend_decl.
|
GFC_DECL_SAVED_DESCRIPTOR of the sym's backend_decl.
|
||||||
For all others it's sym's backend_decl directly. */
|
For all others it's sym's backend_decl directly. */
|
||||||
|
|
@ -3121,6 +3130,7 @@ build_class_array_ref (gfc_se *se, tree base, tree index)
|
||||||
class_ref->next = NULL;
|
class_ref->next = NULL;
|
||||||
gfc_init_se (&tmpse, NULL);
|
gfc_init_se (&tmpse, NULL);
|
||||||
gfc_conv_expr (&tmpse, expr);
|
gfc_conv_expr (&tmpse, expr);
|
||||||
|
gfc_add_block_to_block (&se->pre, &tmpse.pre);
|
||||||
decl = tmpse.expr;
|
decl = tmpse.expr;
|
||||||
class_ref->next = ref;
|
class_ref->next = ref;
|
||||||
}
|
}
|
||||||
|
|
@ -7094,6 +7104,28 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr)
|
||||||
loop.from, loop.to, 0,
|
loop.from, loop.to, 0,
|
||||||
GFC_ARRAY_UNKNOWN, false);
|
GFC_ARRAY_UNKNOWN, false);
|
||||||
parm = gfc_create_var (parmtype, "parm");
|
parm = gfc_create_var (parmtype, "parm");
|
||||||
|
|
||||||
|
/* When expression is a class object, then add the class' handle to
|
||||||
|
the parm_decl. */
|
||||||
|
if (expr->ts.type == BT_CLASS && expr->expr_type == EXPR_VARIABLE)
|
||||||
|
{
|
||||||
|
gfc_expr *class_expr = gfc_find_and_cut_at_last_class_ref (expr);
|
||||||
|
gfc_se classse;
|
||||||
|
|
||||||
|
/* class_expr can be NULL, when no _class ref is in expr.
|
||||||
|
We must not fix this here with a gfc_fix_class_ref (). */
|
||||||
|
if (class_expr)
|
||||||
|
{
|
||||||
|
gfc_init_se (&classse, NULL);
|
||||||
|
gfc_conv_expr (&classse, class_expr);
|
||||||
|
gfc_free_expr (class_expr);
|
||||||
|
|
||||||
|
gcc_assert (classse.pre.head == NULL_TREE
|
||||||
|
&& classse.post.head == NULL_TREE);
|
||||||
|
gfc_allocate_lang_decl (parm);
|
||||||
|
GFC_DECL_SAVED_DESCRIPTOR (parm) = classse.expr;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = gfc_index_zero_node;
|
offset = gfc_index_zero_node;
|
||||||
|
|
@ -7255,6 +7287,13 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr)
|
||||||
: base;
|
: base;
|
||||||
gfc_conv_descriptor_offset_set (&loop.pre, parm, tmp);
|
gfc_conv_descriptor_offset_set (&loop.pre, parm, tmp);
|
||||||
}
|
}
|
||||||
|
else if (IS_CLASS_ARRAY (expr) && !se->data_not_needed
|
||||||
|
&& (!rank_remap || se->use_offset)
|
||||||
|
&& GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)))
|
||||||
|
{
|
||||||
|
gfc_conv_descriptor_offset_set (&loop.pre, parm,
|
||||||
|
gfc_conv_descriptor_offset_get (desc));
|
||||||
|
}
|
||||||
else if (onebased && (!rank_remap || se->use_offset)
|
else if (onebased && (!rank_remap || se->use_offset)
|
||||||
&& expr->symtree
|
&& expr->symtree
|
||||||
&& !(expr->symtree->n.sym && expr->symtree->n.sym->ts.type == BT_CLASS
|
&& !(expr->symtree->n.sym && expr->symtree->n.sym->ts.type == BT_CLASS
|
||||||
|
|
@ -7290,6 +7329,18 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr)
|
||||||
GFC_DECL_SAVED_DESCRIPTOR (expr->symtree->n.sym->backend_decl)
|
GFC_DECL_SAVED_DESCRIPTOR (expr->symtree->n.sym->backend_decl)
|
||||||
: expr->symtree->n.sym->backend_decl;
|
: expr->symtree->n.sym->backend_decl;
|
||||||
}
|
}
|
||||||
|
else if (expr->expr_type == EXPR_ARRAY && VAR_P (desc)
|
||||||
|
&& IS_CLASS_ARRAY (expr))
|
||||||
|
{
|
||||||
|
tree vtype;
|
||||||
|
gfc_allocate_lang_decl (desc);
|
||||||
|
tmp = gfc_create_var (expr->ts.u.derived->backend_decl, "class");
|
||||||
|
GFC_DECL_SAVED_DESCRIPTOR (desc) = tmp;
|
||||||
|
vtype = gfc_class_vptr_get (tmp);
|
||||||
|
gfc_add_modify (&se->pre, vtype,
|
||||||
|
gfc_build_addr_expr (TREE_TYPE (vtype),
|
||||||
|
gfc_find_vtab (&expr->ts)->backend_decl));
|
||||||
|
}
|
||||||
if (!se->direct_byref || se->byref_noassign)
|
if (!se->direct_byref || se->byref_noassign)
|
||||||
{
|
{
|
||||||
/* Get a pointer to the new descriptor. */
|
/* Get a pointer to the new descriptor. */
|
||||||
|
|
@ -8200,10 +8251,8 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl,
|
||||||
/* Allocatable CLASS components. */
|
/* Allocatable CLASS components. */
|
||||||
comp = fold_build3_loc (input_location, COMPONENT_REF, ctype,
|
comp = fold_build3_loc (input_location, COMPONENT_REF, ctype,
|
||||||
decl, cdecl, NULL_TREE);
|
decl, cdecl, NULL_TREE);
|
||||||
/* Add reference to '_data' component. */
|
|
||||||
tmp = CLASS_DATA (c)->backend_decl;
|
comp = gfc_class_data_get (comp);
|
||||||
comp = fold_build3_loc (input_location, COMPONENT_REF,
|
|
||||||
TREE_TYPE (tmp), comp, tmp, NULL_TREE);
|
|
||||||
if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (comp)))
|
if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (comp)))
|
||||||
gfc_conv_descriptor_data_set (&fnblock, comp, null_pointer_node);
|
gfc_conv_descriptor_data_set (&fnblock, comp, null_pointer_node);
|
||||||
else
|
else
|
||||||
|
|
@ -8541,6 +8590,14 @@ gfc_is_reallocatable_lhs (gfc_expr *expr)
|
||||||
if (!expr->ref)
|
if (!expr->ref)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
/* An allocatable class variable with no reference. */
|
||||||
|
if (expr->symtree->n.sym->ts.type == BT_CLASS
|
||||||
|
&& CLASS_DATA (expr->symtree->n.sym)->attr.allocatable
|
||||||
|
&& expr->ref && expr->ref->type == REF_COMPONENT
|
||||||
|
&& strcmp (expr->ref->u.c.component->name, "_data") == 0
|
||||||
|
&& expr->ref->next == NULL)
|
||||||
|
return true;
|
||||||
|
|
||||||
/* An allocatable variable. */
|
/* An allocatable variable. */
|
||||||
if (expr->symtree->n.sym->attr.allocatable
|
if (expr->symtree->n.sym->attr.allocatable
|
||||||
&& expr->ref
|
&& expr->ref
|
||||||
|
|
|
||||||
|
|
@ -350,7 +350,7 @@ gfc_expr *
|
||||||
gfc_find_and_cut_at_last_class_ref (gfc_expr *e)
|
gfc_find_and_cut_at_last_class_ref (gfc_expr *e)
|
||||||
{
|
{
|
||||||
gfc_expr *base_expr;
|
gfc_expr *base_expr;
|
||||||
gfc_ref *ref, *class_ref, *tail, *array_ref;
|
gfc_ref *ref, *class_ref, *tail = NULL, *array_ref;
|
||||||
|
|
||||||
/* Find the last class reference. */
|
/* Find the last class reference. */
|
||||||
class_ref = NULL;
|
class_ref = NULL;
|
||||||
|
|
@ -383,7 +383,7 @@ gfc_find_and_cut_at_last_class_ref (gfc_expr *e)
|
||||||
tail = class_ref->next;
|
tail = class_ref->next;
|
||||||
class_ref->next = NULL;
|
class_ref->next = NULL;
|
||||||
}
|
}
|
||||||
else
|
else if (e->symtree && e->symtree->n.sym->ts.type == BT_CLASS)
|
||||||
{
|
{
|
||||||
tail = e->ref;
|
tail = e->ref;
|
||||||
e->ref = NULL;
|
e->ref = NULL;
|
||||||
|
|
@ -397,7 +397,7 @@ gfc_find_and_cut_at_last_class_ref (gfc_expr *e)
|
||||||
gfc_free_ref_list (class_ref->next);
|
gfc_free_ref_list (class_ref->next);
|
||||||
class_ref->next = tail;
|
class_ref->next = tail;
|
||||||
}
|
}
|
||||||
else
|
else if (e->symtree && e->symtree->n.sym->ts.type == BT_CLASS)
|
||||||
{
|
{
|
||||||
gfc_free_ref_list (e->ref);
|
gfc_free_ref_list (e->ref);
|
||||||
e->ref = tail;
|
e->ref = tail;
|
||||||
|
|
@ -1458,7 +1458,12 @@ gfc_trans_class_init_assign (gfc_code *code)
|
||||||
|
|
||||||
if (code->expr1->ts.type == BT_CLASS
|
if (code->expr1->ts.type == BT_CLASS
|
||||||
&& CLASS_DATA (code->expr1)->attr.dimension)
|
&& CLASS_DATA (code->expr1)->attr.dimension)
|
||||||
tmp = gfc_trans_class_array_init_assign (rhs, lhs, code->expr1);
|
{
|
||||||
|
gfc_array_spec *tmparr = gfc_get_array_spec ();
|
||||||
|
*tmparr = *CLASS_DATA (code->expr1)->as;
|
||||||
|
gfc_add_full_array_ref (lhs, tmparr);
|
||||||
|
tmp = gfc_trans_class_array_init_assign (rhs, lhs, code->expr1);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sz = gfc_copy_expr (code->expr1);
|
sz = gfc_copy_expr (code->expr1);
|
||||||
|
|
@ -1503,114 +1508,6 @@ gfc_trans_class_init_assign (gfc_code *code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Translate an assignment to a CLASS object
|
|
||||||
(pointer or ordinary assignment). */
|
|
||||||
|
|
||||||
tree
|
|
||||||
gfc_trans_class_assign (gfc_expr *expr1, gfc_expr *expr2, gfc_exec_op op)
|
|
||||||
{
|
|
||||||
stmtblock_t block;
|
|
||||||
tree tmp;
|
|
||||||
gfc_expr *lhs;
|
|
||||||
gfc_expr *rhs;
|
|
||||||
gfc_ref *ref;
|
|
||||||
|
|
||||||
gfc_start_block (&block);
|
|
||||||
|
|
||||||
ref = expr1->ref;
|
|
||||||
while (ref && ref->next)
|
|
||||||
ref = ref->next;
|
|
||||||
|
|
||||||
/* Class valued proc_pointer assignments do not need any further
|
|
||||||
preparation. */
|
|
||||||
if (ref && ref->type == REF_COMPONENT
|
|
||||||
&& ref->u.c.component->attr.proc_pointer
|
|
||||||
&& expr2->expr_type == EXPR_VARIABLE
|
|
||||||
&& expr2->symtree->n.sym->attr.flavor == FL_PROCEDURE
|
|
||||||
&& op == EXEC_POINTER_ASSIGN)
|
|
||||||
goto assign;
|
|
||||||
|
|
||||||
if (expr2->ts.type != BT_CLASS)
|
|
||||||
{
|
|
||||||
/* Insert an additional assignment which sets the '_vptr' field. */
|
|
||||||
gfc_symbol *vtab = NULL;
|
|
||||||
gfc_symtree *st;
|
|
||||||
|
|
||||||
lhs = gfc_copy_expr (expr1);
|
|
||||||
gfc_add_vptr_component (lhs);
|
|
||||||
|
|
||||||
if (UNLIMITED_POLY (expr1)
|
|
||||||
&& expr2->expr_type == EXPR_NULL && expr2->ts.type == BT_UNKNOWN)
|
|
||||||
{
|
|
||||||
rhs = gfc_get_null_expr (&expr2->where);
|
|
||||||
goto assign_vptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expr2->expr_type == EXPR_NULL)
|
|
||||||
vtab = gfc_find_vtab (&expr1->ts);
|
|
||||||
else
|
|
||||||
vtab = gfc_find_vtab (&expr2->ts);
|
|
||||||
gcc_assert (vtab);
|
|
||||||
|
|
||||||
rhs = gfc_get_expr ();
|
|
||||||
rhs->expr_type = EXPR_VARIABLE;
|
|
||||||
gfc_find_sym_tree (vtab->name, vtab->ns, 1, &st);
|
|
||||||
rhs->symtree = st;
|
|
||||||
rhs->ts = vtab->ts;
|
|
||||||
assign_vptr:
|
|
||||||
tmp = gfc_trans_pointer_assignment (lhs, rhs);
|
|
||||||
gfc_add_expr_to_block (&block, tmp);
|
|
||||||
|
|
||||||
gfc_free_expr (lhs);
|
|
||||||
gfc_free_expr (rhs);
|
|
||||||
}
|
|
||||||
else if (expr1->ts.type == BT_DERIVED && UNLIMITED_POLY (expr2))
|
|
||||||
{
|
|
||||||
/* F2003:C717 only sequence and bind-C types can come here. */
|
|
||||||
gcc_assert (expr1->ts.u.derived->attr.sequence
|
|
||||||
|| expr1->ts.u.derived->attr.is_bind_c);
|
|
||||||
gfc_add_data_component (expr2);
|
|
||||||
goto assign;
|
|
||||||
}
|
|
||||||
else if (CLASS_DATA (expr2)->attr.dimension && expr2->expr_type != EXPR_FUNCTION)
|
|
||||||
{
|
|
||||||
/* Insert an additional assignment which sets the '_vptr' field. */
|
|
||||||
lhs = gfc_copy_expr (expr1);
|
|
||||||
gfc_add_vptr_component (lhs);
|
|
||||||
|
|
||||||
rhs = gfc_copy_expr (expr2);
|
|
||||||
gfc_add_vptr_component (rhs);
|
|
||||||
|
|
||||||
tmp = gfc_trans_pointer_assignment (lhs, rhs);
|
|
||||||
gfc_add_expr_to_block (&block, tmp);
|
|
||||||
|
|
||||||
gfc_free_expr (lhs);
|
|
||||||
gfc_free_expr (rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Do the actual CLASS assignment. */
|
|
||||||
if (expr2->ts.type == BT_CLASS
|
|
||||||
&& !CLASS_DATA (expr2)->attr.dimension)
|
|
||||||
op = EXEC_ASSIGN;
|
|
||||||
else if (expr2->expr_type != EXPR_FUNCTION || expr2->ts.type != BT_CLASS
|
|
||||||
|| !CLASS_DATA (expr2)->attr.dimension)
|
|
||||||
gfc_add_data_component (expr1);
|
|
||||||
|
|
||||||
assign:
|
|
||||||
|
|
||||||
if (op == EXEC_ASSIGN)
|
|
||||||
tmp = gfc_trans_assignment (expr1, expr2, false, true);
|
|
||||||
else if (op == EXEC_POINTER_ASSIGN)
|
|
||||||
tmp = gfc_trans_pointer_assignment (expr1, expr2);
|
|
||||||
else
|
|
||||||
gcc_unreachable();
|
|
||||||
|
|
||||||
gfc_add_expr_to_block (&block, tmp);
|
|
||||||
|
|
||||||
return gfc_finish_block (&block);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* End of prototype trans-class.c */
|
/* End of prototype trans-class.c */
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -5908,6 +5805,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
|
||||||
|
|
||||||
if (comp)
|
if (comp)
|
||||||
ts = comp->ts;
|
ts = comp->ts;
|
||||||
|
else if (sym->ts.type == BT_CLASS)
|
||||||
|
ts = CLASS_DATA (sym)->ts;
|
||||||
else
|
else
|
||||||
ts = sym->ts;
|
ts = sym->ts;
|
||||||
|
|
||||||
|
|
@ -5978,7 +5877,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
|
||||||
&& GFC_DESCRIPTOR_TYPE_P
|
&& GFC_DESCRIPTOR_TYPE_P
|
||||||
(TREE_TYPE (TREE_TYPE (TREE_TYPE (se->expr)))))
|
(TREE_TYPE (TREE_TYPE (TREE_TYPE (se->expr)))))
|
||||||
se->expr = build_fold_indirect_ref_loc (input_location,
|
se->expr = build_fold_indirect_ref_loc (input_location,
|
||||||
se->expr);
|
se->expr);
|
||||||
|
|
||||||
/* If the lhs of an assignment x = f(..) is allocatable and
|
/* If the lhs of an assignment x = f(..) is allocatable and
|
||||||
f2003 is allowed, we must do the automatic reallocation.
|
f2003 is allowed, we must do the automatic reallocation.
|
||||||
|
|
@ -6264,6 +6163,26 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Associate the rhs class object's meta-data with the result, when the
|
||||||
|
result is a temporary. */
|
||||||
|
if (args && args->expr && args->expr->ts.type == BT_CLASS
|
||||||
|
&& sym->ts.type == BT_CLASS && result != NULL_TREE && DECL_P (result)
|
||||||
|
&& !GFC_CLASS_TYPE_P (TREE_TYPE (result)))
|
||||||
|
{
|
||||||
|
gfc_se parmse;
|
||||||
|
gfc_expr *class_expr = gfc_find_and_cut_at_last_class_ref (args->expr);
|
||||||
|
|
||||||
|
gfc_init_se (&parmse, NULL);
|
||||||
|
parmse.data_not_needed = 1;
|
||||||
|
gfc_conv_expr (&parmse, class_expr);
|
||||||
|
if (!DECL_LANG_SPECIFIC (result))
|
||||||
|
gfc_allocate_lang_decl (result);
|
||||||
|
GFC_DECL_SAVED_DESCRIPTOR (result) = parmse.expr;
|
||||||
|
gfc_free_expr (class_expr);
|
||||||
|
gcc_assert (parmse.pre.head == NULL_TREE
|
||||||
|
&& parmse.post.head == NULL_TREE);
|
||||||
|
}
|
||||||
|
|
||||||
/* Follow the function call with the argument post block. */
|
/* Follow the function call with the argument post block. */
|
||||||
if (byref)
|
if (byref)
|
||||||
{
|
{
|
||||||
|
|
@ -7886,6 +7805,201 @@ gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Get the _len component for an unlimited polymorphic expression. */
|
||||||
|
|
||||||
|
static tree
|
||||||
|
trans_get_upoly_len (stmtblock_t *block, gfc_expr *expr)
|
||||||
|
{
|
||||||
|
gfc_se se;
|
||||||
|
gfc_ref *ref = expr->ref;
|
||||||
|
|
||||||
|
gfc_init_se (&se, NULL);
|
||||||
|
while (ref && ref->next)
|
||||||
|
ref = ref->next;
|
||||||
|
gfc_add_len_component (expr);
|
||||||
|
gfc_conv_expr (&se, expr);
|
||||||
|
gfc_add_block_to_block (block, &se.pre);
|
||||||
|
gcc_assert (se.post.head == NULL_TREE);
|
||||||
|
if (ref)
|
||||||
|
{
|
||||||
|
gfc_free_ref_list (ref->next);
|
||||||
|
ref->next = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gfc_free_ref_list (expr->ref);
|
||||||
|
expr->ref = NULL;
|
||||||
|
}
|
||||||
|
return se.expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Assign _vptr and _len components as appropriate. BLOCK should be a
|
||||||
|
statement-list outside of the scalarizer-loop. When code is generated, that
|
||||||
|
depends on the scalarized expression, it is added to RSE.PRE.
|
||||||
|
Returns le's _vptr tree and when set the len expressions in to_lenp and
|
||||||
|
from_lenp to form a le%_vptr%_copy (re, le, [from_lenp, to_lenp])
|
||||||
|
expression. */
|
||||||
|
|
||||||
|
static tree
|
||||||
|
trans_class_vptr_len_assignment (stmtblock_t *block, gfc_expr * le,
|
||||||
|
gfc_expr * re, gfc_se *rse,
|
||||||
|
tree * to_lenp, tree * from_lenp)
|
||||||
|
{
|
||||||
|
gfc_se se;
|
||||||
|
gfc_expr * vptr_expr;
|
||||||
|
tree tmp, to_len = NULL_TREE, from_len = NULL_TREE, lhs_vptr;
|
||||||
|
bool set_vptr = false, temp_rhs = false;
|
||||||
|
stmtblock_t *pre = block;
|
||||||
|
|
||||||
|
/* Create a temporary for complicated expressions. */
|
||||||
|
if (re->expr_type != EXPR_VARIABLE && re->expr_type != EXPR_NULL
|
||||||
|
&& rse->expr != NULL_TREE && !DECL_P (rse->expr))
|
||||||
|
{
|
||||||
|
tmp = gfc_create_var (TREE_TYPE (rse->expr), "rhs");
|
||||||
|
pre = &rse->pre;
|
||||||
|
gfc_add_modify (&rse->pre, tmp, rse->expr);
|
||||||
|
rse->expr = tmp;
|
||||||
|
temp_rhs = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the _vptr for the left-hand side expression. */
|
||||||
|
gfc_init_se (&se, NULL);
|
||||||
|
vptr_expr = gfc_find_and_cut_at_last_class_ref (le);
|
||||||
|
if (vptr_expr != NULL && gfc_expr_attr (vptr_expr).class_ok)
|
||||||
|
{
|
||||||
|
/* Care about _len for unlimited polymorphic entities. */
|
||||||
|
if (UNLIMITED_POLY (vptr_expr)
|
||||||
|
|| (vptr_expr->ts.type == BT_DERIVED
|
||||||
|
&& vptr_expr->ts.u.derived->attr.unlimited_polymorphic))
|
||||||
|
to_len = trans_get_upoly_len (block, vptr_expr);
|
||||||
|
gfc_add_vptr_component (vptr_expr);
|
||||||
|
set_vptr = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
vptr_expr = gfc_lval_expr_from_sym (gfc_find_vtab (&le->ts));
|
||||||
|
se.want_pointer = 1;
|
||||||
|
gfc_conv_expr (&se, vptr_expr);
|
||||||
|
gfc_free_expr (vptr_expr);
|
||||||
|
gfc_add_block_to_block (block, &se.pre);
|
||||||
|
gcc_assert (se.post.head == NULL_TREE);
|
||||||
|
lhs_vptr = se.expr;
|
||||||
|
STRIP_NOPS (lhs_vptr);
|
||||||
|
|
||||||
|
/* Set the _vptr only when the left-hand side of the assignment is a
|
||||||
|
class-object. */
|
||||||
|
if (set_vptr)
|
||||||
|
{
|
||||||
|
/* Get the vptr from the rhs expression only, when it is variable.
|
||||||
|
Functions are expected to be assigned to a temporary beforehand. */
|
||||||
|
vptr_expr = re->expr_type == EXPR_VARIABLE
|
||||||
|
? gfc_find_and_cut_at_last_class_ref (re)
|
||||||
|
: NULL;
|
||||||
|
if (vptr_expr != NULL && vptr_expr->ts.type == BT_CLASS)
|
||||||
|
{
|
||||||
|
if (to_len != NULL_TREE)
|
||||||
|
{
|
||||||
|
/* Get the _len information from the rhs. */
|
||||||
|
if (UNLIMITED_POLY (vptr_expr)
|
||||||
|
|| (vptr_expr->ts.type == BT_DERIVED
|
||||||
|
&& vptr_expr->ts.u.derived->attr.unlimited_polymorphic))
|
||||||
|
from_len = trans_get_upoly_len (block, vptr_expr);
|
||||||
|
}
|
||||||
|
gfc_add_vptr_component (vptr_expr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (re->expr_type == EXPR_VARIABLE
|
||||||
|
&& DECL_P (re->symtree->n.sym->backend_decl)
|
||||||
|
&& DECL_LANG_SPECIFIC (re->symtree->n.sym->backend_decl)
|
||||||
|
&& GFC_DECL_SAVED_DESCRIPTOR (re->symtree->n.sym->backend_decl)
|
||||||
|
&& GFC_CLASS_TYPE_P (TREE_TYPE (GFC_DECL_SAVED_DESCRIPTOR (
|
||||||
|
re->symtree->n.sym->backend_decl))))
|
||||||
|
{
|
||||||
|
vptr_expr = NULL;
|
||||||
|
se.expr = gfc_class_vptr_get (GFC_DECL_SAVED_DESCRIPTOR (
|
||||||
|
re->symtree->n.sym->backend_decl));
|
||||||
|
if (to_len)
|
||||||
|
from_len = gfc_class_len_get (GFC_DECL_SAVED_DESCRIPTOR (
|
||||||
|
re->symtree->n.sym->backend_decl));
|
||||||
|
}
|
||||||
|
else if (temp_rhs && re->ts.type == BT_CLASS)
|
||||||
|
{
|
||||||
|
vptr_expr = NULL;
|
||||||
|
se.expr = gfc_class_vptr_get (rse->expr);
|
||||||
|
}
|
||||||
|
else if (re->expr_type != EXPR_NULL)
|
||||||
|
/* Only when rhs is non-NULL use its declared type for vptr
|
||||||
|
initialisation. */
|
||||||
|
vptr_expr = gfc_lval_expr_from_sym (gfc_find_vtab (&re->ts));
|
||||||
|
else
|
||||||
|
/* When the rhs is NULL use the vtab of lhs' declared type. */
|
||||||
|
vptr_expr = gfc_lval_expr_from_sym (gfc_find_vtab (&le->ts));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vptr_expr)
|
||||||
|
{
|
||||||
|
gfc_init_se (&se, NULL);
|
||||||
|
se.want_pointer = 1;
|
||||||
|
gfc_conv_expr (&se, vptr_expr);
|
||||||
|
gfc_free_expr (vptr_expr);
|
||||||
|
gfc_add_block_to_block (block, &se.pre);
|
||||||
|
gcc_assert (se.post.head == NULL_TREE);
|
||||||
|
}
|
||||||
|
gfc_add_modify (pre, lhs_vptr, fold_convert (TREE_TYPE (lhs_vptr),
|
||||||
|
se.expr));
|
||||||
|
|
||||||
|
if (to_len != NULL_TREE)
|
||||||
|
{
|
||||||
|
/* The _len component needs to be set. Figure how to get the
|
||||||
|
value of the right-hand side. */
|
||||||
|
if (from_len == NULL_TREE)
|
||||||
|
{
|
||||||
|
if (rse->string_length != NULL_TREE)
|
||||||
|
from_len = rse->string_length;
|
||||||
|
else if (re->ts.type == BT_CHARACTER && re->ts.u.cl->length)
|
||||||
|
{
|
||||||
|
from_len = gfc_get_expr_charlen (re);
|
||||||
|
gfc_init_se (&se, NULL);
|
||||||
|
gfc_conv_expr (&se, re->ts.u.cl->length);
|
||||||
|
gfc_add_block_to_block (block, &se.pre);
|
||||||
|
gcc_assert (se.post.head == NULL_TREE);
|
||||||
|
from_len = gfc_evaluate_now (se.expr, block);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
from_len = integer_zero_node;
|
||||||
|
}
|
||||||
|
gfc_add_modify (pre, to_len, fold_convert (TREE_TYPE (to_len),
|
||||||
|
from_len));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the _len trees only, when requested. */
|
||||||
|
if (to_lenp)
|
||||||
|
*to_lenp = to_len;
|
||||||
|
if (from_lenp)
|
||||||
|
*from_lenp = from_len;
|
||||||
|
return lhs_vptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Indentify class valued proc_pointer assignments. */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
pointer_assignment_is_proc_pointer (gfc_expr * expr1, gfc_expr * expr2)
|
||||||
|
{
|
||||||
|
gfc_ref * ref;
|
||||||
|
|
||||||
|
ref = expr1->ref;
|
||||||
|
while (ref && ref->next)
|
||||||
|
ref = ref->next;
|
||||||
|
|
||||||
|
return ref && ref->type == REF_COMPONENT
|
||||||
|
&& ref->u.c.component->attr.proc_pointer
|
||||||
|
&& expr2->expr_type == EXPR_VARIABLE
|
||||||
|
&& expr2->symtree->n.sym->attr.flavor == FL_PROCEDURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
tree
|
tree
|
||||||
gfc_trans_pointer_assign (gfc_code * code)
|
gfc_trans_pointer_assign (gfc_code * code)
|
||||||
{
|
{
|
||||||
|
|
@ -7898,20 +8012,22 @@ gfc_trans_pointer_assign (gfc_code * code)
|
||||||
tree
|
tree
|
||||||
gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
|
gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
|
||||||
{
|
{
|
||||||
gfc_expr *expr1_vptr = NULL;
|
|
||||||
gfc_se lse;
|
gfc_se lse;
|
||||||
gfc_se rse;
|
gfc_se rse;
|
||||||
stmtblock_t block;
|
stmtblock_t block;
|
||||||
tree desc;
|
tree desc;
|
||||||
tree tmp;
|
tree tmp;
|
||||||
tree decl;
|
tree decl;
|
||||||
bool scalar;
|
bool scalar, non_proc_pointer_assign;
|
||||||
gfc_ss *ss;
|
gfc_ss *ss;
|
||||||
|
|
||||||
gfc_start_block (&block);
|
gfc_start_block (&block);
|
||||||
|
|
||||||
gfc_init_se (&lse, NULL);
|
gfc_init_se (&lse, NULL);
|
||||||
|
|
||||||
|
/* Usually testing whether this is not a proc pointer assignment. */
|
||||||
|
non_proc_pointer_assign = !pointer_assignment_is_proc_pointer (expr1, expr2);
|
||||||
|
|
||||||
/* Check whether the expression is a scalar or not; we cannot use
|
/* Check whether the expression is a scalar or not; we cannot use
|
||||||
expr1->rank as it can be nonzero for proc pointers. */
|
expr1->rank as it can be nonzero for proc pointers. */
|
||||||
ss = gfc_walk_expr (expr1);
|
ss = gfc_walk_expr (expr1);
|
||||||
|
|
@ -7920,7 +8036,7 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
|
||||||
gfc_free_ss_chain (ss);
|
gfc_free_ss_chain (ss);
|
||||||
|
|
||||||
if (expr1->ts.type == BT_DERIVED && expr2->ts.type == BT_CLASS
|
if (expr1->ts.type == BT_DERIVED && expr2->ts.type == BT_CLASS
|
||||||
&& expr2->expr_type != EXPR_FUNCTION)
|
&& expr2->expr_type != EXPR_FUNCTION && non_proc_pointer_assign)
|
||||||
{
|
{
|
||||||
gfc_add_data_component (expr2);
|
gfc_add_data_component (expr2);
|
||||||
/* The following is required as gfc_add_data_component doesn't
|
/* The following is required as gfc_add_data_component doesn't
|
||||||
|
|
@ -7937,6 +8053,13 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
|
||||||
rse.want_pointer = 1;
|
rse.want_pointer = 1;
|
||||||
gfc_conv_expr (&rse, expr2);
|
gfc_conv_expr (&rse, expr2);
|
||||||
|
|
||||||
|
if (non_proc_pointer_assign && expr1->ts.type == BT_CLASS)
|
||||||
|
{
|
||||||
|
trans_class_vptr_len_assignment (&block, expr1, expr2, &rse, NULL,
|
||||||
|
NULL);
|
||||||
|
lse.expr = gfc_class_data_get (lse.expr);
|
||||||
|
}
|
||||||
|
|
||||||
if (expr1->symtree->n.sym->attr.proc_pointer
|
if (expr1->symtree->n.sym->attr.proc_pointer
|
||||||
&& expr1->symtree->n.sym->attr.dummy)
|
&& expr1->symtree->n.sym->attr.dummy)
|
||||||
lse.expr = build_fold_indirect_ref_loc (input_location,
|
lse.expr = build_fold_indirect_ref_loc (input_location,
|
||||||
|
|
@ -7950,27 +8073,6 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
|
||||||
gfc_add_block_to_block (&block, &lse.pre);
|
gfc_add_block_to_block (&block, &lse.pre);
|
||||||
gfc_add_block_to_block (&block, &rse.pre);
|
gfc_add_block_to_block (&block, &rse.pre);
|
||||||
|
|
||||||
/* For string assignments to unlimited polymorphic pointers add an
|
|
||||||
assignment of the string_length to the _len component of the
|
|
||||||
pointer. */
|
|
||||||
if ((expr1->ts.type == BT_CLASS || expr1->ts.type == BT_DERIVED)
|
|
||||||
&& expr1->ts.u.derived->attr.unlimited_polymorphic
|
|
||||||
&& (expr2->ts.type == BT_CHARACTER ||
|
|
||||||
((expr2->ts.type == BT_DERIVED || expr2->ts.type == BT_CLASS)
|
|
||||||
&& expr2->ts.u.derived->attr.unlimited_polymorphic)))
|
|
||||||
{
|
|
||||||
gfc_expr *len_comp;
|
|
||||||
gfc_se se;
|
|
||||||
len_comp = gfc_get_len_component (expr1);
|
|
||||||
gfc_init_se (&se, NULL);
|
|
||||||
gfc_conv_expr (&se, len_comp);
|
|
||||||
|
|
||||||
/* ptr % _len = len (str) */
|
|
||||||
gfc_add_modify (&block, se.expr, rse.string_length);
|
|
||||||
lse.string_length = se.expr;
|
|
||||||
gfc_free_expr (len_comp);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check character lengths if character expression. The test is only
|
/* Check character lengths if character expression. The test is only
|
||||||
really added if -fbounds-check is enabled. Exclude deferred
|
really added if -fbounds-check is enabled. Exclude deferred
|
||||||
character length lefthand sides. */
|
character length lefthand sides. */
|
||||||
|
|
@ -7997,9 +8099,6 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
|
||||||
build_int_cst (gfc_charlen_type_node, 0));
|
build_int_cst (gfc_charlen_type_node, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expr1->ts.type == BT_DERIVED && expr2->ts.type == BT_CLASS)
|
|
||||||
rse.expr = gfc_class_data_get (rse.expr);
|
|
||||||
|
|
||||||
gfc_add_modify (&block, lse.expr,
|
gfc_add_modify (&block, lse.expr,
|
||||||
fold_convert (TREE_TYPE (lse.expr), rse.expr));
|
fold_convert (TREE_TYPE (lse.expr), rse.expr));
|
||||||
|
|
||||||
|
|
@ -8010,6 +8109,7 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
|
||||||
{
|
{
|
||||||
gfc_ref* remap;
|
gfc_ref* remap;
|
||||||
bool rank_remap;
|
bool rank_remap;
|
||||||
|
tree expr1_vptr = NULL_TREE;
|
||||||
tree strlen_lhs;
|
tree strlen_lhs;
|
||||||
tree strlen_rhs = NULL_TREE;
|
tree strlen_rhs = NULL_TREE;
|
||||||
|
|
||||||
|
|
@ -8026,9 +8126,6 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
|
||||||
gfc_init_se (&lse, NULL);
|
gfc_init_se (&lse, NULL);
|
||||||
if (remap)
|
if (remap)
|
||||||
lse.descriptor_only = 1;
|
lse.descriptor_only = 1;
|
||||||
if (expr2->expr_type == EXPR_FUNCTION && expr2->ts.type == BT_CLASS
|
|
||||||
&& expr1->ts.type == BT_CLASS)
|
|
||||||
expr1_vptr = gfc_copy_expr (expr1);
|
|
||||||
gfc_conv_expr_descriptor (&lse, expr1);
|
gfc_conv_expr_descriptor (&lse, expr1);
|
||||||
strlen_lhs = lse.string_length;
|
strlen_lhs = lse.string_length;
|
||||||
desc = lse.expr;
|
desc = lse.expr;
|
||||||
|
|
@ -8054,16 +8151,15 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
|
||||||
rse.expr = gfc_class_data_get (rse.expr);
|
rse.expr = gfc_class_data_get (rse.expr);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
expr1_vptr = trans_class_vptr_len_assignment (&block, expr1,
|
||||||
|
expr2, &rse,
|
||||||
|
NULL, NULL);
|
||||||
gfc_add_block_to_block (&block, &rse.pre);
|
gfc_add_block_to_block (&block, &rse.pre);
|
||||||
tmp = gfc_create_var (TREE_TYPE (rse.expr), "ptrtemp");
|
tmp = gfc_create_var (TREE_TYPE (rse.expr), "ptrtemp");
|
||||||
gfc_add_modify (&lse.pre, tmp, rse.expr);
|
gfc_add_modify (&lse.pre, tmp, rse.expr);
|
||||||
|
|
||||||
gfc_add_vptr_component (expr1_vptr);
|
gfc_add_modify (&lse.pre, expr1_vptr,
|
||||||
gfc_init_se (&rse, NULL);
|
fold_convert (TREE_TYPE (expr1_vptr),
|
||||||
rse.want_pointer = 1;
|
|
||||||
gfc_conv_expr (&rse, expr1_vptr);
|
|
||||||
gfc_add_modify (&lse.pre, rse.expr,
|
|
||||||
fold_convert (TREE_TYPE (rse.expr),
|
|
||||||
gfc_class_vptr_get (tmp)));
|
gfc_class_vptr_get (tmp)));
|
||||||
rse.expr = gfc_class_data_get (tmp);
|
rse.expr = gfc_class_data_get (tmp);
|
||||||
}
|
}
|
||||||
|
|
@ -8091,6 +8187,10 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
|
||||||
{
|
{
|
||||||
gfc_conv_expr_descriptor (&rse, expr2);
|
gfc_conv_expr_descriptor (&rse, expr2);
|
||||||
strlen_rhs = rse.string_length;
|
strlen_rhs = rse.string_length;
|
||||||
|
if (expr1->ts.type == BT_CLASS)
|
||||||
|
expr1_vptr = trans_class_vptr_len_assignment (&block, expr1,
|
||||||
|
expr2, &rse,
|
||||||
|
NULL, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (expr2->expr_type == EXPR_VARIABLE)
|
else if (expr2->expr_type == EXPR_VARIABLE)
|
||||||
|
|
@ -8109,12 +8209,22 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
|
||||||
gfc_init_se (&rse, NULL);
|
gfc_init_se (&rse, NULL);
|
||||||
rse.descriptor_only = 1;
|
rse.descriptor_only = 1;
|
||||||
gfc_conv_expr (&rse, expr2);
|
gfc_conv_expr (&rse, expr2);
|
||||||
|
if (expr1->ts.type == BT_CLASS)
|
||||||
|
trans_class_vptr_len_assignment (&block, expr1, expr2, &rse,
|
||||||
|
NULL, NULL);
|
||||||
tmp = gfc_get_element_type (TREE_TYPE (rse.expr));
|
tmp = gfc_get_element_type (TREE_TYPE (rse.expr));
|
||||||
tmp = fold_convert (gfc_array_index_type, size_in_bytes (tmp));
|
tmp = fold_convert (gfc_array_index_type, size_in_bytes (tmp));
|
||||||
if (!INTEGER_CST_P (tmp))
|
if (!INTEGER_CST_P (tmp))
|
||||||
gfc_add_block_to_block (&lse.post, &rse.pre);
|
gfc_add_block_to_block (&lse.post, &rse.pre);
|
||||||
gfc_add_modify (&lse.post, GFC_DECL_SPAN(decl), tmp);
|
gfc_add_modify (&lse.post, GFC_DECL_SPAN(decl), tmp);
|
||||||
}
|
}
|
||||||
|
else if (expr1->ts.type == BT_CLASS)
|
||||||
|
{
|
||||||
|
rse.expr = NULL_TREE;
|
||||||
|
rse.string_length = NULL_TREE;
|
||||||
|
trans_class_vptr_len_assignment (&block, expr1, expr2, &rse,
|
||||||
|
NULL, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (expr2->expr_type == EXPR_FUNCTION && expr2->ts.type == BT_CLASS)
|
else if (expr2->expr_type == EXPR_FUNCTION && expr2->ts.type == BT_CLASS)
|
||||||
{
|
{
|
||||||
|
|
@ -8128,16 +8238,15 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
expr1_vptr = trans_class_vptr_len_assignment (&block, expr1,
|
||||||
|
expr2, &rse, NULL,
|
||||||
|
NULL);
|
||||||
gfc_add_block_to_block (&block, &rse.pre);
|
gfc_add_block_to_block (&block, &rse.pre);
|
||||||
tmp = gfc_create_var (TREE_TYPE (rse.expr), "ptrtemp");
|
tmp = gfc_create_var (TREE_TYPE (rse.expr), "ptrtemp");
|
||||||
gfc_add_modify (&lse.pre, tmp, rse.expr);
|
gfc_add_modify (&lse.pre, tmp, rse.expr);
|
||||||
|
|
||||||
gfc_add_vptr_component (expr1_vptr);
|
gfc_add_modify (&lse.pre, expr1_vptr,
|
||||||
gfc_init_se (&rse, NULL);
|
fold_convert (TREE_TYPE (expr1_vptr),
|
||||||
rse.want_pointer = 1;
|
|
||||||
gfc_conv_expr (&rse, expr1_vptr);
|
|
||||||
gfc_add_modify (&lse.pre, rse.expr,
|
|
||||||
fold_convert (TREE_TYPE (rse.expr),
|
|
||||||
gfc_class_vptr_get (tmp)));
|
gfc_class_vptr_get (tmp)));
|
||||||
rse.expr = gfc_class_data_get (tmp);
|
rse.expr = gfc_class_data_get (tmp);
|
||||||
gfc_add_modify (&lse.pre, desc, rse.expr);
|
gfc_add_modify (&lse.pre, desc, rse.expr);
|
||||||
|
|
@ -8156,9 +8265,6 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
|
||||||
gfc_add_modify (&lse.pre, desc, tmp);
|
gfc_add_modify (&lse.pre, desc, tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (expr1_vptr)
|
|
||||||
gfc_free_expr (expr1_vptr);
|
|
||||||
|
|
||||||
gfc_add_block_to_block (&block, &lse.pre);
|
gfc_add_block_to_block (&block, &lse.pre);
|
||||||
if (rank_remap)
|
if (rank_remap)
|
||||||
gfc_add_block_to_block (&block, &rse.pre);
|
gfc_add_block_to_block (&block, &rse.pre);
|
||||||
|
|
@ -8408,7 +8514,6 @@ gfc_trans_scalar_assign (gfc_se * lse, gfc_se * rse, gfc_typespec ts,
|
||||||
|
|
||||||
if (rse->string_length != NULL_TREE)
|
if (rse->string_length != NULL_TREE)
|
||||||
{
|
{
|
||||||
gcc_assert (rse->string_length != NULL_TREE);
|
|
||||||
gfc_conv_string_parameter (rse);
|
gfc_conv_string_parameter (rse);
|
||||||
gfc_add_block_to_block (&block, &rse->pre);
|
gfc_add_block_to_block (&block, &rse->pre);
|
||||||
rlen = rse->string_length;
|
rlen = rse->string_length;
|
||||||
|
|
@ -9364,14 +9469,101 @@ is_runtime_conformable (gfc_expr *expr1, gfc_expr *expr2)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static tree
|
||||||
|
trans_class_assignment (stmtblock_t *block, gfc_expr *lhs, gfc_expr *rhs,
|
||||||
|
gfc_se *lse, gfc_se *rse, bool use_vptr_copy)
|
||||||
|
{
|
||||||
|
tree tmp;
|
||||||
|
tree fcn;
|
||||||
|
tree stdcopy, to_len, from_len;
|
||||||
|
vec<tree, va_gc> *args = NULL;
|
||||||
|
|
||||||
|
tmp = trans_class_vptr_len_assignment (block, lhs, rhs, rse, &to_len,
|
||||||
|
&from_len);
|
||||||
|
|
||||||
|
fcn = gfc_vptr_copy_get (tmp);
|
||||||
|
|
||||||
|
tmp = GFC_CLASS_TYPE_P (TREE_TYPE (rse->expr))
|
||||||
|
? gfc_class_data_get (rse->expr) : rse->expr;
|
||||||
|
if (use_vptr_copy)
|
||||||
|
{
|
||||||
|
if (!POINTER_TYPE_P (TREE_TYPE (tmp))
|
||||||
|
|| INDIRECT_REF_P (tmp)
|
||||||
|
|| (rhs->ts.type == BT_DERIVED
|
||||||
|
&& rhs->ts.u.derived->attr.unlimited_polymorphic
|
||||||
|
&& !rhs->ts.u.derived->attr.pointer
|
||||||
|
&& !rhs->ts.u.derived->attr.allocatable)
|
||||||
|
|| (UNLIMITED_POLY (rhs)
|
||||||
|
&& !CLASS_DATA (rhs)->attr.pointer
|
||||||
|
&& !CLASS_DATA (rhs)->attr.allocatable))
|
||||||
|
vec_safe_push (args, gfc_build_addr_expr (NULL_TREE, tmp));
|
||||||
|
else
|
||||||
|
vec_safe_push (args, tmp);
|
||||||
|
tmp = GFC_CLASS_TYPE_P (TREE_TYPE (lse->expr))
|
||||||
|
? gfc_class_data_get (lse->expr) : lse->expr;
|
||||||
|
if (!POINTER_TYPE_P (TREE_TYPE (tmp))
|
||||||
|
|| INDIRECT_REF_P (tmp)
|
||||||
|
|| (lhs->ts.type == BT_DERIVED
|
||||||
|
&& lhs->ts.u.derived->attr.unlimited_polymorphic
|
||||||
|
&& !lhs->ts.u.derived->attr.pointer
|
||||||
|
&& !lhs->ts.u.derived->attr.allocatable)
|
||||||
|
|| (UNLIMITED_POLY (lhs)
|
||||||
|
&& !CLASS_DATA (lhs)->attr.pointer
|
||||||
|
&& !CLASS_DATA (lhs)->attr.allocatable))
|
||||||
|
vec_safe_push (args, gfc_build_addr_expr (NULL_TREE, tmp));
|
||||||
|
else
|
||||||
|
vec_safe_push (args, tmp);
|
||||||
|
|
||||||
|
stdcopy = build_call_vec (TREE_TYPE (TREE_TYPE (fcn)), fcn, args);
|
||||||
|
|
||||||
|
if (to_len != NULL_TREE && !integer_zerop (from_len))
|
||||||
|
{
|
||||||
|
tree extcopy;
|
||||||
|
vec_safe_push (args, from_len);
|
||||||
|
vec_safe_push (args, to_len);
|
||||||
|
extcopy = build_call_vec (TREE_TYPE (TREE_TYPE (fcn)), fcn, args);
|
||||||
|
|
||||||
|
tmp = fold_build2_loc (input_location, GT_EXPR,
|
||||||
|
boolean_type_node, from_len,
|
||||||
|
integer_zero_node);
|
||||||
|
return fold_build3_loc (input_location, COND_EXPR,
|
||||||
|
void_type_node, tmp,
|
||||||
|
extcopy, stdcopy);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return stdcopy;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tree rhst = GFC_CLASS_TYPE_P (TREE_TYPE (lse->expr))
|
||||||
|
? gfc_class_data_get (lse->expr) : lse->expr;
|
||||||
|
stmtblock_t tblock;
|
||||||
|
gfc_init_block (&tblock);
|
||||||
|
if (!POINTER_TYPE_P (TREE_TYPE (tmp)))
|
||||||
|
tmp = gfc_build_addr_expr (NULL_TREE, tmp);
|
||||||
|
if (!POINTER_TYPE_P (TREE_TYPE (rhst)))
|
||||||
|
rhst = gfc_build_addr_expr (NULL_TREE, rhst);
|
||||||
|
/* When coming from a ptr_copy lhs and rhs are swapped. */
|
||||||
|
gfc_add_modify_loc (input_location, &tblock, rhst,
|
||||||
|
fold_convert (TREE_TYPE (rhst), tmp));
|
||||||
|
return gfc_finish_block (&tblock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Subroutine of gfc_trans_assignment that actually scalarizes the
|
/* Subroutine of gfc_trans_assignment that actually scalarizes the
|
||||||
assignment. EXPR1 is the destination/LHS and EXPR2 is the source/RHS.
|
assignment. EXPR1 is the destination/LHS and EXPR2 is the source/RHS.
|
||||||
init_flag indicates initialization expressions and dealloc that no
|
init_flag indicates initialization expressions and dealloc that no
|
||||||
deallocate prior assignment is needed (if in doubt, set true). */
|
deallocate prior assignment is needed (if in doubt, set true).
|
||||||
|
When PTR_COPY is set and expr1 is a class type, then use the _vptr-copy
|
||||||
|
routine instead of a pointer assignment. Alias resolution is only done,
|
||||||
|
when MAY_ALIAS is set (the default). This flag is used by ALLOCATE()
|
||||||
|
where it is known, that newly allocated memory on the lhs can never be
|
||||||
|
an alias of the rhs. */
|
||||||
|
|
||||||
static tree
|
static tree
|
||||||
gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
|
gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
|
||||||
bool dealloc)
|
bool dealloc, bool use_vptr_copy, bool may_alias)
|
||||||
{
|
{
|
||||||
gfc_se lse;
|
gfc_se lse;
|
||||||
gfc_se rse;
|
gfc_se rse;
|
||||||
|
|
@ -9387,7 +9579,7 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
|
||||||
tree string_length;
|
tree string_length;
|
||||||
int n;
|
int n;
|
||||||
bool maybe_workshare = false;
|
bool maybe_workshare = false;
|
||||||
symbol_attribute lhs_caf_attr, rhs_caf_attr;
|
symbol_attribute lhs_caf_attr, rhs_caf_attr, lhs_attr;
|
||||||
|
|
||||||
/* Assignment of the form lhs = rhs. */
|
/* Assignment of the form lhs = rhs. */
|
||||||
gfc_start_block (&block);
|
gfc_start_block (&block);
|
||||||
|
|
@ -9408,8 +9600,13 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
|
||||||
|| gfc_is_alloc_class_scalar_function (expr2)))
|
|| gfc_is_alloc_class_scalar_function (expr2)))
|
||||||
expr2->must_finalize = 1;
|
expr2->must_finalize = 1;
|
||||||
|
|
||||||
lhs_caf_attr = gfc_caf_attr (expr1);
|
/* Only analyze the expressions for coarray properties, when in coarray-lib
|
||||||
rhs_caf_attr = gfc_caf_attr (expr2);
|
mode. */
|
||||||
|
if (flag_coarray == GFC_FCOARRAY_LIB)
|
||||||
|
{
|
||||||
|
lhs_caf_attr = gfc_caf_attr (expr1);
|
||||||
|
rhs_caf_attr = gfc_caf_attr (expr2);
|
||||||
|
}
|
||||||
|
|
||||||
if (lss != gfc_ss_terminator)
|
if (lss != gfc_ss_terminator)
|
||||||
{
|
{
|
||||||
|
|
@ -9442,7 +9639,8 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
|
||||||
for (n = 0; n < GFC_MAX_DIMENSIONS; n++)
|
for (n = 0; n < GFC_MAX_DIMENSIONS; n++)
|
||||||
loop.reverse[n] = GFC_ENABLE_REVERSE;
|
loop.reverse[n] = GFC_ENABLE_REVERSE;
|
||||||
/* Resolve any data dependencies in the statement. */
|
/* Resolve any data dependencies in the statement. */
|
||||||
gfc_conv_resolve_dependencies (&loop, lss, rss);
|
if (may_alias)
|
||||||
|
gfc_conv_resolve_dependencies (&loop, lss, rss);
|
||||||
/* Setup the scalarizing loops. */
|
/* Setup the scalarizing loops. */
|
||||||
gfc_conv_loop_setup (&loop, &expr2->where);
|
gfc_conv_loop_setup (&loop, &expr2->where);
|
||||||
|
|
||||||
|
|
@ -9589,9 +9787,26 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
|
||||||
gfc_add_block_to_block (&loop.post, &rse.post);
|
gfc_add_block_to_block (&loop.post, &rse.post);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flag_coarray == GFC_FCOARRAY_LIB
|
lhs_attr = gfc_expr_attr (expr1);
|
||||||
&& lhs_caf_attr.codimension && rhs_caf_attr.codimension
|
if ((use_vptr_copy || lhs_attr.pointer
|
||||||
&& lhs_caf_attr.alloc_comp && rhs_caf_attr.alloc_comp)
|
|| (lhs_attr.allocatable && !lhs_attr.dimension))
|
||||||
|
&& (expr1->ts.type == BT_CLASS
|
||||||
|
|| (gfc_is_class_array_ref (expr1, NULL)
|
||||||
|
|| gfc_is_class_scalar_expr (expr1))
|
||||||
|
|| (gfc_is_class_array_ref (expr2, NULL)
|
||||||
|
|| gfc_is_class_scalar_expr (expr2))))
|
||||||
|
{
|
||||||
|
tmp = trans_class_assignment (&body, expr1, expr2, &lse, &rse,
|
||||||
|
use_vptr_copy || (lhs_attr.allocatable
|
||||||
|
&& !lhs_attr.dimension));
|
||||||
|
/* Modify the expr1 after the assignment, to allow the realloc below.
|
||||||
|
Therefore only needed, when realloc_lhs is enabled. */
|
||||||
|
if (flag_realloc_lhs && !lhs_attr.pointer)
|
||||||
|
gfc_add_data_component (expr1);
|
||||||
|
}
|
||||||
|
else if (flag_coarray == GFC_FCOARRAY_LIB
|
||||||
|
&& lhs_caf_attr.codimension && rhs_caf_attr.codimension
|
||||||
|
&& lhs_caf_attr.alloc_comp && rhs_caf_attr.alloc_comp)
|
||||||
{
|
{
|
||||||
gfc_code code;
|
gfc_code code;
|
||||||
gfc_actual_arglist a1, a2;
|
gfc_actual_arglist a1, a2;
|
||||||
|
|
@ -9609,7 +9824,13 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
|
||||||
|| scalar_to_array
|
|| scalar_to_array
|
||||||
|| expr2->expr_type == EXPR_ARRAY,
|
|| expr2->expr_type == EXPR_ARRAY,
|
||||||
!(l_is_temp || init_flag) && dealloc);
|
!(l_is_temp || init_flag) && dealloc);
|
||||||
|
/* Add the pre blocks to the body. */
|
||||||
|
gfc_add_block_to_block (&body, &rse.pre);
|
||||||
|
gfc_add_block_to_block (&body, &lse.pre);
|
||||||
gfc_add_expr_to_block (&body, tmp);
|
gfc_add_expr_to_block (&body, tmp);
|
||||||
|
/* Add the post blocks to the body. */
|
||||||
|
gfc_add_block_to_block (&body, &rse.post);
|
||||||
|
gfc_add_block_to_block (&body, &lse.post);
|
||||||
|
|
||||||
if (lss == gfc_ss_terminator)
|
if (lss == gfc_ss_terminator)
|
||||||
{
|
{
|
||||||
|
|
@ -9724,7 +9945,7 @@ copyable_array_p (gfc_expr * expr)
|
||||||
|
|
||||||
tree
|
tree
|
||||||
gfc_trans_assignment (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
|
gfc_trans_assignment (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
|
||||||
bool dealloc)
|
bool dealloc, bool use_vptr_copy, bool may_alias)
|
||||||
{
|
{
|
||||||
tree tmp;
|
tree tmp;
|
||||||
|
|
||||||
|
|
@ -9767,7 +9988,8 @@ gfc_trans_assignment (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fallback to the scalarizer to generate explicit loops. */
|
/* Fallback to the scalarizer to generate explicit loops. */
|
||||||
return gfc_trans_assignment_1 (expr1, expr2, init_flag, dealloc);
|
return gfc_trans_assignment_1 (expr1, expr2, init_flag, dealloc,
|
||||||
|
use_vptr_copy, may_alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
tree
|
tree
|
||||||
|
|
|
||||||
|
|
@ -5439,7 +5439,10 @@ gfc_trans_allocate (gfc_code * code)
|
||||||
if (code->expr3->rank != 0
|
if (code->expr3->rank != 0
|
||||||
&& ((!attr.allocatable && !attr.pointer)
|
&& ((!attr.allocatable && !attr.pointer)
|
||||||
|| (code->expr3->expr_type == EXPR_FUNCTION
|
|| (code->expr3->expr_type == EXPR_FUNCTION
|
||||||
&& code->expr3->ts.type != BT_CLASS)))
|
&& (code->expr3->ts.type != BT_CLASS
|
||||||
|
|| (code->expr3->value.function.isym
|
||||||
|
&& code->expr3->value.function.isym
|
||||||
|
->transformational)))))
|
||||||
gfc_conv_expr_descriptor (&se, code->expr3);
|
gfc_conv_expr_descriptor (&se, code->expr3);
|
||||||
else
|
else
|
||||||
gfc_conv_expr_reference (&se, code->expr3);
|
gfc_conv_expr_reference (&se, code->expr3);
|
||||||
|
|
@ -5623,73 +5626,6 @@ gfc_trans_allocate (gfc_code * code)
|
||||||
else
|
else
|
||||||
expr3_esize = TYPE_SIZE_UNIT (
|
expr3_esize = TYPE_SIZE_UNIT (
|
||||||
gfc_typenode_for_spec (&code->expr3->ts));
|
gfc_typenode_for_spec (&code->expr3->ts));
|
||||||
|
|
||||||
/* The routine gfc_trans_assignment () already implements all
|
|
||||||
techniques needed. Unfortunately we may have a temporary
|
|
||||||
variable for the source= expression here. When that is the
|
|
||||||
case convert this variable into a temporary gfc_expr of type
|
|
||||||
EXPR_VARIABLE and used it as rhs for the assignment. The
|
|
||||||
advantage is, that we get scalarizer support for free,
|
|
||||||
don't have to take care about scalar to array treatment and
|
|
||||||
will benefit of every enhancements gfc_trans_assignment ()
|
|
||||||
gets.
|
|
||||||
No need to check whether e3_is is E3_UNSET, because that is
|
|
||||||
done by expr3 != NULL_TREE.
|
|
||||||
Exclude variables since the following block does not handle
|
|
||||||
array sections. In any case, there is no harm in sending
|
|
||||||
variables to gfc_trans_assignment because there is no
|
|
||||||
evaluation of variables. */
|
|
||||||
if (code->expr3->expr_type != EXPR_VARIABLE
|
|
||||||
&& e3_is != E3_MOLD && expr3 != NULL_TREE
|
|
||||||
&& DECL_P (expr3) && DECL_ARTIFICIAL (expr3))
|
|
||||||
{
|
|
||||||
/* Build a temporary symtree and symbol. Do not add it to
|
|
||||||
the current namespace to prevent accidently modifying
|
|
||||||
a colliding symbol's as. */
|
|
||||||
newsym = XCNEW (gfc_symtree);
|
|
||||||
/* The name of the symtree should be unique, because
|
|
||||||
gfc_create_var () took care about generating the
|
|
||||||
identifier. */
|
|
||||||
newsym->name = gfc_get_string (IDENTIFIER_POINTER (
|
|
||||||
DECL_NAME (expr3)));
|
|
||||||
newsym->n.sym = gfc_new_symbol (newsym->name, NULL);
|
|
||||||
/* The backend_decl is known. It is expr3, which is inserted
|
|
||||||
here. */
|
|
||||||
newsym->n.sym->backend_decl = expr3;
|
|
||||||
e3rhs = gfc_get_expr ();
|
|
||||||
e3rhs->ts = code->expr3->ts;
|
|
||||||
e3rhs->rank = code->expr3->rank;
|
|
||||||
e3rhs->symtree = newsym;
|
|
||||||
/* Mark the symbol referenced or gfc_trans_assignment will
|
|
||||||
bug. */
|
|
||||||
newsym->n.sym->attr.referenced = 1;
|
|
||||||
e3rhs->expr_type = EXPR_VARIABLE;
|
|
||||||
e3rhs->where = code->expr3->where;
|
|
||||||
/* Set the symbols type, upto it was BT_UNKNOWN. */
|
|
||||||
newsym->n.sym->ts = e3rhs->ts;
|
|
||||||
/* Check whether the expr3 is array valued. */
|
|
||||||
if (e3rhs->rank)
|
|
||||||
{
|
|
||||||
gfc_array_spec *arr;
|
|
||||||
arr = gfc_get_array_spec ();
|
|
||||||
arr->rank = e3rhs->rank;
|
|
||||||
arr->type = AS_DEFERRED;
|
|
||||||
/* Set the dimension and pointer attribute for arrays
|
|
||||||
to be on the safe side. */
|
|
||||||
newsym->n.sym->attr.dimension = 1;
|
|
||||||
newsym->n.sym->attr.pointer = 1;
|
|
||||||
newsym->n.sym->as = arr;
|
|
||||||
gfc_add_full_array_ref (e3rhs, arr);
|
|
||||||
}
|
|
||||||
else if (POINTER_TYPE_P (TREE_TYPE (expr3)))
|
|
||||||
newsym->n.sym->attr.pointer = 1;
|
|
||||||
/* The string length is known to. Set it for char arrays. */
|
|
||||||
if (e3rhs->ts.type == BT_CHARACTER)
|
|
||||||
newsym->n.sym->ts.u.cl->backend_decl = expr3_len;
|
|
||||||
gfc_commit_symbol (newsym->n.sym);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
e3rhs = gfc_copy_expr (code->expr3);
|
|
||||||
}
|
}
|
||||||
gcc_assert (expr3_esize);
|
gcc_assert (expr3_esize);
|
||||||
expr3_esize = fold_convert (sizetype, expr3_esize);
|
expr3_esize = fold_convert (sizetype, expr3_esize);
|
||||||
|
|
@ -5723,6 +5659,95 @@ gfc_trans_allocate (gfc_code * code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The routine gfc_trans_assignment () already implements all
|
||||||
|
techniques needed. Unfortunately we may have a temporary
|
||||||
|
variable for the source= expression here. When that is the
|
||||||
|
case convert this variable into a temporary gfc_expr of type
|
||||||
|
EXPR_VARIABLE and used it as rhs for the assignment. The
|
||||||
|
advantage is, that we get scalarizer support for free,
|
||||||
|
don't have to take care about scalar to array treatment and
|
||||||
|
will benefit of every enhancements gfc_trans_assignment ()
|
||||||
|
gets.
|
||||||
|
No need to check whether e3_is is E3_UNSET, because that is
|
||||||
|
done by expr3 != NULL_TREE.
|
||||||
|
Exclude variables since the following block does not handle
|
||||||
|
array sections. In any case, there is no harm in sending
|
||||||
|
variables to gfc_trans_assignment because there is no
|
||||||
|
evaluation of variables. */
|
||||||
|
if (code->expr3)
|
||||||
|
{
|
||||||
|
if (code->expr3->expr_type != EXPR_VARIABLE
|
||||||
|
&& e3_is != E3_MOLD && expr3 != NULL_TREE
|
||||||
|
&& DECL_P (expr3) && DECL_ARTIFICIAL (expr3))
|
||||||
|
{
|
||||||
|
/* Build a temporary symtree and symbol. Do not add it to the current
|
||||||
|
namespace to prevent accidently modifying a colliding
|
||||||
|
symbol's as. */
|
||||||
|
newsym = XCNEW (gfc_symtree);
|
||||||
|
/* The name of the symtree should be unique, because gfc_create_var ()
|
||||||
|
took care about generating the identifier. */
|
||||||
|
newsym->name = gfc_get_string (IDENTIFIER_POINTER (
|
||||||
|
DECL_NAME (expr3)));
|
||||||
|
newsym->n.sym = gfc_new_symbol (newsym->name, NULL);
|
||||||
|
/* The backend_decl is known. It is expr3, which is inserted
|
||||||
|
here. */
|
||||||
|
newsym->n.sym->backend_decl = expr3;
|
||||||
|
e3rhs = gfc_get_expr ();
|
||||||
|
e3rhs->rank = code->expr3->rank;
|
||||||
|
e3rhs->symtree = newsym;
|
||||||
|
/* Mark the symbol referenced or gfc_trans_assignment will bug. */
|
||||||
|
newsym->n.sym->attr.referenced = 1;
|
||||||
|
e3rhs->expr_type = EXPR_VARIABLE;
|
||||||
|
e3rhs->where = code->expr3->where;
|
||||||
|
/* Set the symbols type, upto it was BT_UNKNOWN. */
|
||||||
|
if (IS_CLASS_ARRAY (code->expr3)
|
||||||
|
&& code->expr3->expr_type == EXPR_FUNCTION
|
||||||
|
&& code->expr3->value.function.isym
|
||||||
|
&& code->expr3->value.function.isym->transformational)
|
||||||
|
{
|
||||||
|
e3rhs->ts = CLASS_DATA (code->expr3)->ts;
|
||||||
|
}
|
||||||
|
else if (code->expr3->ts.type == BT_CLASS
|
||||||
|
&& !GFC_CLASS_TYPE_P (TREE_TYPE (expr3)))
|
||||||
|
e3rhs->ts = CLASS_DATA (code->expr3)->ts;
|
||||||
|
else
|
||||||
|
e3rhs->ts = code->expr3->ts;
|
||||||
|
newsym->n.sym->ts = e3rhs->ts;
|
||||||
|
/* Check whether the expr3 is array valued. */
|
||||||
|
if (e3rhs->rank)
|
||||||
|
{
|
||||||
|
gfc_array_spec *arr;
|
||||||
|
arr = gfc_get_array_spec ();
|
||||||
|
arr->rank = e3rhs->rank;
|
||||||
|
arr->type = AS_DEFERRED;
|
||||||
|
/* Set the dimension and pointer attribute for arrays
|
||||||
|
to be on the safe side. */
|
||||||
|
newsym->n.sym->attr.dimension = 1;
|
||||||
|
newsym->n.sym->attr.pointer = 1;
|
||||||
|
newsym->n.sym->as = arr;
|
||||||
|
if (IS_CLASS_ARRAY (code->expr3)
|
||||||
|
&& code->expr3->expr_type == EXPR_FUNCTION
|
||||||
|
&& code->expr3->value.function.isym
|
||||||
|
&& code->expr3->value.function.isym->transformational)
|
||||||
|
{
|
||||||
|
gfc_array_spec *tarr;
|
||||||
|
tarr = gfc_get_array_spec ();
|
||||||
|
*tarr = *arr;
|
||||||
|
e3rhs->ts.u.derived->as = tarr;
|
||||||
|
}
|
||||||
|
gfc_add_full_array_ref (e3rhs, arr);
|
||||||
|
}
|
||||||
|
else if (POINTER_TYPE_P (TREE_TYPE (expr3)))
|
||||||
|
newsym->n.sym->attr.pointer = 1;
|
||||||
|
/* The string length is known, too. Set it for char arrays. */
|
||||||
|
if (e3rhs->ts.type == BT_CHARACTER)
|
||||||
|
newsym->n.sym->ts.u.cl->backend_decl = expr3_len;
|
||||||
|
gfc_commit_symbol (newsym->n.sym);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
e3rhs = gfc_copy_expr (code->expr3);
|
||||||
|
}
|
||||||
|
|
||||||
/* Loop over all objects to allocate. */
|
/* Loop over all objects to allocate. */
|
||||||
for (al = code->ext.alloc.list; al != NULL; al = al->next)
|
for (al = code->ext.alloc.list; al != NULL; al = al->next)
|
||||||
{
|
{
|
||||||
|
|
@ -5960,8 +5985,9 @@ gfc_trans_allocate (gfc_code * code)
|
||||||
gfc_add_expr_to_block (&block, tmp);
|
gfc_add_expr_to_block (&block, tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the vptr. */
|
/* Set the vptr only when no source= is set. When source= is set, then
|
||||||
if (al_vptr != NULL_TREE)
|
the trans_assignment below will set the vptr. */
|
||||||
|
if (al_vptr != NULL_TREE && (!code->expr3 || code->expr3->mold))
|
||||||
{
|
{
|
||||||
if (expr3_vptr != NULL_TREE)
|
if (expr3_vptr != NULL_TREE)
|
||||||
/* The vtab is already known, so just assign it. */
|
/* The vtab is already known, so just assign it. */
|
||||||
|
|
@ -6046,153 +6072,34 @@ gfc_trans_allocate (gfc_code * code)
|
||||||
if (code->expr3 && !code->expr3->mold && e3_is != E3_MOLD)
|
if (code->expr3 && !code->expr3->mold && e3_is != E3_MOLD)
|
||||||
{
|
{
|
||||||
/* Initialization via SOURCE block (or static default initializer).
|
/* Initialization via SOURCE block (or static default initializer).
|
||||||
Classes need some special handling, so catch them first. */
|
Switch off automatic reallocation since we have just done the
|
||||||
if (expr3 != NULL_TREE
|
ALLOCATE. */
|
||||||
&& TREE_CODE (expr3) != POINTER_PLUS_EXPR
|
int realloc_lhs = flag_realloc_lhs;
|
||||||
&& code->expr3->ts.type == BT_CLASS
|
gfc_expr *init_expr = gfc_expr_to_initialize (expr);
|
||||||
&& (expr->ts.type == BT_CLASS
|
gfc_expr *rhs = e3rhs ? e3rhs : gfc_copy_expr (code->expr3);
|
||||||
|| expr->ts.type == BT_DERIVED))
|
flag_realloc_lhs = 0;
|
||||||
{
|
tmp = gfc_trans_assignment (init_expr, rhs, false, false, true,
|
||||||
/* copy_class_to_class can be used for class arrays, too.
|
false);
|
||||||
It just needs to be ensured, that the decl_saved_descriptor
|
flag_realloc_lhs = realloc_lhs;
|
||||||
has a way to get to the vptr. */
|
/* Free the expression allocated for init_expr. */
|
||||||
tree to;
|
gfc_free_expr (init_expr);
|
||||||
to = VAR_P (se.expr) ? se.expr : TREE_OPERAND (se.expr, 0);
|
if (rhs != e3rhs)
|
||||||
tmp = gfc_copy_class_to_class (expr3, to,
|
gfc_free_expr (rhs);
|
||||||
nelems, upoly_expr);
|
|
||||||
}
|
|
||||||
else if (al->expr->ts.type == BT_CLASS)
|
|
||||||
{
|
|
||||||
gfc_actual_arglist *actual, *last_arg;
|
|
||||||
gfc_expr *ppc;
|
|
||||||
gfc_code *ppc_code;
|
|
||||||
gfc_ref *ref, *dataref;
|
|
||||||
gfc_expr *rhs = e3rhs ? e3rhs : gfc_copy_expr (code->expr3);
|
|
||||||
|
|
||||||
/* Do a polymorphic deep copy. */
|
|
||||||
actual = gfc_get_actual_arglist ();
|
|
||||||
actual->expr = gfc_copy_expr (rhs);
|
|
||||||
if (rhs->ts.type == BT_CLASS)
|
|
||||||
gfc_add_data_component (actual->expr);
|
|
||||||
last_arg = actual->next = gfc_get_actual_arglist ();
|
|
||||||
last_arg->expr = gfc_copy_expr (al->expr);
|
|
||||||
last_arg->expr->ts.type = BT_CLASS;
|
|
||||||
gfc_add_data_component (last_arg->expr);
|
|
||||||
|
|
||||||
dataref = NULL;
|
|
||||||
/* Make sure we go up through the reference chain to
|
|
||||||
the _data reference, where the arrayspec is found. */
|
|
||||||
for (ref = last_arg->expr->ref; ref; ref = ref->next)
|
|
||||||
if (ref->type == REF_COMPONENT
|
|
||||||
&& strcmp (ref->u.c.component->name, "_data") == 0)
|
|
||||||
dataref = ref;
|
|
||||||
|
|
||||||
if (dataref && dataref->u.c.component->as)
|
|
||||||
{
|
|
||||||
gfc_array_spec *as = dataref->u.c.component->as;
|
|
||||||
gfc_free_ref_list (dataref->next);
|
|
||||||
dataref->next = NULL;
|
|
||||||
gfc_add_full_array_ref (last_arg->expr, as);
|
|
||||||
gfc_resolve_expr (last_arg->expr);
|
|
||||||
gcc_assert (last_arg->expr->ts.type == BT_CLASS
|
|
||||||
|| last_arg->expr->ts.type == BT_DERIVED);
|
|
||||||
last_arg->expr->ts.type = BT_CLASS;
|
|
||||||
}
|
|
||||||
if (rhs->ts.type == BT_CLASS)
|
|
||||||
{
|
|
||||||
if (rhs->ref)
|
|
||||||
ppc = gfc_find_and_cut_at_last_class_ref (rhs);
|
|
||||||
else
|
|
||||||
ppc = gfc_copy_expr (rhs);
|
|
||||||
gfc_add_vptr_component (ppc);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ppc = gfc_lval_expr_from_sym (gfc_find_vtab (&rhs->ts));
|
|
||||||
gfc_add_component_ref (ppc, "_copy");
|
|
||||||
|
|
||||||
ppc_code = gfc_get_code (EXEC_CALL);
|
|
||||||
ppc_code->resolved_sym = ppc->symtree->n.sym;
|
|
||||||
ppc_code->loc = al->expr->where;
|
|
||||||
/* Although '_copy' is set to be elemental in class.c, it is
|
|
||||||
not staying that way. Find out why, sometime.... */
|
|
||||||
ppc_code->resolved_sym->attr.elemental = 1;
|
|
||||||
ppc_code->ext.actual = actual;
|
|
||||||
ppc_code->expr1 = ppc;
|
|
||||||
/* Since '_copy' is elemental, the scalarizer will take care
|
|
||||||
of arrays in gfc_trans_call. */
|
|
||||||
tmp = gfc_trans_call (ppc_code, true, NULL, NULL, false);
|
|
||||||
/* We need to add the
|
|
||||||
if (al_len > 0)
|
|
||||||
al_vptr->copy (expr3_data, al_data, expr3_len, al_len);
|
|
||||||
else
|
|
||||||
al_vptr->copy (expr3_data, al_data);
|
|
||||||
block, because al is unlimited polymorphic or a deferred
|
|
||||||
length char array, whose copy routine needs the array lengths
|
|
||||||
as third and fourth arguments. */
|
|
||||||
if (al_len && UNLIMITED_POLY (code->expr3))
|
|
||||||
{
|
|
||||||
tree stdcopy, extcopy;
|
|
||||||
/* Add al%_len. */
|
|
||||||
last_arg->next = gfc_get_actual_arglist ();
|
|
||||||
last_arg = last_arg->next;
|
|
||||||
last_arg->expr = gfc_find_and_cut_at_last_class_ref (
|
|
||||||
al->expr);
|
|
||||||
gfc_add_len_component (last_arg->expr);
|
|
||||||
/* Add expr3's length. */
|
|
||||||
last_arg->next = gfc_get_actual_arglist ();
|
|
||||||
last_arg = last_arg->next;
|
|
||||||
if (code->expr3->ts.type == BT_CLASS)
|
|
||||||
{
|
|
||||||
last_arg->expr =
|
|
||||||
gfc_find_and_cut_at_last_class_ref (code->expr3);
|
|
||||||
gfc_add_len_component (last_arg->expr);
|
|
||||||
}
|
|
||||||
else if (code->expr3->ts.type == BT_CHARACTER)
|
|
||||||
last_arg->expr =
|
|
||||||
gfc_copy_expr (code->expr3->ts.u.cl->length);
|
|
||||||
else
|
|
||||||
gcc_unreachable ();
|
|
||||||
|
|
||||||
stdcopy = tmp;
|
|
||||||
extcopy = gfc_trans_call (ppc_code, true, NULL, NULL, false);
|
|
||||||
|
|
||||||
tmp = fold_build2_loc (input_location, GT_EXPR,
|
|
||||||
boolean_type_node, expr3_len,
|
|
||||||
integer_zero_node);
|
|
||||||
tmp = fold_build3_loc (input_location, COND_EXPR,
|
|
||||||
void_type_node, tmp, extcopy, stdcopy);
|
|
||||||
}
|
|
||||||
gfc_free_statements (ppc_code);
|
|
||||||
if (rhs != e3rhs)
|
|
||||||
gfc_free_expr (rhs);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Switch off automatic reallocation since we have just
|
|
||||||
done the ALLOCATE. */
|
|
||||||
int realloc_lhs = flag_realloc_lhs;
|
|
||||||
gfc_expr *init_expr = gfc_expr_to_initialize (expr);
|
|
||||||
flag_realloc_lhs = 0;
|
|
||||||
tmp = gfc_trans_assignment (init_expr, e3rhs, false, false);
|
|
||||||
flag_realloc_lhs = realloc_lhs;
|
|
||||||
/* Free the expression allocated for init_expr. */
|
|
||||||
gfc_free_expr (init_expr);
|
|
||||||
}
|
|
||||||
gfc_add_expr_to_block (&block, tmp);
|
gfc_add_expr_to_block (&block, tmp);
|
||||||
}
|
}
|
||||||
else if (code->expr3 && code->expr3->mold
|
else if (code->expr3 && code->expr3->mold
|
||||||
&& code->expr3->ts.type == BT_CLASS)
|
&& code->expr3->ts.type == BT_CLASS)
|
||||||
{
|
{
|
||||||
/* Since the _vptr has already been assigned to the allocate
|
/* Use class_init_assign to initialize expr. */
|
||||||
object, we can use gfc_copy_class_to_class in its
|
gfc_code *ini;
|
||||||
initialization mode. */
|
ini = gfc_get_code (EXEC_INIT_ASSIGN);
|
||||||
tmp = TREE_OPERAND (se.expr, 0);
|
ini->expr1 = gfc_find_and_cut_at_last_class_ref (expr);
|
||||||
tmp = gfc_copy_class_to_class (NULL_TREE, tmp, nelems,
|
tmp = gfc_trans_class_init_assign (ini);
|
||||||
upoly_expr);
|
gfc_free_statements (ini);
|
||||||
gfc_add_expr_to_block (&block, tmp);
|
gfc_add_expr_to_block (&block, tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
gfc_free_expr (expr);
|
gfc_free_expr (expr);
|
||||||
} // for-loop
|
} // for-loop
|
||||||
|
|
||||||
if (e3rhs)
|
if (e3rhs)
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ tree gfc_trans_assign (gfc_code *);
|
||||||
tree gfc_trans_pointer_assign (gfc_code *);
|
tree gfc_trans_pointer_assign (gfc_code *);
|
||||||
tree gfc_trans_init_assign (gfc_code *);
|
tree gfc_trans_init_assign (gfc_code *);
|
||||||
tree gfc_trans_class_init_assign (gfc_code *);
|
tree gfc_trans_class_init_assign (gfc_code *);
|
||||||
tree gfc_trans_class_assign (gfc_expr *, gfc_expr *, gfc_exec_op);
|
|
||||||
|
|
||||||
/* trans-stmt.c */
|
/* trans-stmt.c */
|
||||||
tree gfc_trans_cycle (gfc_code *);
|
tree gfc_trans_cycle (gfc_code *);
|
||||||
|
|
|
||||||
|
|
@ -1704,10 +1704,7 @@ trans_code (gfc_code * code, tree cond)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXEC_ASSIGN:
|
case EXEC_ASSIGN:
|
||||||
if (code->expr1->ts.type == BT_CLASS)
|
res = gfc_trans_assign (code);
|
||||||
res = gfc_trans_class_assign (code->expr1, code->expr2, code->op);
|
|
||||||
else
|
|
||||||
res = gfc_trans_assign (code);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXEC_LABEL_ASSIGN:
|
case EXEC_LABEL_ASSIGN:
|
||||||
|
|
@ -1715,16 +1712,7 @@ trans_code (gfc_code * code, tree cond)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXEC_POINTER_ASSIGN:
|
case EXEC_POINTER_ASSIGN:
|
||||||
if (code->expr1->ts.type == BT_CLASS)
|
res = gfc_trans_pointer_assign (code);
|
||||||
res = gfc_trans_class_assign (code->expr1, code->expr2, code->op);
|
|
||||||
else if (UNLIMITED_POLY (code->expr2)
|
|
||||||
&& code->expr1->ts.type == BT_DERIVED
|
|
||||||
&& (code->expr1->ts.u.derived->attr.sequence
|
|
||||||
|| code->expr1->ts.u.derived->attr.is_bind_c))
|
|
||||||
/* F2003: C717 */
|
|
||||||
res = gfc_trans_class_assign (code->expr1, code->expr2, code->op);
|
|
||||||
else
|
|
||||||
res = gfc_trans_pointer_assign (code);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXEC_INIT_ASSIGN:
|
case EXEC_INIT_ASSIGN:
|
||||||
|
|
|
||||||
|
|
@ -699,7 +699,8 @@ tree gfc_call_realloc (stmtblock_t *, tree, tree);
|
||||||
tree gfc_trans_structure_assign (tree, gfc_expr *, bool);
|
tree gfc_trans_structure_assign (tree, gfc_expr *, bool);
|
||||||
|
|
||||||
/* Generate code for an assignment, includes scalarization. */
|
/* Generate code for an assignment, includes scalarization. */
|
||||||
tree gfc_trans_assignment (gfc_expr *, gfc_expr *, bool, bool);
|
tree gfc_trans_assignment (gfc_expr *, gfc_expr *, bool, bool, bool p = false,
|
||||||
|
bool a = true);
|
||||||
|
|
||||||
/* Generate code for a pointer assignment. */
|
/* Generate code for a pointer assignment. */
|
||||||
tree gfc_trans_pointer_assignment (gfc_expr *, gfc_expr *);
|
tree gfc_trans_pointer_assignment (gfc_expr *, gfc_expr *);
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,18 @@
|
||||||
|
2016-10-22 Andre Vehreschild <vehre@gcc.gnu.org>
|
||||||
|
|
||||||
|
Forgot to add on original commit.
|
||||||
|
* gfortran.dg/coarray_alloc_comp_2.f08: New test.
|
||||||
|
|
||||||
|
2016-10-22 Andre Vehreschild <vehre@gcc.gnu.org>
|
||||||
|
|
||||||
|
PR fortran/43366
|
||||||
|
PR fortran/57117
|
||||||
|
PR fortran/61337
|
||||||
|
* gfortran.dg/alloc_comp_class_5.f03: New test.
|
||||||
|
* gfortran.dg/class_allocate_21.f90: New test.
|
||||||
|
* gfortran.dg/class_allocate_22.f90: New test.
|
||||||
|
* gfortran.dg/realloc_on_assign_27.f08: New test.
|
||||||
|
|
||||||
2016-10-21 Jeff Law <law@redhat.com>
|
2016-10-21 Jeff Law <law@redhat.com>
|
||||||
|
|
||||||
* PR tree-optimization/71947
|
* PR tree-optimization/71947
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,70 @@
|
||||||
|
! { dg-do run }
|
||||||
|
!
|
||||||
|
! Contributed by Vladimir Fuka
|
||||||
|
! Check that pr61337 is fixed.
|
||||||
|
|
||||||
|
module array_list
|
||||||
|
|
||||||
|
type container
|
||||||
|
class(*), allocatable :: items(:)
|
||||||
|
end type
|
||||||
|
|
||||||
|
contains
|
||||||
|
|
||||||
|
subroutine add_item(a, e)
|
||||||
|
type(container),allocatable,intent(inout) :: a(:)
|
||||||
|
class(*),intent(in) :: e(:)
|
||||||
|
type(container),allocatable :: tmp(:)
|
||||||
|
|
||||||
|
if (.not.allocated(a)) then
|
||||||
|
allocate(a(1))
|
||||||
|
allocate(a(1)%items(size(e)), source = e)
|
||||||
|
else
|
||||||
|
call move_alloc(a,tmp)
|
||||||
|
allocate(a(size(tmp)+1))
|
||||||
|
a(1:size(tmp)) = tmp
|
||||||
|
allocate(a(size(tmp)+1)%items(size(e)), source=e)
|
||||||
|
end if
|
||||||
|
end subroutine
|
||||||
|
|
||||||
|
end module
|
||||||
|
|
||||||
|
program test_pr61337
|
||||||
|
|
||||||
|
use array_list
|
||||||
|
|
||||||
|
type(container), allocatable :: a_list(:)
|
||||||
|
integer(kind = 8) :: i
|
||||||
|
|
||||||
|
call add_item(a_list, [1, 2])
|
||||||
|
call add_item(a_list, [3.0_8, 4.0_8])
|
||||||
|
call add_item(a_list, [.true., .false.])
|
||||||
|
|
||||||
|
if (size(a_list) /= 3) call abort()
|
||||||
|
do i = 1, size(a_list)
|
||||||
|
call checkarr(a_list(i))
|
||||||
|
end do
|
||||||
|
|
||||||
|
deallocate(a_list)
|
||||||
|
|
||||||
|
contains
|
||||||
|
|
||||||
|
subroutine checkarr(c)
|
||||||
|
type(container) :: c
|
||||||
|
|
||||||
|
if (allocated(c%items)) then
|
||||||
|
select type (x=>c%items)
|
||||||
|
type is (integer)
|
||||||
|
if (any(x /= [1, 2])) call abort()
|
||||||
|
type is (real(kind=8))
|
||||||
|
if (any(x /= [3.0_8, 4.0_8])) call abort()
|
||||||
|
type is (logical)
|
||||||
|
if (any(x .neqv. [.true., .false.])) call abort()
|
||||||
|
class default
|
||||||
|
call abort()
|
||||||
|
end select
|
||||||
|
else
|
||||||
|
call abort()
|
||||||
|
end if
|
||||||
|
end subroutine
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
! { dg-do run }
|
||||||
|
!
|
||||||
|
! Testcase for pr57117
|
||||||
|
|
||||||
|
implicit none
|
||||||
|
|
||||||
|
type :: ti
|
||||||
|
integer :: i
|
||||||
|
end type
|
||||||
|
|
||||||
|
class(ti), allocatable :: x(:,:), z(:)
|
||||||
|
integer :: i
|
||||||
|
|
||||||
|
allocate(x(3,3))
|
||||||
|
x%i = reshape([( i, i = 1, 9 )], [3, 3])
|
||||||
|
allocate(z(9), source=reshape(x, (/ 9 /)))
|
||||||
|
|
||||||
|
if (any( z%i /= [( i, i = 1, 9 )])) call abort()
|
||||||
|
deallocate (x, z)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
! { dg-do run }
|
||||||
|
!
|
||||||
|
! Check pr57117 is fixed.
|
||||||
|
|
||||||
|
program pr57117
|
||||||
|
implicit none
|
||||||
|
|
||||||
|
type :: ti
|
||||||
|
integer :: i
|
||||||
|
end type
|
||||||
|
|
||||||
|
class(ti), allocatable :: x(:,:), y(:,:)
|
||||||
|
integer :: i
|
||||||
|
|
||||||
|
allocate(x(2,6))
|
||||||
|
select type (x)
|
||||||
|
class is (ti)
|
||||||
|
x%i = reshape([(i,i=1, 12)],[2,6])
|
||||||
|
end select
|
||||||
|
allocate(y, source=transpose(x))
|
||||||
|
|
||||||
|
if (any( ubound(y) /= [6,2])) call abort()
|
||||||
|
if (any(reshape(y(:,:)%i, [12]) /= [ 1,3,5,7,9,11, 2,4,6,8,10,12])) call abort()
|
||||||
|
deallocate (x,y)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
! { dg-do run }
|
||||||
|
! { dg-options "-fcoarray=lib -lcaf_single" }
|
||||||
|
|
||||||
|
! Contributed by Damian Rouson
|
||||||
|
! Check the new _caf_send_by_ref()-routine.
|
||||||
|
|
||||||
|
program main
|
||||||
|
|
||||||
|
implicit none
|
||||||
|
|
||||||
|
type :: mytype
|
||||||
|
integer :: i
|
||||||
|
integer, allocatable :: indices(:)
|
||||||
|
real, dimension(2,5,3) :: volume
|
||||||
|
integer, allocatable :: scalar
|
||||||
|
integer :: j
|
||||||
|
integer, allocatable :: matrix(:,:)
|
||||||
|
real, allocatable :: dynvol(:,:,:)
|
||||||
|
end type
|
||||||
|
|
||||||
|
type arrtype
|
||||||
|
type(mytype), allocatable :: vec(:)
|
||||||
|
type(mytype), allocatable :: mat(:,:)
|
||||||
|
end type arrtype
|
||||||
|
|
||||||
|
type(mytype), save :: object[*]
|
||||||
|
type(arrtype), save :: bar[*]
|
||||||
|
integer :: i,j,me,neighbor
|
||||||
|
integer :: idx(5)
|
||||||
|
real, allocatable :: volume(:,:,:), vol2(:,:,:)
|
||||||
|
real :: vol_static(2,5,3)
|
||||||
|
|
||||||
|
idx = (/ 1,2,1,7,5 /)
|
||||||
|
|
||||||
|
me=this_image()
|
||||||
|
neighbor = merge(1,me+1,me==num_images())
|
||||||
|
object[neighbor]%indices=[(i,i=1,5)]
|
||||||
|
object[neighbor]%i = 37
|
||||||
|
object[neighbor]%scalar = 42
|
||||||
|
vol_static = reshape([(i, i=1, 2*5*3)], [2, 5, 3])
|
||||||
|
object[neighbor]%volume = vol_static
|
||||||
|
object[neighbor]%matrix = reshape([(i, i=1, 70)], [10, 7])
|
||||||
|
object[neighbor]%dynvol = vol_static
|
||||||
|
sync all
|
||||||
|
if (object%scalar /= 42) call abort()
|
||||||
|
if (any( object%indices /= [1,2,3,4,5] )) call abort()
|
||||||
|
if (any( object%matrix /= reshape([(i, i=1, 70)], [10, 7]))) call abort()
|
||||||
|
if (any( object%volume /= vol_static)) call abort()
|
||||||
|
if (any( object%dynvol /= vol_static)) call abort()
|
||||||
|
|
||||||
|
vol2 = vol_static
|
||||||
|
vol2(:, ::2, :) = 42
|
||||||
|
object[neighbor]%volume(:, ::2, :) = 42
|
||||||
|
object[neighbor]%dynvol(:, ::2, :) = 42
|
||||||
|
if (any( object%volume /= vol2)) call abort()
|
||||||
|
if (any( object%dynvol /= vol2)) call abort()
|
||||||
|
|
||||||
|
allocate(bar%vec(-2:2))
|
||||||
|
|
||||||
|
bar[neighbor]%vec(1)%volume = vol_static
|
||||||
|
if (any(bar%vec(1)%volume /= vol_static)) call abort()
|
||||||
|
|
||||||
|
i = 15
|
||||||
|
bar[neighbor]%vec(1)%scalar = i
|
||||||
|
if (.not. allocated(bar%vec(1)%scalar)) call abort()
|
||||||
|
if (bar%vec(1)%scalar /= 15) call abort()
|
||||||
|
|
||||||
|
bar[neighbor]%vec(0)%scalar = 27
|
||||||
|
if (.not. allocated(bar%vec(0)%scalar)) call abort()
|
||||||
|
if (bar%vec(0)%scalar /= 27) call abort()
|
||||||
|
|
||||||
|
bar[neighbor]%vec(1)%indices = [ 3, 4, 15 ]
|
||||||
|
allocate(bar%vec(2)%indices(5))
|
||||||
|
bar[neighbor]%vec(2)%indices = 89
|
||||||
|
|
||||||
|
if (.not. allocated(bar%vec(1)%indices)) call abort()
|
||||||
|
if (allocated(bar%vec(-2)%indices)) call abort()
|
||||||
|
if (allocated(bar%vec(-1)%indices)) call abort()
|
||||||
|
if (allocated(bar%vec( 0)%indices)) call abort()
|
||||||
|
if (.not. allocated(bar%vec( 2)%indices)) call abort()
|
||||||
|
if (any(bar%vec(2)%indices /= 89)) call abort()
|
||||||
|
|
||||||
|
if (any (bar%vec(1)%indices /= [ 3,4,15])) call abort()
|
||||||
|
end program
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
! { dg-do run }
|
||||||
|
|
||||||
|
type :: t
|
||||||
|
integer :: i
|
||||||
|
end type
|
||||||
|
|
||||||
|
type, extends(t) :: r
|
||||||
|
real :: r
|
||||||
|
end type
|
||||||
|
|
||||||
|
class(t), allocatable :: x
|
||||||
|
type(r) :: y = r (3, 42)
|
||||||
|
|
||||||
|
x = y
|
||||||
|
if (x%i /= 3) call abort()
|
||||||
|
select type(x)
|
||||||
|
class is (r)
|
||||||
|
if (x%r /= 42.0) call abort()
|
||||||
|
class default
|
||||||
|
call abort()
|
||||||
|
end select
|
||||||
|
end
|
||||||
|
|
||||||
Loading…
Reference in New Issue