summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/fortran/ChangeLog10
-rw-r--r--gcc/fortran/trans-expr.c37
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gfortran.dg/class_64.f9038
4 files changed, 87 insertions, 4 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 41215a88338..0c25ce212f7 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,13 @@
+2017-11-01 Paul Thomas <pault@gcc.gnu.org>
+
+ Backport from trunk
+ PR fortran/80850
+ * trans_expr.c (gfc_conv_procedure_call): When passing a class
+ argument to an unlimited polymorphic dummy, it is wrong to cast
+ the passed expression as unlimited, unless it is unlimited. The
+ correct way is to assign to each of the fields and set the _len
+ field to zero.
+
2017-10-28 Andre Vehreschild <vehre@gcc.gnu.org>
* check.c (gfc_check_co_reduce): Clarify error message.
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index 36046deb010..fa04ed45419 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -5173,10 +5173,39 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
}
else
{
- gfc_add_modify (&parmse.pre, var,
- fold_build1_loc (input_location,
- VIEW_CONVERT_EXPR,
- type, parmse.expr));
+ /* Since the internal representation of unlimited
+ polymorphic expressions includes an extra field
+ that other class objects do not, a cast to the
+ formal type does not work. */
+ if (!UNLIMITED_POLY (e) && UNLIMITED_POLY (fsym))
+ {
+ tree efield;
+
+ /* Set the _data field. */
+ tmp = gfc_class_data_get (var);
+ efield = fold_convert (TREE_TYPE (tmp),
+ gfc_class_data_get (parmse.expr));
+ gfc_add_modify (&parmse.pre, tmp, efield);
+
+ /* Set the _vptr field. */
+ tmp = gfc_class_vptr_get (var);
+ efield = fold_convert (TREE_TYPE (tmp),
+ gfc_class_vptr_get (parmse.expr));
+ gfc_add_modify (&parmse.pre, tmp, efield);
+
+ /* Set the _len field. */
+ tmp = gfc_class_len_get (var);
+ gfc_add_modify (&parmse.pre, tmp,
+ build_int_cst (TREE_TYPE (tmp), 0));
+ }
+ else
+ {
+ tmp = fold_build1_loc (input_location,
+ VIEW_CONVERT_EXPR,
+ type, parmse.expr);
+ gfc_add_modify (&parmse.pre, var, tmp);
+ ;
+ }
parmse.expr = gfc_build_addr_expr (NULL_TREE, var);
}
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index cf1fb72082b..8057858d771 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2017-11-01 Paul Thomas <pault@gcc.gnu.org>
+
+ Backported from trunk
+ PR fortran/80850
+ * gfortran.dg/class_64_f90 : New test.
+
2017-10-30 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/82085
diff --git a/gcc/testsuite/gfortran.dg/class_64.f90 b/gcc/testsuite/gfortran.dg/class_64.f90
new file mode 100644
index 00000000000..059ebaa8a01
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/class_64.f90
@@ -0,0 +1,38 @@
+! { dg-do compile }
+! { dg-options "-fdump-tree-original" }
+!
+! Test the fix for PR80850 in which the _len field was not being
+! set for 'arg' in the call to 'foo'.
+!
+ type :: mytype
+ integer :: i
+ end type
+ class (mytype), pointer :: c
+
+ allocate (c, source = mytype (99_8))
+
+ call foo(c)
+ call bar(c)
+
+ deallocate (c)
+
+contains
+
+ subroutine foo (arg)
+ class(*) :: arg
+ select type (arg)
+ type is (mytype)
+ if (arg%i .ne. 99_8) call abort
+ end select
+ end subroutine
+
+ subroutine bar (arg)
+ class(mytype) :: arg
+ select type (arg)
+ type is (mytype)
+ if (arg%i .ne. 99_8) call abort
+ end select
+ end subroutine
+
+end
+! { dg-final { scan-tree-dump-times "arg.*._len" 1 "original" } }