Bug 41714

Summary: [OOP] ALLOCATE SOURCE= does not properly copy the value from SOURCE
Product: gcc Reporter: Tobias Burnus <burnus>
Component: fortranAssignee: janus
Status: RESOLVED FIXED    
Severity: normal CC: gcc-bugs, janus
Priority: P3 Keywords: wrong-code
Version: 4.5.0   
Target Milestone: 4.5.0   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2009-10-15 13:14:36

Description Tobias Burnus 2009-10-15 12:31:27 UTC
The following program should print "1", "2". It does so with ifort but with gfortran it prints "1", "0".

type t
  integer :: i
end type t
type, extends(t) :: t2
  integer :: j
end type t2

class(t), allocatable :: a
allocate(a, source=t2(1,2))
print *,a%i
if(a%i /= 1) call abort()
select type (a)
  type is (t2)
     print *,a%j
     if(a%j /= 2) call abort()
end select
end


The dump shows that the type is wrong for the assignment:

  {
    struct t2 D.1377;
    struct t2 t2.0;

    t2.0.t.i = 1;
    t2.0.j = 2;
    D.1377 = t2.0;
    *a.$data = VIEW_CONVERT_EXPR<struct t>(D.1377);
  }
Comment 1 janus 2009-10-15 13:14:35 UTC
Certainly mine. I should have thought of this case when fixing PR41581. The cure is for sure:

Index: gcc/fortran/trans-stmt.c
===================================================================
--- gcc/fortran/trans-stmt.c    (Revision 152720)
+++ gcc/fortran/trans-stmt.c    (Arbeitskopie)
@@ -4091,6 +4091,18 @@ gfc_trans_allocate (gfc_code * code)
              gfc_free_expr (sz);
              tmp = gfc_build_memcpy_call (dst.expr, src.expr, len.expr);
            }
+         else if (al->expr->ts.type == BT_CLASS
+                  && rhs->ts.u.derived != expr->ts.u.derived)
+           {
+             gfc_se dst,src;
+             gfc_init_se (&dst, NULL);
+             gfc_init_se (&src, NULL);
+             gfc_conv_expr (&dst, expr);
+             gfc_conv_expr (&src, rhs);
+             gfc_add_block_to_block (&block, &src.pre);
+             tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&rhs->ts));
+             tmp = gfc_build_memcpy_call (dst.expr, src.expr, tmp);
+           }
          else
            tmp = gfc_trans_assignment (gfc_expr_to_initialize (expr),
                                        rhs, false);
Comment 2 janus 2009-10-15 20:27:26 UTC
Problem: The patch in comment #1 regresses on class_allocate_1.f03:

gfortran-4.5 class_allocate_1.f03 -O1
class_allocate_1.f03: In function ‘MAIN__’:
class_allocate_1.f03:57:0: internal compiler error: in
tree_annotate_all_with_location, at gimplify.c:892

