From bfa204b8b474475379cf40f066c25f63ab43d5f1 Mon Sep 17 00:00:00 2001
From: Paul Thomas <pault@gcc.gnu.org>
Date: Wed, 18 Jan 2012 20:52:48 +0000
Subject: [PATCH] re PR fortran/51634 ([OOP] ICE with polymorphic operators)

2012-01-18  Paul Thomas  <pault@gcc.gnu.org>

	PR fortran/51634
	* trans-expr.c (gfc_conv_procedure_call): Deallocate allocatable
	components of temporary class arguments.

2012-01-18  Paul Thomas  <pault@gcc.gnu.org>

	PR fortran/51634
	* gfortran.dg/typebound_operator_12.f03: New.
	* gfortran.dg/typebound_operator_13.f03: New.

From-SVN: r183287
---
 gcc/fortran/ChangeLog                         |  6 ++
 gcc/fortran/trans-expr.c                      | 12 +++-
 gcc/testsuite/ChangeLog                       |  6 ++
 .../gfortran.dg/typebound_operator_12.f03     | 45 ++++++++++++++
 .../gfortran.dg/typebound_operator_13.f03     | 59 +++++++++++++++++++
 5 files changed, 127 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gfortran.dg/typebound_operator_12.f03
 create mode 100644 gcc/testsuite/gfortran.dg/typebound_operator_13.f03

diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index cbe12fada7ac..db01c0cfbe23 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,9 @@
+2012-01-18  Paul Thomas  <pault@gcc.gnu.org>
+
+	PR fortran/51634
+	* trans-expr.c (gfc_conv_procedure_call): Deallocate allocatable
+	components of temporary class arguments.
+
 2012-01-17  Tobias Burnus  <burnus@net-b.de>
 	    Janne Blomqvist  <jb@gcc.gnu.org>
 
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index b41935add47e..15b6797c12b9 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -3736,7 +3736,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
       /* Allocated allocatable components of derived types must be
 	 deallocated for non-variable scalars.  Non-variable arrays are
 	 dealt with in trans-array.c(gfc_conv_array_parameter).  */
-      if (e && e->ts.type == BT_DERIVED
+      if (e && (e->ts.type == BT_DERIVED || e->ts.type == BT_CLASS)
 	    && e->ts.u.derived->attr.alloc_comp
 	    && !(e->symtree && e->symtree->n.sym->attr.pointer)
 	    && (e->expr_type != EXPR_VARIABLE && !e->rank))
@@ -3768,6 +3768,16 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 	      gfc_add_expr_to_block (&se->post, local_tmp);
 	    }
 
+	  if (e->ts.type == BT_DERIVED && fsym && fsym->ts.type == BT_CLASS)
+	    {
+	      /* The derived type is passed to gfc_deallocate_alloc_comp.
+		 Therefore, class actuals can handled correctly but derived
+		 types passed to class formals need the _data component.  */
+	      tmp = gfc_class_data_get (tmp);
+	      if (!CLASS_DATA (fsym)->attr.dimension)
+		tmp = build_fold_indirect_ref_loc (input_location, tmp);
+	    }
+
 	  tmp = gfc_deallocate_alloc_comp (e->ts.u.derived, tmp, parm_rank);
 
 	  gfc_add_expr_to_block (&se->post, tmp);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index e79f00b58aca..1d982ecebe9c 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2012-01-18  Paul Thomas  <pault@gcc.gnu.org>
+
+	PR fortran/51634
+	* gfortran.dg/typebound_operator_12.f03: New.
+	* gfortran.dg/typebound_operator_13.f03: New.
+
 2012-01-18  Paolo Carlini  <paolo.carlini@oracle.com>
 
 	PR c++/51225
