]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/fortran/class.c
Update copyright years.
[thirdparty/gcc.git] / gcc / fortran / class.c
index 1b1e85d07c05a995cdaf53a799dad06c73501c4f..45fd5cbecaa2f3e727744cc821b608c8dc435624 100644 (file)
@@ -1,6 +1,5 @@
 /* Implementation of Fortran 2003 Polymorphism.
-   Copyright (C) 2009, 2010, 2011, 2012, 2013
-   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,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(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'.
+
    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.
@@ -54,6 +59,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "gfortran.h"
 #include "constructor.h"
+#include "target-memory.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
@@ -66,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;
@@ -165,7 +174,23 @@ gfc_fix_class_refs (gfc_expr *e)
          && e->value.function.isym != NULL))
     return;
 
-  ts = &e->symtree->n.sym->ts;
+  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)
     {
@@ -184,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)
     {
@@ -202,16 +228,29 @@ gfc_add_component_ref (gfc_expr *e, const char *name)
        break;
       tail = &((*tail)->next);
     }
+  if (derived->components && derived->components->next &&
+      derived->components->next->ts.type == BT_DERIVED &&
+      derived->components->next->ts.u.derived == NULL)
+    {
+      /* Fix up missing vtype.  */
+      gfc_symbol *vtab = gfc_find_derived_vtab (derived->components->ts.u.derived);
+      gcc_assert (vtab);
+      derived->components->next->ts.u.derived = vtab->ts.u.derived;
+    }
   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;
+  }
 }
 
 
@@ -225,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)
@@ -273,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;
@@ -343,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;
 
@@ -355,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;
     }
@@ -397,26 +436,21 @@ gfc_is_class_container_ref (gfc_expr *e)
 }
 
 
-/* Build a NULL initializer for CLASS pointers,
-   initializing the _data component to NULL and
-   the _vptr component to the declared type.  */
+/* Build an initializer for CLASS pointers,
+   initializing the _data component to the init_expr (or NULL) and the _vptr
+   component to the corresponding type (or the declared type, given by ts).  */
 
 gfc_expr *
-gfc_class_null_initializer (gfc_typespec *ts, gfc_expr *init_expr)
+gfc_class_initializer (gfc_typespec *ts, gfc_expr *init_expr)
 {
   gfc_expr *init;
   gfc_component *comp;
   gfc_symbol *vtab = NULL;
-  bool is_unlimited_polymorphic;
-
-  is_unlimited_polymorphic = ts->u.derived
-      && ts->u.derived->components->ts.u.derived
-      && ts->u.derived->components->ts.u.derived->attr.unlimited_polymorphic;
 
-  if (is_unlimited_polymorphic && init_expr)
-    vtab = gfc_find_intrinsic_vtab (&ts->u.derived->components->ts);
+  if (init_expr && init_expr->expr_type != EXPR_NULL)
+    vtab = gfc_find_vtab (&init_expr->ts);
   else
-    vtab = gfc_find_derived_vtab (ts->u.derived);
+    vtab = gfc_find_vtab (ts);
 
   init = gfc_get_structure_constructor_expr (ts->type, ts->kind,
                                             &ts->u.derived->declared_at);
@@ -427,6 +461,8 @@ gfc_class_null_initializer (gfc_typespec *ts, gfc_expr *init_expr)
       gfc_constructor *ctor = gfc_constructor_get();
       if (strcmp (comp->name, "_vptr") == 0 && vtab)
        ctor->expr = gfc_lval_expr_from_sym (vtab);
+      else if (init_expr && init_expr->expr_type != EXPR_NULL)
+         ctor->expr = gfc_copy_expr (init_expr);
       else
        ctor->expr = gfc_get_null_expr (NULL);
       gfc_constructor_append (&init->value.constructor, ctor);
@@ -445,10 +481,9 @@ get_unique_type_string (char *string, gfc_symbol *derived)
 {
   char dt_name[GFC_MAX_SYMBOL_LEN+1];
   if (derived->attr.unlimited_polymorphic)
-    sprintf (dt_name, "%s", "$tar");
+    strcpy (dt_name, "STAR");
   else
-  sprintf (dt_name, "%s", 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)
@@ -523,16 +558,63 @@ 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, int k)
+{
+  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);
+  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;
+}
+
+
 /* 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.  */
 
-gfc_try
+bool
 gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr,
-                       gfc_array_spec **as, bool delayed_vtab)
+                       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;
@@ -545,35 +627,35 @@ gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr,
     {
       gfc_error ("Assumed size polymorphic objects or components, such "
                 "as that at %C, have not yet been implemented");
-      return FAILURE;
+      return false;
     }
 
   if (attr->class_ok)
     /* Class container has already been built.  */
-    return SUCCESS;
+    return true;
 
   attr->class_ok = attr->dummy || attr->pointer || attr->allocatable
-                  || attr->select_type_temporary;
+                  || attr->select_type_temporary || attr->associate_var;
 
   if (!attr->class_ok)
-    /* We can not build the class container yet.  */
-    return SUCCESS;
+    /* 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_%d", 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", tname);
+    name = xasprintf ("__class_%s_t", tname);
 
   if (ts->u.derived->attr.unlimited_polymorphic)
     {
@@ -599,13 +681,13 @@ gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr,
       if (!ts->u.derived->attr.unlimited_polymorphic)
        fclass->attr.abstract = ts->u.derived->attr.abstract;
       fclass->f2k_derived = gfc_get_namespace (NULL, 0);
-      if (gfc_add_flavor (&fclass->attr, FL_DERIVED,
-         NULL, &gfc_current_locus) == FAILURE)
-       return FAILURE;
+      if (!gfc_add_flavor (&fclass->attr, FL_DERIVED, NULL,
+                          &gfc_current_locus))
+       return false;
 
       /* Add component '_data'.  */
-      if (gfc_add_component (fclass, "_data", &c) == FAILURE)
-       return FAILURE;
+      if (!gfc_add_component (fclass, "_data", &c))
+       return false;
       c->ts = *ts;
       c->ts.type = BT_DERIVED;
       c->attr.access = ACCESS_PRIVATE;
@@ -621,21 +703,31 @@ gfc_build_class_symbol (gfc_typespec *ts, symbol_attribute *attr,
       c->initializer = NULL;
 
       /* Add component '_vptr'.  */
-      if (gfc_add_component (fclass, "_vptr", &c) == FAILURE)
-       return FAILURE;
+      if (!gfc_add_component (fclass, "_vptr", &c))
+       return false;
       c->ts.type = BT_DERIVED;
-      if (delayed_vtab
-         || (ts->u.derived->f2k_derived
-             && ts->u.derived->f2k_derived->finalizers))
-       c->ts.u.derived = NULL;
-      else
+      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;
        }
-      c->attr.access = ACCESS_PRIVATE;
-      c->attr.pointer = 1;
+      else
+       /* Build vtab later.  */
+       c->ts.u.derived = NULL;
     }
 
   if (!ts->u.derived->attr.unlimited_polymorphic)
@@ -644,20 +736,22 @@ 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 FAILURE;
+       return false;
        }
 
       fclass->attr.extension = ts->u.derived->attr.extension + 1;
       fclass->attr.alloc_comp = ts->u.derived->attr.alloc_comp;
+      fclass->attr.coarray_comp = ts->u.derived->attr.coarray_comp;
     }
 
   fclass->attr.is_class = 1;
   ts->u.derived = fclass;
   attr->allocatable = attr->pointer = attr->dimension = attr->codimension = 0;
   (*as) = NULL;
-  return SUCCESS;
+  free (name);
+  return true;
 }
 
 
@@ -669,15 +763,15 @@ 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)
     {
       /* Add procedure component.  */
-      if (gfc_add_component (vtype, name, &c) == FAILURE)
+      if (!gfc_add_component (vtype, name, &c))
        return;
 
       if (!c->tb)
@@ -700,9 +794,11 @@ add_proc_comp (gfc_symbol *vtype, const char *name, gfc_typebound_proc *tb)
 
   if (tb->u.specific)
     {
-      c->ts.interface = tb->u.specific->n.sym;
+      gfc_symbol *ifc = tb->u.specific->n.sym;
+      c->ts.interface = ifc;
       if (!tb->deferred)
        c->initializer = gfc_get_variable_expr (tb->u.specific);
+      c->attr.pure = ifc->attr.pure;
     }
 }
 
@@ -739,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);
@@ -757,20 +853,44 @@ 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;
 }
 
 
