OSDN Git Service

* trans.h (struct gfc_ss, struct gfc_ss_info): Move member struct
[pf3gnuchains/gcc-fork.git] / gcc / fortran / trans-array.c
index 3d5e5ba..173e52b 100644 (file)
@@ -1,5 +1,6 @@
 /* Array translation routines
-   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+   Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+   2011
    Free Software Foundation, Inc.
    Contributed by Paul Brook <paul@nowt.org>
    and Steven Bosscher <s.bosscher@student.tudelft.nl>
@@ -80,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"
@@ -127,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
@@ -265,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)
 {
@@ -427,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
@@ -463,20 +486,30 @@ gfc_free_ss_chain (gfc_ss * ss)
 }
 
 
+static void
+free_ss_info (gfc_ss_info *ss_info)
+{
+  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->data.info.subscript[ss->dim[n]])
+           gfc_free_ss_chain (ss->data.info.subscript[ss->dim[n]]);
        }
       break;
 
@@ -484,7 +517,77 @@ 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->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->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->type = GFC_SS_SCALAR;
+  ss_info->expr = expr;
+
+  ss = gfc_get_ss ();
+  ss->info = ss_info;
+  ss->next = next;
+
+  return ss;
 }
 
 
@@ -563,7 +666,7 @@ gfc_set_loop_bounds_from_array_spec (gfc_interface_mapping * mapping,
   if (as && as->type == AS_EXPLICIT)
     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)
@@ -606,7 +709,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;
@@ -625,18 +728,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);
        }
@@ -719,15 +831,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;
@@ -750,10 +862,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;
@@ -767,8 +880,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->data.info;
+
+  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);
@@ -776,7 +891,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])
@@ -793,7 +908,7 @@ gfc_trans_create_temp_array (stmtblock_t * pre, stmtblock_t * post,
         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];
 
@@ -805,7 +920,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;
@@ -843,7 +958,7 @@ gfc_trans_create_temp_array (stmtblock_t * pre, stmtblock_t * post,
 
   for (n = 0; n < loop->dimen; n++)
     {
-      dim = info->dim[n];
+      dim = ss->dim[n];
 
       if (size == NULL_TREE)
        {
@@ -851,8 +966,8 @@ gfc_trans_create_temp_array (stmtblock_t * pre, stmtblock_t * post,
             of the descriptor fields.  */
          tmp = fold_build2_loc (input_location,
                MINUS_EXPR, gfc_array_index_type,
-               gfc_conv_descriptor_ubound_get (desc, gfc_rank_cst[n]),
-               gfc_conv_descriptor_lbound_get (desc, gfc_rank_cst[n]));
+               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;
        }
@@ -909,8 +1024,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;
 }
@@ -1342,7 +1457,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);
@@ -1368,10 +1483,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,
@@ -1494,11 +1609,55 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
 }
 
 
+/* A catch-all to obtain the string length for anything that is not a
+   a substring of non-constant length, a constant, array or variable.  */
+
+static void
+get_array_ctor_all_strlen (stmtblock_t *block, gfc_expr *e, tree *len)
+{
+  gfc_se se;
+  gfc_ss *ss;
+
+  /* Don't bother if we already know the length is a constant.  */
+  if (*len && INTEGER_CST_P (*len))
+    return;
+
+  if (!e->ref && e->ts.u.cl && e->ts.u.cl->length
+       && e->ts.u.cl->length->expr_type == EXPR_CONSTANT)
+    {
+      /* This is easy.  */
+      gfc_conv_const_charlen (e->ts.u.cl);
+      *len = e->ts.u.cl->backend_decl;
+    }
+  else
+    {
+      /* Otherwise, be brutal even if inefficient.  */
+      ss = gfc_walk_expr (e);
+      gfc_init_se (&se, NULL);
+
+      /* No function call, in case of side effects.  */
+      se.no_function_call = 1;
+      if (ss == gfc_ss_terminator)
+       gfc_conv_expr (&se, e);
+      else
+       gfc_conv_expr_descriptor (&se, e, ss);
+
+      /* Fix the value.  */
+      *len = gfc_evaluate_now (se.string_length, &se.pre);
+
+      gfc_add_block_to_block (block, &se.pre);
+      gfc_add_block_to_block (block, &se.post);
+
+      e->ts.u.cl->backend_decl = *len;
+    }
+}
+
+
 /* Figure out the string length of a variable reference expression.
    Used by get_array_ctor_strlen.  */
 
 static void
-get_array_ctor_var_strlen (gfc_expr * expr, tree * len)
+get_array_ctor_var_strlen (stmtblock_t *block, gfc_expr * expr, tree * len)
 {
   gfc_ref *ref;
   gfc_typespec *ts;
@@ -1525,7 +1684,11 @@ get_array_ctor_var_strlen (gfc_expr * expr, tree * len)
        case REF_SUBSTRING:
          if (ref->u.ss.start->expr_type != EXPR_CONSTANT
              || ref->u.ss.end->expr_type != EXPR_CONSTANT)
-           break;
+           {
+             /* Note that this might evaluate expr.  */
+             get_array_ctor_all_strlen (block, expr, len);
+             return;
+           }
          mpz_init_set_ui (char_len, 1);
          mpz_add (char_len, char_len, ref->u.ss.end->value.integer);
          mpz_sub (char_len, char_len, ref->u.ss.start->value.integer);
@@ -1535,10 +1698,7 @@ get_array_ctor_var_strlen (gfc_expr * expr, tree * len)
          return;
 
        default:
-         /* TODO: Substrings are tricky because we can't evaluate the
-            expression more than once.  For now we just give up, and hope
-            we can figure it out elsewhere.  */
-         return;
+        gcc_unreachable ();
        }
     }
 
@@ -1546,49 +1706,6 @@ get_array_ctor_var_strlen (gfc_expr * expr, tree * len)
 }
 
 
-/* A catch-all to obtain the string length for anything that is not a
-   constant, array or variable.  */
-static void
-get_array_ctor_all_strlen (stmtblock_t *block, gfc_expr *e, tree *len)
-{
-  gfc_se se;
-  gfc_ss *ss;
-
-  /* Don't bother if we already know the length is a constant.  */
-  if (*len && INTEGER_CST_P (*len))
-    return;
-
-  if (!e->ref && e->ts.u.cl && e->ts.u.cl->length
-       && e->ts.u.cl->length->expr_type == EXPR_CONSTANT)
-    {
-      /* This is easy.  */
-      gfc_conv_const_charlen (e->ts.u.cl);
-      *len = e->ts.u.cl->backend_decl;
-    }
-  else
-    {
-      /* Otherwise, be brutal even if inefficient.  */
-      ss = gfc_walk_expr (e);
-      gfc_init_se (&se, NULL);
-
-      /* No function call, in case of side effects.  */
-      se.no_function_call = 1;
-      if (ss == gfc_ss_terminator)
-       gfc_conv_expr (&se, e);
-      else
-       gfc_conv_expr_descriptor (&se, e, ss);
-
-      /* Fix the value.  */
-      *len = gfc_evaluate_now (se.string_length, &se.pre);
-
-      gfc_add_block_to_block (block, &se.pre);
-      gfc_add_block_to_block (block, &se.post);
-
-      e->ts.u.cl->backend_decl = *len;
-    }
-}
-
-
 /* Figure out the string length of a character array constructor.
    If len is NULL, don't calculate the length; this happens for recursive calls
    when a sub-array-constructor is an element but not at the first position,
@@ -1632,7 +1749,7 @@ get_array_ctor_strlen (stmtblock_t *block, gfc_constructor_base base, tree * len
        case EXPR_VARIABLE:
          is_const = false;
          if (len)
-           get_array_ctor_var_strlen (c->expr, len);
+           get_array_ctor_var_strlen (block, c->expr, len);
          break;
 
        default:
@@ -1759,14 +1876,13 @@ 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;
 
@@ -1774,22 +1890,18 @@ gfc_trans_constant_array_constructor (gfc_loopinfo * loop,
   info->data = gfc_build_addr_expr (NULL_TREE, tmp);
   info->offset = gfc_index_zero_node;
 
-  for (i = 0; i < info->dimen; 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
@@ -1837,78 +1949,84 @@ gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss, locus * where)
   tree offsetvar;
   tree desc;
   tree type;
+  tree tmp;
   bool dynamic;
   bool old_first_len, old_typespec_chararray_ctor;
   tree old_first_len_val;
+  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;
 
+  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,
@@ -1943,13 +2061,16 @@ 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;
            }
        }
     }
 
-  gfc_trans_create_temp_array (&loop->pre, &loop->post, loop, &ss->data.info,
+  if (TREE_CODE (loop->to[0]) == VAR_DECL)
+    dynamic = true;
+
+  gfc_trans_create_temp_array (&loop->pre, &loop->post, loop, ss,
                               type, NULL_TREE, dynamic, true, false, where);
 
   desc = ss->data.info.descriptor;
@@ -1963,12 +2084,23 @@ gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss, locus * where)
   /* If the array grows dynamically, the upper bound of the loop variable
      is determined by the array's final upper bound.  */
   if (dynamic)
