]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/fortran/class.c
Update copyright years.
[thirdparty/gcc.git] / gcc / fortran / class.c
index 55e7ef4a56bab3a9c6d69c3be67763db69f36277..45fd5cbecaa2f3e727744cc821b608c8dc435624 100644 (file)
@@ -1,5 +1,5 @@
 /* Implementation of Fortran 2003 Polymorphism.
-   Copyright (C) 2009-2015 Free Software Foundation, Inc.
+   Copyright (C) 2009-2020 Free Software Foundation, Inc.
    Contributed by Paul Richard Thomas <pault@gcc.gnu.org>
    and Janus Weil <janus@gcc.gnu.org>
 
@@ -35,7 +35,7 @@ along with GCC; see the file COPYING3.  If not see
     * _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
+    * _len:  An integer(C_SIZE_T) 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'.
@@ -72,19 +72,22 @@ along with GCC; see the file COPYING3.  If not see
 static void
 insert_component_ref (gfc_typespec *ts, gfc_ref **ref, const char * const name)
 {
-  gfc_symbol *type_sym;
   gfc_ref *new_ref;
+  int wcnt, ecnt;
 
   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 (ts->u.derived, name, true, true, &new_ref);
+
+  gfc_get_errors (&wcnt, &ecnt);
+  if (ecnt > 0 && !new_ref)
+    return;
   gcc_assert (new_ref->u.c.component);
 
+  while (new_ref->next)
+    new_ref = new_ref->next;
+  new_ref->next = *ref;
+
   if (new_ref->next)
     {
       gfc_ref *next = NULL;
@@ -206,8 +209,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)
     {
@@ -224,7 +228,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.  */
@@ -234,14 +239,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;
+  }
 }
 
 
@@ -255,7 +264,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)
@@ -303,9 +312,7 @@ class_array_ref_detected (gfc_ref *ref, bool *full_array)
            *full_array = true;
        }
       else if (ref->next && ref->next->type == REF_ARRAY
-           && !ref->next->next
            && ref->type == REF_COMPONENT
-           && ref->next->type == REF_ARRAY
            && ref->next->u.ar.type != AR_ELEMENT)
        {
          with_data = true;
@@ -373,7 +380,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;
 
@@ -385,7 +393,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;
     }
@@ -474,8 +483,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)
@@ -557,7 +565,7 @@ gfc_intrinsic_hash_value (gfc_typespec *ts)
    ref to the _len component.  */
 
 gfc_expr *
-gfc_get_len_component (gfc_expr *e)
+gfc_get_len_component (gfc_expr *e, int k)
 {
   gfc_expr *ptr;
   gfc_ref *ref, **last;
@@ -581,7 +589,15 @@ gfc_get_len_component (gfc_expr *e)
       ref = ref->next;
     }
   /* And replace if with a ref to the _len component.  */
-  gfc_add_component_ref (ptr, "_len");
+  gfc_add_len_component (ptr);
+  if (k != ptr->ts.kind)
+    {
+      gfc_typespec ts;
+      gfc_clear_ts (&ts);
+      ts.type = BT_INTEGER;
+      ts.kind = k;
+      gfc_convert_type_warn (ptr, &ts, 2, 0);
+    }
   return ptr;
 }
 
