This is the mail archive of the fortran@gcc.gnu.org mailing list for the GNU Fortran project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Partially fix FMT= with CHARACTER arrays (PR fortran/39865)


Hi!

Both F95 and F2003 standards say that FMT= argument can be a CHARACTER
array, in which case the format string consists of the array elements
concatenated in array order.  But gfc_convert_array_to_string
ICEs in several places on those.

The following patch attempts to fix it at least partially, for packed
arrays.  The size computation should be correct even for non-packed arrays,
but in that case we'd need to allocate a temporary and concatenate the array
elements into it, possibly with a runtime check whether the temporary needs
to be allocated and populated/freed.

In the new testcase below the last call is commented out, because the array
isn't packed and so the testcase fails at runtime.

The patch also fixes ICE on:
 subroutine test()
   interface
     function f()
       character(len=1) :: f(5)
     end function f
   end interface
   write (*, f()) 1
 end subroutine test

Also, io.c was complaining that CHARACTER array in format string is an
extension, when it is in F95/F2003 standards, I wouldn't consider it an
extension.

2009-05-12  Jakub Jelinek  <jakub@redhat.com>

	PR fortran/39865
	* io.c (resolve_tag_format): CHARACTER array in FMT= argument
	isn't an extension.
	* trans-io.c (gfc_convert_array_to_string): Rewritten.

	* gfortran.dg/pr39865.f90: New test.
	* gfortran.dg/hollerith.f90: Don't expect errors for CHARACTER
	arrays in FMT=.
	* gfortran.dg/hollerith_f95.f90: Likewise.

--- gcc/fortran/trans-io.c.jj	2009-05-04 16:46:12.000000000 +0200
+++ gcc/fortran/trans-io.c	2009-05-12 14:47:39.000000000 +0200
@@ -579,54 +579,74 @@ gfc_convert_array_to_string (gfc_se * se
   tree array;
   tree type;
   tree size;
-  int rank;
-  gfc_symbol *sym;
 
-  sym = e->symtree->n.sym;
-  rank = sym->as->rank - 1;
-
-  if (e->ref->u.ar.type == AR_FULL)
+  if (e->rank == 0)
     {
-      se->expr = gfc_get_symbol_decl (sym);
-      se->expr = gfc_conv_array_data (se->expr);
+      gfc_conv_expr (se, e);
+      se->string_length
+	= fold_convert (gfc_charlen_type_node,
+			TYPE_SIZE_UNIT (TREE_TYPE (se->expr)));
+      se->expr = gfc_build_addr_expr (NULL_TREE, se->expr);
+      return;
     }
-  else
+
+  if (e->expr_type == EXPR_VARIABLE
+      && e->ref->u.ar.type == AR_FULL
+      && e->symtree
+      && e->symtree->n.sym->backend_decl
+      && GFC_DECL_PACKED_ARRAY (e->symtree->n.sym->backend_decl))
     {
-      gfc_conv_expr (se, e);
+      int rank = e->rank - 1;
+
+      se->expr = gfc_get_symbol_decl (e->symtree->n.sym);
+      se->expr = gfc_conv_array_data (se->expr);
+      array = e->symtree->n.sym->backend_decl;
+      type = TREE_TYPE (array);
+      if (GFC_ARRAY_TYPE_P (type))
+	size = GFC_TYPE_ARRAY_SIZE (type);
+      else
+	{
+	  gcc_assert (GFC_DESCRIPTOR_TYPE_P (type));
+	  size = gfc_conv_array_stride (array, rank);
+	  tmp = fold_build2 (MINUS_EXPR, gfc_array_index_type,
+			     gfc_conv_array_ubound (array, rank),
+			     gfc_conv_array_lbound (array, rank));
+	  tmp = fold_build2 (PLUS_EXPR, gfc_array_index_type, tmp,
+			     gfc_index_one_node);
+	  size = fold_build2 (MULT_EXPR, gfc_array_index_type, tmp, size);
+	}
+      gcc_assert (size);
+      tmp = TYPE_SIZE_UNIT (gfc_get_element_type (type));
+      size = fold_build2 (MULT_EXPR, gfc_array_index_type, size,
+			  fold_convert (gfc_array_index_type, tmp));
+      se->string_length = fold_convert (gfc_charlen_type_node, size);
+      return;
     }
 
-  array = sym->backend_decl;
+  gfc_conv_expr_descriptor (se, e, gfc_walk_expr (e));
+  array = se->expr;
   type = TREE_TYPE (array);
-
-  if (GFC_ARRAY_TYPE_P (type))
-    size = GFC_TYPE_ARRAY_SIZE (type);
+  if (e->rank > 1)
+    size = build_call_expr (gfor_fndecl_size0, 1,
+			    gfc_build_addr_expr (NULL, array));
   else
     {
-      gcc_assert (GFC_DESCRIPTOR_TYPE_P (type));
-      size = gfc_conv_array_stride (array, rank);
-      tmp = fold_build2 (MINUS_EXPR, gfc_array_index_type,
-		gfc_conv_array_ubound (array, rank),
-		gfc_conv_array_lbound (array, rank));
-      tmp = fold_build2 (PLUS_EXPR, gfc_array_index_type, tmp,
-		gfc_index_one_node);
-      size = fold_build2 (MULT_EXPR, gfc_array_index_type, tmp, size);      
-    }
+      tree ubound = gfc_conv_descriptor_ubound (array, gfc_index_zero_node);
+      tree lbound = gfc_conv_descriptor_lbound (array, gfc_index_zero_node);
 
-  gcc_assert (size);
-
-  /* If it is an element, we need the its address and size of the rest.  */
-  if (e->ref->u.ar.type == AR_ELEMENT)
-    {
-      size = fold_build2 (MINUS_EXPR, gfc_array_index_type, size,
-		TREE_OPERAND (se->expr, 1));
-      se->expr = gfc_build_addr_expr (NULL_TREE, se->expr);
+      size = fold_build2 (MINUS_EXPR, gfc_array_index_type, ubound, lbound);
+      size = fold_build2 (PLUS_EXPR, gfc_array_index_type, size,
+			  gfc_index_one_node);
+      size = fold_build2 (MAX_EXPR, gfc_array_index_type, size,
+			  gfc_index_zero_node);
     }
-
   tmp = TYPE_SIZE_UNIT (gfc_get_element_type (type));
   size = fold_build2 (MULT_EXPR, gfc_array_index_type, size,
 		      fold_convert (gfc_array_index_type, tmp));
-
   se->string_length = fold_convert (gfc_charlen_type_node, size);
+  /* FIXME: This is wrong for non-packed array, where we need to allocate
+     a temporary and concatenate the array elements in it.  */
+  se->expr = gfc_conv_descriptor_data_get (array);
 }
 
 
