OSDN Git Service

2010-02-20 Paul Thomas <pault@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / fortran / trans-array.c
index 2708355..2ea978d 100644 (file)
@@ -725,7 +725,7 @@ gfc_trans_create_temp_array (stmtblock_t * pre, stmtblock_t * post,
   /* Initialize the descriptor.  */
   type =
     gfc_get_array_type_bounds (eltype, info->dimen, loop->from, loop->to, 1,
-                              GFC_ARRAY_UNKNOWN);
+                              GFC_ARRAY_UNKNOWN, true);
   desc = gfc_create_var (type, "atmp");
   GFC_DECL_PACKED_ARRAY (desc) = 1;
 
@@ -837,7 +837,7 @@ gfc_conv_array_transpose (gfc_se * se, gfc_expr * expr)
 {
   tree dest, src, dest_index, src_index;
   gfc_loopinfo *loop;
-  gfc_ss_info *dest_info, *src_info;
+  gfc_ss_info *dest_info;
   gfc_ss *dest_ss, *src_ss;
   gfc_se src_se;
   int n;
@@ -847,10 +847,8 @@ gfc_conv_array_transpose (gfc_se * se, gfc_expr * expr)
   src_ss = gfc_walk_expr (expr);
   dest_ss = se->ss;
 
-  src_info = &src_ss->data.info;
   dest_info = &dest_ss->data.info;
   gcc_assert (dest_info->dimen == 2);
-  gcc_assert (src_info->dimen == 2);
 
   /* Get a descriptor for EXPR.  */
   gfc_init_se (&src_se, NULL);
@@ -1533,7 +1531,7 @@ get_array_ctor_var_strlen (gfc_expr * expr, tree * len)
        }
     }
 
-  *len = ts->cl->backend_decl;
+  *len = ts->u.cl->backend_decl;
 }
 
 
@@ -1549,12 +1547,12 @@ get_array_ctor_all_strlen (stmtblock_t *block, gfc_expr *e, tree *len)
   if (*len && INTEGER_CST_P (*len))
     return;
 
-  if (!e->ref && e->ts.cl && e->ts.cl->length
-       && e->ts.cl->length->expr_type == EXPR_CONSTANT)
+  if (!e->ref && e->ts.u.cl && e->ts.u.cl->length
+       && e->ts.u.cl->length->expr_type == EXPR_CONSTANT)
     {
       /* This is easy.  */
-      gfc_conv_const_charlen (e->ts.cl);
-      *len = e->ts.cl->backend_decl;
+      gfc_conv_const_charlen (e->ts.u.cl);
+      *len = e->ts.u.cl->backend_decl;
     }
   else
     {
@@ -1575,7 +1573,7 @@ get_array_ctor_all_strlen (stmtblock_t *block, gfc_expr *e, tree *len)
       gfc_add_block_to_block (block, &se.pre);
       gfc_add_block_to_block (block, &se.post);
 
-      e->ts.cl->backend_decl = *len;
+      e->ts.u.cl->backend_decl = *len;
     }
 }
 
@@ -1715,7 +1713,7 @@ gfc_build_constant_array_constructor (gfc_expr * expr, tree type)
        as.upper[i] = gfc_int_expr (tmp - 1);
       }
 
-  tmptype = gfc_get_nodesc_array_type (type, &as, PACKED_STATIC);
+  tmptype = gfc_get_nodesc_array_type (type, &as, PACKED_STATIC, true);
 
   init = build_constructor_from_list (tmptype, nreverse (list));
 
@@ -1825,8 +1823,8 @@ gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss, locus * where)
 
   /* Do bounds-checking here and in gfc_trans_array_ctor_element only if no
      typespec was given for the array constructor.  */
-  typespec_chararray_ctor = (ss->expr->ts.cl
-                            && ss->expr->ts.cl->length_from_typespec);
+  typespec_chararray_ctor = (ss->expr->ts.u.cl
+                            && ss->expr->ts.u.cl->length_from_typespec);
 
   if ((gfc_option.rtcheck & GFC_RTCHECK_BOUNDS)
       && ss->expr->ts.type == BT_CHARACTER && !typespec_chararray_ctor)
@@ -1845,14 +1843,14 @@ gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss, locus * where)
       /* get_array_ctor_strlen walks the elements of the constructor, if a
         typespec was given, we already know the string length and want the one
         specified there.  */
