OSDN Git Service

PR fortran/12840
authorrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 9 Sep 2005 06:00:40 +0000 (06:00 +0000)
committerrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 9 Sep 2005 06:00:40 +0000 (06:00 +0000)
* trans.h (gfor_fndecl_internal_realloc): Declare.
(gfor_fndecl_internal_realloc64): Declare.
* trans-decl.c (gfor_fndecl_internal_realloc): New variable.
(gfor_fndecl_internal_realloc64): New variable.
(gfc_build_builtin_function_decls): Initialize them.
* trans-array.h (gfc_trans_allocate_temp_array): Add a fourth argument.
* trans-array.c (gfc_trans_allocate_array_storage): Add an argument
to say whether the array can grow later.  Don't allocate the array
on the stack if so.  Don't call malloc for zero-sized arrays.
(gfc_trans_allocate_temp_array): Add a similar argument here.
Pass it along to gfc_trans_allocate_array_storage.
(gfc_get_iteration_count, gfc_grow_array): New functions.
(gfc_iterator_has_dynamic_bounds): New function.
(gfc_get_array_constructor_element_size): New function.
(gfc_get_array_constructor_size): New function.
(gfc_trans_array_ctor_element): Replace pointer argument with
a descriptor tree.
(gfc_trans_array_constructor_subarray): Likewise.  Take an extra
argument to say whether the variable-sized part of the constructor
must be allocated using realloc.  Grow the array when this
argument is true.
(gfc_trans_array_constructor_value): Likewise.
(gfc_get_array_cons_size): Delete.
(gfc_trans_array_constructor): If the loop bound has not been set,
split the allocation into a static part and a dynamic part.  Set
loop->to to the bounds for static part before allocating the
temporary.  Adjust call to gfc_trans_array_constructor_value.
(gfc_conv_loop_setup): Allow any constructor to determine the
loop bounds.  Check whether the constructor has a dynamic size
and prefer to use something else if so.  Expect the loop bound
to be set later.  Adjust call to gfc_trans_allocate_temp_array.
* trans-expr.c (gfc_conv_function_call): Adjust another call here.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@104073 138bc75d-0d04-0410-961f-82ee72b054a4

16 files changed:
gcc/fortran/ChangeLog
gcc/fortran/trans-array.c
gcc/fortran/trans-array.h
gcc/fortran/trans-decl.c
gcc/fortran/trans-expr.c
gcc/fortran/trans.h
gcc/testsuite/ChangeLog
gcc/testsuite/gfortran.dg/array_constructor_10.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/array_constructor_11.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/array_constructor_12.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/array_constructor_6.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/array_constructor_7.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/array_constructor_8.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/array_constructor_9.f90 [new file with mode: 0644]
libgfortran/ChangeLog
libgfortran/runtime/memory.c

index 6cc04bd..157578f 100644 (file)
@@ -1,3 +1,39 @@
+2005-09-09  Richard Sandiford  <richard@codesourcery.com>
+
+       PR fortran/12840
+       * trans.h (gfor_fndecl_internal_realloc): Declare.
+       (gfor_fndecl_internal_realloc64): Declare.
+       * trans-decl.c (gfor_fndecl_internal_realloc): New variable.
+       (gfor_fndecl_internal_realloc64): New variable.
+       (gfc_build_builtin_function_decls): Initialize them.
+       * trans-array.h (gfc_trans_allocate_temp_array): Add a fourth argument.
+       * trans-array.c (gfc_trans_allocate_array_storage): Add an argument
+       to say whether the array can grow later.  Don't allocate the array
+       on the stack if so.  Don't call malloc for zero-sized arrays.
+       (gfc_trans_allocate_temp_array): Add a similar argument here.
+       Pass it along to gfc_trans_allocate_array_storage.
+       (gfc_get_iteration_count, gfc_grow_array): New functions.
+       (gfc_iterator_has_dynamic_bounds): New function.
+       (gfc_get_array_constructor_element_size): New function.
+       (gfc_get_array_constructor_size): New function.
+       (gfc_trans_array_ctor_element): Replace pointer argument with
+       a descriptor tree.
+       (gfc_trans_array_constructor_subarray): Likewise.  Take an extra
+       argument to say whether the variable-sized part of the constructor
+       must be allocated using realloc.  Grow the array when this
+       argument is true.
+       (gfc_trans_array_constructor_value): Likewise.
+       (gfc_get_array_cons_size): Delete.
+       (gfc_trans_array_constructor): If the loop bound has not been set,
+       split the allocation into a static part and a dynamic part.  Set
+       loop->to to the bounds for static part before allocating the
+       temporary.  Adjust call to gfc_trans_array_constructor_value.
+       (gfc_conv_loop_setup): Allow any constructor to determine the
+       loop bounds.  Check whether the constructor has a dynamic size
+       and prefer to use something else if so.  Expect the loop bound
+       to be set later.  Adjust call to gfc_trans_allocate_temp_array.
+       * trans-expr.c (gfc_conv_function_call): Adjust another call here.
+
 2005-09-09  Paul Thomas  <pault@gcc.gnu.org>
 
        PR fortran/18878
index fbd8b5b..f6bd24c 100644 (file)
@@ -94,6 +94,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "dependency.h"
 
 static gfc_ss *gfc_walk_subexpr (gfc_ss *, gfc_expr *);
+static bool gfc_get_array_constructor_size (mpz_t *, gfc_constructor *);
 
 /* The contents of this structure aren't actually used, just the address.  */
 static gfc_ss gfc_ss_terminator_var;