+static bool
+comp_is_finalizable (gfc_component *comp)
+{
+  if (comp->attr.proc_pointer)
+    return false;
+  else if (comp->attr.allocatable && comp->ts.type != BT_CLASS)
+    return true;
+  else if (comp->ts.type == BT_DERIVED && !comp->attr.pointer
+          && (comp->ts.u.derived->attr.alloc_comp
+              || has_finalizer_component (comp->ts.u.derived)
+              || (comp->ts.u.derived->f2k_derived
+                  && comp->ts.u.derived->f2k_derived->finalizers)))
+    return true;
+  else if (comp->ts.type == BT_CLASS && CLASS_DATA (comp)
+           && CLASS_DATA (comp)->attr.allocatable)
+    return true;
+  else
+    return false;
+}
+
+
 /* Call DEALLOCATE for the passed component if it is allocatable, if it is
    neither allocatable nor a pointer but has a finalizer, call it. If it
    is a nonpointer component with allocatable components or has finalizers, walk
@@ -782,24 +902,16 @@ has_finalizer_component (gfc_symbol *derived)
 
 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;
 
-  if (comp->ts.type != BT_DERIVED && comp->ts.type != BT_CLASS
-      && !comp->attr.allocatable)
-    return;
-
-  if ((comp->ts.type == BT_DERIVED && comp->attr.pointer)
-      || (comp->ts.type == BT_CLASS && CLASS_DATA (comp)
-         && CLASS_DATA (comp)->attr.pointer))
+  if (!comp_is_finalizable (comp))
     return;
 
-  if (comp->ts.type == BT_DERIVED && !comp->attr.allocatable
-      && (comp->ts.u.derived->f2k_derived == NULL
-         || comp->ts.u.derived->f2k_derived->finalizers == NULL)
-      && !has_finalizer_component (comp->ts.u.derived))
+  if (comp->finalized)
     return;
 
   e = gfc_copy_expr (expr);
@@ -817,17 +929,18 @@ finalize_component (gfc_expr *expr, gfc_symbol *derived, gfc_component *comp,
   ref->u.c.component = comp;
   e->ts = comp->ts;
 
-  if (comp->attr.dimension
+  if (comp->attr.dimension || comp->attr.codimension
       || (comp->ts.type == BT_CLASS && CLASS_DATA (comp)
-         && CLASS_DATA (comp)->attr.dimension))
+         && (CLASS_DATA (comp)->attr.dimension
+             || CLASS_DATA (comp)->attr.codimension)))
     {
       ref->next = gfc_get_ref ();
       ref->next->type = REF_ARRAY;
-      ref->next->u.ar.type = AR_FULL;
       ref->next->u.ar.dimen = 0;
       ref->next->u.ar.as = comp->ts.type == BT_CLASS ? CLASS_DATA (comp)->as
                                                        : comp->as;
       e->rank = ref->next->u.ar.as->rank;
+      ref->next->u.ar.type = e->rank ? AR_FULL : AR_ELEMENT;
     }
 
   /* Call DEALLOCATE (comp, stat=ignore).  */
@@ -840,9 +953,9 @@ 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 = XCNEW (gfc_code);
+         block = gfc_get_code (EXEC_IF);
          if (*code)
            {
              (*code)->next = block;
@@ -851,33 +964,44 @@ finalize_component (gfc_expr *expr, gfc_symbol *derived, gfc_component *comp,
          else
              (*code) = block;
 
-         block->loc = gfc_current_locus;
-         block->op = EXEC_IF;
-
-         block->block = XCNEW (gfc_code);
+         block->block = gfc_get_code (EXEC_IF);
          block = block->block;
-         block->loc = gfc_current_locus;
-         block->op = EXEC_IF;
          block->expr1 = gfc_lval_expr_from_sym (fini_coarray);
        }
 
-      dealloc = XCNEW (gfc_code);
-      dealloc->op = EXEC_DEALLOCATE;
-      dealloc->loc = gfc_current_locus;
+      dealloc = gfc_get_code (EXEC_DEALLOCATE);
 
       dealloc->ext.alloc.list = gfc_get_alloc ();
       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
@@ -894,10 +1018,7 @@ finalize_component (gfc_expr *expr, gfc_symbol *derived, gfc_component *comp,
          break;
 
       gcc_assert (c);
-      final_wrap = XCNEW (gfc_code);
-      final_wrap->op = EXEC_CALL;
-      final_wrap->loc = gfc_current_locus;
-      final_wrap->loc = gfc_current_locus;
+      final_wrap = gfc_get_code (EXEC_CALL);
       final_wrap->symtree = c->initializer->symtree;
       final_wrap->resolved_sym = c->initializer->symtree->n.sym;
       final_wrap->ext.actual = gfc_get_actual_arglist ();
@@ -916,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;
 }
 
 
@@ -934,15 +1057,15 @@ finalization_scalarizer (gfc_symbol *array, gfc_symbol *ptr,
   gfc_expr *expr, *expr2;
 
   /* C_F_POINTER().  */
-  block = XCNEW (gfc_code);
-  block->op = EXEC_CALL;
-  block->loc = gfc_current_locus;
+  block = gfc_get_code (EXEC_CALL);
   gfc_get_sym_tree ("c_f_pointer", sub_ns, &block->symtree, true);
   block->resolved_sym = block->symtree->n.sym;
   block->resolved_sym->attr.flavor = FL_PROCEDURE;
   block->resolved_sym->attr.intrinsic = 1;
+  block->resolved_sym->attr.subroutine = 1;
   block->resolved_sym->from_intmod = INTMOD_ISO_C_BINDING;
   block->resolved_sym->intmod_sym_id = ISOCBINDING_F_POINTER;
+  block->resolved_isym = gfc_intrinsic_subroutine_by_id (GFC_ISYM_C_F_POINTER);
   gfc_commit_symbol (block->resolved_sym);
 
   /* C_F_POINTER's first argument: TRANSFER ( <addr>, c_intptr_t).  */
@@ -950,34 +1073,10 @@ 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.  */
 
   /* The <addr> part: TRANSFER (C_LOC (array), c_intptr_t).  */
 
-  /* TRANSFER.  */
-  expr2 = gfc_get_expr ();
-  expr2->expr_type = EXPR_FUNCTION;
-  expr2->value.function.name = "__transfer0";
-  expr2->value.function.isym
-           = gfc_intrinsic_function_by_id (GFC_ISYM_TRANSFER);
-  /* Set symtree for -fdump-parse-tree.  */
-  gfc_get_sym_tree ("transfer", sub_ns, &expr2->symtree, false);
-  expr2->symtree->n.sym->intmod_sym_id = GFC_ISYM_TRANSFER;
-  expr2->symtree->n.sym->attr.flavor = FL_PROCEDURE;
-  expr2->symtree->n.sym->attr.intrinsic = 1;
-  gfc_commit_symbol (expr2->symtree->n.sym);
-  expr2->value.function.actual = gfc_get_actual_arglist ();
-  expr2->value.function.actual->expr
-           = gfc_lval_expr_from_sym (array);
-  expr2->ts.type = BT_INTEGER;
-  expr2->ts.kind = gfc_index_integer_kind;
-
-  /* TRANSFER's second argument: 0_c_intptr_t.  */
-  expr2->value.function.actual = gfc_get_actual_arglist ();
-  expr2->value.function.actual->next = gfc_get_actual_arglist ();
-  expr2->value.function.actual->next->expr
-               = gfc_get_int_expr (gfc_index_integer_kind, NULL, 0);
-  expr2->value.function.actual->next->next = gfc_get_actual_arglist ();
-
   /* TRANSFER's first argument: C_LOC (array).  */
   expr = gfc_get_expr ();
   expr->expr_type = EXPR_FUNCTION;
@@ -986,7 +1085,7 @@ finalization_scalarizer (gfc_symbol *array, gfc_symbol *ptr,
   expr->symtree->n.sym->intmod_sym_id = ISOCBINDING_LOC;
   expr->symtree->n.sym->attr.intrinsic = 1;
   expr->symtree->n.sym->from_intmod = INTMOD_ISO_C_BINDING;
-  expr->value.function.esym = expr->symtree->n.sym;
+  expr->value.function.isym = gfc_intrinsic_function_by_id (GFC_ISYM_C_LOC);
   expr->value.function.actual = gfc_get_actual_arglist ();
   expr->value.function.actual->expr
            = gfc_lval_expr_from_sym (array);
@@ -994,7 +1093,15 @@ 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;
-  expr2->value.function.actual->expr = expr;
+  expr->where = gfc_current_locus;
+
+  /* TRANSFER.  */
+  expr2 = gfc_build_intrinsic_call (sub_ns, GFC_ISYM_TRANSFER, "transfer",
+                                   gfc_current_locus, 3, expr,
+                                   gfc_get_int_expr (gfc_index_integer_kind,
+                                                     NULL, 0), NULL);
+  expr2->ts.type = BT_INTEGER;
+  expr2->ts.kind = gfc_index_integer_kind;
 
   /* <array addr> + <offset>.  */
   block->ext.actual->expr = gfc_get_expr ();
@@ -1003,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 ();
@@ -1031,10 +1139,8 @@ finalization_get_offset (gfc_symbol *idx, gfc_symbol *idx2, gfc_symbol *offset,
   gfc_expr *expr, *expr2;
 
   /* offset = 0.  */
-  block->next = XCNEW (gfc_code);
+  block->next = gfc_get_code (EXEC_ASSIGN);
   block = block->next;
-  block->op = EXEC_ASSIGN;
-  block->loc = gfc_current_locus;
   block->expr1 = gfc_lval_expr_from_sym (offset);
   block->expr2 = gfc_get_int_expr (gfc_index_integer_kind, NULL, 0);
 
@@ -1044,39 +1150,28 @@ finalization_get_offset (gfc_symbol *idx, gfc_symbol *idx2, gfc_symbol *offset,
   iter->start = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
   iter->end = gfc_copy_expr (rank);
   iter->step = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
-  block->next = XCNEW (gfc_code);
+  block->next = gfc_get_code (EXEC_DO);
   block = block->next;
-  block->op = EXEC_DO;
-  block->loc = gfc_current_locus;
   block->ext.iterator = iter;
-  block->block = gfc_get_code ();
-  block->block->op = EXEC_DO;
+  block->block = gfc_get_code (EXEC_DO);
 
   /* Loop body: offset = offset + mod (idx, sizes(idx2)) / sizes(idx2-1)
                                  * strides(idx2).  */
 
   /* mod (idx, sizes(idx2)).  */
-  expr = gfc_get_expr ();
-  expr->expr_type = EXPR_FUNCTION;
-  expr->value.function.isym = gfc_intrinsic_function_by_id (GFC_ISYM_MOD);
-  gfc_get_sym_tree ("mod", sub_ns, &expr->symtree, false);
-  expr->symtree->n.sym->intmod_sym_id = GFC_ISYM_MOD;
-  expr->symtree->n.sym->attr.flavor = FL_PROCEDURE;
-  expr->symtree->n.sym->attr.intrinsic = 1;
-  gfc_commit_symbol (expr->symtree->n.sym);
-  expr->value.function.actual = gfc_get_actual_arglist ();
-  expr->value.function.actual->expr = gfc_lval_expr_from_sym (idx);
-  expr->value.function.actual->next = gfc_get_actual_arglist ();
-  expr->value.function.actual->next->expr = gfc_lval_expr_from_sym (sizes);
-  expr->value.function.actual->next->expr->ref = gfc_get_ref ();
-  expr->value.function.actual->next->expr->ref->type = REF_ARRAY;
-  expr->value.function.actual->next->expr->ref->u.ar.as = sizes->as;
-  expr->value.function.actual->next->expr->ref->u.ar.type = AR_ELEMENT;
-  expr->value.function.actual->next->expr->ref->u.ar.dimen = 1;
-  expr->value.function.actual->next->expr->ref->u.ar.dimen_type[0]
-       = DIMEN_ELEMENT;
-  expr->value.function.actual->next->expr->ref->u.ar.start[0]
-       = gfc_lval_expr_from_sym (idx2);
+  expr = gfc_lval_expr_from_sym (sizes);
+  expr->ref = gfc_get_ref ();
+  expr->ref->type = REF_ARRAY;
+  expr->ref->u.ar.as = sizes->as;
+  expr->ref->u.ar.type = AR_ELEMENT;
+  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,
+                                  gfc_lval_expr_from_sym (idx), expr);
   expr->ts = idx->ts;
 
   /* (...) / sizes(idx2-1).  */
@@ -1093,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);
@@ -1101,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 ();
@@ -1116,11 +1213,10 @@ 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 = XCNEW (gfc_code);
-  block->block->next->op = EXEC_ASSIGN;
-  block->block->next->loc = gfc_current_locus;
+  block->block->next = gfc_get_code (EXEC_ASSIGN);
   block->block->next->expr1 = gfc_lval_expr_from_sym (offset);
   block->block->next->expr2 = gfc_get_expr ();
   block->block->next->expr2->expr_type = EXPR_OP;
@@ -1128,12 +1224,11 @@ 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 = XCNEW (gfc_code);
+  block->next = gfc_get_code (EXEC_ASSIGN);
   block = block->next;
-  block->op = EXEC_ASSIGN;
-  block->loc = gfc_current_locus;
   block->expr1 = gfc_lval_expr_from_sym (offset);
   block->expr2 = gfc_get_expr ();
   block->expr2->expr_type = EXPR_OP;
@@ -1141,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;
 }
 
@@ -1179,7 +1275,7 @@ static void
 finalizer_insert_packed_call (gfc_code *block, gfc_finalizer *fini,
                              gfc_symbol *array, gfc_symbol *byte_stride,
                              gfc_symbol *idx, gfc_symbol *ptr,
-                             gfc_symbol *nelem, gfc_symtree *size_intr,
+                             gfc_symbol *nelem,
                              gfc_symbol *strides, gfc_symbol *sizes,
                              gfc_symbol *idx2, gfc_symbol *offset,
                              gfc_symbol *is_contiguous, gfc_expr *rank,
@@ -1192,15 +1288,11 @@ finalizer_insert_packed_call (gfc_code *block, gfc_finalizer *fini,
   gfc_code *block2;
   int i;
 
-  block->next = XCNEW (gfc_code);
+  block->next = gfc_get_code (EXEC_IF);
   block = block->next;
-  block->loc = gfc_current_locus;
-  block->op = EXEC_IF;
 
-  block->block = XCNEW (gfc_code);
+  block->block = gfc_get_code (EXEC_IF);
   block = block->block;
-  block->loc = gfc_current_locus;
-  block->op = EXEC_IF;
 
   /* size_expr = STORAGE_SIZE (...) / NUMERIC_STORAGE_SIZE.  */
   size_expr = gfc_get_expr ();
@@ -1209,24 +1301,12 @@ finalizer_insert_packed_call (gfc_code *block, gfc_finalizer *fini,
   size_expr->value.op.op = INTRINSIC_DIVIDE;
 
   /* STORAGE_SIZE (array,kind=c_intptr_t).  */
-  size_expr->value.op.op1 = gfc_get_expr ();
-  size_expr->value.op.op1->where = gfc_current_locus;
-  size_expr->value.op.op1->expr_type = EXPR_FUNCTION;
-  size_expr->value.op.op1->value.function.isym
-               = gfc_intrinsic_function_by_id (GFC_ISYM_STORAGE_SIZE);
-  gfc_get_sym_tree ("storage_size", sub_ns, &size_expr->value.op.op1->symtree,
-                   false);
-  size_expr->value.op.op1->symtree->n.sym->intmod_sym_id
-       = GFC_ISYM_STORAGE_SIZE;
-  size_expr->value.op.op1->symtree->n.sym->attr.flavor = FL_PROCEDURE;
-  size_expr->value.op.op1->symtree->n.sym->attr.intrinsic = 1;
-  gfc_commit_symbol (size_expr->value.op.op1->symtree->n.sym);
-  size_expr->value.op.op1->value.function.actual = gfc_get_actual_arglist ();
-  size_expr->value.op.op1->value.function.actual->expr
-               = gfc_lval_expr_from_sym (array);
-  size_expr->value.op.op1->value.function.actual->next = gfc_get_actual_arglist ();
-  size_expr->value.op.op1->value.function.actual->next->expr
-               = gfc_get_int_expr (gfc_index_integer_kind, NULL, 0);
+  size_expr->value.op.op1
+       = gfc_build_intrinsic_call (sub_ns, GFC_ISYM_STORAGE_SIZE,
+                                   "storage_size", gfc_current_locus, 2,
+                                   gfc_lval_expr_from_sym (array),
+                                   gfc_get_int_expr (gfc_index_integer_kind,
+                                                     NULL, 0));
 
   /* NUMERIC_STORAGE_SIZE.  */
   size_expr->value.op.op2 = gfc_get_int_expr (gfc_index_integer_kind, NULL,
@@ -1239,7 +1319,6 @@ finalizer_insert_packed_call (gfc_code *block, gfc_finalizer *fini,
                        || is_contiguous)
                   || 0 == size_expr.  */
   block->expr1 = gfc_get_expr ();
-  block->expr1->expr_type = EXPR_FUNCTION;
   block->expr1->ts.type = BT_LOGICAL;
   block->expr1->ts.kind = gfc_default_logical_kind;
   block->expr1->expr_type = EXPR_OP;
@@ -1258,8 +1337,9 @@ finalizer_insert_packed_call (gfc_code *block, gfc_finalizer *fini,
        = gfc_lval_expr_from_sym (byte_stride);
   expr->value.op.op2 = size_expr;
 
-  /* If strides aren't allowd (not assumed shape or CONTIGUOUS),
+  /* If strides aren't allowed (not assumed shape or CONTIGUOUS),
      add is_contiguous check.  */
+
   if (fini->proc_tree->n.sym->formal->sym->as->type != AS_ASSUMED_SHAPE
       || fini->proc_tree->n.sym->formal->sym->attr.contiguous)
     {
@@ -1289,27 +1369,23 @@ finalizer_insert_packed_call (gfc_code *block, gfc_finalizer *fini,
   block->expr1->value.op.op2->value.op.op2 = gfc_copy_expr (size_expr);
 
   /* IF body: call final subroutine.  */
-  block->next = XCNEW (gfc_code);
-  block->next->op = EXEC_CALL;
-  block->next->loc = gfc_current_locus;
+  block->next = gfc_get_code (EXEC_CALL);
   block->next->symtree = fini->proc_tree;
   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.  */
 
-  block->block = XCNEW (gfc_code);
+  block->block = gfc_get_code (EXEC_IF);
   block = block->block;
-  block->loc = gfc_current_locus;
-  block->op = EXEC_IF;
 
-  block->next = XCNEW (gfc_code);
+  /* BLOCK ... END BLOCK.  */
+  block->next = gfc_get_code (EXEC_BLOCK);
   block = block->next;
 
-  /* BLOCK ... END BLOCK.  */
-  block->op = EXEC_BLOCK;
-  block->loc = gfc_current_locus;
   ns = gfc_build_block_ns (sub_ns);
   block->ext.block.ns = ns;
   block->ext.block.assoc = NULL;
@@ -1339,22 +1415,17 @@ finalizer_insert_packed_call (gfc_code *block, gfc_finalizer *fini,
       gfc_expr *shape_expr;
       tmp_array->as->lower[i] = gfc_get_int_expr (gfc_default_integer_kind,
                                                  NULL, 1);
-      /* SIZE (array, dim=i+1, kind=default_kind).  */
-      shape_expr = gfc_get_expr ();
-      shape_expr->expr_type = EXPR_FUNCTION;
-      shape_expr->value.function.isym
-                               = gfc_intrinsic_function_by_id (GFC_ISYM_SIZE);
-      shape_expr->symtree = size_intr;
-      shape_expr->value.function.actual = gfc_get_actual_arglist ();
-      shape_expr->value.function.actual->expr = gfc_lval_expr_from_sym (array);
-      shape_expr->value.function.actual->next = gfc_get_actual_arglist ();
-      shape_expr->value.function.actual->next->expr
-               = gfc_get_int_expr (gfc_default_integer_kind, NULL, i+1);
-      shape_expr->value.function.actual->next->next = gfc_get_actual_arglist ();
-      shape_expr->value.function.actual->next->next->expr
-               = gfc_get_int_expr (gfc_default_integer_kind, NULL, 0);
-      shape_expr->ts = shape_expr->value.function.isym->ts;
-
+      /* SIZE (array, dim=i+1, kind=gfc_index_integer_kind).  */
+      shape_expr
+       = gfc_build_intrinsic_call (sub_ns, GFC_ISYM_SIZE, "size",
+                                   gfc_current_locus, 3,
+                                   gfc_lval_expr_from_sym (array),
+                                   gfc_get_int_expr (gfc_default_integer_kind,
+                                                     NULL, i+1),
+                                   gfc_get_int_expr (gfc_default_integer_kind,
+                                                     NULL,
+                                                     gfc_index_integer_kind));
+      shape_expr->ts.kind = gfc_index_integer_kind;
       tmp_array->as->upper[i] = shape_expr;
     }
   gfc_set_sym_referenced (tmp_array);
@@ -1367,18 +1438,15 @@ finalizer_insert_packed_call (gfc_code *block, gfc_finalizer *fini,
   iter->end = gfc_lval_expr_from_sym (nelem);
   iter->step = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
 
-  block = XCNEW (gfc_code);
+  block = gfc_get_code (EXEC_DO);
   ns->code = block;
-  block->op = EXEC_DO;
-  block->loc = gfc_current_locus;
   block->ext.iterator = iter;
-  block->block = gfc_get_code ();
-  block->block->op = EXEC_DO;
+  block->block = gfc_get_code (EXEC_DO);
 
   /* Offset calculation for the new array: idx * size of type (in bytes).  */
   offset2 = gfc_get_expr ();
-  offset2 = block->ext.actual->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);
@@ -1396,19 +1464,17 @@ finalizer_insert_packed_call (gfc_code *block, gfc_finalizer *fini,
                                          sub_ns);
   block2 = block2->next;
   block2->next = finalization_scalarizer (tmp_array, ptr2, offset2, sub_ns);
+  block2 = block2->next;
 
   /* ptr2 = ptr.  */
-  block2->next = XCNEW (gfc_code);
-  block2->next->op = EXEC_ASSIGN;
-  block2->next->loc = gfc_current_locus;
-  block2->next->expr1 = gfc_lval_expr_from_sym (ptr2);
-  block2->next->expr2 = gfc_lval_expr_from_sym (ptr);
-
-  /* Call now the user's final subroutine. */
-  block->next  = XCNEW (gfc_code);
+  block2->next = gfc_get_code (EXEC_ASSIGN);
+  block2 = block2->next;
+  block2->expr1 = gfc_lval_expr_from_sym (ptr2);
+  block2->expr2 = gfc_lval_expr_from_sym (ptr);
+
+  /* Call now the user's final subroutine.  */
+  block->next  = gfc_get_code (EXEC_CALL);
   block = block->next;
-  block->op = EXEC_CALL;
-  block->loc = gfc_current_locus;
   block->symtree = fini->proc_tree;
   block->resolved_sym = fini->proc_tree->n.sym;
   block->ext.actual = gfc_get_actual_arglist ();
@@ -1426,13 +1492,10 @@ finalizer_insert_packed_call (gfc_code *block, gfc_finalizer *fini,
   iter->end = gfc_lval_expr_from_sym (nelem);
   iter->step = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
 
-  block->next = XCNEW (gfc_code);
+  block->next = gfc_get_code (EXEC_DO);
   block = block->next;
-  block->op = EXEC_DO;
-  block->loc = gfc_current_locus;
   block->ext.iterator = iter;
-  block->block = gfc_get_code ();
-  block->block->op = EXEC_DO;
+  block->block = gfc_get_code (EXEC_DO);
 
   /* Offset calculation of "array".  */
   block2 = finalization_get_offset (idx, idx2, offset, strides, sizes,
@@ -1445,13 +1508,12 @@ finalizer_insert_packed_call (gfc_code *block, gfc_finalizer *fini,
                                          gfc_lval_expr_from_sym (offset),
                                          sub_ns);
   block2 = block2->next;
-  block2->next = finalization_scalarizer (tmp_array, ptr2, offset2, sub_ns);
+  block2->next = finalization_scalarizer (tmp_array, ptr2,
+                                         gfc_copy_expr (offset2), sub_ns);
   block2 = block2->next;
 
   /* ptr = ptr2.  */
-  block2->next = XCNEW (gfc_code);
-  block2->next->op = EXEC_ASSIGN;
-  block2->next->loc = gfc_current_locus;
+  block2->next = gfc_get_code (EXEC_ASSIGN);
   block2->next->expr1 = gfc_lval_expr_from_sym (ptr);
   block2->next->expr2 = gfc_lval_expr_from_sym (ptr2);
 }
@@ -1479,17 +1541,22 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
 {
   gfc_symbol *final, *array, *fini_coarray, *byte_stride, *sizes, *strides;
   gfc_symbol *ptr = NULL, *idx, *idx2, *is_contiguous, *offset, *nelem;
-  gfc_symtree *size_intr;
   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;
   gfc_iterator *iter;
 
-  /* Search for the ancestor's finalizers. */
+  if (derived->attr.unlimited_polymorphic)
+    {
+      vtab_final->initializer = gfc_get_null_expr (NULL);
+      return;
+    }
+
+  /* Search for the ancestor's finalizers.  */
   if (derived->attr.extension && derived->components
       && (!derived->components->ts.u.derived->attr.abstract
          || has_finalizer_component (derived)))
@@ -1522,17 +1589,7 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
            && ancestor_wrapper && ancestor_wrapper->expr_type != EXPR_NULL)
        continue;
 
-       if (comp->ts.type != BT_CLASS && !comp->attr.pointer
-           && (comp->attr.allocatable
-               || (comp->ts.type == BT_DERIVED
-                   && (comp->ts.u.derived->attr.alloc_comp
-                       || has_finalizer_component (comp->ts.u.derived)
-                       || (comp->ts.u.derived->f2k_derived
-                           && comp->ts.u.derived->f2k_derived->finalizers)))))
-         finalizable_comp = true;
-       else if (comp->ts.type == BT_CLASS && CLASS_DATA (comp)
-                && CLASS_DATA (comp)->attr.allocatable)
-         finalizable_comp = true;
+       finalizable_comp |= comp_is_finalizable (comp);
       }
 
   /* If there is no new finalizer and no new allocatable, return with
@@ -1556,7 +1613,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);
@@ -1566,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;
@@ -1662,18 +1721,11 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
   gfc_commit_symbol (offset);
 
   /* Create RANK expression.  */
-  rank = gfc_get_expr ();
-  rank->expr_type = EXPR_FUNCTION;
-  rank->value.function.isym = gfc_intrinsic_function_by_id (GFC_ISYM_RANK);
-  gfc_get_sym_tree ("rank", sub_ns, &rank->symtree, false);
-  rank->symtree->n.sym->intmod_sym_id = GFC_ISYM_RANK;
-  rank->symtree->n.sym->attr.flavor = FL_PROCEDURE;
-  rank->symtree->n.sym->attr.intrinsic = 1;
-  gfc_commit_symbol (rank->symtree->n.sym);
-  rank->value.function.actual = gfc_get_actual_arglist ();
-  rank->value.function.actual->expr = gfc_lval_expr_from_sym (array);
-  rank->ts = rank->value.function.isym->ts;
-  gfc_convert_type (rank, &idx->ts, 2);
+  rank = gfc_build_intrinsic_call (sub_ns, GFC_ISYM_RANK, "rank",
+                                  gfc_current_locus, 1,
+                                  gfc_lval_expr_from_sym (array));
+  if (rank->ts.kind != idx->ts.kind)
+    gfc_convert_type_warn (rank, &idx->ts, 2, 0);
 
   /* Create is_contiguous variable.  */
   gfc_get_symbol ("is_contiguous", sub_ns, &is_contiguous);
@@ -1721,27 +1773,21 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
 
 
   /* Set return value to 0.  */
-  last_code = XCNEW (gfc_code);
-  last_code->op = EXEC_ASSIGN;
-  last_code->loc = gfc_current_locus;
+  last_code = gfc_get_code (EXEC_ASSIGN);
   last_code->expr1 = gfc_lval_expr_from_sym (final);
   last_code->expr2 = gfc_get_int_expr (4, NULL, 0);
   sub_ns->code = last_code;
 
   /* Set:  is_contiguous = .true.  */
-  last_code->next = XCNEW (gfc_code);
+  last_code->next = gfc_get_code (EXEC_ASSIGN);
   last_code = last_code->next;
-  last_code->op = EXEC_ASSIGN;
-  last_code->loc = gfc_current_locus;
   last_code->expr1 = gfc_lval_expr_from_sym (is_contiguous);
   last_code->expr2 = gfc_get_logical_expr (gfc_default_logical_kind,
                                           &gfc_current_locus, true);
 
   /* Set:  sizes(0) = 1.  */
-  last_code->next = XCNEW (gfc_code);
+  last_code->next = gfc_get_code (EXEC_ASSIGN);
   last_code = last_code->next;
-  last_code->op = EXEC_ASSIGN;
-  last_code->loc = gfc_current_locus;
   last_code->expr1 = gfc_lval_expr_from_sym (sizes);
   last_code->expr1->ref = gfc_get_ref ();
   last_code->expr1->ref->type = REF_ARRAY;
@@ -1757,7 +1803,7 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
      DO idx = 1, rank
        strides(idx) = _F._stride (array, dim=idx)
        sizes(idx) = sizes(i-1) * size(array, dim=idx, kind=index_kind)
-       if (strides(idx) /= sizes(i-1)) is_contiguous = .false.
+       if (strides (idx) /= sizes(i-1)) is_contiguous = .false.
      END DO.  */
 
   /* Create loop.  */
@@ -1766,19 +1812,14 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
   iter->start = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
   iter->end = gfc_copy_expr (rank);
   iter->step = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
-  last_code->next = XCNEW (gfc_code);
+  last_code->next = gfc_get_code (EXEC_DO);
   last_code = last_code->next;
-  last_code->op = EXEC_DO;
-  last_code->loc = gfc_current_locus;
   last_code->ext.iterator = iter;
-  last_code->block = gfc_get_code ();
-  last_code->block->op = EXEC_DO;
+  last_code->block = gfc_get_code (EXEC_DO);
 
-  /* strides(idx) = _F._stride(array,dim=idx). */
-  last_code->block->next = XCNEW (gfc_code);
+  /* strides(idx) = _F._stride(array,dim=idx).  */
+  last_code->block->next = gfc_get_code (EXEC_ASSIGN);
   block = last_code->block->next;
-  block->op = EXEC_ASSIGN;
-  block->loc = gfc_current_locus;
 
   block->expr1 = gfc_lval_expr_from_sym (strides);
   block->expr1->ref = gfc_get_ref ();
@@ -1789,31 +1830,16 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
   block->expr1->ref->u.ar.start[0] = gfc_lval_expr_from_sym (idx);
   block->expr1->ref->u.ar.as = strides->as;
 
-  block->expr2 = gfc_get_expr ();
-  block->expr2->expr_type = EXPR_FUNCTION;
-  block->expr2->value.function.isym
-       = gfc_intrinsic_function_by_id (GFC_ISYM_STRIDE);
-  gfc_get_sym_tree (GFC_PREFIX ("stride"), sub_ns,
-                   &block->expr2->symtree, false);
-  block->expr2->symtree->n.sym->intmod_sym_id = GFC_ISYM_STRIDE;
-  block->expr2->symtree->n.sym->attr.flavor = FL_PROCEDURE;
-  block->expr2->symtree->n.sym->attr.intrinsic = 1;
-  gfc_commit_symbol (block->expr2->symtree->n.sym);
-  block->expr2->value.function.actual = gfc_get_actual_arglist ();
-  block->expr2->value.function.actual->expr = gfc_lval_expr_from_sym (array);
-  /* dim=idx. */
-  block->expr2->value.function.actual->next = gfc_get_actual_arglist ();
-  block->expr2->value.function.actual->next->expr
-       = gfc_lval_expr_from_sym (idx);
-  block->expr2->ts = block->expr2->value.function.isym->ts;
+  block->expr2 = gfc_build_intrinsic_call (sub_ns, GFC_ISYM_STRIDE, "stride",
+                                          gfc_current_locus, 2,
+                                          gfc_lval_expr_from_sym (array),
+                                          gfc_lval_expr_from_sym (idx));
 
-  /* sizes(idx) = sizes(idx-1) * size(array,dim=idx, kind=index_kind). */
-  block->next = XCNEW (gfc_code);
+  /* sizes(idx) = sizes(idx-1) * size(array,dim=idx, kind=index_kind).  */
+  block->next = gfc_get_code (EXEC_ASSIGN);
   block = block->next;
-  block->op = EXEC_ASSIGN;
-  block->loc = gfc_current_locus;
 
-  /* sizes(idx) = ... */
+  /* sizes(idx) = ...  */
   block->expr1 = gfc_lval_expr_from_sym (sizes);
   block->expr1->ref = gfc_get_ref ();
   block->expr1->ref->type = REF_ARRAY;
@@ -1826,8 +1852,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;
@@ -1837,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);
@@ -1846,44 +1874,23 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
        = block->expr2->value.op.op1->ref->u.ar.start[0]->value.op.op1->ts;
 
   /* size(array, dim=idx, kind=index_kind).  */
-  block->expr2->value.op.op2 = gfc_get_expr ();
-  block->expr2->value.op.op2->expr_type = EXPR_FUNCTION;
-  block->expr2->value.op.op2->value.function.isym
-       = gfc_intrinsic_function_by_id (GFC_ISYM_SIZE);
-  gfc_get_sym_tree ("size", sub_ns, &block->expr2->value.op.op2->symtree,
-                   false);
-  size_intr = block->expr2->value.op.op2->symtree;
-  block->expr2->value.op.op2->symtree->n.sym->intmod_sym_id = GFC_ISYM_SIZE;
-  block->expr2->value.op.op2->symtree->n.sym->attr.flavor = FL_PROCEDURE;
-  block->expr2->value.op.op2->symtree->n.sym->attr.intrinsic = 1;
-  gfc_commit_symbol (block->expr2->value.op.op2->symtree->n.sym);
-  block->expr2->value.op.op2->value.function.actual
-       = gfc_get_actual_arglist ();
-  block->expr2->value.op.op2->value.function.actual->expr
-       = gfc_lval_expr_from_sym (array);
-  /* dim=idx. */
-  block->expr2->value.op.op2->value.function.actual->next
-       = gfc_get_actual_arglist ();
-  block->expr2->value.op.op2->value.function.actual->next->expr
-       = gfc_lval_expr_from_sym (idx);
-  /* kind=c_intptr_t. */
-  block->expr2->value.op.op2->value.function.actual->next->next
-       = gfc_get_actual_arglist ();
-  block->expr2->value.op.op2->value.function.actual->next->next->expr
-       = gfc_get_int_expr (gfc_index_integer_kind, NULL, 0);
-  block->expr2->value.op.op2->ts = idx->ts;
+  block->expr2->value.op.op2
+       = gfc_build_intrinsic_call (sub_ns, GFC_ISYM_SIZE, "size",
+                                   gfc_current_locus, 3,
+                                   gfc_lval_expr_from_sym (array),
+                                   gfc_lval_expr_from_sym (idx),
+                                   gfc_get_int_expr (gfc_index_integer_kind,
+                                                     NULL,
+                                                     gfc_index_integer_kind));
+  block->expr2->value.op.op2->ts.kind = gfc_index_integer_kind;
   block->expr2->ts = idx->ts;
 
-  /* if (strides(idx) /= sizes(idx-1)) is_contiguous = .false.  */
-  block->next = XCNEW (gfc_code);
+  /* if (strides (idx) /= sizes(idx-1)) is_contiguous = .false.  */
+  block->next = gfc_get_code (EXEC_IF);
   block = block->next;
-  block->loc = gfc_current_locus;
-  block->op = EXEC_IF;
 
-  block->block = XCNEW (gfc_code);
+  block->block = gfc_get_code (EXEC_IF);
   block = block->block;
-  block->loc = gfc_current_locus;
-  block->op = EXEC_IF;
 
   /* if condition: strides(idx) /= sizes(idx-1).  */
   block->expr1 = gfc_get_expr ();
@@ -1911,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);
@@ -1920,10 +1928,8 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
        = block->expr1->value.op.op2->ref->u.ar.start[0]->value.op.op1->ts;
 
   /* if body: is_contiguous = .false.  */
-  block->next = XCNEW (gfc_code);
+  block->next = gfc_get_code (EXEC_ASSIGN);
   block = block->next;
-  block->op = EXEC_ASSIGN;
-  block->loc = gfc_current_locus;
   block->expr1 = gfc_lval_expr_from_sym (is_contiguous);
   block->expr2 = gfc_get_logical_expr (gfc_default_logical_kind,
                                       &gfc_current_locus, false);
@@ -1939,10 +1945,8 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
   gfc_commit_symbol (nelem);
 
   /* nelem = sizes (rank) - 1.  */
-  last_code->next = XCNEW (gfc_code);
+  last_code->next = gfc_get_code (EXEC_ASSIGN);
   last_code = last_code->next;
-  last_code->op = EXEC_ASSIGN;
-  last_code->loc = gfc_current_locus;
 
   last_code->expr1 = gfc_lval_expr_from_sym (nelem);
 
@@ -1952,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 ();
@@ -1984,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;
@@ -1994,15 +1999,14 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
       gfc_commit_symbol (ptr);
 
       /* SELECT CASE (RANK (array)).  */
-      last_code->next = XCNEW (gfc_code);
+      last_code->next = gfc_get_code (EXEC_SELECT);
       last_code = last_code->next;
-      last_code->op = EXEC_SELECT;
-      last_code->loc = gfc_current_locus;
       last_code->expr1 = gfc_copy_expr (rank);
       block = NULL;
 
       for (fini = derived->f2k_derived->finalizers; fini; fini = fini->next)
        {
+         gcc_assert (fini->proc_tree);   /* Should have been set in gfc_resolve_finalizers.  */
          if (fini->proc_tree->n.sym->attr.elemental)
            {
              fini_elem = fini;
@@ -2012,16 +2016,14 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
          /* CASE (fini_rank).  */
          if (block)
            {
-             block->block = XCNEW (gfc_code);
+             block->block = gfc_get_code (EXEC_SELECT);
              block = block->block;
            }
          else
            {
-             block = XCNEW (gfc_code);
+             block = gfc_get_code (EXEC_SELECT);
              last_code->block = block;
            }
-         block->loc = gfc_current_locus;
-         block->op = EXEC_SELECT;
          block->ext.block.case_list = gfc_get_case ();
          block->ext.block.case_list->where = gfc_current_locus;
          if (fini->proc_tree->n.sym->formal->sym->attr.dimension)
@@ -2032,19 +2034,17 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
            block->ext.block.case_list->low
                = gfc_get_int_expr (gfc_default_integer_kind, NULL, 0);
          block->ext.block.case_list->high
-               = block->ext.block.case_list->low;
+               = gfc_copy_expr (block->ext.block.case_list->low);
 
          /* CALL fini_rank (array) - possibly with packing.  */
           if (fini->proc_tree->n.sym->formal->sym->attr.dimension)
            finalizer_insert_packed_call (block, fini, array, byte_stride,
-                                         idx, ptr, nelem, size_intr, strides,
+                                         idx, ptr, nelem, strides,
                                          sizes, idx2, offset, is_contiguous,
                                          rank, sub_ns);
          else
            {
-             block->next = XCNEW (gfc_code);
-             block->next->op = EXEC_CALL;
-             block->next->loc = gfc_current_locus;
+             block->next = gfc_get_code (EXEC_CALL);
              block->next->symtree = fini->proc_tree;
              block->next->resolved_sym = fini->proc_tree->n.sym;
              block->next->ext.actual = gfc_get_actual_arglist ();
@@ -2058,16 +2058,14 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
          /* CASE DEFAULT.  */
          if (block)
            {
-             block->block = XCNEW (gfc_code);
+             block->block = gfc_get_code (EXEC_SELECT);
              block = block->block;
            }
          else
            {
-             block = XCNEW (gfc_code);
+             block = gfc_get_code (EXEC_SELECT);
              last_code->block = block;
            }
-         block->loc = gfc_current_locus;
-         block->op = EXEC_SELECT;
          block->ext.block.case_list = gfc_get_case ();
 
          /* Create loop.  */
@@ -2076,13 +2074,10 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
          iter->start = gfc_get_int_expr (gfc_index_integer_kind, NULL, 0);
          iter->end = gfc_lval_expr_from_sym (nelem);
          iter->step = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
-         block->next = XCNEW (gfc_code);
+         block->next = gfc_get_code (EXEC_DO);
          block = block->next;
-         block->op = EXEC_DO;
-         block->loc = gfc_current_locus;
          block->ext.iterator = iter;
-         block->block = gfc_get_code ();
-         block->block->op = EXEC_DO;
+         block->block = gfc_get_code (EXEC_DO);
 
          /* Offset calculation.  */
          block = finalization_get_offset (idx, idx2, offset, strides, sizes,
@@ -2099,10 +2094,8 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
          block = block->next;
 
          /* CALL final_elemental (array).  */
-         block->next = XCNEW (gfc_code);
+         block->next = gfc_get_code (EXEC_CALL);
          block = block->next;
-         block->op = EXEC_CALL;
-         block->loc = gfc_current_locus;
          block->symtree = fini_elem->proc_tree;
          block->resolved_sym = fini_elem->proc_sym;
          block->ext.actual = gfc_get_actual_arglist ();
@@ -2120,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;
@@ -2144,13 +2137,10 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
       iter->start = gfc_get_int_expr (gfc_index_integer_kind, NULL, 0);
       iter->end = gfc_lval_expr_from_sym (nelem);
       iter->step = gfc_get_int_expr (gfc_index_integer_kind, NULL, 1);
-      last_code->next = XCNEW (gfc_code);
+      last_code->next = gfc_get_code (EXEC_DO);
       last_code = last_code->next;
-      last_code->op = EXEC_DO;
-      last_code->loc = gfc_current_locus;
       last_code->ext.iterator = iter;
-      last_code->block = gfc_get_code ();
-      last_code->block->op = EXEC_DO;
+      last_code->block = gfc_get_code (EXEC_DO);
 
       /* Offset calculation.  */
       block = finalization_get_offset (idx, idx2, offset, strides, sizes,
@@ -2172,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;
        }
@@ -2182,10 +2172,8 @@ generate_finalization_wrapper (gfc_symbol *derived, gfc_namespace *ns,
   /* Call the finalizer of the ancestor.  */
   if (ancestor_wrapper && ancestor_wrapper->expr_type != EXPR_NULL)
     {
-      last_code->next = XCNEW (gfc_code);
+      last_code->next = gfc_get_code (EXEC_CALL);
       last_code = last_code->next;
-      last_code->op = EXEC_CALL;
-      last_code->loc = gfc_current_locus;
       last_code->symtree = ancestor_wrapper->symtree;
       last_code->resolved_sym = ancestor_wrapper->symtree->n.sym;
 
@@ -2201,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);
 }
 
 
@@ -2237,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)
@@ -2247,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)
@@ -2265,32 +2284,46 @@ 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_VARIABLE, NULL,
-                             &gfc_current_locus) == FAILURE)
+         if (!gfc_add_flavor (&vtab->attr, FL_VARIABLE, NULL,
+                              &gfc_current_locus))
            goto cleanup;
          vtab->attr.target = 1;
          vtab->attr.save = SAVE_IMPLICIT;
          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, &gfc_current_locus) == FAILURE)
+             if (!gfc_add_flavor (&vtype->attr, FL_DERIVED, NULL,
+                                  &gfc_current_locus))
                goto cleanup;
              vtype->attr.access = ACCESS_PUBLIC;
              vtype->attr.vtype = 1;
              gfc_set_sym_referenced (vtype);
 
              /* Add component '_hash'.  */
-             if (gfc_add_component (vtype, "_hash", &c) == FAILURE)
+             if (!gfc_add_component (vtype, "_hash", &c))
                goto cleanup;
              c->ts.type = BT_INTEGER;
              c->ts.kind = 4;
@@ -2299,20 +2332,20 @@ gfc_find_derived_vtab (gfc_symbol *derived)
                                                 NULL, derived->hash_value);
 
              /* Add component '_size'.  */
-             if (gfc_add_component (vtype, "_size", &c) == FAILURE)
+             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.  */
-             if (gfc_add_component (vtype, "_extends", &c) == FAILURE)
+             if (!gfc_add_component (vtype, "_extends", &c))
                goto cleanup;
              c->attr.pointer = 1;
              c->attr.access = ACCESS_PRIVATE;
@@ -2349,7 +2382,7 @@ gfc_find_derived_vtab (gfc_symbol *derived)
                }
 
              /* Add component _def_init.  */
-             if (gfc_add_component (vtype, "_def_init", &c) == FAILURE)
+             if (!gfc_add_component (vtype, "_def_init", &c))
                goto cleanup;
              c->attr.pointer = 1;
              c->attr.artificial = 1;
@@ -2362,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;
@@ -2378,7 +2411,7 @@ gfc_find_derived_vtab (gfc_symbol *derived)
                }
 
              /* Add component _copy.  */
-             if (gfc_add_component (vtype, "_copy", &c) == FAILURE)
+             if (!gfc_add_component (vtype, "_copy", &c))
                goto cleanup;
              c->attr.proc_pointer = 1;
              c->attr.access = ACCESS_PRIVATE;
@@ -2395,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;
@@ -2426,13 +2459,12 @@ gfc_find_derived_vtab (gfc_symbol *derived)
                  dst->attr.flavor = FL_VARIABLE;
                  dst->attr.dummy = 1;
                  dst->attr.artificial = 1;
-                 dst->attr.intent = INTENT_OUT;
+                 dst->attr.intent = INTENT_INOUT;
                  gfc_set_sym_referenced (dst);
                  copy->formal->next = gfc_get_formal_arglist ();
                  copy->formal->next->sym = dst;
                  /* Set up code.  */
-                 sub_ns->code = gfc_get_code ();
-                 sub_ns->code->op = EXEC_INIT_ASSIGN;
+                 sub_ns->code = gfc_get_code (EXEC_INIT_ASSIGN);
                  sub_ns->code->expr1 = gfc_lval_expr_from_sym (dst);
                  sub_ns->code->expr2 = gfc_lval_expr_from_sym (src);
                  /* Set initializer.  */
@@ -2445,17 +2477,74 @@ gfc_find_derived_vtab (gfc_symbol *derived)
                 components and the calls to finalization subroutines.
                 Note: The actual wrapper function can only be generated
                 at resolution time.  */
-           /* FIXME: Enable ABI-breaking "_final" generation.  */
-           if (0)
-           {
-             if (gfc_add_component (vtype, "_final", &c) == FAILURE)
+             if (!gfc_add_component (vtype, "_final", &c))
                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)
@@ -2466,6 +2555,7 @@ have_vtype:
          vtab->ts.u.derived = vtype;
          vtab->value = gfc_default_initializer (&vtab->ts);
        }
+      free (name);
     }
 
   found_sym = vtab;
@@ -2486,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 ();
@@ -2537,69 +2631,47 @@ yes:
 
 
 /* Find (or generate) the symbol for an intrinsic type's vtab.  This is
-   need to support unlimited polymorphism.  */
+   needed to support unlimited polymorphism.  */
 
-gfc_symbol *
-gfc_find_intrinsic_vtab (gfc_typespec *ts)
+static gfc_symbol *
+find_intrinsic_vtab (gfc_typespec *ts)
 {
   gfc_namespace *ns;
-  gfc_symbol *vtab = NULL, *vtype = NULL, *found_sym = NULL, *def_init = NULL;
+  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)
-    {
-      gfc_error ("TODO: Deferred character length variable at %C cannot "
-                "yet be associated with unlimited polymorphic entities");
-      return NULL;
-    }
-
-  if (ts->type == BT_UNKNOWN)
-    return NULL;
-
-  /* Sometimes the typespec is passed from a single call.  */
-  if (ts->type == BT_DERIVED)
-    return gfc_find_derived_vtab (ts->u.derived);
 
   /* Find the top-level namespace.  */
   for (ns = gfc_current_ns; ns; ns = ns->parent)
     if (!ns->parent)
       break;
 
-  if (ts->type == BT_CHARACTER && 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);
-
   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)
        {
          gfc_get_symbol (name, ns, &vtab);
          vtab->ts.type = BT_DERIVED;
-         if (gfc_add_flavor (&vtab->attr, FL_VARIABLE, NULL,
-                             &gfc_current_locus) == FAILURE)
+         if (!gfc_add_flavor (&vtab->attr, FL_VARIABLE, NULL,
+                              &gfc_current_locus))
            goto cleanup;
          vtab->attr.target = 1;
          vtab->attr.save = SAVE_IMPLICIT;
          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)
@@ -2608,17 +2680,19 @@ gfc_find_intrinsic_vtab (gfc_typespec *ts)
              int hash;
              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, &gfc_current_locus) == FAILURE)
+             if (!gfc_add_flavor (&vtype->attr, FL_DERIVED, NULL,
+                                  &gfc_current_locus))
                goto cleanup;
              vtype->attr.access = ACCESS_PUBLIC;
              vtype->attr.vtype = 1;
              gfc_set_sym_referenced (vtype);
 
              /* Add component '_hash'.  */
-             if (gfc_add_component (vtype, "_hash", &c) == FAILURE)
+             if (!gfc_add_component (vtype, "_hash", &c))
                goto cleanup;
              c->ts.type = BT_INTEGER;
              c->ts.kind = 4;
@@ -2628,20 +2702,31 @@ gfc_find_intrinsic_vtab (gfc_typespec *ts)
                                                 NULL, hash);
 
              /* Add component '_size'.  */
-             if (gfc_add_component (vtype, "_size", &c) == FAILURE)
+             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'.  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;
              if (ts->type == BT_CHARACTER)
-               c->initializer = gfc_get_int_expr (gfc_default_integer_kind,
-                                                  NULL, charlen*ts->kind);
+               e_size = ts->kind;
              else
-               c->initializer = gfc_get_int_expr (gfc_default_integer_kind,
-                                                  NULL, ts->kind);
+               gfc_element_size (e, &e_size);
+             c->initializer = gfc_get_int_expr (gfc_size_kind,
+                                                NULL,
+                                                e_size);
+             gfc_free_expr (e);
 
              /* Add component _extends.  */
-             if (gfc_add_component (vtype, "_extends", &c) == FAILURE)
+             if (!gfc_add_component (vtype, "_extends", &c))
                goto cleanup;
              c->attr.pointer = 1;
              c->attr.access = ACCESS_PRIVATE;
@@ -2649,7 +2734,7 @@ gfc_find_intrinsic_vtab (gfc_typespec *ts)
              c->initializer = gfc_get_null_expr (NULL);
 
              /* Add component _def_init.  */
-             if (gfc_add_component (vtype, "_def_init", &c) == FAILURE)
+             if (!gfc_add_component (vtype, "_def_init", &c))
                goto cleanup;
              c->attr.pointer = 1;
              c->attr.access = ACCESS_PRIVATE;
@@ -2657,24 +2742,29 @@ gfc_find_intrinsic_vtab (gfc_typespec *ts)
              c->initializer = gfc_get_null_expr (NULL);
 
              /* Add component _copy.  */
-             if (gfc_add_component (vtype, "_copy", &c) == FAILURE)
+             if (!gfc_add_component (vtype, "_copy", &c))
                goto cleanup;
              c->attr.proc_pointer = 1;
              c->attr.access = ACCESS_PRIVATE;
              c->tb = XCNEW (gfc_typebound_proc);
              c->tb->ppc = 1;
 
-             /* Check to see if copy function already exists.  Note
-                that this is only used for characters of different
-                lengths.  */
-             contained = ns->contained;
-             for (; contained; contained = contained->sibling)
-               if (contained->proc_name
-                   && strcmp (name, contained->proc_name->name) == 0)
-                 {
-                   copy = contained->proc_name;
-                   goto got_char_copy;
-                 }
+             if (ts->type != BT_CHARACTER)
+               name = xasprintf ("__copy_%s", tname);
+             else
+               {
+                 /* __copy is always the same for characters.
+                    Check to see if copy function already exists.  */
+                 name = xasprintf ("__copy_character_%d", ts->kind);
+                 contained = ns->contained;
+                 for (; contained; contained = contained->sibling)
+                   if (contained->proc_name
+                       && strcmp (name, contained->proc_name->name) == 0)
+                     {
+                       copy = contained->proc_name;
+                       goto got_char_copy;
+                     }
+               }
 
              /* Set up namespace.  */
              sub_ns = gfc_get_namespace (ns, 0);
@@ -2682,11 +2772,6 @@ gfc_find_intrinsic_vtab (gfc_typespec *ts)
              ns->contained = sub_ns;
              sub_ns->resolved = 1;
              /* Set up procedure symbol.  */
-             if (ts->type != BT_CHARACTER)
-               sprintf (name, "__copy_%s", tname);
-             else
-               /* __copy is always the same for characters.  */
-               sprintf (name, "__copy_character_%d", ts->kind);
              gfc_get_symbol (name, sub_ns, &copy);
              sub_ns->proc_name = copy;
              copy->attr.flavor = FL_PROCEDURE;
