]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR fortran/41600 ([OOP] SELECT TYPE with associate-name => exp: Arrays not supported)
authorPaul Thomas <pault@gcc.gnu.org>
Sat, 5 May 2012 08:49:43 +0000 (08:49 +0000)
committerPaul Thomas <pault@gcc.gnu.org>
Sat, 5 May 2012 08:49:43 +0000 (08:49 +0000)
2012-05-05  Paul Thomas  <pault@gcc.gnu.org>

PR fortran/41600
* trans-array.c (build_array_ref): New static function.
(gfc_conv_array_ref, gfc_get_dataptr_offset): Call it.
* trans-expr.c (gfc_get_vptr_from_expr): New function.
(gfc_conv_derived_to_class): Add a new argument for a caller
supplied vptr and use it if it is not NULL.
(gfc_conv_procedure_call): Add NULL to call to above.
symbol.c (gfc_is_associate_pointer): Return true if symbol is
a class object.
* trans-stmt.c (trans_associate_var): Handle class associate-
names.
* expr.c (gfc_get_variable_expr): Supply the array-spec if
possible.
* trans-types.c (gfc_typenode_for_spec): Set GFC_CLASS_TYPE_P
for class types.
* trans.h : Add prototypes for gfc_get_vptr_from_expr and
gfc_conv_derived_to_class. Define GFC_CLASS_TYPE_P.
* resolve.c (resolve_variable): For class arrays, ensure that
the target expression has all the necessary _data references.
(resolve_assoc_var): Throw a "not yet implemented" error for
class array selectors that need a temporary.
* match.c (copy_ts_from_selector_to_associate,
select_derived_set_tmp, select_class_set_tmp): New functions.
(select_type_set_tmp): Call one of last two new functions.
(gfc_match_select_type): Copy_ts_from_selector_to_associate is
called if associate-name is typed.

PR fortran/53191
* resolve.c (resolve_ref): C614 applied to class expressions.

2012-05-05  Paul Thomas  <pault@gcc.gnu.org>

PR fortran/41600
* gfortran.dg/select_type_26.f03 : New test.
* gfortran.dg/select_type_27.f03 : New test.

PR fortran/53191
* gfortran.dg/select_type_28.f03 : New test.

From-SVN: r187192

14 files changed:
gcc/fortran/ChangeLog
gcc/fortran/expr.c
gcc/fortran/match.c
gcc/fortran/resolve.c
gcc/fortran/symbol.c
gcc/fortran/trans-array.c
gcc/fortran/trans-expr.c
gcc/fortran/trans-stmt.c
gcc/fortran/trans-types.c
gcc/fortran/trans.h
gcc/testsuite/ChangeLog
gcc/testsuite/gfortran.dg/select_type_26.f03 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/select_type_27.f03 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/select_type_28.f03 [new file with mode: 0644]

index a9b4195499dc0f2999c324b2fa1c138f1c252602..a9f1cecc46222cbe40f7d7ea845e51ab5af77812 100644 (file)
@@ -1,3 +1,35 @@
+2012-05-05  Paul Thomas  <pault@gcc.gnu.org>
+
+       PR fortran/41600
+       * trans-array.c (build_array_ref): New static function.
+       (gfc_conv_array_ref, gfc_get_dataptr_offset): Call it.
+       * trans-expr.c (gfc_get_vptr_from_expr): New function.
+       (gfc_conv_derived_to_class): Add a new argument for a caller
+       supplied vptr and use it if it is not NULL.
+       (gfc_conv_procedure_call): Add NULL to call to above.
+       symbol.c (gfc_is_associate_pointer): Return true if symbol is
+       a class object.
+       * trans-stmt.c (trans_associate_var): Handle class associate-
+       names.
+       * expr.c (gfc_get_variable_expr): Supply the array-spec if
+       possible.
+       * trans-types.c (gfc_typenode_for_spec): Set GFC_CLASS_TYPE_P
+       for class types.
+       * trans.h : Add prototypes for gfc_get_vptr_from_expr and
+       gfc_conv_derived_to_class. Define GFC_CLASS_TYPE_P.
+       * resolve.c (resolve_variable): For class arrays, ensure that
+       the target expression has all the necessary _data references.
+       (resolve_assoc_var): Throw a "not yet implemented" error for
+       class array selectors that need a temporary.
+       * match.c (copy_ts_from_selector_to_associate,
+       select_derived_set_tmp, select_class_set_tmp): New functions.
+       (select_type_set_tmp): Call one of last two new functions.
+       (gfc_match_select_type): Copy_ts_from_selector_to_associate is
+       called if associate-name is typed.
+
+       PR fortran/53191
+       * resolve.c (resolve_ref): C614 applied to class expressions.
+
 2012-05-05  Janne Blomqvist  <jb@gcc.gnu.org>
 
        PR fortran/49010