diff --git a/gcc/testsuite/gfortran.dg/typebound_operator_12.f03 b/gcc/testsuite/gfortran.dg/typebound_operator_12.f03
new file mode 100644
index 000000000000..3496ed38639d
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/typebound_operator_12.f03
@@ -0,0 +1,45 @@
+! { dg-do run }
+! PR51634 - Handle allocatable components correctly in expressions 
+! involving typebound operators. See comment 2 of PR.
+!
+! Reported by Tobias Burnus  <burnus@gcc.gnu.org>
+! 
+module soop_stars_class
+  implicit none
+  type soop_stars
+    real, dimension(:), allocatable :: position,velocity
+  contains
+    procedure :: total
+    procedure :: product
+    generic :: operator(+) => total
+    generic :: operator(*) => product
+  end type
+contains
+  type(soop_stars) function product(lhs,rhs)
+    class(soop_stars) ,intent(in) :: lhs
+    real ,intent(in) :: rhs
+    product%position = lhs%position*rhs
+    product%velocity = lhs%velocity*rhs
+  end function
+
+  type(soop_stars) function total(lhs,rhs)
+    class(soop_stars) ,intent(in) :: lhs,rhs
+    total%position = lhs%position + rhs%position
+    total%velocity = lhs%velocity + rhs%velocity
+  end function
+end module
+
+program main
+  use soop_stars_class ,only : soop_stars
+  implicit none
+  type(soop_stars) :: fireworks
+  real :: dt
+  fireworks%position = [1,2,3]
+  fireworks%velocity = [4,5,6]
+  dt = 5
+  fireworks = fireworks + fireworks*dt
+  if (any (fireworks%position .ne. [6, 12, 18])) call abort
+  if (any (fireworks%velocity .ne. [24, 30, 36])) call abort
+end program
+! { dg-final { cleanup-modules "soop_stars_class" } }
+
diff --git a/gcc/testsuite/gfortran.dg/typebound_operator_13.f03 b/gcc/testsuite/gfortran.dg/typebound_operator_13.f03
new file mode 100644
index 000000000000..e1371c8a8178
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/typebound_operator_13.f03
@@ -0,0 +1,59 @@
+! { dg-do run }
+! PR51634 - Handle allocatable components correctly in expressions 
+! involving typebound operators. From comment 2 of PR but using
+! classes throughout.
+!
+! Reported by Tobias Burnus  <burnus@gcc.gnu.org>
+! 
+module soop_stars_class
+  implicit none
+  type soop_stars
+    real, dimension(:), allocatable :: position,velocity
+  contains
+    procedure :: total
+    procedure :: mult
+    procedure :: assign
+    generic :: operator(+) => total
+    generic :: operator(*) => mult
+    generic :: assignment(=) => assign
+  end type
+contains
+  function mult(lhs,rhs)
+    class(soop_stars) ,intent(in) :: lhs
+    real ,intent(in) :: rhs
+    class(soop_stars), allocatable :: mult
+    type(soop_stars) :: tmp
+    tmp = soop_stars (lhs%position*rhs, lhs%velocity*rhs)
+    allocate (mult, source = tmp)
+  end function
+
+  function total(lhs,rhs)
+    class(soop_stars) ,intent(in) :: lhs,rhs
+    class(soop_stars), allocatable :: total
+    type(soop_stars) :: tmp
+    tmp = soop_stars (lhs%position + rhs%position, &
+                      lhs%velocity + rhs%velocity)
+    allocate (total, source = tmp)
+  end function
+
+  subroutine assign(lhs,rhs)
+    class(soop_stars), intent(in) :: rhs
+    class(soop_stars), intent(out) :: lhs
+    lhs%position = rhs%position
+    lhs%velocity = rhs%velocity
+  end subroutine
+end module
+
+program main
+  use soop_stars_class ,only : soop_stars
+  implicit none
+  class(soop_stars), allocatable :: fireworks
+  real :: dt
+  allocate (fireworks, source = soop_stars ([1,2,3], [4,5,6]))
+  dt = 5
+  fireworks = fireworks + fireworks*dt
+  if (any (fireworks%position .ne. [6, 12, 18])) call abort
+  if (any (fireworks%velocity .ne. [24, 30, 36])) call abort
+end program
+! { dg-final { cleanup-modules "soop_stars_class" } }
+
-- 
GitLab