+2015-10-18 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/67177
+ PR fortran/67977
+ * primary.c (match_substring): Add an argument 'deferred' to
+ flag that a substring reference with null start and end should
+ not be optimized away for deferred length strings.
+ (match_string_constant, gfc_match_rvalue): Set the argument.
+ * trans-expr.c (alloc_scalar_allocatable_for_assignment): If
+ there is a substring reference return.
+ * trans-intrinsic.c (conv_intrinsic_move_alloc): For deferred
+ characters, assign the 'from' string length to the 'to' string
+ length. If the 'from' expression is deferred, set its string
+ length to zero. If the 'to' expression has allocatable
+ components, deallocate them.
+
2015-10-17 Steven G. Kargl <kargl@gcc.gnu.org>
PR fortran/67987
* decl.c (char_len_param_value): Unwrap unlong line. If LEN < 0,
- force it to zero per the Fortran 90, 95, 2003, and 2008 Standards.
+ force it to zero per the Fortran 90, 95, 2003, and 2008 Standards.
* resolve.c (gfc_resolve_substring_charlen): Unwrap unlong line.
If 'start' is larger than 'end', length of substring is negative,
so explicitly set it to zero.
{
if (*p == '.')
continue;
-
+
if (*p != '0')
{
*p = '0';
/* Match a substring reference. */
static match
-match_substring (gfc_charlen *cl, int init, gfc_ref **result)
+match_substring (gfc_charlen *cl, int init, gfc_ref **result, bool deferred)
{
gfc_expr *start, *end;
locus old_loc;
}
/* Optimize away the (:) reference. */
- if (start == NULL && end == NULL)
+ if (start == NULL && end == NULL && !deferred)
ref = NULL;
else
{
if (ret != -1)
gfc_internal_error ("match_string_constant(): Delimiter not found");
- if (match_substring (NULL, 0, &e->ref) != MATCH_NO)
+ if (match_substring (NULL, 0, &e->ref, false) != MATCH_NO)
e->expr_type = EXPR_SUBSTRING;
*result = e;
if (primary->ts.type == BT_CHARACTER)
{
- switch (match_substring (primary->ts.u.cl, equiv_flag, &substring))
+ bool def = primary->ts.deferred == 1;
+ switch (match_substring (primary->ts.u.cl, equiv_flag, &substring, def))
{
case MATCH_YES:
if (tail == NULL)
that we're not sure is a variable yet. */
if ((implicit_char || sym->ts.type == BT_CHARACTER)
- && match_substring (sym->ts.u.cl, 0, &e->ref) == MATCH_YES)
+ && match_substring (sym->ts.u.cl, 0, &e->ref, false) == MATCH_YES)
{
e->expr_type = EXPR_VARIABLE;
tree jump_label1;
tree jump_label2;
gfc_se lse;
+ gfc_ref *ref;
if (!expr1 || expr1->rank)
return;
if (!expr2 || expr2->rank)
return;
+ for (ref = expr1->ref; ref; ref = ref->next)
+ if (ref->type == REF_SUBSTRING)
+ return;
+
realloc_lhs_warning (expr2->ts.type, false, &expr2->where);
/* Since this is a scalar lhs, we can afford to do this. That is,
}
}
+ if (to_expr->ts.type == BT_CHARACTER && to_expr->ts.deferred)
+ {
+ gfc_add_modify_loc (input_location, &block, to_se.string_length,
+ fold_convert (TREE_TYPE (to_se.string_length),
+ from_se.string_length));
+ if (from_expr->ts.deferred)
+ gfc_add_modify_loc (input_location, &block, from_se.string_length,
+ build_int_cst (TREE_TYPE (from_se.string_length), 0));
+ }
+
return gfc_finish_block (&block);
}
}
else
{
+ if (to_expr->ts.type == BT_DERIVED
+ && to_expr->ts.u.derived->attr.alloc_comp)
+ {
+ tmp = gfc_deallocate_alloc_comp (to_expr->ts.u.derived,
+ to_se.expr, to_expr->rank);
+ gfc_add_expr_to_block (&block, tmp);
+ }
+
tmp = gfc_conv_descriptor_data_get (to_se.expr);
tmp = gfc_deallocate_with_status (tmp, NULL_TREE, NULL_TREE, NULL_TREE,
NULL_TREE, true, to_expr, false);
gfc_add_modify_loc (input_location, &block, tmp,
fold_convert (TREE_TYPE (tmp), null_pointer_node));
+
+ if (to_expr->ts.type == BT_CHARACTER && to_expr->ts.deferred)
+ {
+ gfc_add_modify_loc (input_location, &block, to_se.string_length,
+ fold_convert (TREE_TYPE (to_se.string_length),
+ from_se.string_length));
+ if (from_expr->ts.deferred)
+ gfc_add_modify_loc (input_location, &block, from_se.string_length,
+ build_int_cst (TREE_TYPE (from_se.string_length), 0));
+ }
+
return gfc_finish_block (&block);
}
+2015-10-18 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/67177
+ * gfortran.dg/move_alloc_15.f90: New test
+ * gfortran.dg/move_alloc_16.f90: New test
+
+ PR fortran/67977
+ * gfortran.dg/deferred_character_assignment_1.f90: New test
+
2015-10-17 Steven G. Kargl <kargl@gcc.gnu.org>
PR fortran/67987
--- /dev/null
+! { dg-do run }
+!
+! Checks the fix for PR67977 in which automatic reallocation on assignment
+! was performed when the lhs had a substring reference.
+!
+! Contributed by Anton Shterenlikht <mexas@bristol.ac.uk>
+!
+ character(:), allocatable :: z
+ integer :: length
+ z = "cockatoo"
+ length = len (z)
+ z(:) = ''
+ if (len(z) .ne. length) call abort
+ if (trim (z) .ne. '') call abort
+ z(:3) = "foo"
+ if (len(z) .ne. length) call abort
+ if (trim (z) .ne. "foo") call abort
+ z(4:) = "__bar"
+ if (len(z) .ne. length) call abort
+ if (trim (z) .ne. "foo__bar") call abort
+ deallocate (z)
+end
--- /dev/null
+! { dg-do run }
+! { dg-options "-fdump-tree-original" }
+!
+! Fix for PR......
+!
+! The 'to' components of 'mytemp' would remain allocated after the call to
+! MOVE_ALLOC, resulting in memory leaks.
+!
+! Contributed by Alberto Luaces.
+!
+! See https://groups.google.com/forum/#!topic/comp.lang.fortran/k3bkKUbOpFU
+!
+module alloctest
+ type myallocatable
+ integer, allocatable:: i(:)
+ end type myallocatable
+
+contains
+ subroutine f(num, array)
+ implicit none
+ integer, intent(in) :: num
+ integer :: i
+ type(myallocatable):: array(:)
+
+ do i = 1, num
+ allocate(array(i)%i(5), source = [1,2,3,4,5])
+ end do
+
+ end subroutine f
+end module alloctest
+
+program name
+ use alloctest
+ implicit none
+ type(myallocatable), allocatable:: myarray(:), mytemp(:)
+ integer, parameter:: OLDSIZE = 7, NEWSIZE = 20
+ logical :: flag
+
+ allocate(myarray(OLDSIZE))
+ call f(size(myarray), myarray)
+
+ allocate(mytemp(NEWSIZE))
+ mytemp(1:OLDSIZE) = myarray
+
+ flag = .false.
+ call foo
+ call bar
+
+ deallocate(myarray)
+ if (allocated (mytemp)) deallocate (mytemp)
+
+ allocate(myarray(OLDSIZE))
+ call f(size(myarray), myarray)
+
+ allocate(mytemp(NEWSIZE))
+ mytemp(1:OLDSIZE) = myarray
+
+! Verfify that there is no segfault if the allocatable components
+! are deallocated before the call to move_alloc
+ flag = .true.
+ call foo
+ call bar
+
+ deallocate(myarray)
+contains
+ subroutine foo
+ integer :: i
+ if (flag) then
+ do i = 1, OLDSIZE
+ deallocate (mytemp(i)%i)
+ end do
+ end if
+ call move_alloc(mytemp, myarray)
+ end subroutine
+
+ subroutine bar
+ integer :: i
+ do i = 1, OLDSIZE
+ if (.not.flag .and. allocated (myarray(i)%i)) then
+ if (any (myarray(i)%i .ne. [1,2,3,4,5])) call abort
+ else
+ if (.not.flag) call abort
+ end if
+ end do
+ end subroutine
+end program name
+! { dg-final { scan-tree-dump-times "__builtin_malloc" 11 "original" } }
+! { dg-final { scan-tree-dump-times "__builtin_free" 11 "original" } }
--- /dev/null
+! { dg-do run }
+!
+! Tests the fix for PR67177 in which MOVE_ALLOC was not assigning the string
+! length for deferred length characters.
+!
+! Contributed by <templed@tcd.ie>
+!
+program str
+ implicit none
+
+ type string
+ character(:), Allocatable :: text
+ end type string
+
+ type strings
+ type(string), allocatable, dimension(:) :: strlist
+ end type strings
+
+ type(strings) :: teststrs
+ type(string) :: tmpstr
+ integer :: strlen = 20
+
+ allocate (teststrs%strlist(1))
+ allocate (character(len=strlen) :: tmpstr%text)
+
+ allocate (character(len=strlen) :: teststrs%strlist(1)%text)
+
+! Full string reference was required because reallocation on assignment is
+! functioning when it should not if the lhs is a substring - PR67977
+ tmpstr%text(1:3) = 'foo'
+
+ if (.not.allocated (teststrs%strlist(1)%text)) call abort
+ if (len (tmpstr%text) .ne. strlen) call abort
+
+ call move_alloc(tmpstr%text,teststrs%strlist(1)%text)
+
+ if (.not.allocated (teststrs%strlist(1)%text)) call abort
+ if (len (teststrs%strlist(1)%text) .ne. strlen) call abort
+ if (trim (teststrs%strlist(1)%text(1:3)) .ne. 'foo') call abort
+
+! Clean up so that valgrind reports all allocated memory freed.
+ if (allocated (teststrs%strlist(1)%text)) deallocate (teststrs%strlist(1)%text)
+ if (allocated (teststrs%strlist)) deallocate (teststrs%strlist)
+end program str