]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/fortran/class.c
PR 78534 Revert r244011
[thirdparty/gcc.git] / gcc / fortran / class.c
index d01d7d8c97a975017c1213e1fbc6f15cf1bb52f6..d507e22ce0947bd26436c247e6429073b28abc93 100644 (file)
@@ -1,5 +1,5 @@
 /* Implementation of Fortran 2003 Polymorphism.
-   Copyright (C) 2009-2014 Free Software Foundation, Inc.
+   Copyright (C) 2009-2017 Free Software Foundation, Inc.
    Contributed by Paul Richard Thomas <pault@gcc.gnu.org>
    and Janus Weil <janus@gcc.gnu.org>
 
@@ -34,6 +34,12 @@ along with GCC; see the file COPYING3.  If not see
              (pointer/allocatable/dimension/...).
     * _vptr: A pointer to the vtable entry (see below) of the dynamic type.
 
+    Only for unlimited polymorphic classes:
+    * _len:  An integer(4) to store the string length when the unlimited
+             polymorphic pointer is used to point to a char array.  The '_len'
+             component will be zero when no character array is stored in
+             '_data'.
+
    For each derived type we set up a "vtable" entry, i.e. a structure with the
    following fields:
     * _hash:     A hash value serving as a unique identifier for this type.
@@ -72,12 +78,11 @@ insert_component_ref (gfc_typespec *ts, gfc_ref **ref, const char * const name)
   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);
+  gfc_find_component (type_sym, name, true, true, &new_ref);
   gcc_assert (new_ref->u.c.component);
+  while (new_ref->next)
+    new_ref = new_ref->next;
+  new_ref->next = *ref;
 
   if (new_ref->next)
     {
@@ -200,8 +205,9 @@ gfc_fix_class_refs (gfc_expr *e)
 void
 gfc_add_component_ref (gfc_expr *e, const char *name)
 {
+  gfc_component *c;
   gfc_ref **tail = &(e->ref);
-  gfc_ref *next = NULL;
+  gfc_ref *ref, *next = NULL;
   gfc_symbol *derived = e->symtree->n.sym->ts.u.derived;
   while (*tail != NULL)
     {
@@ -218,7 +224,8 @@ gfc_add_component_ref (gfc_expr *e, const char *name)
        break;
       tail = &((*tail)->next);
     }
-  if (derived->components->next->ts.type == BT_DERIVED &&
+  if (derived->components && derived->components->next &&
+      derived->components->next->ts.type == BT_DERIVED &&
       derived->components->next->ts.u.derived == NULL)
     {
       /* Fix up missing vtype.  */
@@ -228,14 +235,18 @@ gfc_add_component_ref (gfc_expr *e, const char *name)
     }
   if (*tail != NULL && strcmp (name, "_data") == 0)
     next = *tail;
-  (*tail) = gfc_get_ref();
-  (*tail)->next = next;
-  (*tail)->type = REF_COMPONENT;
-  (*tail)->u.c.sym = derived;
-  (*tail)->u.c.component = gfc_find_component (derived, name, true, true);
-  gcc_assert((*tail)->u.c.component);
-  if (!next)
-    e->ts = (*tail)->u.c.component->ts;
+  else
+    /* Avoid losing memory.  */
+    gfc_free_ref_list (*tail);
+  c = gfc_find_component (derived, name, true, true, tail);
+
+  if (c) {
+    for (ref = *tail; ref->next; ref = ref->next)
+      ;
+    ref->next = next;
+    if (!next)
+      e->ts = c->ts;
+  }
 }
 
 
@@ -249,7 +260,7 @@ gfc_add_class_array_ref (gfc_expr *e)
   int rank = CLASS_DATA (e)->as->rank;
   gfc_array_spec *as = CLASS_DATA (e)->as;
   gfc_ref *ref = NULL;
-  gfc_add_component_ref (e, "_data");
+  gfc_add_data_component (e);
   e->rank = rank;
   for (ref = e->ref; ref; ref = ref->next)
     if (!ref->next)
@@ -367,7 +378,8 @@ gfc_is_class_scalar_expr (gfc_expr *e)
        && CLASS_DATA (e->symtree->n.sym)
        && !CLASS_DATA (e->symtree->n.sym)->attr.dimension
        && (e->ref == NULL
-           || (strcmp (e->ref->u.c.component->name, "_data") == 0
+           || (e->ref->type == REF_COMPONENT
+               && strcmp (e->ref->u.c.component->name, "_data") == 0
                && e->ref->next == NULL)))
     return true;
 
@@ -379,7 +391,8 @@ gfc_is_class_scalar_expr (gfc_expr *e)
            && CLASS_DATA (ref->u.c.component)
            && !CLASS_DATA (ref->u.c.component)->attr.dimension
            && (ref->next == NULL
-               || (strcmp (ref->next->u.c.component->name, "_data") == 0
+               || (ref->next->type == REF_COMPONENT
+                   && strcmp (ref->next->u.c.component->name, "_data") == 0
                    && ref->next->next == NULL)))
        return true;
     }