-    loop->to[0] = gfc_conv_descriptor_ubound_get (desc, gfc_rank_cst[0]);
+    {
+      tmp = fold_build2_loc (input_location, MINUS_EXPR,
+                            gfc_array_index_type,
+                            offsetvar, gfc_index_one_node);
+      tmp = gfc_evaluate_now (tmp, &loop->pre);
+      gfc_conv_descriptor_ubound_set (&loop->pre, desc, gfc_rank_cst[0], tmp);
+      if (loop->to[0] && TREE_CODE (loop->to[0]) == VAR_DECL)
+       gfc_add_modify (&loop->pre, loop->to[0], tmp);
+      else
+       loop->to[0] = tmp;
+    }
 
   if (TREE_USED (offsetvar))
     pushdecl (offsetvar);
   else
     gcc_assert (INTEGER_CST_P (offset));
+
 #if 0
   /* Disable bound checking for now because it's probably broken.  */
   if (gfc_option.rtcheck & GFC_RTCHECK_BOUNDS)
@@ -1991,8 +2123,9 @@ finish:
    loop bounds.  */
 
 static void
-gfc_set_vector_loop_bounds (gfc_loopinfo * loop, gfc_ss_info * info)
+set_vector_loop_bounds (gfc_loopinfo * loop, gfc_ss * ss)
 {
+  gfc_array_info *info;
   gfc_se se;
   tree tmp;
   tree desc;
@@ -2000,9 +2133,11 @@ gfc_set_vector_loop_bounds (gfc_loopinfo * loop, gfc_ss_info * info)
   int n;
   int dim;
 
+  info = &ss->data.info;
+
   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)
        {
@@ -2011,7 +2146,7 @@ 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;
@@ -2036,6 +2171,8 @@ gfc_add_loop_ss_code (gfc_loopinfo * loop, gfc_ss * ss, bool subscript,
                      locus * where)
 {
   gfc_se se;
+  gfc_ss_info *ss_info;
+  gfc_expr *expr;
   int n;
 
   /* TODO: This can generate bad code if there are ordering dependencies,
@@ -2046,16 +2183,19 @@ 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;
+
+      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.  */
@@ -2068,20 +2208,20 @@ gfc_add_loop_ss_code (gfc_loopinfo * loop, gfc_ss * ss, bool subscript,
          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:
@@ -2091,13 +2231,13 @@ gfc_add_loop_ss_code (gfc_loopinfo * loop, gfc_ss * ss, bool subscript,
              gfc_add_loop_ss_code (loop, ss->data.info.subscript[n], true,
                                    where);
 
-         gfc_set_vector_loop_bounds (loop, &ss->data.info);
+         set_vector_loop_bounds (loop, 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;
@@ -2113,22 +2253,22 @@ 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);
            }
@@ -2154,16 +2294,19 @@ static void
 gfc_conv_ss_descriptor (stmtblock_t * block, gfc_ss * ss, int base)
 {
   gfc_se se;
+  gfc_ss_info *ss_info;
   tree tmp;
 
+  ss_info = ss->info;
+
   /* 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;
+  ss_info->string_length = se.string_length;
 
   if (base)
     {
@@ -2181,6 +2324,11 @@ gfc_conv_ss_descriptor (stmtblock_t * block, gfc_ss * ss, int base)
 
       tmp = gfc_conv_array_offset (se.expr);
       ss->data.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;
     }
 }
 
@@ -2200,7 +2348,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;
@@ -2321,42 +2469,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->data.info.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));
@@ -2386,7 +2517,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
     {
@@ -2404,7 +2535,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;
@@ -2416,36 +2547,41 @@ 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->data.info;
+
   /* Get the index into the array for this dimension.  */
   if (ar)
     {
       gcc_assert (ar->type != AR_ELEMENT);
       switch (ar->dimen_type[dim])
        {
+       case DIMEN_THIS_IMAGE:
+         gcc_unreachable ();
+         break;
        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);
+                     && info->subscript[dim]->info->type == GFC_SS_VECTOR);
          desc = info->subscript[dim]->data.info.descriptor;
 
          /* Get a zero-based index into the vector.  */
@@ -2466,10 +2602,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:
@@ -2497,6 +2632,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]);
@@ -2516,31 +2663,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->data.info;
   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);
 }
 
@@ -2550,11 +2699,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
@@ -2567,14 +2732,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)
@@ -2584,10 +2767,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);
@@ -2622,7 +2807,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.  */
@@ -2646,7 +2831,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);
            }
        }
 
@@ -2656,19 +2841,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->data.info;
+
+  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);
 }
 
 
@@ -2679,11 +2889,11 @@ 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_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
@@ -2693,83 +2903,58 @@ gfc_trans_preloop_setup (gfc_loopinfo * loop, int dim, int flag,
       if ((ss->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;
 
-      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)
@@ -2956,7 +3141,7 @@ 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)
+  for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain)
     ss->useflags = 0;
 }
 