@@ -597,7 +613,8 @@ bool
 gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr,
                        gfc_array_spec **as)
 {
-  char name[GFC_MAX_SYMBOL_LEN+1], tname[GFC_MAX_SYMBOL_LEN+1];
+  char tname[GFC_MAX_SYMBOL_LEN+1];
+  char *name;
   gfc_symbol *fclass;
   gfc_symbol *vtab;
   gfc_component *c;
@@ -621,24 +638,24 @@ gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr,
                   || attr->select_type_temporary || attr->associate_var;
 
   if (!attr->class_ok)
-    /* We can not build the class container yet.  */
+    /* We cannot build the class container yet.  */
     return true;
 
   /* Determine the name of the encapsulating type.  */
   rank = !(*as) || (*as)->rank == -1 ? GFC_MAX_DIMENSIONS : (*as)->rank;
   get_unique_hashed_string (tname, ts->u.derived);
   if ((*as) && attr->allocatable)
-    sprintf (name, "__class_%s_%d_%da", tname, rank, (*as)->corank);
+    name = xasprintf ("__class_%s_%d_%da", tname, rank, (*as)->corank);
   else if ((*as) && attr->pointer)
-    sprintf (name, "__class_%s_%d_%dp", tname, rank, (*as)->corank);
+    name = xasprintf ("__class_%s_%d_%dp", tname, rank, (*as)->corank);
   else if ((*as))
-    sprintf (name, "__class_%s_%d_%dt", tname, rank, (*as)->corank);
+    name = xasprintf ("__class_%s_%d_%dt", tname, rank, (*as)->corank);
   else if (attr->pointer)
-    sprintf (name, "__class_%s_p", tname);
+    name = xasprintf ("__class_%s_p", tname);
   else if (attr->allocatable)
-    sprintf (name, "__class_%s_a", tname);
+    name = xasprintf ("__class_%s_a", tname);
   else
-    sprintf (name, "__class_%s_t", tname);
+    name = xasprintf ("__class_%s_t", tname);
 
   if (ts->u.derived->attr.unlimited_polymorphic)
     {
@@ -704,7 +721,7 @@ gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr,
          if (!gfc_add_component (fclass, "_len", &c))
            return false;
          c->ts.type = BT_INTEGER;
-         c->ts.kind = 4;
+         c->ts.kind = gfc_charlen_int_kind;
          c->attr.access = ACCESS_PRIVATE;
          c->attr.artificial = 1;
        }
@@ -733,6 +750,7 @@ gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr,
   ts->u.derived = fclass;
   attr->allocatable = attr->pointer = attr->dimension = attr->codimension = 0;
   (*as) = NULL;
+  free (name);
   return true;
 }
 
@@ -745,10 +763,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)
     {
@@ -817,7 +835,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);
@@ -835,16 +853,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;
 }
 
@@ -881,7 +902,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;
@@ -889,6 +911,9 @@ finalize_component (gfc_expr *expr, gfc_symbol *derived, gfc_component *comp,
   if (!comp_is_finalizable (comp))
     return;
 
+  if (comp->finalized)
+    return;
+
   e = gfc_copy_expr (expr);
   if (!e->ref)
     e->ref = ref = gfc_get_ref ();
@@ -950,15 +975,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
@@ -994,9 +1037,11 @@ 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);
     }
+  comp->finalized = true;
 }
 
 
@@ -1048,6 +1093,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",
@@ -1064,6 +1110,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 ();
@@ -1120,6 +1167,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,
@@ -1140,6 +1188,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);
@@ -1148,6 +1197,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 ();
@@ -1163,6 +1213,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);
@@ -1173,6 +1224,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);
@@ -1184,6 +1236,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;
 }
 
@@ -1321,6 +1374,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.  */
 
@@ -1391,6 +1446,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);
@@ -1488,7 +1544,7 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
   gfc_component *comp;
   gfc_namespace *sub_ns;
   gfc_code *last_code, *block;
-  char name[GFC_MAX_SYMBOL_LEN+1];
+  char *name;
   bool finalizable_comp = false;
   bool expr_null_wrapper = false;
   gfc_expr *ancestor_wrapper = NULL, *rank;
@@ -1567,16 +1623,18 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
   sub_ns->resolved = 1;
 
   /* Set up the procedure symbol.  */
-  sprintf (name, "__final_%s", tname);
+  name = xasprintf ("__final_%s", tname);
   gfc_get_symbol (name, sub_ns, &final);
   sub_ns->proc_name = final;
   final->attr.flavor = FL_PROCEDURE;
   final->attr.function = 1;
   final->attr.pure = 0;
+  final->attr.recursive = 1;
   final->result = final;
   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;
@@ -1794,6 +1852,7 @@ 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).  */
   block->expr2->value.op.op1 = gfc_lval_expr_from_sym (sizes);
@@ -1805,6 +1864,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);
@@ -1858,6 +1918,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);
@@ -1895,6 +1956,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 ();
@@ -1927,7 +1989,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;
@@ -2051,7 +2113,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;
@@ -2100,7 +2162,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;
        }
@@ -2127,6 +2189,7 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
   gfc_free_expr (rank);
   vtab_final->initializer = gfc_lval_expr_from_sym (final);
   vtab_final->ts.interface = final;