@@ -468,8 +481,7 @@ get_unique_type_string (char *string, gfc_symbol *derived)
   if (derived->attr.unlimited_polymorphic)
     strcpy (dt_name, "STAR");
   else
-    strcpy (dt_name, derived->name);
-  dt_name[0] = TOUPPER (dt_name[0]);
+    strcpy (dt_name, gfc_dt_upper_string (derived->name));
   if (derived->attr.unlimited_polymorphic)
     sprintf (string, "_%s", dt_name);
   else if (derived->module)
@@ -544,10 +556,48 @@ gfc_intrinsic_hash_value (gfc_typespec *ts)
 }
 
 
+/* Get the _len component from a class/derived object storing a string.
+   For unlimited polymorphic entities a ref to the _data component is available
+   while a ref to the _len component is needed.  This routine traverese the
+   ref-chain and strips the last ref to a _data from it replacing it with a
+   ref to the _len component.  */
+
+gfc_expr *
+gfc_get_len_component (gfc_expr *e)
+{
+  gfc_expr *ptr;
+  gfc_ref *ref, **last;
+
+  ptr = gfc_copy_expr (e);
+
+  /* We need to remove the last _data component ref from ptr.  */
+  last = &(ptr->ref);
+  ref = ptr->ref;
+  while (ref)
+    {
+      if (!ref->next
+         && ref->type == REF_COMPONENT
+         && strcmp ("_data", ref->u.c.component->name)== 0)
+       {
+         gfc_free_ref_list (ref);
+         *last = NULL;
+         break;
+       }
+      last = &(ref->next);
+      ref = ref->next;
+    }
+  /* And replace if with a ref to the _len component.  */
+  gfc_add_len_component (ptr);
+  return ptr;
+}
+
+
 /* Build a polymorphic CLASS entity, using the symbol that comes from
    build_sym. A CLASS entity is represented by an encapsulating type,
    which contains the declared type as '_data' component, plus a pointer
-   component '_vptr' which determines the dynamic type.  */
+   component '_vptr' which determines the dynamic type.  When this CLASS
+   entity is unlimited polymorphic, then also add a component '_len' to
+   store the length of string when that is stored in it.  */
 
 bool
 gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr,
@@ -588,13 +638,13 @@ gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr,
   else if ((*as) && attr->pointer)
     sprintf (name, "__class_%s_%d_%dp", tname, rank, (*as)->corank);
   else if ((*as))
-    sprintf (name, "__class_%s_%d_%d", tname, rank, (*as)->corank);
+    sprintf (name, "__class_%s_%d_%dt", tname, rank, (*as)->corank);
   else if (attr->pointer)
     sprintf (name, "__class_%s_p", tname);
   else if (attr->allocatable)
     sprintf (name, "__class_%s_a", tname);
   else
-    sprintf (name, "__class_%s", tname);
+    sprintf (name, "__class_%s_t", tname);
 
   if (ts->u.derived->attr.unlimited_polymorphic)
     {
@@ -645,19 +695,28 @@ gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr,
       if (!gfc_add_component (fclass, "_vptr", &c))
        return false;
       c->ts.type = BT_DERIVED;
+      c->attr.access = ACCESS_PRIVATE;
+      c->attr.pointer = 1;
 
       if (ts->u.derived->attr.unlimited_polymorphic)
        {
          vtab = gfc_find_derived_vtab (ts->u.derived);
          gcc_assert (vtab);
          c->ts.u.derived = vtab->ts.u.derived;
+
+         /* Add component '_len'.  Only unlimited polymorphic pointers may
+             have a string assigned to them, i.e., only those need the _len
+             component.  */
+         if (!gfc_add_component (fclass, "_len", &c))
+           return false;
+         c->ts.type = BT_INTEGER;
+         c->ts.kind = gfc_charlen_int_kind;
+         c->attr.access = ACCESS_PRIVATE;
+         c->attr.artificial = 1;
        }
       else
        /* Build vtab later.  */
        c->ts.u.derived = NULL;
-
-      c->attr.access = ACCESS_PRIVATE;
-      c->attr.pointer = 1;
     }
 
   if (!ts->u.derived->attr.unlimited_polymorphic)