@@ -2989,12 +3174,16 @@ 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)
     {
+      gfc_ss_type ss_type;
+
       if ((ss->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;
@@ -3017,71 +3206,78 @@ gfc_trans_scalarized_loop_boundary (gfc_loopinfo * loop, stmtblock_t * body)
 }
 
 
-/* Calculate the lower bound of an array section.  */
+/* 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
-gfc_conv_section_startstride (gfc_loopinfo * loop, gfc_ss * ss, int dim)
+evaluate_bound (stmtblock_t *block, tree *bounds, gfc_expr ** values,
+               tree desc, int dim, bool lbound)
 {
-  gfc_expr *start;
-  gfc_expr *end;
-  gfc_expr *stride;
-  tree desc;
   gfc_se se;
-  gfc_ss_info *info;
-
-  gcc_assert (ss->type == GFC_SS_SECTION);
+  gfc_expr * input_val = values[dim];
+  tree *output = &bounds[dim];
 
-  info = &ss->data.info;
 
-  if (info->ref->u.ar.dimen_type[dim] == DIMEN_VECTOR)
+  if (input_val)
     {
-      /* We use a zero-based index to access the vector.  */
-      info->start[dim] = gfc_index_zero_node;
-      info->stride[dim] = gfc_index_one_node;
-      info->end[dim] = NULL;
-      return;
+      /* 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)
+{
+  gfc_expr *stride = NULL;
+  tree desc;
+  gfc_se se;
+  gfc_array_info *info;
+  gfc_array_ref *ar;
+
+  gcc_assert (ss->info->type == GFC_SS_SECTION);
 
-  gcc_assert (info->ref->u.ar.dimen_type[dim] == DIMEN_RANGE);
+  info = &ss->data.info;
+  ar = &info->ref->u.ar;
+
+  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;
+      info->stride[dim] = gfc_index_one_node;
+      return;
+    }
+
+  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];
-  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 (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 (stride == NULL)
@@ -3110,25 +3306,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;
-         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;
+           case GFC_ISYM_LCOBOUND:
+           case GFC_ISYM_UCOBOUND:
+           case GFC_ISYM_THIS_IMAGE:
+             loop->dimen = ss->dimen;
+             goto done;
 
            default:
              break;
@@ -3141,42 +3340,57 @@ 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 != 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->data.info;
 
-      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]);
+         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:
            case GFC_ISYM_UBOUND:
+           case GFC_ISYM_LCOBOUND:
+           case GFC_ISYM_UCOBOUND:
+           case GFC_ISYM_THIS_IMAGE:
              break;
+
            default:
              continue;
            }
 
        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];
+
+             ss->data.info.start[dim]  = gfc_index_zero_node;
+             ss->data.info.end[dim]    = gfc_index_zero_node;
+             ss->data.info.stride[dim] = gfc_index_one_node;
            }
          break;
 
@@ -3193,7 +3407,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;
 
@@ -3205,10 +3419,23 @@ 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.  */
@@ -3220,7 +3447,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;
 
@@ -3234,10 +3461,10 @@ 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;
 
@@ -3293,18 +3520,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
                {
@@ -3315,12 +3542,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
@@ -3347,29 +3574,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.  */
@@ -3393,14 +3620,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);
@@ -3410,10 +3637,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);
@@ -3425,6 +3652,37 @@ gfc_conv_ss_startstride (gfc_loopinfo * loop)
     }
 }
 
+/* Return true if both symbols could refer to the same data object.  Does
+   not take account of aliasing due to equivalence statements.  */
+
+static int
+symbols_could_alias (gfc_symbol *lsym, gfc_symbol *rsym, bool lsym_pointer,
+                    bool lsym_target, bool rsym_pointer, bool rsym_target)
+{
+  /* Aliasing isn't possible if the symbols have different base types.  */
+  if (gfc_compare_types (&lsym->ts, &rsym->ts) == 0)
+    return 0;
+
+  /* Pointers can point to other pointers and target objects.  */
+
+  if ((lsym_pointer && (rsym_pointer || rsym_target))
+      || (rsym_pointer && (lsym_pointer || lsym_target)))
+    return 1;
+
+  /* Special case: Argument association, cf. F90 12.4.1.6, F2003 12.4.1.7
+     and F2008 12.5.2.13 items 3b and 4b. The pointer case (a) is already
+     checked above.  */
+  if (lsym_target && rsym_target
+      && ((lsym->attr.dummy && !lsym->attr.contiguous
+          && (!lsym->attr.dimension || lsym->as->type == AS_ASSUMED_SHAPE))
+         || (rsym->attr.dummy && !rsym->attr.contiguous
+             && (!rsym->attr.dimension
+                 || rsym->as->type == AS_ASSUMED_SHAPE))))
+    return 1;
+
+  return 0;
+}
+
 
 /* Return true if the two SS could be aliased, i.e. both point to the same data
    object.  */
@@ -3435,47 +3693,107 @@ 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;
-  if (gfc_symbols_could_alias (lsym, rsym))
+  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;
+  rsym_pointer = rsym->attr.pointer;
+  rsym_target = rsym->attr.target;
+
+  if (symbols_could_alias (lsym, rsym, lsym_pointer, lsym_target,
+                          rsym_pointer, rsym_target))
     return 1;
 
-  if (rsym->ts.type != BT_DERIVED
-      && lsym->ts.type != BT_DERIVED)
+  if (rsym->ts.type != BT_DERIVED && rsym->ts.type != BT_CLASS
+      && lsym->ts.type != BT_DERIVED && lsym->ts.type != BT_CLASS)
     return 0;
 
   /* 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->data.info.ref; lref = lref->next)
     {
       if (lref->type != REF_COMPONENT)
        continue;
 
-      if (gfc_symbols_could_alias (lref->u.c.sym, rsym))
+      lsym_pointer = lsym_pointer || lref->u.c.sym->attr.pointer;
+      lsym_target  = lsym_target  || lref->u.c.sym->attr.target;
+
+      if (symbols_could_alias (lref->u.c.sym, rsym, lsym_pointer, lsym_target,
+                              rsym_pointer, rsym_target))
        return 1;
 
-      for (rref = rss->expr->ref; rref != rss->data.info.ref;
+      if ((lsym_pointer && (rsym_pointer || rsym_target))
+         || (rsym_pointer && (lsym_pointer || lsym_target)))
+       {
+         if (gfc_compare_types (&lref->u.c.component->ts,
+                                &rsym->ts))
+           return 1;
+       }
+
+      for (rref = rexpr->ref; rref != rss->data.info.ref;
           rref = rref->next)
        {
          if (rref->type != REF_COMPONENT)
            continue;
 
-         if (gfc_symbols_could_alias (lref->u.c.sym, rref->u.c.sym))
+         rsym_pointer = rsym_pointer || rref->u.c.sym->attr.pointer;
+         rsym_target  = lsym_target  || rref->u.c.sym->attr.target;
+
+         if (symbols_could_alias (lref->u.c.sym, rref->u.c.sym,
+                                  lsym_pointer, lsym_target,
+                                  rsym_pointer, rsym_target))
            return 1;
+
+         if ((lsym_pointer && (rsym_pointer || rsym_target))
+             || (rsym_pointer && (lsym_pointer || lsym_target)))
+           {
+             if (gfc_compare_types (&lref->u.c.component->ts,
+                                    &rref->u.c.sym->ts))
+               return 1;
+             if (gfc_compare_types (&lref->u.c.sym->ts,
+                                    &rref->u.c.component->ts))
+               return 1;
+             if (gfc_compare_types (&lref->u.c.component->ts,
+                                    &rref->u.c.component->ts))
+               return 1;
+           }
        }
     }
 
-  for (rref = rss->expr->ref; rref != rss->data.info.ref; rref = rref->next)
+  lsym_pointer = lsym->attr.pointer;
+  lsym_target = lsym->attr.target;
+  lsym_pointer = lsym->attr.pointer;
+  lsym_target = lsym->attr.target;
+
+  for (rref = rexpr->ref; rref != rss->data.info.ref; rref = rref->next)
     {
       if (rref->type != REF_COMPONENT)
        break;
 
-      if (gfc_symbols_could_alias (rref->u.c.sym, lsym))
+      rsym_pointer = rsym_pointer || rref->u.c.sym->attr.pointer;
+      rsym_target  = lsym_target  || rref->u.c.sym->attr.target;
+
+      if (symbols_could_alias (rref->u.c.sym, lsym,
+                              lsym_pointer, lsym_target,
+                              rsym_pointer, rsym_target))
        return 1;
+
+      if ((lsym_pointer && (rsym_pointer || rsym_target))
+         || (rsym_pointer && (lsym_pointer || lsym_target)))
+       {
+         if (gfc_compare_types (&lsym->ts, &rref->u.c.component->ts))
+           return 1;
+       }
     }
 
   return 0;
@@ -3493,20 +3811,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;
@@ -3514,18 +3837,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.  */
@@ -3574,16 +3897,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->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
@@ -3601,9 +3920,9 @@ void
 gfc_conv_loop_setup (gfc_loopinfo * loop, locus * where)
 {
   int n, dim, spec_dim;
-  gfc_ss_info *info;
-  gfc_ss_info *specinfo;
-  gfc_ss *ss;
+  gfc_array_info *info;
+  gfc_array_info *specinfo;
+  gfc_ss *ss, *tmp_ss;
   tree tmp;
   gfc_ss *loopspec[GFC_MAX_DIMENSIONS];
   bool dynamic[GFC_MAX_DIMENSIONS];
@@ -3619,16 +3938,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];
+         dim = ss->dim[n];
 
          if (loopspec[n] != NULL)
            {
              specinfo = &loopspec[n]->data.info;
-             spec_dim = specinfo->dim[n];
+             spec_dim = loopspec[n]->dim[n];
            }
          else
            {
@@ -3637,19 +3961,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.
@@ -3661,7 +3985,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;
@@ -3670,13 +3994,18 @@ 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;
            }
 
