re PR fortran/35059 (Seg fault when max constructor limit reached)
[gcc.git] / gcc / fortran / expr.c
index 1242e5eb0a90b37a371b881a9079bd7e8d08bf7e..329bc722dba7e3a44b169cac7cffb5fbb045ddab 100644 (file)
@@ -1,5 +1,5 @@
 /* Routines for manipulation of expression nodes.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
    Contributed by Andy Vaught
 
@@ -963,6 +963,8 @@ simplify_intrinsic_op (gfc_expr *p, int type)
 static try
 simplify_constructor (gfc_constructor *c, int type)
 {
+  gfc_expr *p;
+
   for (; c; c = c->next)
     {
       if (c->iterator
@@ -971,8 +973,21 @@ simplify_constructor (gfc_constructor *c, int type)
              || gfc_simplify_expr (c->iterator->step, type) == FAILURE))
        return FAILURE;
 
-      if (c->expr && gfc_simplify_expr (c->expr, type) == FAILURE)
-       return FAILURE;
+      if (c->expr)
+       {
+         /* Try and simplify a copy.  Replace the original if successful
+            but keep going through the constructor at all costs.  Not
+            doing so can make a dog's dinner of complicated things.  */
+         p = gfc_copy_expr (c->expr);
+
+         if (gfc_simplify_expr (p, type) == FAILURE)
+           {
+             gfc_free_expr (p);
+             continue;
+           }
+
+         gfc_replace_expr (c->expr, p);
+       }
     }
 
   return SUCCESS;
@@ -1009,14 +1024,17 @@ find_array_element (gfc_constructor *cons, gfc_array_ref *ar,
          cons = NULL;
          goto depart;
        }
-
-      /* Check the bounds.  */
-      if (ar->as->upper[i]
-         && (mpz_cmp (e->value.integer, ar->as->upper[i]->value.integer) > 0
-             || mpz_cmp (e->value.integer,
-                         ar->as->lower[i]->value.integer) < 0))
+        /* Check the bounds.  */
+      if ((ar->as->upper[i]
+            && ar->as->upper[i]->expr_type == EXPR_CONSTANT
+            && mpz_cmp (e->value.integer,
+                        ar->as->upper[i]->value.integer) > 0)
+               ||
+         (ar->as->lower[i]->expr_type == EXPR_CONSTANT
+            && mpz_cmp (e->value.integer,
+                        ar->as->lower[i]->value.integer) < 0))
        {
-         gfc_error ("index in dimension %d is out of bounds "
+         gfc_error ("Index in dimension %d is out of bounds "
                     "at %L", i + 1, &ar->c_where[i]);
          cons = NULL;
          t = FAILURE;
@@ -1033,18 +1051,19 @@ find_array_element (gfc_constructor *cons, gfc_array_ref *ar,
       mpz_mul (span, span, tmp);
     }
 
-  if (cons)
-    {
-      for (nelemen = mpz_get_ui (offset); nelemen > 0; nelemen--)
-       {
-         if (cons->iterator)
-           {
-             cons = NULL;
-             goto depart;
-           }
-         cons = cons->next;
-       }
-    }
+    for (nelemen = mpz_get_ui (offset); nelemen > 0; nelemen--)
+      {
+        if (cons)
+         {
+           if (cons->iterator)
+             {
+               cons = NULL;
+             
+               goto depart;
+             }
+           cons = cons->next;
+         }
+      }
 
 depart:
   mpz_clear (delta);
@@ -1323,7 +1342,7 @@ find_array_section (gfc_expr *expr, gfc_ref *ref)
          cons = base;
        }
 
-      while (mpz_cmp (ptr, index) > 0)
+      while (cons && cons->next && mpz_cmp (ptr, index) > 0)
        {
          mpz_add_ui (index, index, one);
          cons = cons->next;
@@ -2091,7 +2110,8 @@ check_elemental (gfc_expr *e)
       || !e->value.function.isym->elemental)
     return MATCH_NO;
 
-  if ((e->ts.type != BT_INTEGER || e->ts.type != BT_CHARACTER)
+  if (e->ts.type != BT_INTEGER
+      && e->ts.type != BT_CHARACTER
       && gfc_notify_std (GFC_STD_F2003, "Extension: Evaluation of "
                        "nonstandard initialization expression at %L",
                        &e->where) == FAILURE)
@@ -2187,7 +2207,18 @@ check_init_expr (gfc_expr *e)
 
       if (e->symtree->n.sym->attr.flavor == FL_PARAMETER)
        {
-         t = simplify_parameter_variable (e, 0);
+         /* A PARAMETER shall not be used to define itself, i.e.
+               REAL, PARAMETER :: x = transfer(0, x)
+            is invalid.  */
+         if (!e->symtree->n.sym->value)
+           {
+             gfc_error("PARAMETER '%s' is used at %L before its definition "
+                       "is complete", e->symtree->n.sym->name, &e->where);
+             t = FAILURE;
+           }
+         else
+           t = simplify_parameter_variable (e, 0);
+
          break;
        }
 
@@ -2218,6 +2249,12 @@ check_init_expr (gfc_expr *e)
                           e->symtree->n.sym->name, &e->where);
                break;
 
+             case AS_EXPLICIT:
+               gfc_error ("Array '%s' at %L is a variable, which does "
+                          "not reduce to a constant expression",
+                          e->symtree->n.sym->name, &e->where);
+               break;
+
              default:
                gcc_unreachable();
          }