--- gcc/fortran/io.c.jj	2008-12-27 10:12:25.000000000 +0100
+++ gcc/fortran/io.c	2009-05-12 14:39:59.000000000 +0200
@@ -1,5 +1,5 @@
 /* Deal with I/O statements & related stuff.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
    Contributed by Andy Vaught
 
@@ -1266,21 +1266,12 @@ resolve_tag_format (const gfc_expr *e)
       return SUCCESS;
     }
 
-  /* If rank is nonzero, we allow the type to be character under GFC_STD_GNU
-     and other type under GFC_STD_LEGACY. It may be assigned an Hollerith
-     constant.  */
-  if (e->ts.type == BT_CHARACTER)
-    {
-      if (gfc_notify_std (GFC_STD_GNU, "Extension: Character array "
-			  "in FORMAT tag at %L", &e->where) == FAILURE)
-	return FAILURE;
-    }
-  else
-    {
-      if (gfc_notify_std (GFC_STD_LEGACY, "Extension: Non-character "
-			  "in FORMAT tag at %L", &e->where) == FAILURE)
-	return FAILURE;
-    }
+  /* If rank is nonzero and type is not character, we allow it under GFC_STD_LEGACY.
+     It may be assigned an Hollerith constant.  */
+  if (e->ts.type != BT_CHARACTER
+      && gfc_notify_std (GFC_STD_LEGACY, "Extension: Non-character "
+			 "in FORMAT tag at %L", &e->where) == FAILURE)
+    return FAILURE;
 
   return SUCCESS;
 }