-         if (ss->type != GFC_SS_SECTION)
+         /* Avoid using an allocatable lhs in an assignment, since
+            there might be a reallocation coming.  */
+         if (loopspec[n] && ss->is_alloc_lhs)
+           continue;
+
+         if (ss_type != GFC_SS_SECTION)
            continue;
 
          if (!loopspec[n])
@@ -3688,7 +4017,8 @@ 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])
                   && !integer_onep (specinfo->stride[spec_dim]))
@@ -3710,15 +4040,15 @@ gfc_conv_loop_setup (gfc_loopinfo * loop, locus * where)
       gcc_assert (loopspec[n]);
 
       info = &loopspec[n]->data.info;
-      dim = info->dim[n];
+      dim = loopspec[n]->dim[n];
 
       /* Set the extents of this range.  */
-      cshape = loopspec[n]->shape;
+      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);
@@ -3733,7 +4063,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
@@ -3758,9 +4088,9 @@ gfc_conv_loop_setup (gfc_loopinfo * loop, locus * where)
        }
 
       /* Transform everything so we have a simple incrementing variable.  */
-      if (integer_onep (info->stride[dim]))
+      if (n < loop->dimen && integer_onep (info->stride[dim]))
        info->delta[dim] = gfc_index_zero_node;
-      else
+      else if (n < loop->dimen)
        {
          /* Set the delta for this section.  */
          info->delta[dim] = gfc_evaluate_now (loop->from[n], &loop->pre);
@@ -3786,30 +4116,30 @@ gfc_conv_loop_setup (gfc_loopinfo * loop, locus * where)
      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 (&loop->temp_ss->data.info, 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);
     }
 
@@ -3826,19 +4156,22 @@ gfc_conv_loop_setup (gfc_loopinfo * loop, locus * where)
   /* 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;
 
-      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.  */
@@ -3893,17 +4226,17 @@ gfc_conv_array_extent_dim (tree lbound, tree ubound, tree* or_expr)
 
 
 /* For an array descriptor, get the total number of elements.  This is just
-   the product of the extents along all dimensions.  */
+   the product of the extents along from_dim to to_dim.  */
 
-tree
-gfc_conv_descriptor_size (tree desc, int rank)
+static tree
+gfc_conv_descriptor_size_1 (tree desc, int from_dim, int to_dim)
 {
   tree res;
   int dim;
 
   res = gfc_index_one_node;
 
-  for (dim = 0; dim < rank; ++dim)
+  for (dim = from_dim; dim < to_dim; ++dim)
     {
       tree lbound;
       tree ubound;
@@ -3921,9 +4254,29 @@ gfc_conv_descriptor_size (tree desc, int rank)
 }
 
 
-/* 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.  Returns the size of the array.
+/* Full size of an array.  */
+
+tree
+gfc_conv_descriptor_size (tree desc, int rank)
+{
+  return gfc_conv_descriptor_size_1 (desc, 0, rank);
+}
+
+
+/* Size of a coarray for all dimensions but the last.  */
+
+tree
+gfc_conv_descriptor_cosize (tree desc, int rank, int corank)
+{
+  return gfc_conv_descriptor_size_1 (desc, rank, rank + corank - 1);
+}
+
+
+/* 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,
+   which should be of integer type, will increase in value if overflow
+   occurs during the size calculation.  Returns the size of the array.
    {
     stride = 1;
     offset = 0;
@@ -3934,26 +4287,37 @@ gfc_conv_descriptor_size (tree desc, int rank)
        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;
     return (stride);
    }  */
 /*GCC ARRAYS*/
 
 static tree
 gfc_array_init_size (tree descriptor, int rank, int corank, tree * poffset,
-                    gfc_expr ** lower, gfc_expr ** upper,
-                    stmtblock_t * pblock)
+                    gfc_expr ** lower, gfc_expr ** upper, stmtblock_t * pblock,
+                    stmtblock_t * descriptor_block, tree * overflow)
 {
   tree type;
   tree tmp;
   tree size;
   tree offset;
   tree stride;
+  tree element_size;
   tree or_expr;
   tree thencase;
   tree elsecase;
+  tree cond;
   tree var;
   stmtblock_t thenblock;
   stmtblock_t elseblock;
@@ -3968,7 +4332,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;
 
@@ -4001,8 +4365,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.  */
@@ -4017,17 +4381,41 @@ 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.  */
       size = gfc_conv_array_extent_dim (conv_lbound, conv_ubound, &or_expr);
-
+      size = gfc_evaluate_now (size, pblock);
+
+      /* Check whether multiplying the stride by the number of
+        elements in this dimension would overflow. We must also check
+        whether the current dimension has zero size in order to avoid
+        division by zero. 
+      */
+      tmp = fold_build2_loc (input_location, TRUNC_DIV_EXPR, 
+                            gfc_array_index_type, 
+                            fold_convert (gfc_array_index_type, 
+                                          TYPE_MAX_VALUE (gfc_array_index_type)),
+                                          size);
+      cond = gfc_unlikely (fold_build2_loc (input_location, LT_EXPR,
+                                           boolean_type_node, tmp, stride));
+      tmp = fold_build3_loc (input_location, COND_EXPR, integer_type_node, cond,
+                            integer_one_node, integer_zero_node);
+      cond = gfc_unlikely (fold_build2_loc (input_location, EQ_EXPR,
+                                           boolean_type_node, size,
+                                           gfc_index_zero_node));
+      tmp = fold_build3_loc (input_location, COND_EXPR, integer_type_node, cond,
+                            integer_zero_node, tmp);
+      tmp = fold_build2_loc (input_location, PLUS_EXPR, integer_type_node,
+                            *overflow, tmp);
+      *overflow = gfc_evaluate_now (tmp, pblock);
+      
       /* Multiply the stride by the number of elements in this dimension.  */
       stride = fold_build2_loc (input_location, MULT_EXPR,
                                gfc_array_index_type, stride, size);
@@ -4058,8 +4446,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)
        {
@@ -4067,7 +4455,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);
        }
     }
