Commit c41fea4a by Paul Thomas

re PR fortran/34955 (transfer_assumed_size_1.f90: Valgrind error: invalid read of size 3)

2009-01-17  Paul Thomas  <pault@gcc.gnu.org>

	PR fortran/34955
	* trans-intrinsic.c (gfc_conv_intrinsic_array_transfer): Has
	been absorbed into gfc_conv_intrinsic_transfer. All
	references to it in trans-intrinsic.c have been changed
	accordingly.  PR fixed by using a temporary for scalar
	character transfer, when the source is shorter than the
	destination.

2009-01-17  Paul Thomas  <pault@gcc.gnu.org>

	PR fortran/34955
	* gfortran.dg/transfer_intrinsic_1.f90: New test.
	* gfortran.dg/transfer_intrinsic_2.f90: New test.

From-SVN: r143462
parent 6e7ff326
2009-01-17 Paul Thomas <pault@gcc.gnu.org> 2009-01-17 Paul Thomas <pault@gcc.gnu.org>
PR fortran/34955
* trans-intrinsic.c (gfc_conv_intrinsic_array_transfer): Has
been absorbed into gfc_conv_intrinsic_transfer. All
references to it in trans-intrinsic.c have been changed
accordingly. PR fixed by using a temporary for scalar
character transfer, when the source is shorter than the
destination.
2009-01-17 Paul Thomas <pault@gcc.gnu.org>
PR fortran/38657 PR fortran/38657
* module.c (write_common_0): Revert patch of 2009-01-05. * module.c (write_common_0): Revert patch of 2009-01-05.
......
...@@ -3615,18 +3615,27 @@ gfc_conv_intrinsic_adjust (gfc_se * se, gfc_expr * expr, tree fndecl) ...@@ -3615,18 +3615,27 @@ gfc_conv_intrinsic_adjust (gfc_se * se, gfc_expr * expr, tree fndecl)
} }
/* Array transfer statement. /* Generate code for the TRANSFER intrinsic:
DEST(1:N) = TRANSFER (SOURCE, MOLD[, SIZE]) For scalar results:
where: DEST = TRANSFER (SOURCE, MOLD)
typeof<DEST> = typeof<MOLD> where:
and: typeof<DEST> = typeof<MOLD>
N = min (sizeof (SOURCE(:)), sizeof (DEST(:)), and:
MOLD is scalar.
For array results:
DEST(1:N) = TRANSFER (SOURCE, MOLD[, SIZE])
where:
typeof<DEST> = typeof<MOLD>
and:
N = min (sizeof (SOURCE(:)), sizeof (DEST(:)),
sizeof (DEST(0) * SIZE). */ sizeof (DEST(0) * SIZE). */
static void static void
gfc_conv_intrinsic_array_transfer (gfc_se * se, gfc_expr * expr) gfc_conv_intrinsic_transfer (gfc_se * se, gfc_expr * expr)
{ {
tree tmp; tree tmp;
tree tmpdecl;
tree ptr;
tree extent; tree extent;
tree source; tree source;
tree source_type; tree source_type;
...@@ -3645,14 +3654,27 @@ gfc_conv_intrinsic_array_transfer (gfc_se * se, gfc_expr * expr) ...@@ -3645,14 +3654,27 @@ gfc_conv_intrinsic_array_transfer (gfc_se * se, gfc_expr * expr)
gfc_ss_info *info; gfc_ss_info *info;
stmtblock_t block; stmtblock_t block;
int n; int n;
bool scalar_mold;
gcc_assert (se->loop); info = NULL;
info = &se->ss->data.info; if (se->loop)
info = &se->ss->data.info;
/* Convert SOURCE. The output from this stage is:- /* Convert SOURCE. The output from this stage is:-
source_bytes = length of the source in bytes source_bytes = length of the source in bytes
source = pointer to the source data. */ source = pointer to the source data. */
arg = expr->value.function.actual; arg = expr->value.function.actual;
/* Ensure double transfer through LOGICAL preserves all
the needed bits. */
if (arg->expr->expr_type == EXPR_FUNCTION
&& arg->expr->value.function.esym == NULL
&& arg->expr->value.function.isym != NULL
&& arg->expr->value.function.isym->id == GFC_ISYM_TRANSFER
&& arg->expr->ts.type == BT_LOGICAL
&& expr->ts.type != arg->expr->ts.type)
arg->expr->value.function.name = "__transfer_in_transfer";
gfc_init_se (&argse, NULL); gfc_init_se (&argse, NULL);
ss = gfc_walk_expr (arg->expr); ss = gfc_walk_expr (arg->expr);
...@@ -3682,8 +3704,8 @@ gfc_conv_intrinsic_array_transfer (gfc_se * se, gfc_expr * expr) ...@@ -3682,8 +3704,8 @@ gfc_conv_intrinsic_array_transfer (gfc_se * se, gfc_expr * expr)
source_type = gfc_get_element_type (TREE_TYPE (argse.expr)); source_type = gfc_get_element_type (TREE_TYPE (argse.expr));
/* Repack the source if not a full variable array. */ /* Repack the source if not a full variable array. */
if (!(arg->expr->expr_type == EXPR_VARIABLE if (arg->expr->expr_type == EXPR_VARIABLE
&& arg->expr->ref->u.ar.type == AR_FULL)) && arg->expr->ref->u.ar.type != AR_FULL)
{ {
tmp = build_fold_addr_expr (argse.expr); tmp = build_fold_addr_expr (argse.expr);
...@@ -3750,6 +3772,8 @@ gfc_conv_intrinsic_array_transfer (gfc_se * se, gfc_expr * expr) ...@@ -3750,6 +3772,8 @@ gfc_conv_intrinsic_array_transfer (gfc_se * se, gfc_expr * expr)
gfc_init_se (&argse, NULL); gfc_init_se (&argse, NULL);
ss = gfc_walk_expr (arg->expr); ss = gfc_walk_expr (arg->expr);
scalar_mold = arg->expr->rank == 0;
if (ss == gfc_ss_terminator) if (ss == gfc_ss_terminator)
{ {
gfc_conv_expr_reference (&argse, arg->expr); gfc_conv_expr_reference (&argse, arg->expr);
...@@ -3763,6 +3787,9 @@ gfc_conv_intrinsic_array_transfer (gfc_se * se, gfc_expr * expr) ...@@ -3763,6 +3787,9 @@ gfc_conv_intrinsic_array_transfer (gfc_se * se, gfc_expr * expr)
mold_type = gfc_get_element_type (TREE_TYPE (argse.expr)); mold_type = gfc_get_element_type (TREE_TYPE (argse.expr));
} }
gfc_add_block_to_block (&se->pre, &argse.pre);
gfc_add_block_to_block (&se->post, &argse.post);
if (strcmp (expr->value.function.name, "__transfer_in_transfer") == 0) if (strcmp (expr->value.function.name, "__transfer_in_transfer") == 0)
{ {
/* If this TRANSFER is nested in another TRANSFER, use a type /* If this TRANSFER is nested in another TRANSFER, use a type
...@@ -3799,14 +3826,14 @@ gfc_conv_intrinsic_array_transfer (gfc_se * se, gfc_expr * expr) ...@@ -3799,14 +3826,14 @@ gfc_conv_intrinsic_array_transfer (gfc_se * se, gfc_expr * expr)
else else
tmp = NULL_TREE; tmp = NULL_TREE;
/* Separate array and scalar results. */
if (scalar_mold && tmp == NULL_TREE)
goto scalar_transfer;
size_bytes = gfc_create_var (gfc_array_index_type, NULL); size_bytes = gfc_create_var (gfc_array_index_type, NULL);
if (tmp != NULL_TREE) if (tmp != NULL_TREE)
{ tmp = fold_build2 (MULT_EXPR, gfc_array_index_type,
tmp = fold_build2 (MULT_EXPR, gfc_array_index_type, tmp, dest_word_len);
tmp, dest_word_len);
tmp = fold_build2 (MIN_EXPR, gfc_array_index_type,
tmp, source_bytes);
}
else else
tmp = source_bytes; tmp = source_bytes;
...@@ -3847,9 +3874,7 @@ gfc_conv_intrinsic_array_transfer (gfc_se * se, gfc_expr * expr) ...@@ -3847,9 +3874,7 @@ gfc_conv_intrinsic_array_transfer (gfc_se * se, gfc_expr * expr)
se->loop->to[n] = upper; se->loop->to[n] = upper;
/* Build a destination descriptor, using the pointer, source, as the /* Build a destination descriptor, using the pointer, source, as the
data field. This is already allocated so set callee_alloc. data field. */
FIXME callee_alloc is not set! */
gfc_trans_create_temp_array (&se->pre, &se->post, se->loop, gfc_trans_create_temp_array (&se->pre, &se->post, se->loop,
info, mold_type, NULL_TREE, false, true, false, info, mold_type, NULL_TREE, false, true, false,
&expr->where); &expr->where);
...@@ -3863,72 +3888,71 @@ gfc_conv_intrinsic_array_transfer (gfc_se * se, gfc_expr * expr) ...@@ -3863,72 +3888,71 @@ gfc_conv_intrinsic_array_transfer (gfc_se * se, gfc_expr * expr)
3, 3,
tmp, tmp,
fold_convert (pvoid_type_node, source), fold_convert (pvoid_type_node, source),
size_bytes); fold_build2 (MIN_EXPR, gfc_array_index_type,
size_bytes, source_bytes));
gfc_add_expr_to_block (&se->pre, tmp); gfc_add_expr_to_block (&se->pre, tmp);
se->expr = info->descriptor; se->expr = info->descriptor;
if (expr->ts.type == BT_CHARACTER) if (expr->ts.type == BT_CHARACTER)
se->string_length = dest_word_len; se->string_length = dest_word_len;
}
return;
/* Scalar transfer statement. /* Deal with scalar results. */
TRANSFER (source, mold) = memcpy(&tmpdecl, &source, size), tmpdecl. */ scalar_transfer:
extent = fold_build2 (MIN_EXPR, gfc_array_index_type,
dest_word_len, source_bytes);
static void if (expr->ts.type == BT_CHARACTER)
gfc_conv_intrinsic_transfer (gfc_se * se, gfc_expr * expr) {
{ tree direct;
gfc_actual_arglist *arg; tree indirect;
gfc_se argse;
tree type;
tree ptr;
gfc_ss *ss;
tree tmpdecl, tmp;
/* Get a pointer to the source. */ ptr = convert (gfc_get_pchar_type (expr->ts.kind), source);
arg = expr->value.function.actual; tmpdecl = gfc_create_var (gfc_get_pchar_type (expr->ts.kind),
ss = gfc_walk_expr (arg->expr); "transfer");
gfc_init_se (&argse, NULL);
if (ss == gfc_ss_terminator)
gfc_conv_expr_reference (&argse, arg->expr);
else
gfc_conv_array_parameter (&argse, arg->expr, ss, 1, NULL, NULL);
gfc_add_block_to_block (&se->pre, &argse.pre);
gfc_add_block_to_block (&se->post, &argse.post);
ptr = argse.expr;
arg = arg->next; /* If source is longer than the destination, use a pointer to
type = gfc_typenode_for_spec (&expr->ts); the source directly. */
if (strcmp (expr->value.function.name, "__transfer_in_transfer") == 0) gfc_init_block (&block);
{ gfc_add_modify (&block, tmpdecl, ptr);
/* If this TRANSFER is nested in another TRANSFER, use a type direct = gfc_finish_block (&block);
that preserves all bits. */
if (expr->ts.type == BT_LOGICAL)
type = gfc_get_int_type (expr->ts.kind);
}
if (expr->ts.type == BT_CHARACTER) /* Otherwise, allocate a string with the length of the destination
{ and copy the source into it. */
ptr = convert (build_pointer_type (type), ptr); gfc_init_block (&block);
gfc_init_se (&argse, NULL); tmp = gfc_get_pchar_type (expr->ts.kind);
gfc_conv_expr (&argse, arg->expr); tmp = gfc_call_malloc (&block, tmp, dest_word_len);
gfc_add_block_to_block (&se->pre, &argse.pre); gfc_add_modify (&block, tmpdecl,
gfc_add_block_to_block (&se->post, &argse.post); fold_convert (TREE_TYPE (ptr), tmp));
se->expr = ptr; tmp = build_call_expr (built_in_decls[BUILT_IN_MEMCPY], 3,
se->string_length = argse.string_length; fold_convert (pvoid_type_node, tmpdecl),
fold_convert (pvoid_type_node, ptr),
extent);
gfc_add_expr_to_block (&block, tmp);
indirect = gfc_finish_block (&block);
/* Wrap it up with the condition. */
tmp = fold_build2 (LE_EXPR, boolean_type_node,
dest_word_len, source_bytes);
tmp = build3_v (COND_EXPR, tmp, direct, indirect);
gfc_add_expr_to_block (&se->pre, tmp);
se->expr = tmpdecl;
se->string_length = dest_word_len;
} }
else else
{ {
tree moldsize; tmpdecl = gfc_create_var (mold_type, "transfer");
tmpdecl = gfc_create_var (type, "transfer");
moldsize = size_in_bytes (type); ptr = convert (build_pointer_type (mold_type), source);
/* Use memcpy to do the transfer. */ /* Use memcpy to do the transfer. */
tmp = build_fold_addr_expr (tmpdecl); tmp = build_fold_addr_expr (tmpdecl);
tmp = build_call_expr (built_in_decls[BUILT_IN_MEMCPY], 3, tmp = build_call_expr (built_in_decls[BUILT_IN_MEMCPY], 3,
fold_convert (pvoid_type_node, tmp), fold_convert (pvoid_type_node, tmp),
fold_convert (pvoid_type_node, ptr), fold_convert (pvoid_type_node, ptr),
moldsize); extent);
gfc_add_expr_to_block (&se->pre, tmp); gfc_add_expr_to_block (&se->pre, tmp);
se->expr = tmpdecl; se->expr = tmpdecl;
...@@ -4828,23 +4852,7 @@ gfc_conv_intrinsic_function (gfc_se * se, gfc_expr * expr) ...@@ -4828,23 +4852,7 @@ gfc_conv_intrinsic_function (gfc_se * se, gfc_expr * expr)
gfc_advance_se_ss_chain (se); gfc_advance_se_ss_chain (se);
} }
else else
{ gfc_conv_intrinsic_transfer (se, expr);
/* Ensure double transfer through LOGICAL preserves all
the needed bits. */
gfc_expr *source = expr->value.function.actual->expr;
if (source->expr_type == EXPR_FUNCTION
&& source->value.function.esym == NULL
&& source->value.function.isym != NULL
&& source->value.function.isym->id == GFC_ISYM_TRANSFER
&& source->ts.type == BT_LOGICAL
&& expr->ts.type != source->ts.type)
source->value.function.name = "__transfer_in_transfer";
if (se->ss)
gfc_conv_intrinsic_array_transfer (se, expr);
else
gfc_conv_intrinsic_transfer (se, expr);
}
break; break;
case GFC_ISYM_TTYNAM: case GFC_ISYM_TTYNAM:
......
2009-01-17 Paul Thomas <pault@gcc.gnu.org> 2009-01-17 Paul Thomas <pault@gcc.gnu.org>
PR fortran/34955
* gfortran.dg/transfer_intrinsic_1.f90: New test.
* gfortran.dg/transfer_intrinsic_2.f90: New test.
2009-01-17 Paul Thomas <pault@gcc.gnu.org>
PR fortran/38657 PR fortran/38657
* gfortran.dg/module_commons_3.f90: Remove * gfortran.dg/module_commons_3.f90: Remove
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
return return
end function Upper end function Upper
end end
! The sign that all is well is that [S.5][1] appears twice. ! The sign that all is well is that [S.6][1] appears twice.
! Platform dependent variations are [S$5][1], [__S_5][1], [S___5][1] ! Platform dependent variations are [S$6][1], [__S_6][1], [S___6][1]
! { dg-final { scan-tree-dump-times "5\\\]\\\[1\\\]" 2 "original" } } ! { dg-final { scan-tree-dump-times "6\\\]\\\[1\\\]" 2 "original" } }
! { dg-final { cleanup-tree-dump "original" } } ! { dg-final { cleanup-tree-dump "original" } }
! { dg-do compile }
! { dg-options "-fdump-tree-original" }
!
! Check the fix for PR34955 in which three bytes would be copied
! from bytes by TRANSFER, instead of the required two.
!
! Contributed by Tobias Burnus <burnus@gcc.gnu.org>
!
subroutine BytesToString(bytes, string)
type ByteType
integer(kind=1) :: singleByte
end type
type (ByteType) :: bytes(2)
character(len=*) :: string
string = transfer(bytes, string)
end subroutine
! { dg-final { scan-tree-dump-times "MIN_EXPR" 1 "original" } }
! { dg-final { cleanup-tree-dump "original" } }
! { dg-do run }
!
! Check the fix for PR34955 in which three bytes would be copied
! from bytes by TRANSFER, instead of the required two and the
! resulting string length would be incorrect.
!
! Contributed by Dominique Dhumieres <dominiq@lps.ens.fr>
!
character(len = 1) :: string = "z"
character(len = 20) :: tmp = ""
tmp = Upper ("abcdefgh")
if (trim(tmp) .ne. "ab") call abort ()
contains
Character (len = 20) Function Upper (string)
Character(len = *) string
integer :: ij
i = size (transfer (string,"xy",len (string)))
if (i /= len (string)) call abort ()
Upper = ""
Upper(1:2) = &
transfer (merge (transfer (string,"xy",len (string)), &
string(1:2), .true.), "xy")
return
end function Upper
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment