OSDN Git Service

* trans-expr.c: Do not include convert.h, ggc.h, real.h, and gimple.h.
[pf3gnuchains/gcc-fork.git] / gcc / fortran / trans-expr.c
index 6646b26..b76a324 100644 (file)
@@ -1,5 +1,5 @@
 /* Expression translation
-   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
    Contributed by Paul Brook <paul@nowt.org>
    and Steven Bosscher <s.bosscher@student.tudelft.nl>
@@ -26,15 +26,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "tree.h"
-#include "convert.h"
-#include "ggc.h"
 #include "toplev.h"
-#include "real.h"
-#include "gimple.h"
 #include "langhooks.h"
 #include "flags.h"
 #include "gfortran.h"
 #include "arith.h"
+#include "constructor.h"
 #include "trans.h"
 #include "trans-const.h"
 #include "trans-types.h"
@@ -278,11 +275,14 @@ flatten_array_ctors_without_strlen (gfc_expr* e)
       /* We've found what we're looking for.  */
       if (e->ts.type == BT_CHARACTER && !e->ts.u.cl->length)
        {
+         gfc_constructor *c;
          gfc_expr* new_expr;
+
          gcc_assert (e->value.constructor);
 
-         new_expr = e->value.constructor->expr;
-         e->value.constructor->expr = NULL;
+         c = gfc_constructor_first (e->value.constructor);
+         new_expr = c->expr;
+         c->expr = NULL;
 
          flatten_array_ctors_without_strlen (new_expr);
          gfc_replace_expr (e, new_expr);
@@ -291,7 +291,8 @@ flatten_array_ctors_without_strlen (gfc_expr* e)
 
       /* Otherwise, fall through to handle constructor elements.  */
     case EXPR_STRUCTURE:
-      for (c = e->value.constructor; c; c = c->next)
+      for (c = gfc_constructor_first (e->value.constructor);
+          c; c = gfc_constructor_next (c))
        flatten_array_ctors_without_strlen (c->expr);
       break;
 
@@ -356,7 +357,6 @@ gfc_conv_substring (gfc_se * se, gfc_ref * ref, int kind,
 {
   tree tmp;
   tree type;
-  tree var;
   tree fault;
   gfc_se start;
   gfc_se end;
@@ -365,7 +365,6 @@ gfc_conv_substring (gfc_se * se, gfc_ref * ref, int kind,
   type = gfc_get_character_type (kind, ref->u.ss.length);
   type = build_pointer_type (type);
 
-  var = NULL_TREE;
   gfc_init_se (&start, se);
   gfc_conv_expr_type (&start, ref->u.ss.start, gfc_charlen_type_node);
   gfc_add_block_to_block (&se->pre, &start.pre);
@@ -509,6 +508,9 @@ conv_parent_component_references (gfc_se * se, gfc_ref * ref)
   parent.u.c.sym = dt;
   parent.u.c.component = dt->components;
 
+  if (dt->backend_decl == NULL)
+    gfc_get_derived_type (dt);
+
   if (dt->attr.extension && dt->components)
     {
       if (dt->attr.is_class)
@@ -1109,8 +1111,6 @@ gfc_conv_string_tmp (gfc_se * se, tree type, tree len)
   tree var;
   tree tmp;
 
-  gcc_assert (types_compatible_p (TREE_TYPE (len), gfc_charlen_type_node));
-
   if (gfc_can_put_var_on_stack (len))
     {
       /* Create a temporary variable to hold the result.  */
@@ -1224,8 +1224,9 @@ gfc_conv_expr_op (gfc_se * se, gfc_expr * expr)
   switch (expr->value.op.op)
     {
     case INTRINSIC_PARENTHESES:
-      if (expr->ts.type == BT_REAL
-         || expr->ts.type == BT_COMPLEX)
+      if ((expr->ts.type == BT_REAL
+          || expr->ts.type == BT_COMPLEX)
+         && gfc_option.flag_protect_parens)
        {
          gfc_conv_unary_op (PAREN_EXPR, se, expr);
          gcc_assert (FLOAT_TYPE_P (TREE_TYPE (se->expr)));
@@ -1430,7 +1431,8 @@ gfc_conv_scalar_char_value (gfc_symbol *sym, gfc_se *se, gfc_expr **expr)
          gfc_typespec ts;
           gfc_clear_ts (&ts);
 
-         *expr = gfc_int_expr ((int)(*expr)->value.character.string[0]);
+         *expr = gfc_get_int_expr (gfc_default_integer_kind, NULL,
+                                   (int)(*expr)->value.character.string[0]);
          if ((*expr)->ts.kind != gfc_c_int_kind)
            {
              /* The expr needs to be compatible with a C int.  If the 
@@ -1524,137 +1526,11 @@ get_proc_ptr_comp (gfc_expr *e)
 }
 
 
-/* Select a class typebound procedure at runtime.  */
-static void
-select_class_proc (gfc_se *se, gfc_class_esym_list *elist,
-                  tree declared, gfc_expr *expr)
-{
-  tree end_label;
-  tree label;
-  tree tmp;
-  tree vindex;
-  stmtblock_t body;
-  gfc_class_esym_list *next_elist, *tmp_elist;
-  gfc_se tmpse;
-
-  /* Convert the vindex expression.  */
-  gfc_init_se (&tmpse, NULL);
-  gfc_conv_expr (&tmpse, elist->vindex);
-  gfc_add_block_to_block (&se->pre, &tmpse.pre);
-  vindex = gfc_evaluate_now (tmpse.expr, &se->pre);
-  gfc_add_block_to_block (&se->post, &tmpse.post);
-
-  /* Fix the function type to be that of the declared type method.  */
-  declared = gfc_create_var (TREE_TYPE (declared), "method");
-
-  end_label = gfc_build_label_decl (NULL_TREE);
-
-  gfc_init_block (&body);
-
-  /* Go through the list of extensions.  */
-  for (; elist; elist = next_elist)
-    {
-      /* This case has already been added.  */
-      if (elist->derived == NULL)
-       goto free_elist;
-
-      /* Run through the chain picking up all the cases that call the
-        same procedure.  */
-      tmp_elist = elist;
-      for (; elist; elist = elist->next)
-       {
-         tree cval;
-
-         if (elist->esym != tmp_elist->esym)
-           continue;
-
-         cval = build_int_cst (TREE_TYPE (vindex),
-                               elist->derived->vindex);
-         /* Build a label for the vindex value.  */
-         label = gfc_build_label_decl (NULL_TREE);
-         tmp = fold_build3 (CASE_LABEL_EXPR, void_type_node,
-                            cval, NULL_TREE, label);
-         gfc_add_expr_to_block (&body, tmp);
-
-         /* Null the reference the derived type so that this case is
-            not used again.  */
-         elist->derived = NULL;
-       }
-
-      elist = tmp_elist;
-
-      /* Get a pointer to the procedure,  */
-      tmp = gfc_get_symbol_decl (elist->esym);
-      if (!POINTER_TYPE_P (TREE_TYPE (tmp)))
-       {
-         gcc_assert (TREE_CODE (tmp) == FUNCTION_DECL);
-         tmp = gfc_build_addr_expr (NULL_TREE, tmp);
-       }
-
-      /* Assign the pointer to the appropriate procedure.  */
-      gfc_add_modify (&body, declared,
-                     fold_convert (TREE_TYPE (declared), tmp));
-
-      /* Break to the end of the construct.  */
-      tmp = build1_v (GOTO_EXPR, end_label);
-      gfc_add_expr_to_block (&body, tmp);
-
-      /* Free the elists as we go; freeing them in gfc_free_expr causes
-        segfaults because it occurs too early and too often.  */
-    free_elist:
-      next_elist = elist->next;
-      if (elist->vindex)
-       gfc_free_expr (elist->vindex);
-      gfc_free (elist);
-      elist = NULL;
-    }
-
-  /* Default is an error.  */
-  label = gfc_build_label_decl (NULL_TREE);
-  tmp = fold_build3 (CASE_LABEL_EXPR, void_type_node,
-                    NULL_TREE, NULL_TREE, label);
-  gfc_add_expr_to_block (&body, tmp);
-  tmp = gfc_trans_runtime_error (true, &expr->where,
-               "internal error: bad vindex in dynamic dispatch");
-  gfc_add_expr_to_block (&body, tmp);
-
-  /* Write the switch expression.  */
-  tmp = gfc_finish_block (&body);
-  tmp = build3_v (SWITCH_EXPR, vindex, tmp, NULL_TREE);
-  gfc_add_expr_to_block (&se->pre, tmp);
-
-  tmp = build1_v (LABEL_EXPR, end_label);
-  gfc_add_expr_to_block (&se->pre, tmp);
-
-  se->expr = declared;
-  return;
-}
-
-
 static void
 conv_function_val (gfc_se * se, gfc_symbol * sym, gfc_expr * expr)
 {
   tree tmp;
 
-  if (expr && expr->symtree
-       && expr->value.function.class_esym)
-    {
-      if (!sym->backend_decl)
-       sym->backend_decl = gfc_get_extern_function_decl (sym);
-
-      tmp = sym->backend_decl;
-
-      if (!POINTER_TYPE_P (TREE_TYPE (tmp)))
-       {
-         gcc_assert (TREE_CODE (tmp) == FUNCTION_DECL);
-         tmp = gfc_build_addr_expr (NULL_TREE, tmp);
-       }
-
-      select_class_proc (se, expr->value.function.class_esym,
-                        tmp, expr);
-      return;
-    }
-
   if (gfc_is_proc_ptr_comp (expr, NULL))
     tmp = get_proc_ptr_comp (expr);
   else if (sym->attr.dummy)
@@ -1842,6 +1718,7 @@ gfc_add_interface_mapping (gfc_interface_mapping * mapping,
   new_sym->as = gfc_copy_array_spec (sym->as);
   new_sym->attr.referenced = 1;
   new_sym->attr.dimension = sym->attr.dimension;
+  new_sym->attr.codimension = sym->attr.codimension;
   new_sym->attr.pointer = sym->attr.pointer;
   new_sym->attr.allocatable = sym->attr.allocatable;
   new_sym->attr.flavor = sym->attr.flavor;
@@ -1984,9 +1861,10 @@ gfc_finish_interface_mapping (gfc_interface_mapping * mapping,
 
 static void
 gfc_apply_interface_mapping_to_cons (gfc_interface_mapping * mapping,
-                                    gfc_constructor * c)
+                                    gfc_constructor_base base)
 {
-  for (; c; c = c->next)
+  gfc_constructor *c;
+  for (c = gfc_constructor_first (base); c; c = gfc_constructor_next (c))
     {
       gfc_apply_interface_mapping_to_expr (mapping, c->expr);
       if (c->iterator)
@@ -2070,7 +1948,7 @@ gfc_map_intrinsic_function (gfc_expr *expr, gfc_interface_mapping *mapping)
       break;
 
     case GFC_ISYM_SIZE:
-      if (!sym->as)
+      if (!sym->as || sym->as->rank == 0)
        return false;
 
       if (arg2 && arg2->expr_type == EXPR_CONSTANT)
@@ -2094,7 +1972,9 @@ gfc_map_intrinsic_function (gfc_expr *expr, gfc_interface_mapping *mapping)
              return false;
            }
 
-         tmp = gfc_add (gfc_copy_expr (sym->as->upper[d]), gfc_int_expr (1));
+         tmp = gfc_add (gfc_copy_expr (sym->as->upper[d]),
+                                       gfc_get_int_expr (gfc_default_integer_kind,
+                                                         NULL, 1));
          tmp = gfc_subtract (tmp, gfc_copy_expr (sym->as->lower[d]));
          if (new_expr)
            new_expr = gfc_multiply (new_expr, tmp);
@@ -2108,7 +1988,7 @@ gfc_map_intrinsic_function (gfc_expr *expr, gfc_interface_mapping *mapping)
        /* TODO These implementations of lbound and ubound do not limit if
           the size < 0, according to F95's 13.14.53 and 13.14.113.  */
 
-      if (!sym->as)
+      if (!sym->as || sym->as->rank == 0)
        return false;
 
       if (arg2 && arg2->expr_type == EXPR_CONSTANT)
@@ -2292,8 +2172,8 @@ gfc_apply_interface_mapping (gfc_interface_mapping * mapping,
    an actual argument derived type array is copied and then returned
    after the function call.  */
 void
-gfc_conv_subref_array_arg (gfc_se * parmse, gfc_expr * expr,
-                          int g77, sym_intent intent)
+gfc_conv_subref_array_arg (gfc_se * parmse, gfc_expr * expr, int g77,
+                          sym_intent intent, bool formal_ptr)
 {
   gfc_se lse;
   gfc_se rse;
@@ -2306,8 +2186,10 @@ gfc_conv_subref_array_arg (gfc_se * parmse, gfc_expr * expr,
   tree tmp_index;
   tree tmp;
   tree base_type;
+  tree size;
   stmtblock_t body;
   int n;
+  int dimen;
 
   gcc_assert (expr->expr_type == EXPR_VARIABLE);
 
@@ -2378,7 +2260,7 @@ gfc_conv_subref_array_arg (gfc_se * parmse, gfc_expr * expr,
 
   if (intent != INTENT_OUT)
     {
-      tmp = gfc_trans_scalar_assign (&lse, &rse, expr->ts, true, false);
+      tmp = gfc_trans_scalar_assign (&lse, &rse, expr->ts, true, false, true);
       gfc_add_expr_to_block (&body, tmp);
       gcc_assert (rse.ss == gfc_ss_terminator);
       gfc_trans_scalarizing_loops (&loop, &body);
@@ -2436,9 +2318,10 @@ gfc_conv_subref_array_arg (gfc_se * parmse, gfc_expr * expr,
      outside the innermost loop, so the overall transfer could be
      optimized further.  */
   info = &rse.ss->data.info;
+  dimen = info->dimen;
 
   tmp_index = gfc_index_zero_node;
-  for (n = info->dimen - 1; n > 0; n--)
+  for (n = dimen - 1; n > 0; n--)
     {
       tree tmp_str;
       tmp = rse.loop->loopvar[n];
@@ -2475,7 +2358,7 @@ gfc_conv_subref_array_arg (gfc_se * parmse, gfc_expr * expr,
 
   gcc_assert (lse.ss == gfc_ss_terminator);
 
-  tmp = gfc_trans_scalar_assign (&lse, &rse, expr->ts, false, false);
+  tmp = gfc_trans_scalar_assign (&lse, &rse, expr->ts, false, false, true);
   gfc_add_expr_to_block (&body, tmp);
   
   /* Generate the copying loops.  */
@@ -2499,6 +2382,42 @@ gfc_conv_subref_array_arg (gfc_se * parmse, gfc_expr * expr,
   if (expr->ts.type == BT_CHARACTER)
     parmse->string_length = expr->ts.u.cl->backend_decl;
 
+  /* Determine the offset for pointer formal arguments and set the
+     lbounds to one.  */
+  if (formal_ptr)
+    {
+      size = gfc_index_one_node;
+      offset = gfc_index_zero_node;  
+      for (n = 0; n < dimen; n++)
+       {
+         tmp = gfc_conv_descriptor_ubound_get (parmse->expr,
+                                               gfc_rank_cst[n]);
+         tmp = fold_build2 (PLUS_EXPR, gfc_array_index_type,
+                            tmp, gfc_index_one_node);
+         gfc_conv_descriptor_ubound_set (&parmse->pre,
+                                         parmse->expr,
+                                         gfc_rank_cst[n],
+                                         tmp);
+         gfc_conv_descriptor_lbound_set (&parmse->pre,
+                                         parmse->expr,
+                                         gfc_rank_cst[n],
+                                         gfc_index_one_node);
+         size = gfc_evaluate_now (size, &parmse->pre);
+         offset = fold_build2 (MINUS_EXPR, gfc_array_index_type,
+                               offset, size);
+         offset = gfc_evaluate_now (offset, &parmse->pre);
+         tmp = fold_build2 (MINUS_EXPR, gfc_array_index_type,
+                            rse.loop->to[n], rse.loop->from[n]);
+         tmp = fold_build2 (PLUS_EXPR, gfc_array_index_type,
+                            tmp, gfc_index_one_node);
+         size = fold_build2 (MULT_EXPR, gfc_array_index_type,
+                             size, tmp);
+       }
+
+      gfc_conv_descriptor_offset_set (&parmse->pre, parmse->expr,
+                                     offset);
+    }
+
   /* We want either the address for the data or the address of the descriptor,
      depending on the mode of passing array arguments.  */
   if (g77)
@@ -2533,6 +2452,61 @@ conv_arglist_function (gfc_se *se, gfc_expr *expr, const char *name)
 }
 
 
+/* Takes a derived type expression and returns the address of a temporary
+   class object of the 'declared' type.  */ 
+static void
+gfc_conv_derived_to_class (gfc_se *parmse, gfc_expr *e,
+                          gfc_typespec class_ts)
+{
+  gfc_component *cmp;
+  gfc_symbol *vtab;
+  gfc_symbol *declared = class_ts.u.derived;
+  gfc_ss *ss;
+  tree ctree;
+  tree var;
+  tree tmp;
+
+  /* The derived type needs to be converted to a temporary
+     CLASS object.  */
+  tmp = gfc_typenode_for_spec (&class_ts);
+  var = gfc_create_var (tmp, "class");
+
+  /* Set the vptr.  */
+  cmp = gfc_find_component (declared, "$vptr", true, true);
+  ctree = fold_build3 (COMPONENT_REF, TREE_TYPE (cmp->backend_decl),
+                      var, cmp->backend_decl, NULL_TREE);
+
+  /* Remember the vtab corresponds to the derived type
+    not to the class declared type.  */
+  vtab = gfc_find_derived_vtab (e->ts.u.derived, true);
+  gcc_assert (vtab);
+  gfc_trans_assign_vtab_procs (&parmse->pre, e->ts.u.derived, vtab);
+  tmp = gfc_build_addr_expr (NULL_TREE, gfc_get_symbol_decl (vtab));
+  gfc_add_modify (&parmse->pre, ctree,
+                 fold_convert (TREE_TYPE (ctree), tmp));
+
+  /* Now set the data field.  */
+  cmp = gfc_find_component (declared, "$data", true, true);
+  ctree = fold_build3 (COMPONENT_REF, TREE_TYPE (cmp->backend_decl),
+                      var, cmp->backend_decl, NULL_TREE);
+  ss = gfc_walk_expr (e);
+  if (ss == gfc_ss_terminator)
+    {
+      gfc_conv_expr_reference (parmse, e);
+      tmp = fold_convert (TREE_TYPE (ctree), parmse->expr);
+      gfc_add_modify (&parmse->pre, ctree, tmp);
+    }
+  else
+    {
+      gfc_conv_expr (parmse, e);
+      gfc_add_modify (&parmse->pre, ctree, parmse->expr);
+    }
+
+  /* Pass the address of the class object.  */
+  parmse->expr = gfc_build_addr_expr (NULL_TREE, var);
+}
+
+
 /* The following routine generates code for the intrinsic
    procedures from the ISO_C_BINDING module:
     * C_LOC           (function)
@@ -2701,6 +2675,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
   tree var;
   tree len;
   tree stringargs;
+  tree result = NULL;
   gfc_formal_arglist *formal;
   int has_alternate_specifier = 0;
   bool need_interface_mapping;
@@ -2731,18 +2706,18 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
       if (!sym->attr.elemental)
        {
          gcc_assert (se->ss->type == GFC_SS_FUNCTION);
-          if (se->ss->useflags)
-            {
+         if (se->ss->useflags)
+           {
              gcc_assert ((!comp && gfc_return_by_reference (sym)
                           && sym->result->attr.dimension)
                          || (comp && comp->attr.dimension));
-              gcc_assert (se->loop != NULL);
+             gcc_assert (se->loop != NULL);
 
-              /* Access the previously obtained result.  */
-              gfc_conv_tmp_array_ref (se);
-              gfc_advance_se_ss_chain (se);
-              return 0;
-            }
+             /* Access the previously obtained result.  */
+             gfc_conv_tmp_array_ref (se);
+             gfc_advance_se_ss_chain (se);
+             return 0;
+           }
        }
       info = &se->ss->data.info;
     }
@@ -2776,9 +2751,9 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
       e = arg->expr;
       fsym = formal ? formal->sym : NULL;
       parm_kind = MISSING;
+
       if (e == NULL)
        {
-
          if (se->ignore_optional)
            {
              /* Some intrinsics have already been resolved to the correct
@@ -2787,74 +2762,31 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
            }
          else if (arg->label)
            {
-              has_alternate_specifier = 1;
-              continue;
+             has_alternate_specifier = 1;
+             continue;
            }
          else
            {
              /* Pass a NULL pointer for an absent arg.  */
              gfc_init_se (&parmse, NULL);
              parmse.expr = null_pointer_node;
-              if (arg->missing_arg_type == BT_CHARACTER)
+             if (arg->missing_arg_type == BT_CHARACTER)
                parmse.string_length = build_int_cst (gfc_charlen_type_node, 0);
            }
        }
       else if (fsym && fsym->ts.type == BT_CLASS
                 && e->ts.type == BT_DERIVED)
        {
-         tree data;
-         tree vindex;
-         tree size;
-
          /* The derived type needs to be converted to a temporary
             CLASS object.  */
          gfc_init_se (&parmse, se);
-         type = gfc_typenode_for_spec (&fsym->ts);
-         var = gfc_create_var (type, "class");
-
-         /* Get the components.  */
-         tmp = fsym->ts.u.derived->components->backend_decl;
-         data = fold_build3 (COMPONENT_REF, TREE_TYPE (tmp),
-                             var, tmp, NULL_TREE);
-         tmp = fsym->ts.u.derived->components->next->backend_decl;
-         vindex = fold_build3 (COMPONENT_REF, TREE_TYPE (tmp),
-                               var, tmp, NULL_TREE);
-         tmp = fsym->ts.u.derived->components->next->next->backend_decl;
-         size = fold_build3 (COMPONENT_REF, TREE_TYPE (tmp),
-                             var, tmp, NULL_TREE);
-
-         /* Set the vindex.  */
-         tmp = build_int_cst (TREE_TYPE (vindex), e->ts.u.derived->vindex);
-         gfc_add_modify (&parmse.pre, vindex, tmp);
-
-         /* Set the size.  */
-         tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&e->ts));
-         gfc_add_modify (&parmse.pre, size,
-                         fold_convert (TREE_TYPE (size), tmp));
-
-         /* Now set the data field.  */
-         argss = gfc_walk_expr (e);
-         if (argss == gfc_ss_terminator)
-            {
-             gfc_conv_expr_reference (&parmse, e);
-             tmp = fold_convert (TREE_TYPE (data),
-                                 parmse.expr);
-             gfc_add_modify (&parmse.pre, data, tmp);
-           }
-         else
-           {
-             gfc_conv_expr (&parmse, e);
-             gfc_add_modify (&parmse.pre, data, parmse.expr);
-           }
-
-         /* Pass the address of the class object.  */
-         parmse.expr = gfc_build_addr_expr (NULL_TREE, var);
+         gfc_conv_derived_to_class (&parmse, e, fsym->ts);
        }
       else if (se->ss && se->ss->useflags)
        {
          /* An elemental function inside a scalarized loop.  */
-          gfc_init_se (&parmse, se);
-          gfc_conv_expr_reference (&parmse, e);
+         gfc_init_se (&parmse, se);
+         gfc_conv_expr_reference (&parmse, e);
          parm_kind = ELEMENTAL;
        }
       else
@@ -2864,7 +2796,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
          argss = gfc_walk_expr (e);
 
          if (argss == gfc_ss_terminator)
-            {
+           {
              if (e->expr_type == EXPR_VARIABLE
                    && e->symtree->n.sym->attr.cray_pointee
                    && fsym && fsym->attr.flavor == FL_PROCEDURE)
@@ -2975,7 +2907,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
                  ALLOCATABLE or assumed shape, we do not use g77's calling
                  convention, and pass the address of the array descriptor
                  instead. Otherwise we use g77's calling convention.  */
-             int f;
+             bool f;
              f = (fsym != NULL)
                  && !(fsym->attr.pointer || fsym->attr.allocatable)
                  && fsym->as->type != AS_ASSUMED_SHAPE;
@@ -2991,7 +2923,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
                   is converted to a temporary, which is passed and then
                   written back after the procedure call.  */
                gfc_conv_subref_array_arg (&parmse, e, f,
-                       fsym ? fsym->attr.intent : INTENT_INOUT);
+                               fsym ? fsym->attr.intent : INTENT_INOUT,
+                               fsym && fsym->attr.pointer);
              else
                gfc_conv_array_parameter (&parmse, e, argss, f, fsym,
                                          sym->name, NULL);
@@ -3138,7 +3071,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
                 it is invalid to pass a non-present argument on, even
                 though there is no technical reason for this in gfortran.
                 See Fortran 2003, Section 12.4.1.6 item (7)+(8).  */
-             tree present, nullptr, type;
+             tree present, null_ptr, type;
 
              if (attr->allocatable
                  && (fsym == NULL || !fsym->attr.allocatable))
@@ -3162,10 +3095,10 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
              present = fold_build2 (EQ_EXPR, boolean_type_node, present,
                                     fold_convert (type, null_pointer_node));
              type = TREE_TYPE (parmse.expr);
-             nullptr = fold_build2 (EQ_EXPR, boolean_type_node, parmse.expr,
-                                    fold_convert (type, null_pointer_node));
+             null_ptr = fold_build2 (EQ_EXPR, boolean_type_node, parmse.expr,
+                                     fold_convert (type, null_pointer_node));
              cond = fold_build2 (TRUTH_ORIF_EXPR, boolean_type_node,
-                                 present, nullptr);
+                                 present, null_ptr);
            }
           else
            {
@@ -3275,6 +3208,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
            se->expr = build_fold_indirect_ref_loc (input_location,
                                                se->expr);
 
+         result = build_fold_indirect_ref_loc (input_location,
+                                               se->expr);
          retargs = gfc_chainon_list (retargs, se->expr);
        }
       else if (comp && comp->attr.dimension)
@@ -3297,8 +3232,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
                                       callee_alloc, &se->ss->expr->where);
 
          /* Pass the temporary as the first argument.  */
-         tmp = info->descriptor;
-         tmp = gfc_build_addr_expr (NULL_TREE, tmp);
+         result = info->descriptor;
+         tmp = gfc_build_addr_expr (NULL_TREE, result);
          retargs = gfc_chainon_list (retargs, tmp);
        }
       else if (!comp && sym->result->attr.dimension)
@@ -3321,8 +3256,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
                                       callee_alloc, &se->ss->expr->where);
 
          /* Pass the temporary as the first argument.  */
-         tmp = info->descriptor;
-         tmp = gfc_build_addr_expr (NULL_TREE, tmp);
+         result = info->descriptor;
+         tmp = gfc_build_addr_expr (NULL_TREE, result);
          retargs = gfc_chainon_list (retargs, tmp);
        }
       else if (ts.type == BT_CHARACTER)
@@ -3338,6 +3273,12 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
            {
              var = gfc_create_var (type, "pstr");
 
+             if ((!comp && sym->attr.allocatable)
+                 || (comp && comp->attr.allocatable))
+               gfc_add_modify (&se->pre, var,
+                               fold_convert (TREE_TYPE (var),
+                                             null_pointer_node));
+
              /* Provide an address expression for the function arguments.  */
              var = gfc_build_addr_expr (NULL_TREE, var);
            }
@@ -3400,7 +3341,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
      something like
         x = f()
      where f is pointer valued, we have to dereference the result.  */
-  if (!se->want_pointer && !byref && sym->attr.pointer
+  if (!se->want_pointer && !byref
+      && (sym->attr.pointer || sym->attr.allocatable)
       && !gfc_is_proc_ptr_comp (expr, NULL))
     se->expr = build_fold_indirect_ref_loc (input_location,
                                        se->expr);
@@ -3467,7 +3409,36 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 
   /* Follow the function call with the argument post block.  */
   if (byref)
-    gfc_add_block_to_block (&se->pre, &post);
+    {
+      gfc_add_block_to_block (&se->pre, &post);
+
+      /* Transformational functions of derived types with allocatable
+         components must have the result allocatable components copied.  */
+      arg = expr->value.function.actual;
+      if (result && arg && expr->rank
+           && expr->value.function.isym
+           && expr->value.function.isym->transformational
+           && arg->expr->ts.type == BT_DERIVED
+           && arg->expr->ts.u.derived->attr.alloc_comp)
+       {
+         tree tmp2;
+         /* Copy the allocatable components.  We have to use a
+            temporary here to prevent source allocatable components
+            from being corrupted.  */
+         tmp2 = gfc_evaluate_now (result, &se->pre);
+         tmp = gfc_copy_alloc_comp (arg->expr->ts.u.derived,
+                                    result, tmp2, expr->rank);
+         gfc_add_expr_to_block (&se->pre, tmp);
+         tmp = gfc_copy_allocatable_data (result, tmp2, TREE_TYPE(tmp2),
+                                          expr->rank);
+         gfc_add_expr_to_block (&se->pre, tmp);
+
+         /* Finally free the temporary's data field.  */
+         tmp = gfc_conv_descriptor_data_get (tmp2);
+         tmp = gfc_deallocate_with_status (tmp, NULL_TREE, true, NULL);
+         gfc_add_expr_to_block (&se->pre, tmp);
+       }
+    }
   else
     gfc_add_block_to_block (&se->post, &post);
 
@@ -3817,6 +3788,43 @@ gfc_conv_function_expr (gfc_se * se, gfc_expr * expr)
 }
 
 
+/* Determine whether the given EXPR_CONSTANT is a zero initializer.  */
+
+static bool
+is_zero_initializer_p (gfc_expr * expr)
+{
+  if (expr->expr_type != EXPR_CONSTANT)
+    return false;
+
+  /* We ignore constants with prescribed memory representations for now.  */
+  if (expr->representation.string)
+    return false;
+
+  switch (expr->ts.type)
+    {
+    case BT_INTEGER:
+      return mpz_cmp_si (expr->value.integer, 0) == 0;
+
+    case BT_REAL:
+      return mpfr_zero_p (expr->value.real)
+            && MPFR_SIGN (expr->value.real) >= 0;
+
+    case BT_LOGICAL:
+      return expr->value.logical == 0;
+
+    case BT_COMPLEX:
+      return mpfr_zero_p (mpc_realref (expr->value.complex))
+            && MPFR_SIGN (mpc_realref (expr->value.complex)) >= 0
+             && mpfr_zero_p (mpc_imagref (expr->value.complex))
+            && MPFR_SIGN (mpc_imagref (expr->value.complex)) >= 0;
+
+    default:
+      break;
+    }
+  return false;
+}
+
+
 static void
 gfc_conv_array_constructor_expr (gfc_se * se, gfc_expr * expr)
 {
@@ -3850,12 +3858,14 @@ gfc_conv_initializer (gfc_expr * expr, gfc_typespec * ts, tree type,
     {
       gfc_symbol *derived = expr->ts.u.derived;
 
-      expr = gfc_int_expr (0);
-
       /* The derived symbol has already been converted to a (void *).  Use
         its kind.  */
+      expr = gfc_get_int_expr (derived->ts.kind, NULL, 0);
       expr->ts.f90_type = derived->ts.f90_type;
-      expr->ts.kind = derived->ts.kind;
+
+      gfc_init_se (&se, NULL);
+      gfc_conv_constant (&se, expr);
+      return se.expr;
     }
   
   if (array)
@@ -3863,6 +3873,9 @@ gfc_conv_initializer (gfc_expr * expr, gfc_typespec * ts, tree type,
       /* Arrays need special handling.  */
       if (pointer)
        return gfc_build_null_descriptor (type);
+      /* Special case assigning an array to zero.  */
+      else if (is_zero_initializer_p (expr))
+        return build_constructor (type, NULL);
       else
        return gfc_conv_array_initializer (type, expr);
     }
@@ -3875,7 +3888,10 @@ gfc_conv_initializer (gfc_expr * expr, gfc_typespec * ts, tree type,
        case BT_DERIVED:
        case BT_CLASS:
          gfc_init_se (&se, NULL);
-         gfc_conv_structure (&se, expr, 1);
+         if (ts->type == BT_CLASS && expr->expr_type == EXPR_NULL)
+           gfc_conv_structure (&se, gfc_class_null_initializer(ts), 1);
+         else
+           gfc_conv_structure (&se, expr, 1);
          return se.expr;
 
        case BT_CHARACTER:
@@ -3971,7 +3987,7 @@ gfc_trans_subarray_assign (tree dest, gfc_component * cm, gfc_expr * expr)
 
   gfc_conv_expr (&rse, expr);
 
-  tmp = gfc_trans_scalar_assign (&lse, &rse, cm->ts, true, false);
+  tmp = gfc_trans_scalar_assign (&lse, &rse, cm->ts, true, false, true);
   gfc_add_expr_to_block (&body, tmp);
 
   gcc_assert (rse.ss == gfc_ss_terminator);
@@ -3993,6 +4009,149 @@ gfc_trans_subarray_assign (tree dest, gfc_component * cm, gfc_expr * expr)
 }
 
 
+static tree
+gfc_trans_alloc_subarray_assign (tree dest, gfc_component * cm,
+                                gfc_expr * expr)
+{
+  gfc_se se;
+  gfc_ss *rss;
+  stmtblock_t block;
+  tree offset;
+  int n;
+  tree tmp;
+  tree tmp2;
+  gfc_array_spec *as;
+  gfc_expr *arg = NULL;
+
+  gfc_start_block (&block);
+  gfc_init_se (&se, NULL);
+
+  /* Get the descriptor for the expressions.  */ 
+  rss = gfc_walk_expr (expr);
+  se.want_pointer = 0;
+  gfc_conv_expr_descriptor (&se, expr, rss);
+  gfc_add_block_to_block (&block, &se.pre);
+  gfc_add_modify (&block, dest, se.expr);
+
+  /* Deal with arrays of derived types with allocatable components.  */
+  if (cm->ts.type == BT_DERIVED
+       && cm->ts.u.derived->attr.alloc_comp)
+    tmp = gfc_copy_alloc_comp (cm->ts.u.derived,
+                              se.expr, dest,
+                              cm->as->rank);
+  else
+    tmp = gfc_duplicate_allocatable (dest, se.expr,
+                                    TREE_TYPE(cm->backend_decl),
+                                    cm->as->rank);
+
+  gfc_add_expr_to_block (&block, tmp);
+  gfc_add_block_to_block (&block, &se.post);
+
+  if (expr->expr_type != EXPR_VARIABLE)
+    gfc_conv_descriptor_data_set (&block, se.expr,
+                                 null_pointer_node);
+
+  /* We need to know if the argument of a conversion function is a
+     variable, so that the correct lower bound can be used.  */
+  if (expr->expr_type == EXPR_FUNCTION
+       && expr->value.function.isym
+       && expr->value.function.isym->conversion
+       && expr->value.function.actual->expr
+       && expr->value.function.actual->expr->expr_type == EXPR_VARIABLE)
+    arg = expr->value.function.actual->expr;
+
+  /* Obtain the array spec of full array references.  */
+  if (arg)
+    as = gfc_get_full_arrayspec_from_expr (arg);
+  else
+    as = gfc_get_full_arrayspec_from_expr (expr);
+
+  /* Shift the lbound and ubound of temporaries to being unity,
+     rather than zero, based. Always calculate the offset.  */
+  offset = gfc_conv_descriptor_offset_get (dest);
+  gfc_add_modify (&block, offset, gfc_index_zero_node);
+  tmp2 =gfc_create_var (gfc_array_index_type, NULL);
+
+  for (n = 0; n < expr->rank; n++)
+    {
+      tree span;
+      tree lbound;
+
+      /* Obtain the correct lbound - ISO/IEC TR 15581:2001 page 9.
+        TODO It looks as if gfc_conv_expr_descriptor should return
+        the correct bounds and that the following should not be
+        necessary.  This would simplify gfc_conv_intrinsic_bound
+        as well.  */
+      if (as && as->lower[n])
+       {
+         gfc_se lbse;
+         gfc_init_se (&lbse, NULL);
+         gfc_conv_expr (&lbse, as->lower[n]);
+         gfc_add_block_to_block (&block, &lbse.pre);
+         lbound = gfc_evaluate_now (lbse.expr, &block);
+       }
+      else if (as && arg)
+       {
+         tmp = gfc_get_symbol_decl (arg->symtree->n.sym);
+         lbound = gfc_conv_descriptor_lbound_get (tmp,
+                                       gfc_rank_cst[n]);
+       }
+      else if (as)
+       lbound = gfc_conv_descriptor_lbound_get (dest,
+                                               gfc_rank_cst[n]);
+      else
+       lbound = gfc_index_one_node;
+
+      lbound = fold_convert (gfc_array_index_type, lbound);
+
+      /* Shift the bounds and set the offset accordingly.  */
+      tmp = gfc_conv_descriptor_ubound_get (dest, gfc_rank_cst[n]);
+      span = fold_build2 (MINUS_EXPR, gfc_array_index_type, tmp,
+               gfc_conv_descriptor_lbound_get (dest, gfc_rank_cst[n]));
+      tmp = fold_build2 (PLUS_EXPR, gfc_array_index_type, span, lbound);
+      gfc_conv_descriptor_ubound_set (&block, dest,
+                                     gfc_rank_cst[n], tmp);
+      gfc_conv_descriptor_lbound_set (&block, dest,
+                                     gfc_rank_cst[n], lbound);
+
+      tmp = fold_build2 (MULT_EXPR, gfc_array_index_type,
+                        gfc_conv_descriptor_lbound_get (dest,
+                                                        gfc_rank_cst[n]),
+                        gfc_conv_descriptor_stride_get (dest,
+                                                        gfc_rank_cst[n]));
+      gfc_add_modify (&block, tmp2, tmp);
+      tmp = fold_build2 (MINUS_EXPR, gfc_array_index_type, offset, tmp2);
+      gfc_conv_descriptor_offset_set (&block, dest, tmp);
+    }
+
+  if (arg)
+    {
+      /* If a conversion expression has a null data pointer
+        argument, nullify the allocatable component.  */
+      tree non_null_expr;
+      tree null_expr;
+
+      if (arg->symtree->n.sym->attr.allocatable
+           || arg->symtree->n.sym->attr.pointer)
+       {
+         non_null_expr = gfc_finish_block (&block);
+         gfc_start_block (&block);
+         gfc_conv_descriptor_data_set (&block, dest,
+                                       null_pointer_node);
+         null_expr = gfc_finish_block (&block);
+         tmp = gfc_conv_descriptor_data_get (arg->symtree->n.sym->backend_decl);
+         tmp = build2 (EQ_EXPR, boolean_type_node, tmp,
+                       fold_convert (TREE_TYPE (tmp),
+                                     null_pointer_node));
+         return build3_v (COND_EXPR, tmp,
+                          null_expr, non_null_expr);
+       }
+    }
+
+  return gfc_finish_block (&block);
+}
+
+
 /* Assign a single component of a derived type constructor.  */
 
 static tree
@@ -4003,8 +4162,6 @@ gfc_trans_subcomponent_assign (tree dest, gfc_component * cm, gfc_expr * expr)
   gfc_ss *rss;
   stmtblock_t block;
   tree tmp;
-  tree offset;
-  int n;
 
   gfc_start_block (&block);
 
@@ -4042,7 +4199,7 @@ gfc_trans_subcomponent_assign (tree dest, gfc_component * cm, gfc_expr * expr)
     {
       /* NULL initialization for CLASS components.  */
       tmp = gfc_trans_structure_assign (dest,
-                                       gfc_default_initializer (&cm->ts));
+                                       gfc_class_null_initializer (&cm->ts));
       gfc_add_expr_to_block (&block, tmp);
     }
   else if (cm->attr.dimension)
@@ -4051,89 +4208,8 @@ gfc_trans_subcomponent_assign (tree dest, gfc_component * cm, gfc_expr * expr)
        gfc_conv_descriptor_data_set (&block, dest, null_pointer_node);
       else if (cm->attr.allocatable)
        {
-         tree tmp2;
-
-          gfc_init_se (&se, NULL);
-         rss = gfc_walk_expr (expr);
-         se.want_pointer = 0;
-         gfc_conv_expr_descriptor (&se, expr, rss);
-         gfc_add_block_to_block (&block, &se.pre);
-         gfc_add_modify (&block, dest, se.expr);
-
-         if (cm->ts.type == BT_DERIVED && cm->ts.u.derived->attr.alloc_comp)
-           tmp = gfc_copy_alloc_comp (cm->ts.u.derived, se.expr, dest,
-                                      cm->as->rank);
-         else
-           tmp = gfc_duplicate_allocatable (dest, se.expr,
-                                            TREE_TYPE(cm->backend_decl),
-                                            cm->as->rank);
-
+         tmp = gfc_trans_alloc_subarray_assign (dest, cm, expr);
          gfc_add_expr_to_block (&block, tmp);
-         gfc_add_block_to_block (&block, &se.post);
-
-         if (expr->expr_type != EXPR_VARIABLE)
-           gfc_conv_descriptor_data_set (&block, se.expr, null_pointer_node);
-
-         /* Shift the lbound and ubound of temporaries to being unity, rather
-            than zero, based.  Calculate the offset for all cases.  */
-         offset = gfc_conv_descriptor_offset_get (dest);
-         gfc_add_modify (&block, offset, gfc_index_zero_node);
-         tmp2 =gfc_create_var (gfc_array_index_type, NULL);
-         for (n = 0; n < expr->rank; n++)
-           {
-             if (expr->expr_type != EXPR_VARIABLE
-                   && expr->expr_type != EXPR_CONSTANT)
-               {
-                 tree span;
-                 tmp = gfc_conv_descriptor_ubound_get (dest, gfc_rank_cst[n]);
-                 span = fold_build2 (MINUS_EXPR, gfc_array_index_type, tmp,
-                           gfc_conv_descriptor_lbound_get (dest, gfc_rank_cst[n]));
-                 tmp = fold_build2 (PLUS_EXPR, gfc_array_index_type,
-                                    span, gfc_index_one_node);
-                 gfc_conv_descriptor_ubound_set (&block, dest, gfc_rank_cst[n],
-                                                 tmp);
-                 gfc_conv_descriptor_lbound_set (&block, dest, gfc_rank_cst[n],
-                                                 gfc_index_one_node);
-               }
-             tmp = fold_build2 (MULT_EXPR, gfc_array_index_type,
-                                gfc_conv_descriptor_lbound_get (dest,
-                                                            gfc_rank_cst[n]),
-                                gfc_conv_descriptor_stride_get (dest,
-                                                            gfc_rank_cst[n]));
-             gfc_add_modify (&block, tmp2, tmp);
-             tmp = fold_build2 (MINUS_EXPR, gfc_array_index_type, offset, tmp2);
-             gfc_conv_descriptor_offset_set (&block, dest, tmp);
-           }
-
-         if (expr->expr_type == EXPR_FUNCTION
-               && expr->value.function.isym
-               && expr->value.function.isym->conversion
-               && expr->value.function.actual->expr
-               && expr->value.function.actual->expr->expr_type
-                                               == EXPR_VARIABLE)
-           {
-             /* If a conversion expression has a null data pointer
-                argument, nullify the allocatable component.  */
-             gfc_symbol *s;
-             tree non_null_expr;
-             tree null_expr;
-             s = expr->value.function.actual->expr->symtree->n.sym;
-             if (s->attr.allocatable || s->attr.pointer)
-               {
-                 non_null_expr = gfc_finish_block (&block);
-                 gfc_start_block (&block);
-                 gfc_conv_descriptor_data_set (&block, dest,
-                                               null_pointer_node);
-                 null_expr = gfc_finish_block (&block);
-                 tmp = gfc_conv_descriptor_data_get (s->backend_decl);
-                 tmp = build2 (EQ_EXPR, boolean_type_node, tmp,
-                               fold_convert (TREE_TYPE (tmp),
-                                             null_pointer_node));
-                 return build3_v (COND_EXPR, tmp, null_expr,
-                                  non_null_expr);
-               }
-           }
        }
       else
        {
@@ -4169,7 +4245,7 @@ gfc_trans_subcomponent_assign (tree dest, gfc_component * cm, gfc_expr * expr)
       if (cm->ts.type == BT_CHARACTER)
        lse.string_length = cm->ts.u.cl->backend_decl;
       lse.expr = dest;
-      tmp = gfc_trans_scalar_assign (&lse, &se, cm->ts, true, false);
+      tmp = gfc_trans_scalar_assign (&lse, &se, cm->ts, true, false, true);
       gfc_add_expr_to_block (&block, tmp);
     }
   return gfc_finish_block (&block);
@@ -4188,12 +4264,26 @@ gfc_trans_structure_assign (tree dest, gfc_expr * expr)
 
   gfc_start_block (&block);
   cm = expr->ts.u.derived->components;
-  for (c = expr->value.constructor; c; c = c->next, cm = cm->next)
+  for (c = gfc_constructor_first (expr->value.constructor);
+       c; c = gfc_constructor_next (c), cm = cm->next)
     {
       /* Skip absent members in default initializers.  */
       if (!c->expr)
        continue;
 
+      /* Handle c_null_(fun)ptr.  */
+      if (c && c->expr && c->expr->ts.is_iso_c)
+       {
+         field = cm->backend_decl;
+         tmp = fold_build3 (COMPONENT_REF, TREE_TYPE (field),
+                            dest, field, NULL_TREE);
+         tmp = fold_build2 (MODIFY_EXPR, TREE_TYPE (tmp), tmp,
+                            fold_convert (TREE_TYPE (tmp),
+                                          null_pointer_node));
+         gfc_add_expr_to_block (&block, tmp);
+         continue;
+       }
+
       field = cm->backend_decl;
       tmp = fold_build3 (COMPONENT_REF, TREE_TYPE (field),
                         dest, field, NULL_TREE);
@@ -4231,7 +4321,8 @@ gfc_conv_structure (gfc_se * se, gfc_expr * expr, int init)
 
   cm = expr->ts.u.derived->components;
 
-  for (c = expr->value.constructor; c; c = c->next, cm = cm->next)
+  for (c = gfc_constructor_first (expr->value.constructor);
+       c; c = gfc_constructor_next (c), cm = cm->next)
     {
       /* Skip absent members in default initializers and allocatable
         components.  Although the latter have a default initializer
@@ -4240,16 +4331,19 @@ gfc_conv_structure (gfc_se * se, gfc_expr * expr, int init)
       if (!c->expr || cm->attr.allocatable)
         continue;
 
-      if (cm->ts.type == BT_CLASS)
+      if (strcmp (cm->name, "$size") == 0)
        {
-         val = gfc_conv_initializer (c->expr, &cm->ts,
-             TREE_TYPE (cm->ts.u.derived->components->backend_decl),
-             cm->ts.u.derived->components->attr.dimension,
-             cm->ts.u.derived->components->attr.pointer);
-
-         /* Append it to the constructor list.  */
-         CONSTRUCTOR_APPEND_ELT (v, cm->ts.u.derived->components->backend_decl,
-                                 val);
+         val = TYPE_SIZE_UNIT (gfc_get_derived_type (cm->ts.u.derived));
+         CONSTRUCTOR_APPEND_ELT (v, cm->backend_decl, val);
+       }
+      else if (cm->initializer && cm->initializer->expr_type != EXPR_NULL
+              && strcmp (cm->name, "$extends") == 0)
+       {
+         tree vtab;
+         gfc_symbol *vtabs;
+         vtabs = cm->initializer->symtree->n.sym;
+         vtab = gfc_build_addr_expr (NULL_TREE, gfc_get_symbol_decl (vtabs));
+         CONSTRUCTOR_APPEND_ELT (v, cm->backend_decl, vtab);
        }
       else
        {
@@ -4303,6 +4397,8 @@ gfc_conv_expr (gfc_se * se, gfc_expr * expr)
       /* Substitute a scalar expression evaluated outside the scalarization
          loop.  */
       se->expr = se->ss->data.scalar.expr;
+      if (se->ss->type == GFC_SS_REFERENCE)
+       se->expr = gfc_build_addr_expr (NULL_TREE, se->expr);
       se->string_length = se->ss->string_length;
       gfc_advance_se_ss_chain (se);
       return;
@@ -4423,9 +4519,9 @@ gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr)
   if (se->ss && se->ss->expr == expr
       && se->ss->type == GFC_SS_REFERENCE)
     {
-      se->expr = se->ss->data.scalar.expr;
-      se->string_length = se->ss->string_length;
-      gfc_advance_se_ss_chain (se);
+      /* Returns a reference to the scalar evaluated outside the loop
+        for this case.  */
+      gfc_conv_expr (se, expr);
       return;
     }
 
@@ -4669,11 +4765,12 @@ gfc_conv_string_parameter (gfc_se * se)
 
 
 /* Generate code for assignment of scalar variables.  Includes character
-   strings and derived types with allocatable components.  */
+   strings and derived types with allocatable components.
+   If you know that the LHS has no allocations, set dealloc to false.  */
 
 tree
 gfc_trans_scalar_assign (gfc_se * lse, gfc_se * rse, gfc_typespec ts,
-                        bool l_is_temp, bool r_is_var)
+                        bool l_is_temp, bool r_is_var, bool dealloc)
 {
   stmtblock_t block;
   tree tmp;
@@ -4721,7 +4818,7 @@ gfc_trans_scalar_assign (gfc_se * lse, gfc_se * rse, gfc_typespec ts,
         the same as the rhs.  This must be done following the assignment
         to prevent deallocating data that could be used in the rhs
         expression.  */
-      if (!l_is_temp)
+      if (!l_is_temp && dealloc)
        {
          tmp = gfc_evaluate_now (lse->expr, &lse->pre);
          tmp = gfc_deallocate_alloc_comp (ts.u.derived, tmp, 0);
@@ -4858,7 +4955,16 @@ gfc_trans_arrayfunc_assign (gfc_expr * expr1, gfc_expr * expr2)
   gfc_start_block (&se.pre);
   se.want_pointer = 1;
 
-  gfc_conv_array_parameter (&se, expr1, ss, 0, NULL, NULL, NULL);
+  gfc_conv_array_parameter (&se, expr1, ss, false, NULL, NULL, NULL);
+
+  if (expr1->ts.type == BT_DERIVED
+       && expr1->ts.u.derived->attr.alloc_comp)
+    {
+      tree tmp;
+      tmp = gfc_deallocate_alloc_comp (expr1->ts.u.derived, se.expr,
+                                      expr1->rank);
+      gfc_add_expr_to_block (&se.pre, tmp);
+    }
 
   se.direct_byref = 1;
   se.ss = gfc_walk_expr (expr2);
@@ -4869,41 +4975,6 @@ gfc_trans_arrayfunc_assign (gfc_expr * expr1, gfc_expr * expr2)
   return gfc_finish_block (&se.pre);
 }
 
-/* Determine whether the given EXPR_CONSTANT is a zero initializer.  */
-
-static bool
-is_zero_initializer_p (gfc_expr * expr)
-{
-  if (expr->expr_type != EXPR_CONSTANT)
-    return false;
-
-  /* We ignore constants with prescribed memory representations for now.  */
-  if (expr->representation.string)
-    return false;
-
-  switch (expr->ts.type)
-    {
-    case BT_INTEGER:
-      return mpz_cmp_si (expr->value.integer, 0) == 0;
-
-    case BT_REAL:
-      return mpfr_zero_p (expr->value.real)
-            && MPFR_SIGN (expr->value.real) >= 0;
-
-    case BT_LOGICAL:
-      return expr->value.logical == 0;
-
-    case BT_COMPLEX:
-      return mpfr_zero_p (mpc_realref (expr->value.complex))
-            && MPFR_SIGN (mpc_realref (expr->value.complex)) >= 0
-             && mpfr_zero_p (mpc_imagref (expr->value.complex))
-            && MPFR_SIGN (mpc_imagref (expr->value.complex)) >= 0;
-
-    default:
-      break;
-    }
-  return false;
-}
 
 /* Try to efficiently translate array(:) = 0.  Return NULL if this
    can't be done.  */
@@ -5077,10 +5148,13 @@ gfc_trans_array_constructor_copy (gfc_expr * expr1, gfc_expr * expr2)
 
 
 /* Subroutine of gfc_trans_assignment that actually scalarizes the
-   assignment.  EXPR1 is the destination/LHS and EXPR2 is the source/RHS.  */
+   assignment.  EXPR1 is the destination/LHS and EXPR2 is the source/RHS.
+   init_flag indicates initialization expressions and dealloc that no
+   deallocate prior assignment is needed (if in doubt, set true).  */
 
 static tree
-gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag)
+gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
+                       bool dealloc)
 {
   gfc_se lse;
   gfc_se rse;
@@ -5197,7 +5271,7 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag)
                       && expr2->expr_type != EXPR_VARIABLE
                       && !gfc_is_constant_expr (expr2)
                       && expr1->rank && !expr2->rank);
-  if (scalar_to_array)
+  if (scalar_to_array && dealloc)
     {
       tmp = gfc_deallocate_alloc_comp (expr2->ts.u.derived, rse.expr, 0);
       gfc_add_expr_to_block (&loop.post, tmp);
@@ -5206,7 +5280,7 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag)
   tmp = gfc_trans_scalar_assign (&lse, &rse, expr1->ts,
                                 l_is_temp || init_flag,
                                 (expr2->expr_type == EXPR_VARIABLE)
-                                   || scalar_to_array);
+                                   || scalar_to_array, dealloc);
   gfc_add_expr_to_block (&body, tmp);
 
   if (lss == gfc_ss_terminator)
@@ -5243,7 +5317,7 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag)
            rse.string_length = string_length;
 
          tmp = gfc_trans_scalar_assign (&lse, &rse, expr1->ts,
-                                        false, false);
+                                        false, false, dealloc);
          gfc_add_expr_to_block (&body, tmp);
        }
 
@@ -5301,7 +5375,8 @@ copyable_array_p (gfc_expr * expr)
 /* Translate an assignment.  */
 
 tree
-gfc_trans_assignment (gfc_expr * expr1, gfc_expr * expr2, bool init_flag)
+gfc_trans_assignment (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
+                     bool dealloc)
 {
   tree tmp;
 
@@ -5344,19 +5419,116 @@ gfc_trans_assignment (gfc_expr * expr1, gfc_expr * expr2, bool init_flag)
     }
 
   /* Fallback to the scalarizer to generate explicit loops.  */
-  return gfc_trans_assignment_1 (expr1, expr2, init_flag);
+  return gfc_trans_assignment_1 (expr1, expr2, init_flag, dealloc);
 }
 
 tree
 gfc_trans_init_assign (gfc_code * code)
 {
-  return gfc_trans_assignment (code->expr1, code->expr2, true);
+  return gfc_trans_assignment (code->expr1, code->expr2, true, false);
 }
 
 tree
 gfc_trans_assign (gfc_code * code)
 {
-  return gfc_trans_assignment (code->expr1, code->expr2, false);
+  return gfc_trans_assignment (code->expr1, code->expr2, false, true);
+}
+
+
+/* Generate code to assign typebound procedures to a derived vtab.  */
+void gfc_trans_assign_vtab_procs (stmtblock_t *block, gfc_symbol *dt,
+                                 gfc_symbol *vtab)
+{
+  gfc_component *cmp;
+  tree vtb;
+  tree ctree;
+  tree proc;
+  tree cond = NULL_TREE;
+  stmtblock_t body;
+  bool seen_extends;
+
+  /* Point to the first procedure pointer.  */
+  cmp = gfc_find_component (vtab->ts.u.derived, "$extends", true, true);
+
+  seen_extends = (cmp != NULL);
+
+  vtb = gfc_get_symbol_decl (vtab);
+
+  if (seen_extends)
+    {
+      cmp = cmp->next;
+      if (!cmp)
+       return;
+      ctree = fold_build3 (COMPONENT_REF, TREE_TYPE (cmp->backend_decl),
+                          vtb, cmp->backend_decl, NULL_TREE);
+      cond = fold_build2 (EQ_EXPR, boolean_type_node, ctree,
+                          build_int_cst (TREE_TYPE (ctree), 0));
+    }
+  else
+    {
+      cmp = vtab->ts.u.derived->components; 
+    }
+
+  gfc_init_block (&body);
+  for (; cmp; cmp = cmp->next)
+    {
+      gfc_symbol *target = NULL;
+      
+      /* Generic procedure - build its vtab.  */
+      if (cmp->ts.type == BT_DERIVED && !cmp->tb)
+       {
+         gfc_symbol *vt = cmp->ts.interface;
+
+         if (vt == NULL)
+           {
+             /* Use association loses the interface.  Obtain the vtab
+                by name instead.  */
+             char name[2 * GFC_MAX_SYMBOL_LEN + 8];
+             sprintf (name, "vtab$%s$%s", vtab->ts.u.derived->name,
+                      cmp->name);
+             gfc_find_symbol (name, vtab->ns, 0, &vt);
+             if (vt == NULL)
+               continue;
+           }
+
+         gfc_trans_assign_vtab_procs (&body, dt, vt);
+         ctree = fold_build3 (COMPONENT_REF, TREE_TYPE (cmp->backend_decl),
+                              vtb, cmp->backend_decl, NULL_TREE);
+         proc = gfc_get_symbol_decl (vt);
+         proc = gfc_build_addr_expr (TREE_TYPE (ctree), proc);
+         gfc_add_modify (&body, ctree, proc);
+         continue;
+       }
+
+      /* This is required when typebound generic procedures are called
+        with derived type targets.  The specific procedures do not get
+        added to the vtype, which remains "empty".  */
+      if (cmp->tb && cmp->tb->u.specific && cmp->tb->u.specific->n.sym)
+       target = cmp->tb->u.specific->n.sym;
+      else
+       {
+         gfc_symtree *st;
+         st = gfc_find_typebound_proc (dt, NULL, cmp->name, false, NULL);
+         if (st->n.tb && st->n.tb->u.specific)
+           target = st->n.tb->u.specific->n.sym;
+       }
+
+      if (!target)
+       continue;
+
+      ctree = fold_build3 (COMPONENT_REF, TREE_TYPE (cmp->backend_decl),
+                          vtb, cmp->backend_decl, NULL_TREE);
+      proc = gfc_get_symbol_decl (target);
+      proc = gfc_build_addr_expr (TREE_TYPE (ctree), proc);
+      gfc_add_modify (&body, ctree, proc);
+    }
+
+  proc = gfc_finish_block (&body);
+
+  if (seen_extends)
+    proc = build3_v (COND_EXPR, cond, proc, build_empty_stmt (input_location));
+
+  gfc_add_expr_to_block (block, proc);
 }
 
 
@@ -5368,47 +5540,56 @@ gfc_trans_class_assign (gfc_code *code)
 {
   stmtblock_t block;
   tree tmp;
+  gfc_expr *lhs;
+  gfc_expr *rhs;
 
   gfc_start_block (&block);
-
-  if (code->expr2->ts.type != BT_CLASS)
+  
+  if (code->op == EXEC_INIT_ASSIGN)
     {
-      /* Insert an additional assignment which sets the '$vindex' field.  */
-      gfc_expr *lhs,*rhs;
-      lhs = gfc_copy_expr (code->expr1);
-      gfc_add_component_ref (lhs, "$vindex");
-      if (code->expr2->ts.type == BT_DERIVED)
-       /* vindex is constant, determined at compile time.  */
-       rhs = gfc_int_expr (code->expr2->ts.u.derived->vindex);
-      else if (code->expr2->expr_type == EXPR_NULL)
-       rhs = gfc_int_expr (0);
-      else
-       gcc_unreachable ();
-      tmp = gfc_trans_assignment (lhs, rhs, false);
+      /* Special case for initializing a CLASS variable on allocation.
+        A MEMCPY is needed to copy the full data of the dynamic type,
+        which may be different from the declared type.  */
+      gfc_se dst,src;
+      tree memsz;
+      gfc_init_se (&dst, NULL);
+      gfc_init_se (&src, NULL);
+      gfc_add_component_ref (code->expr1, "$data");
+      gfc_conv_expr (&dst, code->expr1);
+      gfc_conv_expr (&src, code->expr2);
+      gfc_add_block_to_block (&block, &src.pre);
+      memsz = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&code->expr2->ts));
+      tmp = gfc_build_memcpy_call (dst.expr, src.expr, memsz);
       gfc_add_expr_to_block (&block, tmp);
+      return gfc_finish_block (&block);
+    }
 
-      /* Insert another assignment which sets the '$size' field.  */
+  if (code->expr2->ts.type != BT_CLASS)
+    {
+      /* Insert an additional assignment which sets the '$vptr' field.  */
       lhs = gfc_copy_expr (code->expr1);
-      gfc_add_component_ref (lhs, "$size");
+      gfc_add_component_ref (lhs, "$vptr");
       if (code->expr2->ts.type == BT_DERIVED)
        {
-         /* Size is fixed at compile time.  */
-         gfc_se lse;
-         gfc_init_se (&lse, NULL);
-         gfc_conv_expr (&lse, lhs);
-         tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&code->expr2->ts));
-         gfc_add_modify (&block, lse.expr,
-                         fold_convert (TREE_TYPE (lse.expr), tmp));
+         gfc_symbol *vtab;
+         gfc_symtree *st;
+         vtab = gfc_find_derived_vtab (code->expr2->ts.u.derived, true);
+         gcc_assert (vtab);
+         gfc_trans_assign_vtab_procs (&block, code->expr2->ts.u.derived, vtab);
+         rhs = gfc_get_expr ();
+         rhs->expr_type = EXPR_VARIABLE;
+         gfc_find_sym_tree (vtab->name, NULL, 1, &st);
+         rhs->symtree = st;
+         rhs->ts = vtab->ts;
        }
       else if (code->expr2->expr_type == EXPR_NULL)
-       {
-         rhs = gfc_int_expr (0);
-         tmp = gfc_trans_assignment (lhs, rhs, false);
-         gfc_add_expr_to_block (&block, tmp);
-       }
+       rhs = gfc_get_int_expr (gfc_default_integer_kind, NULL, 0);
       else
        gcc_unreachable ();
 
+      tmp = gfc_trans_pointer_assignment (lhs, rhs);
+      gfc_add_expr_to_block (&block, tmp);
+
       gfc_free_expr (lhs);
       gfc_free_expr (rhs);
     }