OSDN Git Service

2010-04-06 Tobias Burnus <burnus@net-b.de>
[pf3gnuchains/gcc-fork.git] / gcc / fortran / array.c
index a34695e..4282fd1 100644 (file)
@@ -1,5 +1,5 @@
 /* Array things
-   Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008
+   Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
    Contributed by Andy Vaught
 
@@ -24,13 +24,6 @@ along with GCC; see the file COPYING3.  If not see
 #include "gfortran.h"
 #include "match.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 65535
-
-
 /**************** Array reference matching subroutines *****************/
 
 /* Copy an array reference structure.  */
@@ -195,7 +188,7 @@ gfc_free_array_spec (gfc_array_spec *as)
   if (as == NULL)
     return;
 
-  for (i = 0; i < as->rank; i++)
+  for (i = 0; i < as->rank + as->corank; i++)
     {
       gfc_free_expr (as->lower[i]);
       gfc_free_expr (as->upper[i]);
@@ -208,7 +201,7 @@ gfc_free_array_spec (gfc_array_spec *as)
 /* Take an array bound, resolves the expression, that make up the
    shape and check associated constraints.  */
 
-static try
+static gfc_try
 resolve_array_bound (gfc_expr *e, int check_constant)
 {
   if (e == NULL)
@@ -232,7 +225,7 @@ resolve_array_bound (gfc_expr *e, int check_constant)
 /* Takes an array specification, resolves the expressions that make up
    the shape and make sure everything is integral.  */
 
-try
+gfc_try
 gfc_resolve_array_spec (gfc_array_spec *as, int check_constant)
 {
   gfc_expr *e;
@@ -241,7 +234,7 @@ gfc_resolve_array_spec (gfc_array_spec *as, int check_constant)
   if (as == NULL)
     return SUCCESS;
 
-  for (i = 0; i < as->rank; i++)
+  for (i = 0; i < as->rank + as->corank; i++)
     {
       e = as->lower[i];
       if (resolve_array_bound (e, check_constant) == FAILURE)
@@ -297,8 +290,8 @@ match_array_element_spec (gfc_array_spec *as)
   gfc_expr **upper, **lower;
   match m;
 
-  lower = &as->lower[as->rank - 1];
-  upper = &as->upper[as->rank - 1];
+  lower = &as->lower[as->rank + as->corank - 1];
+  upper = &as->upper[as->rank + as->corank - 1];
 
   if (gfc_match_char ('*') == MATCH_YES)
     {
@@ -314,6 +307,8 @@ match_array_element_spec (gfc_array_spec *as)
     gfc_error ("Expected expression in array specification at %C");
   if (m != MATCH_YES)
     return AS_UNKNOWN;
+  if (gfc_expr_check_typed (*upper, gfc_current_ns, false) == FAILURE)
+    return AS_UNKNOWN;
 
   if (gfc_match_char (':') == MATCH_NO)
     {
@@ -332,28 +327,27 @@ match_array_element_spec (gfc_array_spec *as)
     return AS_UNKNOWN;
   if (m == MATCH_NO)
     return AS_ASSUMED_SHAPE;
+  if (gfc_expr_check_typed (*upper, gfc_current_ns, false) == FAILURE)
+    return AS_UNKNOWN;
 
   return AS_EXPLICIT;
 }
 
 
 /* Matches an array specification, incidentally figuring out what sort
-   it is.  */
+   it is. Match either a normal array specification, or a coarray spec
+   or both. Optionally allow [:] for coarrays.  */
 
 match
-gfc_match_array_spec (gfc_array_spec **asp)
+gfc_match_array_spec (gfc_array_spec **asp, bool match_dim, bool match_codim)
 {
   array_type current_type;
   gfc_array_spec *as;
   int i;
-
-  if (gfc_match_char ('(') != MATCH_YES)
-    {
-      *asp = NULL;
-      return MATCH_NO;
-    }
-
   as = gfc_get_array_spec ();
+  as->corank = 0;
+  as->rank = 0;
 
   for (i = 0; i < GFC_MAX_DIMENSIONS; i++)
     {
@@ -361,10 +355,19 @@ gfc_match_array_spec (gfc_array_spec **asp)
       as->upper[i] = NULL;
     }
 
-  as->rank = 1;
+  if (!match_dim)
+    goto coarray;
+
+  if (gfc_match_char ('(') != MATCH_YES)
+    {
+      if (!match_codim)
+       goto done;
+      goto coarray;
+    }
 
   for (;;)
     {
+      as->rank++;
       current_type = match_array_element_spec (as);
 
       if (as->rank == 1)
@@ -430,32 +433,144 @@ gfc_match_array_spec (gfc_array_spec **asp)
          goto cleanup;
        }
 
-      if (as->rank >= GFC_MAX_DIMENSIONS)
+      if (as->rank + as->corank >= GFC_MAX_DIMENSIONS)
        {
          gfc_error ("Array specification at %C has more than %d dimensions",
                     GFC_MAX_DIMENSIONS);
          goto cleanup;
        }
 
-      if (as->rank > 7
+      if (as->corank + 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++;
+  if (!match_codim)
+    goto done;
+
+coarray:
+  if (gfc_match_char ('[')  != MATCH_YES)
+    goto done;
+
+  if (gfc_notify_std (GFC_STD_F2008, "Fortran 2008: Coarray declaration at %C")
+      == FAILURE)
+    goto cleanup;
+
+  if (gfc_option.coarray == GFC_FCOARRAY_NONE)
+    {
+       gfc_error ("Coarrays disabled at %C, use -fcoarray= to enable");
+       goto cleanup;
+    }
+
+  for (;;)
+    {
+      as->corank++;
+      current_type = match_array_element_spec (as);
+
+      if (current_type == AS_UNKNOWN)
+       goto cleanup;
+
+      if (as->corank == 1)
+       as->cotype = current_type;
+      else
+       switch (as->cotype)
+         { /* See how current spec meshes with the existing.  */
+           case AS_UNKNOWN:
+             goto cleanup;
+
+           case AS_EXPLICIT:
+             if (current_type == AS_ASSUMED_SIZE)
+               {
+                 as->cotype = AS_ASSUMED_SIZE;
+                 break;
+               }
+
+             if (current_type == AS_EXPLICIT)
+               break;
+
+             gfc_error ("Bad array specification for an explicitly "
+                        "shaped array at %C");
+
+             goto cleanup;
+
+           case AS_ASSUMED_SHAPE:
+             if ((current_type == AS_ASSUMED_SHAPE)
+                 || (current_type == AS_DEFERRED))
+               break;
+
+             gfc_error ("Bad array specification for assumed shape "
+                        "array at %C");
+             goto cleanup;
+
+           case AS_DEFERRED:
+             if (current_type == AS_DEFERRED)
+               break;
+
+             if (current_type == AS_ASSUMED_SHAPE)
+               {
+                 as->cotype = AS_ASSUMED_SHAPE;
+                 break;
+               }
+
+             gfc_error ("Bad specification for deferred shape array at %C");
+             goto cleanup;
+
+           case AS_ASSUMED_SIZE:
+             gfc_error ("Bad specification for assumed size array at %C");
+             goto cleanup;
+         }
+
+      if (gfc_match_char (']') == MATCH_YES)
+       break;
+
+      if (gfc_match_char (',') != MATCH_YES)
+       {
+         gfc_error ("Expected another dimension in array declaration at %C");
+         goto cleanup;
+       }
+
+      if (as->corank >= GFC_MAX_DIMENSIONS)
+       {
+         gfc_error ("Array specification at %C has more than %d "
+                    "dimensions", GFC_MAX_DIMENSIONS);
+         goto cleanup;
+       }
+    }
+
+  if (current_type == AS_EXPLICIT)
+    {
+      gfc_error ("Upper bound of last coarray dimension must be '*' at %C");
+      goto cleanup;
+    }
+
+  if (as->cotype == AS_ASSUMED_SIZE)
+    as->cotype = AS_EXPLICIT;
+
+  if (as->rank == 0)
+    as->type = as->cotype;
+
+done:
+  if (as->rank == 0 && as->corank == 0)
+    {
+      *asp = NULL;
+      gfc_free_array_spec (as);
+      return MATCH_NO;
     }
 
   /* If a lower bounds of an assumed shape array is blank, put in one.  */
   if (as->type == AS_ASSUMED_SHAPE)
     {
-      for (i = 0; i < as->rank; i++)
+      for (i = 0; i < as->rank + as->corank; i++)
        {
          if (as->lower[i] == NULL)
            as->lower[i] = gfc_int_expr (1);
        }
     }
+
   *asp = as;
+
   return MATCH_YES;
 
 cleanup:
@@ -469,17 +584,67 @@ cleanup:
    have that array specification.  The error locus is needed in case
    something goes wrong.  On failure, the caller must free the spec.  */
 
-try
+gfc_try
 gfc_set_array_spec (gfc_symbol *sym, gfc_array_spec *as, locus *error_loc)
 {
+  int i;
+
   if (as == NULL)
     return SUCCESS;
 
-  if (gfc_add_dimension (&sym->attr, sym->name, error_loc) == FAILURE)
+  if (as->rank
+      && gfc_add_dimension (&sym->attr, sym->name, error_loc) == FAILURE)
     return FAILURE;
 
-  sym->as = as;
+  if (as->corank
+      && gfc_add_codimension (&sym->attr, sym->name, error_loc) == FAILURE)
+    return FAILURE;
+
+  if (sym->as == NULL)
+    {
+      sym->as = as;
+      return SUCCESS;
+    }
+
+  if (as->corank)
+    {
+      /* The "sym" has no corank (checked via gfc_add_codimension). Thus
+        the codimension is simply added.  */
+      gcc_assert (as->rank == 0 && sym->as->corank == 0);
+
+      sym->as->cotype = as->cotype;
+      sym->as->corank = as->corank;
+      for (i = 0; i < as->corank; i++)
+       {
+         sym->as->lower[sym->as->rank + i] = as->lower[i];
+         sym->as->upper[sym->as->rank + i] = as->upper[i];
+       }
+    }
+  else
+    {
+      /* The "sym" has no rank (checked via gfc_add_dimension). Thus
+        the dimension is added - but first the codimensions (if existing
+        need to be shifted to make space for the dimension.  */
+      gcc_assert (as->corank == 0 && sym->as->rank == 0);
+
+      sym->as->rank = as->rank;
+      sym->as->type = as->type;
+      sym->as->cray_pointee = as->cray_pointee;
+      sym->as->cp_was_assumed = as->cp_was_assumed;
+
+      for (i = 0; i < sym->as->corank; i++)
+       {
+         sym->as->lower[as->rank + i] = sym->as->lower[i];
+         sym->as->upper[as->rank + i] = sym->as->upper[i];
+       }
+      for (i = 0; i < as->rank; i++)
+       {
+         sym->as->lower[i] = as->lower[i];
+         sym->as->upper[i] = as->upper[i];
+       }
+    }
 
+  gfc_free (as);
   return SUCCESS;
 }
 
@@ -499,7 +664,7 @@ gfc_copy_array_spec (gfc_array_spec *src)
 
   *dest = *src;
 
-  for (i = 0; i < dest->rank; i++)
+  for (i = 0; i < dest->rank + dest->corank; i++)
     {
       dest->lower[i] = gfc_copy_expr (dest->lower[i]);
       dest->upper[i] = gfc_copy_expr (dest->upper[i]);
@@ -546,6 +711,9 @@ gfc_compare_array_spec (gfc_array_spec *as1, gfc_array_spec *as2)
   if (as1->rank != as2->rank)
     return 0;
 
+  if (as1->corank != as2->corank)
+    return 0;
+
   if (as1->rank == 0)
     return 1;
 
@@ -553,7 +721,7 @@ gfc_compare_array_spec (gfc_array_spec *as1, gfc_array_spec *as2)
     return 0;
 
   if (as1->type == AS_EXPLICIT)
-    for (i = 0; i < as1->rank; i++)
+    for (i = 0; i < as1->rank + as1->corank; i++)
       {
        if (compare_bounds (as1->lower[i], as2->lower[i]) == 0)
          return 0;
@@ -592,7 +760,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_expr)
 {
   gfc_constructor *c;
 
@@ -608,9 +776,10 @@ gfc_append_constructor (gfc_expr *base, gfc_expr *new)
       c = c->next;
     }
 
-  c->expr = new;
+  c->expr = new_expr;
 
-  if (new->ts.type != base->ts.type || new->ts.kind != base->ts.kind)
+  if (new_expr
+      && (new_expr->ts.type != base->ts.type || new_expr->ts.kind != base->ts.kind))
     gfc_internal_error ("gfc_append_constructor(): New node has wrong kind");
 }
 
@@ -678,7 +847,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;
@@ -755,7 +924,7 @@ static match match_array_cons_element (gfc_constructor **);
 static match
 match_array_list (gfc_constructor **result)
 {
-  gfc_constructor *p, *head, *tail, *new;
+  gfc_constructor *p, *head, *tail, *new_cons;
   gfc_iterator iter;
   locus old_loc;
   gfc_expr *e;
@@ -790,7 +959,7 @@ match_array_list (gfc_constructor **result)
       if (m == MATCH_ERROR)
        goto cleanup;
 
-      m = match_array_cons_element (&new);
+      m = match_array_cons_element (&new_cons);
       if (m == MATCH_ERROR)
        goto cleanup;
       if (m == MATCH_NO)
@@ -801,8 +970,8 @@ match_array_list (gfc_constructor **result)
          goto cleanup;         /* Could be a complex constant */
        }
 
-      tail->next = new;
-      tail = new;
+      tail->next = new_cons;
+      tail = new_cons;
 
       if (gfc_match_char (',') != MATCH_YES)
        {
@@ -881,7 +1050,7 @@ match_array_cons_element (gfc_constructor **result)
 match
 gfc_match_array_constructor (gfc_expr **result)
 {
-  gfc_constructor *head, *tail, *new;
+  gfc_constructor *head, *tail, *new_cons;
   gfc_expr *expr;
   gfc_typespec ts;
   locus where;
@@ -909,7 +1078,7 @@ gfc_match_array_constructor (gfc_expr **result)
   seen_ts = false;
 
   /* Try to match an optional "type-spec ::"  */
-  if (gfc_match_type_spec (&ts, 0) == MATCH_YES)
+  if (gfc_match_decl_type_spec (&ts, 0) == MATCH_YES)
     {
       seen_ts = (gfc_match (" ::") == MATCH_YES);
 
@@ -937,18 +1106,18 @@ gfc_match_array_constructor (gfc_expr **result)
 
   for (;;)
     {
-      m = match_array_cons_element (&new);
+      m = match_array_cons_element (&new_cons);
       if (m == MATCH_ERROR)
        goto cleanup;
       if (m == MATCH_NO)
        goto syntax;
 
       if (head == NULL)
-       head = new;
+       head = new_cons;
       else
-       tail->next = new;
+       tail->next = new_cons;
 
-      tail = new;
+      tail = new_cons;
 
       if (gfc_match_char (',') == MATCH_NO)
        break;
@@ -970,8 +1139,8 @@ done:
   else
     expr->ts.type = BT_UNKNOWN;
   
-  if (expr->ts.cl)
-    expr->ts.cl->length_from_typespec = seen_ts;
+  if (expr->ts.u.cl)
+    expr->ts.u.cl->length_from_typespec = seen_ts;
 
   expr->where = where;
   expr->rank = 1;
@@ -1038,7 +1207,7 @@ check_element_type (gfc_expr *expr, bool convert)
 
 /* Recursive work function for gfc_check_constructor_type().  */
 
-static try
+static gfc_try
 check_constructor_type (gfc_constructor *c, bool convert)
 {
   gfc_expr *e;
@@ -1066,10 +1235,10 @@ check_constructor_type (gfc_constructor *c, bool convert)
 /* Check that all elements of an array constructor are the same type.
    On FAILURE, an error has been generated.  */
 
-try
+gfc_try
 gfc_check_constructor_type (gfc_expr *e)
 {
-  try t;
+  gfc_try t;
 
   if (e->ts.type != BT_UNKNOWN)
     {
@@ -1102,12 +1271,12 @@ cons_stack;
 
 static cons_stack *base;
 
-static try check_constructor (gfc_constructor *, try (*) (gfc_expr *));
+static gfc_try check_constructor (gfc_constructor *, gfc_try (*) (gfc_expr *));
 
 /* Check an EXPR_VARIABLE expression in a constructor to make sure
    that that variable is an iteration variables.  */
 
-try
+gfc_try
 gfc_check_iter_variable (gfc_expr *expr)
 {
   gfc_symbol *sym;
@@ -1127,12 +1296,12 @@ gfc_check_iter_variable (gfc_expr *expr)
    to calling the check function for each expression in the
    constructor, giving variables with the names of iterators a pass.  */
 
-static try
-check_constructor (gfc_constructor *c, try (*check_function) (gfc_expr *))
+static gfc_try
+check_constructor (gfc_constructor *c, gfc_try (*check_function) (gfc_expr *))
 {
   cons_stack element;
   gfc_expr *e;
-  try t;
+  gfc_try t;
 
   for (; c; c = c->next)
     {
@@ -1165,11 +1334,11 @@ check_constructor (gfc_constructor *c, try (*check_function) (gfc_expr *))
    expression -- specification, restricted, or initialization as
    determined by the check_function.  */
 
-try
-gfc_check_constructor (gfc_expr *expr, try (*check_function) (gfc_expr *))
+gfc_try
+gfc_check_constructor (gfc_expr *expr, gfc_try (*check_function) (gfc_expr *))
 {
   cons_stack *base_save;
-  try t;
+  gfc_try t;
 
   base_save = base;
   base = NULL;
@@ -1197,19 +1366,19 @@ typedef struct
   gfc_component *component;
   mpz_t *repeat;
 
-  try (*expand_work_function) (gfc_expr *);
+  gfc_try (*expand_work_function) (gfc_expr *);
 }
 expand_info;
 
 static expand_info current_expand;
 
-static try expand_constructor (gfc_constructor *);
+static gfc_try expand_constructor (gfc_constructor *);
 
 
 /* Work function that counts the number of elements present in a
    constructor.  */
 
-static try
+static gfc_try
 count_elements (gfc_expr *e)
 {
   mpz_t result;
@@ -1236,10 +1405,9 @@ count_elements (gfc_expr *e)
 /* Work function that extracts a particular element from an array
    constructor, freeing the rest.  */
 
-static try
+static gfc_try
 extract_element (gfc_expr *e)
 {
-
   if (e->rank != 0)
     {                          /* Something unextractable */
       gfc_free_expr (e);
@@ -1252,6 +1420,7 @@ extract_element (gfc_expr *e)
     gfc_free_expr (e);
 
   current_expand.extract_count++;
+  
   return SUCCESS;
 }
 
@@ -1259,7 +1428,7 @@ extract_element (gfc_expr *e)
 /* Work function that constructs a new constructor out of the old one,
    stringing new elements together.  */
 
-static try
+static gfc_try
 expand (gfc_expr *e)
 {
   if (current_expand.new_head == NULL)
@@ -1307,7 +1476,7 @@ gfc_simplify_iterator_var (gfc_expr *e)
 /* Expand an expression with that is inside of a constructor,
    recursing into other constructors if present.  */
 
-static try
+static gfc_try
 expand_expr (gfc_expr *e)
 {
   if (e->expr_type == EXPR_ARRAY)
@@ -1325,13 +1494,13 @@ expand_expr (gfc_expr *e)
 }
 
 
-static try
+static gfc_try
 expand_iterator (gfc_constructor *c)
 {
   gfc_expr *start, *end, *step;
   iterator_stack frame;
   mpz_t trip;
-  try t;
+  gfc_try t;
 
   end = step = NULL;
 
@@ -1409,7 +1578,7 @@ cleanup:
    expressions.  The work function needs to either save or free the
    passed expression.  */
 
-static try
+static gfc_try
 expand_constructor (gfc_constructor *c)
 {
   gfc_expr *e;
@@ -1452,14 +1621,14 @@ expand_constructor (gfc_constructor *c)
 /* Top level subroutine for expanding constructors.  We only expand
    constructor if they are small enough.  */
 
-try
+gfc_try
 gfc_expand_constructor (gfc_expr *e)
 {
   expand_info expand_save;
   gfc_expr *f;
-  try rc;
+  gfc_try rc;
 
-  f = gfc_get_array_element (e, GFC_MAX_AC_EXPAND);
+  f = gfc_get_array_element (e, gfc_option.flag_max_array_constructor);
   if (f != NULL)
     {
       gfc_free_expr (f);
@@ -1496,8 +1665,8 @@ done:
    constant, after removal of any iteration variables.  We return
    FAILURE if not so.  */
 
-static try
-constant_element (gfc_expr *e)
+static gfc_try
+is_constant_element (gfc_expr *e)
 {
   int rv;
 
@@ -1518,15 +1687,38 @@ int
 gfc_constant_ac (gfc_expr *e)
 {
   expand_info expand_save;
-  try rc;
+  gfc_try rc;
+  gfc_constructor * con;
+  
+  rc = SUCCESS;
 
-  iter_stack = NULL;
-  expand_save = current_expand;
-  current_expand.expand_work_function = constant_element;
+  if (e->value.constructor
+      && e->value.constructor->expr->expr_type == EXPR_ARRAY)
+    {
+      /* Expand the constructor.  */
+      iter_stack = NULL;
+      expand_save = current_expand;
+      current_expand.expand_work_function = is_constant_element;
 
-  rc = expand_constructor (e->value.constructor);
+      rc = expand_constructor (e->value.constructor);
+
+      current_expand = expand_save;
+    }
+  else
+    {
+      /* No need to expand this further.  */
+      for (con = e->value.constructor; con; con = con->next)
+       {
+         if (con->expr->expr_type == EXPR_CONSTANT)
+           continue;
+         else
+           {
+             if (!gfc_is_constant_expr (con->expr))
+               rc = FAILURE;
+           }
+       }
+    }
 
-  current_expand = expand_save;
   if (rc == FAILURE)
     return 0;
 
@@ -1556,10 +1748,10 @@ gfc_expanded_ac (gfc_expr *e)
 /* Recursive array list resolution function.  All of the elements must
    be of the same type.  */
 
-static try
+static gfc_try
 resolve_array_list (gfc_constructor *p)
 {
-  try t;
+  gfc_try t;
 
   t = SUCCESS;
 
@@ -1577,11 +1769,11 @@ resolve_array_list (gfc_constructor *p)
 }
 
 /* Resolve character array constructor. If it has a specified constant character
-   length, pad/trunkate the elements here; if the length is not specified and
+   length, pad/truncate 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.  */
 
-try
+gfc_try
 gfc_resolve_character_array_constructor (gfc_expr *expr)
 {
   gfc_constructor *p;
@@ -1590,27 +1782,25 @@ gfc_resolve_character_array_constructor (gfc_expr *expr)
   gcc_assert (expr->expr_type == EXPR_ARRAY);
   gcc_assert (expr->ts.type == BT_CHARACTER);
 
-  if (expr->ts.cl == NULL)
+  if (expr->ts.u.cl == NULL)
     {
       for (p = expr->value.constructor; p; p = p->next)
-       if (p->expr->ts.cl != NULL)
+       if (p->expr->ts.u.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;
+           expr->ts.u.cl = p->expr->ts.u.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;
+      expr->ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL);
     }
 
 got_charlen:
 
   found_length = -1;
 
-  if (expr->ts.cl->length == NULL)
+  if (expr->ts.u.cl->length == NULL)
     {
       /* Check that all constant string elements have the same length until
         we reach the end or find a variable-length one.  */
@@ -1634,11 +1824,11 @@ got_charlen:
                - 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)
+         else if (p->expr->ts.u.cl && p->expr->ts.u.cl->length
+                  && p->expr->ts.u.cl->length->expr_type == EXPR_CONSTANT)
            {
              long j;
-             j = mpz_get_si (p->expr->ts.cl->length->value.integer);
+             j = mpz_get_si (p->expr->ts.u.cl->length->value.integer);
              current_length = (int) j;
            }
          else
@@ -1662,20 +1852,20 @@ got_charlen:
       gcc_assert (found_length != -1);
 
       /* Update the character length of the array constructor.  */
-      expr->ts.cl->length = gfc_int_expr (found_length);
+      expr->ts.u.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);
+      gcc_assert (expr->ts.u.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);
+      gfc_extract_int (expr->ts.u.cl->length, &found_length);
 
-      /* Now pad/trunkate the elements accordingly to the specified character
+      /* Now pad/truncate 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.  */
@@ -1687,16 +1877,16 @@ got_charlen:
              int current_length = -1;
              bool has_ts;
 
-             if (p->expr->ts.cl && p->expr->ts.cl->length)
+             if (p->expr->ts.u.cl && p->expr->ts.u.cl->length)
              {
-               cl = p->expr->ts.cl->length;
+               cl = p->expr->ts.u.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);
+             has_ts = (expr->ts.u.cl && expr->ts.u.cl->length_from_typespec);
 
              if (! cl
                  || (current_length != -1 && current_length < found_length))
@@ -1711,10 +1901,10 @@ got_charlen:
 
 /* Resolve all of the expressions in an array list.  */
 
-try
+gfc_try
 gfc_resolve_array_constructor (gfc_expr *expr)
 {
-  try t;
+  gfc_try t;
 
   t = resolve_array_list (expr->value.constructor);
   if (t == SUCCESS)
@@ -1795,7 +1985,7 @@ gfc_get_array_element (gfc_expr *array, int element)
 {
   expand_info expand_save;
   gfc_expr *e;
-  try rc;
+  gfc_try rc;
 
   expand_save = current_expand;
   current_expand.extract_n = element;
@@ -1826,7 +2016,7 @@ gfc_get_array_element (gfc_expr *array, int element)
 /* Get the size of single dimension of an array specification.  The
    array is guaranteed to be one dimensional.  */
 
-try
+gfc_try
 spec_dimen_size (gfc_array_spec *as, int dimen, mpz_t *result)
 {
   if (as == NULL)
@@ -1853,7 +2043,7 @@ spec_dimen_size (gfc_array_spec *as, int dimen, mpz_t *result)
 }
 
 
-try
+gfc_try
 spec_size (gfc_array_spec *as, mpz_t *result)
 {
   mpz_t size;
@@ -1879,14 +2069,14 @@ 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)
+gfc_try
+gfc_ref_dimen_size (gfc_array_ref *ar, int dimen, mpz_t *result)
 {
   mpz_t upper, lower, stride;
-  try t;
+  gfc_try t;
 
   if (dimen < 0 || ar == NULL || dimen > ar->dimen - 1)
-    gfc_internal_error ("ref_dimen_size(): Bad dimension");
+    gfc_internal_error ("gfc_ref_dimen_size(): Bad dimension");
 
   switch (ar->dimen_type[dimen])
     {
@@ -1960,14 +2150,14 @@ ref_dimen_size (gfc_array_ref *ar, int dimen, mpz_t *result)
       return t;
 
     default:
-      gfc_internal_error ("ref_dimen_size(): Bad dimen_type");
+      gfc_internal_error ("gfc_ref_dimen_size(): Bad dimen_type");
     }
 
   return t;
 }
 
 
-static try
+static gfc_try
 ref_size (gfc_array_ref *ar, mpz_t *result)
 {
   mpz_t size;
@@ -1977,7 +2167,7 @@ ref_size (gfc_array_ref *ar, mpz_t *result)
 
   for (d = 0; d < ar->dimen; d++)
     {
-      if (ref_dimen_size (ar, d, &size) == FAILURE)
+      if (gfc_ref_dimen_size (ar, d, &size) == FAILURE)
        {
          mpz_clear (*result);
          return FAILURE;
@@ -1996,7 +2186,7 @@ ref_size (gfc_array_ref *ar, mpz_t *result)
    able to return a result in the 'result' variable, FAILURE
    otherwise.  */
 
-try
+gfc_try
 gfc_array_dimen_size (gfc_expr *array, int dimen, mpz_t *result)
 {
   gfc_ref *ref;
@@ -2023,7 +2213,7 @@ gfc_array_dimen_size (gfc_expr *array, int dimen, mpz_t *result)
                if (ref->u.ar.dimen_type[i] != DIMEN_ELEMENT)
                  dimen--;
 
-             return ref_dimen_size (&ref->u.ar, i - 1, result);
+             return gfc_ref_dimen_size (&ref->u.ar, i - 1, result);
            }
        }
 
@@ -2033,7 +2223,15 @@ gfc_array_dimen_size (gfc_expr *array, int dimen, mpz_t *result)
          return SUCCESS;
        }
 
-      if (spec_dimen_size (array->symtree->n.sym->as, dimen, result) == FAILURE)
+      if (array->symtree->n.sym->attr.generic
+         && array->value.function.esym != NULL)
+       {
+         if (spec_dimen_size (array->value.function.esym->as, dimen, result)
+             == FAILURE)
+           return FAILURE;
+       }
+      else if (spec_dimen_size (array->symtree->n.sym->as, dimen, result)
+              == FAILURE)
        return FAILURE;
 
       break;
@@ -2064,19 +2262,18 @@ gfc_array_dimen_size (gfc_expr *array, int dimen, mpz_t *result)
    array.  Returns SUCCESS if this is possible, and sets the 'result'
    variable.  Otherwise returns FAILURE.  */
 
-try
+gfc_try
 gfc_array_size (gfc_expr *array, mpz_t *result)
 {
   expand_info expand_save;
   gfc_ref *ref;
-  int i, flag;
-  try t;
+  int i;
+  gfc_try t;
 
   switch (array->expr_type)
     {
     case EXPR_ARRAY:
-      flag = gfc_suppress_error;
-      gfc_suppress_error = 1;
+      gfc_push_suppress_errors ();
 
       expand_save = current_expand;
 
@@ -2087,7 +2284,8 @@ gfc_array_size (gfc_expr *array, mpz_t *result)
       iter_stack = NULL;
 
       t = expand_constructor (array->value.constructor);
-      gfc_suppress_error = flag;
+
+      gfc_pop_suppress_errors ();
 
       if (t == FAILURE)
        mpz_clear (*result);
@@ -2129,7 +2327,7 @@ gfc_array_size (gfc_expr *array, mpz_t *result)
 /* Given an array reference, return the shape of the reference in an
    array of mpz_t integers.  */
 
-try
+gfc_try
 gfc_array_ref_shape (gfc_array_ref *ar, mpz_t *shape)
 {
   int d;
@@ -2151,7 +2349,7 @@ gfc_array_ref_shape (gfc_array_ref *ar, mpz_t *shape)
        {
          if (ar->dimen_type[i] != DIMEN_ELEMENT)
            {
-             if (ref_dimen_size (ar, i, &shape[d]) == FAILURE)
+             if (gfc_ref_dimen_size (ar, i, &shape[d]) == FAILURE)
                goto cleanup;
              d++;
            }