Comment 3 janus 2009-10-16 16:22:38 UTC
(In reply to comment #2)
> Problem: The patch in comment #1 regresses on class_allocate_1.f03:

In addition to this there are two more test cases failing:

Native configuration is x86_64-unknown-linux-gnu

		=== gfortran tests ===

Schedule of variations:
    unix

Running target unix
Using /usr/share/dejagnu/baseboards/unix.exp as board description file for target.
Using /usr/share/dejagnu/config/unix.exp as generic interface file for target.
Using /home/jweil/gcc45/trunk/gcc/testsuite/config/default.exp as tool-and-target-specific interface file.
Running /home/jweil/gcc45/trunk/gcc/testsuite/gfortran.dg/debug/debug.exp ...
Running /home/jweil/gcc45/trunk/gcc/testsuite/gfortran.dg/dg.exp ...
FAIL: gfortran.dg/class_allocate_1.f03  -O1  (internal compiler error)
FAIL: gfortran.dg/class_allocate_1.f03  -O1  (test for excess errors)
FAIL: gfortran.dg/class_allocate_1.f03  -O2  (internal compiler error)
FAIL: gfortran.dg/class_allocate_1.f03  -O2  (test for excess errors)
FAIL: gfortran.dg/class_allocate_1.f03  -O3 -fomit-frame-pointer  (internal compiler error)
FAIL: gfortran.dg/class_allocate_1.f03  -O3 -fomit-frame-pointer  (test for excess errors)
FAIL: gfortran.dg/class_allocate_1.f03  -O3 -fomit-frame-pointer -funroll-loops  (internal compiler error)
FAIL: gfortran.dg/class_allocate_1.f03  -O3 -fomit-frame-pointer -funroll-loops  (test for excess errors)
FAIL: gfortran.dg/class_allocate_1.f03  -O3 -fomit-frame-pointer -funroll-all-loops -finline-functions  (internal compiler error)
FAIL: gfortran.dg/class_allocate_1.f03  -O3 -fomit-frame-pointer -funroll-all-loops -finline-functions  (test for excess errors)
FAIL: gfortran.dg/class_allocate_1.f03  -O3 -g  (internal compiler error)
FAIL: gfortran.dg/class_allocate_1.f03  -O3 -g  (test for excess errors)
FAIL: gfortran.dg/class_allocate_1.f03  -Os  (internal compiler error)
FAIL: gfortran.dg/class_allocate_1.f03  -Os  (test for excess errors)
FAIL: gfortran.dg/dynamic_dispatch_4.f03  -O0  (test for excess errors)
FAIL: gfortran.dg/dynamic_dispatch_4.f03  -O1  (test for excess errors)
FAIL: gfortran.dg/dynamic_dispatch_4.f03  -O2  (test for excess errors)
FAIL: gfortran.dg/dynamic_dispatch_4.f03  -O3 -fomit-frame-pointer  (test for excess errors)
FAIL: gfortran.dg/dynamic_dispatch_4.f03  -O3 -fomit-frame-pointer -funroll-loops  (test for excess errors)
FAIL: gfortran.dg/dynamic_dispatch_4.f03  -O3 -fomit-frame-pointer -funroll-all-loops -finline-functions  (test for excess errors)
FAIL: gfortran.dg/dynamic_dispatch_4.f03  -O3 -g  (test for excess errors)
FAIL: gfortran.dg/dynamic_dispatch_4.f03  -Os  (test for excess errors)
FAIL: gfortran.dg/dynamic_dispatch_5.f03  -O  (test for excess errors)
Running /home/jweil/gcc45/trunk/gcc/testsuite/gfortran.dg/gomp/gomp.exp ...
Running /home/jweil/gcc45/trunk/gcc/testsuite/gfortran.dg/graphite/graphite.exp ...
Running /home/jweil/gcc45/trunk/gcc/testsuite/gfortran.dg/guality/guality.exp ...
Running /home/jweil/gcc45/trunk/gcc/testsuite/gfortran.dg/lto/lto.exp ...
Running /home/jweil/gcc45/trunk/gcc/testsuite/gfortran.dg/vect/vect.exp ...
Running /home/jweil/gcc45/trunk/gcc/testsuite/gfortran.fortran-torture/compile/compile.exp ...
Running /home/jweil/gcc45/trunk/gcc/testsuite/gfortran.fortran-torture/execute/execute.exp ...

		=== gfortran Summary ===

# of expected passes		32786
# of unexpected failures	23
# of expected failures		30
# of unresolved testcases	15
# of unsupported tests		60
/home/jweil/gcc45/build/gcc/testsuite/gfortran/../../gfortran  version 4.5.0 20091015 (experimental) [trunk revision 152844] (GCC) 
Comment 4 janus 2009-10-16 21:25:47 UTC
(In reply to comment #3)
> In addition to this there are two more test cases failing:

Sorry, these were fake (my local source tree was messed up). The only real failure is class_allocate_1.f03, from which one can extract a reduced test case:

 implicit none

 type t1
   integer :: a
 end type

 type, extends(t1) :: t2
   integer :: b
 end type

 class(t1),pointer :: cp
 type(t2) :: x

 allocate(cp, source = x)

end


which gives the same error at -O1 and above:

internal compiler error: in tree_annotate_all_with_location, at gimplify.c:892

Comment 5 janus 2009-10-25 10:24:08 UTC
(In reply to comment #4)
> internal compiler error: in tree_annotate_all_with_location, at gimplify.c:892

This goes away with the following patchlet:

Index: gcc/fortran/trans-expr.c
===================================================================
--- gcc/fortran/trans-expr.c	(Revision 153538)
+++ gcc/fortran/trans-expr.c	(Arbeitskopie)
@@ -4888,7 +4888,10 @@ gfc_build_memcpy_call (tree dst, tree src, tree le
   /* Construct call to __builtin_memcpy.  */
   tmp = build_call_expr_loc (input_location,
 			 built_in_decls[BUILT_IN_MEMCPY], 3, dst, src, len);
-  return fold_convert (void_type_node, tmp);
+  if (TREE_CODE (tmp) == NOP_EXPR)
+    return tmp;
+  else
+    return fold_convert (void_type_node, tmp);
 }


The source of the problem was that the memcpy call

  (void) __builtin_memcpy ((void *) cp.$data, (void *) &x, 8);

is being replaced at -O1 by:

  (*(struct t2 * {ref-all}) SAVE_EXPR <cp.$data> = x;, (void *) SAVE_EXPR <cp.$data>;);

which 'gfc_build_memcpy_call' was not able to cope with. I.e. the 'fold_convert' would produce an COMPOUND_EXPR, which later on would trigger the error in 'tree_annotate_all_with_location'.
Comment 6 Dominique d'Humieres 2009-10-25 13:55:45 UTC
The patches in comment #1 and #5 seem to work as advertized (currently regtesting).

After having looked at the f2003 standard draft, I understand that

allocate(a, source=t2(1,2))

is equivalent to

allocate(t2::a)
a%i=1
a%j=2

With this change the compilation fails with:

pr41714_db.f90:12.3:

a%j=2
   1
Error: 'j' at (1) is not a member of the 't' structure

Did I missed something in the standard or is this a bug?
Comment 7 Dominique d'Humieres 2009-10-25 17:20:24 UTC
(In reply to comment #6)
> Did I missed something in the standard or is this a bug?

Probably the former!-(If I move

a%j=2

inside the "type is (t2)" block, the code compiles without error).
Comment 8 janus 2009-10-26 09:08:19 UTC
Subject: Bug 41714

Author: janus
Date: Mon Oct 26 09:08:03 2009
New Revision: 153547

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=153547
Log:
2009-10-26  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/41714
	* gimple.h (tree_annotate_all_with_location): Remove prototype.
	* gimplify.c (tree_should_carry_location_p,
	tree_annotate_one_with_location,tree_annotate_all_with_location):
	Remove obsolete functions.


2009-10-26  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/41714
	* trans.c (gfc_trans_code): Remove call to
	'tree_annotate_all_with_location'. Location should already be set.
	* trans-openmp.c (gfc_trans_omp_workshare): Ditto.
	* trans-stmt.c (gfc_trans_allocate): Do correct data initialization for
	CLASS variables with SOURCE tag, plus some cleanup.


2009-10-26  Janus Weil  <janus@gcc.gnu.org>

	PR fortran/41714
	* gfortran.dg/class_allocate_4.f03: New test.

Added:
    trunk/gcc/testsuite/gfortran.dg/class_allocate_4.f03
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/fortran/ChangeLog
    trunk/gcc/fortran/trans-openmp.c
    trunk/gcc/fortran/trans-stmt.c
    trunk/gcc/fortran/trans.c
    trunk/gcc/gimple.h
    trunk/gcc/gimplify.c
    trunk/gcc/testsuite/ChangeLog

Comment 9 janus 2009-10-26 09:13:06 UTC
Fixed with r153547. Closing.