@@ -2464,6 +2501,7 @@ check_restricted (gfc_expr *e)
       if (sym->attr.in_common
          || sym->attr.use_assoc
          || sym->attr.dummy
+         || sym->attr.implied_index
          || sym->ns != gfc_current_ns
          || (sym->ns->proc_name != NULL
              && sym->ns->proc_name->attr.flavor == FL_MODULE)
@@ -2668,6 +2706,15 @@ gfc_check_assign (gfc_expr *lvalue, gfc_expr *rvalue, int conform)
            bad_proc = true;
        }
 
+      /* (iv) Host associated and not the function symbol or the
+             parent result.  This picks up sibling references, which
+             cannot be entries.  */
+      if (!sym->attr.entry
+           && sym->ns == gfc_current_ns->parent
+           && sym != gfc_current_ns->proc_name
+           && sym != gfc_current_ns->parent->proc_name->result)
+       bad_proc = true;
+
       if (bad_proc)
        {
          gfc_error ("'%s' at %L is not a VALUE", sym->name, &lvalue->where);
@@ -2740,11 +2787,29 @@ gfc_check_assign (gfc_expr *lvalue, gfc_expr *rvalue, int conform)
   /* Handle the case of a BOZ literal on the RHS.  */
   if (rvalue->is_boz && lvalue->ts.type != BT_INTEGER)
     {
+      int rc;
       if (gfc_option.warn_surprising)
         gfc_warning ("BOZ literal at %L is bitwise transferred "
                      "non-integer symbol '%s'", &rvalue->where,
                      lvalue->symtree->n.sym->name);
-      gfc_convert_boz (rvalue, &lvalue->ts);
+      if (!gfc_convert_boz (rvalue, &lvalue->ts))
+       return FAILURE;
+      if ((rc = gfc_range_check (rvalue)) != ARITH_OK)
+       {
+         if (rc == ARITH_UNDERFLOW)
+           gfc_error ("Arithmetic underflow of bit-wise transferred BOZ at %L"
+                      ". This check can be disabled with the option "
+                      "-fno-range-check", &rvalue->where);
+         else if (rc == ARITH_OVERFLOW)
+           gfc_error ("Arithmetic overflow of bit-wise transferred BOZ at %L"
+                      ". This check can be disabled with the option "
+                      "-fno-range-check", &rvalue->where);
+         else if (rc == ARITH_NAN)
+           gfc_error ("Arithmetic NaN of bit-wise transferred BOZ at %L"
+                      ". This check can be disabled with the option "
+                      "-fno-range-check", &rvalue->where);
+         return FAILURE;
+       }
     }
 
   if (gfc_compare_types (&lvalue->ts, &rvalue->ts))
@@ -2761,8 +2826,8 @@ gfc_check_assign (gfc_expr *lvalue, gfc_expr *rvalue, int conform)
       if (lvalue->ts.type == BT_LOGICAL && rvalue->ts.type == BT_LOGICAL)
        return SUCCESS;
 
-      gfc_error ("Incompatible types in assignment at %L, %s to %s",
-                &rvalue->where, gfc_typename (&rvalue->ts),
+      gfc_error ("Incompatible types in assignment at %L; attempted assignment "
+                "of %s to %s", &rvalue->where, gfc_typename (&rvalue->ts),
                 gfc_typename (&lvalue->ts));
 
       return FAILURE;
@@ -2845,8 +2910,9 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
 
   if (!gfc_compare_types (&lvalue->ts, &rvalue->ts))
     {
-      gfc_error ("Different types in pointer assignment at %L",
-                &lvalue->where);
+      gfc_error ("Different types in pointer assignment at %L; attempted "
+                "assignment of %s to %s", &lvalue->where, 
+                gfc_typename (&rvalue->ts), gfc_typename (&lvalue->ts));
       return FAILURE;
     }