@@ -4075,8 +4463,35 @@ gfc_array_init_size (tree descriptor, int rank, int corank, tree * poffset,
   /* The stride 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,
-                         stride, fold_convert (gfc_array_index_type, tmp));
+  /* 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
+     have zero element_size, we must check for that before
+     dividing.  */
+  tmp = fold_build2_loc (input_location, TRUNC_DIV_EXPR, 
+                        size_type_node,
+                        TYPE_MAX_VALUE (size_type_node), element_size);
+  cond = gfc_unlikely (fold_build2_loc (input_location, LT_EXPR,
+                                       boolean_type_node, tmp, stride));
+  tmp = fold_build3_loc (input_location, COND_EXPR, integer_type_node, cond,
+                        integer_one_node, integer_zero_node);
+  cond = gfc_unlikely (fold_build2_loc (input_location, EQ_EXPR,
+                                       boolean_type_node, element_size,
+                                       build_int_cst (size_type_node, 0)));
+  tmp = fold_build3_loc (input_location, COND_EXPR, integer_type_node, cond,
+                        integer_zero_node, tmp);
+  tmp = fold_build2_loc (input_location, PLUS_EXPR, integer_type_node,
+                        *overflow, tmp);
+  *overflow = gfc_evaluate_now (tmp, pblock);
+
+  size = fold_build2_loc (input_location, MULT_EXPR, size_type_node,
+                         stride, element_size);
 
   if (poffset != NULL)
     {
@@ -4087,11 +4502,11 @@ gfc_array_init_size (tree descriptor, int rank, int corank, tree * poffset,
   if (integer_zerop (or_expr))
     return size;
   if (integer_onep (or_expr))
-    return gfc_index_zero_node;
+    return build_int_cst (size_type_node, 0);
 
   var = gfc_create_var (TREE_TYPE (size), "size");
   gfc_start_block (&thenblock);
-  gfc_add_modify (&thenblock, var, gfc_index_zero_node);
+  gfc_add_modify (&thenblock, var, build_int_cst (size_type_node, 0));
   thencase = gfc_finish_block (&thenblock);
 
   gfc_start_block (&elseblock);
@@ -4111,16 +4526,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 = NULL_TREE;
+  tree overflow; /* Boolean storing whether size calculation overflows.  */
+  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;
 
@@ -4138,22 +4563,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)
@@ -4184,26 +4606,87 @@ gfc_array_allocate (gfc_se * se, gfc_expr * expr, tree pstat)
       break;
     }
 
+  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);
+                             &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);
+
+      /* 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);
+    }
+
+  if (status != NULL_TREE)
+    {
+      tree status_type = TREE_TYPE (status);
+      stmtblock_t set_status_block;
+
+      gfc_start_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 (&se->pre, pointer, size, pstat, expr);
+  if (coarray && gfc_option.coarray == GFC_FCOARRAY_LIB)
+    token = gfc_build_addr_expr (NULL_TREE,
+                                gfc_conv_descriptor_token (se->expr));
+
+  /* The allocatable variant takes the old pointer as first argument.  */
+  if (allocatable)
+    gfc_allocate_allocatable (&elseblock, pointer, size, token,
+                             status, errmsg, errlen, expr);
   else
-    tmp = gfc_allocate_with_status (&se->pre, size, pstat);
-  tmp = fold_build2_loc (input_location, MODIFY_EXPR, void_type_node, pointer,
-                        tmp);
+    gfc_allocate_using_malloc (&elseblock, pointer, size, status);
+
+  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
+  if ((expr->ts.type == BT_DERIVED || expr->ts.type == BT_CLASS)
        && expr->ts.u.derived->attr.alloc_comp)
     {
       tmp = gfc_nullify_alloc_comp (expr->ts.u.derived, se->expr,
@@ -4255,7 +4738,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)
@@ -4309,28 +4792,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;
 
@@ -4348,6 +4859,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.  */
 
@@ -4429,6 +4977,7 @@ gfc_trans_array_bounds (tree type, gfc_symbol * sym, tree * poffset,
       size = stride;
     }
 
+  gfc_trans_array_cobounds (type, pblock, sym);
   gfc_trans_vla_type_sizes (sym, pblock);
 
   *poffset = offset;
@@ -4444,9 +4993,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));
@@ -4459,7 +5010,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
@@ -4503,15 +5054,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)
@@ -4520,10 +5086,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);
+
+  if (space)
+    {
+      tree addr;
+      pushdecl (space);
 
-  gfc_add_init_cleanup (block, gfc_finish_block (&init), tmp);
+      /* 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);
 }
 
 
@@ -4784,7 +5366,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
@@ -4861,6 +5443,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);
@@ -5146,6 +5730,18 @@ get_array_charlen (gfc_expr *expr, gfc_se *se)
 }
 
 
+/* Helper function to check dimensions.  */
+static bool
+transposed_dims (gfc_ss *ss)
+{
+  int n;
+
+  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
    vector subscripts are evaluated and stored in a temporary, which is then
    passed.  For whole arrays the descriptor is passed.  For array sections
@@ -5178,8 +5774,10 @@ get_array_charlen (gfc_expr *expr, gfc_se *se)
 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;
@@ -5189,11 +5787,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)
     {
@@ -5201,8 +5803,8 @@ 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);
+      gcc_assert (ss_type == GFC_SS_SECTION);
+      gcc_assert (ss_expr == expr);
       info = &ss->data.info;
 
       /* Get the descriptor for the array.  */
@@ -5230,15 +5832,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)
-       for (n = 0; n < info->dimen; n++)
-         if (info->dim[n] != n)
-           {
-             full = 0;
-             break;
-           }
-
-      if (full)
+      if (full && !transposed_dims (ss))
        {
          if (se->direct_byref && !se->byref_noassign)
            {
@@ -5288,7 +5882,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)
@@ -5300,16 +5894,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
@@ -5328,7 +5922,7 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
 
     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))
        {
@@ -5371,24 +5965,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;
+      /* 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);
     }
 
@@ -5432,7 +6020,8 @@ 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.  */
@@ -5440,10 +6029,10 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
 
       desc = loop.temp_ss->data.info.descriptor;
     }
-  else if (expr->expr_type == EXPR_FUNCTION)
+  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
     {
@@ -5452,7 +6041,7 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
         limits will be the limits of the section.
         A function may decide to repack the array to speed up access, but
         we're not bothered about that here.  */
-      int dim, ndim;
+      int dim, ndim, codim;
       tree parm;
       tree parmtype;
       tree stride;
@@ -5460,6 +6049,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);
@@ -5475,7 +6093,7 @@ 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, 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");
@@ -5506,7 +6124,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;
       for (n = 0; n < ndim; n++)
        {
          stride = gfc_conv_array_stride (desc, n);
@@ -5516,8 +6133,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
            {
@@ -5547,7 +6164,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.  */
@@ -5608,6 +6225,17 @@ gfc_conv_expr_descriptor (gfc_se * se, gfc_expr * expr, gfc_ss * ss)
                                          gfc_rank_cst[dim], stride);
        }
 
+      for (n = loop.dimen; n < loop.dimen + codim; n++)
+       {
+         from = loop.from[n];
+         to = loop.to[n];
+         gfc_conv_descriptor_lbound_set (&loop.pre, parm,
+                                         gfc_rank_cst[n], from);
+         if (n < loop.dimen + codim - 1)
+           gfc_conv_descriptor_ubound_set (&loop.pre, parm,
+                                           gfc_rank_cst[n], to);
+       }
+
       if (se->data_not_needed)
        gfc_conv_descriptor_data_set (&loop.pre, parm,
                                      gfc_index_zero_node);
@@ -5750,7 +6378,7 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, gfc_ss * ss, bool g77,
       if (sym->ts.type == BT_CHARACTER)
        se->string_length = sym->ts.u.cl->backend_decl;
 