index d9614413e67eaacffa9511bb547381954132c2e9..93d5df654556c7b0b946ea8de4ad94dfae08f20c 100644 (file)
@@ -3821,6 +3821,9 @@ gfc_get_variable_expr (gfc_symtree *var)
       e->ref = gfc_get_ref ();
       e->ref->type = REF_ARRAY;
       e->ref->u.ar.type = AR_FULL;
+      e->ref->u.ar.as = gfc_copy_array_spec (var->n.sym->ts.type == BT_CLASS
+                                            ? CLASS_DATA (var->n.sym)->as
+                                            : var->n.sym->as);
     }
 
   return e;
index 15edfc36db1eff20d4b19f073cf389bcf8c4810f..3d119180a73a058c6cd1343099a1616d643c284b 100644 (file)
@@ -5112,6 +5112,78 @@ gfc_match_select (void)
 }
 
 
+/* Transfer the selector typespec to the associate name.  */
+
+static void
+copy_ts_from_selector_to_associate (gfc_expr *associate, gfc_expr *selector)
+{
+  gfc_ref *ref;
+  gfc_symbol *assoc_sym;
+
+  assoc_sym = associate->symtree->n.sym;
+
+  /* Ensure that any array reference is resolved.  */
+  gfc_resolve_expr (selector);
+
+  /* At this stage the expression rank and arrayspec dimensions have
+     not been completely sorted out. We must get the expr2->rank
+     right here, so that the correct class container is obtained.  */
+  ref = selector->ref;
+  while (ref && ref->next)
+    ref = ref->next;
+
+  if (selector->ts.type == BT_CLASS
+       && CLASS_DATA (selector)->as
+       && ref && ref->type == REF_ARRAY)
+    {
+      if (ref->u.ar.type == AR_FULL)
+       selector->rank = CLASS_DATA (selector)->as->rank;
+      else if (ref->u.ar.type == AR_SECTION)
+       selector->rank = ref->u.ar.dimen;
+      else
+       selector->rank = 0;
+    }
+
+  if (selector->ts.type != BT_CLASS)
+    {
+      /* The correct class container has to be available.  */
+      if (selector->rank)
+       {
+         assoc_sym->attr.dimension = 1;
+         assoc_sym->as = gfc_get_array_spec ();
+         assoc_sym->as->rank = selector->rank;
+         assoc_sym->as->type = AS_DEFERRED;
+       }
+      else
+       assoc_sym->as = NULL;
+
+      assoc_sym->ts.type = BT_CLASS;
+      assoc_sym->ts.u.derived = selector->ts.u.derived;
+      assoc_sym->attr.pointer = 1;
+      gfc_build_class_symbol (&assoc_sym->ts, &assoc_sym->attr,
+                             &assoc_sym->as, false);
+    }
+  else
+    {
+      /* The correct class container has to be available.  */
+      if (selector->rank)
+       {
+         assoc_sym->attr.dimension = 1;
+         assoc_sym->as = gfc_get_array_spec ();
+         assoc_sym->as->rank = selector->rank;
+         assoc_sym->as->type = AS_DEFERRED;
+       }
+      else
+       assoc_sym->as = NULL;
+      assoc_sym->ts.type = BT_CLASS;
+      assoc_sym->ts.u.derived = CLASS_DATA (selector)->ts.u.derived;
+      assoc_sym->attr.pointer = 1;
+      gfc_build_class_symbol (&assoc_sym->ts, &assoc_sym->attr,
+                             &assoc_sym->as, false);
+    }
+}
+
+
 /* Push the current selector onto the SELECT TYPE stack.  */
 
 static void
@@ -5126,64 +5198,103 @@ select_type_push (gfc_symbol *sel)
 }
 
 
-/* Set the temporary for the current SELECT TYPE selector.  */
+/* Set the temporary for the current derived type SELECT TYPE selector.  */
 
