OSDN Git Service

* trans-array.c (gfc_trans_array_constructor, trans_array_constructor):
[pf3gnuchains/gcc-fork.git] / gcc / fortran / trans-array.c
index f8e26b0..01a411a 100644 (file)
@@ -81,6 +81,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "tree.h"
+#include "gimple.h"
 #include "diagnostic-core.h"   /* For internal_error/fatal_error.  */
 #include "flags.h"
 #include "gfortran.h"
@@ -128,6 +129,7 @@ gfc_array_dataptr_type (tree desc)
 #define OFFSET_FIELD 1
 #define DTYPE_FIELD 2
 #define DIMENSION_FIELD 3
+#define CAF_TOKEN_FIELD 4
 
 #define STRIDE_SUBFIELD 0
 #define LBOUND_SUBFIELD 1
@@ -266,6 +268,25 @@ gfc_conv_descriptor_dimension (tree desc, tree dim)
   return tmp;
 }
 
+
+tree
+gfc_conv_descriptor_token (tree desc)
+{
+  tree type;
+  tree field;
+
+  type = TREE_TYPE (desc);
+  gcc_assert (GFC_DESCRIPTOR_TYPE_P (type));
+  gcc_assert (GFC_TYPE_ARRAY_AKIND (type) == GFC_ARRAY_ALLOCATABLE);
+  gcc_assert (gfc_option.coarray == GFC_FCOARRAY_LIB);
+  field = gfc_advance_chain (TYPE_FIELDS (type), CAF_TOKEN_FIELD);
+  gcc_assert (field != NULL_TREE && TREE_TYPE (field) == prvoid_type_node);
+
+  return fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
+                         desc, field, NULL_TREE);
+}
+
+
 static tree
 gfc_conv_descriptor_stride (tree desc, tree dim)
 {
@@ -428,6 +449,7 @@ gfc_conv_shift_descriptor_lbound (stmtblock_t* block, tree desc,
 #undef OFFSET_FIELD
 #undef DTYPE_FIELD
 #undef DIMENSION_FIELD
+#undef CAF_TOKEN_FIELD
 #undef STRIDE_SUBFIELD
 #undef LBOUND_SUBFIELD
 #undef UBOUND_SUBFIELD
@@ -441,7 +463,7 @@ void
 gfc_mark_ss_chain_used (gfc_ss * ss, unsigned flags)
 {
   for (; ss != gfc_ss_terminator; ss = ss->next)
-    ss->useflags = flags;
+    ss->info->useflags = flags;
 }
 
 static void gfc_free_ss (gfc_ss *);
@@ -464,20 +486,35 @@ gfc_free_ss_chain (gfc_ss * ss)
 }
 
 
+static void
+free_ss_info (gfc_ss_info *ss_info)
+{
+  ss_info->refcount--;
+  if (ss_info->refcount > 0)
+    return;
+
+  gcc_assert (ss_info->refcount == 0);
+  free (ss_info);
+}
+
+
 /* Free a SS.  */
 
 static void
 gfc_free_ss (gfc_ss * ss)
 {
+  gfc_ss_info *ss_info;
   int n;
 
-  switch (ss->type)
+  ss_info = ss->info;
+
+  switch (ss_info->type)
     {
     case GFC_SS_SECTION:
-      for (n = 0; n < ss->data.info.dimen; n++)
+      for (n = 0; n < ss->dimen; n++)
        {
-         if (ss->data.info.subscript[ss->data.info.dim[n]])
-           gfc_free_ss_chain (ss->data.info.subscript[ss->data.info.dim[n]]);
+         if (ss_info->data.array.subscript[ss->dim[n]])
+           gfc_free_ss_chain (ss_info->data.array.subscript[ss->dim[n]]);
        }
       break;
 
@@ -485,7 +522,80 @@ gfc_free_ss (gfc_ss * ss)
       break;
     }
 
-  gfc_free (ss);
+  free_ss_info (ss_info);
+  free (ss);
+}
+
+
+/* Creates and initializes an array type gfc_ss struct.  */
+
+gfc_ss *
+gfc_get_array_ss (gfc_ss *next, gfc_expr *expr, int dimen, gfc_ss_type type)
+{
+  gfc_ss *ss;
+  gfc_ss_info *ss_info;
+  int i;
+
+  ss_info = gfc_get_ss_info ();
+  ss_info->refcount++;
+  ss_info->type = type;
+  ss_info->expr = expr;
+
+  ss = gfc_get_ss ();
+  ss->info = ss_info;
+  ss->next = next;
+  ss->dimen = dimen;
+  for (i = 0; i < ss->dimen; i++)
+    ss->dim[i] = i;
+
+  return ss;
+}
+
+
+/* Creates and initializes a temporary type gfc_ss struct.  */
+
+gfc_ss *
+gfc_get_temp_ss (tree type, tree string_length, int dimen)
+{
+  gfc_ss *ss;
+  gfc_ss_info *ss_info;
+  int i;
+
+  ss_info = gfc_get_ss_info ();
+  ss_info->refcount++;
+  ss_info->type = GFC_SS_TEMP;
+  ss_info->string_length = string_length;
+  ss_info->data.temp.type = type;
+
+  ss = gfc_get_ss ();
+  ss->info = ss_info;
+  ss->next = gfc_ss_terminator;
+  ss->dimen = dimen;
+  for (i = 0; i < ss->dimen; i++)
+    ss->dim[i] = i;
+
+  return ss;
+}
+               
+
+/* Creates and initializes a scalar type gfc_ss struct.  */
+
+gfc_ss *
+gfc_get_scalar_ss (gfc_ss *next, gfc_expr *expr)
+{
+  gfc_ss *ss;
+  gfc_ss_info *ss_info;
+
+  ss_info = gfc_get_ss_info ();
+  ss_info->refcount++;
+  ss_info->type = GFC_SS_SCALAR;
+  ss_info->expr = expr;
+
+  ss = gfc_get_ss ();
+  ss->info = ss_info;
+  ss->next = next;
+
+  return ss;
 }
 
 
@@ -508,6 +618,27 @@ gfc_cleanup_loop (gfc_loopinfo * loop)
 }
 
 
+static void
+set_ss_loop (gfc_ss *ss, gfc_loopinfo *loop)
+{
+  int n;
+
+  for (; ss != gfc_ss_terminator; ss = ss->next)
+    {
+      ss->loop = loop;
+
+      if (ss->info->type == GFC_SS_SCALAR
+         || ss->info->type == GFC_SS_REFERENCE
+         || ss->info->type == GFC_SS_TEMP)
+       continue;
+
+      for (n = 0; n < GFC_MAX_DIMENSIONS; n++)
+       if (ss->info->data.array.subscript[n] != NULL)
+         set_ss_loop (ss->info->data.array.subscript[n], loop);
+    }
+}
+
+
 /* Associate a SS chain with a loop.  */
 
 void
@@ -518,6 +649,8 @@ gfc_add_ss_to_loop (gfc_loopinfo * loop, gfc_ss * head)
   if (head == gfc_ss_terminator)
     return;
 