-      if (typespec_chararray_ctor && ss->expr->ts.cl->length
-         && ss->expr->ts.cl->length->expr_type != EXPR_CONSTANT)
+      if (typespec_chararray_ctor && ss->expr->ts.u.cl->length
+         && ss->expr->ts.u.cl->length->expr_type != EXPR_CONSTANT)
        {
          gfc_se length_se;
 
          const_string = false;
          gfc_init_se (&length_se, NULL);
-         gfc_conv_expr_type (&length_se, ss->expr->ts.cl->length,
+         gfc_conv_expr_type (&length_se, ss->expr->ts.u.cl->length,
                              gfc_charlen_type_node);
          ss->string_length = length_se.expr;
          gfc_add_block_to_block (&loop->pre, &length_se.pre);
@@ -1866,7 +1864,7 @@ gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss, locus * where)
         and not end up here.  */
       gcc_assert (ss->string_length);
 
-      ss->expr->ts.cl->backend_decl = ss->string_length;
+      ss->expr->ts.u.cl->backend_decl = ss->string_length;
 
       type = gfc_get_character_type_len (ss->expr->ts.kind, ss->string_length);
       if (const_string)
@@ -2096,11 +2094,11 @@ gfc_add_loop_ss_code (gfc_loopinfo * loop, gfc_ss * ss, bool subscript,
        case GFC_SS_CONSTRUCTOR:
          if (ss->expr->ts.type == BT_CHARACTER
                && ss->string_length == NULL
-               && ss->expr->ts.cl
-               && ss->expr->ts.cl->length)
+               && ss->expr->ts.u.cl
+               && ss->expr->ts.u.cl->length)
            {
              gfc_init_se (&se, NULL);
-             gfc_conv_expr_type (&se, ss->expr->ts.cl->length,
+             gfc_conv_expr_type (&se, ss->expr->ts.u.cl->length,
                                  gfc_charlen_type_node);
              ss->string_length = se.expr;
              gfc_add_block_to_block (&loop->pre, &se.pre);
@@ -2296,7 +2294,7 @@ gfc_trans_array_bound_check (gfc_se * se, tree descriptor, tree index, int n,
                             locus * where, bool check_upper)
 {
   tree fault;
-  tree tmp;
+  tree tmp_lo, tmp_up;
   char *msg;
   const char * name = NULL;
 
@@ -2333,34 +2331,46 @@ gfc_trans_array_bound_check (gfc_se * se, tree descriptor, tree index, int n,
          name = "unnamed constant";
     }
 
-  /* Check lower bound.  */
-  tmp = gfc_conv_array_lbound (descriptor, n);
-  fault = fold_build2 (LT_EXPR, boolean_type_node, index, tmp);
-  if (name)
-    asprintf (&msg, "%s for array '%s', lower bound of dimension %d exceeded"
-             "(%%ld < %%ld)", gfc_msg_fault, name, n+1);
-  else
-    asprintf (&msg, "%s, lower bound of dimension %d exceeded (%%ld < %%ld)",
-             gfc_msg_fault, n+1);
-  gfc_trans_runtime_check (true, false, fault, &se->pre, where, msg,
-                          fold_convert (long_integer_type_node, index),
-                          fold_convert (long_integer_type_node, tmp));
-  gfc_free (msg);
-
-  /* Check upper bound.  */
+  /* If upper bound is present, include both bounds in the error message.  */
   if (check_upper)
     {
-      tmp = gfc_conv_array_ubound (descriptor, n);
-      fault = fold_build2 (GT_EXPR, boolean_type_node, index, tmp);
+      tmp_lo = gfc_conv_array_lbound (descriptor, n);
+      tmp_up = gfc_conv_array_ubound (descriptor, n);
+
       if (name)
-       asprintf (&msg, "%s for array '%s', upper bound of dimension %d "
-                       " exceeded (%%ld > %%ld)", gfc_msg_fault, name, n+1);
+       asprintf (&msg, "Index '%%ld' of dimension %d of array '%s' "
+                 "outside of expected range (%%ld:%%ld)", n+1, name);
       else
-       asprintf (&msg, "%s, upper bound of dimension %d exceeded (%%ld > %%ld)",
-                 gfc_msg_fault, n+1);
+       asprintf (&msg, "Index '%%ld' of dimension %d "
+                 "outside of expected range (%%ld:%%ld)", n+1);
+
+      fault = fold_build2 (LT_EXPR, boolean_type_node, index, tmp_lo);
+      gfc_trans_runtime_check (true, false, fault, &se->pre, where, msg,
+                              fold_convert (long_integer_type_node, index),
+                              fold_convert (long_integer_type_node, tmp_lo),
+                              fold_convert (long_integer_type_node, tmp_up));
+      fault = fold_build2 (GT_EXPR, boolean_type_node, index, tmp_up);
       gfc_trans_runtime_check (true, false, fault, &se->pre, where, msg,
                               fold_convert (long_integer_type_node, index),
-                              fold_convert (long_integer_type_node, tmp));
+                              fold_convert (long_integer_type_node, tmp_lo),
+                              fold_convert (long_integer_type_node, tmp_up));
+      gfc_free (msg);
+    }
+  else
+    {
+      tmp_lo = gfc_conv_array_lbound (descriptor, n);
+
+      if (name)
+       asprintf (&msg, "Index '%%ld' of dimension %d of array '%s' "
+                 "below lower bound of %%ld", n+1, name);
+      else
+       asprintf (&msg, "Index '%%ld' of dimension %d "
+                 "below lower bound of %%ld", n+1);
+
+      fault = fold_build2 (LT_EXPR, boolean_type_node, index, tmp_lo);
+      gfc_trans_runtime_check (true, false, fault, &se->pre, where, msg,
+                              fold_convert (long_integer_type_node, index),
+                              fold_convert (long_integer_type_node, tmp_lo));
       gfc_free (msg);
     }
 
@@ -2561,9 +2571,8 @@ gfc_conv_array_ref (gfc_se * se, gfc_array_ref * ar, gfc_symbol * sym,
 
          cond = fold_build2 (LT_EXPR, boolean_type_node, 
                              indexse.expr, tmp);
-         asprintf (&msg, "%s for array '%s', "
-                   "lower bound of dimension %d exceeded (%%ld < %%ld)",
-                   gfc_msg_fault, sym->name, n+1);
+         asprintf (&msg, "Index '%%ld' of dimension %d of array '%s' "
+                   "below lower bound of %%ld", n+1, sym->name);
          gfc_trans_runtime_check (true, false, cond, &se->pre, where, msg,
                                   fold_convert (long_integer_type_node,
                                                 indexse.expr),
@@ -2587,9 +2596,8 @@ gfc_conv_array_ref (gfc_se * se, gfc_array_ref * ar, gfc_symbol * sym,
 
              cond = fold_build2 (GT_EXPR, boolean_type_node, 
                                  indexse.expr, tmp);
-             asprintf (&msg, "%s for array '%s', "
-                       "upper bound of dimension %d exceeded (%%ld > %%ld)",
-                       gfc_msg_fault, sym->name, n+1);
+             asprintf (&msg, "Index '%%ld' of dimension %d of array '%s' "
+                       "above upper bound of %%ld", n+1, sym->name);
              gfc_trans_runtime_check (true, false, cond, &se->pre, where, msg,
                                   fold_convert (long_integer_type_node,
                                                 indexse.expr),
@@ -2755,7 +2763,7 @@ gfc_start_scalarized_body (gfc_loopinfo * loop, stmtblock_t * pbody)
 
 /* Generates the actual loop code for a scalarization loop.  */
 
-static void
+void
 gfc_trans_scalarized_loop_end (gfc_loopinfo * loop, int n,
                               stmtblock_t * pbody)
 {
@@ -2822,7 +2830,8 @@ gfc_trans_scalarized_loop_end (gfc_loopinfo * loop, int n,
       loopbody = gfc_finish_block (pbody);
 
       /* Initialize the loopvar.  */
-      gfc_add_modify (&loop->code[n], loop->loopvar[n], loop->from[n]);
+      if (loop->loopvar[n] != loop->from[n])
+       gfc_add_modify (&loop->code[n], loop->loopvar[n], loop->from[n]);
 
       exit_label = gfc_build_label_decl (NULL_TREE);
 
@@ -3165,7 +3174,7 @@ gfc_conv_ss_startstride (gfc_loopinfo * loop)
       tree lbound, ubound;
       tree end;
       tree size[GFC_MAX_DIMENSIONS];
-      tree stride_pos, stride_neg, non_zerosized, tmp2;
+      tree stride_pos, stride_neg, non_zerosized, tmp2, tmp3;
       gfc_ss_info *info;
       char *msg;
       int dim;
@@ -3245,77 +3254,95 @@ gfc_conv_ss_startstride (gfc_loopinfo * loop)
                                           stride_pos, stride_neg);
 
              /* Check the start of the range against the lower and upper
-                bounds of the array, if the range is not empty.  */
-             tmp = fold_build2 (LT_EXPR, boolean_type_node, info->start[n],
-                                lbound);
-             tmp = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
-                                non_zerosized, tmp);
-             asprintf (&msg, "%s, lower bound of dimension %d of array '%s'"
-                       " exceeded (%%ld < %%ld)", gfc_msg_fault,
-                       info->dim[n]+1, ss->expr->symtree->name);
-             gfc_trans_runtime_check (true, false, tmp, &inner,
-                                      &ss->expr->where, msg,
-                                      fold_convert (long_integer_type_node,
-                                                    info->start[n]),
-                                      fold_convert (long_integer_type_node,
-                                                    lbound));
-             gfc_free (msg);
-
+                bounds of the array, if the range is not empty. 
+                If upper bound is present, include both bounds in the 
+                error message.  */
              if (check_upper)
                {
-                 tmp = fold_build2 (GT_EXPR, boolean_type_node,
-                                    info->start[n], ubound);
+                 tmp = fold_build2 (LT_EXPR, boolean_type_node, 
+                                    info->start[n], lbound);
                  tmp = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
                                     non_zerosized, tmp);
-                 asprintf (&msg, "%s, upper bound of dimension %d of array "
-                           "'%s' exceeded (%%ld > %%ld)", gfc_msg_fault,
+                 tmp2 = fold_build2 (GT_EXPR, boolean_type_node,
+                                     info->start[n], ubound);
+                 tmp2 = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
+                                     non_zerosized, tmp2);
+                 asprintf (&msg, "Index '%%ld' of dimension %d of array '%s' "
+                           "outside of expected range (%%ld:%%ld)", 
                            info->dim[n]+1, ss->expr->symtree->name);
-                 gfc_trans_runtime_check (true, false, tmp, &inner,
-                       &ss->expr->where, msg,
-                       fold_convert (long_integer_type_node, info->start[n]),
-                       fold_convert (long_integer_type_node, ubound));
+                 gfc_trans_runtime_check (true, false, tmp, &inner, 
+                                          &ss->expr->where, msg,
+                    fold_convert (long_integer_type_node, info->start[n]),
+                    fold_convert (long_integer_type_node, lbound), 
+                    fold_convert (long_integer_type_node, ubound));
+                 gfc_trans_runtime_check (true, false, tmp2, &inner, 
+                                          &ss->expr->where, msg,
+                    fold_convert (long_integer_type_node, info->start[n]),
+                    fold_convert (long_integer_type_node, lbound), 
+                    fold_convert (long_integer_type_node, ubound));
                  gfc_free (msg);
                }
-
+             else
+               {
+                 tmp = fold_build2 (LT_EXPR, boolean_type_node, 
+                                    info->start[n], lbound);
+                 tmp = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
+                                    non_zerosized, tmp);
+                 asprintf (&msg, "Index '%%ld' of dimension %d of array '%s' "
+                           "below lower bound of %%ld", 
+                           info->dim[n]+1, ss->expr->symtree->name);
+                 gfc_trans_runtime_check (true, false, tmp, &inner, 
+                                          &ss->expr->where, msg,
+                    fold_convert (long_integer_type_node, info->start[n]),
+                    fold_convert (long_integer_type_node, lbound));
+                 gfc_free (msg);
+               }
+             
              /* Compute the last element of the range, which is not
                 necessarily "end" (think 0:5:3, which doesn't contain 5)
                 and check it against both lower and upper bounds.  */
-             tmp2 = fold_build2 (MINUS_EXPR, gfc_array_index_type, end,
+
+             tmp = fold_build2 (MINUS_EXPR, gfc_array_index_type, end,
                                  info->start[n]);
-             tmp2 = fold_build2 (TRUNC_MOD_EXPR, gfc_array_index_type, tmp2,
+             tmp = fold_build2 (TRUNC_MOD_EXPR, gfc_array_index_type, tmp,
                                  info->stride[n]);
-             tmp2 = fold_build2 (MINUS_EXPR, gfc_array_index_type, end,
-                                 tmp2);
-
-             tmp = fold_build2 (LT_EXPR, boolean_type_node, tmp2, lbound);
-             tmp = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
-                                non_zerosized, tmp);
-             asprintf (&msg, "%s, lower bound of dimension %d of array '%s'"
-                       " exceeded (%%ld < %%ld)", gfc_msg_fault,
-                       info->dim[n]+1, ss->expr->symtree->name);
-             gfc_trans_runtime_check (true, false, tmp, &inner,
-                                      &ss->expr->where, msg,
-                                      fold_convert (long_integer_type_node,
-                                                    tmp2),
-                                      fold_convert (long_integer_type_node,
-                                                    lbound));
-             gfc_free (msg);
-
+             tmp = fold_build2 (MINUS_EXPR, gfc_array_index_type, end,
+                                 tmp);
+             tmp2 = fold_build2 (LT_EXPR, boolean_type_node, tmp, lbound);
+             tmp2 = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
+                                non_zerosized, tmp2);
              if (check_upper)
                {
-                 tmp = fold_build2 (GT_EXPR, boolean_type_node, tmp2, ubound);
-                 tmp = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
-                                    non_zerosized, tmp);
-                 asprintf (&msg, "%s, upper bound of dimension %d of array "
-                           "'%s' exceeded (%%ld > %%ld)", gfc_msg_fault,
+                 tmp3 = fold_build2 (GT_EXPR, boolean_type_node, tmp, ubound);
+                 tmp3 = fold_build2 (TRUTH_AND_EXPR, boolean_type_node,
+                                     non_zerosized, tmp3);
+                 asprintf (&msg, "Index '%%ld' of dimension %d of array '%s' "
+                           "outside of expected range (%%ld:%%ld)", 
                            info->dim[n]+1, ss->expr->symtree->name);
-                 gfc_trans_runtime_check (true, false, tmp, &inner,
-                       &ss->expr->where, msg,
-                       fold_convert (long_integer_type_node, tmp2),
-                       fold_convert (long_integer_type_node, ubound));
+                 gfc_trans_runtime_check (true, false, tmp2, &inner,
+                                          &ss->expr->where, msg,
+                    fold_convert (long_integer_type_node, tmp),
+                    fold_convert (long_integer_type_node, ubound), 
+                    fold_convert (long_integer_type_node, lbound));
+                 gfc_trans_runtime_check (true, false, tmp3, &inner,
+                                          &ss->expr->where, msg,
+                    fold_convert (long_integer_type_node, tmp),
+                    fold_convert (long_integer_type_node, ubound), 
+                    fold_convert (long_integer_type_node, lbound));
                  gfc_free (msg);
                }
-
+             else
+               {
+                 asprintf (&msg, "Index '%%ld' of dimension %d of array '%s' "
+                           "below lower bound of %%ld", 
+                           info->dim[n]+1, ss->expr->symtree->name);
+                 gfc_trans_runtime_check (true, false, tmp2, &inner,
+                                          &ss->expr->where, msg,
+                    fold_convert (long_integer_type_node, tmp),
+                    fold_convert (long_integer_type_node, lbound));
+                 gfc_free (msg);
+               }
+             
              /* Check the section sizes match.  */
              tmp = fold_build2 (MINUS_EXPR, gfc_array_index_type, end,
                                 info->start[n]);
@@ -3329,8 +3356,6 @@ gfc_conv_ss_startstride (gfc_loopinfo * loop)
                 others against this.  */
              if (size[n])
                {
-                 tree tmp3;
-
                  tmp3 = fold_build2 (NE_EXPR, boolean_type_node, tmp, size[n]);
                  asprintf (&msg, "%s, size mismatch for dimension %d "
                            "of array '%s' (%%ld/%%ld)", gfc_msg_bounds,
@@ -3432,13 +3457,9 @@ gfc_conv_resolve_dependencies (gfc_loopinfo * loop, gfc_ss * dest,
   gfc_ss *ss;
   gfc_ref *lref;
   gfc_ref *rref;
-  gfc_ref *aref;
   int nDepend = 0;
-  int temp_dim = 0;
 
   loop->temp_ss = NULL;
-  aref = dest->data.info.ref;
-  temp_dim = 0;
 
   for (ss = rss; ss != gfc_ss_terminator; ss = ss->next)
     {
@@ -3487,7 +3508,6 @@ gfc_conv_resolve_dependencies (gfc_loopinfo * loop, gfc_ss * dest,
                  if (depends[n])
                  loop->order[dim++] = n;
                }
-             temp_dim = dim;
              for (n = 0; n < loop->dimen; n++)
                {
                  if (! depends[n])
@@ -3530,12 +3550,10 @@ void
 gfc_conv_loop_setup (gfc_loopinfo * loop, locus * where)
 {
   int n;
-  int dim;
   gfc_ss_info *info;
   gfc_ss_info *specinfo;
   gfc_ss *ss;
   tree tmp;
-  tree len;
   gfc_ss *loopspec[GFC_MAX_DIMENSIONS];
   bool dynamic[GFC_MAX_DIMENSIONS];
   gfc_constructor *c;
@@ -3716,7 +3734,6 @@ gfc_conv_loop_setup (gfc_loopinfo * loop, locus * where)
                         loop->temp_ss->string_length);
 
       tmp = loop->temp_ss->data.temp.type;
-      len = loop->temp_ss->string_length;
       n = loop->temp_ss->data.temp.dimen;
       memset (&loop->temp_ss->data.info, 0, sizeof (gfc_ss_info));
       loop->temp_ss->type = GFC_SS_SECTION;
@@ -3748,8 +3765,6 @@ gfc_conv_loop_setup (gfc_loopinfo * loop, locus * where)
 
       for (n = 0; n < info->dimen; n++)
        {
-         dim = info->dim[n];
-
          /* If we are specifying the range the delta is already set.  */
          if (loopspec[n] != ss)
            {
@@ -4001,9 +4016,9 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree pstat)
   gfc_conv_descriptor_offset_set (&se->pre, se->expr, offset);
 
   if (expr->ts.type == BT_DERIVED
-       && expr->ts.derived->attr.alloc_comp)
+       && expr->ts.u.derived->attr.alloc_comp)
     {
-      tmp = gfc_nullify_alloc_comp (expr->ts.derived, se->expr,
+      tmp = gfc_nullify_alloc_comp (expr->ts.u.derived, se->expr,
                                    ref->u.ar.as->rank);
       gfc_add_expr_to_block (&se->pre, tmp);
     }
@@ -4094,11 +4109,11 @@ gfc_conv_array_initializer (tree type, gfc_expr * expr)
             {
               /* Problems occur when we get something like
                  integer :: a(lots) = (/(i, i=1, lots)/)  */
-              gfc_error_now ("The number of elements in the array constructor "
-                            "at %L requires an increase of the allowed %d "
-                            "upper limit.   See -fmax-array-constructor "
-                            "option", &expr->where,
-                            gfc_option.flag_max_array_constructor);
+              gfc_fatal_error ("The number of elements in the array constructor "
+                              "at %L requires an increase of the allowed %d "
+                              "upper limit.   See -fmax-array-constructor "
+                              "option", &expr->where,
+                              gfc_option.flag_max_array_constructor);
              return NULL_TREE;
            }
           if (mpz_cmp_si (c->n.offset, 0) != 0)
@@ -4289,9 +4304,9 @@ gfc_trans_auto_array_allocation (tree decl, gfc_symbol * sym, tree fnbody)
 
   /* Evaluate character string length.  */
   if (sym->ts.type == BT_CHARACTER
-      && onstack && !INTEGER_CST_P (sym->ts.cl->backend_decl))
+      && onstack && !INTEGER_CST_P (sym->ts.u.cl->backend_decl))
     {
-      gfc_conv_string_length (sym->ts.cl, NULL, &block);
+      gfc_conv_string_length (sym->ts.u.cl, NULL, &block);
 
       gfc_trans_vla_type_sizes (sym, &block);
 
@@ -4314,8 +4329,8 @@ gfc_trans_auto_array_allocation (tree decl, gfc_symbol * sym, tree fnbody)
   gcc_assert (!sym->module);
 
   if (sym->ts.type == BT_CHARACTER
-      && !INTEGER_CST_P (sym->ts.cl->backend_decl))
-    gfc_conv_string_length (sym->ts.cl, NULL, &block);
+      && !INTEGER_CST_P (sym->ts.u.cl->backend_decl))
+    gfc_conv_string_length (sym->ts.u.cl, NULL, &block);
 
   size = gfc_trans_array_bounds (type, sym, &offset, &block);
 
@@ -4380,8 +4395,8 @@ gfc_trans_g77_array (gfc_symbol * sym, tree body)
   gfc_start_block (&block);
 
   if (sym->ts.type == BT_CHARACTER
-      && TREE_CODE (sym->ts.cl->backend_decl) == VAR_DECL)
-    gfc_conv_string_length (sym->ts.cl, NULL, &block);
+      && TREE_CODE (sym->ts.u.cl->backend_decl) == VAR_DECL)
+    gfc_conv_string_length (sym->ts.u.cl, NULL, &block);
 
   /* Evaluate the bounds of the array.  */
   gfc_trans_array_bounds (type, sym, &offset, &block);
@@ -4473,8 +4488,8 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, tree body)
   gfc_start_block (&block);
 
   if (sym->ts.type == BT_CHARACTER
-      && TREE_CODE (sym->ts.cl->backend_decl) == VAR_DECL)
-    gfc_conv_string_length (sym->ts.cl, NULL, &block);
+      && TREE_CODE (sym->ts.u.cl->backend_decl) == VAR_DECL)
+    gfc_conv_string_length (sym->ts.u.cl, NULL, &block);
 
   checkparm = (sym->as->type == AS_EXPLICIT
               && (gfc_option.rtcheck & GFC_RTCHECK_BOUNDS));
@@ -4866,11 +4881,11 @@ get_array_charlen (gfc_expr *expr, gfc_se *se)
   gfc_actual_arglist *arg;
   gfc_se tse;
 
-  if (expr->ts.cl->length
-       && gfc_is_constant_expr (expr->ts.cl->length))
+  if (expr->ts.u.cl->length
+       && gfc_is_constant_expr (expr->ts.u.cl->length))
     {
-      if (!expr->ts.cl->backend_decl)
-       gfc_conv_string_length (expr->ts.cl, expr, &se->pre);
+      if (!expr->ts.u.cl->backend_decl)
+       gfc_conv_string_length (expr->ts.u.cl, expr, &se->pre);
       return;
     }
 
@@ -4879,11 +4894,11 @@ get_array_charlen (gfc_expr *expr, gfc_se *se)
     case EXPR_OP:
       get_array_charlen (expr->value.op.op1, se);
 
-      /* For parentheses the expression ts.cl is identical.  */
+      /* For parentheses the expression ts.u.cl is identical.  */
       if (expr->value.op.op == INTRINSIC_PARENTHESES)
        return;
 
-     expr->ts.cl->backend_decl =
+     expr->ts.u.cl->backend_decl =
                gfc_create_var (gfc_charlen_type_node, "sln");
 
       if (expr->value.op.op2)
@@ -4894,21 +4909,21 @@ get_array_charlen (gfc_expr *expr, gfc_se *se)
 
          /* Add the string lengths and assign them to the expression
             string length backend declaration.  */
-         gfc_add_modify (&se->pre, expr->ts.cl->backend_decl,
+         gfc_add_modify (&se->pre, expr->ts.u.cl->backend_decl,
                          fold_build2 (PLUS_EXPR, gfc_charlen_type_node,
-                               expr->value.op.op1->ts.cl->backend_decl,
-                               expr->value.op.op2->ts.cl->backend_decl));
+                               expr->value.op.op1->ts.u.cl->backend_decl,
+                               expr->value.op.op2->ts.u.cl->backend_decl));
        }
       else
-       gfc_add_modify (&se->pre, expr->ts.cl->backend_decl,
-                       expr->value.op.op1->ts.cl->backend_decl);
+       gfc_add_modify (&se->pre, expr->ts.u.cl->backend_decl,
+                       expr->value.op.op1->ts.u.cl->backend_decl);
       break;
 
     case EXPR_FUNCTION:
       if (expr->value.function.esym == NULL
-           || expr->ts.cl->length->expr_type == EXPR_CONSTANT)
+           || expr->ts.u.cl->length->expr_type == EXPR_CONSTANT)
        {
-         gfc_conv_string_length (expr->ts.cl, expr, &se->pre);
+         gfc_conv_string_length (expr->ts.u.cl, expr, &se->pre);
          break;
        }
 
@@ -4931,19 +4946,19 @@ get_array_charlen (gfc_expr *expr, gfc_se *se)
       gfc_init_se (&tse, NULL);
 
       /* Build the expression for the character length and convert it.  */
-      gfc_apply_interface_mapping (&mapping, &tse, expr->ts.cl->length);
+      gfc_apply_interface_mapping (&mapping, &tse, expr->ts.u.cl->length);
 
       gfc_add_block_to_block (&se->pre, &tse.pre);
       gfc_add_block_to_block (&se->post, &tse.post);
       tse.expr = fold_convert (gfc_charlen_type_node, tse.expr);
       tse.expr = fold_build2 (MAX_EXPR, gfc_charlen_type_node, tse.expr,
                              build_int_cst (gfc_charlen_type_node, 0));
-      expr->ts.cl->backend_decl = tse.expr;
+      expr->ts.u.cl->backend_decl = tse.expr;
       gfc_free_interface_mapping (&mapping);
       break;
 
     default:
-      gfc_conv_string_length (expr->ts.cl, expr, &se->pre);
+      gfc_conv_string_length (expr->ts.u.cl, expr, &se->pre);
       break;
     }
 }
@@ -5084,7 +5099,7 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
          /* Elemental function.  */
          need_tmp = 1;
          if (expr->ts.type == BT_CHARACTER
-               && expr->ts.cl->length->expr_type != EXPR_CONSTANT)
+               && expr->ts.u.cl->length->expr_type != EXPR_CONSTANT)
            get_array_charlen (expr, se);
 
          info = NULL;
@@ -5146,13 +5161,13 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
       loop.temp_ss->next = gfc_ss_terminator;
 
       if (expr->ts.type == BT_CHARACTER
-           && !expr->ts.cl->backend_decl)
+           && !expr->ts.u.cl->backend_decl)
        get_array_charlen (expr, se);
 
       loop.temp_ss->data.temp.type = gfc_typenode_for_spec (&expr->ts);
 
       if (expr->ts.type == BT_CHARACTER)