-static void
-select_type_set_tmp (gfc_typespec *ts)
+static gfc_symtree *
+select_derived_set_tmp (gfc_typespec *ts)
 {
   char name[GFC_MAX_SYMBOL_LEN];
   gfc_symtree *tmp;
   
-  if (!ts)
+  sprintf (name, "__tmp_type_%s", ts->u.derived->name);
+  gfc_get_sym_tree (name, gfc_current_ns, &tmp, false);
+  gfc_add_type (tmp->n.sym, ts, NULL);
+
+  /* Copy across the array spec to the selector.  */
+  if (select_type_stack->selector->ts.type == BT_CLASS
+      && select_type_stack->selector->attr.class_ok
+      && (CLASS_DATA (select_type_stack->selector)->attr.dimension
+         || CLASS_DATA (select_type_stack->selector)->attr.codimension))
     {
-      select_type_stack->tmp = NULL;
-      return;
+      tmp->n.sym->attr.dimension
+               = CLASS_DATA (select_type_stack->selector)->attr.dimension;
+      tmp->n.sym->attr.codimension
+               = CLASS_DATA (select_type_stack->selector)->attr.codimension;
+      tmp->n.sym->as
+       = gfc_copy_array_spec (CLASS_DATA (select_type_stack->selector)->as);
     }
+
+  gfc_set_sym_referenced (tmp->n.sym);
+  gfc_add_flavor (&tmp->n.sym->attr, FL_VARIABLE, name, NULL);
+  tmp->n.sym->attr.select_type_temporary = 1;
+
+  return tmp;
+}
+
+
+/* Set the temporary for the current class SELECT TYPE selector.  */
+
+static gfc_symtree *
+select_class_set_tmp (gfc_typespec *ts)
+{
+  char name[GFC_MAX_SYMBOL_LEN];
+  gfc_symtree *tmp;
   
-  if (!gfc_type_is_extensible (ts->u.derived))
-    return;
+  if (select_type_stack->selector->ts.type == BT_CLASS
+      && !select_type_stack->selector->attr.class_ok)
+    return NULL;
 
-  if (ts->type == BT_CLASS)
-    sprintf (name, "__tmp_class_%s", ts->u.derived->name);
-  else
-    sprintf (name, "__tmp_type_%s", ts->u.derived->name);
+  sprintf (name, "__tmp_class_%s", ts->u.derived->name);
   gfc_get_sym_tree (name, gfc_current_ns, &tmp, false);
   gfc_add_type (tmp->n.sym, ts, NULL);
 
-/* Copy across the array spec to the selector, taking care as to
-   whether or not it is a class object or not.  */
+/* Copy across the array spec to the selector.  */
   if (select_type_stack->selector->ts.type == BT_CLASS
-      && select_type_stack->selector->attr.class_ok
       && (CLASS_DATA (select_type_stack->selector)->attr.dimension
          || CLASS_DATA (select_type_stack->selector)->attr.codimension))
     {
-      if (ts->type == BT_CLASS)
-       {
-         CLASS_DATA (tmp->n.sym)->attr.dimension
+      tmp->n.sym->attr.pointer = 1;
+      tmp->n.sym->attr.dimension
                = CLASS_DATA (select_type_stack->selector)->attr.dimension;
-         CLASS_DATA (tmp->n.sym)->attr.codimension
+      tmp->n.sym->attr.codimension
                = CLASS_DATA (select_type_stack->selector)->attr.codimension;
-         CLASS_DATA (tmp->n.sym)->as = gfc_get_array_spec ();
-         CLASS_DATA (tmp->n.sym)->as
-                       = CLASS_DATA (select_type_stack->selector)->as;
-       }
-      else
-       {
-         tmp->n.sym->attr.dimension
-               = CLASS_DATA (select_type_stack->selector)->attr.dimension;
-         tmp->n.sym->attr.codimension
-               = CLASS_DATA (select_type_stack->selector)->attr.codimension;
-         tmp->n.sym->as = gfc_get_array_spec ();
-         tmp->n.sym->as = CLASS_DATA (select_type_stack->selector)->as;
-       }
+      tmp->n.sym->as
+       = gfc_copy_array_spec (CLASS_DATA (select_type_stack->selector)->as);
     }
 
   gfc_set_sym_referenced (tmp->n.sym);
   gfc_add_flavor (&tmp->n.sym->attr, FL_VARIABLE, name, NULL);
   tmp->n.sym->attr.select_type_temporary = 1;
+  gfc_build_class_symbol (&tmp->n.sym->ts, &tmp->n.sym->attr,
+                         &tmp->n.sym->as, false);
+
+  return tmp;
+}
+
+
+static void
+select_type_set_tmp (gfc_typespec *ts)
+{
+  gfc_symtree *tmp;
+
+  if (!ts)
+    {
+      select_type_stack->tmp = NULL;
+      return;
+    }
+  
+  if (!gfc_type_is_extensible (ts->u.derived))
+    return;
+
+  /* Logic is a LOT clearer with separate functions for class and derived
+     type temporaries! There are not many more lines of code either.  */
   if (ts->type == BT_CLASS)
-    gfc_build_class_symbol (&tmp->n.sym->ts, &tmp->n.sym->attr,
-                           &tmp->n.sym->as, false);
+    tmp = select_class_set_tmp (ts);
+  else
+    tmp = select_derived_set_tmp (ts);
+
+  if (tmp == NULL)
+    return;
 
   /* Add an association for it, so the rest of the parser knows it is
      an associate-name.  The target will be set during resolution.  */
@@ -5194,7 +5305,7 @@ select_type_set_tmp (gfc_typespec *ts)
   select_type_stack->tmp = tmp;
 }
 
-
+  
 /* Match a SELECT TYPE statement.  */
 
 match
@@ -5204,6 +5315,7 @@ gfc_match_select_type (void)
   match m;
   char name[GFC_MAX_SYMBOL_LEN];
   bool class_array;
+  gfc_symbol *sym;
 
   m = gfc_match_label ();
   if (m == MATCH_ERROR)
