2005-10-23 Paul Thomas <pault@gcc.gnu.org>
authorpault <pault@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 23 Oct 2005 06:59:17 +0000 (06:59 +0000)
committerpault <pault@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 23 Oct 2005 06:59:17 +0000 (06:59 +0000)
PR fortran/18022
* trans-expr.c (gfc_trans_arrayfunc_assign): Return NULL
if there is a component ref during an array ref to force
use of temporary in assignment.

PR fortran/24311
PR fortran/24384
* fortran/iresolve.c (check_charlen_present): New function to
add a charlen to the typespec, in the case of constant
expressions.
(gfc_resolve_merge, gfc_resolve_spread): Call.the above.
(gfc_resolve_spread): Make calls to library functions that
handle the case of the spread intrinsic with a scalar source.
* libgfortran/intrinsics/spread_generic.c (spread_internal
_scalar): New function that handles the special case of spread
with a scalar source. This has interface functions -
(spread_scalar, spread_char_scalar): New functions to interface
with the calls specified in gfc_resolve_spread.

2005-10-23  Paul Thomas  <pault@gcc.gnu.org>

PR fortran/18022
gfortran.dg/assign_func_dtcomp_1.f90: New test.

PR fortran/24311
gfortran.dg/merge_char_const.f90: New test.

PR fortran/24384
gfortran.dg/spread_scalar_source.f90: New test.

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

gcc/fortran/ChangeLog
gcc/fortran/iresolve.c
gcc/fortran/trans-expr.c
gcc/testsuite/ChangeLog
gcc/testsuite/gfortran.dg/assign_func_dtcomp_1.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/merge_char_const.f90 [new file with mode: 0644]
gcc/testsuite/gfortran.dg/spread_scalar_source.f90 [new file with mode: 0755]
libgfortran/ChangeLog
libgfortran/intrinsics/spread_generic.c

index 51178f2..af15594 100644 (file)
@@ -1,3 +1,19 @@
+2005-10-23  Paul Thomas  <pault@gcc.gnu.org>
+
+       PR fortran/18022
+       * trans-expr.c (gfc_trans_arrayfunc_assign): Return NULL
+       if there is a component ref during an array ref to force
+       use of temporary in assignment.
+
+       PR fortran/24311
+       PR fortran/24384
+       * fortran/iresolve.c (check_charlen_present): New function to
+       add a charlen to the typespec, in the case of constant
+       expressions.
+       (gfc_resolve_merge, gfc_resolve_spread): Call.the above.
+       (gfc_resolve_spread): Make calls to library functions that
+       handle the case of the spread intrinsic with a scalar source.
+
 2005-10-22  Erik Edelmann  <eedelman@gcc.gnu.org>
 
        PR fortran/24426
index 6c23d4a..9cba18b 100644 (file)
@@ -59,6 +59,21 @@ gfc_get_string (const char *format, ...)
   return IDENTIFIER_POINTER (ident);
 }
 
+/* MERGE and SPREAD need to have source charlen's present for passing
+   to the result expression.  */
+static void
+check_charlen_present (gfc_expr *source)
+{
+  if (source->expr_type == EXPR_CONSTANT && source->ts.cl == NULL)
+    {
+      source->ts.cl = gfc_get_charlen ();
+      source->ts.cl->next = gfc_current_ns->cl_list;
+      gfc_current_ns->cl_list = source->ts.cl;
+      source->ts.cl->length = gfc_int_expr (source->value.character.length);
+      source->rank = 0;
+    }
+}
+
 /********************** Resolution functions **********************/
 
 