--- gcc/testsuite/gfortran.dg/pr39865.f90.jj	2009-05-12 14:25:33.000000000 +0200
+++ gcc/testsuite/gfortran.dg/pr39865.f90	2009-05-12 14:24:49.000000000 +0200
@@ -0,0 +1,67 @@
+! PR fortran/39865
+! { dg-do run }
+
+subroutine f1 (a)
+  character(len=1) :: a(7:)
+  character(len=12) :: b
+  character(len=1) :: c(2:10)
+  write (b, a) 'Hell', 'o wo', 'rld!'
+  if (b .ne. 'Hello world!') call abort
+  write (b, a(:)) 'Hell', 'o wo', 'rld!'
+  if (b .ne. 'Hello world!') call abort
+  write (b, a(8:)) 'Hell', 'o wo', 'rld!'
+  if (b .ne. 'Hello world!') call abort
+  c(2) = ' '
+  c(3) = '('
+  c(4) = '3'
+  c(5) = 'A'
+  c(6) = '4'
+  c(7) = ')'
+  write (b, c) 'Hell', 'o wo', 'rld!'
+  if (b .ne. 'Hello world!') call abort
+  write (b, c(:)) 'Hell', 'o wo', 'rld!'
+  if (b .ne. 'Hello world!') call abort
+  write (b, c(3:)) 'Hell', 'o wo', 'rld!'
+  if (b .ne. 'Hello world!') call abort
+end subroutine f1
+
+subroutine f2 (a)
+  character(len=1) :: a(10:,20:)
+  character(len=12) :: b
+  write (b, a) 'Hell', 'o wo', 'rld!'
+  if (b .ne. 'Hello world!') call abort
+  write (b, a) 'Hell', 'o wo', 'rld!'
+  if (b .ne. 'Hello world!') call abort
+end subroutine f2
+
+  interface
+    subroutine f1 (a)
+      character(len=1) :: a(:)
+    end
+  end interface
+  interface
+    subroutine f2 (a)
+      character(len=1) :: a(:,:)
+    end
+  end interface
+  integer :: i, j
+  character(len=1) :: e (6, 7:9), f (3,2), g (10)
+  e = 'X'
+  e(2,8) = ' '
+  e(3,8) = '('
+  e(4,8) = '3'
+  e(2,9) = 'A'
+  e(3,9) = '4'
+  e(4,9) = ')'
+  f = e(2:4,8:9)
+  g = 'X'
+  g(2) = ' '
+  g(3) = '('
+  g(4) = '3'
+  g(5) = 'A'
+  g(6) = '4'
+  g(7) = ')'
+  call f1 (g(2:7))
+  call f2 (f)
+! call f2 (e(2:4,8:9))
+end
--- gcc/testsuite/gfortran.dg/hollerith_f95.f90.jj	2008-09-05 12:55:20.000000000 +0200
+++ gcc/testsuite/gfortran.dg/hollerith_f95.f90	2009-05-12 14:48:41.000000000 +0200
@@ -91,10 +91,3 @@ end subroutine
 ! { dg-error "Non-character in FORMAT tag" "" { target *-*-* } 38 }
 
 ! { dg-error "Non-character in FORMAT tag" "" { target *-*-* } 40 }
-
-! { dg-error "Character array in FORMAT tag" "" { target *-*-* } 44 }
-
-! { dg-error "Character array in FORMAT tag" "" { target *-*-* } 46 }
-
-! { dg-error "Character array in FORMAT tag" "" { target *-*-* } 48 }
-
--- gcc/testsuite/gfortran.dg/hollerith.f90.jj	2008-11-13 15:02:53.000000000 +0100
+++ gcc/testsuite/gfortran.dg/hollerith.f90	2009-05-12 14:46:55.000000000 +0200
@@ -99,10 +99,4 @@ end subroutine
 
 ! { dg-warning "Non-character in FORMAT tag" "" { target *-*-* } 39 }
 
-! { dg-warning "Character array in FORMAT tag" "" { target *-*-* } 43 }
-
-! { dg-warning "Character array in FORMAT tag" "" { target *-*-* } 45 }
-
-! { dg-warning "Character array in FORMAT tag" "" { target *-*-* } 47 }
-
 ! { dg-warning "Hollerith constant" "" { target *-*-* } 51 }

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]