+  free (name);
 }
 
 
@@ -2163,6 +2226,11 @@ 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;
+
+  if (derived->attr.pdt_template)
+    return NULL;
 
   /* Find the top-level namespace.  */
   for (ns = gfc_current_ns; ns; ns = ns->parent)
@@ -2173,15 +2241,40 @@ gfc_find_derived_vtab (gfc_symbol *derived)
   if (!derived->attr.unlimited_polymorphic && derived->attr.is_class)
     derived = gfc_get_derived_super_type (derived);
 
+  if (!derived)
+    return NULL;
+
+  /* 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];
+      char tname[GFC_MAX_SYMBOL_LEN+1];
+      char *name;
 
       get_unique_hashed_string (tname, derived);
-      sprintf (name, "__vtab_%s", tname);
+      name = xasprintf ("__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)
@@ -2199,13 +2292,27 @@ gfc_find_derived_vtab (gfc_symbol *derived)
          vtab->attr.vtab = 1;
          vtab->attr.access = ACCESS_PUBLIC;
          gfc_set_sym_referenced (vtab);
-         sprintf (name, "__vtype_%s", tname);
+         name = xasprintf ("__vtype_%s", tname);
 
          gfc_find_symbol (name, ns, 0, &vtype);
          if (vtype == NULL)
            {
              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,
@@ -2228,13 +2335,13 @@ gfc_find_derived_vtab (gfc_symbol *derived)
              if (!gfc_add_component (vtype, "_size", &c))
                goto cleanup;
              c->ts.type = BT_INTEGER;
-             c->ts.kind = 4;
+             c->ts.kind = gfc_size_kind;
              c->attr.access = ACCESS_PRIVATE;
              /* Remember the derived type in ts.u.derived,
                 so that the correct initializer can be set later on
                 (in gfc_conv_structure).  */
              c->ts.u.derived = derived;
-             c->initializer = gfc_get_int_expr (gfc_default_integer_kind,
+             c->initializer = gfc_get_int_expr (gfc_size_kind,
                                                 NULL, 0);
 
              /* Add component _extends.  */
@@ -2288,7 +2395,7 @@ gfc_find_derived_vtab (gfc_symbol *derived)
              else
                {
                  /* Construct default initialization variable.  */
-                 sprintf (name, "__def_init_%s", tname);
+                 name = xasprintf ("__def_init_%s", tname);
                  gfc_get_symbol (name, ns, &def_init);
                  def_init->attr.target = 1;
                  def_init->attr.artificial = 1;
@@ -2321,7 +2428,7 @@ gfc_find_derived_vtab (gfc_symbol *derived)
                  ns->contained = sub_ns;
                  sub_ns->resolved = 1;
                  /* Set up procedure symbol.  */
-                 sprintf (name, "__copy_%s", tname);
+                 name = xasprintf ("__copy_%s", tname);
                  gfc_get_symbol (name, sub_ns, &copy);
                  sub_ns->proc_name = copy;
                  copy->attr.flavor = FL_PROCEDURE;
@@ -2374,10 +2481,71 @@ gfc_find_derived_vtab (gfc_symbol *derived)
                goto cleanup;
              c->attr.proc_pointer = 1;
              c->attr.access = ACCESS_PRIVATE;
+             c->attr.artificial = 1;
              c->tb = XCNEW (gfc_typebound_proc);
              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.  */
+                 name = xasprintf ("__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);
@@ -2387,6 +2555,7 @@ have_vtype:
          vtab->ts.u.derived = vtype;
          vtab->value = gfc_default_initializer (&vtab->ts);
        }
+      free (name);
     }
 
   found_sym = vtab;
@@ -2407,6 +2576,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 ();
@@ -2466,11 +2639,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 && !ts->deferred && 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)
@@ -2479,20 +2647,17 @@ find_intrinsic_vtab (gfc_typespec *ts)
 
   if (ns)
     {
-      char name[GFC_MAX_SYMBOL_LEN+1], tname[GFC_MAX_SYMBOL_LEN+1];
+      char tname[GFC_MAX_SYMBOL_LEN+1];
+      char *name;
 
-      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);
+      name = xasprintf ("__vtab_%s", tname);
 
