This is a somewhat delayed patch to fix issues with the original patch, as flagged up by Rainer in comment #12, Rainer in comment #14 and Eric in comment #15. The fix for these problems was posted in April in comment #17. It was thoroughly tested but remained uncommitted because my attention was elsewhere.
I have added the fix to Damian's failing test posted at https://gcc.gnu.org/ml/fortran/2019-11/msg00061.html ? and referenced by Tobias in comment #23. The submitted testcase leaks memory as in PR38319, which I will return to as I work my way through my assigned PRs. I have returned to this latter PR on several occasions and have thus far not managed to find a fix for the problem, which is primarily due to various issues with allocatable component derived type constructor. For the main part, the patch relies on ensuring vtables are available and forcing all assignments to unlimited polymorphic entities to use the vtable _copy. Regtests on FC30/x86_64 - OK to commit? Paul 2019-11-17 Paul Thomas <pa...@gcc.gnu.org> PR fortran/83118 * resolve.c (resolve_ordinary_assign): Generate a vtable if necessary for scalar non-polymorphic rhs's to unlimited lhs's. * trans-array.c (structure_alloc_comps): Delete trailing white spaces. (gfc_alloc_allocatable_for_assignment): Use earlier evaluation of 'cond_null'. If unlimited poly initialize 'size1' to zero and jump to 'no_shape_tests'. Force reallocation of unlimited polymorphic lhs's. For allocation to unlimited polymorphic lhs from a class rhs, use the vtable size. * trans-expr.c (gfc_conv_procedure_call): Ensure the vtable is present for passing a non-class actual to an unlimited formal. (gfc_trans_assignment_1): Simplify some of the logic with 'realloc_flag'. (realloc_flag): Set 'vptr_copy' for all array assignments to unlimited polymorphic lhs. 2019-11-17 Paul Thomas <pa...@gcc.gnu.org> PR fortran/83118 * gfortran.dg/unlimited_polymorphic_31.f03: New test.
Index: gcc/fortran/resolve.c =================================================================== *** gcc/fortran/resolve.c (revision 278354) --- gcc/fortran/resolve.c (working copy) *************** resolve_ordinary_assign (gfc_code *code, *** 10868,10874 **** /* Make sure there is a vtable and, in particular, a _copy for the rhs type. */ ! if (UNLIMITED_POLY (lhs) && lhs->rank && rhs->ts.type != BT_CLASS) gfc_find_vtab (&rhs->ts); bool caf_convert_to_send = flag_coarray == GFC_FCOARRAY_LIB --- 10868,10874 ---- /* Make sure there is a vtable and, in particular, a _copy for the rhs type. */ ! if (UNLIMITED_POLY (lhs) && rhs->ts.type != BT_CLASS) gfc_find_vtab (&rhs->ts); bool caf_convert_to_send = flag_coarray == GFC_FCOARRAY_LIB Index: gcc/fortran/trans-array.c =================================================================== *** gcc/fortran/trans-array.c (revision 278354) --- gcc/fortran/trans-array.c (working copy) *************** structure_alloc_comps (gfc_symbol * der_ *** 8822,8828 **** cdesc = gfc_create_var (cdesc, "cdesc"); DECL_ARTIFICIAL (cdesc) = 1; ! gfc_add_modify (&tmpblock, gfc_conv_descriptor_dtype (cdesc), gfc_get_dtype_rank_type (1, tmp)); gfc_conv_descriptor_lbound_set (&tmpblock, cdesc, --- 8822,8828 ---- cdesc = gfc_create_var (cdesc, "cdesc"); DECL_ARTIFICIAL (cdesc) = 1; ! gfc_add_modify (&tmpblock, gfc_conv_descriptor_dtype (cdesc), gfc_get_dtype_rank_type (1, tmp)); gfc_conv_descriptor_lbound_set (&tmpblock, cdesc, *************** structure_alloc_comps (gfc_symbol * der_ *** 8833,8839 **** gfc_index_one_node); gfc_conv_descriptor_ubound_set (&tmpblock, cdesc, gfc_index_zero_node, ubound); ! if (attr->dimension) comp = gfc_conv_descriptor_data_get (comp); else --- 8833,8839 ---- gfc_index_one_node); gfc_conv_descriptor_ubound_set (&tmpblock, cdesc, gfc_index_zero_node, ubound); ! if (attr->dimension) comp = gfc_conv_descriptor_data_get (comp); else *************** gfc_alloc_allocatable_for_assignment (gf *** 10184,10198 **** rss->info->string_length); cond_null = fold_build2_loc (input_location, TRUTH_OR_EXPR, logical_type_node, tmp, cond_null); } else cond_null= gfc_evaluate_now (cond_null, &fblock); - tmp = build3_v (COND_EXPR, cond_null, - build1_v (GOTO_EXPR, jump_label1), - build_empty_stmt (input_location)); - gfc_add_expr_to_block (&fblock, tmp); - /* Get arrayspec if expr is a full array. */ if (expr2 && expr2->expr_type == EXPR_FUNCTION && expr2->value.function.isym --- 10184,10194 ---- rss->info->string_length); cond_null = fold_build2_loc (input_location, TRUTH_OR_EXPR, logical_type_node, tmp, cond_null); + cond_null= gfc_evaluate_now (cond_null, &fblock); } else cond_null= gfc_evaluate_now (cond_null, &fblock); /* Get arrayspec if expr is a full array. */ if (expr2 && expr2->expr_type == EXPR_FUNCTION && expr2->value.function.isym *************** gfc_alloc_allocatable_for_assignment (gf *** 10207,10212 **** --- 10203,10220 ---- else as = NULL; + if (UNLIMITED_POLY (expr1)) + { + size1 = gfc_create_var (gfc_array_index_type, NULL); + gfc_add_modify (&fblock, size1, gfc_index_zero_node); + goto no_shape_tests; + } + + tmp = build3_v (COND_EXPR, cond_null, + build1_v (GOTO_EXPR, jump_label1), + build_empty_stmt (input_location)); + gfc_add_expr_to_block (&fblock, tmp); + /* If the lhs shape is not the same as the rhs jump to setting the bounds and doing the reallocation....... */ for (n = 0; n < expr1->rank; n++) *************** gfc_alloc_allocatable_for_assignment (gf *** 10253,10258 **** --- 10261,10268 ---- gfc_finish_block (&realloc_block)); gfc_add_expr_to_block (&fblock, tmp); + no_shape_tests: + /* Get the rhs size and fix it. */ if (expr2) desc2 = rss->info->data.array.descriptor; *************** gfc_alloc_allocatable_for_assignment (gf *** 10277,10285 **** cond = fold_build2_loc (input_location, NE_EXPR, logical_type_node, size1, size2); ! /* If the lhs is deferred length, assume that the element size ! changes and force a reallocation. */ ! if (expr1->ts.deferred) neq_size = gfc_evaluate_now (logical_true_node, &fblock); else neq_size = gfc_evaluate_now (cond, &fblock); --- 10287,10295 ---- cond = fold_build2_loc (input_location, NE_EXPR, logical_type_node, size1, size2); ! /* If the lhs is deferred length or unlimited polymorphic, assume that ! the element size changes and force a reallocation. */ ! if (expr1->ts.deferred || UNLIMITED_POLY (expr1)) neq_size = gfc_evaluate_now (logical_true_node, &fblock); else neq_size = gfc_evaluate_now (cond, &fblock); *************** gfc_alloc_allocatable_for_assignment (gf *** 10424,10431 **** gfc_array_index_type, tmp, expr1->ts.u.cl->backend_decl); } ! else if (UNLIMITED_POLY (expr1) && expr2->ts.type != BT_CLASS) ! tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&expr2->ts)); else tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&expr1->ts)); tmp = fold_convert (gfc_array_index_type, tmp); --- 10434,10444 ---- gfc_array_index_type, tmp, expr1->ts.u.cl->backend_decl); } ! else if (UNLIMITED_POLY (expr1)) ! if (expr2->ts.type != BT_CLASS) ! tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&expr2->ts)); ! else ! tmp = gfc_class_vtab_size_get (TREE_OPERAND (desc2, 0)); else tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&expr1->ts)); tmp = fold_convert (gfc_array_index_type, tmp); *************** gfc_alloc_allocatable_for_assignment (gf *** 10603,10613 **** alloc_expr = gfc_finish_block (&alloc_block); /* Malloc if not allocated; realloc otherwise. */ ! tmp = build_int_cst (TREE_TYPE (array1), 0); ! cond = fold_build2_loc (input_location, EQ_EXPR, ! logical_type_node, ! array1, tmp); ! tmp = build3_v (COND_EXPR, cond, alloc_expr, realloc_expr); gfc_add_expr_to_block (&fblock, tmp); /* Make sure that the scalarizer data pointer is updated. */ --- 10616,10622 ---- alloc_expr = gfc_finish_block (&alloc_block); /* Malloc if not allocated; realloc otherwise. */ ! tmp = build3_v (COND_EXPR, cond_null, alloc_expr, realloc_expr); gfc_add_expr_to_block (&fblock, tmp); /* Make sure that the scalarizer data pointer is updated. */ Index: gcc/fortran/trans-expr.c =================================================================== *** gcc/fortran/trans-expr.c (revision 278354) --- gcc/fortran/trans-expr.c (working copy) *************** gfc_conv_procedure_call (gfc_se * se, gf *** 5586,5593 **** --- 5586,5595 ---- { /* The intrinsic type needs to be converted to a temporary CLASS object for the unlimited polymorphic formal. */ + gfc_find_vtab (&e->ts); gfc_init_se (&parmse, se); gfc_conv_intrinsic_to_class (&parmse, e, fsym->ts); + } else if (se->ss && se->ss->info->useflags) { *************** gfc_trans_assignment_1 (gfc_expr * expr1 *** 10717,10722 **** --- 10719,10725 ---- bool maybe_workshare = false, lhs_refs_comp = false, rhs_refs_comp = false; symbol_attribute lhs_caf_attr, rhs_caf_attr, lhs_attr; bool is_poly_assign; + bool realloc_flag; /* Assignment of the form lhs = rhs. */ gfc_start_block (&block); *************** gfc_trans_assignment_1 (gfc_expr * expr1 *** 10757,10762 **** --- 10760,10769 ---- || gfc_is_class_array_ref (expr2, NULL) || gfc_is_class_scalar_expr (expr2)); + realloc_flag = flag_realloc_lhs + && gfc_is_reallocatable_lhs (expr1) + && expr2->rank + && !is_runtime_conformable (expr1, expr2); /* Only analyze the expressions for coarray properties, when in coarray-lib mode. */ *************** gfc_trans_assignment_1 (gfc_expr * expr1 *** 11001,11008 **** if (is_poly_assign) tmp = trans_class_assignment (&body, expr1, expr2, &lse, &rse, use_vptr_copy || (lhs_attr.allocatable ! && !lhs_attr.dimension), ! flag_realloc_lhs && !lhs_attr.pointer); else if (flag_coarray == GFC_FCOARRAY_LIB && lhs_caf_attr.codimension && rhs_caf_attr.codimension && ((lhs_caf_attr.allocatable && lhs_refs_comp) --- 11008,11016 ---- if (is_poly_assign) tmp = trans_class_assignment (&body, expr1, expr2, &lse, &rse, use_vptr_copy || (lhs_attr.allocatable ! && !lhs_attr.dimension), ! !realloc_flag && flag_realloc_lhs ! && !lhs_attr.pointer); else if (flag_coarray == GFC_FCOARRAY_LIB && lhs_caf_attr.codimension && rhs_caf_attr.codimension && ((lhs_caf_attr.allocatable && lhs_refs_comp) *************** gfc_trans_assignment_1 (gfc_expr * expr1 *** 11107,11116 **** } /* F2003: Allocate or reallocate lhs of allocatable array. */ ! if (flag_realloc_lhs ! && gfc_is_reallocatable_lhs (expr1) ! && expr2->rank ! && !is_runtime_conformable (expr1, expr2)) { realloc_lhs_warning (expr1->ts.type, true, &expr1->where); ompws_flags &= ~OMPWS_SCALARIZER_WS; --- 11115,11121 ---- } /* F2003: Allocate or reallocate lhs of allocatable array. */ ! if (realloc_flag) { realloc_lhs_warning (expr1->ts.type, true, &expr1->where); ompws_flags &= ~OMPWS_SCALARIZER_WS; *************** gfc_trans_assignment (gfc_expr * expr1, *** 11219,11226 **** return tmp; } ! if (UNLIMITED_POLY (expr1) && expr1->rank ! && expr2->ts.type != BT_CLASS) use_vptr_copy = true; /* Fallback to the scalarizer to generate explicit loops. */ --- 11224,11230 ---- return tmp; } ! if (UNLIMITED_POLY (expr1) && expr1->rank) use_vptr_copy = true; /* Fallback to the scalarizer to generate explicit loops. */ Index: gcc/testsuite/gfortran.dg/unlimited_polymorphic_31.f03 =================================================================== *** gcc/testsuite/gfortran.dg/unlimited_polymorphic_31.f03 (nonexistent) --- gcc/testsuite/gfortran.dg/unlimited_polymorphic_31.f03 (working copy) *************** *** 0 **** --- 1,59 ---- + ! { dg-do run } + ! + ! Test the fix of the test case referenced in comment 17 of PR83118. + ! + ! Contributed by Damian Rouson <dam...@sourceryinstitute.org> + ! + implicit none + type Wrapper + class(*), allocatable :: elements(:) + end type + type Mytype + real(4) :: r = 42.0 + end type + + call driver + contains + subroutine driver + class(*), allocatable :: obj + type(Wrapper) w + integer(4) :: expected4(2) = [42_4, 43_4] + integer(8) :: expected8(3) = [42_8, 43_8, 44_8] + + w = new_wrapper (expected4) + obj = w + call test (obj, 0) + obj = new_wrapper (expected8) ! Used to generate a linker error + call test (obj, 10) + obj = new_wrapper ([mytype (99.0)]) + call test (obj, 100) + obj = Mytype (42.0) ! Used to generate a linker error + call test (obj, 1000) + end subroutine + function new_wrapper(array) result (res) + class(*) :: array(:) + type(Wrapper) :: res + res%elements = array ! Used to runtime segfault + end function + subroutine test (arg, idx) + class(*) :: arg + integer :: idx + select type (arg) + type is (wrapper) + select type (z => arg%elements) + type is (integer(4)) + if (any (z .ne. [42_4, 43_4])) stop 1 + idx + type is (integer(8)) + if (any (z .ne. [42_8, 43_8, 44_8])) stop 1 + idx + type is (Mytype) + if (abs (z(1)%r - 99.0) .ge. 1e-6) stop 1 + idx + class default + stop 2 + idx + end select + type is (Mytype) + if (abs (arg%r - 42.0) .ge. 1e-6) stop 1 + idx + class default + stop 3 + idx + end select + end subroutine + end