aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/resolve.c
diff options
context:
space:
mode:
authorpault <pault@138bc75d-0d04-0410-961f-82ee72b054a4>2016-10-21 12:50:56 +0000
committerpault <pault@138bc75d-0d04-0410-961f-82ee72b054a4>2016-10-21 12:50:56 +0000
commit60e91af4cf1337f3ce8d61b5c8d6b23aec89b4dd (patch)
tree8c272f3218f0e29691939ff45b3f7f5bd4e1a7af /gcc/fortran/resolve.c
parentbc5cd04e5abf132003d84c8b0fb9420479b70d35 (diff)
2016-10-21 Paul Thomas <pault@gcc.gnu.org>
PR fortran/69566 * resolve.c (fixup_array_ref): New function. (resolve_select_type): Gather up the rank and array reference, if any, from the selector. Fix up the 'associate name' and the 'associate entities' as necessary. * trans-expr.c (gfc_conv_class_to_class): If the symbol backend decl is a FUNCTION_DECL, use the 'fake_result_decl' instead. 2016-10-21 Paul Thomas <pault@gcc.gnu.org> PR fortran/69566 * gfortran.dg/select_type_37.f03: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@241403 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/fortran/resolve.c')
-rw-r--r--gcc/fortran/resolve.c79
1 files changed, 78 insertions, 1 deletions
diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c
index 87178a41333..c4426f81320 100644
--- a/gcc/fortran/resolve.c
+++ b/gcc/fortran/resolve.c
@@ -8327,6 +8327,48 @@ resolve_assoc_var (gfc_symbol* sym, bool resolve_target)
}
+/* Ensure that SELECT TYPE expressions have the correct rank and a full
+ array reference, where necessary. The symbols are artificial and so
+ the dimension attribute and arrayspec can also be set. In addition,
+ sometimes the expr1 arrives as BT_DERIVED, when the symbol is BT_CLASS.
+ This is corrected here as well.*/
+
+static void
+fixup_array_ref (gfc_expr **expr1, gfc_expr *expr2,
+ int rank, gfc_ref *ref)
+{
+ gfc_ref *nref = (*expr1)->ref;
+ gfc_symbol *sym1 = (*expr1)->symtree->n.sym;
+ gfc_symbol *sym2 = expr2 ? expr2->symtree->n.sym : NULL;
+ (*expr1)->rank = rank;
+ if (sym1->ts.type == BT_CLASS)
+ {
+ if ((*expr1)->ts.type != BT_CLASS)
+ (*expr1)->ts = sym1->ts;
+
+ CLASS_DATA (sym1)->attr.dimension = 1;
+ if (CLASS_DATA (sym1)->as == NULL && sym2)
+ CLASS_DATA (sym1)->as
+ = gfc_copy_array_spec (CLASS_DATA (sym2)->as);
+ }
+ else
+ {
+ sym1->attr.dimension = 1;
+ if (sym1->as == NULL && sym2)
+ sym1->as = gfc_copy_array_spec (sym2->as);
+ }
+
+ for (; nref; nref = nref->next)
+ if (nref->next == NULL)
+ break;
+
+ if (ref && nref && nref->type != REF_ARRAY)
+ nref->next = gfc_copy_ref (ref);
+ else if (ref && !nref)
+ (*expr1)->ref = gfc_copy_ref (ref);
+}
+
+
/* Resolve a SELECT TYPE statement. */
static void
@@ -8341,6 +8383,8 @@ resolve_select_type (gfc_code *code, gfc_namespace *old_ns)
gfc_namespace *ns;
int error = 0;
int charlen = 0;
+ int rank = 0;
+ gfc_ref* ref = NULL;
ns = code->ext.block.ns;
gfc_resolve (ns);
@@ -8468,6 +8512,31 @@ resolve_select_type (gfc_code *code, gfc_namespace *old_ns)
else
code->ext.block.assoc = NULL;
+ /* Ensure that the selector rank and arrayspec are available to
+ correct expressions in which they might be missing. */
+ if (code->expr2 && code->expr2->rank)
+ {
+ rank = code->expr2->rank;
+ for (ref = code->expr2->ref; ref; ref = ref->next)
+ if (ref->next == NULL)
+ break;
+ if (ref && ref->type == REF_ARRAY)
+ ref = gfc_copy_ref (ref);
+
+ /* Fixup expr1 if necessary. */
+ if (rank)
+ fixup_array_ref (&code->expr1, code->expr2, rank, ref);
+ }
+ else if (code->expr1->rank)
+ {
+ rank = code->expr1->rank;
+ for (ref = code->expr1->ref; ref; ref = ref->next)
+ if (ref->next == NULL)
+ break;
+ if (ref && ref->type == REF_ARRAY)
+ ref = gfc_copy_ref (ref);
+ }
+
/* Add EXEC_SELECT to switch on type. */
new_st = gfc_get_code (code->op);
new_st->expr1 = code->expr1;
@@ -8533,7 +8602,12 @@ resolve_select_type (gfc_code *code, gfc_namespace *old_ns)
st->n.sym->assoc->target = gfc_get_variable_expr (code->expr1->symtree);
st->n.sym->assoc->target->where = code->expr1->where;
if (c->ts.type != BT_CLASS && c->ts.type != BT_UNKNOWN)
- gfc_add_data_component (st->n.sym->assoc->target);
+ {
+ gfc_add_data_component (st->n.sym->assoc->target);
+ /* Fixup the target expression if necessary. */
+ if (rank)
+ fixup_array_ref (&st->n.sym->assoc->target, NULL, rank, ref);
+ }
new_st = gfc_get_code (EXEC_BLOCK);
new_st->ext.block.ns = gfc_build_block_ns (ns);
@@ -8672,6 +8746,9 @@ resolve_select_type (gfc_code *code, gfc_namespace *old_ns)
gfc_resolve_blocks (code->block, gfc_current_ns);
gfc_current_ns = old_ns;
+ if (ref)
+ free (ref);
+
resolve_select (code, true);
}