@@ -2696,9 +2781,9 @@ gfc_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;
@@ -2714,13 +2799,12 @@ gfc_find_intrinsic_vtab (gfc_typespec *ts)
              dst->ts.kind = ts->kind;
              dst->attr.flavor = FL_VARIABLE;
              dst->attr.dummy = 1;
-             dst->attr.intent = INTENT_OUT;
+             dst->attr.intent = INTENT_INOUT;
              gfc_set_sym_referenced (dst);
              copy->formal->next = gfc_get_formal_arglist ();
              copy->formal->next->sym = dst;
              /* Set up code.  */
-             sub_ns->code = gfc_get_code ();
-             sub_ns->code->op = EXEC_INIT_ASSIGN;
+             sub_ns->code = gfc_get_code (EXEC_INIT_ASSIGN);
              sub_ns->code->expr1 = gfc_lval_expr_from_sym (dst);
              sub_ns->code->expr2 = gfc_lval_expr_from_sym (src);
            got_char_copy:
@@ -2729,10 +2813,11 @@ gfc_find_intrinsic_vtab (gfc_typespec *ts)
              c->ts.interface = copy;
 
              /* Add component _final.  */
-             if (gfc_add_component (vtype, "_final", &c) == FAILURE)
+             if (!gfc_add_component (vtype, "_final", &c))
                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);
@@ -2740,6 +2825,7 @@ gfc_find_intrinsic_vtab (gfc_typespec *ts)
          vtab->ts.u.derived = vtype;
          vtab->value = gfc_default_initializer (&vtab->ts);
        }
+      free (name);
     }
 
   found_sym = vtab;
@@ -2752,8 +2838,6 @@ cleanup:
       gfc_commit_symbol (vtab);
       if (vtype)
        gfc_commit_symbol (vtype);
-      if (def_init)
-       gfc_commit_symbol (def_init);
       if (copy)
        gfc_commit_symbol (copy);
       if (src)
@@ -2768,25 +2852,49 @@ cleanup:
 }
 
 
+/*  Find (or generate) a vtab for an arbitrary type (derived or intrinsic).  */
+
+gfc_symbol *
+gfc_find_vtab (gfc_typespec *ts)
+{
+  switch (ts->type)
+    {
+    case BT_UNKNOWN:
+      return NULL;
+    case BT_DERIVED:
+      return gfc_find_derived_vtab (ts->u.derived);
+    case BT_CLASS:
+      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);
+    }
+}
+
+
 /* General worker function to find either a type-bound procedure or a
    type-bound user operator.  */
 
 static gfc_symtree*
-find_typebound_proc_uop (gfc_symbol* derived, gfc_try* t,
+find_typebound_proc_uop (gfc_symbol* derived, bool* t,
                         const char* name, bool noaccess, bool uop,
                         locus* where)
 {
   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;
+    *t = false;
+
+  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);
@@ -2794,16 +2902,16 @@ find_typebound_proc_uop (gfc_symbol* derived, gfc_try* t,
     {
       /* We found one.  */
       if (t)
-       *t = SUCCESS;
+       *t = true;
 
       if (!noaccess && derived->attr.use_assoc
          && 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 = FAILURE;
+           *t = false;
        }
 
       return res;
@@ -2829,14 +2937,14 @@ find_typebound_proc_uop (gfc_symbol* derived, gfc_try* t,
    (looking recursively through the super-types).  */
 
 gfc_symtree*
-gfc_find_typebound_proc (gfc_symbol* derived, gfc_try* t,
+gfc_find_typebound_proc (gfc_symbol* derived, bool* t,
                         const char* name, bool noaccess, locus* where)
 {
   return find_typebound_proc_uop (derived, t, name, noaccess, false, where);
 }
 
 gfc_symtree*
-gfc_find_typebound_user_op (gfc_symbol* derived, gfc_try* t,
+gfc_find_typebound_user_op (gfc_symbol* derived, bool* t,
                            const char* name, bool noaccess, locus* where)
 {
   return find_typebound_proc_uop (derived, t, name, noaccess, true, where);
@@ -2847,7 +2955,7 @@ gfc_find_typebound_user_op (gfc_symbol* derived, gfc_try* t,
    super-type hierarchy.  */
 
 gfc_typebound_proc*
-gfc_find_typebound_intrinsic_op (gfc_symbol* derived, gfc_try* t,
+gfc_find_typebound_intrinsic_op (gfc_symbol* derived, bool* t,
                                 gfc_intrinsic_op op, bool noaccess,
                                 locus* where)
 {
@@ -2855,7 +2963,7 @@ gfc_find_typebound_intrinsic_op (gfc_symbol* derived, gfc_try* t,
 
   /* Set default to failure.  */
   if (t)
-    *t = FAILURE;
+    *t = false;
 
   /* Try to find it in the current type's namespace.  */
   if (derived->f2k_derived)
@@ -2868,16 +2976,16 @@ gfc_find_typebound_intrinsic_op (gfc_symbol* derived, gfc_try* t,
     {
       /* We found one.  */
       if (t)
-       *t = SUCCESS;
+       *t = true;
 
       if (!noaccess && derived->attr.use_assoc
          && 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 = FAILURE;
+           *t = false;
        }
 
       return res;
@@ -2906,15 +3014,6 @@ gfc_find_typebound_intrinsic_op (gfc_symbol* derived, gfc_try* 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);
 }