+  set_ss_loop (head, loop);
+
   ss = head;
   for (; ss && ss != gfc_ss_terminator; ss = ss->next)
     {
@@ -562,9 +695,9 @@ gfc_set_loop_bounds_from_array_spec (gfc_interface_mapping * mapping,
   tree tmp;
 
   if (as && as->type == AS_EXPLICIT)
-    for (n = 0; n < se->loop->dimen + se->loop->codimen; n++)
+    for (n = 0; n < se->loop->dimen; n++)
       {
-       dim = se->ss->data.info.dim[n];
+       dim = se->ss->dim[n];
        gcc_assert (dim < as->rank);
        gcc_assert (se->loop->dimen == as->rank);
        if (se->loop->to[n] == NULL_TREE)
@@ -576,22 +709,18 @@ gfc_set_loop_bounds_from_array_spec (gfc_interface_mapping * mapping,
            gfc_add_block_to_block (&se->post, &tmpse.post);
            lower = fold_convert (gfc_array_index_type, tmpse.expr);
 
-           if (se->loop->codimen == 0
-               || n < se->loop->dimen + se->loop->codimen - 1)
-             {
-               /* ...and the upper bound.  */
-               gfc_init_se (&tmpse, NULL);
-               gfc_apply_interface_mapping (mapping, &tmpse, as->upper[dim]);
-               gfc_add_block_to_block (&se->pre, &tmpse.pre);
-               gfc_add_block_to_block (&se->post, &tmpse.post);
-               upper = fold_convert (gfc_array_index_type, tmpse.expr);
-
-               /* Set the upper bound of the loop to UPPER - LOWER.  */
-               tmp = fold_build2_loc (input_location, MINUS_EXPR,
-                                      gfc_array_index_type, upper, lower);
-               tmp = gfc_evaluate_now (tmp, &se->pre);
-               se->loop->to[n] = tmp;
-             }
+           /* ...and the upper bound.  */
+           gfc_init_se (&tmpse, NULL);
+           gfc_apply_interface_mapping (mapping, &tmpse, as->upper[dim]);
+           gfc_add_block_to_block (&se->pre, &tmpse.pre);
+           gfc_add_block_to_block (&se->post, &tmpse.post);
+           upper = fold_convert (gfc_array_index_type, tmpse.expr);
+
+           /* Set the upper bound of the loop to UPPER - LOWER.  */
+           tmp = fold_build2_loc (input_location, MINUS_EXPR,
+                                  gfc_array_index_type, upper, lower);
+           tmp = gfc_evaluate_now (tmp, &se->pre);
+           se->loop->to[n] = tmp;
          }
       }
 }
@@ -611,7 +740,7 @@ gfc_set_loop_bounds_from_array_spec (gfc_interface_mapping * mapping,
 
 static void
 gfc_trans_allocate_array_storage (stmtblock_t * pre, stmtblock_t * post,
-                                 gfc_ss_info * info, tree size, tree nelem,
+                                 gfc_array_info * info, tree size, tree nelem,
                                  tree initial, bool dynamic, bool dealloc)
 {
   tree tmp;
@@ -630,18 +759,27 @@ gfc_trans_allocate_array_storage (stmtblock_t * pre, stmtblock_t * post,
     {
       /* Allocate the temporary.  */
       onstack = !dynamic && initial == NULL_TREE
-                        && gfc_can_put_var_on_stack (size);
+                        && (gfc_option.flag_stack_arrays
+                            || gfc_can_put_var_on_stack (size));
 
       if (onstack)
        {
          /* Make a temporary variable to hold the data.  */
          tmp = fold_build2_loc (input_location, MINUS_EXPR, TREE_TYPE (nelem),
                                 nelem, gfc_index_one_node);
+         tmp = gfc_evaluate_now (tmp, pre);
          tmp = build_range_type (gfc_array_index_type, gfc_index_zero_node,
                                  tmp);
          tmp = build_array_type (gfc_get_element_type (TREE_TYPE (desc)),
                                  tmp);
          tmp = gfc_create_var (tmp, "A");
+         /* If we're here only because of -fstack-arrays we have to
+            emit a DECL_EXPR to make the gimplifier emit alloca calls.  */
+         if (!gfc_can_put_var_on_stack (size))
+           gfc_add_expr_to_block (pre,
+                                  fold_build1_loc (input_location,
+                                                   DECL_EXPR, TREE_TYPE (tmp),
+                                                   tmp));
          tmp = gfc_build_addr_expr (NULL_TREE, tmp);
          gfc_conv_descriptor_data_set (pre, desc, tmp);
        }
@@ -724,15 +862,15 @@ gfc_trans_allocate_array_storage (stmtblock_t * pre, stmtblock_t * post,
    */
 
 static int
-get_array_ref_dim (gfc_ss_info *info, int loop_dim)
+get_array_ref_dim (gfc_ss *ss, int loop_dim)
 {
   int n, array_dim, array_ref_dim;
 
   array_ref_dim = 0;
-  array_dim = info->dim[loop_dim];
+  array_dim = ss->dim[loop_dim];
 
-  for (n = 0; n < info->dimen; n++)
-    if (n != loop_dim && info->dim[n] < array_dim)
+  for (n = 0; n < ss->dimen; n++)
+    if (ss->dim[n] < array_dim)
       array_ref_dim++;
 
   return array_ref_dim;
@@ -755,10 +893,11 @@ get_array_ref_dim (gfc_ss_info *info, int loop_dim)
 
 tree
 gfc_trans_create_temp_array (stmtblock_t * pre, stmtblock_t * post,
-                            gfc_loopinfo * loop, gfc_ss_info * info,
+                            gfc_loopinfo * loop, gfc_ss * ss,
                             tree eltype, tree initial, bool dynamic,
                             bool dealloc, bool callee_alloc, locus * where)
 {
+  gfc_array_info *info;
   tree from[GFC_MAX_DIMENSIONS], to[GFC_MAX_DIMENSIONS];
   tree type;
   tree desc;
@@ -772,8 +911,10 @@ gfc_trans_create_temp_array (stmtblock_t * pre, stmtblock_t * post,
   memset (from, 0, sizeof (from));
   memset (to, 0, sizeof (to));
 
-  gcc_assert (info->dimen > 0);
-  gcc_assert (loop->dimen == info->dimen);
+  info = &ss->info->data.array;
+
+  gcc_assert (ss->dimen > 0);
+  gcc_assert (loop->dimen == ss->dimen);
 
   if (gfc_option.warn_array_temp && where)
     gfc_warning ("Creating array temporary at %L", where);
@@ -781,7 +922,7 @@ gfc_trans_create_temp_array (stmtblock_t * pre, stmtblock_t * post,
   /* Set the lower bound to zero.  */
   for (n = 0; n < loop->dimen; n++)
     {
-      dim = info->dim[n];
+      dim = ss->dim[n];
 
       /* Callee allocated arrays may not have a known bound yet.  */
       if (loop->to[n])
@@ -792,13 +933,18 @@ gfc_trans_create_temp_array (stmtblock_t * pre, stmtblock_t * post,
                        pre);
       loop->from[n] = gfc_index_zero_node;
 
+      /* We have just changed the loop bounds, we must clear the
+        corresponding specloop, so that delta calculation is not skipped
+        later in set_delta.  */
+      loop->specloop[n] = NULL;
+
       /* We are constructing the temporary's descriptor based on the loop
         dimensions. As the dimensions may be accessed in arbitrary order
         (think of transpose) the size taken from the n'th loop may not map
         to the n'th dimension of the array. We need to reconstruct loop infos
         in the right order before using it to set the descriptor
         bounds.  */
-      tmp_dim = get_array_ref_dim (info, n);
+      tmp_dim = get_array_ref_dim (ss, n);
       from[tmp_dim] = loop->from[n];
       to[tmp_dim] = loop->to[n];
 
@@ -810,7 +956,7 @@ gfc_trans_create_temp_array (stmtblock_t * pre, stmtblock_t * post,
 
   /* Initialize the descriptor.  */
   type =
-    gfc_get_array_type_bounds (eltype, info->dimen, 0, from, to, 1,
+    gfc_get_array_type_bounds (eltype, ss->dimen, 0, from, to, 1,
                               GFC_ARRAY_UNKNOWN, true);
   desc = gfc_create_var (type, "atmp");
   GFC_DECL_PACKED_ARRAY (desc) = 1;
@@ -846,12 +992,12 @@ gfc_trans_create_temp_array (stmtblock_t * pre, stmtblock_t * post,
        break;
       }
 
-  for (n = 0; n < loop->dimen; n++)
+  if (size == NULL_TREE)
     {
-      dim = info->dim[n];
-
-      if (size == NULL_TREE)
+      for (n = 0; n < loop->dimen; n++)
        {
+         dim = ss->dim[n];
+
          /* For a callee allocated array express the loop bounds in terms
             of the descriptor fields.  */
          tmp = fold_build2_loc (input_location,
@@ -859,46 +1005,42 @@ gfc_trans_create_temp_array (stmtblock_t * pre, stmtblock_t * post,
                gfc_conv_descriptor_ubound_get (desc, gfc_rank_cst[dim]),
                gfc_conv_descriptor_lbound_get (desc, gfc_rank_cst[dim]));
          loop->to[n] = tmp;
-         continue;
        }
-       
-      /* Store the stride and bound components in the descriptor.  */
-      gfc_conv_descriptor_stride_set (pre, desc, gfc_rank_cst[n], size);
+    }
+  else
+    {
+      for (n = 0; n < loop->dimen; n++)
+       {
+         /* Store the stride and bound components in the descriptor.  */
+         gfc_conv_descriptor_stride_set (pre, desc, gfc_rank_cst[n], size);
 
-      gfc_conv_descriptor_lbound_set (pre, desc, gfc_rank_cst[n],
-                                     gfc_index_zero_node);
+         gfc_conv_descriptor_lbound_set (pre, desc, gfc_rank_cst[n],
+                                         gfc_index_zero_node);
 
-      gfc_conv_descriptor_ubound_set (pre, desc, gfc_rank_cst[n],
-                                     to[n]);
+         gfc_conv_descriptor_ubound_set (pre, desc, gfc_rank_cst[n], to[n]);
 
-      tmp = fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type,
-                            to[n], gfc_index_one_node);
+         tmp = fold_build2_loc (input_location, PLUS_EXPR,
+                                gfc_array_index_type,
+                                to[n], gfc_index_one_node);
 
-      /* Check whether the size for this dimension is negative.  */
-      cond = fold_build2_loc (input_location, LE_EXPR, boolean_type_node, tmp,
-                             gfc_index_zero_node);
-      cond = gfc_evaluate_now (cond, pre);
+         /* Check whether the size for this dimension is negative.  */
+         cond = fold_build2_loc (input_location, LE_EXPR, boolean_type_node,
+                                 tmp, gfc_index_zero_node);
+         cond = gfc_evaluate_now (cond, pre);
 
-      if (n == 0)
-       or_expr = cond;
-      else
-       or_expr = fold_build2_loc (input_location, TRUTH_OR_EXPR,
-                                  boolean_type_node, or_expr, cond);
+         if (n == 0)
+           or_expr = cond;
+         else
+           or_expr = fold_build2_loc (input_location, TRUTH_OR_EXPR,
+                                      boolean_type_node, or_expr, cond);
 
-      size = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
-                             size, tmp);
-      size = gfc_evaluate_now (size, pre);
-    }
-  for (n = info->dimen; n < info->dimen + info->codimen; n++)
-    {
-      gfc_conv_descriptor_lbound_set (pre, desc, gfc_rank_cst[n],
-                                      gfc_index_zero_node);
-      if (n < info->dimen + info->codimen - 1)
-       gfc_conv_descriptor_ubound_set (pre, desc, gfc_rank_cst[n], loop->to[n]);
+         size = fold_build2_loc (input_location, MULT_EXPR,
+                                 gfc_array_index_type, size, tmp);
+         size = gfc_evaluate_now (size, pre);
+       }
     }
 
   /* Get the size of the array.  */
-
   if (size && !callee_alloc)
     {
       /* If or_expr is true, then the extent in at least one
@@ -921,8 +1063,8 @@ gfc_trans_create_temp_array (stmtblock_t * pre, stmtblock_t * post,
   gfc_trans_allocate_array_storage (pre, post, info, size, nelem, initial,
                                    dynamic, dealloc);
 
-  if (info->dimen > loop->temp_dim)
-    loop->temp_dim = info->dimen;
+  if (ss->dimen > loop->temp_dim)
+    loop->temp_dim = ss->dimen;
 
   return size;
 }
@@ -1354,7 +1496,7 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
                  p = gfc_constructor_next (p);
                }
 
-             bound = build_int_cst (NULL_TREE, n - 1);
+             bound = size_int (n - 1);
               /* Create an array type to hold them.  */
              tmptype = build_range_type (gfc_array_index_type,
                                          gfc_index_zero_node, bound);
@@ -1380,10 +1522,10 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
              init = gfc_build_addr_expr (NULL_TREE, init);
 
              size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type));
-             bound = build_int_cst (NULL_TREE, n * size);
+             bound = build_int_cst (size_type_node, n * size);
              tmp = build_call_expr_loc (input_location,
-                                    built_in_decls[BUILT_IN_MEMCPY], 3,
-                                    tmp, init, bound);
+                                        builtin_decl_explicit (BUILT_IN_MEMCPY),
+                                        3, tmp, init, bound);
              gfc_add_expr_to_block (&body, tmp);
 
              *poffset = fold_build2_loc (input_location, PLUS_EXPR,
@@ -1773,37 +1915,32 @@ gfc_build_constant_array_constructor (gfc_expr * expr, tree type)
    gfc_build_constant_array_constructor.  */
 
 static void
-gfc_trans_constant_array_constructor (gfc_loopinfo * loop,
-                                     gfc_ss * ss, tree type)
+trans_constant_array_constructor (gfc_ss * ss, tree type)
 {
-  gfc_ss_info *info;
+  gfc_array_info *info;
   tree tmp;
   int i;
 
-  tmp = gfc_build_constant_array_constructor (ss->expr, type);
+  tmp = gfc_build_constant_array_constructor (ss->info->expr, type);
 
-  info = &ss->data.info;
+  info = &ss->info->data.array;
 
   info->descriptor = tmp;
   info->data = gfc_build_addr_expr (NULL_TREE, tmp);
   info->offset = gfc_index_zero_node;
 
-  for (i = 0; i < info->dimen + info->codimen; i++)
+  for (i = 0; i < ss->dimen; i++)
     {
       info->delta[i] = gfc_index_zero_node;
       info->start[i] = gfc_index_zero_node;
       info->end[i] = gfc_index_zero_node;
       info->stride[i] = gfc_index_one_node;
-      info->dim[i] = i;
     }
-
-  if (info->dimen > loop->temp_dim)
-    loop->temp_dim = info->dimen;
 }
 
 /* Helper routine of gfc_trans_array_constructor to determine if the
    bounds of the loop specified by LOOP are constant and simple enough
-   to use with gfc_trans_constant_array_constructor.  Returns the
+   to use with trans_constant_array_constructor.  Returns the
    iteration count of the loop if suitable, and NULL_TREE otherwise.  */
 
 static tree
@@ -1844,7 +1981,7 @@ constant_array_constructor_loop_size (gfc_loopinfo * loop)
    simplest method.  */
 
 static void
-gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss, locus * where)
+trans_array_constructor (gfc_ss * ss, locus * where)
 {
   gfc_constructor_base c;
   tree offset;
@@ -1855,75 +1992,82 @@ gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss, locus * where)
   bool dynamic;
   bool old_first_len, old_typespec_chararray_ctor;
   tree old_first_len_val;
+  gfc_loopinfo *loop;
+  gfc_ss_info *ss_info;
+  gfc_expr *expr;
 
   /* Save the old values for nested checking.  */
   old_first_len = first_len;
   old_first_len_val = first_len_val;
   old_typespec_chararray_ctor = typespec_chararray_ctor;
 
+  loop = ss->loop;
+  ss_info = ss->info;
+  expr = ss_info->expr;
+
   /* 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.u.cl
-                            && ss->expr->ts.u.cl->length_from_typespec);
+  typespec_chararray_ctor = (expr->ts.u.cl
+                            && expr->ts.u.cl->length_from_typespec);
 
   if ((gfc_option.rtcheck & GFC_RTCHECK_BOUNDS)
-      && ss->expr->ts.type == BT_CHARACTER && !typespec_chararray_ctor)
+      && expr->ts.type == BT_CHARACTER && !typespec_chararray_ctor)
     {  
       first_len_val = gfc_create_var (gfc_charlen_type_node, "len");
       first_len = true;
     }
 
-  ss->data.info.dimen = loop->dimen;
+  gcc_assert (ss->dimen == loop->dimen);
 
-  c = ss->expr->value.constructor;
-  if (ss->expr->ts.type == BT_CHARACTER)
+  c = expr->value.constructor;
+  if (expr->ts.type == BT_CHARACTER)
     {
       bool const_string;
       
       /* 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.u.cl->length
-         && ss->expr->ts.u.cl->length->expr_type != EXPR_CONSTANT)
+      if (typespec_chararray_ctor && expr->ts.u.cl->length
+         && 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.u.cl->length,
+         gfc_conv_expr_type (&length_se, expr->ts.u.cl->length,
                              gfc_charlen_type_node);
-         ss->string_length = length_se.expr;
+         ss_info->string_length = length_se.expr;
          gfc_add_block_to_block (&loop->pre, &length_se.pre);
          gfc_add_block_to_block (&loop->post, &length_se.post);
        }
       else
        const_string = get_array_ctor_strlen (&loop->pre, c,
-                                             &ss->string_length);
+                                             &ss_info->string_length);
 
       /* Complex character array constructors should have been taken care of
         and not end up here.  */
-      gcc_assert (ss->string_length);
+      gcc_assert (ss_info->string_length);
 
-      ss->expr->ts.u.cl->backend_decl = ss->string_length;
+      expr->ts.u.cl->backend_decl = ss_info->string_length;
 
-      type = gfc_get_character_type_len (ss->expr->ts.kind, ss->string_length);
+      type = gfc_get_character_type_len (expr->ts.kind, ss_info->string_length);
       if (const_string)
        type = build_pointer_type (type);
     }
   else
-    type = gfc_typenode_for_spec (&ss->expr->ts);
+    type = gfc_typenode_for_spec (&expr->ts);
 
   /* See if the constructor determines the loop bounds.  */
   dynamic = false;
 
-  if (ss->expr->shape && loop->dimen > 1 && loop->to[0] == NULL_TREE)
+  if (expr->shape && loop->dimen > 1 && loop->to[0] == NULL_TREE)
     {
       /* We have a multidimensional parameter.  */
       int n;
-      for (n = 0; n < ss->expr->rank; n++)
+      for (n = 0; n < expr->rank; n++)
       {
        loop->from[n] = gfc_index_zero_node;
-       loop->to[n] = gfc_conv_mpz_to_tree (ss->expr->shape [n],
+       loop->to[n] = gfc_conv_mpz_to_tree (expr->shape [n],
                                            gfc_index_integer_kind);
        loop->to[n] = fold_build2_loc (input_location, MINUS_EXPR,
                                       gfc_array_index_type,
@@ -1958,7 +2102,7 @@ gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss, locus * where)
          tree size = constant_array_constructor_loop_size (loop);
          if (size && compare_tree_int (size, nelem) == 0)
            {
-             gfc_trans_constant_array_constructor (loop, ss, type);
+             trans_constant_array_constructor (ss, type);
              goto finish;
            }
        }
@@ -1967,10 +2111,10 @@ gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss, locus * where)
   if (TREE_CODE (loop->to[0]) == VAR_DECL)
     dynamic = true;
 
-  gfc_trans_create_temp_array (&loop->pre, &loop->post, loop, &ss->data.info,
+  gfc_trans_create_temp_array (&loop->pre, &loop->post, loop, ss,
                               type, NULL_TREE, dynamic, true, false, where);
 
-  desc = ss->data.info.descriptor;
+  desc = ss_info->data.array.descriptor;
   offset = gfc_index_zero_node;
   offsetvar = gfc_create_var_np (gfc_array_index_type, "offset");
   TREE_NO_WARNING (offsetvar) = 1;
@@ -2020,8 +2164,10 @@ finish:
    loop bounds.  */
 
 static void
-gfc_set_vector_loop_bounds (gfc_loopinfo * loop, gfc_ss_info * info)
+set_vector_loop_bounds (gfc_ss * ss)
 {
+  gfc_loopinfo *loop;
+  gfc_array_info *info;
   gfc_se se;
   tree tmp;
   tree desc;
@@ -2029,9 +2175,12 @@ gfc_set_vector_loop_bounds (gfc_loopinfo * loop, gfc_ss_info * info)
   int n;
   int dim;
 
-  for (n = 0; n < loop->dimen + loop->codimen; n++)
+  info = &ss->info->data.array;
+  loop = ss->loop;
+
+  for (n = 0; n < loop->dimen; n++)
     {
-      dim = info->dim[n];
+      dim = ss->dim[n];
       if (info->ref->u.ar.dimen_type[dim] == DIMEN_VECTOR
          && loop->to[n] == NULL)
        {
@@ -2040,10 +2189,10 @@ gfc_set_vector_loop_bounds (gfc_loopinfo * loop, gfc_ss_info * info)
             difference between the vector's upper and lower bounds.  */
          gcc_assert (loop->from[n] == gfc_index_zero_node);
          gcc_assert (info->subscript[dim]
-                     && info->subscript[dim]->type == GFC_SS_VECTOR);
+                     && info->subscript[dim]->info->type == GFC_SS_VECTOR);
 
          gfc_init_se (&se, NULL);
-         desc = info->subscript[dim]->data.info.descriptor;
+         desc = info->subscript[dim]->info->data.array.descriptor;
          zero = gfc_rank_cst[0];
          tmp = fold_build2_loc (input_location, MINUS_EXPR,
                             gfc_array_index_type,
@@ -2065,6 +2214,9 @@ gfc_add_loop_ss_code (gfc_loopinfo * loop, gfc_ss * ss, bool subscript,
                      locus * where)
 {
   gfc_se se;
+  gfc_ss_info *ss_info;
+  gfc_array_info *info;
+  gfc_expr *expr;
   int n;
 
   /* TODO: This can generate bad code if there are ordering dependencies,
@@ -2075,61 +2227,64 @@ gfc_add_loop_ss_code (gfc_loopinfo * loop, gfc_ss * ss, bool subscript,
     {
       gcc_assert (ss);
 
-      switch (ss->type)
+      ss_info = ss->info;
+      expr = ss_info->expr;
+      info = &ss_info->data.array;
+
+      switch (ss_info->type)
        {
        case GFC_SS_SCALAR:
          /* Scalar expression.  Evaluate this now.  This includes elemental
             dimension indices, but not array section bounds.  */
          gfc_init_se (&se, NULL);
-         gfc_conv_expr (&se, ss->expr);
+         gfc_conv_expr (&se, expr);
          gfc_add_block_to_block (&loop->pre, &se.pre);
 
-         if (ss->expr->ts.type != BT_CHARACTER)
+         if (expr->ts.type != BT_CHARACTER)
            {
              /* Move the evaluation of scalar expressions outside the
                 scalarization loop, except for WHERE assignments.  */
              if (subscript)
                se.expr = convert(gfc_array_index_type, se.expr);
-             if (!ss->where)
+             if (!ss_info->where)
                se.expr = gfc_evaluate_now (se.expr, &loop->pre);
              gfc_add_block_to_block (&loop->pre, &se.post);
            }
          else
            gfc_add_block_to_block (&loop->post, &se.post);
 
-         ss->data.scalar.expr = se.expr;
-         ss->string_length = se.string_length;
+         ss_info->data.scalar.value = se.expr;
+         ss_info->string_length = se.string_length;
          break;
 
        case GFC_SS_REFERENCE:
          /* Scalar argument to elemental procedure.  Evaluate this
             now.  */
          gfc_init_se (&se, NULL);
-         gfc_conv_expr (&se, ss->expr);
+         gfc_conv_expr (&se, expr);
          gfc_add_block_to_block (&loop->pre, &se.pre);
          gfc_add_block_to_block (&loop->post, &se.post);
 
-         ss->data.scalar.expr = gfc_evaluate_now (se.expr, &loop->pre);
-         ss->string_length = se.string_length;
+         ss_info->data.scalar.value = gfc_evaluate_now (se.expr, &loop->pre);
+         ss_info->string_length = se.string_length;
          break;
 
        case GFC_SS_SECTION:
          /* Add the expressions for scalar and vector subscripts.  */
          for (n = 0; n < GFC_MAX_DIMENSIONS; n++)
-           if (ss->data.info.subscript[n])
-             gfc_add_loop_ss_code (loop, ss->data.info.subscript[n], true,
-                                   where);
+           if (info->subscript[n])
+             gfc_add_loop_ss_code (loop, info->subscript[n], true, where);
 
-         gfc_set_vector_loop_bounds (loop, &ss->data.info);
+         set_vector_loop_bounds (ss);
          break;
 
        case GFC_SS_VECTOR:
          /* Get the vector's descriptor and store it in SS.  */
          gfc_init_se (&se, NULL);
-         gfc_conv_expr_descriptor (&se, ss->expr, gfc_walk_expr (ss->expr));
+         gfc_conv_expr_descriptor (&se, expr, gfc_walk_expr (expr));
          gfc_add_block_to_block (&loop->pre, &se.pre);
          gfc_add_block_to_block (&loop->post, &se.post);
-         ss->data.info.descriptor = se.expr;
+         info->descriptor = se.expr;
          break;
 
        case GFC_SS_INTRINSIC:
@@ -2142,26 +2297,26 @@ gfc_add_loop_ss_code (gfc_loopinfo * loop, gfc_ss * ss, bool subscript,
          gfc_init_se (&se, NULL);
          se.loop = loop;
          se.ss = ss;
-         gfc_conv_expr (&se, ss->expr);
+         gfc_conv_expr (&se, expr);
          gfc_add_block_to_block (&loop->pre, &se.pre);
          gfc_add_block_to_block (&loop->post, &se.post);
-         ss->string_length = se.string_length;
+         ss_info->string_length = se.string_length;
          break;
 
        case GFC_SS_CONSTRUCTOR:
-         if (ss->expr->ts.type == BT_CHARACTER
-               && ss->string_length == NULL
-               && ss->expr->ts.u.cl
-               && ss->expr->ts.u.cl->length)
+         if (expr->ts.type == BT_CHARACTER
+             && ss_info->string_length == NULL
+             && expr->ts.u.cl
+             && expr->ts.u.cl->length)
            {
              gfc_init_se (&se, NULL);
-             gfc_conv_expr_type (&se, ss->expr->ts.u.cl->length,
+             gfc_conv_expr_type (&se, expr->ts.u.cl->length,
                                  gfc_charlen_type_node);
-             ss->string_length = se.expr;
+             ss_info->string_length = se.expr;
              gfc_add_block_to_block (&loop->pre, &se.pre);
              gfc_add_block_to_block (&loop->post, &se.post);
            }
-         gfc_trans_array_constructor (loop, ss, where);
+         trans_array_constructor (ss, where);
          break;
 
         case GFC_SS_TEMP:
@@ -2183,16 +2338,21 @@ static void
 gfc_conv_ss_descriptor (stmtblock_t * block, gfc_ss * ss, int base)
 {
   gfc_se se;
+  gfc_ss_info *ss_info;
+  gfc_array_info *info;
   tree tmp;
 
+  ss_info = ss->info;
+  info = &ss_info->data.array;
+
   /* Get the descriptor for the array to be scalarized.  */
-  gcc_assert (ss->expr->expr_type == EXPR_VARIABLE);
+  gcc_assert (ss_info->expr->expr_type == EXPR_VARIABLE);
   gfc_init_se (&se, NULL);
   se.descriptor_only = 1;
-  gfc_conv_expr_lhs (&se, ss->expr);
+  gfc_conv_expr_lhs (&se, ss_info->expr);
   gfc_add_block_to_block (block, &se.pre);
-  ss->data.info.descriptor = se.expr;
-  ss->string_length = se.string_length;
+  info->descriptor = se.expr;
+  ss_info->string_length = se.string_length;
 
   if (base)
     {
@@ -2206,15 +2366,15 @@ gfc_conv_ss_descriptor (stmtblock_t * block, gfc_ss * ss, int base)
            || (TREE_CODE (tmp) == ADDR_EXPR
                && DECL_P (TREE_OPERAND (tmp, 0)))))
        tmp = gfc_evaluate_now (tmp, block);
-      ss->data.info.data = tmp;
+      info->data = tmp;
 
       tmp = gfc_conv_array_offset (se.expr);
-      ss->data.info.offset = gfc_evaluate_now (tmp, block);
+      info->offset = gfc_evaluate_now (tmp, block);
 
       /* Make absolutely sure that the saved_offset is indeed saved
         so that the variable is still accessible after the loops
         are translated.  */
-      ss->data.info.saved_offset = ss->data.info.offset;
+      info->saved_offset = info->offset;
     }
 }
 
@@ -2234,7 +2394,7 @@ gfc_init_loopinfo (gfc_loopinfo * loop)
   for (n = 0; n < GFC_MAX_DIMENSIONS; n++)
     {
       loop->order[n] = n;
-      loop->reverse[n] = GFC_CANNOT_REVERSE;
+      loop->reverse[n] = GFC_INHIBIT_REVERSE;
     }
 
   loop->ss = gfc_ss_terminator;
@@ -2355,42 +2515,25 @@ gfc_conv_array_ubound (tree descriptor, int dim)
 /* Generate code to perform an array index bound check.  */
 
 static tree
-gfc_trans_array_bound_check (gfc_se * se, tree descriptor, tree index, int n,
-                            locus * where, bool check_upper)
+trans_array_bound_check (gfc_se * se, gfc_ss *ss, tree index, int n,
+                        locus * where, bool check_upper)
 {
   tree fault;
   tree tmp_lo, tmp_up;
+  tree descriptor;
   char *msg;
   const char * name = NULL;
 
   if (!(gfc_option.rtcheck & GFC_RTCHECK_BOUNDS))
     return index;
 
+  descriptor = ss->info->data.array.descriptor;
+
   index = gfc_evaluate_now (index, &se->pre);
 
   /* We find a name for the error message.  */
-  if (se->ss)
-    name = se->ss->expr->symtree->name;
-
-  if (!name && se->loop && se->loop->ss && se->loop->ss->expr
-      && se->loop->ss->expr->symtree)
-    name = se->loop->ss->expr->symtree->name;
-
-  if (!name && se->loop && se->loop->ss && se->loop->ss->loop_chain
-      && se->loop->ss->loop_chain->expr
-      && se->loop->ss->loop_chain->expr->symtree)
-    name = se->loop->ss->loop_chain->expr->symtree->name;
-
-  if (!name && se->loop && se->loop->ss && se->loop->ss->expr)
-    {
-      if (se->loop->ss->expr->expr_type == EXPR_FUNCTION
-         && se->loop->ss->expr->value.function.name)
-       name = se->loop->ss->expr->value.function.name;
-      else
-       if (se->loop->ss->type == GFC_SS_CONSTRUCTOR
-           || se->loop->ss->type == GFC_SS_SCALAR)
-         name = "unnamed constant";
-    }
+  name = ss->info->expr->symtree->n.sym->name;
+  gcc_assert (name != NULL);
 
   if (TREE_CODE (descriptor) == VAR_DECL)
     name = IDENTIFIER_POINTER (DECL_NAME (descriptor));
@@ -2420,7 +2563,7 @@ gfc_trans_array_bound_check (gfc_se * se, tree descriptor, tree index, int n,
                               fold_convert (long_integer_type_node, index),
                               fold_convert (long_integer_type_node, tmp_lo),
                               fold_convert (long_integer_type_node, tmp_up));
-      gfc_free (msg);
+      free (msg);
     }
   else
     {
@@ -2438,7 +2581,7 @@ gfc_trans_array_bound_check (gfc_se * se, tree descriptor, tree index, int n,
       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);
+      free (msg);
     }
 
   return index;
@@ -2450,13 +2593,16 @@ gfc_trans_array_bound_check (gfc_se * se, tree descriptor, tree index, int n,
    DIM is the array dimension, I is the loop dimension.  */
 
 static tree
-gfc_conv_array_index_offset (gfc_se * se, gfc_ss_info * info, int dim, int i,
-                            gfc_array_ref * ar, tree stride)
+conv_array_index_offset (gfc_se * se, gfc_ss * ss, int dim, int i,
+                        gfc_array_ref * ar, tree stride)
 {
+  gfc_array_info *info;
   tree index;
   tree desc;
   tree data;
 
+  info = &ss->info->data.array;
+
   /* Get the index into the array for this dimension.  */
   if (ar)
     {
@@ -2469,21 +2615,20 @@ gfc_conv_array_index_offset (gfc_se * se, gfc_ss_info * info, int dim, int i,
        case DIMEN_ELEMENT:
          /* Elemental dimension.  */
          gcc_assert (info->subscript[dim]
-                     && info->subscript[dim]->type == GFC_SS_SCALAR);
+                     && info->subscript[dim]->info->type == GFC_SS_SCALAR);
          /* We've already translated this value outside the loop.  */
-         index = info->subscript[dim]->data.scalar.expr;
+         index = info->subscript[dim]->info->data.scalar.value;
 
-         index = gfc_trans_array_bound_check (se, info->descriptor,
-                       index, dim, &ar->where,
-                       ar->as->type != AS_ASSUMED_SIZE
-                       || dim < ar->dimen - 1);
+         index = trans_array_bound_check (se, ss, index, dim, &ar->where,
+                                          ar->as->type != AS_ASSUMED_SIZE
+                                          || dim < ar->dimen - 1);
          break;
 
        case DIMEN_VECTOR:
          gcc_assert (info && se->loop);
          gcc_assert (info->subscript[dim]
-                     && info->subscript[dim]->type == GFC_SS_VECTOR);
-         desc = info->subscript[dim]->data.info.descriptor;
+                     && info->subscript[dim]->info->type == GFC_SS_VECTOR);
+         desc = info->subscript[dim]->info->data.array.descriptor;
 
          /* Get a zero-based index into the vector.  */
          index = fold_build2_loc (input_location, MINUS_EXPR,
@@ -2503,10 +2648,9 @@ gfc_conv_array_index_offset (gfc_se * se, gfc_ss_info * info, int dim, int i,
          index = fold_convert (gfc_array_index_type, index);
 
          /* Do any bounds checking on the final info->descriptor index.  */
-         index = gfc_trans_array_bound_check (se, info->descriptor,
-                       index, dim, &ar->where,
-                       ar->as->type != AS_ASSUMED_SIZE
-                       || dim < ar->dimen - 1);
+         index = trans_array_bound_check (se, ss, index, dim, &ar->where,
+                                          ar->as->type != AS_ASSUMED_SIZE
+                                          || dim < ar->dimen - 1);
          break;
 
        case DIMEN_RANGE:
@@ -2534,6 +2678,18 @@ gfc_conv_array_index_offset (gfc_se * se, gfc_ss_info * info, int dim, int i,
       /* Temporary array or derived type component.  */
       gcc_assert (se->loop);
       index = se->loop->loopvar[se->loop->order[i]];
+
+      /* Pointer functions can have stride[0] different from unity. 
+        Use the stride returned by the function call and stored in
+        the descriptor for the temporary.  */ 
+      if (se->ss && se->ss->info->type == GFC_SS_FUNCTION
+         && se->ss->info->expr
+         && se->ss->info->expr->symtree
+         && se->ss->info->expr->symtree->n.sym->result
+         && se->ss->info->expr->symtree->n.sym->result->attr.pointer)
+       stride = gfc_conv_descriptor_stride_get (info->descriptor,
+                                                gfc_rank_cst[dim]);
+
       if (!integer_zerop (info->delta[dim]))
        index = fold_build2_loc (input_location, PLUS_EXPR,
                                 gfc_array_index_type, index, info->delta[dim]);
@@ -2553,31 +2709,33 @@ gfc_conv_array_index_offset (gfc_se * se, gfc_ss_info * info, int dim, int i,
 static void
 gfc_conv_scalarized_array_ref (gfc_se * se, gfc_array_ref * ar)
 {
-  gfc_ss_info *info;
+  gfc_array_info *info;
   tree decl = NULL_TREE;
   tree index;
   tree tmp;
+  gfc_ss *ss;
+  gfc_expr *expr;
   int n;
 
-  info = &se->ss->data.info;
+  ss = se->ss;
+  expr = ss->info->expr;
+  info = &ss->info->data.array;
   if (ar)
     n = se->loop->order[0];
   else
     n = 0;
 
-  index = gfc_conv_array_index_offset (se, info, info->dim[n], n, ar,
-                                      info->stride0);
+  index = conv_array_index_offset (se, ss, ss->dim[n], n, ar, info->stride0);
   /* Add the offset for this dimension to the stored offset for all other
      dimensions.  */
   if (!integer_zerop (info->offset))
     index = fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type,
                             index, info->offset);
 
-  if (se->ss->expr && is_subref_array (se->ss->expr))
-    decl = se->ss->expr->symtree->n.sym->backend_decl;
+  if (expr && is_subref_array (expr))
+    decl = expr->symtree->n.sym->backend_decl;
 
-  tmp = build_fold_indirect_ref_loc (input_location,
-                                info->data);
+  tmp = build_fold_indirect_ref_loc (input_location, info->data);
   se->expr = gfc_build_array_ref (tmp, index, decl);
 }
 
@@ -2587,11 +2745,27 @@ gfc_conv_scalarized_array_ref (gfc_se * se, gfc_array_ref * ar)
 void
 gfc_conv_tmp_array_ref (gfc_se * se)
 {
-  se->string_length = se->ss->string_length;
+  se->string_length = se->ss->info->string_length;
   gfc_conv_scalarized_array_ref (se, NULL);
   gfc_advance_se_ss_chain (se);
 }
 
+/* Add T to the offset pair *OFFSET, *CST_OFFSET.  */
+
+static void
+add_to_offset (tree *cst_offset, tree *offset, tree t)
+{
+  if (TREE_CODE (t) == INTEGER_CST)
+    *cst_offset = int_const_binop (PLUS_EXPR, *cst_offset, t);
+  else
+    {
+      if (!integer_zerop (*offset))
+       *offset = fold_build2_loc (input_location, PLUS_EXPR,
+                                  gfc_array_index_type, *offset, t);
+      else
+       *offset = t;
+    }
+}
 
 /* Build an array reference.  se->expr already holds the array descriptor.
    This should be either a variable, indirect variable reference or component
@@ -2604,14 +2778,32 @@ gfc_conv_array_ref (gfc_se * se, gfc_array_ref * ar, gfc_symbol * sym,
                    locus * where)
 {
   int n;
-  tree index;
+  tree offset, cst_offset;
   tree tmp;
   tree stride;
   gfc_se indexse;
   gfc_se tmpse;
 
   if (ar->dimen == 0)
-    return;
+    {
+      gcc_assert (ar->codimen);
+
+      if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (se->expr)))
+       se->expr = build_fold_indirect_ref (gfc_conv_array_data (se->expr));
+      else
+       {
+         if (GFC_ARRAY_TYPE_P (TREE_TYPE (se->expr))
+             && TREE_CODE (TREE_TYPE (se->expr)) == POINTER_TYPE)
+           se->expr = build_fold_indirect_ref_loc (input_location, se->expr);
+
+         /* Use the actual tree type and not the wrapped coarray. */
+         if (!se->want_pointer)
+           se->expr = fold_convert (TYPE_MAIN_VARIANT (TREE_TYPE (se->expr)),
+                                    se->expr);
+       }
+
+      return;
+    }
 
   /* Handle scalarized references separately.  */
   if (ar->type != AR_ELEMENT)
@@ -2621,10 +2813,12 @@ gfc_conv_array_ref (gfc_se * se, gfc_array_ref * ar, gfc_symbol * sym,
       return;
     }
 
-  index = gfc_index_zero_node;
+  cst_offset = offset = gfc_index_zero_node;
+  add_to_offset (&cst_offset, &offset, gfc_conv_array_offset (se->expr));
 
-  /* Calculate the offsets from all the dimensions.  */
-  for (n = 0; n < ar->dimen; n++)
+  /* Calculate the offsets from all the dimensions.  Make sure to associate
+     the final offset so that we form a chain of loop invariant summands.  */
+  for (n = ar->dimen - 1; n >= 0; n--)
     {
       /* Calculate the index for this dimension.  */
       gfc_init_se (&indexse, se);
@@ -2659,7 +2853,7 @@ gfc_conv_array_ref (gfc_se * se, gfc_array_ref * ar, gfc_symbol * sym,
                                   fold_convert (long_integer_type_node,
                                                 indexse.expr),
                                   fold_convert (long_integer_type_node, tmp));
-         gfc_free (msg);
+         free (msg);
 
          /* Upper bound, but not for the last dimension of assumed-size
             arrays.  */
@@ -2683,7 +2877,7 @@ gfc_conv_array_ref (gfc_se * se, gfc_array_ref * ar, gfc_symbol * sym,
                                   fold_convert (long_integer_type_node,
                                                 indexse.expr),
                                   fold_convert (long_integer_type_node, tmp));
-             gfc_free (msg);
+             free (msg);
            }
        }
 
@@ -2693,19 +2887,44 @@ gfc_conv_array_ref (gfc_se * se, gfc_array_ref * ar, gfc_symbol * sym,
                             indexse.expr, stride);
 
       /* And add it to the total.  */
-      index = fold_build2_loc (input_location, PLUS_EXPR,
-                              gfc_array_index_type, index, tmp);
+      add_to_offset (&cst_offset, &offset, tmp);
     }
 
-  tmp = gfc_conv_array_offset (se->expr);
-  if (!integer_zerop (tmp))
-    index = fold_build2_loc (input_location, PLUS_EXPR,
-                            gfc_array_index_type, index, tmp);
+  if (!integer_zerop (cst_offset))
+    offset = fold_build2_loc (input_location, PLUS_EXPR,
+                             gfc_array_index_type, offset, cst_offset);
 
   /* Access the calculated element.  */
   tmp = gfc_conv_array_data (se->expr);
   tmp = build_fold_indirect_ref (tmp);
-  se->expr = gfc_build_array_ref (tmp, index, sym->backend_decl);
+  se->expr = gfc_build_array_ref (tmp, offset, sym->backend_decl);
+}
+
+
+/* Add the offset corresponding to array's ARRAY_DIM dimension and loop's
+   LOOP_DIM dimension (if any) to array's offset.  */
+
+static void
+add_array_offset (stmtblock_t *pblock, gfc_loopinfo *loop, gfc_ss *ss,
+                 gfc_array_ref *ar, int array_dim, int loop_dim)
+{
+  gfc_se se;
+  gfc_array_info *info;
+  tree stride, index;
+
+  info = &ss->info->data.array;
+
+  gfc_init_se (&se, NULL);
+  se.loop = loop;
+  se.expr = info->descriptor;
+  stride = gfc_conv_array_stride (info->descriptor, array_dim);
+  index = conv_array_index_offset (&se, ss, array_dim, loop_dim, ar, stride);
+  gfc_add_block_to_block (pblock, &se.pre);
+
+  info->offset = fold_build2_loc (input_location, PLUS_EXPR,
+                                 gfc_array_index_type,
+                                 info->offset, index);
+  info->offset = gfc_evaluate_now (info->offset, pblock);
 }
 
 
@@ -2716,97 +2935,75 @@ static void
 gfc_trans_preloop_setup (gfc_loopinfo * loop, int dim, int flag,
                         stmtblock_t * pblock)
 {
-  tree index;
   tree stride;
-  gfc_ss_info *info;
+  gfc_ss_info *ss_info;
+  gfc_array_info *info;
+  gfc_ss_type ss_type;
   gfc_ss *ss;
-  gfc_se se;
+  gfc_array_ref *ar;
   int i;
 
   /* This code will be executed before entering the scalarization loop
      for this dimension.  */
   for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain)
     {
-      if ((ss->useflags & flag) == 0)
+      ss_info = ss->info;
+
+      if ((ss_info->useflags & flag) == 0)
        continue;
 
-      if (ss->type != GFC_SS_SECTION
-         && ss->type != GFC_SS_FUNCTION && ss->type != GFC_SS_CONSTRUCTOR
-         && ss->type != GFC_SS_COMPONENT)
+      ss_type = ss_info->type;
+      if (ss_type != GFC_SS_SECTION
+         && ss_type != GFC_SS_FUNCTION
+         && ss_type != GFC_SS_CONSTRUCTOR
+         && ss_type != GFC_SS_COMPONENT)
        continue;
 
-      info = &ss->data.info;
+      info = &ss_info->data.array;
 
-      if (dim >= info->dimen)
-       continue;
+      gcc_assert (dim < ss->dimen);
+      gcc_assert (ss->dimen == loop->dimen);
+
+      if (info->ref)
+       ar = &info->ref->u.ar;
+      else
+       ar = NULL;
+
+      if (dim == loop->dimen - 1)
+       i = 0;
+      else
+       i = dim + 1;
+
+      /* For the time being, there is no loop reordering.  */
+      gcc_assert (i == loop->order[i]);
+      i = loop->order[i];
 
-      if (dim == info->dimen - 1)
+      if (dim == loop->dimen - 1)
        {
+         stride = gfc_conv_array_stride (info->descriptor, ss->dim[i]);
+
+         /* Calculate the stride of the innermost loop.  Hopefully this will
+            allow the backend optimizers to do their stuff more effectively.
+          */
+         info->stride0 = gfc_evaluate_now (stride, pblock);
+
          /* For the outermost loop calculate the offset due to any
             elemental dimensions.  It will have been initialized with the
             base offset of the array.  */
          if (info->ref)
            {
-             for (i = 0; i < info->ref->u.ar.dimen; i++)
+             for (i = 0; i < ar->dimen; i++)
                {
-                 if (info->ref->u.ar.dimen_type[i] != DIMEN_ELEMENT)
+                 if (ar->dimen_type[i] != DIMEN_ELEMENT)
                    continue;
 
-                 gfc_init_se (&se, NULL);
-                 se.loop = loop;
-                 se.expr = info->descriptor;
-                 stride = gfc_conv_array_stride (info->descriptor, i);
-                 index = gfc_conv_array_index_offset (&se, info, i, -1,
-                                                      &info->ref->u.ar,
-                                                      stride);
-                 gfc_add_block_to_block (pblock, &se.pre);
-
-                 info->offset = fold_build2_loc (input_location, PLUS_EXPR,
-                                                 gfc_array_index_type,
-                                                 info->offset, index);
-                 info->offset = gfc_evaluate_now (info->offset, pblock);
+                 add_array_offset (pblock, loop, ss, ar, i, /* unused */ -1);
                }
            }
-
-         i = loop->order[0];
-         /* For the time being, the innermost loop is unconditionally on
-            the first dimension of the scalarization loop.  */
-         gcc_assert (i == 0);
-         stride = gfc_conv_array_stride (info->descriptor, info->dim[i]);
-
-         /* Calculate the stride of the innermost loop.  Hopefully this will
-            allow the backend optimizers to do their stuff more effectively.
-          */
-         info->stride0 = gfc_evaluate_now (stride, pblock);
        }
       else
-       {
-         /* Add the offset for the previous loop dimension.  */
-         gfc_array_ref *ar;
-
-         if (info->ref)
-           {
-             ar = &info->ref->u.ar;
-             i = loop->order[dim + 1];
-           }
-         else
-           {
-             ar = NULL;
-             i = dim + 1;
-           }
-
-         gfc_init_se (&se, NULL);
-         se.loop = loop;
-         se.expr = info->descriptor;
-         stride = gfc_conv_array_stride (info->descriptor, info->dim[i]);
-         index = gfc_conv_array_index_offset (&se, info, info->dim[i], i,
-                                              ar, stride);
-         gfc_add_block_to_block (pblock, &se.pre);
-         info->offset = fold_build2_loc (input_location, PLUS_EXPR,
-                                         gfc_array_index_type, info->offset,
-                                         index);
-         info->offset = gfc_evaluate_now (info->offset, pblock);
-       }
+       /* Add the offset for the previous loop dimension.  */
+       add_array_offset (pblock, loop, ss, ar, ss->dim[i], i);
 
       /* Remember this offset for the second loop.  */
       if (dim == loop->temp_dim - 1)
@@ -2827,7 +3024,7 @@ gfc_start_scalarized_body (gfc_loopinfo * loop, stmtblock_t * pbody)
 
   gcc_assert (!loop->array_parameter);
 
-  for (dim = loop->dimen + loop->codimen - 1; dim >= 0; dim--)
+  for (dim = loop->dimen - 1; dim >= 0; dim--)
     {
       n = loop->order[dim];
 
@@ -2981,7 +3178,7 @@ gfc_trans_scalarizing_loops (gfc_loopinfo * loop, stmtblock_t * body)
 
   pblock = body;
   /* Generate the loops.  */
-  for (dim = 0; dim < loop->dimen + loop->codimen; dim++)
+  for (dim = 0; dim < loop->dimen; dim++)
     {
       n = loop->order[dim];
       gfc_trans_scalarized_loop_end (loop, n, pblock);
@@ -2993,8 +3190,8 @@ gfc_trans_scalarizing_loops (gfc_loopinfo * loop, stmtblock_t * body)
   gfc_add_expr_to_block (&loop->pre, tmp);
 
   /* Clear all the used flags.  */
-  for (ss = loop->ss; ss; ss = ss->loop_chain)
-    ss->useflags = 0;
+  for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain)
+    ss->info->useflags = 0;
 }
 
 
@@ -3026,15 +3223,22 @@ gfc_trans_scalarized_loop_boundary (gfc_loopinfo * loop, stmtblock_t * body)
   /* Restore the initial offsets.  */
   for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain)
     {
-      if ((ss->useflags & 2) == 0)
+      gfc_ss_type ss_type;
+      gfc_ss_info *ss_info;
+
+      ss_info = ss->info;
+
+      if ((ss_info->useflags & 2) == 0)
        continue;
 
-      if (ss->type != GFC_SS_SECTION
-         && ss->type != GFC_SS_FUNCTION && ss->type != GFC_SS_CONSTRUCTOR
-         && ss->type != GFC_SS_COMPONENT)
+      ss_type = ss_info->type;
+      if (ss_type != GFC_SS_SECTION
+         && ss_type != GFC_SS_FUNCTION
+         && ss_type != GFC_SS_CONSTRUCTOR
+         && ss_type != GFC_SS_COMPONENT)
        continue;
 
-      ss->data.info.offset = ss->data.info.saved_offset;
+      ss_info->data.array.offset = ss_info->data.array.saved_offset;
     }
 
   /* Restart all the inner loops we just finished.  */
@@ -3054,82 +3258,83 @@ gfc_trans_scalarized_loop_boundary (gfc_loopinfo * loop, stmtblock_t * body)
 }
 
 
+/* Precalculate (either lower or upper) bound of an array section.
+     BLOCK: Block in which the (pre)calculation code will go.
+     BOUNDS[DIM]: Where the bound value will be stored once evaluated.
+     VALUES[DIM]: Specified bound (NULL <=> unspecified).
+     DESC: Array descriptor from which the bound will be picked if unspecified
+       (either lower or upper bound according to LBOUND).  */
+
+static void
+evaluate_bound (stmtblock_t *block, tree *bounds, gfc_expr ** values,
+               tree desc, int dim, bool lbound)
+{
+  gfc_se se;
+  gfc_expr * input_val = values[dim];
+  tree *output = &bounds[dim];
+
+
+  if (input_val)
+    {
+      /* Specified section bound.  */
+      gfc_init_se (&se, NULL);
+      gfc_conv_expr_type (&se, input_val, gfc_array_index_type);
+      gfc_add_block_to_block (block, &se.pre);
+      *output = se.expr;
+    }
+  else
+    {
+      /* No specific bound specified so use the bound of the array.  */
+      *output = lbound ? gfc_conv_array_lbound (desc, dim) :
+                        gfc_conv_array_ubound (desc, dim);
+    }
+  *output = gfc_evaluate_now (*output, block);
+}
+
+
 /* Calculate the lower bound of an array section.  */
 
 static void
-gfc_conv_section_startstride (gfc_loopinfo * loop, gfc_ss * ss, int dim,
-                             bool coarray, bool coarray_last)
+gfc_conv_section_startstride (gfc_loopinfo * loop, gfc_ss * ss, int dim)
 {
-  gfc_expr *start;
-  gfc_expr *end;
   gfc_expr *stride = NULL;
   tree desc;
   gfc_se se;
-  gfc_ss_info *info;
+  gfc_array_info *info;
+  gfc_array_ref *ar;
 
-  gcc_assert (ss->type == GFC_SS_SECTION);
+  gcc_assert (ss->info->type == GFC_SS_SECTION);
 
-  info = &ss->data.info;
+  info = &ss->info->data.array;
+  ar = &info->ref->u.ar;
 
-  if (info->ref->u.ar.dimen_type[dim] == DIMEN_VECTOR)
+  if (ar->dimen_type[dim] == DIMEN_VECTOR)
     {
       /* We use a zero-based index to access the vector.  */
       info->start[dim] = gfc_index_zero_node;
       info->end[dim] = NULL;
-      if (!coarray)
-       info->stride[dim] = gfc_index_one_node;
+      info->stride[dim] = gfc_index_one_node;
       return;
     }
 
-  gcc_assert (info->ref->u.ar.dimen_type[dim] == DIMEN_RANGE);
+  gcc_assert (ar->dimen_type[dim] == DIMEN_RANGE
+             || ar->dimen_type[dim] == DIMEN_THIS_IMAGE);
   desc = info->descriptor;
-  start = info->ref->u.ar.start[dim];
-  end = info->ref->u.ar.end[dim];
-  if (!coarray)
-    stride = info->ref->u.ar.stride[dim];
+  stride = ar->stride[dim];
 
   /* Calculate the start of the range.  For vector subscripts this will
      be the range of the vector.  */
-  if (start)
-    {
-      /* Specified section start.  */
-      gfc_init_se (&se, NULL);
-      gfc_conv_expr_type (&se, start, gfc_array_index_type);
-      gfc_add_block_to_block (&loop->pre, &se.pre);
-      info->start[dim] = se.expr;
-    }
-  else
-    {
-      /* No lower bound specified so use the bound of the array.  */
-      info->start[dim] = gfc_conv_array_lbound (desc, dim);
-    }
-  info->start[dim] = gfc_evaluate_now (info->start[dim], &loop->pre);
+  evaluate_bound (&loop->pre, info->start, ar->start, desc, dim, true);
 
   /* Similarly calculate the end.  Although this is not used in the
      scalarizer, it is needed when checking bounds and where the end
      is an expression with side-effects.  */
-  if (!coarray_last)
-    {
-      if (end)
-       {
-         /* Specified section start.  */
-         gfc_init_se (&se, NULL);
-         gfc_conv_expr_type (&se, end, gfc_array_index_type);
-         gfc_add_block_to_block (&loop->pre, &se.pre);
-         info->end[dim] = se.expr;
-       }
-      else
-       {
-         /* No upper bound specified so use the bound of the array.  */
-         info->end[dim] = gfc_conv_array_ubound (desc, dim);
-       }
-      info->end[dim] = gfc_evaluate_now (info->end[dim], &loop->pre);
-    }
+  evaluate_bound (&loop->pre, info->end, ar->end, desc, dim, false);
 
   /* Calculate the stride.  */
-  if (!coarray && stride == NULL)
+  if (stride == NULL)
     info->stride[dim] = gfc_index_one_node;
-  else if (!coarray)
+  else
     {
       gfc_init_se (&se, NULL);
       gfc_conv_expr_type (&se, stride, gfc_array_index_type);
@@ -3153,35 +3358,28 @@ gfc_conv_ss_startstride (gfc_loopinfo * loop)
 
   loop->dimen = 0;
   /* Determine the rank of the loop.  */
-  for (ss = loop->ss;
-       ss != gfc_ss_terminator && loop->dimen == 0; ss = ss->loop_chain)
+  for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain)
     {
-      switch (ss->type)
+      switch (ss->info->type)
        {
        case GFC_SS_SECTION:
        case GFC_SS_CONSTRUCTOR:
        case GFC_SS_FUNCTION:
        case GFC_SS_COMPONENT:
-         loop->dimen = ss->data.info.dimen;
-         loop->codimen = ss->data.info.codimen;
-         break;
+         loop->dimen = ss->dimen;
+         goto done;
 
        /* As usual, lbound and ubound are exceptions!.  */
        case GFC_SS_INTRINSIC:
-         switch (ss->expr->value.function.isym->id)
+         switch (ss->info->expr->value.function.isym->id)
            {
            case GFC_ISYM_LBOUND:
            case GFC_ISYM_UBOUND:
-             loop->dimen = ss->data.info.dimen;
-             loop->codimen = 0;
-             break;
-
            case GFC_ISYM_LCOBOUND:
            case GFC_ISYM_UCOBOUND:
            case GFC_ISYM_THIS_IMAGE:
-             loop->dimen = ss->data.info.dimen;
-             loop->codimen = ss->data.info.codimen;
-             break;
+             loop->dimen = ss->dimen;
+             goto done;
 
            default:
              break;
@@ -3194,33 +3392,35 @@ gfc_conv_ss_startstride (gfc_loopinfo * loop)
 
   /* We should have determined the rank of the expression by now.  If
      not, that's bad news.  */
-  gcc_assert (loop->dimen + loop->codimen != 0);
+  gcc_unreachable ();
 
+done:
   /* Loop over all the SS in the chain.  */
   for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain)
     {
-      if (ss->expr && ss->expr->shape && !ss->shape)
-       ss->shape = ss->expr->shape;
+      gfc_ss_info *ss_info;
+      gfc_array_info *info;
+      gfc_expr *expr;
+
+      ss_info = ss->info;
+      expr = ss_info->expr;
+      info = &ss_info->data.array;
 
-      switch (ss->type)
+      if (expr && expr->shape && !info->shape)
+       info->shape = expr->shape;
+
+      switch (ss_info->type)
        {
        case GFC_SS_SECTION:
          /* Get the descriptor for the array.  */
          gfc_conv_ss_descriptor (&loop->pre, ss, !loop->array_parameter);
 
-         for (n = 0; n < ss->data.info.dimen; n++)
-           gfc_conv_section_startstride (loop, ss, ss->data.info.dim[n],
-                                         false, false);
-         for (n = ss->data.info.dimen;
-              n < ss->data.info.dimen + ss->data.info.codimen; n++)
-           gfc_conv_section_startstride (loop, ss, ss->data.info.dim[n], true,
-                                         n == ss->data.info.dimen
-                                              + ss->data.info.codimen -1);
-
+         for (n = 0; n < ss->dimen; n++)
+           gfc_conv_section_startstride (loop, ss, ss->dim[n]);
          break;
 
        case GFC_SS_INTRINSIC:
-         switch (ss->expr->value.function.isym->id)
+         switch (expr->value.function.isym->id)
            {
            /* Fall through to supply start and stride.  */
            case GFC_ISYM_LBOUND:
@@ -3236,11 +3436,13 @@ gfc_conv_ss_startstride (gfc_loopinfo * loop)
 
        case GFC_SS_CONSTRUCTOR:
        case GFC_SS_FUNCTION:
-         for (n = 0; n < ss->data.info.dimen; n++)
+         for (n = 0; n < ss->dimen; n++)
            {
-             ss->data.info.start[n] = gfc_index_zero_node;
-             ss->data.info.end[n] = gfc_index_zero_node;
-             ss->data.info.stride[n] = gfc_index_one_node;
+             int dim = ss->dim[n];
+
+             info->start[dim]  = gfc_index_zero_node;
+             info->end[dim]    = gfc_index_zero_node;
+             info->stride[dim] = gfc_index_one_node;
            }
          break;
 
@@ -3257,7 +3459,7 @@ gfc_conv_ss_startstride (gfc_loopinfo * loop)
       tree end;
       tree size[GFC_MAX_DIMENSIONS];
       tree stride_pos, stride_neg, non_zerosized, tmp2, tmp3;
-      gfc_ss_info *info;
+      gfc_array_info *info;
       char *msg;
       int dim;
 
@@ -3269,18 +3471,27 @@ gfc_conv_ss_startstride (gfc_loopinfo * loop)
       for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain)
        {
          stmtblock_t inner;
+         gfc_ss_info *ss_info;
+         gfc_expr *expr;
+         locus *expr_loc;
+         const char *expr_name;
 
-         if (ss->type != GFC_SS_SECTION)
+         ss_info = ss->info;
+         if (ss_info->type != GFC_SS_SECTION)
            continue;
 
          /* Catch allocatable lhs in f2003.  */
          if (gfc_option.flag_realloc_lhs && ss->is_alloc_lhs)
            continue;
 
+         expr = ss_info->expr;
+         expr_loc = &expr->where;
+         expr_name = expr->symtree->name;
+
          gfc_start_block (&inner);
 
          /* TODO: range checking for mapped dimensions.  */
-         info = &ss->data.info;
+         info = &ss_info->data.array;
 
          /* This code only checks ranges.  Elemental and vector
             dimensions are checked later.  */
@@ -3288,7 +3499,7 @@ gfc_conv_ss_startstride (gfc_loopinfo * loop)
            {
              bool check_upper;
 
-             dim = info->dim[n];
+             dim = ss->dim[n];
              if (info->ref->u.ar.dimen_type[dim] != DIMEN_RANGE)
                continue;
 
@@ -3302,12 +3513,12 @@ gfc_conv_ss_startstride (gfc_loopinfo * loop)
              tmp = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node,
                                     info->stride[dim], gfc_index_zero_node);
              asprintf (&msg, "Zero stride is not allowed, for dimension %d "
-                       "of array '%s'", dim + 1, ss->expr->symtree->name);
+                       "of array '%s'", dim + 1, expr_name);
              gfc_trans_runtime_check (true, false, tmp, &inner,
-                                      &ss->expr->where, msg);
-             gfc_free (msg);
+                                      expr_loc, msg);
+             free (msg);
 
-             desc = ss->data.info.descriptor;
+             desc = info->descriptor;
 
              /* This is the run-time equivalent of resolve.c's
                 check_dimension().  The logical is more readable there
@@ -3361,18 +3572,18 @@ gfc_conv_ss_startstride (gfc_loopinfo * loop)
                                          non_zerosized, tmp2);
                  asprintf (&msg, "Index '%%ld' of dimension %d of array '%s' "
                            "outside of expected range (%%ld:%%ld)",
-                           dim + 1, ss->expr->symtree->name);
+                           dim + 1, expr_name);
                  gfc_trans_runtime_check (true, false, tmp, &inner,
-                                          &ss->expr->where, msg,
+                                          expr_loc, msg,
                     fold_convert (long_integer_type_node, info->start[dim]),
                     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,
+                                          expr_loc, msg,
                     fold_convert (long_integer_type_node, info->start[dim]),
                     fold_convert (long_integer_type_node, lbound),
                     fold_convert (long_integer_type_node, ubound));
-                 gfc_free (msg);
+                 free (msg);
                }
              else
                {
@@ -3383,12 +3594,12 @@ gfc_conv_ss_startstride (gfc_loopinfo * loop)
                                         boolean_type_node, non_zerosized, tmp);
                  asprintf (&msg, "Index '%%ld' of dimension %d of array '%s' "
                            "below lower bound of %%ld",
-                           dim + 1, ss->expr->symtree->name);
+                           dim + 1, expr_name);
                  gfc_trans_runtime_check (true, false, tmp, &inner,
-                                          &ss->expr->where, msg,
+                                          expr_loc, msg,
                     fold_convert (long_integer_type_node, info->start[dim]),
                     fold_convert (long_integer_type_node, lbound));
-                 gfc_free (msg);
+                 free (msg);
                }
              
              /* Compute the last element of the range, which is not
@@ -3415,29 +3626,29 @@ gfc_conv_ss_startstride (gfc_loopinfo * loop)
                                          boolean_type_node, non_zerosized, tmp3);
                  asprintf (&msg, "Index '%%ld' of dimension %d of array '%s' "
                            "outside of expected range (%%ld:%%ld)",
-                           dim + 1, ss->expr->symtree->name);
+                           dim + 1, expr_name);
                  gfc_trans_runtime_check (true, false, tmp2, &inner,
-                                          &ss->expr->where, msg,
+                                          expr_loc, 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,
+                                          expr_loc, 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);
+                 free (msg);
                }
              else
                {
                  asprintf (&msg, "Index '%%ld' of dimension %d of array '%s' "
                            "below lower bound of %%ld",
-                           dim + 1, ss->expr->symtree->name);
+                           dim + 1, expr_name);
                  gfc_trans_runtime_check (true, false, tmp2, &inner,
-                                          &ss->expr->where, msg,
+                                          expr_loc, msg,
                     fold_convert (long_integer_type_node, tmp),
                     fold_convert (long_integer_type_node, lbound));
-                 gfc_free (msg);
+                 free (msg);
                }
 
              /* Check the section sizes match.  */
@@ -3461,14 +3672,14 @@ gfc_conv_ss_startstride (gfc_loopinfo * loop)
                                          boolean_type_node, tmp, size[n]);
                  asprintf (&msg, "Array bound mismatch for dimension %d "
                            "of array '%s' (%%ld/%%ld)",
-                           dim + 1, ss->expr->symtree->name);
+                           dim + 1, expr_name);
 
                  gfc_trans_runtime_check (true, false, tmp3, &inner,
-                                          &ss->expr->where, msg,
+                                          expr_loc, msg,
                        fold_convert (long_integer_type_node, tmp),
                        fold_convert (long_integer_type_node, size[n]));
 
-                 gfc_free (msg);
+                 free (msg);
                }
              else
                size[n] = gfc_evaluate_now (tmp, &inner);
@@ -3478,10 +3689,10 @@ gfc_conv_ss_startstride (gfc_loopinfo * loop)
 
          /* For optional arguments, only check bounds if the argument is
             present.  */
-         if (ss->expr->symtree->n.sym->attr.optional
-             || ss->expr->symtree->n.sym->attr.not_always_present)
+         if (expr->symtree->n.sym->attr.optional
+             || expr->symtree->n.sym->attr.not_always_present)
            tmp = build3_v (COND_EXPR,
-                           gfc_conv_expr_present (ss->expr->symtree->n.sym),
+                           gfc_conv_expr_present (expr->symtree->n.sym),
                            tmp, build_empty_stmt (input_location));
 
          gfc_add_expr_to_block (&block, tmp);
@@ -3534,12 +3745,16 @@ gfc_could_be_alias (gfc_ss * lss, gfc_ss * rss)
 {
   gfc_ref *lref;
   gfc_ref *rref;
+  gfc_expr *lexpr, *rexpr;
   gfc_symbol *lsym;
   gfc_symbol *rsym;
   bool lsym_pointer, lsym_target, rsym_pointer, rsym_target;
 
-  lsym = lss->expr->symtree->n.sym;
-  rsym = rss->expr->symtree->n.sym;
+  lexpr = lss->info->expr;
+  rexpr = rss->info->expr;
+
+  lsym = lexpr->symtree->n.sym;
+  rsym = rexpr->symtree->n.sym;
 
   lsym_pointer = lsym->attr.pointer;
   lsym_target = lsym->attr.target;
@@ -3557,7 +3772,7 @@ gfc_could_be_alias (gfc_ss * lss, gfc_ss * rss)
   /* For derived types we must check all the component types.  We can ignore
      array references as these will have the same base type as the previous
      component ref.  */
-  for (lref = lss->expr->ref; lref != lss->data.info.ref; lref = lref->next)
+  for (lref = lexpr->ref; lref != lss->info->data.array.ref; lref = lref->next)
     {
       if (lref->type != REF_COMPONENT)
        continue;
@@ -3577,7 +3792,7 @@ gfc_could_be_alias (gfc_ss * lss, gfc_ss * rss)
            return 1;
        }
 
-      for (rref = rss->expr->ref; rref != rss->data.info.ref;
+      for (rref = rexpr->ref; rref != rss->info->data.array.ref;
           rref = rref->next)
        {
          if (rref->type != REF_COMPONENT)
@@ -3612,7 +3827,7 @@ gfc_could_be_alias (gfc_ss * lss, gfc_ss * rss)
   lsym_pointer = lsym->attr.pointer;
   lsym_target = lsym->attr.target;
 
-  for (rref = rss->expr->ref; rref != rss->data.info.ref; rref = rref->next)
+  for (rref = rexpr->ref; rref != rss->info->data.array.ref; rref = rref->next)
     {
       if (rref->type != REF_COMPONENT)
        break;
@@ -3648,20 +3863,25 @@ gfc_conv_resolve_dependencies (gfc_loopinfo * loop, gfc_ss * dest,
   gfc_ss *ss;
   gfc_ref *lref;
   gfc_ref *rref;
+  gfc_expr *dest_expr;
+  gfc_expr *ss_expr;
   int nDepend = 0;
   int i, j;
 
   loop->temp_ss = NULL;
+  dest_expr = dest->info->expr;
 
   for (ss = rss; ss != gfc_ss_terminator; ss = ss->next)
     {
-      if (ss->type != GFC_SS_SECTION)
+      if (ss->info->type != GFC_SS_SECTION)
        continue;
 
-      if (dest->expr->symtree->n.sym != ss->expr->symtree->n.sym)
+      ss_expr = ss->info->expr;
+
+      if (dest_expr->symtree->n.sym != ss_expr->symtree->n.sym)
        {
          if (gfc_could_be_alias (dest, ss)
-               || gfc_are_equivalenced_arrays (dest->expr, ss->expr))
+             || gfc_are_equivalenced_arrays (dest_expr, ss_expr))
            {
              nDepend = 1;
              break;
@@ -3669,18 +3889,18 @@ gfc_conv_resolve_dependencies (gfc_loopinfo * loop, gfc_ss * dest,
        }
       else
        {
-         lref = dest->expr->ref;
-         rref = ss->expr->ref;
+         lref = dest_expr->ref;
+         rref = ss_expr->ref;
 
          nDepend = gfc_dep_resolver (lref, rref, &loop->reverse[0]);
 
          if (nDepend == 1)
            break;
 
-         for (i = 0; i < dest->data.info.dimen; i++)
-           for (j = 0; j < ss->data.info.dimen; j++)
+         for (i = 0; i < dest->dimen; i++)
+           for (j = 0; j < ss->dimen; j++)
              if (i != j
-                 && dest->data.info.dim[i] == ss->data.info.dim[j])
+                 && dest->dim[i] == ss->dim[j])
                {
                  /* If we don't access array elements in the same order,
                     there is a dependency.  */
@@ -3729,17 +3949,12 @@ temporary:
 
   if (nDepend == 1)
     {
-      tree base_type = gfc_typenode_for_spec (&dest->expr->ts);
+      tree base_type = gfc_typenode_for_spec (&dest_expr->ts);
       if (GFC_ARRAY_TYPE_P (base_type)
          || GFC_DESCRIPTOR_TYPE_P (base_type))
        base_type = gfc_get_element_type (base_type);
-      loop->temp_ss = gfc_get_ss ();
-      loop->temp_ss->type = GFC_SS_TEMP;
-      loop->temp_ss->data.temp.type = base_type;
-      loop->temp_ss->string_length = dest->string_length;
-      loop->temp_ss->data.temp.dimen = loop->dimen;
-      loop->temp_ss->data.temp.codimen = loop->codimen;
-      loop->temp_ss->next = gfc_ss_terminator;
+      loop->temp_ss = gfc_get_temp_ss (base_type, dest->info->string_length,
+                                      loop->dimen);
       gfc_add_ss_to_loop (loop, loop->temp_ss);
     }
   else
@@ -3747,27 +3962,27 @@ temporary:
 }
 
 
-/* Initialize the scalarization loop.  Creates the loop variables.  Determines
-   the range of the loop variables.  Creates a temporary if required.
-   Calculates how to transform from loop variables to array indices for each
-   expression.  Also generates code for scalar expressions which have been
-   moved outside the loop.  */
+/* Browse through each array's information from the scalarizer and set the loop
+   bounds according to the "best" one (per dimension), i.e. the one which
+   provides the most information (constant bounds, shape, etc).  */
 
-void
-gfc_conv_loop_setup (gfc_loopinfo * loop, locus * where)
+static void
+set_loop_bounds (gfc_loopinfo *loop)
 {
   int n, dim, spec_dim;
-  gfc_ss_info *info;
-  gfc_ss_info *specinfo;
+  gfc_array_info *info;
+  gfc_array_info *specinfo;
   gfc_ss *ss;
   tree tmp;
-  gfc_ss *loopspec[GFC_MAX_DIMENSIONS];
+  gfc_ss **loopspec;
   bool dynamic[GFC_MAX_DIMENSIONS];
   mpz_t *cshape;
   mpz_t i;
 
+  loopspec = loop->specloop;
+
   mpz_init (i);
-  for (n = 0; n < loop->dimen + loop->codimen; n++)
+  for (n = 0; n < loop->dimen; n++)
     {
       loopspec[n] = NULL;
       dynamic[n] = false;
@@ -3775,16 +3990,21 @@ gfc_conv_loop_setup (gfc_loopinfo * loop, locus * where)
         loop for this dimension.  We try to pick the simplest term.  */
       for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain)
        {
-         if (ss->type == GFC_SS_SCALAR || ss->type == GFC_SS_REFERENCE)
+         gfc_ss_type ss_type;
+
+         ss_type = ss->info->type;
+         if (ss_type == GFC_SS_SCALAR
+             || ss_type == GFC_SS_TEMP
+             || ss_type == GFC_SS_REFERENCE)
            continue;
 
-         info = &ss->data.info;
-         dim = info->dim[n];
+         info = &ss->info->data.array;
+         dim = ss->dim[n];
 
          if (loopspec[n] != NULL)
            {
-             specinfo = &loopspec[n]->data.info;
-             spec_dim = specinfo->dim[n];
+             specinfo = &loopspec[n]->info->data.array;
+             spec_dim = loopspec[n]->dim[n];
            }
          else
            {
@@ -3793,19 +4013,19 @@ gfc_conv_loop_setup (gfc_loopinfo * loop, locus * where)
              spec_dim = 0;
            }
 
-         if (ss->shape)
+         if (info->shape)
            {
-             gcc_assert (ss->shape[dim]);
+             gcc_assert (info->shape[dim]);
              /* The frontend has worked out the size for us.  */
              if (!loopspec[n]
-                 || !loopspec[n]->shape
+                 || !specinfo->shape
                  || !integer_zerop (specinfo->start[spec_dim]))
                /* Prefer zero-based descriptors if possible.  */
                loopspec[n] = ss;
              continue;
            }
 
-         if (ss->type == GFC_SS_CONSTRUCTOR)
+         if (ss_type == GFC_SS_CONSTRUCTOR)
            {
              gfc_constructor_base base;
              /* An unknown size constructor will always be rank one.
@@ -3817,7 +4037,7 @@ gfc_conv_loop_setup (gfc_loopinfo * loop, locus * where)
                 can be determined at compile time.  Prefer not to otherwise,
                 since the general case involves realloc, and it's better to
                 avoid that overhead if possible.  */
-             base = ss->expr->value.constructor;
+             base = ss->info->expr->value.constructor;
              dynamic[n] = gfc_get_array_constructor_size (&i, base);
              if (!dynamic[n] || !loopspec[n])
                loopspec[n] = ss;
@@ -3826,7 +4046,7 @@ gfc_conv_loop_setup (gfc_loopinfo * loop, locus * where)
 
          /* TODO: Pick the best bound if we have a choice between a
             function and something else.  */
-         if (ss->type == GFC_SS_FUNCTION)
+         if (ss_type == GFC_SS_FUNCTION)
            {
              loopspec[n] = ss;
              continue;
@@ -3837,7 +4057,7 @@ gfc_conv_loop_setup (gfc_loopinfo * loop, locus * where)
          if (loopspec[n] && ss->is_alloc_lhs)
            continue;
 
-         if (ss->type != GFC_SS_SECTION)
+         if (ss_type != GFC_SS_SECTION)
            continue;
 
          if (!loopspec[n])
@@ -3849,7 +4069,7 @@ gfc_conv_loop_setup (gfc_loopinfo * loop, locus * where)
             known lower bound
             known upper bound
           */
-         else if ((loopspec[n]->type == GFC_SS_CONSTRUCTOR && dynamic[n])
+         else if ((loopspec[n]->info->type == GFC_SS_CONSTRUCTOR && dynamic[n])
                   || n >= loop->dimen)
            loopspec[n] = ss;
          else if (integer_onep (info->stride[dim])
@@ -3871,16 +4091,16 @@ gfc_conv_loop_setup (gfc_loopinfo * loop, locus * where)
         that's bad news.  */
       gcc_assert (loopspec[n]);
 
-      info = &loopspec[n]->data.info;
-      dim = info->dim[n];
+      info = &loopspec[n]->info->data.array;
+      dim = loopspec[n]->dim[n];
 
       /* Set the extents of this range.  */
-      cshape = loopspec[n]->shape;
-      if (n < loop->dimen && cshape && INTEGER_CST_P (info->start[dim])
+      cshape = info->shape;
+      if (cshape && INTEGER_CST_P (info->start[dim])
          && INTEGER_CST_P (info->stride[dim]))
        {
          loop->from[n] = info->start[dim];
-         mpz_set (i, cshape[get_array_ref_dim (info, n)]);
+         mpz_set (i, cshape[get_array_ref_dim (loopspec[n], n)]);
          mpz_sub_ui (i, i, 1);
          /* To = from + (size - 1) * stride.  */
          tmp = gfc_conv_mpz_to_tree (i, gfc_index_integer_kind);
@@ -3895,7 +4115,7 @@ gfc_conv_loop_setup (gfc_loopinfo * loop, locus * where)
       else
        {
          loop->from[n] = info->start[dim];
-         switch (loopspec[n]->type)
+         switch (loopspec[n]->info->type)
            {
            case GFC_SS_CONSTRUCTOR:
              /* The upper bound is calculated when we expand the
@@ -3942,65 +4162,100 @@ gfc_conv_loop_setup (gfc_loopinfo * loop, locus * where)
          loop->from[n] = gfc_index_zero_node;
        }
     }
+  mpz_clear (i);
+}
+
+
+static void set_delta (gfc_loopinfo *loop);
+
+
+/* Initialize the scalarization loop.  Creates the loop variables.  Determines
+   the range of the loop variables.  Creates a temporary if required.
+   Also generates code for scalar expressions which have been
+   moved outside the loop.  */
+
+void
+gfc_conv_loop_setup (gfc_loopinfo * loop, locus * where)
+{
+  gfc_ss *tmp_ss;
+  tree tmp;
+
+  set_loop_bounds (loop);
 
   /* Add all the scalar code that can be taken out of the loops.
      This may include calculating the loop bounds, so do it before
      allocating the temporary.  */
   gfc_add_loop_ss_code (loop, loop->ss, false, where);
 
+  tmp_ss = loop->temp_ss;
   /* If we want a temporary then create it.  */
-  if (loop->temp_ss != NULL)
+  if (tmp_ss != NULL)
     {
-      gcc_assert (loop->temp_ss->type == GFC_SS_TEMP);
+      gfc_ss_info *tmp_ss_info;
+
+      tmp_ss_info = tmp_ss->info;
+      gcc_assert (tmp_ss_info->type == GFC_SS_TEMP);
 
       /* Make absolutely sure that this is a complete type.  */
-      if (loop->temp_ss->string_length)
-       loop->temp_ss->data.temp.type
+      if (tmp_ss_info->string_length)
+       tmp_ss_info->data.temp.type
                = gfc_get_character_type_len_for_eltype
-                       (TREE_TYPE (loop->temp_ss->data.temp.type),
-                        loop->temp_ss->string_length);
+                       (TREE_TYPE (tmp_ss_info->data.temp.type),
+                        tmp_ss_info->string_length);
 
-      tmp = loop->temp_ss->data.temp.type;
-      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;
-      loop->temp_ss->data.info.dimen = n;
+      tmp = tmp_ss_info->data.temp.type;
+      memset (&tmp_ss_info->data.array, 0, sizeof (gfc_array_info));
+      tmp_ss_info->type = GFC_SS_SECTION;
 
-      gcc_assert (loop->temp_ss->data.info.dimen != 0);
-      for (n = 0; n < loop->temp_ss->data.info.dimen; n++)
-       loop->temp_ss->data.info.dim[n] = n;
+      gcc_assert (tmp_ss->dimen != 0);
 
       gfc_trans_create_temp_array (&loop->pre, &loop->post, loop,
-                                  &loop->temp_ss->data.info, tmp, NULL_TREE,
+                                  tmp_ss, tmp, NULL_TREE,
                                   false, true, false, where);
     }
 
-  for (n = 0; n < loop->temp_dim; n++)
-    loopspec[loop->order[n]] = NULL;
-
-  mpz_clear (i);
-
   /* For array parameters we don't have loop variables, so don't calculate the
      translations.  */
   if (loop->array_parameter)
     return;
 
+  set_delta (loop);
+}
+
+
+/* Calculates how to transform from loop variables to array indices for each
+   array: once loop bounds are chosen, sets the difference (DELTA field) between
+   loop bounds and array reference bounds, for each array info.  */
+
+static void
+set_delta (gfc_loopinfo *loop)
+{
+  gfc_ss *ss, **loopspec;
+  gfc_array_info *info;
+  tree tmp;
+  int n, dim;
+
+  loopspec = loop->specloop;
+
   /* Calculate the translation from loop variables to array indices.  */
   for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain)
     {
-      if (ss->type != GFC_SS_SECTION && ss->type != GFC_SS_COMPONENT
-           && ss->type != GFC_SS_CONSTRUCTOR)
+      gfc_ss_type ss_type;
 
+      ss_type = ss->info->type;
+      if (ss_type != GFC_SS_SECTION
+         && ss_type != GFC_SS_COMPONENT
+         && ss_type != GFC_SS_CONSTRUCTOR)
        continue;
 
-      info = &ss->data.info;
+      info = &ss->info->data.array;
 
-      for (n = 0; n < info->dimen; n++)
+      for (n = 0; n < ss->dimen; n++)
        {
          /* If we are specifying the range the delta is already set.  */
          if (loopspec[n] != ss)
            {
-             dim = ss->data.info.dim[n];
+             dim = ss->dim[n];
 
              /* Calculate the offset relative to the loop variable.
                 First multiply by the stride.  */
@@ -4101,21 +4356,6 @@ gfc_conv_descriptor_cosize (tree desc, int rank, int corank)
 }
 
 
-/* Helper function for marking a boolean expression tree as unlikely.  */
-
-static tree
-gfc_unlikely (tree cond)
-{
-  tree tmp;
-
-  cond = fold_convert (long_integer_type_node, cond);
-  tmp = build_zero_cst (long_integer_type_node);
-  cond = build_call_expr_loc (input_location,
-                             built_in_decls[BUILT_IN_EXPECT], 2, cond, tmp);
-  cond = fold_convert (boolean_type_node, cond);
-  return cond;
-}
-
 /* Fills in an array descriptor, and returns the size of the array.
    The size will be a simple_val, ie a variable or a constant.  Also
    calculates the offset of the base.  The pointer argument overflow,
@@ -4131,11 +4371,15 @@ gfc_unlikely (tree cond)
        size = 1 - lbound;
        a.ubound[n] = specified_upper_bound;
        a.stride[n] = stride;
-       size = siz >= 0 ? ubound + size : 0; //size = ubound + 1 - lbound
+       size = size >= 0 ? ubound + size : 0; //size = ubound + 1 - lbound
        overflow += size == 0 ? 0: (MAX/size < stride ? 1: 0);
        stride = stride * size;
       }
+    for (n = rank; n < rank+corank; n++)
+      (Set lcobound/ucobound as above.)
     element_size = sizeof (array element);
+    if (!rank)
+      return element_size
     stride = (size_t) stride;
     overflow += element_size == 0 ? 0: (MAX/element_size < stride ? 1: 0);
     stride = stride * element_size;
@@ -4145,8 +4389,8 @@ gfc_unlikely (tree cond)
 
 static tree
 gfc_array_init_size (tree descriptor, int rank, int corank, tree * poffset,
-                    gfc_expr ** lower, gfc_expr ** upper,
-                    stmtblock_t * pblock, tree * overflow)
+                    gfc_expr ** lower, gfc_expr ** upper, stmtblock_t * pblock,
+                    stmtblock_t * descriptor_block, tree * overflow)
 {
   tree type;
   tree tmp;
@@ -4172,7 +4416,7 @@ gfc_array_init_size (tree descriptor, int rank, int corank, tree * poffset,
 
   /* Set the dtype.  */
   tmp = gfc_conv_descriptor_dtype (descriptor);
-  gfc_add_modify (pblock, tmp, gfc_get_dtype (TREE_TYPE (descriptor)));
+  gfc_add_modify (descriptor_block, tmp, gfc_get_dtype (TREE_TYPE (descriptor)));
 
   or_expr = boolean_false_node;
 
@@ -4205,8 +4449,8 @@ gfc_array_init_size (tree descriptor, int rank, int corank, tree * poffset,
              ubound = lower[n];
            }
        }
-      gfc_conv_descriptor_lbound_set (pblock, descriptor, gfc_rank_cst[n],
-                                     se.expr);
+      gfc_conv_descriptor_lbound_set (descriptor_block, descriptor, 
+                                     gfc_rank_cst[n], se.expr);
       conv_lbound = se.expr;
 
       /* Work out the offset for this component.  */
@@ -4221,12 +4465,12 @@ gfc_array_init_size (tree descriptor, int rank, int corank, tree * poffset,
       gfc_conv_expr_type (&se, ubound, gfc_array_index_type);
       gfc_add_block_to_block (pblock, &se.pre);
 
-      gfc_conv_descriptor_ubound_set (pblock, descriptor,
+      gfc_conv_descriptor_ubound_set (descriptor_block, descriptor,
                                      gfc_rank_cst[n], se.expr);
       conv_ubound = se.expr;
 
       /* Store the stride.  */
-      gfc_conv_descriptor_stride_set (pblock, descriptor,
+      gfc_conv_descriptor_stride_set (descriptor_block, descriptor,
                                      gfc_rank_cst[n], stride);
 
       /* Calculate size and check whether extent is negative.  */
@@ -4286,8 +4530,8 @@ gfc_array_init_size (tree descriptor, int rank, int corank, tree * poffset,
              ubound = lower[n];
            }
        }
-      gfc_conv_descriptor_lbound_set (pblock, descriptor, gfc_rank_cst[n],
-                                     se.expr);
+      gfc_conv_descriptor_lbound_set (descriptor_block, descriptor, 
+                                     gfc_rank_cst[n], se.expr);
 
       if (n < rank + corank - 1)
        {
@@ -4295,7 +4539,7 @@ gfc_array_init_size (tree descriptor, int rank, int corank, tree * poffset,
          gcc_assert (ubound);
          gfc_conv_expr_type (&se, ubound, gfc_array_index_type);
          gfc_add_block_to_block (pblock, &se.pre);
-         gfc_conv_descriptor_ubound_set (pblock, descriptor,
+         gfc_conv_descriptor_ubound_set (descriptor_block, descriptor,
                                          gfc_rank_cst[n], se.expr);
        }
     }
@@ -4305,6 +4549,10 @@ gfc_array_init_size (tree descriptor, int rank, int corank, tree * poffset,
   tmp = TYPE_SIZE_UNIT (gfc_get_element_type (type));
   /* Convert to size_t.  */
   element_size = fold_convert (size_type_node, tmp);
+
+  if (rank == 0)
+    return element_size;
+
   stride = fold_convert (size_type_node, stride);
 
   /* First check for overflow. Since an array of type character can
@@ -4362,22 +4610,26 @@ gfc_array_init_size (tree descriptor, int rank, int corank, tree * poffset,
 /*GCC ARRAYS*/
 
 bool
-gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree pstat)
+gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree status, tree errmsg,
+                   tree errlen)
 {
   tree tmp;
   tree pointer;
-  tree offset;
+  tree offset = NULL_TREE;
+  tree token = NULL_TREE;
   tree size;
   tree msg;
-  tree error;
+  tree error = NULL_TREE;
   tree overflow; /* Boolean storing whether size calculation overflows.  */
-  tree var_overflow;
+  tree var_overflow = NULL_TREE;
   tree cond;
+  tree set_descriptor;
+  stmtblock_t set_descriptor_block;
   stmtblock_t elseblock;
   gfc_expr **lower;
   gfc_expr **upper;
   gfc_ref *ref, *prev_ref = NULL;
-  bool allocatable_array, coarray;
+  bool allocatable, coarray, dimension;
 
   ref = expr->ref;
 
@@ -4395,22 +4647,19 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree pstat)
 
   if (!prev_ref)
     {
-      allocatable_array = expr->symtree->n.sym->attr.allocatable;
+      allocatable = expr->symtree->n.sym->attr.allocatable;
       coarray = expr->symtree->n.sym->attr.codimension;
+      dimension = expr->symtree->n.sym->attr.dimension;
     }
   else
     {
-      allocatable_array = prev_ref->u.c.component->attr.allocatable;
+      allocatable = prev_ref->u.c.component->attr.allocatable;
       coarray = prev_ref->u.c.component->attr.codimension;
+      dimension = prev_ref->u.c.component->attr.dimension;
     }
 
-  /* Return if this is a scalar coarray.  */
-  if ((!prev_ref && !expr->symtree->n.sym->attr.dimension)
-      || (prev_ref && !prev_ref->u.c.component->attr.dimension))
-    {
-      gcc_assert (coarray);
-      return false;
-    }
+  if (!dimension)
+    gcc_assert (coarray);
 
   /* Figure out the size of the array.  */
   switch (ref->u.ar.type)
@@ -4442,62 +4691,84 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree pstat)
     }
 
   overflow = integer_zero_node;
+
+  gfc_init_block (&set_descriptor_block);
   size = gfc_array_init_size (se->expr, ref->u.ar.as->rank,
                              ref->u.ar.as->corank, &offset, lower, upper,
-                             &se->pre, &overflow);
+                             &se->pre, &set_descriptor_block, &overflow);
+
+  if (dimension)
+    {
 
-  var_overflow = gfc_create_var (integer_type_node, "overflow");
-  gfc_add_modify (&se->pre, var_overflow, overflow);
+      var_overflow = gfc_create_var (integer_type_node, "overflow");
+      gfc_add_modify (&se->pre, var_overflow, overflow);
 
-  /* Generate the block of code handling overflow.  */
-  msg = gfc_build_addr_expr (pchar_type_node, gfc_build_localized_cstring_const
+      /* Generate the block of code handling overflow.  */
+      msg = gfc_build_addr_expr (pchar_type_node,
+               gfc_build_localized_cstring_const
                        ("Integer overflow when calculating the amount of "
                         "memory to allocate"));
-  error = build_call_expr_loc (input_location,
-                          gfor_fndecl_runtime_error, 1, msg);
+      error = build_call_expr_loc (input_location, gfor_fndecl_runtime_error,
+                                  1, msg);
+    }
 
-  if (pstat != NULL_TREE && !integer_zerop (pstat))
+  if (status != NULL_TREE)
     {
-      /* Set the status variable if it's present.  */
+      tree status_type = TREE_TYPE (status);
       stmtblock_t set_status_block;
-      tree status_type = pstat ? TREE_TYPE (TREE_TYPE (pstat)) : NULL_TREE;
 
       gfc_start_block (&set_status_block);
-      gfc_add_modify (&set_status_block,
-                     fold_build1_loc (input_location, INDIRECT_REF,
-                                      status_type, pstat),
-                          build_int_cst (status_type, LIBERROR_ALLOCATION));
-
-      tmp = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node,
-                            pstat, build_int_cst (TREE_TYPE (pstat), 0));
-      error = fold_build3_loc (input_location, COND_EXPR, void_type_node, tmp,
-                              error, gfc_finish_block (&set_status_block));
+      gfc_add_modify (&set_status_block, status,
+                     build_int_cst (status_type, LIBERROR_ALLOCATION));
+      error = gfc_finish_block (&set_status_block);
     }
 
   gfc_start_block (&elseblock);
-  
+
   /* Allocate memory to store the data.  */
   pointer = gfc_conv_descriptor_data_get (se->expr);
   STRIP_NOPS (pointer);
 
-  /* The allocate_array variants take the old pointer as first argument.  */
-  if (allocatable_array)
-    tmp = gfc_allocate_array_with_status (&elseblock, pointer, size, pstat, expr);
-  else
-    tmp = gfc_allocate_with_status (&elseblock, size, pstat);
-  tmp = fold_build2_loc (input_location, MODIFY_EXPR, void_type_node, pointer,
-                        tmp);
+  if (coarray && gfc_option.coarray == GFC_FCOARRAY_LIB)
+    token = gfc_build_addr_expr (NULL_TREE,
+                                gfc_conv_descriptor_token (se->expr));
 
-  gfc_add_expr_to_block (&elseblock, tmp);
+  /* The allocatable variant takes the old pointer as first argument.  */
+  if (allocatable)
+    gfc_allocate_allocatable (&elseblock, pointer, size, token,
+                             status, errmsg, errlen, expr);
+  else
+    gfc_allocate_using_malloc (&elseblock, pointer, size, status);
 
-  cond = gfc_unlikely (fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
-                                       var_overflow, integer_zero_node));
-  tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond, 
-                        error, gfc_finish_block (&elseblock));
+  if (dimension)
+    {
+      cond = gfc_unlikely (fold_build2_loc (input_location, NE_EXPR,
+                          boolean_type_node, var_overflow, integer_zero_node));
+      tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond, 
+                            error, gfc_finish_block (&elseblock));
+    }
+  else
+    tmp = gfc_finish_block (&elseblock);
 
   gfc_add_expr_to_block (&se->pre, tmp);
 
-  gfc_conv_descriptor_offset_set (&se->pre, se->expr, offset);
+  /* Update the array descriptors. */
+  if (dimension)
+    gfc_conv_descriptor_offset_set (&set_descriptor_block, se->expr, offset);
+  
+  set_descriptor = gfc_finish_block (&set_descriptor_block);
+  if (status != NULL_TREE)
+    {
+      cond = fold_build2_loc (input_location, EQ_EXPR,
+                         boolean_type_node, status,
+                         build_int_cst (TREE_TYPE (status), 0));
+      gfc_add_expr_to_block (&se->pre,
+                fold_build3_loc (input_location, COND_EXPR, void_type_node,
+                                 gfc_likely (cond), set_descriptor,
+                                 build_empty_stmt (input_location))); 
+    }
+  else
+      gfc_add_expr_to_block (&se->pre, set_descriptor);
 
   if ((expr->ts.type == BT_DERIVED || expr->ts.type == BT_CLASS)
        && expr->ts.u.derived->attr.alloc_comp)
@@ -4551,7 +4822,7 @@ gfc_conv_array_initializer (tree type, gfc_expr * expr)
   gfc_se se;
   HOST_WIDE_INT hi;
   unsigned HOST_WIDE_INT lo;
-  tree index;
+  tree index, range;
   VEC(constructor_elt,gc) *v = NULL;
 
   switch (expr->expr_type)
@@ -4605,28 +4876,56 @@ gfc_conv_array_initializer (tree type, gfc_expr * expr)
           else
             index = NULL_TREE;
 
+         if (mpz_cmp_si (c->repeat, 1) > 0)
+           {
+             tree tmp1, tmp2;
+             mpz_t maxval;
+
+             mpz_init (maxval);
+             mpz_add (maxval, c->offset, c->repeat);
+             mpz_sub_ui (maxval, maxval, 1);
+             tmp2 = gfc_conv_mpz_to_tree (maxval, gfc_index_integer_kind);
+             if (mpz_cmp_si (c->offset, 0) != 0)
+               {
+                 mpz_add_ui (maxval, c->offset, 1);
+                 tmp1 = gfc_conv_mpz_to_tree (maxval, gfc_index_integer_kind);
+               }
+             else
+               tmp1 = gfc_conv_mpz_to_tree (c->offset, gfc_index_integer_kind);
+
+             range = fold_build2 (RANGE_EXPR, gfc_array_index_type, tmp1, tmp2);
+             mpz_clear (maxval);
+           }
+         else
+           range = NULL;
+
           gfc_init_se (&se, NULL);
          switch (c->expr->expr_type)
            {
            case EXPR_CONSTANT:
              gfc_conv_constant (&se, c->expr);
-             CONSTRUCTOR_APPEND_ELT (v, index, se.expr);
              break;
 
            case EXPR_STRUCTURE:
               gfc_conv_structure (&se, c->expr, 1);
-             CONSTRUCTOR_APPEND_ELT (v, index, se.expr);
              break;
 
-
            default:
              /* Catch those occasional beasts that do not simplify
                 for one reason or another, assuming that if they are
                 standard defying the frontend will catch them.  */
              gfc_conv_expr (&se, c->expr);
-             CONSTRUCTOR_APPEND_ELT (v, index, se.expr);
              break;
            }
+
+         if (range == NULL_TREE)
+           CONSTRUCTOR_APPEND_ELT (v, index, se.expr);
+         else
+           {
+             if (index != NULL_TREE)
+               CONSTRUCTOR_APPEND_ELT (v, index, se.expr);
+             CONSTRUCTOR_APPEND_ELT (v, range, se.expr);
+           }
         }
       break;
 
@@ -4644,6 +4943,43 @@ gfc_conv_array_initializer (tree type, gfc_expr * expr)
 }
 
 
+/* Generate code to evaluate non-constant coarray cobounds.  */
+
+void
+gfc_trans_array_cobounds (tree type, stmtblock_t * pblock,
+                         const gfc_symbol *sym)
+{
+  int dim;
+  tree ubound;
+  tree lbound;
+  gfc_se se;
+  gfc_array_spec *as;
+
+  as = sym->as;
+
+  for (dim = as->rank; dim < as->rank + as->corank; dim++)
+    {
+      /* Evaluate non-constant array bound expressions.  */
+      lbound = GFC_TYPE_ARRAY_LBOUND (type, dim);
+      if (as->lower[dim] && !INTEGER_CST_P (lbound))
+        {
+          gfc_init_se (&se, NULL);
+          gfc_conv_expr_type (&se, as->lower[dim], gfc_array_index_type);
+          gfc_add_block_to_block (pblock, &se.pre);
+          gfc_add_modify (pblock, lbound, se.expr);
+        }
+      ubound = GFC_TYPE_ARRAY_UBOUND (type, dim);
+      if (as->upper[dim] && !INTEGER_CST_P (ubound))
+        {
+          gfc_init_se (&se, NULL);
+          gfc_conv_expr_type (&se, as->upper[dim], gfc_array_index_type);
+          gfc_add_block_to_block (pblock, &se.pre);
+          gfc_add_modify (pblock, ubound, se.expr);
+        }
+    }
+}
+
+
 /* Generate code to evaluate non-constant array bounds.  Sets *poffset and
    returns the size (in elements) of the array.  */
 
@@ -4724,26 +5060,8 @@ gfc_trans_array_bounds (tree type, gfc_symbol * sym, tree * poffset,
 
       size = stride;
     }
-  for (dim = as->rank; dim < as->rank + as->corank; dim++)
-    {
-      /* Evaluate non-constant array bound expressions.  */
-      lbound = GFC_TYPE_ARRAY_LBOUND (type, dim);
-      if (as->lower[dim] && !INTEGER_CST_P (lbound))
-        {
-          gfc_init_se (&se, NULL);
-          gfc_conv_expr_type (&se, as->lower[dim], gfc_array_index_type);
-          gfc_add_block_to_block (pblock, &se.pre);
-          gfc_add_modify (pblock, lbound, se.expr);
-        }
-      ubound = GFC_TYPE_ARRAY_UBOUND (type, dim);
-      if (as->upper[dim] && !INTEGER_CST_P (ubound))
-        {
-          gfc_init_se (&se, NULL);
-          gfc_conv_expr_type (&se, as->upper[dim], gfc_array_index_type);
-          gfc_add_block_to_block (pblock, &se.pre);
-          gfc_add_modify (pblock, ubound, se.expr);
-        }
-    }
+
+  gfc_trans_array_cobounds (type, pblock, sym);
   gfc_trans_vla_type_sizes (sym, pblock);
 
   *poffset = offset;
@@ -4759,9 +5077,11 @@ gfc_trans_auto_array_allocation (tree decl, gfc_symbol * sym,
 {
   stmtblock_t init;
   tree type;
-  tree tmp;
+  tree tmp = NULL_TREE;
   tree size;
   tree offset;
+  tree space;
+  tree inittree;
   bool onstack;
 
   gcc_assert (!(sym->attr.pointer || sym->attr.allocatable));
@@ -4774,7 +5094,7 @@ gfc_trans_auto_array_allocation (tree decl, gfc_symbol * sym,
   gcc_assert (GFC_ARRAY_TYPE_P (type));
   onstack = TREE_CODE (type) != POINTER_TYPE;
 
-  gfc_start_block (&init);
+  gfc_init_block (&init);
 
   /* Evaluate character string length.  */
   if (sym->ts.type == BT_CHARACTER
@@ -4818,15 +5138,30 @@ gfc_trans_auto_array_allocation (tree decl, gfc_symbol * sym,
       return;
     }
 
-  /* The size is the number of elements in the array, so multiply by the
-     size of an element to get the total size.  */
-  tmp = TYPE_SIZE_UNIT (gfc_get_element_type (type));
-  size = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
-                         size, fold_convert (gfc_array_index_type, tmp));
+  if (gfc_option.flag_stack_arrays)
+    {
+      gcc_assert (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE);
+      space = build_decl (sym->declared_at.lb->location,
+                         VAR_DECL, create_tmp_var_name ("A"),
+                         TREE_TYPE (TREE_TYPE (decl)));
+      gfc_trans_vla_type_sizes (sym, &init);
+    }
+  else
+    {
+      /* The size is the number of elements in the array, so multiply by the
+        size of an element to get the total size.  */
+      tmp = TYPE_SIZE_UNIT (gfc_get_element_type (type));
+      size = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type,
+                             size, fold_convert (gfc_array_index_type, tmp));
 
-  /* Allocate memory to hold the data.  */
-  tmp = gfc_call_malloc (&init, TREE_TYPE (decl), size);
-  gfc_add_modify (&init, decl, tmp);
+      /* Allocate memory to hold the data.  */
+      tmp = gfc_call_malloc (&init, TREE_TYPE (decl), size);
+      gfc_add_modify (&init, decl, tmp);
+
+      /* Free the temporary.  */
+      tmp = gfc_call_free (convert (pvoid_type_node, decl));
+      space = NULL_TREE;
+    }
 
   /* Set offset of the array.  */
   if (TREE_CODE (GFC_TYPE_ARRAY_OFFSET (type)) == VAR_DECL)
@@ -4835,10 +5170,26 @@ gfc_trans_auto_array_allocation (tree decl, gfc_symbol * sym,
   /* Automatic arrays should not have initializers.  */
   gcc_assert (!sym->value);
 
-  /* Free the temporary.  */
-  tmp = gfc_call_free (convert (pvoid_type_node, decl));
+  inittree = gfc_finish_block (&init);
 
-  gfc_add_init_cleanup (block, gfc_finish_block (&init), tmp);
+  if (space)
+    {
+      tree addr;
+      pushdecl (space);
+
+      /* Don't create new scope, emit the DECL_EXPR in exactly the scope
+         where also space is located.  */
+      gfc_init_block (&init);
+      tmp = fold_build1_loc (input_location, DECL_EXPR,
+                            TREE_TYPE (space), space);
+      gfc_add_expr_to_block (&init, tmp);
+      addr = fold_build1_loc (sym->declared_at.lb->location,
+                             ADDR_EXPR, TREE_TYPE (decl), space);
+      gfc_add_modify (&init, decl, addr);
+      gfc_add_init_cleanup (block, gfc_finish_block (&init), NULL_TREE);
+      tmp = NULL_TREE;
+    }
+  gfc_add_init_cleanup (block, inittree, tmp);
 }
 
 
@@ -5099,7 +5450,7 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc,
                        fold_convert (long_integer_type_node, temp),
                        fold_convert (long_integer_type_node, stride2));
 
-             gfc_free (msg);
+             free (msg);
            }
        }
       else
@@ -5176,6 +5527,8 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc,
        }
     }
 
+  gfc_trans_array_cobounds (type, &init, sym);
+
   /* Set the offset.  */
   if (TREE_CODE (GFC_TYPE_ARRAY_OFFSET (type)) == VAR_DECL)
     gfc_add_modify (&init, GFC_TYPE_ARRAY_OFFSET (type), offset);
@@ -5460,15 +5813,17 @@ get_array_charlen (gfc_expr *expr, gfc_se *se)
     }
 }
 
+
 /* Helper function to check dimensions.  */
 static bool
-dim_ok (gfc_ss_info *info)
+transposed_dims (gfc_ss *ss)
 {
   int n;
-  for (n = 0; n < info->dimen; n++)
-    if (info->dim[n] != n)
-      return false;
-  return true;
+
+  for (n = 0; n < ss->dimen; n++)
+    if (ss->dim[n] != n)
+      return true;
+  return false;
 }
 
 /* Convert an array for passing as an actual argument.  Expressions and
@@ -5503,8 +5858,10 @@ dim_ok (gfc_ss_info *info)
 void
 gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
 {
+  gfc_ss_type ss_type;
+  gfc_ss_info *ss_info;
   gfc_loopinfo loop;
-  gfc_ss_info *info;
+  gfc_array_info *info;
   int need_tmp;
   int n;
   tree tmp;
@@ -5514,11 +5871,15 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
   tree offset;
   int full;
   bool subref_array_target = false;
-  gfc_expr *arg;
+  gfc_expr *arg, *ss_expr;
 
   gcc_assert (ss != NULL);
   gcc_assert (ss != gfc_ss_terminator);
 
+  ss_info = ss->info;
+  ss_type = ss_info->type;
+  ss_expr = ss_info->expr;
+
   /* Special case things we know we can pass easily.  */
   switch (expr->expr_type)
     {
@@ -5526,9 +5887,9 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
       /* If we have a linear array section, we can pass it directly.
         Otherwise we need to copy it into a temporary.  */
 
-      gcc_assert (ss->type == GFC_SS_SECTION);
-      gcc_assert (ss->expr == expr);
-      info = &ss->data.info;
+      gcc_assert (ss_type == GFC_SS_SECTION);
+      gcc_assert (ss_expr == expr);
+      info = &ss_info->data.array;
 
       /* Get the descriptor for the array.  */
       gfc_conv_ss_descriptor (&se->pre, ss, 0);
@@ -5555,7 +5916,7 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
       else
        full = gfc_full_array_ref_p (info->ref, NULL);
 
-      if (full && dim_ok (info))
+      if (full && !transposed_dims (ss))
        {
          if (se->direct_byref && !se->byref_noassign)
            {
@@ -5605,7 +5966,7 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
 
       if (se->direct_byref)
        {
-         gcc_assert (ss->type == GFC_SS_FUNCTION && ss->expr == expr);
+         gcc_assert (ss_type == GFC_SS_FUNCTION && ss_expr == expr);
 
          /* For pointer assignments pass the descriptor directly.  */
          if (se->ss == NULL)
@@ -5617,16 +5978,16 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
          return;
        }
 
-      if (ss->expr != expr || ss->type != GFC_SS_FUNCTION)
+      if (ss_expr != expr || ss_type != GFC_SS_FUNCTION)
        {
-         if (ss->expr != expr)
+         if (ss_expr != expr)
            /* Elemental function.  */
            gcc_assert ((expr->value.function.esym != NULL
                         && expr->value.function.esym->attr.elemental)
                        || (expr->value.function.isym != NULL
                            && expr->value.function.isym->elemental));
          else
-           gcc_assert (ss->type == GFC_SS_INTRINSIC);
+           gcc_assert (ss_type == GFC_SS_INTRINSIC);
 
          need_tmp = 1;
          if (expr->ts.type == BT_CHARACTER
@@ -5638,19 +5999,19 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
       else
        {
          /* Transformational function.  */
-         info = &ss->data.info;
+         info = &ss_info->data.array;
          need_tmp = 0;
        }
       break;
 
     case EXPR_ARRAY:
       /* Constant array constructors don't need a temporary.  */
-      if (ss->type == GFC_SS_CONSTRUCTOR
+      if (ss_type == GFC_SS_CONSTRUCTOR
          && expr->ts.type != BT_CHARACTER
          && gfc_constant_array_constructor_p (expr->value.constructor))
        {
          need_tmp = 0;
-         info = &ss->data.info;
+         info = &ss_info->data.array;
        }
       else
        {
@@ -5688,25 +6049,18 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
 
   if (need_tmp)
     {
-      /* Tell the scalarizer to make a temporary.  */
-      loop.temp_ss = gfc_get_ss ();
-      loop.temp_ss->type = GFC_SS_TEMP;
-      loop.temp_ss->next = gfc_ss_terminator;
-
-      if (expr->ts.type == BT_CHARACTER
-           && !expr->ts.u.cl->backend_decl)
+      if (expr->ts.type == BT_CHARACTER && !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.u.cl->backend_decl;
-      else
-       loop.temp_ss->string_length = NULL;
-
-      se->string_length = loop.temp_ss->string_length;
-      loop.temp_ss->data.temp.dimen = loop.dimen;
-      loop.temp_ss->data.temp.codimen = loop.codimen;
+      /* Tell the scalarizer to make a temporary.  */
+      loop.temp_ss = gfc_get_temp_ss (gfc_typenode_for_spec (&expr->ts),
+                                     ((expr->ts.type == BT_CHARACTER)
+                                      ? expr->ts.u.cl->backend_decl
+                                      : NULL),
+                                     loop.dimen);
+
+      se->string_length = loop.temp_ss->info->string_length;
+      gcc_assert (loop.temp_ss->dimen == loop.dimen);
       gfc_add_ss_to_loop (&loop, loop.temp_ss);
     }
 
@@ -5750,18 +6104,19 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
 
       lse.string_length = rse.string_length;
       tmp = gfc_trans_scalar_assign (&lse, &rse, expr->ts, true,
-                                    expr->expr_type == EXPR_VARIABLE, true);
+                                    expr->expr_type == EXPR_VARIABLE
+                                    || expr->expr_type == EXPR_ARRAY, true);
       gfc_add_expr_to_block (&block, tmp);
 
       /* Finish the copying loops.  */
       gfc_trans_scalarizing_loops (&loop, &block);
 
-      desc = loop.temp_ss->data.info.descriptor;
+      desc = loop.temp_ss->info->data.array.descriptor;
     }
-  else if (expr->expr_type == EXPR_FUNCTION && dim_ok (info))
+  else if (expr->expr_type == EXPR_FUNCTION && !transposed_dims (ss))
     {
       desc = info->descriptor;
-      se->string_length = ss->string_length;
+      se->string_length = ss_info->string_length;
     }
   else
     {
@@ -5778,6 +6133,35 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
       tree to;
       tree base;
 
+      ndim = info->ref ? info->ref->u.ar.dimen : ss->dimen;
+
+      if (se->want_coarray)
+       {
+         gfc_array_ref *ar = &info->ref->u.ar;
+
+         codim = gfc_get_corank (expr);
+         for (n = 0; n < codim - 1; n++)
+           {
+             /* Make sure we are not lost somehow.  */
+             gcc_assert (ar->dimen_type[n + ndim] == DIMEN_THIS_IMAGE);
+
+             /* Make sure the call to gfc_conv_section_startstride won't
+                generate unnecessary code to calculate stride.  */
+             gcc_assert (ar->stride[n + ndim] == NULL);
+
+             gfc_conv_section_startstride (&loop, ss, n + ndim);
+             loop.from[n + loop.dimen] = info->start[n + ndim];
+             loop.to[n + loop.dimen]   = info->end[n + ndim];
+           }
+
+         gcc_assert (n == codim - 1);
+         evaluate_bound (&loop.pre, info->start, ar->start,
+                         info->descriptor, n + ndim, true);
+         loop.from[n + loop.dimen] = info->start[n + ndim];
+       }
+      else
+       codim = 0;
+
       /* Set the string_length for a character array.  */
       if (expr->ts.type == BT_CHARACTER)
        se->string_length =  gfc_get_expr_charlen (expr);
@@ -5793,9 +6177,8 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
        {
          /* Otherwise make a new one.  */
          parmtype = gfc_get_element_type (TREE_TYPE (desc));
-         parmtype = gfc_get_array_type_bounds (parmtype, loop.dimen,
-                                               loop.codimen, loop.from,
-                                               loop.to, 0,
+         parmtype = gfc_get_array_type_bounds (parmtype, loop.dimen, codim,
+                                               loop.from, loop.to, 0,
                                                GFC_ARRAY_UNKNOWN, false);
          parm = gfc_create_var (parmtype, "parm");
        }
@@ -5825,8 +6208,6 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
       else
        base = NULL_TREE;
 
-      ndim = info->ref ? info->ref->u.ar.dimen : info->dimen;
-      codim = info->codimen;
       for (n = 0; n < ndim; n++)
        {
          stride = gfc_conv_array_stride (desc, n);
@@ -5836,8 +6217,8 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
              && info->ref->u.ar.dimen_type[n] == DIMEN_ELEMENT)
            {
              gcc_assert (info->subscript[n]
-                     && info->subscript[n]->type == GFC_SS_SCALAR);
-             start = info->subscript[n]->data.scalar.expr;
+                         && info->subscript[n]->info->type == GFC_SS_SCALAR);
+             start = info->subscript[n]->info->data.scalar.value;
            }
          else
            {
@@ -5867,7 +6248,7 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
  
          /* look for the corresponding scalarizer dimension: dim.  */
          for (dim = 0; dim < ndim; dim++)
-           if (info->dim[dim] == n)
+           if (ss->dim[dim] == n)
              break;
 
          /* loop exited early: the DIM being looked for has been found.  */
@@ -5928,24 +6309,15 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
                                          gfc_rank_cst[dim], stride);
        }
 
-      for (n = ndim; n < ndim + codim; n++)
+      for (n = loop.dimen; n < loop.dimen + codim; n++)
        {
-         /* look for the corresponding scalarizer dimension: dim.  */
-         for (dim = 0; dim < ndim + codim; dim++)
-           if (info->dim[dim] == n)
-             break;
-
-         /* loop exited early: the DIM being looked for has been found.  */
-         gcc_assert (dim < ndim + codim);
-
-         from = loop.from[dim];
-         to = loop.to[dim];
+         from = loop.from[n];
+         to = loop.to[n];
          gfc_conv_descriptor_lbound_set (&loop.pre, parm,
-                                         gfc_rank_cst[dim], from);
-         if (n < ndim + codim - 1)
+                                         gfc_rank_cst[n], from);
+         if (n < loop.dimen + codim - 1)
            gfc_conv_descriptor_ubound_set (&loop.pre, parm,
-                                           gfc_rank_cst[dim], to);
-         dim++;
+                                           gfc_rank_cst[n], to);
        }
 
       if (se->data_not_needed)
@@ -6282,7 +6654,7 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, gfc_ss * ss, bool g77,
 
          gfc_trans_runtime_check (false, true, tmp, &se->pre,
                                   &expr->where, msg);
-         gfc_free (msg);
+         free (msg);
        }
 
       gfc_start_block (&block);
@@ -6422,7 +6794,7 @@ duplicate_allocatable (tree dest, tree src, tree type, int rank,
          gfc_add_expr_to_block (&block, tmp);
        }
 
-      tmp = built_in_decls[BUILT_IN_MEMCPY];
+      tmp = builtin_decl_explicit (BUILT_IN_MEMCPY);
       tmp = build_call_expr_loc (input_location, tmp, 3,
                                 dest, src, size);
     }
@@ -6446,7 +6818,7 @@ duplicate_allocatable (tree dest, tree src, tree type, int rank,
 
       /* We know the temporary and the value will be the same length,
         so can use memcpy.  */
-      tmp = built_in_decls[BUILT_IN_MEMCPY];
+      tmp = builtin_decl_explicit (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);
@@ -6623,18 +6995,23 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl,
       switch (purpose)
        {
        case DEALLOCATE_ALLOC_COMP:
-         if (c->attr.allocatable && c->attr.dimension)
+         if (cmp_has_alloc_comps && !c->attr.pointer)
+           {
+             /* Do not deallocate the components of ultimate pointer
+                components.  */
+             comp = fold_build3_loc (input_location, COMPONENT_REF, ctype,
+                                     decl, cdecl, NULL_TREE);
+             rank = c->as ? c->as->rank : 0;
+             tmp = structure_alloc_comps (c->ts.u.derived, comp, NULL_TREE,
+                                          rank, purpose);
+             gfc_add_expr_to_block (&fnblock, tmp);
+           }
+
+         if (c->attr.allocatable
+             && (c->attr.dimension || c->attr.codimension))
            {
              comp = fold_build3_loc (input_location, COMPONENT_REF, ctype,
                                      decl, cdecl, NULL_TREE);
-             if (cmp_has_alloc_comps && !c->attr.pointer)
-               {
-                 /* Do not deallocate the components of ultimate pointer
-                    components.  */
-                 tmp = structure_alloc_comps (c->ts.u.derived, comp, NULL_TREE,
-                                              c->as->rank, purpose);
-                 gfc_add_expr_to_block (&fnblock, tmp);
-               }
              tmp = gfc_trans_dealloc_allocated (comp);
              gfc_add_expr_to_block (&fnblock, tmp);
            }
@@ -6678,7 +7055,8 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl,
        case NULLIFY_ALLOC_COMP:
          if (c->attr.pointer)
            continue;
-         else if (c->attr.allocatable && c->attr.dimension)
+         else if (c->attr.allocatable
+                  && (c->attr.dimension|| c->attr.codimension))
            {
              comp = fold_build3_loc (input_location, COMPONENT_REF, ctype,
                                      decl, cdecl, NULL_TREE);
@@ -6810,6 +7188,8 @@ get_std_lbound (gfc_expr *expr, tree desc, int dim, bool assumed_size)
   tree stride;
   tree cond, cond1, cond3, cond4;
   tree tmp;
+  gfc_ref *ref;
+
   if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)))
     {
       tmp = gfc_rank_cst[dim];
@@ -6843,6 +7223,14 @@ get_std_lbound (gfc_expr *expr, tree desc, int dim, bool assumed_size)
   else if (expr->expr_type == EXPR_VARIABLE)
     {
       tmp = TREE_TYPE (expr->symtree->n.sym->backend_decl);
+      for (ref = expr->ref; ref; ref = ref->next)
+       {
+         if (ref->type == REF_COMPONENT
+               && ref->u.c.component->as
+               && ref->next
+               && ref->next->u.ar.type == AR_FULL)
+           tmp = TREE_TYPE (ref->u.c.component->backend_decl);
+       }
       return GFC_TYPE_ARRAY_LBOUND(tmp, dim);
     }
   else if (expr->expr_type == EXPR_FUNCTION)
@@ -6916,6 +7304,7 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop,
   stmtblock_t fblock;
   gfc_ss *rss;
   gfc_ss *lss;
+  gfc_array_info *linfo;
   tree realloc_expr;
   tree alloc_expr;
   tree size1;
@@ -6946,11 +7335,11 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop,
       /* Find the ss for the lhs.  */
       lss = loop->ss;
       for (; lss && lss != gfc_ss_terminator; lss = lss->loop_chain)
-       if (lss->expr && lss->expr->expr_type == EXPR_VARIABLE)
+       if (lss->info->expr && lss->info->expr->expr_type == EXPR_VARIABLE)
          break;
       if (lss == gfc_ss_terminator)
        return NULL_TREE;
-      expr1 = lss->expr;
+      expr1 = lss->info->expr;
     }
 
   /* Bail out if this is not a valid allocate on assignment.  */
@@ -6961,17 +7350,19 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop,
   /* Find the ss for the lhs.  */
   lss = loop->ss;
   for (; lss && lss != gfc_ss_terminator; lss = lss->loop_chain)
-    if (lss->expr == expr1)
+    if (lss->info->expr == expr1)
       break;
 
   if (lss == gfc_ss_terminator)
     return NULL_TREE;
 
+  linfo = &lss->info->data.array;
+
   /* Find an ss for the rhs. For operator expressions, we see the
      ss's for the operands. Any one of these will do.  */
   rss = loop->ss;
   for (; rss && rss != gfc_ss_terminator; rss = rss->loop_chain)
-    if (rss->expr != expr1 && rss != loop->temp_ss)
+    if (rss->info->expr != expr1 && rss != loop->temp_ss)
       break;
 
   if (expr2 && rss == gfc_ss_terminator)
@@ -6981,7 +7372,7 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop,
 
   /* Since the lhs is allocatable, this must be a descriptor type.
      Get the data and array size.  */
-  desc = lss->data.info.descriptor;
+  desc = linfo->descriptor;
   gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)));
   array1 = gfc_conv_descriptor_data_get (desc);
 
@@ -7051,7 +7442,7 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop,
 
   /* Get the rhs size.  Fix both sizes.  */
   if (expr2)
-    desc2 = rss->data.info.descriptor;
+    desc2 = rss->info->data.array.descriptor;
   else
     desc2 = NULL_TREE;
   size2 = gfc_index_one_node;
@@ -7141,21 +7532,21 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop,
      running offset.  Use the saved_offset instead.  */
   tmp = gfc_conv_descriptor_offset (desc);
   gfc_add_modify (&fblock, tmp, offset);
-  if (lss->data.info.saved_offset
-       && TREE_CODE (lss->data.info.saved_offset) == VAR_DECL)
-      gfc_add_modify (&fblock, lss->data.info.saved_offset, tmp);
+  if (linfo->saved_offset
+      && TREE_CODE (linfo->saved_offset) == VAR_DECL)
+    gfc_add_modify (&fblock, linfo->saved_offset, tmp);
 
   /* Now set the deltas for the lhs.  */
   for (n = 0; n < expr1->rank; n++)
     {
       tmp = gfc_conv_descriptor_lbound_get (desc, gfc_rank_cst[n]);
-      dim = lss->data.info.dim[n];
+      dim = lss->dim[n];
       tmp = fold_build2_loc (input_location, MINUS_EXPR,
                             gfc_array_index_type, tmp,
                             loop->from[dim]);
-      if (lss->data.info.delta[dim]
-           && TREE_CODE (lss->data.info.delta[dim]) == VAR_DECL)
-       gfc_add_modify (&fblock, lss->data.info.delta[dim], tmp);
+      if (linfo->delta[dim]
+         && TREE_CODE (linfo->delta[dim]) == VAR_DECL)
+       gfc_add_modify (&fblock, linfo->delta[dim], tmp);
     }
 
   /* Get the new lhs size in bytes.  */
@@ -7186,7 +7577,7 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop,
      in the array reference - (*desc.data)[<element>]. */
   gfc_init_block (&realloc_block);
   tmp = build_call_expr_loc (input_location,
-                            built_in_decls[BUILT_IN_REALLOC], 2,
+                            builtin_decl_explicit (BUILT_IN_REALLOC), 2,
                             fold_convert (pvoid_type_node, array1),
                             size2);
   gfc_conv_descriptor_data_set (&realloc_block,
@@ -7202,8 +7593,8 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop,
   /* Malloc expression.  */
   gfc_init_block (&alloc_block);
   tmp = build_call_expr_loc (input_location,
-                            built_in_decls[BUILT_IN_MALLOC], 1,
-                            size2);
+                            builtin_decl_explicit (BUILT_IN_MALLOC),
+                            1, size2);
   gfc_conv_descriptor_data_set (&alloc_block,
                                desc, tmp);
   tmp = gfc_conv_descriptor_dtype (desc);
@@ -7219,11 +7610,11 @@ gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop,
   gfc_add_expr_to_block (&fblock, tmp);
 
   /* Make sure that the scalarizer data pointer is updated.  */
-  if (lss->data.info.data
-       && TREE_CODE (lss->data.info.data) == VAR_DECL)
+  if (linfo->data
+      && TREE_CODE (linfo->data) == VAR_DECL)
     {
       tmp = gfc_conv_descriptor_data_get (desc);
-      gfc_add_modify (&fblock, lss->data.info.data, tmp);
+      gfc_add_modify (&fblock, linfo->data, tmp);
     }
 
   /* Add the exit label.  */
@@ -7344,7 +7735,7 @@ gfc_trans_deferred_array (gfc_symbol * sym, gfc_wrapped_block * block)
       gfc_add_expr_to_block (&cleanup, tmp);
     }
 
-  if (sym->attr.allocatable && sym->attr.dimension
+  if (sym->attr.allocatable && (sym->attr.dimension || sym->attr.codimension)
       && !sym->attr.save && !sym->attr.result)
     {
       tmp = gfc_trans_dealloc_allocated (sym->backend_decl);
@@ -7374,29 +7765,28 @@ static gfc_ss *
 gfc_walk_variable_expr (gfc_ss * ss, gfc_expr * expr)
 {
   gfc_ref *ref;
-  gfc_array_ref *ar;
-  gfc_ss *newss;
-  int n;
 
   for (ref = expr->ref; ref; ref = ref->next)
     if (ref->type == REF_ARRAY && ref->u.ar.type != AR_ELEMENT)
       break;
 
+  return gfc_walk_array_ref (ss, expr, ref);
+}
+
+
+gfc_ss *
+gfc_walk_array_ref (gfc_ss * ss, gfc_expr * expr, gfc_ref * ref)
+{
+  gfc_array_ref *ar;
+  gfc_ss *newss;
+  int n;
+
   for (; ref; ref = ref->next)
     {
       if (ref->type == REF_SUBSTRING)
        {
-         newss = gfc_get_ss ();
-         newss->type = GFC_SS_SCALAR;
-         newss->expr = ref->u.ss.start;
-         newss->next = ss;
-         ss = newss;
-
-         newss = gfc_get_ss ();
-         newss->type = GFC_SS_SCALAR;
-         newss->expr = ref->u.ss.end;
-         newss->next = ss;
-         ss = newss;
+         ss = gfc_get_scalar_ss (ss, ref->u.ss.start);
+         ss = gfc_get_scalar_ss (ss, ref->u.ss.end);
        }
 
       /* We're only interested in array sections from now on.  */
@@ -7405,109 +7795,66 @@ gfc_walk_variable_expr (gfc_ss * ss, gfc_expr * expr)
 
       ar = &ref->u.ar;
 
-      if (ar->as->rank == 0)
-       {
-         /* Scalar coarray.  */
-         continue;
-       }
-
       switch (ar->type)
        {
        case AR_ELEMENT:
-         for (n = 0; n < ar->dimen + ar->codimen; n++)
-           {
-             newss = gfc_get_ss ();
-             newss->type = GFC_SS_SCALAR;
-             newss->expr = ar->start[n];
-             newss->next = ss;
-             ss = newss;
-           }
+         for (n = ar->dimen - 1; n >= 0; n--)
+           ss = gfc_get_scalar_ss (ss, ar->start[n]);
          break;
 
        case AR_FULL:
-         newss = gfc_get_ss ();
-         newss->type = GFC_SS_SECTION;
-         newss->expr = expr;
-         newss->next = ss;
-         newss->data.info.dimen = ar->as->rank;
-         newss->data.info.codimen = 0;
-         newss->data.info.ref = ref;
+         newss = gfc_get_array_ss (ss, expr, ar->as->rank, GFC_SS_SECTION);
+         newss->info->data.array.ref = ref;
 
          /* Make sure array is the same as array(:,:), this way
             we don't need to special case all the time.  */
          ar->dimen = ar->as->rank;
-         ar->codimen = 0;
          for (n = 0; n < ar->dimen; n++)
            {
-             newss->data.info.dim[n] = n;
              ar->dimen_type[n] = DIMEN_RANGE;
 
              gcc_assert (ar->start[n] == NULL);
              gcc_assert (ar->end[n] == NULL);
              gcc_assert (ar->stride[n] == NULL);
            }
-         for (n = ar->dimen; n < ar->dimen + ar->as->corank; n++)
-           {
-             newss->data.info.dim[n] = n;
-             ar->dimen_type[n] = DIMEN_RANGE;
-
-             gcc_assert (ar->start[n] == NULL);
-             gcc_assert (ar->end[n] == NULL);
-           }
          ss = newss;
          break;
 
        case AR_SECTION:
-         newss = gfc_get_ss ();
-         newss->type = GFC_SS_SECTION;
-         newss->expr = expr;
-         newss->next = ss;
-         newss->data.info.dimen = 0;
-         newss->data.info.codimen = 0;
-         newss->data.info.ref = ref;
-
-          /* We add SS chains for all the subscripts in the section.  */
-         for (n = 0; n < ar->dimen + ar->codimen; n++)
+         newss = gfc_get_array_ss (ss, expr, 0, GFC_SS_SECTION);
+         newss->info->data.array.ref = ref;
+
+         /* We add SS chains for all the subscripts in the section.  */
+         for (n = 0; n < ar->dimen; n++)
            {
              gfc_ss *indexss;
 
              switch (ar->dimen_type[n])
                {
-               case DIMEN_THIS_IMAGE:
-                 continue;
                case DIMEN_ELEMENT:
                  /* Add SS for elemental (scalar) subscripts.  */
                  gcc_assert (ar->start[n]);
-                 indexss = gfc_get_ss ();
-                 indexss->type = GFC_SS_SCALAR;
-                 indexss->expr = ar->start[n];
-                 indexss->next = gfc_ss_terminator;
+                 indexss = gfc_get_scalar_ss (gfc_ss_terminator, ar->start[n]);
                  indexss->loop_chain = gfc_ss_terminator;
-                 newss->data.info.subscript[n] = indexss;
+                 newss->info->data.array.subscript[n] = indexss;
                  break;
 
                case DIMEN_RANGE:
                   /* We don't add anything for sections, just remember this
                      dimension for later.  */
-                 newss->data.info.dim[newss->data.info.dimen
-                                      + newss->data.info.codimen] = n;
-                 if (n < ar->dimen)
-                   newss->data.info.dimen++;
+                 newss->dim[newss->dimen] = n;
+                 newss->dimen++;
                  break;
 
                case DIMEN_VECTOR:
                  /* Create a GFC_SS_VECTOR index in which we can store
                     the vector's descriptor.  */
-                 indexss = gfc_get_ss ();
-                 indexss->type = GFC_SS_VECTOR;
-                 indexss->expr = ar->start[n];
-                 indexss->next = gfc_ss_terminator;
+                 indexss = gfc_get_array_ss (gfc_ss_terminator, ar->start[n],
+                                             1, GFC_SS_VECTOR);
                  indexss->loop_chain = gfc_ss_terminator;
-                 newss->data.info.subscript[n] = indexss;
-                 newss->data.info.dim[newss->data.info.dimen
-                                      + newss->data.info.codimen] = n;
-                 if (n < ar->dimen)
-                   newss->data.info.dimen++;
+                 newss->info->data.array.subscript[n] = indexss;
+                 newss->dim[newss->dimen] = n;
+                 newss->dimen++;
                  break;
 
                default:
@@ -7515,8 +7862,10 @@ gfc_walk_variable_expr (gfc_ss * ss, gfc_expr * expr)
                  gcc_unreachable ();
                }
            }
-         /* We should have at least one non-elemental dimension.  */
-         gcc_assert (newss->data.info.dimen > 0);
+         /* We should have at least one non-elemental dimension,
+            unless we are creating a descriptor for a (scalar) coarray.  */
+         gcc_assert (newss->dimen > 0
+                     || newss->info->data.array.ref->u.ar.as->corank > 0);
          ss = newss;
          break;
 
@@ -7538,7 +7887,6 @@ gfc_walk_op_expr (gfc_ss * ss, gfc_expr * expr)
 {
   gfc_ss *head;
   gfc_ss *head2;
-  gfc_ss *newss;
 
   head = gfc_walk_subexpr (ss, expr->value.op.op1);
   if (expr->value.op.op2 == NULL)
@@ -7556,8 +7904,6 @@ gfc_walk_op_expr (gfc_ss * ss, gfc_expr * expr)
 
   /* One of the operands needs scalarization, the other is scalar.
      Create a gfc_ss for the scalar expression.  */
-  newss = gfc_get_ss ();
-  newss->type = GFC_SS_SCALAR;
   if (head == ss)
     {
       /* First operand is scalar.  We build the chain in reverse order, so
@@ -7567,17 +7913,13 @@ gfc_walk_op_expr (gfc_ss * ss, gfc_expr * expr)
        head = head->next;
       /* Check we haven't somehow broken the chain.  */
       gcc_assert (head);
-      newss->next = ss;
-      head->next = newss;
-      newss->expr = expr->value.op.op1;
+      head->next = gfc_get_scalar_ss (ss, expr->value.op.op1);
     }
   else                         /* head2 == head */
     {
       gcc_assert (head2 == head);
       /* Second operand is scalar.  */
-      newss->next = head2;
-      head2 = newss;
-      newss->expr = expr->value.op.op2;
+      head2 = gfc_get_scalar_ss (head2, expr->value.op.op2);
     }
 
   return head2;
@@ -7632,10 +7974,9 @@ gfc_walk_elemental_function_args (gfc_ss * ss, gfc_actual_arglist *arg,
       if (newss == head)
        {
          /* Scalar argument.  */
-         newss = gfc_get_ss ();
-         newss->type = type;
-         newss->expr = arg->expr;
-         newss->next = head;
+         gcc_assert (type == GFC_SS_SCALAR || type == GFC_SS_REFERENCE);
+         newss = gfc_get_scalar_ss (head, arg->expr);
+         newss->info->type = type;
        }
       else
        scalar = 0;
@@ -7672,11 +8013,9 @@ gfc_walk_elemental_function_args (gfc_ss * ss, gfc_actual_arglist *arg,
 static gfc_ss *
 gfc_walk_function_expr (gfc_ss * ss, gfc_expr * expr)
 {
-  gfc_ss *newss;
   gfc_intrinsic_sym *isym;
   gfc_symbol *sym;
   gfc_component *comp = NULL;
-  int n;
 
   isym = expr->value.function.isym;
 
@@ -7692,16 +8031,7 @@ gfc_walk_function_expr (gfc_ss * ss, gfc_expr * expr)
   gfc_is_proc_ptr_comp (expr, &comp);
   if ((!comp && gfc_return_by_reference (sym) && sym->result->attr.dimension)
       || (comp && comp->attr.dimension))
-    {
-      newss = gfc_get_ss ();
-      newss->type = GFC_SS_FUNCTION;
-      newss->expr = expr;
-      newss->next = ss;
-      newss->data.info.dimen = expr->rank;
-      for (n = 0; n < newss->data.info.dimen; n++)
-       newss->data.info.dim[n] = n;
-      return newss;
-    }
+    return gfc_get_array_ss (ss, expr, expr->rank, GFC_SS_FUNCTION);
 
   /* Walk the parameters of an elemental function.  For now we always pass
      by reference.  */
@@ -7720,18 +8050,7 @@ gfc_walk_function_expr (gfc_ss * ss, gfc_expr * expr)
 static gfc_ss *
 gfc_walk_array_constructor (gfc_ss * ss, gfc_expr * expr)
 {
-  gfc_ss *newss;
-  int n;
-
-  newss = gfc_get_ss ();
-  newss->type = GFC_SS_CONSTRUCTOR;
-  newss->expr = expr;
-  newss->next = ss;
-  newss->data.info.dimen = expr->rank;
-  for (n = 0; n < expr->rank; n++)
-    newss->data.info.dim[n] = n;
-
-  return newss;
+  return gfc_get_array_ss (ss, expr, expr->rank, GFC_SS_CONSTRUCTOR);
 }