-      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)
        {
@@ -2506,7 +2671,7 @@ find_intrinsic_vtab (gfc_typespec *ts)
          vtab->attr.vtab = 1;
          vtab->attr.access = ACCESS_PUBLIC;
          gfc_set_sym_referenced (vtab);
-         sprintf (name, "__vtype_%s", tname);
+         name = xasprintf ("__vtype_%s", tname);
 
          gfc_find_symbol (name, ns, 0, &vtype);
          if (vtype == NULL)
@@ -2516,6 +2681,7 @@ find_intrinsic_vtab (gfc_typespec *ts)
              gfc_namespace *sub_ns;
              gfc_namespace *contained;
              gfc_expr *e;
+             size_t e_size;
 
              gfc_get_symbol (name, ns, &vtype);
              if (!gfc_add_flavor (&vtype->attr, FL_DERIVED, NULL,
@@ -2539,17 +2705,24 @@ find_intrinsic_vtab (gfc_typespec *ts)
              if (!gfc_add_component (vtype, "_size", &c))
                goto cleanup;
              c->ts.type = BT_INTEGER;
-             c->ts.kind = 4;
+             c->ts.kind = gfc_size_kind;
              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,
+             if (ts->type == BT_CHARACTER)
+               e_size = ts->kind;
+             else
+               gfc_element_size (e, &e_size);
+             c->initializer = gfc_get_int_expr (gfc_size_kind,
                                                 NULL,
-                                                (int)gfc_element_size (e));
+                                                e_size);
              gfc_free_expr (e);
 
              /* Add component _extends.  */
@@ -2577,12 +2750,12 @@ find_intrinsic_vtab (gfc_typespec *ts)
              c->tb->ppc = 1;
 
              if (ts->type != BT_CHARACTER)
-               sprintf (name, "__copy_%s", tname);
+               name = xasprintf ("__copy_%s", tname);
              else
                {
                  /* __copy is always the same for characters.
                     Check to see if copy function already exists.  */
-                 sprintf (name, "__copy_character_%d", ts->kind);
+                 name = xasprintf ("__copy_character_%d", ts->kind);
                  contained = ns->contained;
                  for (; contained; contained = contained->sibling)
                    if (contained->proc_name
@@ -2608,9 +2781,9 @@ find_intrinsic_vtab (gfc_typespec *ts)
              /* This is elemental so that arrays are automatically
                 treated correctly by the scalarizer.  */
              copy->attr.elemental = 1;
-             if (ns->proc_name->attr.flavor == FL_MODULE)
+             if (ns->proc_name && ns->proc_name->attr.flavor == FL_MODULE)
                copy->module = ns->proc_name->name;
-                 gfc_set_sym_referenced (copy);
+             gfc_set_sym_referenced (copy);
              /* Set up formal arguments.  */
              gfc_get_symbol ("src", sub_ns, &src);
              src->ts.type = ts->type;
@@ -2644,6 +2817,7 @@ find_intrinsic_vtab (gfc_typespec *ts)
                goto cleanup;
              c->attr.proc_pointer = 1;
              c->attr.access = ACCESS_PRIVATE;
+             c->attr.artificial = 1;
              c->tb = XCNEW (gfc_typebound_proc);
              c->tb->ppc = 1;
              c->initializer = gfc_get_null_expr (NULL);
@@ -2651,6 +2825,7 @@ find_intrinsic_vtab (gfc_typespec *ts)
          vtab->ts.u.derived = vtype;
          vtab->value = gfc_default_initializer (&vtab->ts);
        }
+      free (name);
     }
 
   found_sym = vtab;
@@ -2689,7 +2864,10 @@ gfc_find_vtab (gfc_typespec *ts)
     case BT_DERIVED:
       return gfc_find_derived_vtab (ts->u.derived);
     case BT_CLASS:
-      return gfc_find_derived_vtab (ts->u.derived->components->ts.u.derived);
+      if (ts->u.derived->components && ts->u.derived->components->ts.u.derived)
+       return gfc_find_derived_vtab (ts->u.derived->components->ts.u.derived);
+      else
+       return NULL;
     default:
       return find_intrinsic_vtab (ts);
     }
@@ -2836,15 +3014,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);
 }