@@ -5225,13 +5337,16 @@ gfc_match_select_type (void)
          m = MATCH_ERROR;
          goto cleanup;
        }
+
+      sym = expr1->symtree->n.sym;
       if (expr2->ts.type == BT_UNKNOWN)
-       expr1->symtree->n.sym->attr.untyped = 1;
+       sym->attr.untyped = 1;
       else
-       expr1->symtree->n.sym->ts = expr2->ts;
-      expr1->symtree->n.sym->attr.flavor = FL_VARIABLE;
-      expr1->symtree->n.sym->attr.referenced = 1;
-      expr1->symtree->n.sym->attr.class_ok = 1;
+       copy_ts_from_selector_to_associate (expr1, expr2);
+
+      sym->attr.flavor = FL_VARIABLE;
+      sym->attr.referenced = 1;
+      sym->attr.class_ok = 1;
     }
   else
     {
index e15d6e12d7daedd698b36de44d7c500af371ffe1..e5a49bcd5614b675862fb7e85d7ffc415b25a90c 100644 (file)
@@ -4904,14 +4904,19 @@ resolve_ref (gfc_expr *expr)
            {
              /* F03:C614.  */
              if (ref->u.c.component->attr.pointer
-                 || ref->u.c.component->attr.proc_pointer)
+                 || ref->u.c.component->attr.proc_pointer
+                 || (ref->u.c.component->ts.type == BT_CLASS
+                       && CLASS_DATA (ref->u.c.component)->attr.pointer))
                {
                  gfc_error ("Component to the right of a part reference "
                             "with nonzero rank must not have the POINTER "
                             "attribute at %L", &expr->where);
                  return FAILURE;
                }
-             else if (ref->u.c.component->attr.allocatable)
+             else if (ref->u.c.component->attr.allocatable
+                       || (ref->u.c.component->ts.type == BT_CLASS
+                           && CLASS_DATA (ref->u.c.component)->attr.allocatable))
+
                {
                  gfc_error ("Component to the right of a part reference "
                             "with nonzero rank must not have the ALLOCATABLE "
@@ -5081,9 +5086,15 @@ resolve_variable (gfc_expr *e)
     }
 
   /* If this is an associate-name, it may be parsed with an array reference
-     in error even though the target is scalar.  Fail directly in this case.  */
-  if (sym->assoc && !sym->attr.dimension && e->ref && e->ref->type == REF_ARRAY)
-    return FAILURE;
+     in error even though the target is scalar.  Fail directly in this case.
+     TODO Understand why class scalar expressions must be excluded.  */
+  if (sym->assoc && !(sym->ts.type == BT_CLASS && e->rank == 0))
+    {
+      if (sym->ts.type == BT_CLASS)
+       gfc_fix_class_refs (e);
+      if (!sym->attr.dimension && e->ref && e->ref->type == REF_ARRAY)
+       return FAILURE;
+    }
 
   if (sym->ts.type == BT_DERIVED && sym->ts.u.derived->attr.generic)
     sym->ts.u.derived = gfc_find_dt_in_generic (sym->ts.u.derived);
@@ -7941,7 +7952,7 @@ gfc_type_is_extensible (gfc_symbol *sym)
 }
 
 
-/* Resolve an associate name:  Resolve target and ensure the type-spec is
+/* Resolve an associate-name:  Resolve target and ensure the type-spec is
    correct as well as possibly the array-spec.  */
 
 static void
@@ -7997,8 +8008,25 @@ resolve_assoc_var (gfc_symbol* sym, bool resolve_target)
       sym->attr.dimension = 0;
       return;
     }
-  if (target->rank > 0)
+
+  /* We cannot deal with class selectors that need temporaries.  */
+  if (target->ts.type == BT_CLASS
+       && gfc_ref_needs_temporary_p (target->ref))
+    {
+      gfc_error ("CLASS selector at %L needs a temporary which is not "
+                "yet implemented", &target->where);
+      return;
+    }
+
+  if (target->ts.type != BT_CLASS && target->rank > 0)
     sym->attr.dimension = 1;
+  else if (target->ts.type == BT_CLASS)
+    gfc_fix_class_refs (target);
+
+  /* The associate-name will have a correct type by now. Make absolutely
+     sure that it has not picked up a dimension attribute.  */
+  if (sym->ts.type == BT_CLASS)
+    sym->attr.dimension = 0;
 
   if (sym->attr.dimension)
     {
index 46e5f56feee9f41731ec289e5aecba3bacff2fe3..6ca4ca330142a800b7324da062d661f8a441ca8c 100644 (file)
@@ -4882,6 +4882,9 @@ gfc_is_associate_pointer (gfc_symbol* sym)
   if (!sym->assoc)
     return false;
 
+  if (sym->ts.type == BT_CLASS)
+    return true;
+
   if (!sym->assoc->variable)
     return false;
 
index b54c95b4087d2e4cd682b55eefb40e1c818ee09a..b24d1c323ede58f1f57e80e86dfaa94725fe73d4 100644 (file)
@@ -3068,6 +3068,36 @@ add_to_offset (tree *cst_offset, tree *offset, tree t)
     }
 }
 