-      if (sym->ts.type == BT_DERIVED)
+      if (sym->ts.type == BT_DERIVED || sym->ts.type == BT_CLASS)
        {
          gfc_conv_expr_descriptor (se, expr, ss);
          se->expr = gfc_conv_array_data (se->expr);
@@ -5856,14 +6484,15 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr * expr, gfc_ss * ss, bool g77,
 
   /* Deallocate the allocatable components of structures that are
      not variable.  */
-  if (expr->ts.type == BT_DERIVED
+  if ((expr->ts.type == BT_DERIVED || expr->ts.type == BT_CLASS)
        && expr->ts.u.derived->attr.alloc_comp
        && expr->expr_type != EXPR_VARIABLE)
     {
-      tmp = build_fold_indirect_ref_loc (input_location,
-                                    se->expr);
+      tmp = build_fold_indirect_ref_loc (input_location, se->expr);
       tmp = gfc_deallocate_alloc_comp (expr->ts.u.derived, tmp, expr->rank);
-      gfc_add_expr_to_block (&se->post, tmp);
+
+      /* The components shall be deallocated before their containing entity.  */
+      gfc_prepend_expr_to_block (&se->post, tmp);
     }
 
   if (g77 || (fsym && fsym->attr.contiguous
@@ -5941,7 +6570,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);
@@ -6081,7 +6710,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);
     }
@@ -6105,7 +6734,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);
@@ -6273,7 +6902,8 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl,
      act on a chain of components.  */
   for (c = der_type->components; c; c = c->next)
     {
-      bool cmp_has_alloc_comps = (c->ts.type == BT_DERIVED)
+      bool cmp_has_alloc_comps = (c->ts.type == BT_DERIVED
+                                 || c->ts.type == BT_CLASS)
                                    && c->ts.u.derived->attr.alloc_comp;
       cdecl = c->backend_decl;
       ctype = TREE_TYPE (cdecl);
@@ -6281,18 +6911,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);
            }
@@ -6336,7 +6971,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);
@@ -6457,6 +7093,451 @@ gfc_copy_only_alloc_comp (gfc_symbol * der_type, tree decl, tree dest, int rank)
 }
 
 