@@ -666,7 +725,7 @@ gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr,
         up to 255 extension levels.  */
       if (ts->u.derived->attr.extension == 255)
        {
-         gfc_error ("Maximum extension level reached with type '%s' at %L",
+         gfc_error ("Maximum extension level reached with type %qs at %L",
                     ts->u.derived->name, &ts->u.derived->declared_at);
        return false;
        }
@@ -692,10 +751,10 @@ add_proc_comp (gfc_symbol *vtype, const char *name, gfc_typebound_proc *tb)
 {
   gfc_component *c;
 
-  if (tb->non_overridable)
+  if (tb->non_overridable && !tb->overridden)
     return;
 
-  c = gfc_find_component (vtype, name, true, true);
+  c = gfc_find_component (vtype, name, true, true, NULL);
 
   if (c == NULL)
     {
@@ -764,7 +823,7 @@ copy_vtab_proc_comps (gfc_symbol *declared, gfc_symbol *vtype)
 
   for (cmp = vtab->ts.u.derived->components; cmp; cmp = cmp->next)
     {
-      if (gfc_find_component (vtype, cmp->name, true, true))
+      if (gfc_find_component (vtype, cmp->name, true, true, NULL))
        continue;
 
       add_proc_comp (vtype, cmp->name, cmp->tb);
@@ -782,16 +841,19 @@ has_finalizer_component (gfc_symbol *derived)
    gfc_component *c;
 
   for (c = derived->components; c; c = c->next)
-    {
-      if (c->ts.type == BT_DERIVED && c->ts.u.derived->f2k_derived
-         && c->ts.u.derived->f2k_derived->finalizers)
-       return true;
-
-      if (c->ts.type == BT_DERIVED
-         && !c->attr.pointer && !c->attr.allocatable
-         && has_finalizer_component (c->ts.u.derived))
-       return true;
-    }
+    if (c->ts.type == BT_DERIVED && !c->attr.pointer && !c->attr.allocatable)
+      {
+       if (c->ts.u.derived->f2k_derived
+           && c->ts.u.derived->f2k_derived->finalizers)
+         return true;
+
+       /* Stop infinite recursion through this function by inhibiting
+         calls when the derived type and that of the component are
+         the same.  */
+       if (!gfc_compare_derived_types (derived, c->ts.u.derived)
+           && has_finalizer_component (c->ts.u.derived))
+         return true;
+      }
   return false;
 }
 
@@ -828,7 +890,8 @@ comp_is_finalizable (gfc_component *comp)
 
 static void
 finalize_component (gfc_expr *expr, gfc_symbol *derived, gfc_component *comp,
-                   gfc_symbol *stat, gfc_symbol *fini_coarray, gfc_code **code)
+                   gfc_symbol *stat, gfc_symbol *fini_coarray, gfc_code **code,
+                   gfc_namespace *sub_ns)
 {
   gfc_expr *e;
   gfc_ref *ref;
@@ -875,7 +938,7 @@ finalize_component (gfc_expr *expr, gfc_symbol *derived, gfc_component *comp,
       /* Add IF (fini_coarray).  */
       if (comp->attr.codimension
          || (comp->ts.type == BT_CLASS && CLASS_DATA (comp)
-             && CLASS_DATA (comp)->attr.allocatable))
+             && CLASS_DATA (comp)->attr.codimension))
        {
          block = gfc_get_code (EXEC_IF);
          if (*code)
@@ -897,15 +960,33 @@ finalize_component (gfc_expr *expr, gfc_symbol *derived, gfc_component *comp,
       dealloc->ext.alloc.list->expr = e;
       dealloc->expr1 = gfc_lval_expr_from_sym (stat);
 
+      gfc_code *cond = gfc_get_code (EXEC_IF);
+      cond->block = gfc_get_code (EXEC_IF);
+      cond->block->expr1 = gfc_get_expr ();
+      cond->block->expr1->expr_type = EXPR_FUNCTION;
+      cond->block->expr1->where = gfc_current_locus;
+      gfc_get_sym_tree ("associated", sub_ns, &cond->block->expr1->symtree, false);
+      cond->block->expr1->symtree->n.sym->attr.flavor = FL_PROCEDURE;
+      cond->block->expr1->symtree->n.sym->attr.intrinsic = 1;
+      cond->block->expr1->symtree->n.sym->result = cond->block->expr1->symtree->n.sym;
+      gfc_commit_symbol (cond->block->expr1->symtree->n.sym);
+      cond->block->expr1->ts.type = BT_LOGICAL;
+      cond->block->expr1->ts.kind = gfc_default_logical_kind;
+      cond->block->expr1->value.function.isym = gfc_intrinsic_function_by_id (GFC_ISYM_ASSOCIATED);
+      cond->block->expr1->value.function.actual = gfc_get_actual_arglist ();
+      cond->block->expr1->value.function.actual->expr = gfc_copy_expr (expr);
+      cond->block->expr1->value.function.actual->next = gfc_get_actual_arglist ();
+      cond->block->next = dealloc;
+
       if (block)
-       block->next = dealloc;
+       block->next = cond;
       else if (*code)
        {
-         (*code)->next = dealloc;
+         (*code)->next = cond;
          (*code) = (*code)->next;
        }
       else
-       (*code) = dealloc;
+       (*code) = cond;
     }
   else if (comp->ts.type == BT_DERIVED
            && comp->ts.u.derived->f2k_derived
@@ -941,7 +1022,8 @@ finalize_component (gfc_expr *expr, gfc_symbol *derived, gfc_component *comp,
       gfc_component *c;
 
       for (c = comp->ts.u.derived->components; c; c = c->next)
-       finalize_component (e, comp->ts.u.derived, c, stat, fini_coarray, code);
+       finalize_component (e, comp->ts.u.derived, c, stat, fini_coarray, code,
+                           sub_ns);
       gfc_free_expr (e);
     }
 }
@@ -975,7 +1057,7 @@ finalization_scalarizer (gfc_symbol *array, gfc_symbol *ptr,
   block->ext.actual->next = gfc_get_actual_arglist ();
   block->ext.actual->next->expr = gfc_get_int_expr (gfc_index_integer_kind,
                                                    NULL, 0);
-  block->ext.actual->next->next = gfc_get_actual_arglist (); /* SIZE. */
+  block->ext.actual->next->next = gfc_get_actual_arglist (); /* SIZE.  */
 
   /* The <addr> part: TRANSFER (C_LOC (array), c_intptr_t).  */
 
@@ -995,6 +1077,7 @@ finalization_scalarizer (gfc_symbol *array, gfc_symbol *ptr,
   gfc_commit_symbol (expr->symtree->n.sym);
   expr->ts.type = BT_INTEGER;
   expr->ts.kind = gfc_index_integer_kind;
+  expr->where = gfc_current_locus;
 
   /* TRANSFER.  */
   expr2 = gfc_build_intrinsic_call (sub_ns, GFC_ISYM_TRANSFER, "transfer",
@@ -1011,6 +1094,7 @@ finalization_scalarizer (gfc_symbol *array, gfc_symbol *ptr,
   block->ext.actual->expr->value.op.op1 = expr2;
   block->ext.actual->expr->value.op.op2 = offset;
   block->ext.actual->expr->ts = expr->ts;
+  block->ext.actual->expr->where = gfc_current_locus;
 
   /* C_F_POINTER's 2nd arg: ptr -- and its absent shape=.  */
   block->ext.actual->next = gfc_get_actual_arglist ();
@@ -1067,6 +1151,7 @@ finalization_get_offset (gfc_symbol *idx, gfc_symbol *idx2, gfc_symbol *offset,
   expr->ref->u.ar.dimen = 1;
   expr->ref->u.ar.dimen_type[0] = DIMEN_ELEMENT;
   expr->ref->u.ar.start[0] = gfc_lval_expr_from_sym (idx2);
+  expr->where = sizes->declared_at;
 
   expr = gfc_build_intrinsic_call (sub_ns, GFC_ISYM_MOD, "mod",
                                   gfc_current_locus, 2,
@@ -1087,6 +1172,7 @@ finalization_get_offset (gfc_symbol *idx, gfc_symbol *idx2, gfc_symbol *offset,
   expr2->value.op.op2->ref->u.ar.dimen_type[0] = DIMEN_ELEMENT;
   expr2->value.op.op2->ref->u.ar.start[0] = gfc_get_expr ();
   expr2->value.op.op2->ref->u.ar.start[0]->expr_type = EXPR_OP;
+  expr2->value.op.op2->ref->u.ar.start[0]->where = gfc_current_locus;
   expr2->value.op.op2->ref->u.ar.start[0]->value.op.op = INTRINSIC_MINUS;
   expr2->value.op.op2->ref->u.ar.start[0]->value.op.op1
        = gfc_lval_expr_from_sym (idx2);
@@ -1095,6 +1181,7 @@ finalization_get_offset (gfc_symbol *idx, gfc_symbol *idx2, gfc_symbol *offset,
   expr2->value.op.op2->ref->u.ar.start[0]->ts
        = expr2->value.op.op2->ref->u.ar.start[0]->value.op.op1->ts;
   expr2->ts = idx->ts;
+  expr2->where = gfc_current_locus;
 
   /* ... * strides(idx2).  */
   expr = gfc_get_expr ();
@@ -1110,6 +1197,7 @@ finalization_get_offset (gfc_symbol *idx, gfc_symbol *idx2, gfc_symbol *offset,
   expr->value.op.op2->ref->u.ar.start[0] = gfc_lval_expr_from_sym (idx2);
   expr->value.op.op2->ref->u.ar.as = strides->as;
   expr->ts = idx->ts;
+  expr->where = gfc_current_locus;
 
   /* offset = offset + ...  */
   block->block->next = gfc_get_code (EXEC_ASSIGN);
@@ -1120,6 +1208,7 @@ finalization_get_offset (gfc_symbol *idx, gfc_symbol *idx2, gfc_symbol *offset,
   block->block->next->expr2->value.op.op1 = gfc_lval_expr_from_sym (offset);
   block->block->next->expr2->value.op.op2 = expr;
   block->block->next->expr2->ts = idx->ts;
+  block->block->next->expr2->where = gfc_current_locus;
 
   /* After the loop:  offset = offset * byte_stride.  */
   block->next = gfc_get_code (EXEC_ASSIGN);
@@ -1131,6 +1220,7 @@ finalization_get_offset (gfc_symbol *idx, gfc_symbol *idx2, gfc_symbol *offset,
   block->expr2->value.op.op1 = gfc_lval_expr_from_sym (offset);
   block->expr2->value.op.op2 = gfc_lval_expr_from_sym (byte_stride);
   block->expr2->ts = block->expr2->value.op.op1->ts;
+  block->expr2->where = gfc_current_locus;
   return block;
 }
 
@@ -1268,6 +1358,8 @@ finalizer_insert_packed_call (gfc_code *block, gfc_finalizer *fini,
   block->next->resolved_sym = fini->proc_tree->n.sym;
   block->next->ext.actual = gfc_get_actual_arglist ();
   block->next->ext.actual->expr = gfc_lval_expr_from_sym (array);
+  block->next->ext.actual->next = gfc_get_actual_arglist ();
+  block->next->ext.actual->next->expr = gfc_copy_expr (size_expr);
 
   /* ELSE.  */
 
@@ -1338,6 +1430,7 @@ finalizer_insert_packed_call (gfc_code *block, gfc_finalizer *fini,
   /* Offset calculation for the new array: idx * size of type (in bytes).  */
   offset2 = gfc_get_expr ();
   offset2->expr_type = EXPR_OP;
+  offset2->where = gfc_current_locus;
   offset2->value.op.op = INTRINSIC_TIMES;
   offset2->value.op.op1 = gfc_lval_expr_from_sym (idx);
   offset2->value.op.op2 = gfc_copy_expr (size_expr);
@@ -1363,7 +1456,7 @@ finalizer_insert_packed_call (gfc_code *block, gfc_finalizer *fini,
   block2->expr1 = gfc_lval_expr_from_sym (ptr2);
   block2->expr2 = gfc_lval_expr_from_sym (ptr);
 
-  /* Call now the user's final subroutine. */
+  /* Call now the user's final subroutine.  */
   block->next  = gfc_get_code (EXEC_CALL);
   block = block->next;
   block->symtree = fini->proc_tree;
@@ -1447,7 +1540,7 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
       return;
     }
 
-  /* Search for the ancestor's finalizers. */
+  /* Search for the ancestor's finalizers.  */
   if (derived->attr.extension && derived->components
       && (!derived->components->ts.u.derived->attr.abstract
          || has_finalizer_component (derived)))
@@ -1504,7 +1597,7 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
      3. Call the ancestor's finalizer.  */
 
   /* Declare the wrapper function; it takes an assumed-rank array
-     and a VALUE logical as arguments. */
+     and a VALUE logical as arguments.  */
 
   /* Set up the namespace.  */
   sub_ns = gfc_get_namespace (ns, 0);
@@ -1524,6 +1617,7 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
   final->ts.type = BT_INTEGER;
   final->ts.kind = 4;
   final->attr.artificial = 1;
+  final->attr.always_explicit = 1;
   final->attr.if_source = expr_null_wrapper ? IFSRC_IFBODY : IFSRC_DECL;
   if (ns->proc_name->attr.flavor == FL_MODULE)
     final->module = ns->proc_name->name;
@@ -1706,7 +1800,7 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
   last_code->ext.iterator = iter;
   last_code->block = gfc_get_code (EXEC_DO);
 
-  /* strides(idx) = _F._stride(array,dim=idx). */
+  /* strides(idx) = _F._stride(array,dim=idx).  */
   last_code->block->next = gfc_get_code (EXEC_ASSIGN);
   block = last_code->block->next;
 
@@ -1724,11 +1818,11 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
                                           gfc_lval_expr_from_sym (array),
                                           gfc_lval_expr_from_sym (idx));
 
-  /* sizes(idx) = sizes(idx-1) * size(array,dim=idx, kind=index_kind). */
+  /* sizes(idx) = sizes(idx-1) * size(array,dim=idx, kind=index_kind).  */
   block->next = gfc_get_code (EXEC_ASSIGN);
   block = block->next;
 
-  /* sizes(idx) = ... */
+  /* sizes(idx) = ...  */
   block->expr1 = gfc_lval_expr_from_sym (sizes);
   block->expr1->ref = gfc_get_ref ();
   block->expr1->ref->type = REF_ARRAY;
@@ -1741,8 +1835,9 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
   block->expr2 = gfc_get_expr ();
   block->expr2->expr_type = EXPR_OP;
   block->expr2->value.op.op = INTRINSIC_TIMES;
+  block->expr2->where = gfc_current_locus;
 
-  /* sizes(idx-1). */
+  /* sizes(idx-1).  */
   block->expr2->value.op.op1 = gfc_lval_expr_from_sym (sizes);
   block->expr2->value.op.op1->ref = gfc_get_ref ();
   block->expr2->value.op.op1->ref->type = REF_ARRAY;
@@ -1752,6 +1847,7 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
   block->expr2->value.op.op1->ref->u.ar.dimen_type[0] = DIMEN_ELEMENT;
   block->expr2->value.op.op1->ref->u.ar.start[0] = gfc_get_expr ();
   block->expr2->value.op.op1->ref->u.ar.start[0]->expr_type = EXPR_OP;
+  block->expr2->value.op.op1->ref->u.ar.start[0]->where = gfc_current_locus;
   block->expr2->value.op.op1->ref->u.ar.start[0]->value.op.op = INTRINSIC_MINUS;
   block->expr2->value.op.op1->ref->u.ar.start[0]->value.op.op1
        = gfc_lval_expr_from_sym (idx);
@@ -1805,6 +1901,7 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
   block->expr1->value.op.op2->ref->u.ar.dimen_type[0] = DIMEN_ELEMENT;
   block->expr1->value.op.op2->ref->u.ar.start[0] = gfc_get_expr ();
   block->expr1->value.op.op2->ref->u.ar.start[0]->expr_type = EXPR_OP;
+  block->expr1->value.op.op2->ref->u.ar.start[0]->where = gfc_current_locus;
   block->expr1->value.op.op2->ref->u.ar.start[0]->value.op.op = INTRINSIC_MINUS;
   block->expr1->value.op.op2->ref->u.ar.start[0]->value.op.op1
        = gfc_lval_expr_from_sym (idx);
@@ -1842,6 +1939,7 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
   last_code->expr2->value.op.op2
        = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
   last_code->expr2->ts = last_code->expr2->value.op.op2->ts;
+  last_code->expr2->where = gfc_current_locus;
 
   last_code->expr2->value.op.op1 = gfc_lval_expr_from_sym (sizes);
   last_code->expr2->value.op.op1->ref = gfc_get_ref ();
@@ -1874,7 +1972,7 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
     {
       gfc_finalizer *fini, *fini_elem = NULL;
 
-      gfc_get_symbol ("ptr", sub_ns, &ptr);
+      gfc_get_symbol ("ptr1", sub_ns, &ptr);
       ptr->ts.type = BT_DERIVED;
       ptr->ts.u.derived = derived;
       ptr->attr.flavor = FL_VARIABLE;
@@ -1998,7 +2096,7 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
 
       if (!ptr)
        {
-         gfc_get_symbol ("ptr", sub_ns, &ptr);
+         gfc_get_symbol ("ptr2", sub_ns, &ptr);
          ptr->ts.type = BT_DERIVED;
          ptr->ts.u.derived = derived;
          ptr->attr.flavor = FL_VARIABLE;
@@ -2047,7 +2145,7 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
            continue;
 
          finalize_component (gfc_lval_expr_from_sym (ptr), derived, comp,
-                             stat, fini_coarray, &block);
+                             stat, fini_coarray, &block, sub_ns);
          if (!last_code->block->next)
            last_code->block->next = block;
        }
@@ -2110,6 +2208,8 @@ gfc_find_derived_vtab (gfc_symbol *derived)
   gfc_namespace *ns;
   gfc_symbol *vtab = NULL, *vtype = NULL, *found_sym = NULL, *def_init = NULL;
   gfc_symbol *copy = NULL, *src = NULL, *dst = NULL;
+  gfc_gsymbol *gsym = NULL;
+  gfc_symbol *dealloc = NULL, *arg = NULL;
 
   /* Find the top-level namespace.  */
   for (ns = gfc_current_ns; ns; ns = ns->parent)
@@ -2120,6 +2220,20 @@ gfc_find_derived_vtab (gfc_symbol *derived)
   if (!derived->attr.unlimited_polymorphic && derived->attr.is_class)
     derived = gfc_get_derived_super_type (derived);
 
+  /* Find the gsymbol for the module of use associated derived types.  */
+  if ((derived->attr.use_assoc || derived->attr.used_in_submodule)
+       && !derived->attr.vtype && !derived->attr.is_class)
+    gsym =  gfc_find_gsymbol (gfc_gsym_root, derived->module);
+  else
+    gsym = NULL;
+
+  /* Work in the gsymbol namespace if the top-level namespace is a module.
+     This ensures that the vtable is unique, which is required since we use
+     its address in SELECT TYPE.  */
+  if (gsym && gsym->ns && ns && ns->proc_name
+      && ns->proc_name->attr.flavor == FL_MODULE)
+    ns = gsym->ns;
+
   if (ns)
     {
       char name[GFC_MAX_SYMBOL_LEN+1], tname[GFC_MAX_SYMBOL_LEN+1];
@@ -2128,7 +2242,14 @@ gfc_find_derived_vtab (gfc_symbol *derived)
       sprintf (name, "__vtab_%s", tname);
 
       /* Look for the vtab symbol in various namespaces.  */
-      gfc_find_symbol (name, gfc_current_ns, 0, &vtab);
+      if (gsym && gsym->ns)
+       {
+         gfc_find_symbol (name, gsym->ns, 0, &vtab);
+         if (vtab)
+           ns = gsym->ns;
+       }
+      if (vtab == NULL)
+       gfc_find_symbol (name, gfc_current_ns, 0, &vtab);
       if (vtab == NULL)
        gfc_find_symbol (name, ns, 0, &vtab);
       if (vtab == NULL)
@@ -2153,6 +2274,20 @@ gfc_find_derived_vtab (gfc_symbol *derived)
            {
              gfc_component *c;
              gfc_symbol *parent = NULL, *parent_vtab = NULL;
+             bool rdt = false;
+
+             /* Is this a derived type with recursive allocatable
+                components?  */
+             c = (derived->attr.unlimited_polymorphic
+                  || derived->attr.abstract) ?
+                 NULL : derived->components;
+             for (; c; c= c->next)
+               if (c->ts.type == BT_DERIVED
+                   && c->ts.u.derived == derived)
+                 {
+                   rdt = true;
+                   break;
+                 }
 
              gfc_get_symbol (name, ns, &vtype);
              if (!gfc_add_flavor (&vtype->attr, FL_DERIVED, NULL,
@@ -2325,6 +2460,66 @@ gfc_find_derived_vtab (gfc_symbol *derived)
              c->tb->ppc = 1;
              generate_finalization_wrapper (derived, ns, tname, c);
 
+             /* Add component _deallocate.  */
+             if (!gfc_add_component (vtype, "_deallocate", &c))
+               goto cleanup;
+             c->attr.proc_pointer = 1;
+             c->attr.access = ACCESS_PRIVATE;
+             c->tb = XCNEW (gfc_typebound_proc);
+             c->tb->ppc = 1;
+             if (derived->attr.unlimited_polymorphic
+                 || derived->attr.abstract
+                 || !rdt)
+               c->initializer = gfc_get_null_expr (NULL);
+             else
+               {
+                 /* Set up namespace.  */
+                 gfc_namespace *sub_ns = gfc_get_namespace (ns, 0);
+
+                 sub_ns->sibling = ns->contained;
+                 ns->contained = sub_ns;
+                 sub_ns->resolved = 1;
+                 /* Set up procedure symbol.  */
+                 sprintf (name, "__deallocate_%s", tname);
+                 gfc_get_symbol (name, sub_ns, &dealloc);
+                 sub_ns->proc_name = dealloc;
+                 dealloc->attr.flavor = FL_PROCEDURE;
+                 dealloc->attr.subroutine = 1;
+                 dealloc->attr.pure = 1;
+                 dealloc->attr.artificial = 1;
+                 dealloc->attr.if_source = IFSRC_DECL;
+
+                 if (ns->proc_name->attr.flavor == FL_MODULE)
+                   dealloc->module = ns->proc_name->name;
+                 gfc_set_sym_referenced (dealloc);
+                 /* Set up formal argument.  */
+                 gfc_get_symbol ("arg", sub_ns, &arg);
+                 arg->ts.type = BT_DERIVED;
+                 arg->ts.u.derived = derived;
+                 arg->attr.flavor = FL_VARIABLE;
+                 arg->attr.dummy = 1;
+                 arg->attr.artificial = 1;
+                 arg->attr.intent = INTENT_INOUT;
+                 arg->attr.dimension = 1;
+                 arg->attr.allocatable = 1;
+                 arg->as = gfc_get_array_spec();
+                 arg->as->type = AS_ASSUMED_SHAPE;
+                 arg->as->rank = 1;
+                 arg->as->lower[0] = gfc_get_int_expr (gfc_default_integer_kind,
+                                                       NULL, 1);
+                 gfc_set_sym_referenced (arg);
+                 dealloc->formal = gfc_get_formal_arglist ();
+                 dealloc->formal->sym = arg;
+                 /* Set up code.  */
+                 sub_ns->code = gfc_get_code (EXEC_DEALLOCATE);
+                 sub_ns->code->ext.alloc.list = gfc_get_alloc ();
+                 sub_ns->code->ext.alloc.list->expr
+                               = gfc_lval_expr_from_sym (arg);
+                 /* Set initializer.  */
+                 c->initializer = gfc_lval_expr_from_sym (dealloc);
+                 c->ts.interface = dealloc;
+               }
+
              /* Add procedure pointers for type-bound procedures.  */
              if (!derived->attr.unlimited_polymorphic)
                add_procs_to_declared_vtab (derived, vtype);
@@ -2354,6 +2549,10 @@ cleanup:
        gfc_commit_symbol (src);
       if (dst)
        gfc_commit_symbol (dst);
+      if (dealloc)
+       gfc_commit_symbol (dealloc);
+      if (arg)
+       gfc_commit_symbol (arg);
     }
   else
     gfc_undo_symbols ();
@@ -2413,20 +2612,6 @@ find_intrinsic_vtab (gfc_typespec *ts)
   gfc_namespace *ns;
   gfc_symbol *vtab = NULL, *vtype = NULL, *found_sym = NULL;
   gfc_symbol *copy = NULL, *src = NULL, *dst = NULL;
-  int charlen = 0;
-
-  if (ts->type == BT_CHARACTER)
-    {
-      if (ts->deferred)
-       {
-         gfc_error ("TODO: Deferred character length variable at %C cannot "
-                    "yet be associated with unlimited polymorphic entities");
-         return NULL;
-       }
-      else if (ts->u.cl && ts->u.cl->length
-              && ts->u.cl->length->expr_type == EXPR_CONSTANT)
-       charlen = mpz_get_si (ts->u.cl->length->value.integer);
-    }
 
   /* Find the top-level namespace.  */
   for (ns = gfc_current_ns; ns; ns = ns->parent)
@@ -2437,18 +2622,14 @@ find_intrinsic_vtab (gfc_typespec *ts)
     {
       char name[GFC_MAX_SYMBOL_LEN+1], tname[GFC_MAX_SYMBOL_LEN+1];
 
-      if (ts->type == BT_CHARACTER)
-       sprintf (tname, "%s_%d_%d", gfc_basic_typename (ts->type),
-                charlen, ts->kind);
-      else
-       sprintf (tname, "%s_%d_", gfc_basic_typename (ts->type), ts->kind);
-
+      /* Encode all types as TYPENAME_KIND_ including especially character
+        arrays, whose length is now consistently stored in the _len component
+        of the class-variable.  */
+      sprintf (tname, "%s_%d_", gfc_basic_typename (ts->type), ts->kind);
       sprintf (name, "__vtab_%s", tname);
 
-      /* Look for the vtab symbol in various namespaces.  */
-      gfc_find_symbol (name, gfc_current_ns, 0, &vtab);
-      if (vtab == NULL)
-       gfc_find_symbol (name, ns, 0, &vtab);
+      /* Look for the vtab symbol in the top-level namespace only.  */
+      gfc_find_symbol (name, ns, 0, &vtab);
 
       if (vtab == NULL)
        {
@@ -2499,13 +2680,18 @@ find_intrinsic_vtab (gfc_typespec *ts)
              c->attr.access = ACCESS_PRIVATE;
 
              /* Build a minimal expression to make use of
-                target-memory.c/gfc_element_size for 'size'. */
+                target-memory.c/gfc_element_size for 'size'.  Special handling
+                for character arrays, that are not constant sized: to support
+                len (str) * kind, only the kind information is stored in the
+                vtab.  */
              e = gfc_get_expr ();
              e->ts = *ts;
              e->expr_type = EXPR_VARIABLE;
              c->initializer = gfc_get_int_expr (gfc_default_integer_kind,
                                                 NULL,
-                                                (int)gfc_element_size (e));
+                                                ts->type == BT_CHARACTER
+                                                ? ts->kind
+                                                : (int)gfc_element_size (e));
              gfc_free_expr (e);
 
              /* Add component _extends.  */
@@ -2686,7 +2872,7 @@ find_typebound_proc_uop (gfc_symbol* derived, bool* t,
          && res->n.tb->access == ACCESS_PRIVATE)
        {
          if (where)
-           gfc_error ("'%s' of '%s' is PRIVATE at %L",
+           gfc_error ("%qs of %qs is PRIVATE at %L",
                       name, derived->name, where);
          if (t)
            *t = false;
@@ -2760,7 +2946,7 @@ gfc_find_typebound_intrinsic_op (gfc_symbol* derived, bool* t,
          && res->access == ACCESS_PRIVATE)
        {
          if (where)
-           gfc_error ("'%s' of '%s' is PRIVATE at %L",
+           gfc_error ("%qs of %qs is PRIVATE at %L",
                       gfc_op2string (op), derived->name, where);
          if (t)
            *t = false;
@@ -2792,15 +2978,6 @@ gfc_find_typebound_intrinsic_op (gfc_symbol* derived, bool* t,
 gfc_symtree*
 gfc_get_tbp_symtree (gfc_symtree **root, const char *name)
 {
-  gfc_symtree *result;
-
-  result = gfc_find_symtree (*root, name);
-  if (!result)
-    {
-      result = gfc_new_symtree (root, name);
-      gcc_assert (result);
-      result->n.tb = NULL;
-    }
-
-  return result;
+  gfc_symtree *result = gfc_find_symtree (*root, name);
+  return result ? result : gfc_new_symtree (root, name);
 }