@@ -435,11 +436,14 @@ gfc_trans_static_array_pointer (gfc_symbol * sym)
 /* Generate code to allocate an array temporary, or create a variable to
    hold the data.  If size is NULL zero the descriptor so that so that the
    callee will allocate the array.  Also generates code to free the array
-   afterwards.  */
+   afterwards.
+
+   DYNAMIC is true if the caller may want to extend the array later
+   using realloc.  This prevents us from putting the array on the stack.  */
 
 static void
 gfc_trans_allocate_array_storage (gfc_loopinfo * loop, gfc_ss_info * info,
-                                 tree size, tree nelem)
+                                 tree size, tree nelem, bool dynamic)
 {
   tree tmp;
   tree args;
@@ -448,7 +452,7 @@ gfc_trans_allocate_array_storage (gfc_loopinfo * loop, gfc_ss_info * info,
 
   desc = info->descriptor;
   info->offset = gfc_index_zero_node;
-  if (size == NULL_TREE)
+  if (size == NULL_TREE || integer_zerop (size))
     {
       /* A callee allocated array.  */
       gfc_conv_descriptor_data_set (&loop->pre, desc, null_pointer_node);
@@ -457,7 +461,7 @@ gfc_trans_allocate_array_storage (gfc_loopinfo * loop, gfc_ss_info * info,
   else
     {
       /* Allocate the temporary.  */
-      onstack = gfc_can_put_var_on_stack (size);
+      onstack = !dynamic && gfc_can_put_var_on_stack (size);
 
       if (onstack)
        {
@@ -512,11 +516,13 @@ gfc_trans_allocate_array_storage (gfc_loopinfo * loop, gfc_ss_info * info,
    functions returning arrays.  Adjusts the loop variables to be zero-based,
    and calculates the loop bounds for callee allocated arrays.
    Also fills in the descriptor, data and offset fields of info if known.
-   Returns the size of the array, or NULL for a callee allocated array.  */
+   Returns the size of the array, or NULL for a callee allocated array.
+
+   DYNAMIC is as for gfc_trans_allocate_array_storage.  */
 
 tree
 gfc_trans_allocate_temp_array (gfc_loopinfo * loop, gfc_ss_info * info,
-                              tree eltype)
+                              tree eltype, bool dynamic)
 {
   tree type;
   tree desc;
@@ -611,7 +617,7 @@ gfc_trans_allocate_temp_array (gfc_loopinfo * loop, gfc_ss_info * info,
     size = fold_build2 (MULT_EXPR, gfc_array_index_type, size,
                        TYPE_SIZE_UNIT (gfc_get_element_type (type)));
 
-  gfc_trans_allocate_array_storage (loop, info, size, nelem);
+  gfc_trans_allocate_array_storage (loop, info, size, nelem, dynamic);
 
   if (info->dimen > loop->temp_dim)
     loop->temp_dim = info->dimen;
@@ -620,6 +626,149 @@ gfc_trans_allocate_temp_array (gfc_loopinfo * loop, gfc_ss_info * info,
 }
 
 
+/* Return the number of iterations in a loop that starts at START,
+   ends at END, and has step STEP.  */
+
+static tree
+gfc_get_iteration_count (tree start, tree end, tree step)
+{
+  tree tmp;
+  tree type;
+
+  type = TREE_TYPE (step);
+  tmp = fold_build2 (MINUS_EXPR, type, end, start);
+  tmp = fold_build2 (FLOOR_DIV_EXPR, type, tmp, step);
+  tmp = fold_build2 (PLUS_EXPR, type, tmp, build_int_cst (type, 1));
+  tmp = fold_build2 (MAX_EXPR, type, tmp, build_int_cst (type, 0));
+  return fold_convert (gfc_array_index_type, tmp);
+}
+
+
+/* Extend the data in array DESC by EXTRA elements.  */
+
+static void
+gfc_grow_array (stmtblock_t * pblock, tree desc, tree extra)
+{
+  tree args;
+  tree tmp;
+  tree size;
+  tree ubound;
+
+  if (integer_zerop (extra))
+    return;
+
+  ubound = gfc_conv_descriptor_ubound (desc, gfc_rank_cst[0]);
+
+  /* Add EXTRA to the upper bound.  */
+  tmp = build2 (PLUS_EXPR, gfc_array_index_type, ubound, extra);
+  gfc_add_modify_expr (pblock, ubound, tmp);
+
+  /* Get the value of the current data pointer.  */
+  tmp = gfc_conv_descriptor_data_get (desc);
+  args = gfc_chainon_list (NULL_TREE, tmp);
+
+  /* Calculate the new array size.  */
+  size = TYPE_SIZE_UNIT (gfc_get_element_type (TREE_TYPE (desc)));
+  tmp = build2 (PLUS_EXPR, gfc_array_index_type, ubound, gfc_index_one_node);
+  tmp = build2 (MULT_EXPR, gfc_array_index_type, tmp, size);
+  args = gfc_chainon_list (args, tmp);
+
+  /* Pick the appropriate realloc function.  */
+  if (gfc_index_integer_kind == 4)
+    tmp = gfor_fndecl_internal_realloc;
+  else if (gfc_index_integer_kind == 8)
+    tmp = gfor_fndecl_internal_realloc64;
+  else
+    gcc_unreachable ();
+
+  /* Set the new data pointer.  */
+  tmp = gfc_build_function_call (tmp, args);
+  gfc_conv_descriptor_data_set (pblock, desc, tmp);
+}
+
+
+/* Return true if the bounds of iterator I can only be determined
+   at run time.  */
+
+static inline bool
+gfc_iterator_has_dynamic_bounds (gfc_iterator * i)
+{
+  return (i->start->expr_type != EXPR_CONSTANT
+         || i->end->expr_type != EXPR_CONSTANT
+         || i->step->expr_type != EXPR_CONSTANT);
+}
+
+
+/* Split the size of constructor element EXPR into the sum of two terms,
+   one of which can be determined at compile time and one of which must
+   be calculated at run time.  Set *SIZE to the former and return true
+   if the latter might be nonzero.  */
+
+static bool
+gfc_get_array_constructor_element_size (mpz_t * size, gfc_expr * expr)
+{
+  if (expr->expr_type == EXPR_ARRAY)
+    return gfc_get_array_constructor_size (size, expr->value.constructor);
+  else if (expr->rank > 0)
+    {
+      /* Calculate everything at run time.  */
+      mpz_set_ui (*size, 0);
+      return true;
+    }
+  else
+    {
+      /* A single element.  */
+      mpz_set_ui (*size, 1);
+      return false;
+    }
+}
+
+
+/* Like gfc_get_array_constructor_element_size, but applied to the whole
+   of array constructor C.  */
+
+static bool
+gfc_get_array_constructor_size (mpz_t * size, gfc_constructor * c)
+{
+  gfc_iterator *i;
+  mpz_t val;
+  mpz_t len;
+  bool dynamic;
+
+  mpz_set_ui (*size, 0);
+  mpz_init (len);
+  mpz_init (val);
+
+  dynamic = false;
+  for (; c; c = c->next)
+    {
+      i = c->iterator;
+      if (i && gfc_iterator_has_dynamic_bounds (i))
+       dynamic = true;
+      else
+       {
+         dynamic |= gfc_get_array_constructor_element_size (&len, c->expr);
+         if (i)
+           {
+             /* Multiply the static part of the element size by the
+                number of iterations.  */
+             mpz_sub (val, i->end->value.integer, i->start->value.integer);
+             mpz_fdiv_q (val, val, i->step->value.integer);
+             mpz_add_ui (val, val, 1);
+             if (mpz_sgn (val) > 0)
+               mpz_mul (len, len, val);
+             else
+               mpz_set_ui (len, 0);
+           }
+         mpz_add (*size, *size, len);
+       }
+    }
+  mpz_clear (len);
+  mpz_clear (val);
+  return dynamic;
+}
+
+
 /* Make sure offset is a variable.  */
 
 static void
@@ -638,7 +787,7 @@ gfc_put_offset_into_var (stmtblock_t * pblock, tree * poffset,
 /* Assign an element of an array constructor.  */
 
 static void
-gfc_trans_array_ctor_element (stmtblock_t * pblock, tree pointer,
+gfc_trans_array_ctor_element (stmtblock_t * pblock, tree desc,
                              tree offset, gfc_se * se, gfc_expr * expr)
 {
   tree tmp;
@@ -647,7 +796,7 @@ gfc_trans_array_ctor_element (stmtblock_t * pblock, tree pointer,
   gfc_conv_expr (se, expr);
 
   /* Store the value.  */
-  tmp = gfc_build_indirect_ref (pointer);
+  tmp = gfc_build_indirect_ref (gfc_conv_descriptor_data_get (desc));
   tmp = gfc_build_array_ref (tmp, offset);
   if (expr->ts.type == BT_CHARACTER)
     {
@@ -684,19 +833,23 @@ gfc_trans_array_ctor_element (stmtblock_t * pblock, tree pointer,
 }
 
 
-/* Add the contents of an array to the constructor.  */
+/* Add the contents of an array to the constructor.  DYNAMIC is as for
+   gfc_trans_array_constructor_value.  */
 
 static void
 gfc_trans_array_constructor_subarray (stmtblock_t * pblock,
                                      tree type ATTRIBUTE_UNUSED,
-                                     tree pointer, gfc_expr * expr,
-                                     tree * poffset, tree * offsetvar)
+                                     tree desc, gfc_expr * expr,
+                                     tree * poffset, tree * offsetvar,
+                                     bool dynamic)
 {
   gfc_se se;
   gfc_ss *ss;
   gfc_loopinfo loop;
   stmtblock_t body;
   tree tmp;
+  tree size;
+  int n;
 
   /* We need this to be a variable so we can increment it.  */
   gfc_put_offset_into_var (pblock, poffset, offsetvar);
@@ -715,6 +868,22 @@ gfc_trans_array_constructor_subarray (stmtblock_t * pblock,
   gfc_conv_ss_startstride (&loop);
   gfc_conv_loop_setup (&loop);
 
+  /* Make sure the constructed array has room for the new data.  */
+  if (dynamic)
+    {
+      /* Set SIZE to the total number of elements in the subarray.  */
+      size = gfc_index_one_node;
+      for (n = 0; n < loop.dimen; n++)
+       {
+         tmp = gfc_get_iteration_count (loop.from[n], loop.to[n],
+                                        gfc_index_one_node);
+         size = fold_build2 (MULT_EXPR, gfc_array_index_type, size, tmp);
+       }
+
+      /* Grow the constructed array by SIZE elements.  */
+      gfc_grow_array (&loop.pre, desc, size);
+    }
+
   /* Make the loop body.  */
   gfc_mark_ss_chain_used (ss, 1);
   gfc_start_scalarized_body (&loop, &body);
@@ -724,7 +893,7 @@ gfc_trans_array_constructor_subarray (stmtblock_t * pblock,
   if (expr->ts.type == BT_CHARACTER)
     gfc_todo_error ("character arrays in constructors");
 
-  gfc_trans_array_ctor_element (&body, pointer, *poffset, &se, expr);
+  gfc_trans_array_ctor_element (&body, desc, *poffset, &se, expr);
   gcc_assert (se.ss == gfc_ss_terminator);
 
   /* Increment the offset.  */
@@ -741,17 +910,23 @@ gfc_trans_array_constructor_subarray (stmtblock_t * pblock,
 }
 
 
-/* Assign the values to the elements of an array constructor.  */
+/* Assign the values to the elements of an array constructor.  DYNAMIC
+   is true if descriptor DESC only contains enough data for the static
+   size calculated by gfc_get_array_constructor_size.  When true, memory
+   for the dynamic parts must be allocated using realloc.  */
 
 static void
 gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
-                                  tree pointer, gfc_constructor * c,
-                                  tree * poffset, tree * offsetvar)
+                                  tree desc, gfc_constructor * c,
+                                  tree * poffset, tree * offsetvar,
+                                  bool dynamic)
 {
   tree tmp;
   stmtblock_t body;
   gfc_se se;
+  mpz_t size;
 
+  mpz_init (size);
   for (; c; c = c->next)
     {
       /* If this is an iterator or an array, the offset must be a variable.  */
@@ -763,14 +938,14 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
       if (c->expr->expr_type == EXPR_ARRAY)
        {
          /* Array constructors can be nested.  */
-         gfc_trans_array_constructor_value (&body, type, pointer,
+         gfc_trans_array_constructor_value (&body, type, desc,
                                             c->expr->value.constructor,
-                                            poffset, offsetvar);
+                                            poffset, offsetvar, dynamic);
        }
       else if (c->expr->rank > 0)
        {
-         gfc_trans_array_constructor_subarray (&body, type, pointer,
-                                               c->expr, poffset, offsetvar);
+         gfc_trans_array_constructor_subarray (&body, type, desc, c->expr,
+                                               poffset, offsetvar, dynamic);
        }
       else
        {
@@ -790,8 +965,8 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
            {
              /* Scalar values.  */
              gfc_init_se (&se, NULL);
-             gfc_trans_array_ctor_element (&body, pointer, *poffset, &se,
-                                           c->expr);
+             gfc_trans_array_ctor_element (&body, desc, *poffset,
+                                           &se, c->expr);
 
              *poffset = fold_build2 (PLUS_EXPR, gfc_array_index_type,
                                      *poffset, gfc_index_one_node);
@@ -813,13 +988,12 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
                  gfc_init_se (&se, NULL);
                  gfc_conv_constant (&se, p->expr);
                  if (p->expr->ts.type == BT_CHARACTER
-                     && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE
-                         (TREE_TYPE (pointer)))))
+                     && POINTER_TYPE_P (type))
                    {
                      /* For constant character array constructors we build
                         an array of pointers.  */
                      se.expr = gfc_build_addr_expr (pchar_type_node,
-                                                     se.expr);
+                                                    se.expr);
                    }
                    
                  list = tree_cons (NULL_TREE, se.expr, list);
@@ -846,7 +1020,8 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
              init = tmp;
 
              /* Use BUILTIN_MEMCPY to assign the values.  */
-             tmp = gfc_build_indirect_ref (pointer);
+             tmp = gfc_conv_descriptor_data_get (desc);
+             tmp = gfc_build_indirect_ref (tmp);
              tmp = gfc_build_array_ref (tmp, *poffset);
              tmp = gfc_build_addr_expr (NULL, tmp);
              init = gfc_build_addr_expr (NULL, init);
@@ -887,6 +1062,7 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
          tree loopvar;
          tree exit_label;
          tree loopbody;
+         tree tmp2;
 
          loopbody = gfc_finish_block (&body);
 
@@ -911,6 +1087,23 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
          gfc_add_block_to_block (pblock, &se.pre);
          step = gfc_evaluate_now (se.expr, pblock);
 
+         /* If this array expands dynamically, and the number of iterations
+            is not constant, we won't have allocated space for the static
+            part of C->EXPR's size.  Do that now.  */
+         if (dynamic && gfc_iterator_has_dynamic_bounds (c->iterator))
+           {
+             /* Get the number of iterations.  */
+             tmp = gfc_get_iteration_count (loopvar, end, step);
+
+             /* Get the static part of C->EXPR's size.  */
+             gfc_get_array_constructor_element_size (&size, c->expr);
+             tmp2 = gfc_conv_mpz_to_tree (size, gfc_index_integer_kind);
+
+             /* Grow the array by TMP * TMP2 elements.  */
+             tmp = fold_build2 (MULT_EXPR, gfc_array_index_type, tmp, tmp2);
+             gfc_grow_array (pblock, desc, tmp);
+           }
+
          /* Generate the loop body.  */
          exit_label = gfc_build_label_decl (NULL_TREE);
          gfc_start_block (&body);
@@ -947,73 +1140,7 @@ gfc_trans_array_constructor_value (stmtblock_t * pblock, tree type,
          gfc_add_expr_to_block (pblock, tmp);
        }
     }
-}
-
-
-/* Get the size of an expression.  Returns -1 if the size isn't constant.
-   Implied do loops with non-constant bounds are tricky because we must only
-   evaluate the bounds once.  */
-
-static void
-gfc_get_array_cons_size (mpz_t * size, gfc_constructor * c)
-{
-  gfc_iterator *i;
-  mpz_t val;
-  mpz_t len;
-
-  mpz_set_ui (*size, 0);
-  mpz_init (len);
-  mpz_init (val);
-
-  for (; c; c = c->next)
-    {
-      if (c->expr->expr_type == EXPR_ARRAY)
-       {
-          /* A nested array constructor.  */
-         gfc_get_array_cons_size (&len, c->expr->value.constructor);
-         if (mpz_sgn (len) < 0)
-           {
-             mpz_set (*size, len);
-             mpz_clear (len);
-             mpz_clear (val);
-             return;
-           }
-       }
-      else
-       {
-         if (c->expr->rank > 0)
-           {
-             mpz_set_si (*size, -1);
-             mpz_clear (len);
-             mpz_clear (val);
-             return;
-           }
-         mpz_set_ui (len, 1);
-       }
-
-      if (c->iterator)
-       {
-         i = c->iterator;
-
-         if (i->start->expr_type != EXPR_CONSTANT
-             || i->end->expr_type != EXPR_CONSTANT
-             || i->step->expr_type != EXPR_CONSTANT)
-           {
-             mpz_set_si (*size, -1);
-             mpz_clear (len);
-             mpz_clear (val);
-             return;
-           }
-
-         mpz_add (val, i->end->value.integer, i->start->value.integer);
-         mpz_tdiv_q (val, val, i->step->value.integer);
-         mpz_add_ui (val, val, 1);
-         mpz_mul (len, len, val);
-       }
-      mpz_add (*size, *size, len);
-    }
-  mpz_clear (len);
-  mpz_clear (val);
+  mpz_clear (size);
 }
 
 
@@ -1104,19 +1231,20 @@ get_array_ctor_strlen (gfc_constructor * c, tree * len)
 static void
 gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss)
 {
+  gfc_constructor *c;
   tree offset;
   tree offsetvar;
   tree desc;
-  tree size;
   tree type;
   bool const_string;
+  bool dynamic;
 
   ss->data.info.dimen = loop->dimen;
 
+  c = ss->expr->value.constructor;
   if (ss->expr->ts.type == BT_CHARACTER)
     {
-      const_string = get_array_ctor_strlen (ss->expr->value.constructor,
-                                           &ss->string_length);
+      const_string = get_array_ctor_strlen (c, &ss->string_length);
       if (!ss->string_length)
        gfc_todo_error ("complex character array constructors");
 
@@ -1130,16 +1258,39 @@ gfc_trans_array_constructor (gfc_loopinfo * loop, gfc_ss * ss)
       type = gfc_typenode_for_spec (&ss->expr->ts);
     }
 
-  size = gfc_trans_allocate_temp_array (loop, &ss->data.info, type);
+  /* See if the constructor determines the loop bounds.  */
+  dynamic = false;
+  if (loop->to[0] == NULL_TREE)
+    {
+      mpz_t size;
+
+      /* We should have a 1-dimensional, zero-based loop.  */
+      gcc_assert (loop->dimen == 1);
+      gcc_assert (integer_zerop (loop->from[0]));
+
+      /* Split the constructor size into a static part and a dynamic part.
+        Allocate the static size up-front and record whether the dynamic
+        size might be nonzero.  */
+      mpz_init (size);
+      dynamic = gfc_get_array_constructor_size (&size, c);
+      mpz_sub_ui (size, size, 1);
+      loop->to[0] = gfc_conv_mpz_to_tree (size, gfc_index_integer_kind);
+      mpz_clear (size);
+    }
+
+  gfc_trans_allocate_temp_array (loop, &ss->data.info, type, dynamic);
 
   desc = ss->data.info.descriptor;
   offset = gfc_index_zero_node;
   offsetvar = gfc_create_var_np (gfc_array_index_type, "offset");
   TREE_USED (offsetvar) = 0;
-  gfc_trans_array_constructor_value (&loop->pre, type,
-                                    ss->data.info.data,
-                                    ss->expr->value.constructor, &offset,
-                                    &offsetvar);
+  gfc_trans_array_constructor_value (&loop->pre, type, desc, c,
+                                    &offset, &offsetvar, dynamic);
+
+  /* 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 (desc, gfc_rank_cst[0]);
 
   if (TREE_USED (offsetvar))
     pushdecl (offsetvar);
@@ -2411,6 +2562,8 @@ gfc_conv_loop_setup (gfc_loopinfo * loop)
   tree tmp;
   tree len;
   gfc_ss *loopspec[GFC_MAX_DIMENSIONS];
+  bool dynamic[GFC_MAX_DIMENSIONS];
+  gfc_constructor *c;
   mpz_t *cshape;
   mpz_t i;
 
@@ -2418,6 +2571,7 @@ gfc_conv_loop_setup (gfc_loopinfo * loop)
   for (n = 0; n < loop->dimen; n++)
     {
       loopspec[n] = NULL;
+      dynamic[n] = false;
       /* We use one SS term, and use that to determine the bounds of the
          loop for this dimension.  We try to pick the simplest term.  */
       for (ss = loop->ss; ss != gfc_ss_terminator; ss = ss->loop_chain)
@@ -2435,17 +2589,15 @@ gfc_conv_loop_setup (gfc_loopinfo * loop)
                 Higher rank constructors will either have known shape,
                 or still be wrapped in a call to reshape.  */
              gcc_assert (loop->dimen == 1);
-             /* Try to figure out the size of the constructor.  */
-             /* TODO: avoid this by making the frontend set the shape.  */
-             gfc_get_array_cons_size (&i, ss->expr->value.constructor);
-             /* A negative value means we failed.  */
-             if (mpz_sgn (i) > 0)
-               {
-                 mpz_sub_ui (i, i, 1);
-                 loop->to[n] =
-                   gfc_conv_mpz_to_tree (i, gfc_index_integer_kind);
-                 loopspec[n] = ss;
-               }
+
+             /* Always prefer to use the constructor bounds if the size
+                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.  */
+             c = ss->expr->value.constructor;
+             dynamic[n] = gfc_get_array_constructor_size (&i, c);
+             if (!dynamic[n] || !loopspec[n])
+               loopspec[n] = ss;
              continue;
            }
 
@@ -2466,31 +2618,30 @@ gfc_conv_loop_setup (gfc_loopinfo * loop)
            specinfo = NULL;
          info = &ss->data.info;
 
+         if (!specinfo)
+           loopspec[n] = ss;
          /* Criteria for choosing a loop specifier (most important first):
+            doesn't need realloc
             stride of one
             known stride
             known lower bound
             known upper bound
           */
-         if (!specinfo)
+         else if (loopspec[n]->type == GFC_SS_CONSTRUCTOR && dynamic[n])
            loopspec[n] = ss;
-         /* TODO: Is != constructor correct?  */
-         else if (loopspec[n]->type != GFC_SS_CONSTRUCTOR)
-           {
-             if (integer_onep (info->stride[n])
-                 && !integer_onep (specinfo->stride[n]))
-               loopspec[n] = ss;
-             else if (INTEGER_CST_P (info->stride[n])
-                      && !INTEGER_CST_P (specinfo->stride[n]))
-               loopspec[n] = ss;
-             else if (INTEGER_CST_P (info->start[n])
-                      && !INTEGER_CST_P (specinfo->start[n]))
-               loopspec[n] = ss;
-             /* We don't work out the upper bound.
-                else if (INTEGER_CST_P (info->finish[n])
-                && ! INTEGER_CST_P (specinfo->finish[n]))
-                loopspec[n] = ss; */
-           }
+         else if (integer_onep (info->stride[n])
+                  && !integer_onep (specinfo->stride[n]))
+           loopspec[n] = ss;
+         else if (INTEGER_CST_P (info->stride[n])
+                  && !INTEGER_CST_P (specinfo->stride[n]))
+           loopspec[n] = ss;
+         else if (INTEGER_CST_P (info->start[n])
+                  && !INTEGER_CST_P (specinfo->start[n]))
+           loopspec[n] = ss;
+         /* We don't work out the upper bound.
+            else if (INTEGER_CST_P (info->finish[n])
+            && ! INTEGER_CST_P (specinfo->finish[n]))
+            loopspec[n] = ss; */
        }
 
       if (!loopspec[n])
@@ -2520,8 +2671,9 @@ gfc_conv_loop_setup (gfc_loopinfo * loop)
          switch (loopspec[n]->type)
            {
            case GFC_SS_CONSTRUCTOR:
-             gcc_assert (info->dimen == 1);
-             gcc_assert (loop->to[n]);
+             /* The upper bound is calculated when we expand the
+                constructor.  */
+             gcc_assert (loop->to[n] == NULL_TREE);
              break;
 
            case GFC_SS_SECTION:
@@ -2575,7 +2727,8 @@ gfc_conv_loop_setup (gfc_loopinfo * loop)
       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;
-      gfc_trans_allocate_temp_array (loop, &loop->temp_ss->data.info, tmp);
+      gfc_trans_allocate_temp_array (loop, &loop->temp_ss->data.info,
+                                    tmp, false);
     }
 
   for (n = 0; n < loop->temp_dim; n++)
index 403b42f..eda4245 100644 (file)
@@ -27,7 +27,7 @@ tree gfc_array_deallocate (tree, tree);
 void gfc_array_allocate (gfc_se *, gfc_ref *, tree);
 
 /* Generate code to allocate a temporary array.  */
-tree gfc_trans_allocate_temp_array (gfc_loopinfo *, gfc_ss_info *, tree);
+tree gfc_trans_allocate_temp_array (gfc_loopinfo *, gfc_ss_info *, tree, bool);
 
 /* Generate function entry code for allocation of compiler allocated array
    variables.  */
index 1b56840..73e02f0 100644 (file)
@@ -73,6 +73,8 @@ tree gfc_static_ctors;
 
 tree gfor_fndecl_internal_malloc;
 tree gfor_fndecl_internal_malloc64;
+tree gfor_fndecl_internal_realloc;
+tree gfor_fndecl_internal_realloc64;
 tree gfor_fndecl_internal_free;
 tree gfor_fndecl_allocate;
 tree gfor_fndecl_allocate64;
@@ -1891,6 +1893,18 @@ gfc_build_builtin_function_decls (void)
                                     pvoid_type_node, 1, gfc_int8_type_node);
   DECL_IS_MALLOC (gfor_fndecl_internal_malloc64) = 1;
 
+  gfor_fndecl_internal_realloc =
+    gfc_build_library_function_decl (get_identifier
+                                    (PREFIX("internal_realloc")),
+                                    pvoid_type_node, 2, pvoid_type_node,
+                                    gfc_int4_type_node);
+
+  gfor_fndecl_internal_realloc64 =
+    gfc_build_library_function_decl (get_identifier
+                                    (PREFIX("internal_realloc64")),
+                                    pvoid_type_node, 2, pvoid_type_node,
+                                    gfc_int8_type_node);
+
   gfor_fndecl_internal_free =
     gfc_build_library_function_decl (get_identifier (PREFIX("internal_free")),
                                     void_type_node, 1, pvoid_type_node);
index cf49ba4..aa60e7f 100644 (file)
@@ -1694,7 +1694,7 @@ gfc_conv_function_call (gfc_se * se, gfc_symbol * sym,
          info->dimen = se->loop->dimen;
 
          /* Allocate a temporary to store the result.  */
-         gfc_trans_allocate_temp_array (se->loop, info, tmp);
+         gfc_trans_allocate_temp_array (se->loop, info, tmp, false);
 
          /* Zero the first stride to indicate a temporary.  */
          tmp = gfc_conv_descriptor_stride (info->descriptor, gfc_rank_cst[0]);
index 3c5734d..5c27fa7 100644 (file)
@@ -443,6 +443,8 @@ tree builtin_function (const char *, tree, int, enum built_in_class,
 /* Runtime library function decls.  */
 extern GTY(()) tree gfor_fndecl_internal_malloc;
 extern GTY(()) tree gfor_fndecl_internal_malloc64;
+extern GTY(()) tree gfor_fndecl_internal_realloc;
+extern GTY(()) tree gfor_fndecl_internal_realloc64;
 extern GTY(()) tree gfor_fndecl_internal_free;
 extern GTY(()) tree gfor_fndecl_allocate;
 extern GTY(()) tree gfor_fndecl_allocate64;
index ed9e1b8..7178e75 100644 (file)
@@ -1,3 +1,14 @@
+2005-09-09  Richard Sandiford  <richard@codesourcery.com>
+
+       PR fortran/12840
+       * gfortran.dg/array_constructor_6.f90
+       * gfortran.dg/array_constructor_7.f90
+       * gfortran.dg/array_constructor_8.f90
+       * gfortran.dg/array_constructor_9.f90
+       * gfortran.dg/array_constructor_10.f90
+       * gfortran.dg/array_constructor_11.f90
+       * gfortran.dg/array_constructor_12.f90: New tests.
+
 2005-09-08  Josh Conner  <jconner@apple.com>
 
        PR c++/23180
diff --git a/gcc/testsuite/gfortran.dg/array_constructor_10.f90 b/gcc/testsuite/gfortran.dg/array_constructor_10.f90
new file mode 100644 (file)
index 0000000..c439e0c
--- /dev/null
@@ -0,0 +1,27 @@
+! Like array_constructor_6.f90, but check constructors that apply
+! an elemental function to an array.
+! { dg-do run }
+program main
+  implicit none
+  call build (200)
+contains
+  subroutine build (order)
+    integer :: order, i
+
+    call test (order, (/ (abs ((/ i, -i, -i * 2 /)), i = 1, order) /))
+    call test (order, abs ((/ ((/ -i, -i, i * 2 /), i = 1, order) /)))
+    call test (order, (/ abs ((/ ((/ i, i, -i * 2 /), i = 1, order) /)) /))
+  end subroutine build
+
+  subroutine test (order, values)
+    integer, dimension (3:) :: values
+    integer :: order, i
+
+    if (size (values, dim = 1) .ne. order * 3) call abort
+    do i = 1, order
+      if (values (i * 3) .ne. i) call abort
+      if (values (i * 3 + 1) .ne. i) call abort
+      if (values (i * 3 + 2) .ne. i * 2) call abort
+    end do
+  end subroutine test
+end program main
diff --git a/gcc/testsuite/gfortran.dg/array_constructor_11.f90 b/gcc/testsuite/gfortran.dg/array_constructor_11.f90
new file mode 100644 (file)
index 0000000..395d292
--- /dev/null
@@ -0,0 +1,47 @@
+! Like array_constructor_6.f90, but check iterators with non-default stride,
+! including combinations which lead to zero-length vectors.
+! { dg-do run }
+program main
+  implicit none
+  call build (77)
+contains
+  subroutine build (order)
+    integer :: order, i, j
+
+    call test (1, 11, 3, (/ (i, i = 1, 11, 3) /))
+    call test (3, 20, 2, (/ (i, i = 3, 20, 2) /))
+    call test (4, 0, 11, (/ (i, i = 4, 0, 11) /))
+
+    call test (110, 10, -3,  (/ (i, i = 110, 10, -3) /))
+    call test (200, 20, -12, (/ (i, i = 200, 20, -12) /))
+    call test (29, 30, -6,   (/ (i, i = 29, 30, -6) /))
+
+    call test (1, order, 3,  (/ (i, i = 1, order, 3) /))
+    call test (order, 1, -3, (/ (i, i = order, 1, -3) /))
+
+    ! Triggers compile-time iterator calculations in trans-array.c
+    call test (1, 1000, 2,   (/ (i, i = 1, 1000, 2),   (i, i = order, 0, 1) /))
+    call test (1, 0, 3,      (/ (i, i = 1, 0, 3),      (i, i = order, 0, 1) /))
+    call test (1, 2000, -5,  (/ (i, i = 1, 2000, -5),  (i, i = order, 0, 1) /))
+    call test (3000, 99, 4,  (/ (i, i = 3000, 99, 4),  (i, i = order, 0, 1) /))
+    call test (400, 77, -39, (/ (i, i = 400, 77, -39), (i, i = order, 0, 1) /))
+
+    do j = -10, 10
+      call test (order + j, order, 5,  (/ (i, i = order + j, order, 5) /))
+      call test (order + j, order, -5, (/ (i, i = order + j, order, -5) /))
+    end do
+
+  end subroutine build
+
+  subroutine test (from, to, step, values)
+    integer, dimension (:) :: values
+    integer :: from, to, step, last, i
+
+    last = 0
+    do i = from, to, step
+      last = last + 1
+      if (values (last) .ne. i) call abort
+    end do
+    if (size (values, dim = 1) .ne. last) call abort
+  end subroutine test
+end program main
diff --git a/gcc/testsuite/gfortran.dg/array_constructor_12.f90 b/gcc/testsuite/gfortran.dg/array_constructor_12.f90
new file mode 100644 (file)
index 0000000..1c22ab9
--- /dev/null
@@ -0,0 +1,51 @@
+! Like array_constructor_6.f90, but check integer(8) iterators.
+! { dg-do run }
+program main
+  integer (kind = 8) :: i, l8, u8, step8
+  integer (kind = 4) :: l4, step4
+  integer (kind = 8), parameter :: big = 10000000000_8
+
+  l4 = huge (1)
+  u8 = l4 + 10_8
+  step4 = 2
+  call test ((/ (i, i = l4, u8, step4) /), l4 + 0_8, u8, step4 + 0_8)
+
+  l8 = big
+  u8 = big * 20
+  step8 = big
+  call test ((/ (i, i = l8, u8, step8) /), l8, u8, step8)
+
+  u8 = big + 100
+  l8 = big
+  step4 = -20
+  call test ((/ (i, i = u8, l8, step4) /), u8, l8, step4 + 0_8)
+
+  u8 = big * 40
+  l8 = big * 20
+  step8 = -big * 2
+  call test ((/ (i, i = u8, l8, step8) /), u8, l8, step8)
+
+  u8 = big
+  l4 = big / 100
+  step4 = -big / 500
+  call test ((/ (i, i = u8, l4, step4) /), u8, l4 + 0_8, step4 + 0_8)
+
+  u8 = big * 40 + 200
+  l4 = 200
+  step8 = -big
+  call test ((/ (i, i = u8, l4, step8) /), u8, l4 + 0_8, step8)
+contains
+  subroutine test (a, l, u, step)
+    integer (kind = 8), dimension (:), intent (in) :: a
+    integer (kind = 8), intent (in) :: l, u, step
+    integer (kind = 8) :: i
+    integer :: j
+
+    j = 1
+    do i = l, u, step
+      if (a (j) .ne. i) call abort
+      j = j + 1
+    end do
+    if (size (a, 1) .ne. j - 1) call abort
+  end subroutine test
+end program main
diff --git a/gcc/testsuite/gfortran.dg/array_constructor_6.f90 b/gcc/testsuite/gfortran.dg/array_constructor_6.f90
new file mode 100644 (file)
index 0000000..177fb20
--- /dev/null
@@ -0,0 +1,25 @@
+! PR 12840.  Make sure that array constructors can be used to determine
+! the bounds of a scalarization loop.
+! { dg-do run }
+program main
+  implicit none
+  call build (11)
+contains
+  subroutine build (order)
+    integer :: order, i
+
+    call test (order, (/ (i * 2, i = 1, order) /))
+    call test (17, (/ (i * 2, i = 1, 17) /))
+    call test (5, (/ 2, 4, 6, 8, 10 /))
+  end subroutine build
+
+  subroutine test (order, values)
+    integer, dimension (:) :: values
+    integer :: order, i
+
+    if (size (values, dim = 1) .ne. order) call abort
+    do i = 1, order
+      if (values (i) .ne. i * 2) call abort
+    end do
+  end subroutine test
+end program main
diff --git a/gcc/testsuite/gfortran.dg/array_constructor_7.f90 b/gcc/testsuite/gfortran.dg/array_constructor_7.f90
new file mode 100644 (file)
index 0000000..65ec26c
--- /dev/null
@@ -0,0 +1,26 @@
+! Like array_constructor_6.f90, but test for nested iterators.
+! { dg-do run }
+program main
+  implicit none
+  call build (17)
+contains
+  subroutine build (order)
+    integer :: order, i, j
+
+    call test (order, (/ (((j + 100) * i, j = 1, i), i = 1, order) /))
+    call test (9, (/ (((j + 100) * i, j = 1, i), i = 1, 9) /))
+    call test (3, (/ 101, 202, 204, 303, 306, 309 /))
+  end subroutine build
+
+  subroutine test (order, values)
+    integer, dimension (:) :: values
+    integer :: order, i, j
+
+    if (size (values, dim = 1) .ne. order * (order + 1) / 2) call abort
+    do i = 1, order
+      do j = 1, i
+        if (values (i * (i - 1) / 2 + j) .ne. (j + 100) * i) call abort
+      end do
+    end do
+  end subroutine test
+end program main
diff --git a/gcc/testsuite/gfortran.dg/array_constructor_8.f90 b/gcc/testsuite/gfortran.dg/array_constructor_8.f90
new file mode 100644 (file)
index 0000000..0ecebbc
--- /dev/null
@@ -0,0 +1,46 @@
+! Like array_constructor_6.f90, but check constructors that mix iterators
+! and individual scalar elements.
+! { dg-do run }
+program main
+  implicit none
+  call build (42)
+contains
+  subroutine build (order)
+    integer :: order, i
+
+    call test (order, 8, 5, (/ ((/ 1, 2, 3, 4, 5, 6, 7, 8 /), i = 1, order), &
+                               100, 200, 300, 400, 500 /))
+
+    call test (order, 2, 3, (/ ((/ 1, 2 /), i = 1, order), &
+                               100, 200, 300 /))
+
+    call test (order, 3, 5, (/ ((/ 1, 2, 3 /), i = 1, order), &
+                               100, 200, 300, 400, 500 /))
+
+    call test (order, 6, 1, (/ ((/ 1, 2, 3, 4, 5, 6 /), i = 1, order), &
+                               100 /))
+
+    call test (order, 5, 0, (/ ((/ 1, 2, 3, 4, 5 /), i = 1, order) /))
+
+    call test (order, 0, 4, (/ 100, 200, 300, 400 /))
+
+    call test (11, 5, 2, (/ ((/ 1, 2, 3, 4, 5 /), i = 1, 11), &
+                            100, 200 /))
+
+    call test (6, 2, order, (/ ((/ 1, 2 /), i = 1, 6), &
+                               (i * 100, i = 1, order) /))
+  end subroutine build
+
+  subroutine test (order, repeat, trail, values)
+    integer, dimension (:) :: values
+    integer :: order, repeat, trail, i
+
+    if (size (values, dim = 1) .ne. order * repeat + trail) call abort
+    do i = 1, order * repeat
+      if (values (i) .ne. mod (i - 1, repeat) + 1) call abort
+    end do
+    do i = 1, trail
+      if (values (i + order * repeat) .ne. i * 100) call abort
+    end do
+  end subroutine test
+end program main
diff --git a/gcc/testsuite/gfortran.dg/array_constructor_9.f90 b/gcc/testsuite/gfortran.dg/array_constructor_9.f90
new file mode 100644 (file)
index 0000000..71e939b
--- /dev/null
@@ -0,0 +1,43 @@
+! Like array_constructor_6.f90, but check constructors in which the length
+! of each subarray can only be determined at run time.
+! { dg-do run }
+program main
+  implicit none
+  call build (9)
+contains
+  function gen (order)
+    real, dimension (:, :), pointer :: gen
+    integer :: order, i, j
+
+    allocate (gen (order, order + 1))
+    forall (i = 1 : order, j = 1 : order + 1) gen (i, j) = i * i + j
+  end function gen
+
+  ! Deliberately leaky!
+  subroutine build (order)
+    integer :: order, i
+
+    call test (order, 0, (/ (gen (i), i = 1, order) /))
+    call test (3, 2, (/ ((/ 1.5, 1.5, gen (i) /), i = 1, 3) /))
+  end subroutine build
+
+  subroutine test (order, prefix, values)
+    real, dimension (:) :: values
+    integer :: order, prefix, last, i, j, k
+
+    last = 0
+    do i = 1, order
+      do j = 1, prefix
+        last = last + 1
+        if (values (last) .ne. 1.5) call abort
+      end do
+      do j = 1, i + 1
+        do k = 1, i
+          last = last + 1
+          if (values (last) .ne. j + k * k) call abort
+        end do
+      end do
+    end do
+    if (size (values, dim = 1) .ne. last) call abort
+  end subroutine test
+end program main
index d43be2e..5edab98 100644 (file)
@@ -1,3 +1,11 @@
+2005-09-09  Richard Sandiford  <richard@codesourcery.com>
+
+       PR fortran/12840
+       * runtime/memory.c (internal_malloc_size): Return a null pointer
+       if the size is zero.
+       (internal_free): Do nothing if the pointer is null.
+       (internal_realloc_size, internal_realloc, internal_realloc64): New.
+
 2005-09-07  Francois-Xavier Coudert  <coudert@clipper.ens.fr>
 
        PR libfortran/23262
index a8264f1..1e1190e 100644 (file)
@@ -141,6 +141,9 @@ internal_malloc_size (size_t size)
 {
   malloc_t *newmem;
 
+  if (size == 0)
+    return 0;
+
   newmem = malloc_with_header (size);
 
   if (!newmem)
@@ -195,7 +198,7 @@ internal_free (void *mem)
   malloc_t *m;
 
   if (!mem)
-    runtime_error ("Internal: Possible double free of temporary.");
+    return;
 
   m = DATA_HEADER (mem);
 
@@ -213,6 +216,67 @@ internal_free (void *mem)
 }
 iexport(internal_free);
 
+/* Reallocate internal memory MEM so it has SIZE bytes of data.
+   Allocate a new block if MEM is zero, and free the block if
+   SIZE is 0.  */
+
+static void *
+internal_realloc_size (void *mem, size_t size)
+{
+  malloc_t *m;
+
+  if (size == 0)
+    {
+      if (mem)
+       internal_free (mem);
+      return 0;
+    }
+
+  if (mem == 0)
+    return internal_malloc (size);
+
+  m = DATA_HEADER (mem);
+  if (m->magic != GFC_MALLOC_MAGIC)
+    runtime_error ("Internal: No magic memblock marker.  "
+                  "Possible memory corruption");
+
+  m = realloc (m, size + HEADER_SIZE);
+  if (!m)
+    os_error ("Out of memory.");
+
+  m->prev->next = m;
+  m->next->prev = m;
+  return DATA_POINTER (m);
+}
+
+extern void *internal_realloc (void *, GFC_INTEGER_4);
+export_proto(internal_realloc);
+
+void *
+internal_realloc (void *mem, GFC_INTEGER_4 size)
+{
+#ifdef GFC_CHECK_MEMORY
+  /* Under normal circumstances, this is _never_ going to happen!  */
+  if (size < 0)
+    runtime_error ("Attempt to allocate a negative amount of memory.");
+#endif
+  return internal_realloc_size (mem, (size_t) size);
+}
+
+extern void *internal_realloc64 (void *, GFC_INTEGER_8);
+export_proto(internal_realloc64);
+
+void *
+internal_realloc64 (void *mem, GFC_INTEGER_8 size)
+{
+#ifdef GFC_CHECK_MEMORY
+  /* Under normal circumstances, this is _never_ going to happen!  */
+  if (size < 0)
+    runtime_error ("Attempt to allocate a negative amount of memory.");
+#endif
+  return internal_realloc_size (mem, (size_t) size);
+}
+
 
 /* User-allocate, one call for each member of the alloc-list of an
    ALLOCATE statement. */