+/* Returns the value of LBOUND for an expression.  This could be broken out
+   from gfc_conv_intrinsic_bound but this seemed to be simpler.  This is
+   called by gfc_alloc_allocatable_for_assignment.  */
+static tree
+get_std_lbound (gfc_expr *expr, tree desc, int dim, bool assumed_size)
+{
+  tree lbound;
+  tree ubound;
+  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];
+      lbound = gfc_conv_descriptor_lbound_get (desc, tmp);
+      ubound = gfc_conv_descriptor_ubound_get (desc, tmp);
+      stride = gfc_conv_descriptor_stride_get (desc, tmp);
+      cond1 = fold_build2_loc (input_location, GE_EXPR, boolean_type_node,
+                              ubound, lbound);
+      cond3 = fold_build2_loc (input_location, GE_EXPR, boolean_type_node,
+                              stride, gfc_index_zero_node);
+      cond3 = fold_build2_loc (input_location, TRUTH_AND_EXPR,
+                              boolean_type_node, cond3, cond1);
+      cond4 = fold_build2_loc (input_location, LT_EXPR, boolean_type_node,
+                              stride, gfc_index_zero_node);
+      if (assumed_size)
+       cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node,
+                               tmp, build_int_cst (gfc_array_index_type,
+                                                   expr->rank - 1));
+      else
+       cond = boolean_false_node;
+
+      cond1 = fold_build2_loc (input_location, TRUTH_OR_EXPR,
+                              boolean_type_node, cond3, cond4);
+      cond = fold_build2_loc (input_location, TRUTH_OR_EXPR,
+                             boolean_type_node, cond, cond1);
+
+      return fold_build3_loc (input_location, COND_EXPR,
+                             gfc_array_index_type, cond,
+                             lbound, gfc_index_one_node);
+    }
+  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)
+    {
+      /* A conversion function, so use the argument.  */
+      expr = expr->value.function.actual->expr;
+      if (expr->expr_type != EXPR_VARIABLE)
+       return gfc_index_one_node;
+      desc = TREE_TYPE (expr->symtree->n.sym->backend_decl);
+      return get_std_lbound (expr, desc, dim, assumed_size);
+    }
+
+  return gfc_index_one_node;
+}
+
+
+/* Returns true if an expression represents an lhs that can be reallocated
+   on assignment.  */
+
+bool
+gfc_is_reallocatable_lhs (gfc_expr *expr)
+{
+  gfc_ref * ref;
+
+  if (!expr->ref)
+    return false;
+
+  /* An allocatable variable.  */
+  if (expr->symtree->n.sym->attr.allocatable
+       && expr->ref
+       && expr->ref->type == REF_ARRAY
+       && expr->ref->u.ar.type == AR_FULL)
+    return true;
+
+  /* All that can be left are allocatable components.  */
+  if ((expr->symtree->n.sym->ts.type != BT_DERIVED
+       && expr->symtree->n.sym->ts.type != BT_CLASS)
+       || !expr->symtree->n.sym->ts.u.derived->attr.alloc_comp)
+    return false;
+
+  /* Find a component ref followed by an array reference.  */
+  for (ref = expr->ref; ref; ref = ref->next)
+    if (ref->next
+         && ref->type == REF_COMPONENT
+         && ref->next->type == REF_ARRAY
+         && !ref->next->next)
+      break;
+
+  if (!ref)
+    return false;
+
+  /* Return true if valid reallocatable lhs.  */
+  if (ref->u.c.component->attr.allocatable
+       && ref->next->u.ar.type == AR_FULL)
+    return true;
+
+  return false;
+}
+
+
+/* Allocate the lhs of an assignment to an allocatable array, otherwise
+   reallocate it.  */
+
+tree
+gfc_alloc_allocatable_for_assignment (gfc_loopinfo *loop,
+                                     gfc_expr *expr1,
+                                     gfc_expr *expr2)
+{
+  stmtblock_t realloc_block;
+  stmtblock_t alloc_block;
+  stmtblock_t fblock;
+  gfc_ss *rss;
+  gfc_ss *lss;
+  tree realloc_expr;
+  tree alloc_expr;
+  tree size1;
+  tree size2;
+  tree array1;
+  tree cond;
+  tree tmp;
+  tree tmp2;
+  tree lbound;
+  tree ubound;
+  tree desc;
+  tree desc2;
+  tree offset;
+  tree jump_label1;
+  tree jump_label2;
+  tree neq_size;
+  tree lbd;
+  int n;
+  int dim;
+  gfc_array_spec * as;
+
+  /* x = f(...) with x allocatable.  In this case, expr1 is the rhs.
+     Find the lhs expression in the loop chain and set expr1 and
+     expr2 accordingly.  */
+  if (expr1->expr_type == EXPR_FUNCTION && expr2 == NULL)
+    {
+      expr2 = expr1;
+      /* Find the ss for the lhs.  */
+      lss = loop->ss;
+      for (; lss && lss != gfc_ss_terminator; lss = lss->loop_chain)
+       if (lss->info->expr && lss->info->expr->expr_type == EXPR_VARIABLE)
+         break;
+      if (lss == gfc_ss_terminator)
+       return NULL_TREE;
+      expr1 = lss->info->expr;
+    }
+
+  /* Bail out if this is not a valid allocate on assignment.  */
+  if (!gfc_is_reallocatable_lhs (expr1)
+       || (expr2 && !expr2->rank))
+    return NULL_TREE;
+
+  /* Find the ss for the lhs.  */
+  lss = loop->ss;
+  for (; lss && lss != gfc_ss_terminator; lss = lss->loop_chain)
+    if (lss->info->expr == expr1)
+      break;
+
+  if (lss == gfc_ss_terminator)
+    return NULL_TREE;
+
+  /* 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->info->expr != expr1 && rss != loop->temp_ss)
+      break;
+
+  if (expr2 && rss == gfc_ss_terminator)
+    return NULL_TREE;
+
+  gfc_start_block (&fblock);
+
+  /* Since the lhs is allocatable, this must be a descriptor type.
+     Get the data and array size.  */
+  desc = lss->data.info.descriptor;
+  gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)));
+  array1 = gfc_conv_descriptor_data_get (desc);
+
+  /* 7.4.1.3 "If variable is an allocated allocatable variable, it is
+     deallocated if expr is an array of different shape or any of the
+     corresponding length type parameter values of variable and expr
+     differ."  This assures F95 compatibility.  */
+  jump_label1 = gfc_build_label_decl (NULL_TREE);
+  jump_label2 = gfc_build_label_decl (NULL_TREE);
+
+  /* Allocate if data is NULL.  */
+  cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node,
+                        array1, build_int_cst (TREE_TYPE (array1), 0));
+  tmp = build3_v (COND_EXPR, cond,
+                 build1_v (GOTO_EXPR, jump_label1),
+                 build_empty_stmt (input_location));
+  gfc_add_expr_to_block (&fblock, tmp);
+
+  /* Get arrayspec if expr is a full array.  */
+  if (expr2 && expr2->expr_type == EXPR_FUNCTION
+       && expr2->value.function.isym
+       && expr2->value.function.isym->conversion)
+    {
+      /* For conversion functions, take the arg.  */
+      gfc_expr *arg = expr2->value.function.actual->expr;
+      as = gfc_get_full_arrayspec_from_expr (arg);
+    }
+  else if (expr2)
+    as = gfc_get_full_arrayspec_from_expr (expr2);
+  else
+    as = NULL;
+
+  /* If the lhs shape is not the same as the rhs jump to setting the
+     bounds and doing the reallocation.......  */ 
+  for (n = 0; n < expr1->rank; n++)
+    {
+      /* Check the shape.  */
+      lbound = gfc_conv_descriptor_lbound_get (desc, gfc_rank_cst[n]);
+      ubound = gfc_conv_descriptor_ubound_get (desc, gfc_rank_cst[n]);
+      tmp = fold_build2_loc (input_location, MINUS_EXPR,
+                            gfc_array_index_type,
+                            loop->to[n], loop->from[n]);
+      tmp = fold_build2_loc (input_location, PLUS_EXPR,
+                            gfc_array_index_type,
+                            tmp, lbound);
+      tmp = fold_build2_loc (input_location, MINUS_EXPR,
+                            gfc_array_index_type,
+                            tmp, ubound);
+      cond = fold_build2_loc (input_location, NE_EXPR,
+                             boolean_type_node,
+                             tmp, gfc_index_zero_node);
+      tmp = build3_v (COND_EXPR, cond,
+                     build1_v (GOTO_EXPR, jump_label1),
+                     build_empty_stmt (input_location));
+      gfc_add_expr_to_block (&fblock, tmp);      
+    }
+
+  /* ....else jump past the (re)alloc code.  */
+  tmp = build1_v (GOTO_EXPR, jump_label2);
+  gfc_add_expr_to_block (&fblock, tmp);
+    
+  /* Add the label to start automatic (re)allocation.  */
+  tmp = build1_v (LABEL_EXPR, jump_label1);
+  gfc_add_expr_to_block (&fblock, tmp);
+
+  size1 = gfc_conv_descriptor_size (desc, expr1->rank);
+
+  /* Get the rhs size.  Fix both sizes.  */
+  if (expr2)
+    desc2 = rss->data.info.descriptor;
+  else
+    desc2 = NULL_TREE;
+  size2 = gfc_index_one_node;
+  for (n = 0; n < expr2->rank; n++)
+    {
+      tmp = fold_build2_loc (input_location, MINUS_EXPR,
+                            gfc_array_index_type,
+                            loop->to[n], loop->from[n]);
+      tmp = fold_build2_loc (input_location, PLUS_EXPR,
+                            gfc_array_index_type,
+                            tmp, gfc_index_one_node);
+      size2 = fold_build2_loc (input_location, MULT_EXPR,
+                              gfc_array_index_type,
+                              tmp, size2);
+    }
+
+  size1 = gfc_evaluate_now (size1, &fblock);
+  size2 = gfc_evaluate_now (size2, &fblock);
+
+  cond = fold_build2_loc (input_location, NE_EXPR, boolean_type_node,
+                         size1, size2);
+  neq_size = gfc_evaluate_now (cond, &fblock);
+
+
+  /* Now modify the lhs descriptor and the associated scalarizer
+     variables. F2003 7.4.1.3: "If variable is or becomes an
+     unallocated allocatable variable, then it is allocated with each
+     deferred type parameter equal to the corresponding type parameters
+     of expr , with the shape of expr , and with each lower bound equal
+     to the corresponding element of LBOUND(expr)."  
+     Reuse size1 to keep a dimension-by-dimension track of the
+     stride of the new array.  */
+  size1 = gfc_index_one_node;
+  offset = gfc_index_zero_node;
+
+  for (n = 0; n < expr2->rank; n++)
+    {
+      tmp = fold_build2_loc (input_location, MINUS_EXPR,
+                            gfc_array_index_type,
+                            loop->to[n], loop->from[n]);
+      tmp = fold_build2_loc (input_location, PLUS_EXPR,
+                            gfc_array_index_type,
+                            tmp, gfc_index_one_node);
+
+      lbound = gfc_index_one_node;
+      ubound = tmp;
+
+      if (as)
+       {
+         lbd = get_std_lbound (expr2, desc2, n,
+                               as->type == AS_ASSUMED_SIZE);
+         ubound = fold_build2_loc (input_location,
+                                   MINUS_EXPR,
+                                   gfc_array_index_type,
+                                   ubound, lbound);
+         ubound = fold_build2_loc (input_location,
+                                   PLUS_EXPR,
+                                   gfc_array_index_type,
+                                   ubound, lbd);
+         lbound = lbd;
+       }
+
+      gfc_conv_descriptor_lbound_set (&fblock, desc,
+                                     gfc_rank_cst[n],
+                                     lbound);
+      gfc_conv_descriptor_ubound_set (&fblock, desc,
+                                     gfc_rank_cst[n],
+                                     ubound);
+      gfc_conv_descriptor_stride_set (&fblock, desc,
+                                     gfc_rank_cst[n],
+                                     size1);
+      lbound = gfc_conv_descriptor_lbound_get (desc,
+                                              gfc_rank_cst[n]);
+      tmp2 = fold_build2_loc (input_location, MULT_EXPR,
+                             gfc_array_index_type,
+                             lbound, size1);
+      offset = fold_build2_loc (input_location, MINUS_EXPR,
+                               gfc_array_index_type,
+                               offset, tmp2);
+      size1 = fold_build2_loc (input_location, MULT_EXPR,
+                              gfc_array_index_type,
+                              tmp, size1);
+    }
+
+  /* Set the lhs descriptor and scalarizer offsets.  For rank > 1,
+     the array offset is saved and the info.offset is used for a
+     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);
+
+  /* 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->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);
+    }
+
+  /* Get the new lhs size in bytes.  */
+  if (expr1->ts.type == BT_CHARACTER && expr1->ts.deferred)
+    {
+      tmp = expr2->ts.u.cl->backend_decl;
+      gcc_assert (expr1->ts.u.cl->backend_decl);
+      tmp = fold_convert (TREE_TYPE (expr1->ts.u.cl->backend_decl), tmp);
+      gfc_add_modify (&fblock, expr1->ts.u.cl->backend_decl, tmp);
+    }
+  else if (expr1->ts.type == BT_CHARACTER && expr1->ts.u.cl->backend_decl)
+    {
+      tmp = TYPE_SIZE_UNIT (TREE_TYPE (gfc_typenode_for_spec (&expr1->ts)));
+      tmp = fold_build2_loc (input_location, MULT_EXPR,
+                            gfc_array_index_type, tmp,
+                            expr1->ts.u.cl->backend_decl);
+    }
+  else
+    tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&expr1->ts));
+  tmp = fold_convert (gfc_array_index_type, tmp);
+  size2 = fold_build2_loc (input_location, MULT_EXPR,
+                          gfc_array_index_type,
+                          tmp, size2);
+  size2 = fold_convert (size_type_node, size2);
+  size2 = gfc_evaluate_now (size2, &fblock);
+
+  /* Realloc expression.  Note that the scalarizer uses desc.data
+     in the array reference - (*desc.data)[<element>]. */
+  gfc_init_block (&realloc_block);
+  tmp = build_call_expr_loc (input_location,
+                            builtin_decl_explicit (BUILT_IN_REALLOC), 2,
+                            fold_convert (pvoid_type_node, array1),
+                            size2);
+  gfc_conv_descriptor_data_set (&realloc_block,
+                               desc, tmp);
+  realloc_expr = gfc_finish_block (&realloc_block);
+
+  /* Only reallocate if sizes are different.  */
+  tmp = build3_v (COND_EXPR, neq_size, realloc_expr,
+                 build_empty_stmt (input_location));
+  realloc_expr = tmp;
+
+
+  /* Malloc expression.  */
+  gfc_init_block (&alloc_block);
+  tmp = build_call_expr_loc (input_location,
+                            builtin_decl_explicit (BUILT_IN_MALLOC),
+                            1, size2);
+  gfc_conv_descriptor_data_set (&alloc_block,
+                               desc, tmp);
+  tmp = gfc_conv_descriptor_dtype (desc);
+  gfc_add_modify (&alloc_block, tmp, gfc_get_dtype (TREE_TYPE (desc)));
+  alloc_expr = gfc_finish_block (&alloc_block);
+
+  /* Malloc if not allocated; realloc otherwise.  */
+  tmp = build_int_cst (TREE_TYPE (array1), 0);
+  cond = fold_build2_loc (input_location, EQ_EXPR,
+                         boolean_type_node,
+                         array1, tmp);
+  tmp = build3_v (COND_EXPR, cond, alloc_expr, realloc_expr);
+  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)
+    {
+      tmp = gfc_conv_descriptor_data_get (desc);
+      gfc_add_modify (&fblock, lss->data.info.data, tmp);
+    }
+
+  /* Add the exit label.  */
+  tmp = build1_v (LABEL_EXPR, jump_label2);
+  gfc_add_expr_to_block (&fblock, tmp);
+
+  return gfc_finish_block (&fblock);
+}
+
+
 /* NULLIFY an allocatable/pointer array on function entry, free it on exit.
    Do likewise, recursively if necessary, with the allocatable components of
    derived types.  */
@@ -6473,7 +7554,8 @@ gfc_trans_deferred_array (gfc_symbol * sym, gfc_wrapped_block * block)
   int rank;
   bool sym_has_alloc_comp;
 
-  sym_has_alloc_comp = (sym->ts.type == BT_DERIVED)
+  sym_has_alloc_comp = (sym->ts.type == BT_DERIVED
+                       || sym->ts.type == BT_CLASS)
                          && sym->ts.u.derived->attr.alloc_comp;
 
   /* Make sure the frontend gets these right.  */
@@ -6482,6 +7564,8 @@ gfc_trans_deferred_array (gfc_symbol * sym, gfc_wrapped_block * block)
                 "allocatable attribute or derived type without allocatable "
                 "components.");
 
+  gfc_save_backend_locus (&loc);
+  gfc_set_backend_locus (&sym->declared_at);
   gfc_init_block (&init);
 
   gcc_assert (TREE_CODE (sym->backend_decl) == VAR_DECL
@@ -6498,11 +7582,10 @@ gfc_trans_deferred_array (gfc_symbol * sym, gfc_wrapped_block * block)
   if (sym->attr.dummy || sym->attr.use_assoc || sym->attr.result)
     {
       gfc_add_init_cleanup (block, gfc_finish_block (&init), NULL_TREE);
+      gfc_restore_backend_locus (&loc);
       return;
     }
 
-  gfc_save_backend_locus (&loc);
-  gfc_set_backend_locus (&sym->declared_at);
   descriptor = sym->backend_decl;
 
   /* Although static, derived types with default initializers and
@@ -6551,8 +7634,8 @@ gfc_trans_deferred_array (gfc_symbol * sym, gfc_wrapped_block * block)
   if (GFC_DESCRIPTOR_TYPE_P (type) && !sym->attr.save)
     gfc_conv_descriptor_data_set (&init, descriptor, null_pointer_node);
 
-  gfc_init_block (&cleanup);
   gfc_restore_backend_locus (&loc);
+  gfc_init_block (&cleanup);
 
   /* Allocatable arrays need to be freed when they go out of scope.
      The allocatable components of pointers must not be touched.  */
@@ -6565,7 +7648,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);
@@ -6595,29 +7678,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.  */
@@ -6626,31 +7708,15 @@ 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; 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 = gfc_get_array_ss (ss, expr, ar->as->rank, GFC_SS_SECTION);
          newss->data.info.ref = ref;
 
          /* Make sure array is the same as array(:,:), this way
@@ -6658,7 +7724,6 @@ gfc_walk_variable_expr (gfc_ss * ss, gfc_expr * expr)
          ar->dimen = ar->as->rank;
          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);
@@ -6669,14 +7734,10 @@ gfc_walk_variable_expr (gfc_ss * ss, gfc_expr * expr)
          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 = gfc_get_array_ss (ss, expr, 0, GFC_SS_SECTION);
          newss->data.info.ref = ref;
 
-          /* We add SS chains for all the subscripts in the section.  */
+         /* We add SS chains for all the subscripts in the section.  */
          for (n = 0; n < ar->dimen; n++)
            {
              gfc_ss *indexss;
@@ -6686,10 +7747,7 @@ gfc_walk_variable_expr (gfc_ss * ss, gfc_expr * expr)
                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;
                  break;
@@ -6697,21 +7755,19 @@ gfc_walk_variable_expr (gfc_ss * ss, gfc_expr * expr)
                case DIMEN_RANGE:
                   /* We don't add anything for sections, just remember this
                      dimension for later.  */
-                 newss->data.info.dim[newss->data.info.dimen] = n;
-                 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] = n;
-                 newss->data.info.dimen++;
+                 newss->dim[newss->dimen] = n;
+                 newss->dimen++;
                  break;
 
                default:
@@ -6719,8 +7775,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->data.info.ref->u.ar.as->corank > 0);
          ss = newss;
          break;
 
@@ -6742,7 +7800,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)
@@ -6760,8 +7817,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
@@ -6771,17 +7826,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;
@@ -6836,10 +7887,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;
@@ -6876,11 +7926,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;
 
@@ -6896,16 +7944,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.  */
@@ -6924,18 +7963,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);
 }