-       loop.temp_ss->string_length = expr->ts.cl->backend_decl;
+       loop.temp_ss->string_length = expr->ts.u.cl->backend_decl;
       else
        loop.temp_ss->string_length = NULL;
 
@@ -5249,7 +5264,7 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
          parmtype = gfc_get_element_type (TREE_TYPE (desc));
          parmtype = gfc_get_array_type_bounds (parmtype, loop.dimen,
                                                loop.from, loop.to, 0,
-                                               GFC_ARRAY_UNKNOWN);
+                                               GFC_ARRAY_UNKNOWN, false);
          parm = gfc_create_var (parmtype, "parm");
        }
 
@@ -5444,7 +5459,7 @@ array_parameter_size (tree desc, gfc_expr *expr, tree *size)
 /* TODO: Optimize passing g77 arrays.  */
 
 void
-gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, gfc_ss * ss, int g77,
+gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, gfc_ss * ss, bool g77,
                          const gfc_symbol *fsym, const char *proc_name,
                          tree *size)
 {
@@ -5453,22 +5468,33 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, gfc_ss * ss, int g77,
   tree tmp = NULL_TREE;
   tree stmt;
   tree parent = DECL_CONTEXT (current_function_decl);
-  bool full_array_var, this_array_result;
+  bool full_array_var;
+  bool this_array_result;
+  bool contiguous;
+  bool no_pack;
   gfc_symbol *sym;
   stmtblock_t block;
+  gfc_ref *ref;
+
+  for (ref = expr->ref; ref; ref = ref->next)
+    if (ref->next == NULL)
+      break;
+
+  full_array_var = false;
+  contiguous = false;
+
+  if (expr->expr_type == EXPR_VARIABLE && ref)
+    full_array_var = gfc_full_array_ref_p (ref, &contiguous);
 
-  full_array_var = (expr->expr_type == EXPR_VARIABLE
-                   && expr->ref->type == REF_ARRAY
-                   && expr->ref->u.ar.type == AR_FULL);
   sym = full_array_var ? expr->symtree->n.sym : NULL;
 
   /* The symbol should have an array specification.  */
-  gcc_assert (!sym || sym->as);
+  gcc_assert (!sym || sym->as || ref->u.ar.as);
 
   if (expr->expr_type == EXPR_ARRAY && expr->ts.type == BT_CHARACTER)
     {
       get_array_ctor_strlen (&se->pre, expr->value.constructor, &tmp);
-      expr->ts.cl->backend_decl = tmp;
+      expr->ts.u.cl->backend_decl = tmp;
       se->string_length = tmp;
     }
 
@@ -5485,9 +5511,19 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, gfc_ss * ss, int g77,
       tmp = gfc_get_symbol_decl (sym);
 
       if (sym->ts.type == BT_CHARACTER)
-       se->string_length = sym->ts.cl->backend_decl;
-      if (!sym->attr.pointer && sym->as->type != AS_ASSUMED_SHAPE 
-          && !sym->attr.allocatable)
+       se->string_length = sym->ts.u.cl->backend_decl;
+
+      if (sym->ts.type == BT_DERIVED && !sym->as)
+       {
+         gfc_conv_expr_descriptor (se, expr, ss);
+         se->expr = gfc_conv_array_data (se->expr);
+         return;
+       }
+
+      if (!sym->attr.pointer
+           && sym->as
+           && sym->as->type != AS_ASSUMED_SHAPE 
+            && !sym->attr.allocatable)
         {
          /* Some variables are declared directly, others are declared as
             pointers and allocated on the heap.  */
@@ -5499,6 +5535,7 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, gfc_ss * ss, int g77,
            array_parameter_size (tmp, expr, size);
          return;
         }
+
       if (sym->attr.allocatable)
         {
          if (sym->attr.dummy || sym->attr.result)
@@ -5513,6 +5550,42 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, gfc_ss * ss, int g77,
         }
     }
 