+
+static tree
+build_array_ref (tree desc, tree offset, tree decl)
+{
+  tree tmp;
+
+  /* Class array references need special treatment because the assigned
+     type size needs to be used to point to the element.  */ 
+  if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc))
+       && TREE_CODE (desc) == COMPONENT_REF
+       && GFC_CLASS_TYPE_P (TREE_TYPE (TREE_OPERAND (desc, 0))))
+    {
+      tree type = gfc_get_element_type (TREE_TYPE (desc));
+      tmp = TREE_OPERAND (desc, 0);
+      tmp = gfc_get_class_array_ref (offset, tmp);
+      tmp = fold_convert (build_pointer_type (type), tmp);
+      tmp = build_fold_indirect_ref_loc (input_location, tmp);
+    }
+  else
+    {
+      tmp = gfc_conv_array_data (desc);
+      tmp = build_fold_indirect_ref_loc (input_location, tmp);
+      tmp = gfc_build_array_ref (tmp, offset, decl);
+    }
+
+  return tmp;
+}
+
+
+
 /* Build an array reference.  se->expr already holds the array descriptor.
    This should be either a variable, indirect variable reference or component
    reference.  For arrays which do not have a descriptor, se->expr will be
@@ -3195,10 +3225,7 @@ gfc_conv_array_ref (gfc_se * se, gfc_array_ref * ar, gfc_symbol * sym,
     offset = fold_build2_loc (input_location, PLUS_EXPR,
                              gfc_array_index_type, offset, cst_offset);
 
-  /* Access the calculated element.  */
-  tmp = gfc_conv_array_data (se->expr);
-  tmp = build_fold_indirect_ref (tmp);
-  se->expr = gfc_build_array_ref (tmp, offset, sym->backend_decl);
+  se->expr = build_array_ref (se->expr, offset, sym->backend_decl);
 }
 
 
@@ -6010,10 +6037,7 @@ gfc_get_dataptr_offset (stmtblock_t *block, tree parm, tree desc, tree offset,
        return;
     }
 
-  tmp = gfc_conv_array_data (desc);
-  tmp = build_fold_indirect_ref_loc (input_location,
-                                tmp);
-  tmp = gfc_build_array_ref (tmp, offset, NULL);
+  tmp = build_array_ref (desc, offset, NULL);
 
   /* Offset the data pointer for pointer assignments from arrays with
      subreferences; e.g. my_integer => my_type(:)%integer_component.  */
index 7092bc2f153d1ea253a226f54a47366966b7942b..8045b1f029b81d9bfee65abb912431dee75fabe6 100644 (file)
@@ -147,11 +147,25 @@ gfc_vtable_copy_get (tree decl)
 #undef VTABLE_COPY_FIELD
 
 
+/* Obtain the vptr of the last class reference in an expression.  */
+
+tree
+gfc_get_vptr_from_expr (tree expr)
+{
+  tree tmp = expr;
+  while (tmp && !GFC_CLASS_TYPE_P (TREE_TYPE (tmp)))
+    tmp = TREE_OPERAND (tmp, 0);
+  tmp = gfc_class_vptr_get (tmp);
+  return tmp;
+}
+
 /* Takes a derived type expression and returns the address of a temporary
-   class object of the 'declared' type.  */ 
-static void
+   class object of the 'declared' type.  If vptr is not NULL, this is
+   used for the temporary class object.  */ 
+void
 gfc_conv_derived_to_class (gfc_se *parmse, gfc_expr *e,
-                          gfc_typespec class_ts)
+                          gfc_typespec class_ts, tree vptr)
 {
   gfc_symbol *vtab;
   gfc_ss *ss;
@@ -167,11 +181,19 @@ gfc_conv_derived_to_class (gfc_se *parmse, gfc_expr *e,
   /* Set the vptr.  */
   ctree =  gfc_class_vptr_get (var);
 
-  /* Remember the vtab corresponds to the derived type
-     not to the class declared type.  */
-  vtab = gfc_find_derived_vtab (e->ts.u.derived);
-  gcc_assert (vtab);
-  tmp = gfc_build_addr_expr (NULL_TREE, gfc_get_symbol_decl (vtab));
+  if (vptr != NULL_TREE)
+    {
+      /* Use the dynamic vptr.  */
+      tmp = vptr;
+    }
+  else
+    {
+      /* In this case the vtab corresponds to the derived type and the
+        vptr must point to it.  */
+      vtab = gfc_find_derived_vtab (e->ts.u.derived);
+      gcc_assert (vtab);
+      tmp = gfc_build_addr_expr (NULL_TREE, gfc_get_symbol_decl (vtab));
+    }
   gfc_add_modify (&parmse->pre, ctree,
                  fold_convert (TREE_TYPE (ctree), tmp));
 
@@ -3531,7 +3553,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
          /* The derived type needs to be converted to a temporary
             CLASS object.  */
          gfc_init_se (&parmse, se);
-         gfc_conv_derived_to_class (&parmse, e, fsym->ts);
+         gfc_conv_derived_to_class (&parmse, e, fsym->ts, NULL);
        }
       else if (se->ss && se->ss->info->useflags)
        {
index 12a1390e2aaa18318e5205eab3a59f763919db93..323fca382c3fe0950aff8fddba73878c23c4347d 100644 (file)
@@ -1140,6 +1140,10 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block)
   gfc_expr *e;
   tree tmp;
   bool class_target;
+  tree desc;
+  tree offset;
+  tree dim;
+  int n;
 
   gcc_assert (sym->assoc);
   e = sym->assoc->target;
@@ -1191,8 +1195,9 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block)
                            gfc_finish_block (&se.post));
     }
 