@@ -996,6 +1011,9 @@ gfc_resolve_merge (gfc_expr * f, gfc_expr * tsource,
                   gfc_expr * fsource ATTRIBUTE_UNUSED,
                   gfc_expr * mask ATTRIBUTE_UNUSED)
 {
+  if (tsource->ts.type == BT_CHARACTER)
+    check_charlen_present (tsource);
+
   f->ts = tsource->ts;
   f->value.function.name =
     gfc_get_string ("__merge_%c%d", gfc_type_letter (tsource->ts.type),
@@ -1395,11 +1413,19 @@ gfc_resolve_spread (gfc_expr * f, gfc_expr * source,
                    gfc_expr * dim,
                    gfc_expr * ncopies)
 {
+  if (source->ts.type == BT_CHARACTER)
+    check_charlen_present (source);
+
   f->ts = source->ts;
   f->rank = source->rank + 1;
-  f->value.function.name = (source->ts.type == BT_CHARACTER
-                           ? PREFIX("spread_char")
-                           : PREFIX("spread"));
+  if (source->rank == 0)
+    f->value.function.name = (source->ts.type == BT_CHARACTER
+                             ? PREFIX("spread_char_scalar")
+                             : PREFIX("spread_scalar"));
+  else
+    f->value.function.name = (source->ts.type == BT_CHARACTER
+                             ? PREFIX("spread_char")
+                             : PREFIX("spread"));
 
   gfc_resolve_dim_arg (dim);
   gfc_resolve_index (ncopies, 1);
index 7c6b409..fe5e24b 100644 (file)
@@ -2591,6 +2591,8 @@ gfc_trans_arrayfunc_assign (gfc_expr * expr1, gfc_expr * expr2)
 {
   gfc_se se;
   gfc_ss *ss;
+  gfc_ref * ref;
+  bool seen_array_ref;
 
   /* The caller has already checked rank>0 and expr_type == EXPR_FUNCTION.  */
   if (expr2->value.function.isym && !gfc_is_intrinsic_libcall (expr2))
@@ -2605,6 +2607,20 @@ gfc_trans_arrayfunc_assign (gfc_expr * expr1, gfc_expr * expr2)
   if (gfc_ref_needs_temporary_p (expr1->ref))
     return NULL;
 
+  /* Check that no LHS component references appear during an array
+     reference. This is needed because we do not have the means to
+     span any arbitrary stride with an array descriptor. This check
+     is not needed for the rhs because the function result has to be
+     a complete type.  */
+  seen_array_ref = false;
+  for (ref = expr1->ref; ref; ref = ref->next)
+    {
+      if (ref->type == REF_ARRAY)
+       seen_array_ref= true;
+      else if (ref->type == REF_COMPONENT && seen_array_ref)
+       return NULL;
+    }
+
   /* Check for a dependency.  */
   if (gfc_check_fncall_dependency (expr1, expr2))
     return NULL;
index e1ddf72..af24da1 100644 (file)
@@ -1,3 +1,14 @@
+2005-10-23  Paul Thomas  <pault@gcc.gnu.org>
+
+       PR fortran/18022
+       gfortran.dg/assign_func_dtcomp_1.f90: New test.
+
+       PR fortran/24311
+       gfortran.dg/merge_char_const.f90: New test.
+
+       PR fortran/24384
+       gfortran.dg/spread_scalar_source.f90: New test.
+
 2005-10-22  Hans-Peter Nilsson  <hp@axis.com>
 
        * g++.old-deja/g++.jason/thunk2.C: Guard test with { target fpic }.
diff --git a/gcc/testsuite/gfortran.dg/assign_func_dtcomp_1.f90 b/gcc/testsuite/gfortran.dg/assign_func_dtcomp_1.f90
new file mode 100644 (file)
index 0000000..385eb27
--- /dev/null
@@ -0,0 +1,47 @@
+! { dg-do run }
+! { dg-options "-O0" }
+!
+! Test fix for PR18022.
+!
+! Contributed by Paul Thomas <pault@gcc.gnu.org>
+!
+program assign_func_dtcomp
+ implicit none
+ type                         ::  mytype
+   real                       ::  x
+   real                       ::  y
+ end type mytype
+ type (mytype), dimension (4) ::  z
+
+ type                         ::  thytype
+   real                       ::  x(4)
+ end type thytype
+ type (thytype)               ::  w
+ real, dimension (4)          ::  a = (/1.,2.,3.,4./)
+ real, dimension (4)          ::  b = (/5.,6.,7.,8./)
+
+
+! Test the original problem is fixed.
+ z(:)%x = foo (a)
+ z(:)%y = foo (b)
+
+
+ if (any(z%x.ne.a).or.any(z%y.ne.b)) call abort ()
+
+! Make sure we did not break anything on the way.
+ w%x(:) = foo (b)
+ a = foo (b)
+
+ if (any(w%x.ne.b).or.any(a.ne.b)) call abort ()
+
+contains
+
+ function foo (v) result (ans)
+   real, dimension (:), intent(in)   ::  v
+   real, dimension (size(v))  ::  ans
+   ans = v
+ end function foo
+
+
+end program assign_func_dtcomp
+
diff --git a/gcc/testsuite/gfortran.dg/merge_char_const.f90 b/gcc/testsuite/gfortran.dg/merge_char_const.f90
new file mode 100644 (file)
index 0000000..32c87f5
--- /dev/null
@@ -0,0 +1,13 @@
+! { dg-do run }
+! { dg-options "-O0" }
+! This tests the patch for PR24311 in which the PRINT statement would
+! ICE on trying to print a MERGE statement with character constants
+! for the first two arguments.
+!
+! Contributed by Paul Thomas <pault@gcc.gnu.org>
+!
+  integer, dimension(6) :: i = (/1,0,0,1,1,0/)
+  print '(6a1)', Merge ("a", "b", i  == 1) ! { dg-output "abbaab" }
+  end
+
+
diff --git a/gcc/testsuite/gfortran.dg/spread_scalar_source.f90 b/gcc/testsuite/gfortran.dg/spread_scalar_source.f90
new file mode 100755 (executable)
index 0000000..c253165
--- /dev/null
@@ -0,0 +1,52 @@
+! { dg-do run }
+! { dg-options "-O0" }
+
+  character*1 :: i, j(10)
+  character*8 :: buffer
+  integer*1 :: ii, jj(10)
+  type :: mytype
+    real*8 :: x
+    integer*1 :: i
+    character*15 :: ch
+  end type mytype
+  type(mytype) :: iii, jjj(10)
+
+  i = "w"
+  ii = 42
+  iii = mytype (41.9999_8, 77, "test_of_spread_")
+
+! Test constant sources.
+
+  j = spread ("z", 1 , 10)
+  if (any (j /= "z")) call abort ()
+  jj = spread (19, 1 , 10)
+  if (any (jj /= 19)) call abort ()
+
+! Test variable sources.
+
+  j = spread (i, 1 , 10)
+  if (any (j /= "w")) call abort ()
+  jj = spread (ii, 1 , 10)
+  if (any (jj /= 42)) call abort ()
+  jjj = spread (iii, 1 , 10)
+  if (any (jjj%x /= 41.9999_8)) call abort ()
+  if (any (jjj%i /= 77)) call abort ()
+  if (any (jjj%ch /= "test_of_spread_")) call abort ()
+
+! Check that spread != 1 is OK.
+
+  jj(2:10:2) = spread (1, 1, 5)
+  if (any (jj(1:9:2) /= 42) .or. any (jj(2:10:2) /= 1)) call abort ()
+
+! Finally, check that temporaries and trans-io.c work correctly.
+
+  write (buffer, '(4a1)') spread (i, 1 , 4)
+  if (trim(buffer) /= "wwww") call abort ()
+  write (buffer, '(4a1)') spread ("r", 1 , 4)
+  if (trim(buffer) /= "rrrr") call abort ()
+  write (buffer, '(4i2)') spread (ii, 1 , 4)
+  if (trim(buffer) /= "42424242") call abort ()
+  write (buffer, '(4i2)') spread (31, 1 , 4)
+  if (trim(buffer) /= "31313131") call abort ()
+
+  end
\ No newline at end of file
index 2c4f5f8..3666964 100644 (file)
@@ -1,3 +1,12 @@
+2005-10-23  Paul Thomas  <pault@gcc.gnu.org>
+
+       PR fortran/24384
+       * intrinsics/spread_generic.c (spread_internal_scalar): New
+       function that handles the special case of spread with a scalar
+       source. This has new interface functions -
+       (spread_scalar, spread_char_scalar): New functions to interface
+       with the calls specified in gfc_resolve_spread.
+
 2005-10-21  Francois-Xavier Coudert  <coudert@clipper.ens.fr>
 
        PR libfortran/24383
index a9cddb0..bdcc0d1 100644 (file)
@@ -176,6 +176,49 @@ spread_internal (gfc_array_char *ret, const gfc_array_char *source,
     }
 }
 
+/* This version of spread_internal treats the special case of a scalar
+   source.  This is much simpler than the more general case above.  */
+
+static void
+spread_internal_scalar (gfc_array_char *ret, const char *source,
+                       const index_type *along, const index_type *pncopies,
+                       index_type size)
+{
+  int n;
+  int ncopies = *pncopies;
+  char * dest;
+
+  if (GFC_DESCRIPTOR_RANK (ret) != 1)
+    runtime_error ("incorrect destination rank in spread()");
+
+  if (*along > 1)
+    runtime_error ("dim outside of rank in spread()");
+
+  if (ret->data == NULL)
+    {
+      ret->data = internal_malloc_size (ncopies * size);
+      ret->offset = 0;
+      ret->dim[0].stride = 1;
+      ret->dim[0].lbound = 0;
+      ret->dim[0].ubound = ncopies - 1;
+    }
+  else
+    {
+      if (ret->dim[0].stride == 0)
+       ret->dim[0].stride = 1;
+
+      if (ncopies - 1 > (ret->dim[0].ubound - ret->dim[0].lbound)
+                          / ret->dim[0].stride)
+       runtime_error ("dim too large in spread()");
+    }
+
+  for (n = 0; n < ncopies; n++)
+    {
+      dest = (char*)(ret->data + n*size*ret->dim[0].stride);
+      memcpy (dest , source, size);
+    }
+}
+
 extern void spread (gfc_array_char *, const gfc_array_char *,
                    const index_type *, const index_type *);
 export_proto(spread);
@@ -200,3 +243,37 @@ spread_char (gfc_array_char *ret,
 {
   spread_internal (ret, source, along, pncopies, source_length);
 }
+
+/* The following are the prototypes for the versions of spread with a
+   scalar source.  */
+
+extern void spread_scalar (gfc_array_char *, const char *,
+                          const index_type *, const index_type *);
+export_proto(spread_scalar);
+
+void
+spread_scalar (gfc_array_char *ret, const char *source,
+              const index_type *along, const index_type *pncopies)
+{
+  if (!ret->dtype)
+    runtime_error ("return array missing descriptor in spread()");
+  spread_internal_scalar (ret, source, along, pncopies, GFC_DESCRIPTOR_SIZE (ret));
+}
+
+
+extern void spread_char_scalar (gfc_array_char *, GFC_INTEGER_4,
+                               const char *, const index_type *,
+                               const index_type *, GFC_INTEGER_4);
+export_proto(spread_char_scalar);
+
+void
+spread_char_scalar (gfc_array_char *ret,
+                   GFC_INTEGER_4 ret_length __attribute__((unused)),
+                   const char *source, const index_type *along,
+                   const index_type *pncopies, GFC_INTEGER_4 source_length)
+{
+  if (!ret->dtype)
+    runtime_error ("return array missing descriptor in spread()");
+  spread_internal_scalar (ret, source, along, pncopies, source_length);
+}
+