[PATCH] Avoid sharing ts.cl if ts.cl->length == NULL
Jakub Jelinek
jakub@redhat.com
Fri Aug 17 17:13:00 GMT 2007
Hi!
The attached testcase is miscompiled by gfortran 4.1.x and 4.2.x.
While it works with 4.3.x, I still see incorrect ts.cl on EXPR_ARRAY etc.
The problem is that ts.cl struct is shared among all variables
declared on the same line, in this case
character(*), intent(in) :: bar1, bar2
While trans-decl.c (create_function_arglist) unshares them for the dummy
arguments, at that point it is too late. Between variable_decl and
create_function_arglist bar2's ts has been copied over to many other
expressions (e.g. EXPR_ARRAY) and while bar2's ts is changed afterwards,
all the expressions still share ts.cl with bar1. And
create_function_arglist sets f->sym->ts.cl->backend_decl to _bar1
argument and so anything that uses EXPR_ARRAY's etc. ts.cl->backend_decl
will use wrong length (_bar1 instead of _bar2).
Tested on 4.2/x86_64-linux and 4.3/x86_64-linux (the patch below is 4.2
version, there are whitespace differences in the trunk patch).
Ok for 4.1/4.2/trunk?
2007-08-17 Jakub Jelinek <jakub@redhat.com>
* decl.c (variable_decl): Don't share charlen structs if
length == NULL.
* trans-decl.c (create_function_arglist): Assert
f->sym->ts.cl->backend_decl is NULL instead of unsharing
charlen struct here.
* gfortran.dg/assumed_charlen_sharing.f90: New test.
--- gcc/fortran/decl.c.jj 2007-03-20 00:22:06.000000000 +0100
+++ gcc/fortran/decl.c 2007-08-17 15:51:25.000000000 +0200
@@ -1139,10 +1139,11 @@ variable_decl (int elem)
break;
/* Non-constant lengths need to be copied after the first
- element. */
+ element. Also copy assumed lengths. */
case MATCH_NO:
- if (elem > 1 && current_ts.cl->length
- && current_ts.cl->length->expr_type != EXPR_CONSTANT)
+ if (elem > 1
+ && (current_ts.cl->length == NULL
+ || current_ts.cl->length->expr_type != EXPR_CONSTANT))
{
cl = gfc_get_charlen ();
cl->next = gfc_current_ns->cl_list;
--- gcc/fortran/trans-decl.c.jj 2007-03-02 09:27:51.000000000 +0100
+++ gcc/fortran/trans-decl.c 2007-08-17 16:16:47.000000000 +0200
@@ -1428,25 +1428,8 @@ create_function_arglist (gfc_symbol * sy
if (!f->sym->ts.cl->length)
{
TREE_USED (length) = 1;
- if (!f->sym->ts.cl->backend_decl)
- f->sym->ts.cl->backend_decl = length;
- else
- {
- /* there is already another variable using this
- gfc_charlen node, build a new one for this variable
- and chain it into the list of gfc_charlens.
- This happens for e.g. in the case
- CHARACTER(*)::c1,c2
- since CHARACTER declarations on the same line share
- the same gfc_charlen node. */
- gfc_charlen *cl;
-
- cl = gfc_get_charlen ();
- cl->backend_decl = length;
- cl->next = f->sym->ts.cl->next;
- f->sym->ts.cl->next = cl;
- f->sym->ts.cl = cl;
- }
+ gcc_assert (!f->sym->ts.cl->backend_decl);
+ f->sym->ts.cl->backend_decl = length;
}
hidden_typelist = TREE_CHAIN (hidden_typelist);
--- gcc/testsuite/gfortran.dg/assumed_charlen_sharing.f90.jj 2007-08-17 16:20:56.000000000 +0200
+++ gcc/testsuite/gfortran.dg/assumed_charlen_sharing.f90 2007-08-17 16:23:24.000000000 +0200
@@ -0,0 +1,29 @@
+! This testcase was miscompiled, because ts.cl
+! in function bar was initially shared between both
+! dummy arguments. Although it was later unshared,
+! all expressions which copied ts.cl from bar2
+! before that used incorrectly bar1's length
+! instead of bar2.
+! { dg-do run }
+
+subroutine foo (foo1, foo2)
+ implicit none
+ integer, intent(in) :: foo2
+ character(*), intent(in) :: foo1(foo2)
+end subroutine foo
+
+subroutine bar (bar1, bar2)
+ implicit none
+ character(*), intent(in) :: bar1, bar2
+
+ call foo ((/ bar2 /), 1)
+end subroutine bar
+
+program test
+ character(80) :: str1
+ character(5) :: str2
+
+ str1 = 'String'
+ str2 = 'Strng'
+ call bar (str2, str1)
+end program test
Jakub
More information about the Fortran
mailing list