OSDN Git Service

contrib/
[pf3gnuchains/gcc-fork.git] / gcc / fortran / array.c
index 6ab5f83..c6bb5e8 100644 (file)
@@ -1,36 +1,34 @@
 /* Array things
-   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008
+   Free Software Foundation, Inc.
    Contributed by Andy Vaught
 
-This file is part of GNU G95.
+This file is part of GCC.
 
-GNU G95 is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
 
-GNU G95 is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU G95; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
+#include "system.h"
 #include "gfortran.h"
 #include "match.h"
 
-#include <string.h>
-#include <assert.h>
-
 /* This parameter is the size of the largest array constructor that we
    will expand to an array constructor without iterators.
    Constructors larger than this will remain in the iterator form.  */
 
-#define GFC_MAX_AC_EXPAND 100
+#define GFC_MAX_AC_EXPAND 65535
 
 
 /**************** Array reference matching subroutines *****************/
@@ -38,7 +36,7 @@ Boston, MA 02111-1307, USA.  */
 /* Copy an array reference structure.  */
 
 gfc_array_ref *
-gfc_copy_array_ref (gfc_array_ref * src)
+gfc_copy_array_ref (gfc_array_ref *src)
 {
   gfc_array_ref *dest;
   int i;
@@ -70,14 +68,14 @@ gfc_copy_array_ref (gfc_array_ref * src)
    expression.  */
 
 static match
-match_subscript (gfc_array_ref * ar, int init)
+match_subscript (gfc_array_ref *ar, int init)
 {
   match m;
   int i;
 
   i = ar->dimen;
 
-  ar->c_where[i] = *gfc_current_locus ();
+  ar->c_where[i] = gfc_current_locus;
   ar->start[i] = ar->end[i] = ar->stride[i] = NULL;
 
   /* We can't be sure of the difference between DIMEN_ELEMENT and
@@ -120,7 +118,7 @@ end_element:
   if (gfc_match_char (':') == MATCH_YES)
     {
       m = init ? gfc_match_init_expr (&ar->stride[i])
-       : gfc_match_expr (&ar->stride[i]);
+              : gfc_match_expr (&ar->stride[i]);
 
       if (m == MATCH_NO)
        gfc_error ("Expected array subscript stride at %C");
@@ -137,13 +135,13 @@ end_element:
    to consist of init expressions.  */
 
 match
-gfc_match_array_ref (gfc_array_ref * ar, gfc_array_spec * as, int init)
+gfc_match_array_ref (gfc_array_ref *ar, gfc_array_spec *as, int init)
 {
   match m;
 
   memset (ar, '\0', sizeof (ar));
 
-  ar->where = *gfc_current_locus ();
+  ar->where = gfc_current_locus;
   ar->as = as;
 
   if (gfc_match_char ('(') != MATCH_YES)
@@ -171,8 +169,8 @@ gfc_match_array_ref (gfc_array_ref * ar, gfc_array_spec * as, int init)
        }
     }
 
-  gfc_error ("Array reference at %C cannot have more than "
-            stringize (GFC_MAX_DIMENSIONS) " dimensions");
+  gfc_error ("Array reference at %C cannot have more than %d dimensions",
+            GFC_MAX_DIMENSIONS);
 
 error:
   return MATCH_ERROR;
@@ -190,7 +188,7 @@ matched:
    specifications.  */
 
 void
-gfc_free_array_spec (gfc_array_spec * as)
+gfc_free_array_spec (gfc_array_spec *as)
 {
   int i;
 
@@ -211,9 +209,8 @@ gfc_free_array_spec (gfc_array_spec * as)
    shape and check associated constraints.  */
 
 static try
-resolve_array_bound (gfc_expr * e, int check_constant)
+resolve_array_bound (gfc_expr *e, int check_constant)
 {
-
   if (e == NULL)
     return SUCCESS;
 
@@ -236,7 +233,7 @@ resolve_array_bound (gfc_expr * e, int check_constant)
    the shape and make sure everything is integral.  */
 
 try
-gfc_resolve_array_spec (gfc_array_spec * as, int check_constant)
+gfc_resolve_array_spec (gfc_array_spec *as, int check_constant)
 {
   gfc_expr *e;
   int i;
@@ -253,6 +250,21 @@ gfc_resolve_array_spec (gfc_array_spec * as, int check_constant)
       e = as->upper[i];
       if (resolve_array_bound (e, check_constant) == FAILURE)
        return FAILURE;
+
+      if ((as->lower[i] == NULL) || (as->upper[i] == NULL))
+       continue;
+
+      /* If the size is negative in this dimension, set it to zero.  */
+      if (as->lower[i]->expr_type == EXPR_CONSTANT
+           && as->upper[i]->expr_type == EXPR_CONSTANT
+           && mpz_cmp (as->upper[i]->value.integer,
+                       as->lower[i]->value.integer) < 0)
+       {
+         gfc_free_expr (as->upper[i]);
+         as->upper[i] = gfc_copy_expr (as->lower[i]);
+         mpz_sub_ui (as->upper[i]->value.integer,
+                     as->upper[i]->value.integer, 1);
+       }
     }
 
   return SUCCESS;
@@ -265,14 +277,14 @@ gfc_resolve_array_spec (gfc_array_spec * as, int check_constant)
    individual specifications make sense as a whole.
 
 
-        Parsed       Lower   Upper  Returned
-        ------------------------------------
-          :          NULL    NULL   AS_DEFERRED (*)
-          x           1       x     AS_EXPLICIT
-          x:          x      NULL   AS_ASSUMED_SHAPE
-          x:y         x       y     AS_EXPLICIT
-          x:*         x      NULL   AS_ASSUMED_SIZE
-          *           1      NULL   AS_ASSUMED_SIZE
+       Parsed       Lower   Upper  Returned
+       ------------------------------------
+                   NULL    NULL   AS_DEFERRED (*)
+                    1       x     AS_EXPLICIT
+         x:           x      NULL   AS_ASSUMED_SHAPE
+         x:y          x       y     AS_EXPLICIT
+         x:*          x      NULL   AS_ASSUMED_SIZE
+                    1      NULL   AS_ASSUMED_SIZE
 
   (*) For non-pointer dummy arrays this is AS_ASSUMED_SHAPE.  This
   is fixed during the resolution of formal interfaces.
@@ -280,7 +292,7 @@ gfc_resolve_array_spec (gfc_array_spec * as, int check_constant)
    Anything else AS_UNKNOWN.  */
 
 static array_type
-match_array_element_spec (gfc_array_spec * as)
+match_array_element_spec (gfc_array_spec *as)
 {
   gfc_expr **upper, **lower;
   match m;
@@ -329,7 +341,7 @@ match_array_element_spec (gfc_array_spec * as)
    it is.  */
 
 match
-gfc_match_array_spec (gfc_array_spec ** asp)
+gfc_match_array_spec (gfc_array_spec **asp)
 {
   array_type current_type;
   gfc_array_spec *as;
@@ -363,7 +375,7 @@ gfc_match_array_spec (gfc_array_spec ** asp)
        }
       else
        switch (as->type)
-         {                     /* See how current spec meshes with the existing */
+         {             /* See how current spec meshes with the existing.  */
          case AS_UNKNOWN:
            goto cleanup;
 
@@ -377,9 +389,8 @@ gfc_match_array_spec (gfc_array_spec ** asp)
            if (current_type == AS_EXPLICIT)
              break;
 
-           gfc_error
-             ("Bad array specification for an explicitly shaped array"
-              " at %C");
+           gfc_error ("Bad array specification for an explicitly shaped "
+                      "array at %C");
 
            goto cleanup;
 
@@ -388,8 +399,8 @@ gfc_match_array_spec (gfc_array_spec ** asp)
                || (current_type == AS_DEFERRED))
              break;
 
-           gfc_error
-             ("Bad array specification for assumed shape array at %C");
+           gfc_error ("Bad array specification for assumed shape "
+                      "array at %C");
            goto cleanup;
 
          case AS_DEFERRED:
@@ -421,11 +432,17 @@ gfc_match_array_spec (gfc_array_spec ** asp)
 
       if (as->rank >= GFC_MAX_DIMENSIONS)
        {
-         gfc_error ("Array specification at %C has more than "
-                    stringize (GFC_MAX_DIMENSIONS) " dimensions");
+         gfc_error ("Array specification at %C has more than %d dimensions",
+                    GFC_MAX_DIMENSIONS);
          goto cleanup;
        }
 
+      if (as->rank > 7
+         && gfc_notify_std (GFC_STD_F2008, "Fortran 2008: Array "
+                            "specification at %C with more than 7 dimensions")
+            == FAILURE)
+       goto cleanup;
+
       as->rank++;
     }
 
@@ -453,13 +470,12 @@ cleanup:
    something goes wrong.  On failure, the caller must free the spec.  */
 
 try
-gfc_set_array_spec (gfc_symbol * sym, gfc_array_spec * as, locus * error_loc)
+gfc_set_array_spec (gfc_symbol *sym, gfc_array_spec *as, locus *error_loc)
 {
-
   if (as == NULL)
     return SUCCESS;
 
-  if (gfc_add_dimension (&sym->attr, error_loc) == FAILURE)
+  if (gfc_add_dimension (&sym->attr, sym->name, error_loc) == FAILURE)
     return FAILURE;
 
   sym->as = as;
@@ -471,7 +487,7 @@ gfc_set_array_spec (gfc_symbol * sym, gfc_array_spec * as, locus * error_loc)
 /* Copy an array specification.  */
 
 gfc_array_spec *
-gfc_copy_array_spec (gfc_array_spec * src)
+gfc_copy_array_spec (gfc_array_spec *src)
 {
   gfc_array_spec *dest;
   int i;
@@ -492,11 +508,12 @@ gfc_copy_array_spec (gfc_array_spec * src)
   return dest;
 }
 
+
 /* Returns nonzero if the two expressions are equal.  Only handles integer
    constants.  */
 
 static int
-compare_bounds (gfc_expr * bound1, gfc_expr * bound2)
+compare_bounds (gfc_expr *bound1, gfc_expr *bound2)
 {
   if (bound1 == NULL || bound2 == NULL
       || bound1->expr_type != EXPR_CONSTANT
@@ -511,11 +528,12 @@ compare_bounds (gfc_expr * bound1, gfc_expr * bound2)
     return 0;
 }
 
+
 /* Compares two array specifications.  They must be constant or deferred
    shape.  */
 
 int
-gfc_compare_array_spec (gfc_array_spec * as1, gfc_array_spec * as2)
+gfc_compare_array_spec (gfc_array_spec *as1, gfc_array_spec *as2)
 {
   int i;
 
@@ -554,7 +572,7 @@ gfc_compare_array_spec (gfc_array_spec * as1, gfc_array_spec * as2)
    elements and should be appended to by gfc_append_constructor().  */
 
 gfc_expr *
-gfc_start_constructor (bt type, int kind, locus * where)
+gfc_start_constructor (bt type, int kind, locus *where)
 {
   gfc_expr *result;
 
@@ -574,7 +592,7 @@ gfc_start_constructor (bt type, int kind, locus * where)
    node onto the constructor.  */
 
 void
-gfc_append_constructor (gfc_expr * base, gfc_expr * new)
+gfc_append_constructor (gfc_expr *base, gfc_expr *new)
 {
   gfc_constructor *c;
 
@@ -601,10 +619,11 @@ gfc_append_constructor (gfc_expr * base, gfc_expr * new)
    constructor onto the base's one according to the offset.  */
 
 void
-gfc_insert_constructor (gfc_expr * base, gfc_constructor * c1)
+gfc_insert_constructor (gfc_expr *base, gfc_constructor *c1)
 {
   gfc_constructor *c, *pre;
   expr_t type;
+  int t;
 
   type = base->expr_type;
 
@@ -614,39 +633,40 @@ gfc_insert_constructor (gfc_expr * base, gfc_constructor * c1)
     {
       c = pre = base->value.constructor;
       while (c)
-        {
-          if (type == EXPR_ARRAY)
-            {
-              if (mpz_cmp (c->n.offset, c1->n.offset) < 0)
-                {
-                  pre = c;
-                  c = c->next;
-                }
-              else if (mpz_cmp (c->n.offset, c1->n.offset) == 0)
-                {
-                  gfc_error ("duplicated initializer");
-                  break;
-                }
-              else
-                break;
-            }
-          else
-            {
-              pre = c;
-              c = c->next;
-            }
-        }
+       {
+         if (type == EXPR_ARRAY)
+           {
+             t = mpz_cmp (c->n.offset, c1->n.offset);
+             if (t < 0)
+               {
+                 pre = c;
+                 c = c->next;
+               }
+             else if (t == 0)
+               {
+                 gfc_error ("duplicated initializer");
+                 break;
+               }
+             else
+               break;
+           }
+         else
+           {
+             pre = c;
+             c = c->next;
+           }
+       }
 
       if (pre != c)
-        {
-          pre->next = c1;
-          c1->next = c;
-        }
+       {
+         pre->next = c1;
+         c1->next = c;
+       }
       else
-        {
-          c1->next = c;
-          base->value.constructor = c1;
-        }
+       {
+         c1->next = c;
+         base->value.constructor = c1;
+       }
     }
 }
 
@@ -658,7 +678,7 @@ gfc_get_constructor (void)
 {
   gfc_constructor *c;
 
-  c = gfc_getmem (sizeof(gfc_constructor));
+  c = XCNEW (gfc_constructor);
   c->expr = NULL;
   c->iterator = NULL;
   c->next = NULL;
@@ -671,7 +691,7 @@ gfc_get_constructor (void)
 /* Free chains of gfc_constructor structures.  */
 
 void
-gfc_free_constructor (gfc_constructor * p)
+gfc_free_constructor (gfc_constructor *p)
 {
   gfc_constructor *next;
 
@@ -683,7 +703,7 @@ gfc_free_constructor (gfc_constructor * p)
       next = p->next;
 
       if (p->expr)
-        gfc_free_expr (p->expr);
+       gfc_free_expr (p->expr);
       if (p->iterator != NULL)
        gfc_free_iterator (p->iterator, 1);
       mpz_clear (p->n.offset);
@@ -699,7 +719,7 @@ gfc_free_constructor (gfc_constructor * p)
    duplicate was found.  */
 
 static int
-check_duplicate_iterator (gfc_constructor * c, gfc_symbol * master)
+check_duplicate_iterator (gfc_constructor *c, gfc_symbol *master)
 {
   gfc_expr *e;
 
@@ -716,9 +736,8 @@ check_duplicate_iterator (gfc_constructor * c, gfc_symbol * master)
 
       if (c->iterator->var->symtree->n.sym == master)
        {
-         gfc_error
-           ("DO-iterator '%s' at %L is inside iterator of the same name",
-            master->name, &c->where);
+         gfc_error ("DO-iterator '%s' at %L is inside iterator of the "
+                    "same name", master->name, &c->where);
 
          return 1;
        }
@@ -734,7 +753,7 @@ static match match_array_cons_element (gfc_constructor **);
 /* Match a list of array elements.  */
 
 static match
-match_array_list (gfc_constructor ** result)
+match_array_list (gfc_constructor **result)
 {
   gfc_constructor *p, *head, *tail, *new;
   gfc_iterator iter;
@@ -743,7 +762,7 @@ match_array_list (gfc_constructor ** result)
   match m;
   int n;
 
-  old_loc = *gfc_current_locus ();
+  old_loc = gfc_current_locus;
 
   if (gfc_match_char ('(') == MATCH_NO)
     return MATCH_NO;
@@ -809,7 +828,7 @@ match_array_list (gfc_constructor ** result)
   e->value.constructor = head;
 
   p = gfc_get_constructor ();
-  p->where = *gfc_current_locus ();
+  p->where = gfc_current_locus;
   p->iterator = gfc_get_iterator ();
   *p->iterator = iter;
 
@@ -825,7 +844,7 @@ syntax:
 cleanup:
   gfc_free_constructor (head);
   gfc_free_iterator (&iter, 0);
-  gfc_set_locus (&old_loc);
+  gfc_current_locus = old_loc;
   return m;
 }
 
@@ -834,7 +853,7 @@ cleanup:
    single expression or a list of elements.  */
 
 static match
-match_array_cons_element (gfc_constructor ** result)
+match_array_cons_element (gfc_constructor **result)
 {
   gfc_constructor *p;
   gfc_expr *expr;
@@ -849,7 +868,7 @@ match_array_cons_element (gfc_constructor ** result)
     return m;
 
   p = gfc_get_constructor ();
-  p->where = *gfc_current_locus ();
+  p->where = gfc_current_locus;
   p->expr = expr;
 
   *result = p;
@@ -860,21 +879,61 @@ match_array_cons_element (gfc_constructor ** result)
 /* Match an array constructor.  */
 
 match
-gfc_match_array_constructor (gfc_expr ** result)
+gfc_match_array_constructor (gfc_expr **result)
 {
   gfc_constructor *head, *tail, *new;
   gfc_expr *expr;
+  gfc_typespec ts;
   locus where;
   match m;
+  const char *end_delim;
+  bool seen_ts;
 
   if (gfc_match (" (/") == MATCH_NO)
-    return MATCH_NO;
+    {
+      if (gfc_match (" [") == MATCH_NO)
+       return MATCH_NO;
+      else
+       {
+         if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: [...] "
+                             "style array constructors at %C") == FAILURE)
+           return MATCH_ERROR;
+         end_delim = " ]";
+       }
+    }
+  else
+    end_delim = " /)";
 
-  where = *gfc_current_locus ();
+  where = gfc_current_locus;
   head = tail = NULL;
+  seen_ts = false;
+
+  /* Try to match an optional "type-spec ::"  */
+  if (gfc_match_type_spec (&ts, 0) == MATCH_YES)
+    {
+      seen_ts = (gfc_match (" ::") == MATCH_YES);
+
+      if (seen_ts)
+       {
+         if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: Array constructor "
+                             "including type specification at %C") == FAILURE)
+           goto cleanup;
+       }
+    }
 
-  if (gfc_match (" /)") == MATCH_YES)
-    goto empty;                        /* Special case */
+  if (! seen_ts)
+    gfc_current_locus = where;
+
+  if (gfc_match (end_delim) == MATCH_YES)
+    {
+      if (seen_ts)
+       goto done;
+      else
+       {
+         gfc_error ("Empty array constructor at %C is not allowed");
+         goto cleanup;
+       }
+    }
 
   for (;;)
     {
@@ -895,10 +954,10 @@ gfc_match_array_constructor (gfc_expr ** result)
        break;
     }
 
-  if (gfc_match (" /)") == MATCH_NO)
+  if (gfc_match (end_delim) == MATCH_NO)
     goto syntax;
 
-empty:
+done:
   expr = gfc_get_expr ();
 
   expr->expr_type = EXPR_ARRAY;
@@ -906,6 +965,14 @@ empty:
   expr->value.constructor = head;
   /* Size must be calculated at resolution time.  */
 
+  if (seen_ts)
+    expr->ts = ts;
+  else
+    expr->ts.type = BT_UNKNOWN;
+  
+  if (expr->ts.cl)
+    expr->ts.cl->length_from_typespec = seen_ts;
+
   expr->where = where;
   expr->rank = 1;
 
@@ -936,11 +1003,10 @@ static enum
 cons_state;
 
 static int
-check_element_type (gfc_expr * expr)
+check_element_type (gfc_expr *expr, bool convert)
 {
-
   if (cons_state == CONS_BAD)
-    return 0;                  /* Supress further errors */
+    return 0;                  /* Suppress further errors */
 
   if (cons_state == CONS_START)
     {
@@ -958,6 +1024,9 @@ check_element_type (gfc_expr * expr)
   if (gfc_compare_types (&constructor_ts, &expr->ts))
     return 0;
 
+  if (convert)
+    return gfc_convert_type (expr, &constructor_ts, 1) == SUCCESS ? 0 : 1;
+
   gfc_error ("Element in %s array constructor at %L is %s",
             gfc_typename (&constructor_ts), &expr->where,
             gfc_typename (&expr->ts));
@@ -967,10 +1036,10 @@ check_element_type (gfc_expr * expr)
 }
 
 
-/* Recursive work function for gfc_check_constructor_type(). */
+/* Recursive work function for gfc_check_constructor_type().  */
 
 static try
-check_constructor_type (gfc_constructor * c)
+check_constructor_type (gfc_constructor *c, bool convert)
 {
   gfc_expr *e;
 
@@ -980,13 +1049,13 @@ check_constructor_type (gfc_constructor * c)
 
       if (e->expr_type == EXPR_ARRAY)
        {
-         if (check_constructor_type (e->value.constructor) == FAILURE)
+         if (check_constructor_type (e->value.constructor, convert) == FAILURE)
            return FAILURE;
 
          continue;
        }
 
-      if (check_element_type (e))
+      if (check_element_type (e, convert))
        return FAILURE;
     }
 
@@ -998,14 +1067,24 @@ check_constructor_type (gfc_constructor * c)
    On FAILURE, an error has been generated.  */
 
 try
-gfc_check_constructor_type (gfc_expr * e)
+gfc_check_constructor_type (gfc_expr *e)
 {
   try t;
 
-  cons_state = CONS_START;
-  gfc_clear_ts (&constructor_ts);
+  if (e->ts.type != BT_UNKNOWN)
+    {
+      cons_state = CONS_GOOD;
+      constructor_ts = e->ts;
+    }
+  else
+    {
+      cons_state = CONS_START;
+      gfc_clear_ts (&constructor_ts);
+    }
 
-  t = check_constructor_type (e->value.constructor);
+  /* If e->ts.type != BT_UNKNOWN, the array constructor included a
+     typespec, and we will now convert the values on the fly.  */
+  t = check_constructor_type (e->value.constructor, e->ts.type != BT_UNKNOWN);
   if (t == SUCCESS && e->ts.type == BT_UNKNOWN)
     e->ts = constructor_ts;
 
@@ -1023,15 +1102,14 @@ cons_stack;
 
 static cons_stack *base;
 
-static try check_constructor (gfc_constructor *, try (*)(gfc_expr *));
+static try check_constructor (gfc_constructor *, try (*) (gfc_expr *));
 
 /* Check an EXPR_VARIABLE expression in a constructor to make sure
    that that variable is an iteration variables.  */
 
 try
-gfc_check_iter_variable (gfc_expr * expr)
+gfc_check_iter_variable (gfc_expr *expr)
 {
-
   gfc_symbol *sym;
   cons_stack *c;
 
@@ -1050,7 +1128,7 @@ gfc_check_iter_variable (gfc_expr * expr)
    constructor, giving variables with the names of iterators a pass.  */
 
 static try
-check_constructor (gfc_constructor * c, try (*check_function) (gfc_expr *))
+check_constructor (gfc_constructor *c, try (*check_function) (gfc_expr *))
 {
   cons_stack element;
   gfc_expr *e;
@@ -1088,7 +1166,7 @@ check_constructor (gfc_constructor * c, try (*check_function) (gfc_expr *))
    determined by the check_function.  */
 
 try
-gfc_check_constructor (gfc_expr * expr, try (*check_function) (gfc_expr *))
+gfc_check_constructor (gfc_expr *expr, try (*check_function) (gfc_expr *))
 {
   cons_stack *base_save;
   try t;
@@ -1132,7 +1210,7 @@ static try expand_constructor (gfc_constructor *);
    constructor.  */
 
 static try
-count_elements (gfc_expr * e)
+count_elements (gfc_expr *e)
 {
   mpz_t result;
 
@@ -1159,7 +1237,7 @@ count_elements (gfc_expr * e)
    constructor, freeing the rest.  */
 
 static try
-extract_element (gfc_expr * e)
+extract_element (gfc_expr *e)
 {
 
   if (e->rank != 0)
@@ -1182,9 +1260,8 @@ extract_element (gfc_expr * e)
    stringing new elements together.  */
 
 static try
-expand (gfc_expr * e)
+expand (gfc_expr *e)
 {
-
   if (current_expand.new_head == NULL)
     current_expand.new_head = current_expand.new_tail =
       gfc_get_constructor ();
@@ -1208,7 +1285,7 @@ expand (gfc_expr * e)
    substitute the current value of the iteration variable.  */
 
 void
-gfc_simplify_iterator_var (gfc_expr * e)
+gfc_simplify_iterator_var (gfc_expr *e)
 {
   iterator_stack *p;
 
@@ -1231,9 +1308,8 @@ gfc_simplify_iterator_var (gfc_expr * e)
    recursing into other constructors if present.  */
 
 static try
-expand_expr (gfc_expr * e)
+expand_expr (gfc_expr *e)
 {
-
   if (e->expr_type == EXPR_ARRAY)
     return expand_constructor (e->value.constructor);
 
@@ -1250,7 +1326,7 @@ expand_expr (gfc_expr * e)
 
 
 static try
-expand_iterator (gfc_constructor * c)
+expand_iterator (gfc_constructor *c)
 {
   gfc_expr *start, *end, *step;
   iterator_stack frame;
@@ -1263,6 +1339,7 @@ expand_iterator (gfc_constructor * c)
 
   mpz_init (trip);
   mpz_init (frame.value);
+  frame.prev = NULL;
 
   start = gfc_copy_expr (c->iterator->start);
   if (gfc_simplify_expr (start, 1) == FAILURE)
@@ -1333,7 +1410,7 @@ cleanup:
    passed expression.  */
 
 static try
-expand_constructor (gfc_constructor * c)
+expand_constructor (gfc_constructor *c)
 {
   gfc_expr *e;
 
@@ -1376,7 +1453,7 @@ expand_constructor (gfc_constructor * c)
    constructor if they are small enough.  */
 
 try
-gfc_expand_constructor (gfc_expr * e)
+gfc_expand_constructor (gfc_expr *e)
 {
   expand_info expand_save;
   gfc_expr *f;
@@ -1420,7 +1497,7 @@ done:
    FAILURE if not so.  */
 
 static try
-constant_element (gfc_expr * e)
+constant_element (gfc_expr *e)
 {
   int rv;
 
@@ -1438,7 +1515,7 @@ constant_element (gfc_expr * e)
    function that traverses the expression tree. FIXME.  */
 
 int
-gfc_constant_ac (gfc_expr * e)
+gfc_constant_ac (gfc_expr *e)
 {
   expand_info expand_save;
   try rc;
@@ -1461,7 +1538,7 @@ gfc_constant_ac (gfc_expr * e)
    expanded (no iterators) and zero if iterators are present.  */
 
 int
-gfc_expanded_ac (gfc_expr * e)
+gfc_expanded_ac (gfc_expr *e)
 {
   gfc_constructor *p;
 
@@ -1480,7 +1557,7 @@ gfc_expanded_ac (gfc_expr * e)
    be of the same type.  */
 
 static try
-resolve_array_list (gfc_constructor * p)
+resolve_array_list (gfc_constructor *p)
 {
   try t;
 
@@ -1489,7 +1566,7 @@ resolve_array_list (gfc_constructor * p)
   for (; p; p = p->next)
     {
       if (p->iterator != NULL
-         && gfc_resolve_iterator (p->iterator) == FAILURE)
+         && gfc_resolve_iterator (p->iterator, false) == FAILURE)
        t = FAILURE;
 
       if (gfc_resolve_expr (p->expr) == FAILURE)
@@ -1499,12 +1576,143 @@ resolve_array_list (gfc_constructor * p)
   return t;
 }
 
+/* Resolve character array constructor. If it has a specified constant character
+   length, pad/trunkate the elements here; if the length is not specified and
+   all elements are of compile-time known length, emit an error as this is
+   invalid.  */
 
-/* Resolve all of the expressions in an array list.
-   TODO: String lengths.  */
+try
+gfc_resolve_character_array_constructor (gfc_expr *expr)
+{
+  gfc_constructor *p;
+  int found_length;
+
+  gcc_assert (expr->expr_type == EXPR_ARRAY);
+  gcc_assert (expr->ts.type == BT_CHARACTER);
+
+  if (expr->ts.cl == NULL)
+    {
+      for (p = expr->value.constructor; p; p = p->next)
+       if (p->expr->ts.cl != NULL)
+         {
+           /* Ensure that if there is a char_len around that it is
+              used; otherwise the middle-end confuses them!  */
+           expr->ts.cl = p->expr->ts.cl;
+           goto got_charlen;
+         }
+
+      expr->ts.cl = gfc_get_charlen ();
+      expr->ts.cl->next = gfc_current_ns->cl_list;
+      gfc_current_ns->cl_list = expr->ts.cl;
+    }
+
+got_charlen:
+
+  found_length = -1;
+
+  if (expr->ts.cl->length == NULL)
+    {
+      /* Check that all constant string elements have the same length until
+        we reach the end or find a variable-length one.  */
+
+      for (p = expr->value.constructor; p; p = p->next)
+       {
+         int current_length = -1;
+         gfc_ref *ref;
+         for (ref = p->expr->ref; ref; ref = ref->next)
+           if (ref->type == REF_SUBSTRING
+               && ref->u.ss.start->expr_type == EXPR_CONSTANT
+               && ref->u.ss.end->expr_type == EXPR_CONSTANT)
+             break;
+
+         if (p->expr->expr_type == EXPR_CONSTANT)
+           current_length = p->expr->value.character.length;
+         else if (ref)
+           {
+             long j;
+             j = mpz_get_ui (ref->u.ss.end->value.integer)
+               - mpz_get_ui (ref->u.ss.start->value.integer) + 1;
+             current_length = (int) j;
+           }
+         else if (p->expr->ts.cl && p->expr->ts.cl->length
+                  && p->expr->ts.cl->length->expr_type == EXPR_CONSTANT)
+           {
+             long j;
+             j = mpz_get_si (p->expr->ts.cl->length->value.integer);
+             current_length = (int) j;
+           }
+         else
+           return SUCCESS;
+
+         gcc_assert (current_length != -1);
+
+         if (found_length == -1)
+           found_length = current_length;
+         else if (found_length != current_length)
+           {
+             gfc_error ("Different CHARACTER lengths (%d/%d) in array"
+                        " constructor at %L", found_length, current_length,
+                        &p->expr->where);
+             return FAILURE;
+           }
+
+         gcc_assert (found_length == current_length);
+       }
+
+      gcc_assert (found_length != -1);
+
+      /* Update the character length of the array constructor.  */
+      expr->ts.cl->length = gfc_int_expr (found_length);
+    }
+  else 
+    {
+      /* We've got a character length specified.  It should be an integer,
+        otherwise an error is signalled elsewhere.  */
+      gcc_assert (expr->ts.cl->length);
+
+      /* If we've got a constant character length, pad according to this.
+        gfc_extract_int does check for BT_INTEGER and EXPR_CONSTANT and sets
+        max_length only if they pass.  */
+      gfc_extract_int (expr->ts.cl->length, &found_length);
+
+      /* Now pad/trunkate the elements accordingly to the specified character
+        length.  This is ok inside this conditional, as in the case above
+        (without typespec) all elements are verified to have the same length
+        anyway.  */
+      if (found_length != -1)
+       for (p = expr->value.constructor; p; p = p->next)
+         if (p->expr->expr_type == EXPR_CONSTANT)
+           {
+             gfc_expr *cl = NULL;
+             int current_length = -1;
+             bool has_ts;
+
+             if (p->expr->ts.cl && p->expr->ts.cl->length)
+             {
+               cl = p->expr->ts.cl->length;
+               gfc_extract_int (cl, &current_length);
+             }
+
+             /* If gfc_extract_int above set current_length, we implicitly
+                know the type is BT_INTEGER and it's EXPR_CONSTANT.  */
+
+             has_ts = (expr->ts.cl && expr->ts.cl->length_from_typespec);
+
+             if (! cl
+                 || (current_length != -1 && current_length < found_length))
+               gfc_set_constant_character_len (found_length, p->expr,
+                                               has_ts ? -1 : found_length);
+           }
+    }
+
+  return SUCCESS;
+}
+
+
+/* Resolve all of the expressions in an array list.  */
 
 try
-gfc_resolve_array_constructor (gfc_expr * expr)
+gfc_resolve_array_constructor (gfc_expr *expr)
 {
   try t;
 
@@ -1512,6 +1720,10 @@ gfc_resolve_array_constructor (gfc_expr * expr)
   if (t == SUCCESS)
     t = gfc_check_constructor_type (expr);
 
+  /* gfc_resolve_character_array_constructor is called in gfc_resolve_expr after
+     the call to this function, so we don't need to call it here; if it was
+     called twice, an error message there would be duplicated.  */
+
   return t;
 }
 
@@ -1519,7 +1731,7 @@ gfc_resolve_array_constructor (gfc_expr * expr)
 /* Copy an iterator structure.  */
 
 static gfc_iterator *
-copy_iterator (gfc_iterator * src)
+copy_iterator (gfc_iterator *src)
 {
   gfc_iterator *dest;
 
@@ -1540,7 +1752,7 @@ copy_iterator (gfc_iterator * src)
 /* Copy a constructor structure.  */
 
 gfc_constructor *
-gfc_copy_constructor (gfc_constructor * src)
+gfc_copy_constructor (gfc_constructor *src)
 {
   gfc_constructor *dest;
   gfc_constructor *tail;
@@ -1579,7 +1791,7 @@ gfc_copy_constructor (gfc_constructor * src)
    have to be particularly fast.  */
 
 gfc_expr *
-gfc_get_array_element (gfc_expr * array, int element)
+gfc_get_array_element (gfc_expr *array, int element)
 {
   expand_info expand_save;
   gfc_expr *e;
@@ -1606,18 +1818,17 @@ gfc_get_array_element (gfc_expr * array, int element)
 
 /********* Subroutines for determining the size of an array *********/
 
-/* These are needed just to accomodate RESHAPE().  There are no
+/* These are needed just to accommodate RESHAPE().  There are no
    diagnostics here, we just return a negative number if something
-   goes wrong. */
+   goes wrong.  */
 
 
 /* Get the size of single dimension of an array specification.  The
    array is guaranteed to be one dimensional.  */
 
-static try
-spec_dimen_size (gfc_array_spec * as, int dimen, mpz_t * result)
+try
+spec_dimen_size (gfc_array_spec *as, int dimen, mpz_t *result)
 {
-
   if (as == NULL)
     return FAILURE;
 
@@ -1626,7 +1837,9 @@ spec_dimen_size (gfc_array_spec * as, int dimen, mpz_t * result)
 
   if (as->type != AS_EXPLICIT
       || as->lower[dimen]->expr_type != EXPR_CONSTANT
-      || as->upper[dimen]->expr_type != EXPR_CONSTANT)
+      || as->upper[dimen]->expr_type != EXPR_CONSTANT
+      || as->lower[dimen]->ts.type != BT_INTEGER
+      || as->upper[dimen]->ts.type != BT_INTEGER)
     return FAILURE;
 
   mpz_init (*result);
@@ -1641,7 +1854,7 @@ spec_dimen_size (gfc_array_spec * as, int dimen, mpz_t * result)
 
 
 try
-spec_size (gfc_array_spec * as, mpz_t * result)
+spec_size (gfc_array_spec *as, mpz_t *result)
 {
   mpz_t size;
   int d;
@@ -1667,7 +1880,7 @@ spec_size (gfc_array_spec * as, mpz_t * result)
 /* Get the number of elements in an array section.  */
 
 static try
-ref_dimen_size (gfc_array_ref * ar, int dimen, mpz_t * result)
+ref_dimen_size (gfc_array_ref *ar, int dimen, mpz_t *result)
 {
   mpz_t upper, lower, stride;
   try t;
@@ -1755,7 +1968,7 @@ ref_dimen_size (gfc_array_ref * ar, int dimen, mpz_t * result)
 
 
 static try
-ref_size (gfc_array_ref * ar, mpz_t * result)
+ref_size (gfc_array_ref *ar, mpz_t *result)
 {
   mpz_t size;
   int d;
@@ -1784,7 +1997,7 @@ ref_size (gfc_array_ref * ar, mpz_t * result)
    otherwise.  */
 
 try
-gfc_array_dimen_size (gfc_expr * array, int dimen, mpz_t * result)
+gfc_array_dimen_size (gfc_expr *array, int dimen, mpz_t *result)
 {
   gfc_ref *ref;
   int i;
@@ -1814,6 +2027,12 @@ gfc_array_dimen_size (gfc_expr * array, int dimen, mpz_t * result)
            }
        }
 
+      if (array->shape && array->shape[dimen])
+       {
+         mpz_init_set (*result, array->shape[dimen]);
+         return SUCCESS;
+       }
+
       if (spec_dimen_size (array->symtree->n.sym->as, dimen, result) == FAILURE)
        return FAILURE;
 
@@ -1846,7 +2065,7 @@ gfc_array_dimen_size (gfc_expr * array, int dimen, mpz_t * result)
    variable.  Otherwise returns FAILURE.  */
 
 try
-gfc_array_size (gfc_expr * array, mpz_t * result)
+gfc_array_size (gfc_expr *array, mpz_t *result)
 {
   expand_info expand_save;
   gfc_ref *ref;
@@ -1911,7 +2130,7 @@ gfc_array_size (gfc_expr * array, mpz_t * result)
    array of mpz_t integers.  */
 
 try
-gfc_array_ref_shape (gfc_array_ref * ar, mpz_t * shape)
+gfc_array_ref_shape (gfc_array_ref *ar, mpz_t *shape)
 {
   int d;
   int i;
@@ -1956,14 +2175,13 @@ cleanup:
    characterizes the reference.  */
 
 gfc_array_ref *
-gfc_find_array_ref (gfc_expr * e)
+gfc_find_array_ref (gfc_expr *e)
 {
   gfc_ref *ref;
 
   for (ref = e->ref; ref; ref = ref->next)
     if (ref->type == REF_ARRAY
-       && (ref->u.ar.type == AR_FULL
-           || ref->u.ar.type == AR_SECTION))
+       && (ref->u.ar.type == AR_FULL || ref->u.ar.type == AR_SECTION))
       break;
 
   if (ref == NULL)
@@ -1971,3 +2189,22 @@ gfc_find_array_ref (gfc_expr * e)
 
   return &ref->u.ar;
 }
+
+
+/* Find out if an array shape is known at compile time.  */
+
+int
+gfc_is_compile_time_shape (gfc_array_spec *as)
+{
+  int i;
+
+  if (as->type != AS_EXPLICIT)
+    return 0;
+
+  for (i = 0; i < as->rank; i++)
+    if (!gfc_is_constant_expr (as->lower[i])
+       || !gfc_is_constant_expr (as->upper[i]))
+      return 0;
+
+  return 1;
+}