-  /* CLASS arrays just need the descriptor to be directly assigned.  */
-  else if (class_target && sym->attr.dimension)
+  /* Derived type temporaries, arising from TYPE IS, just need the
+     descriptor of class arrays to be assigned directly.  */
+  else if (class_target && sym->ts.type == BT_DERIVED && sym->attr.dimension)
     {
       gfc_se se;
 
@@ -1217,7 +1222,47 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block)
       gcc_assert (!sym->attr.dimension);
 
       gfc_init_se (&se, NULL);
-      gfc_conv_expr (&se, e);
+
+      /* Class associate-names come this way because they are
+        unconditionally associate pointers and the symbol is scalar.  */
+      if (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.dimension)
+       {
+         /* For a class array we need a descriptor for the selector.  */
+         gfc_conv_expr_descriptor (&se, e, gfc_walk_expr (e));
+
+         /* Obtain a temporary class container for the result.  */ 
+         gfc_conv_class_to_class (&se, e, sym->ts, false);
+         se.expr = build_fold_indirect_ref_loc (input_location, se.expr);
+
+         /* Set the offset.  */
+         desc = gfc_class_data_get (se.expr);
+         offset = gfc_index_zero_node;
+         for (n = 0; n < e->rank; n++)
+           {
+             dim = gfc_rank_cst[n];
+             tmp = fold_build2_loc (input_location, MULT_EXPR,
+                                    gfc_array_index_type,
+                                    gfc_conv_descriptor_stride_get (desc, dim),
+                                    gfc_conv_descriptor_lbound_get (desc, dim));
+             offset = fold_build2_loc (input_location, MINUS_EXPR,
+                                       gfc_array_index_type,
+                                       offset, tmp);
+           }
+         gfc_conv_descriptor_offset_set (&se.pre, desc, offset);
+       }
+      else if (sym->ts.type == BT_CLASS && e->ts.type == BT_CLASS
+              && CLASS_DATA (e)->attr.dimension)
+       {
+         /* This is bound to be a class array element.  */
+         gfc_conv_expr_reference (&se, e);
+         /* Get the _vptr component of the class object.  */ 
+         tmp = gfc_get_vptr_from_expr (se.expr);
+         /* Obtain a temporary class container for the result.  */
+         gfc_conv_derived_to_class (&se, e, sym->ts, tmp);
+         se.expr = build_fold_indirect_ref_loc (input_location, se.expr);
+       }
+      else
+       gfc_conv_expr (&se, e);
 
       tmp = TREE_TYPE (sym->backend_decl);
       tmp = gfc_build_addr_expr (tmp, se.expr);
index 0f2912de1afbe78de9b7f8216174208239df71d1..21a94fd6f069aaab0d42b6713e0ed70abeb83bab 100644 (file)
@@ -1106,6 +1106,9 @@ gfc_typenode_for_spec (gfc_typespec * spec)
     case BT_CLASS:
       basetype = gfc_get_derived_type (spec->u.derived);
 
+      if (spec->type == BT_CLASS)
+       GFC_CLASS_TYPE_P (basetype) = 1;
+
       /* If we're dealing with either C_PTR or C_FUNPTR, we modified the
          type and kind to fit a (void *) and the basetype returned was a
          ptr_type_node.  We need to pass up this new information to the
index 08a6732527460f9ce7e0c85c6edca419da6babc4..3b77281568af8ef8ef72cff5941a838f1fdf6eb0 100644 (file)
@@ -348,8 +348,10 @@ tree gfc_vtable_size_get (tree);
 tree gfc_vtable_extends_get (tree);
 tree gfc_vtable_def_init_get (tree);
 tree gfc_vtable_copy_get (tree);
+tree gfc_get_vptr_from_expr (tree);
 tree gfc_get_class_array_ref (tree, tree);
 tree gfc_copy_class_to_class (tree, tree, tree);
+void gfc_conv_derived_to_class (gfc_se *, gfc_expr *, gfc_typespec, tree);
 void gfc_conv_class_to_class (gfc_se *, gfc_expr *, gfc_typespec, bool);
 
 /* Initialize an init/cleanup block.  */
