OSDN Git Service

2013-01-17 Janus Weil <janus@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / fortran / class.c
index a17fc0a..d4ed6b0 100644 (file)
@@ -52,6 +52,145 @@ along with GCC; see the file COPYING3.  If not see
 #include "constructor.h"
 
 
+/* Inserts a derived type component reference in a data reference chain.
+    TS: base type of the ref chain so far, in which we will pick the component
+    REF: the address of the GFC_REF pointer to update
+    NAME: name of the component to insert
+   Note that component insertion makes sense only if we are at the end of
+   the chain (*REF == NULL) or if we are adding a missing "_data" component
+   to access the actual contents of a class object.  */
+
+static void
+insert_component_ref (gfc_typespec *ts, gfc_ref **ref, const char * const name)
+{
+  gfc_symbol *type_sym;
+  gfc_ref *new_ref;
+
+  gcc_assert (ts->type == BT_DERIVED || ts->type == BT_CLASS);
+  type_sym = ts->u.derived;
+
+  new_ref = gfc_get_ref ();
+  new_ref->type = REF_COMPONENT;
+  new_ref->next = *ref;
+  new_ref->u.c.sym = type_sym;
+  new_ref->u.c.component = gfc_find_component (type_sym, name, true, true);
+  gcc_assert (new_ref->u.c.component);
+
+  if (new_ref->next)
+    {
+      gfc_ref *next = NULL;
+
+      /* We need to update the base type in the trailing reference chain to
+        that of the new component.  */
+
+      gcc_assert (strcmp (name, "_data") == 0);
+
+      if (new_ref->next->type == REF_COMPONENT)
+       next = new_ref->next;
+      else if (new_ref->next->type == REF_ARRAY
+              && new_ref->next->next
+              && new_ref->next->next->type == REF_COMPONENT)
+       next = new_ref->next->next;
+
+      if (next != NULL)
+       {
+         gcc_assert (new_ref->u.c.component->ts.type == BT_CLASS
+                     || new_ref->u.c.component->ts.type == BT_DERIVED);
+         next->u.c.sym = new_ref->u.c.component->ts.u.derived;
+       }
+    }
+
+  *ref = new_ref;
+}
+
+
+/* Tells whether we need to add a "_data" reference to access REF subobject
+   from an object of type TS.  If FIRST_REF_IN_CHAIN is set, then the base
+   object accessed by REF is a variable; in other words it is a full object,
+   not a subobject.  */
+
+static bool
+class_data_ref_missing (gfc_typespec *ts, gfc_ref *ref, bool first_ref_in_chain)
+{
+  /* Only class containers may need the "_data" reference.  */
+  if (ts->type != BT_CLASS)
+    return false;
+
+  /* Accessing a class container with an array reference is certainly wrong.  */
+  if (ref->type != REF_COMPONENT)
+    return true;
+
+  /* Accessing the class container's fields is fine.  */
+  if (ref->u.c.component->name[0] == '_')
+    return false;
+
+  /* At this point we have a class container with a non class container's field
+     component reference.  We don't want to add the "_data" component if we are
+     at the first reference and the symbol's type is an extended derived type.
+     In that case, conv_parent_component_references will do the right thing so
+     it is not absolutely necessary.  Omitting it prevents a regression (see
+     class_41.f03) in the interface mapping mechanism.  When evaluating string
+     lengths depending on dummy arguments, we create a fake symbol with a type
+     equal to that of the dummy type.  However, because of type extension,
+     the backend type (corresponding to the actual argument) can have a
+     different (extended) type.  Adding the "_data" component explicitly, using
+     the base type, confuses the gfc_conv_component_ref code which deals with
+     the extended type.  */
+  if (first_ref_in_chain && ts->u.derived->attr.extension)
+    return false;
+
+  /* We have a class container with a non class container's field component
+     reference that doesn't fall into the above.  */
+  return true;
+}
+
+
+/* Browse through a data reference chain and add the missing "_data" references
+   when a subobject of a class object is accessed without it.
+   Note that it doesn't add the "_data" reference when the class container
+   is the last element in the reference chain.  */
+
+void
+gfc_fix_class_refs (gfc_expr *e)
+{
+  gfc_typespec *ts;
+  gfc_ref **ref;
+
+  if ((e->expr_type != EXPR_VARIABLE
+       && e->expr_type != EXPR_FUNCTION)
+      || (e->expr_type == EXPR_FUNCTION
+         && e->value.function.isym != NULL))
+    return;
+
+  if (e->expr_type == EXPR_VARIABLE)
+    ts = &e->symtree->n.sym->ts;
+  else
+    {
+      gfc_symbol *func;
+
+      gcc_assert (e->expr_type == EXPR_FUNCTION);
+      if (e->value.function.esym != NULL)
+       func = e->value.function.esym;
+      else
+       func = e->symtree->n.sym;
+
+      if (func->result != NULL)
+       ts = &func->result->ts;
+      else
+       ts = &func->ts;
+    }
+
+  for (ref = &e->ref; *ref != NULL; ref = &(*ref)->next)
+    {
+      if (class_data_ref_missing (ts, *ref, ref == &e->ref))
+       insert_component_ref (ts, ref, "_data");
+
+      if ((*ref)->type == REF_COMPONENT)
+       ts = &(*ref)->u.c.component->ts;
+    }
+}
+
+
 /* Insert a reference to the component of the given name.
    Only to be used with CLASS containers and vtables.  */
 