+  /* There is no need to pack and unpack the array, if it is an array
+     constructor or contiguous and not deferred or assumed shape.  */
+  no_pack = ((sym && sym->as
+                 && !sym->attr.pointer
+                 && sym->as->type != AS_DEFERRED
+                 && sym->as->type != AS_ASSUMED_SHAPE)
+                     ||
+            (ref && ref->u.ar.as
+                 && ref->u.ar.as->type != AS_DEFERRED
+                 && ref->u.ar.as->type != AS_ASSUMED_SHAPE));
+
+  no_pack = g77 && !this_array_result
+               && (expr->expr_type == EXPR_ARRAY || (contiguous && no_pack));
+
+  if (no_pack)
+    {
+      gfc_conv_expr_descriptor (se, expr, ss);
+      if (expr->ts.type == BT_CHARACTER)
+       se->string_length = expr->ts.u.cl->backend_decl;
+      if (size)
+       array_parameter_size (se->expr, expr, size);
+      se->expr = gfc_conv_array_data (se->expr);
+      return;
+    }
+
+  if (expr->expr_type == EXPR_ARRAY && g77)
+    {
+      gfc_conv_expr_descriptor (se, expr, ss);
+      if (expr->ts.type == BT_CHARACTER)
+       se->string_length = expr->ts.u.cl->backend_decl;
+      if (size)
+       array_parameter_size (se->expr, expr, size);
+      se->expr = gfc_conv_array_data (se->expr);
+      return;
+    }
+
   if (this_array_result)
     {
       /* Result of the enclosing function.  */
@@ -5542,12 +5615,12 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, gfc_ss * ss, int g77,
   /* Deallocate the allocatable components of structures that are
      not variable.  */
   if (expr->ts.type == BT_DERIVED
-       && expr->ts.derived->attr.alloc_comp
+       && expr->ts.u.derived->attr.alloc_comp
        && expr->expr_type != EXPR_VARIABLE)
     {
       tmp = build_fold_indirect_ref_loc (input_location,
                                     se->expr);
-      tmp = gfc_deallocate_alloc_comp (expr->ts.derived, tmp, expr->rank);
+      tmp = gfc_deallocate_alloc_comp (expr->ts.u.derived, tmp, expr->rank);
       gfc_add_expr_to_block (&se->post, tmp);
     }
 
@@ -5555,7 +5628,6 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, gfc_ss * ss, int g77,
     {
       desc = se->expr;
       /* Repack the array.  */
-
       if (gfc_option.warn_array_temp)
        {
          if (fsym)
@@ -5696,10 +5768,12 @@ get_full_array_size (stmtblock_t *block, tree decl, int rank)
 }
 
 
-/* Allocate dest to the same size as src, and copy src -> dest.  */
+/* Allocate dest to the same size as src, and copy src -> dest.
+   If no_malloc is set, only the copy is done.  */
 
-tree
-gfc_duplicate_allocatable(tree dest, tree src, tree type, int rank)
+static tree
+duplicate_allocatable(tree dest, tree src, tree type, int rank,
+                     bool no_malloc)
 {
   tree tmp;
   tree size;
@@ -5708,35 +5782,66 @@ gfc_duplicate_allocatable(tree dest, tree src, tree type, int rank)
   tree null_data;
   stmtblock_t block;
 
-  /* If the source is null, set the destination to null.  */
+  /* If the source is null, set the destination to null.  Then,
+     allocate memory to the destination.  */
   gfc_init_block (&block);
-  gfc_conv_descriptor_data_set (&block, dest, null_pointer_node);
-  null_data = gfc_finish_block (&block);
 
-  gfc_init_block (&block);
+  if (rank == 0)
+    {
+      tmp = null_pointer_node;
+      tmp = fold_build2 (MODIFY_EXPR, type, dest, tmp);
+      gfc_add_expr_to_block (&block, tmp);
+      null_data = gfc_finish_block (&block);
+
+      gfc_init_block (&block);
+      size = TYPE_SIZE_UNIT (type);
+      if (!no_malloc)
+       {
+         tmp = gfc_call_malloc (&block, type, size);
+         tmp = fold_build2 (MODIFY_EXPR, void_type_node, dest,
+                            fold_convert (type, tmp));
+         gfc_add_expr_to_block (&block, tmp);
+       }
+
+      tmp = built_in_decls[BUILT_IN_MEMCPY];
+      tmp = build_call_expr_loc (input_location, tmp, 3,
+                                dest, src, size);
+    }
+  else
+    {
+      gfc_conv_descriptor_data_set (&block, dest, null_pointer_node);
+      null_data = gfc_finish_block (&block);
+
+      gfc_init_block (&block);
+      nelems = get_full_array_size (&block, src, rank);
+      tmp = fold_convert (gfc_array_index_type,
+                         TYPE_SIZE_UNIT (gfc_get_element_type (type)));
+      size = fold_build2 (MULT_EXPR, gfc_array_index_type, nelems, tmp);
+      if (!no_malloc)
+       {
+         tmp = TREE_TYPE (gfc_conv_descriptor_data_get (src));
+         tmp = gfc_call_malloc (&block, tmp, size);
+         gfc_conv_descriptor_data_set (&block, dest, tmp);
+       }
+
+      /* We know the temporary and the value will be the same length,
+        so can use memcpy.  */
+      tmp = built_in_decls[BUILT_IN_MEMCPY];
+      tmp = build_call_expr_loc (input_location,
+                       tmp, 3, gfc_conv_descriptor_data_get (dest),
+                       gfc_conv_descriptor_data_get (src), size);
+    }
 
-  nelems = get_full_array_size (&block, src, rank);
-  size = fold_build2 (MULT_EXPR, gfc_array_index_type, nelems,
-                     fold_convert (gfc_array_index_type,
-                                   TYPE_SIZE_UNIT (gfc_get_element_type (type))));
-
-  /* Allocate memory to the destination.  */
-  tmp = gfc_call_malloc (&block, TREE_TYPE (gfc_conv_descriptor_data_get (src)),
-                        size);
-  gfc_conv_descriptor_data_set (&block, dest, tmp);
-
-  /* We know the temporary and the value will be the same length,
-     so can use memcpy.  */
-  tmp = built_in_decls[BUILT_IN_MEMCPY];
-  tmp = build_call_expr_loc (input_location,
-                        tmp, 3, gfc_conv_descriptor_data_get (dest),
-                        gfc_conv_descriptor_data_get (src), size);
   gfc_add_expr_to_block (&block, tmp);
   tmp = gfc_finish_block (&block);
 
   /* Null the destination if the source is null; otherwise do
      the allocate and copy.  */
-  null_cond = gfc_conv_descriptor_data_get (src);
+  if (rank == 0)
+    null_cond = src;
+  else
+    null_cond = gfc_conv_descriptor_data_get (src);
+
   null_cond = convert (pvoid_type_node, null_cond);
   null_cond = fold_build2 (NE_EXPR, boolean_type_node,
                           null_cond, null_pointer_node);
@@ -5744,11 +5849,30 @@ gfc_duplicate_allocatable(tree dest, tree src, tree type, int rank)
 }
 
 
+/* Allocate dest to the same size as src, and copy data src -> dest.  */
+
+tree
+gfc_duplicate_allocatable (tree dest, tree src, tree type, int rank)
+{
+  return duplicate_allocatable(dest, src, type, rank, false);
+}
+
+
+/* Copy data src -> dest.  */
+
+tree
+gfc_copy_allocatable_data (tree dest, tree src, tree type, int rank)
+{
+  return duplicate_allocatable(dest, src, type, rank, true);
+}
+
+
 /* Recursively traverse an object of derived type, generating code to
    deallocate, nullify or copy allocatable components.  This is the work horse
    function for the functions named in this enum.  */
 
-enum {DEALLOCATE_ALLOC_COMP = 1, NULLIFY_ALLOC_COMP, COPY_ALLOC_COMP};
+enum {DEALLOCATE_ALLOC_COMP = 1, NULLIFY_ALLOC_COMP, COPY_ALLOC_COMP,
+      COPY_ONLY_ALLOC_COMP};
 
 static tree
 structure_alloc_comps (gfc_symbol * der_type, tree decl,
@@ -5771,7 +5895,7 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl,
 
   gfc_init_block (&fnblock);
 
-  if (POINTER_TYPE_P (TREE_TYPE (decl)))
+  if (POINTER_TYPE_P (TREE_TYPE (decl)) && rank != 0)
     decl = build_fold_indirect_ref_loc (input_location,
                                    decl);
 
@@ -5826,6 +5950,14 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl,
          dref = gfc_build_array_ref (tmp, index, NULL);
          tmp = structure_alloc_comps (der_type, vref, dref, rank, purpose);
        }
+      else if (purpose == COPY_ONLY_ALLOC_COMP)
+        {
+         tmp = build_fold_indirect_ref_loc (input_location,
+                                        gfc_conv_array_data (dest));
+         dref = gfc_build_array_ref (tmp, index, NULL);
+         tmp = structure_alloc_comps (der_type, vref, dref, rank,
+                                      COPY_ALLOC_COMP);
+       }
       else
         tmp = structure_alloc_comps (der_type, vref, NULL_TREE, rank, purpose);
 
@@ -5853,7 +5985,7 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl,
   for (c = der_type->components; c; c = c->next)
     {
       bool cmp_has_alloc_comps = (c->ts.type == BT_DERIVED)
-                                   && c->ts.derived->attr.alloc_comp;
+                                   && c->ts.u.derived->attr.alloc_comp;
       cdecl = c->backend_decl;
       ctype = TREE_TYPE (cdecl);
 
@@ -5867,35 +5999,86 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl,
              comp = fold_build3 (COMPONENT_REF, ctype,
                                  decl, cdecl, NULL_TREE);
              rank = c->as ? c->as->rank : 0;
-             tmp = structure_alloc_comps (c->ts.derived, comp, NULL_TREE,
+             tmp = structure_alloc_comps (c->ts.u.derived, comp, NULL_TREE,
                                           rank, purpose);
              gfc_add_expr_to_block (&fnblock, tmp);
            }
 
-         if (c->attr.allocatable)
+         if (c->attr.allocatable && c->attr.dimension)
            {
              comp = fold_build3 (COMPONENT_REF, ctype,
                                  decl, cdecl, NULL_TREE);
              tmp = gfc_trans_dealloc_allocated (comp);
              gfc_add_expr_to_block (&fnblock, tmp);
            }
+         else if (c->attr.allocatable)
+           {
+             /* Allocatable scalar components.  */
+             comp = fold_build3 (COMPONENT_REF, ctype, decl, cdecl, NULL_TREE);
+
+             tmp = gfc_deallocate_with_status (comp, NULL_TREE, true, NULL);
+             gfc_add_expr_to_block (&fnblock, tmp);
+
+             tmp = fold_build2 (MODIFY_EXPR, void_type_node, comp,
+                                build_int_cst (TREE_TYPE (comp), 0));
+             gfc_add_expr_to_block (&fnblock, tmp);
+           }
+         else if (c->ts.type == BT_CLASS
+                  && c->ts.u.derived->components->attr.allocatable)
+           {
+             /* Allocatable scalar CLASS components.  */
+             comp = fold_build3 (COMPONENT_REF, ctype, decl, cdecl, NULL_TREE);
+             
+             /* Add reference to '$data' component.  */
+             tmp = c->ts.u.derived->components->backend_decl;
+             comp = fold_build3 (COMPONENT_REF, TREE_TYPE (tmp),
+                                 comp, tmp, NULL_TREE);
+
+             tmp = gfc_deallocate_with_status (comp, NULL_TREE, true, NULL);
+             gfc_add_expr_to_block (&fnblock, tmp);
+
+             tmp = fold_build2 (MODIFY_EXPR, void_type_node, comp,
+                                build_int_cst (TREE_TYPE (comp), 0));
+             gfc_add_expr_to_block (&fnblock, tmp);
+           }
          break;
 
        case NULLIFY_ALLOC_COMP:
          if (c->attr.pointer)
            continue;
-         else if (c->attr.allocatable)
+         else if (c->attr.allocatable && c->attr.dimension)
            {
              comp = fold_build3 (COMPONENT_REF, ctype,
                                  decl, cdecl, NULL_TREE);
              gfc_conv_descriptor_data_set (&fnblock, comp, null_pointer_node);
            }
+         else if (c->attr.allocatable)
+           {
+             /* Allocatable scalar components.  */
+             comp = fold_build3 (COMPONENT_REF, ctype, decl, cdecl, NULL_TREE);
+             tmp = fold_build2 (MODIFY_EXPR, void_type_node, comp,
+                                build_int_cst (TREE_TYPE (comp), 0));
+             gfc_add_expr_to_block (&fnblock, tmp);
+           }
+         else if (c->ts.type == BT_CLASS
+                  && c->ts.u.derived->components->attr.allocatable)
+           {
+             /* Allocatable scalar CLASS components.  */
+             comp = fold_build3 (COMPONENT_REF, ctype, decl, cdecl, NULL_TREE);
+             /* Add reference to '$data' component.  */
+             tmp = c->ts.u.derived->components->backend_decl;
+             comp = fold_build3 (COMPONENT_REF, TREE_TYPE (tmp),
+                                 comp, tmp, NULL_TREE);
+             tmp = fold_build2 (MODIFY_EXPR, void_type_node, comp,
+                                build_int_cst (TREE_TYPE (comp), 0));
+             gfc_add_expr_to_block (&fnblock, tmp);
+           }
           else if (cmp_has_alloc_comps)
            {
              comp = fold_build3 (COMPONENT_REF, ctype,
                                  decl, cdecl, NULL_TREE);
              rank = c->as ? c->as->rank : 0;
-             tmp = structure_alloc_comps (c->ts.derived, comp, NULL_TREE,
+             tmp = structure_alloc_comps (c->ts.u.derived, comp, NULL_TREE,
                                           rank, purpose);
              gfc_add_expr_to_block (&fnblock, tmp);
            }
@@ -5912,7 +6095,8 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl,
 
          if (c->attr.allocatable && !cmp_has_alloc_comps)
            {
-             tmp = gfc_duplicate_allocatable(dcmp, comp, ctype, c->as->rank);
+             rank = c->as ? c->as->rank : 0;
+             tmp = gfc_duplicate_allocatable(dcmp, comp, ctype, rank);
              gfc_add_expr_to_block (&fnblock, tmp);
            }
 
@@ -5921,7 +6105,7 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl,
              rank = c->as ? c->as->rank : 0;
              tmp = fold_convert (TREE_TYPE (dcmp), comp);
              gfc_add_modify (&fnblock, dcmp, tmp);
-             tmp = structure_alloc_comps (c->ts.derived, comp, dcmp,
+             tmp = structure_alloc_comps (c->ts.u.derived, comp, dcmp,
                                           rank, purpose);
              gfc_add_expr_to_block (&fnblock, tmp);
            }
@@ -5959,7 +6143,7 @@ gfc_deallocate_alloc_comp (gfc_symbol * der_type, tree decl, int rank)
 
 
 /* Recursively traverse an object of derived type, generating code to
-   copy its allocatable components.  */
+   copy it and its allocatable components.  */
 
 tree
 gfc_copy_alloc_comp (gfc_symbol * der_type, tree decl, tree dest, int rank)
@@ -5968,6 +6152,16 @@ gfc_copy_alloc_comp (gfc_symbol * der_type, tree decl, tree dest, int rank)
 }
 
 
+/* Recursively traverse an object of derived type, generating code to
+   copy only its allocatable components.  */
+
+tree
+gfc_copy_only_alloc_comp (gfc_symbol * der_type, tree decl, tree dest, int rank)
+{
+  return structure_alloc_comps (der_type, decl, dest, rank, COPY_ONLY_ALLOC_COMP);
+}
+
+
 /* NULLIFY an allocatable/pointer array on function entry, free it on exit.
    Do likewise, recursively if necessary, with the allocatable components of
    derived types.  */
@@ -5984,7 +6178,7 @@ gfc_trans_deferred_array (gfc_symbol * sym, tree body)
   bool sym_has_alloc_comp;
 
   sym_has_alloc_comp = (sym->ts.type == BT_DERIVED)
-                         && sym->ts.derived->attr.alloc_comp;
+                         && sym->ts.u.derived->attr.alloc_comp;
 
   /* Make sure the frontend gets these right.  */
   if (!(sym->attr.pointer || sym->attr.allocatable || sym_has_alloc_comp))
@@ -5998,9 +6192,9 @@ gfc_trans_deferred_array (gfc_symbol * sym, tree body)
                || TREE_CODE (sym->backend_decl) == PARM_DECL);
 
   if (sym->ts.type == BT_CHARACTER
-      && !INTEGER_CST_P (sym->ts.cl->backend_decl))
+      && !INTEGER_CST_P (sym->ts.u.cl->backend_decl))
     {
-      gfc_conv_string_length (sym->ts.cl, NULL, &fnblock);
+      gfc_conv_string_length (sym->ts.u.cl, NULL, &fnblock);
       gfc_trans_vla_type_sizes (sym, &fnblock);
     }
 
@@ -6034,7 +6228,7 @@ gfc_trans_deferred_array (gfc_symbol * sym, tree body)
       if (!sym->attr.save)
        {
          rank = sym->as ? sym->as->rank : 0;
-         tmp = gfc_nullify_alloc_comp (sym->ts.derived, descriptor, rank);
+         tmp = gfc_nullify_alloc_comp (sym->ts.u.derived, descriptor, rank);
          gfc_add_expr_to_block (&fnblock, tmp);
          if (sym->value)
            {
@@ -6067,11 +6261,12 @@ gfc_trans_deferred_array (gfc_symbol * sym, tree body)
     {
       int rank;
       rank = sym->as ? sym->as->rank : 0;
-      tmp = gfc_deallocate_alloc_comp (sym->ts.derived, descriptor, rank);
+      tmp = gfc_deallocate_alloc_comp (sym->ts.u.derived, descriptor, rank);
       gfc_add_expr_to_block (&fnblock, tmp);
     }
 
-  if (sym->attr.allocatable && !sym->attr.save && !sym->attr.result)
+  if (sym->attr.allocatable && sym->attr.dimension
+      && !sym->attr.save && !sym->attr.result)
     {
       tmp = gfc_trans_dealloc_allocated (sym->backend_decl);
       gfc_add_expr_to_block (&fnblock, tmp);
@@ -6101,7 +6296,6 @@ gfc_walk_variable_expr (gfc_ss * ss, gfc_expr * expr)
   gfc_ref *ref;
   gfc_array_ref *ar;
   gfc_ss *newss;
-  gfc_ss *head;
   int n;
 
   for (ref = expr->ref; ref; ref = ref->next)
@@ -6174,8 +6368,6 @@ gfc_walk_variable_expr (gfc_ss * ss, gfc_expr * expr)
          newss->data.info.dimen = 0;
          newss->data.info.ref = ref;
 
-         head = newss;
-
           /* We add SS chains for all the subscripts in the section.  */
          for (n = 0; n < ar->dimen; n++)
            {