@@ -827,6 +829,8 @@ struct GTY((variable_size)) lang_decl {
 #define GFC_ARRAY_TYPE_P(node) TYPE_LANG_FLAG_2(node)
 /* Fortran POINTER type.  */
 #define GFC_POINTER_TYPE_P(node) TYPE_LANG_FLAG_3(node)
+/* Fortran CLASS type.  */
+#define GFC_CLASS_TYPE_P(node) TYPE_LANG_FLAG_4(node)
 /* The GFC_TYPE_ARRAY_* members are present in both descriptor and
    descriptorless array types.  */
 #define GFC_TYPE_ARRAY_LBOUND(node, dim) \
index c954165f0fda141e746b82c0fd7f1329b62f9120..f43eb54fa3d32f6f95662ac1a810e04ffedcc3a1 100644 (file)
@@ -1,3 +1,12 @@
+2012-05-05  Paul Thomas  <pault@gcc.gnu.org>
+
+       PR fortran/41600
+       * gfortran.dg/select_type_26.f03 : New test.
+       * gfortran.dg/select_type_27.f03 : New test.
+
+       PR fortran/53191
+       * gfortran.dg/select_type_28.f03 : New test.
+
 2012-05-05  Janne Blomqvist  <jb@gcc.gnu.org>
 
        PR fortran/49010
diff --git a/gcc/testsuite/gfortran.dg/select_type_26.f03 b/gcc/testsuite/gfortran.dg/select_type_26.f03
new file mode 100644 (file)
index 0000000..7d9c437
--- /dev/null
@@ -0,0 +1,110 @@
+! { dg-do run }
+! Tests fix for PR41600 and further SELECT TYPE functionality.
+!
+! Reported by Tobias Burnus  <burnus@gcc.gnu.org>
+!
+  implicit none
+  type t0
+    integer :: j = 42
+  end type t0
+
+  type, extends(t0) :: t1
+    integer :: k = 99
+  end type t1
+
+  type t
+    integer :: i
+    class(t0), allocatable :: foo(:)
+  end type t
+
+  type t_scalar
+    integer :: i
+    class(t0), allocatable :: foo
+  end type t_scalar
+
+  type(t) :: m
+  type(t_scalar) :: m1(4)
+  integer :: n
+
+! Test the fix for PR41600 itself - first with m%foo of declared type.
+  allocate(m%foo(3), source = [(t0(n), n = 1,3)])
+  select type(bar => m%foo)
+    type is(t0)
+      if (any (bar%j .ne. [1,2,3])) call abort
+    type is(t1)
+      call abort
+  end select
+
+  deallocate(m%foo)
+  allocate(m%foo(3), source = [(t1(n, n*10), n = 4,6)])
+
+! Then with m%foo of another dynamic type.
+  select type(bar => m%foo)
+    type is(t0)
+      call abort
+    type is(t1)
+      if (any (bar%k .ne. [40,50,60])) call abort
+  end select
+
+! Try it with a selector array section.
+  select type(bar => m%foo(2:3))
+    type is(t0)
+      call abort
+    type is(t1)
+      if (any (bar%k .ne. [50,60])) call abort
+  end select
+
+! Try it with a selector array element.
+  select type(bar => m%foo(2))
+    type is(t0)
+      call abort
+    type is(t1)
+      if (bar%k .ne. 50) call abort
+  end select
+
+! Now try class is and a selector which is an array section of an associate name.
+  select type(bar => m%foo)
+    type is(t0)
+      call abort
+    class is (t1)
+      if (any (bar%j .ne. [4,5,6])) call abort
+      select type (foobar => bar(3:2:-1))
+        type is (t1)
+          if (any (foobar%k .ne. [60,50])) call abort
+        end select
+  end select
+
+! Now try class is and a selector which is an array element of an associate name.
+  select type(bar => m%foo)
+    type is(t0)
+      call abort
+    class is (t1)
+      if (any (bar%j .ne. [4,5,6])) call abort
+      select type (foobar => bar(2))
+        type is (t1)
+          if (foobar%k .ne. 50) call abort
+        end select
+  end select
+
+! Check class a component of an element of an array. Note that an array of such
+! objects cannot be allowed since the elements could have different dynamic types.
+! (F2003 C614)
+  do n = 1, 2
+    allocate(m1(n)%foo, source = t1(n*99, n*999))
+  end do
+  do n = 3, 4
+    allocate(m1(n)%foo, source = t0(n*99))
+  end do
+  select type(bar => m1(3)%foo)
+    type is(t0)
+      if (bar%j .ne. 297) call abort
+    type is(t1)
+      call abort
+  end select
+  select type(bar => m1(1)%foo)
+    type is(t0)
+      call abort
+    type is(t1)
+      if (bar%k .ne. 999) call abort
+  end select
+end
diff --git a/gcc/testsuite/gfortran.dg/select_type_27.f03 b/gcc/testsuite/gfortran.dg/select_type_27.f03
new file mode 100644 (file)
index 0000000..5bd3c1a
--- /dev/null
@@ -0,0 +1,115 @@
+! { dg-do run }
+! Tests fix for PR41600 and further SELECT TYPE functionality.
+! This differs from the original and select_type_26.f03 by 'm'
+! being a class object rather than a derived type.
+!
+! Reported by Tobias Burnus  <burnus@gcc.gnu.org>
+!
+  implicit none
+  type t0
+    integer :: j = 42
+  end type t0
+
+  type, extends(t0) :: t1
+    integer :: k = 99
+  end type t1
+
+  type t
+    integer :: i
+    class(t0), allocatable :: foo(:)
+  end type t
+
+  type t_scalar
+    integer :: i
+    class(t0), allocatable :: foo
+  end type t_scalar
+
+  class(t), allocatable :: m
+  class(t_scalar), allocatable :: m1(:)
+  integer :: n
+
+  allocate (m)
+  allocate (m1(4))
+
+! Test the fix for PR41600 itself - first with m%foo of declared type.
+  allocate(m%foo(3), source = [(t0(n), n = 1,3)])
+  select type(bar => m%foo)
+    type is(t0)
+      if (any (bar%j .ne. [1,2,3])) call abort
+    type is(t1)
+      call abort
+  end select
+
+  deallocate(m%foo)
+  allocate(m%foo(3), source = [(t1(n, n*10), n = 4,6)])
+
+! Then with m%foo of another dynamic type.
+  select type(bar => m%foo)
+    type is(t0)
+      call abort
+    type is(t1)
+      if (any (bar%k .ne. [40,50,60])) call abort
+  end select
+
+! Try it with a selector array section.
+  select type(bar => m%foo(2:3))
+    type is(t0)
+      call abort
+    type is(t1)
+      if (any (bar%k .ne. [50,60])) call abort
+  end select
+
+! Try it with a selector array element.
+  select type(bar => m%foo(2))
+    type is(t0)
+      call abort
+    type is(t1)
+      if (bar%k .ne. 50) call abort
+  end select
+
+! Now try class is and a selector which is an array section of an associate name.
+  select type(bar => m%foo)
+    type is(t0)
+      call abort
+    class is (t1)
+      if (any (bar%j .ne. [4,5,6])) call abort
+      select type (foobar => bar(3:2:-1))
+        type is (t1)
+          if (any (foobar%k .ne. [60,50])) call abort
+        end select
+  end select
+
+! Now try class is and a selector which is an array element of an associate name.
+  select type(bar => m%foo)
+    type is(t0)
+      call abort
+    class is (t1)
+      if (any (bar%j .ne. [4,5,6])) call abort
+      select type (foobar => bar(2))
+        type is (t1)
+          if (foobar%k .ne. 50) call abort
+        end select
+  end select
+
+! Check class a component of an element of an array. Note that an array of such
+! objects cannot be allowed since the elements could have different dynamic types.
+! (F2003 C614)
+  do n = 1, 2
+    allocate(m1(n)%foo, source = t1(n*99, n*999))
+  end do
+  do n = 3, 4
+    allocate(m1(n)%foo, source = t0(n*99))
+  end do
+  select type(bar => m1(3)%foo)
+    type is(t0)
+      if (bar%j .ne. 297) call abort
+    type is(t1)
+      call abort
+  end select
+  select type(bar => m1(1)%foo)
+    type is(t0)
+      call abort
+    type is(t1)
+      if (bar%k .ne. 999) call abort
+  end select
+end
diff --git a/gcc/testsuite/gfortran.dg/select_type_28.f03 b/gcc/testsuite/gfortran.dg/select_type_28.f03
new file mode 100644 (file)
index 0000000..9cab721
--- /dev/null
@@ -0,0 +1,36 @@
+! { dg-do compile }
+!
+! Fix for PR53191
+!
+  implicit none
+  type t0
+    integer :: j = 42
+  end type t0
+  type, extends(t0) :: t1
+    integer :: k = 99
+  end type t1
+  type t
+    integer :: i
+    class(t0), allocatable :: foo
+  end type t
+  type(t) :: m(4)
+  integer :: n
+
+  do n = 1, 2
+    allocate(m(n)%foo, source = t0(n*99))
+  end do
+  do n = 3, 4
+    allocate(m(n)%foo, source = t1(n*99, n*999))
+  end do
+
+! An array of objects with ultimate class components cannot be a selector
+! since each element could have a different dynamic type. (F2003 C614)
+
+  select type(bar => m%foo) ! { dg-error "part reference with nonzero rank" }
+    type is(t0)
+      if (any (bar%j .ne. [99, 198, 297, 396])) call abort
+    type is(t1)
+      call abort
+  end select
+
+end