@@ -294,8 +433,10 @@ get_unique_hashed_string (char *string, gfc_symbol *derived)
   char tmp[2*GFC_MAX_SYMBOL_LEN+2];
   get_unique_type_string (&tmp[0], derived);
   /* If string is too long, use hash value in hex representation (allow for
-     extra decoration, cf. gfc_build_class_symbol & gfc_find_derived_vtab).  */
-  if (strlen (tmp) > GFC_MAX_SYMBOL_LEN - 11)
+     extra decoration, cf. gfc_build_class_symbol & gfc_find_derived_vtab).
+     We need space to for 15 characters "__class_" + symbol name + "_%d_%da",
+     where %d is the (co)rank which can be up to n = 15.  */
+  if (strlen (tmp) > GFC_MAX_SYMBOL_LEN - 15)
     {
       int h = gfc_hash_value (derived);
       sprintf (string, "%X", h);
@@ -360,10 +501,10 @@ gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr,
 
   /* Determine the name of the encapsulating type.  */
   get_unique_hashed_string (tname, ts->u.derived);
-  if ((*as) && (*as)->rank && attr->allocatable)
-    sprintf (name, "__class_%s_%d_a", tname, (*as)->rank);
-  else if ((*as) && (*as)->rank)
-    sprintf (name, "__class_%s_%d", tname, (*as)->rank);
+  if ((*as) && attr->allocatable)
+    sprintf (name, "__class_%s_%d_%da", tname, (*as)->rank, (*as)->corank);
+  else if ((*as))
+    sprintf (name, "__class_%s_%d_%d", tname, (*as)->rank, (*as)->corank);
   else if (attr->pointer)
     sprintf (name, "__class_%s_p", tname);
   else if (attr->allocatable)
@@ -421,6 +562,8 @@ gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr,
       c->attr.access = ACCESS_PRIVATE;
       c->attr.pointer = 1;
     }
+  else if (!fclass->f2k_derived)
+    fclass->f2k_derived = gfc_get_namespace (NULL, 0);
 
   /* Since the extension field is 8 bit wide, we can only have
      up to 255 extension levels.  */
@@ -588,7 +731,7 @@ gfc_find_derived_vtab (gfc_symbol *derived)
        {
          gfc_get_symbol (name, ns, &vtab);
          vtab->ts.type = BT_DERIVED;
-         if (gfc_add_flavor (&vtab->attr, FL_PARAMETER, NULL,
+         if (gfc_add_flavor (&vtab->attr, FL_VARIABLE, NULL,
                              &gfc_current_locus) == FAILURE)
            goto cleanup;
          vtab->attr.target = 1;
@@ -682,7 +825,7 @@ gfc_find_derived_vtab (gfc_symbol *derived)
                  def_init->attr.target = 1;
                  def_init->attr.save = SAVE_IMPLICIT;
                  def_init->attr.access = ACCESS_PUBLIC;
-                 def_init->attr.flavor = FL_PARAMETER;
+                 def_init->attr.flavor = FL_VARIABLE;
                  gfc_set_sym_referenced (def_init);
                  def_init->ts.type = BT_DERIVED;
                  def_init->ts.u.derived = derived;
@@ -713,6 +856,7 @@ gfc_find_derived_vtab (gfc_symbol *derived)
                  sub_ns->proc_name = copy;
                  copy->attr.flavor = FL_PROCEDURE;
                  copy->attr.subroutine = 1;
+                 copy->attr.pure = 1;
                  copy->attr.if_source = IFSRC_DECL;
                  /* This is elemental so that arrays are automatically
                     treated correctly by the scalarizer.  */
@@ -796,15 +940,17 @@ find_typebound_proc_uop (gfc_symbol* derived, gfc_try* t,
   gfc_symtree* res;
   gfc_symtree* root;
 
-  /* Set correct symbol-root.  */
-  gcc_assert (derived->f2k_derived);
-  root = (uop ? derived->f2k_derived->tb_uop_root
-             : derived->f2k_derived->tb_sym_root);
-
   /* Set default to failure.  */
   if (t)
     *t = FAILURE;
 
+  if (derived->f2k_derived)
+    /* Set correct symbol-root.  */
+    root = (uop ? derived->f2k_derived->tb_uop_root
+               : derived->f2k_derived->tb_sym_root);
+  else
+    return NULL;
+
   /* Try to find it in the current type's namespace.  */
   res = gfc_find_symtree (root, name);
   if (res && res->n.tb && !res->n.tb->error)