diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index 4baadc8..8d039a6 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -173,6 +173,29 @@ gfc_class_len_get (tree decl) } +/* Try to get the _len component of a class. When the class is not unlimited + poly, i.e. no _len field exists, then return a zero node. */ + +tree +gfc_class_len_or_zero_get (tree decl) +{ + tree len; + /* For class arrays decl may be a temporary descriptor handle, the vptr is + then available through the saved descriptor. */ + if (TREE_CODE (decl) == VAR_DECL && DECL_LANG_SPECIFIC (decl) + && GFC_DECL_SAVED_DESCRIPTOR (decl)) + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); + if (POINTER_TYPE_P (TREE_TYPE (decl))) + decl = build_fold_indirect_ref_loc (input_location, decl); + len = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (decl)), + CLASS_LEN_FIELD); + return len != NULL_TREE ? fold_build3_loc (input_location, COMPONENT_REF, + TREE_TYPE (len), decl, len, + NULL_TREE) + : integer_zero_node; +} + + /* Get the specified FIELD from the VPTR. */ static tree @@ -250,6 +273,7 @@ gfc_vptr_size_get (tree vptr) #undef CLASS_DATA_FIELD #undef CLASS_VPTR_FIELD +#undef CLASS_LEN_FIELD #undef VTABLE_HASH_FIELD #undef VTABLE_SIZE_FIELD #undef VTABLE_EXTENDS_FIELD @@ -1120,7 +1144,7 @@ gfc_copy_class_to_class (tree from, tree to, tree nelems, bool unlimited) if (unlimited) { if (from != NULL_TREE && unlimited) - from_len = gfc_class_len_get (from); + from_len = gfc_class_len_or_zero_get (from); else from_len = integer_zero_node; } diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h index add0cea..512615a 100644 --- a/gcc/fortran/trans.h +++ b/gcc/fortran/trans.h @@ -365,6 +365,7 @@ tree gfc_class_set_static_fields (tree, tree, tree); tree gfc_class_data_get (tree); tree gfc_class_vptr_get (tree); tree gfc_class_len_get (tree); +tree gfc_class_len_or_zero_get (tree); gfc_expr * gfc_find_and_cut_at_last_class_ref (gfc_expr *); /* Get an accessor to the class' vtab's * field, when a class handle is available. */ diff --git a/gcc/testsuite/gfortran.dg/unlimited_polymorphic_25.f90 b/gcc/testsuite/gfortran.dg/unlimited_polymorphic_25.f90 new file mode 100644 index 0000000..d0b2a2e --- /dev/null +++ b/gcc/testsuite/gfortran.dg/unlimited_polymorphic_25.f90 @@ -0,0 +1,40 @@ +! { dg-do run } +! +! Test contributed by Valery Weber + +module mod + + TYPE, PUBLIC :: base_type + END TYPE base_type + + TYPE, PUBLIC :: dict_entry_type + CLASS( * ), ALLOCATABLE :: key + CLASS( * ), ALLOCATABLE :: val + END TYPE dict_entry_type + + +contains + + SUBROUTINE dict_put ( this, key, val ) + CLASS(dict_entry_type), INTENT(INOUT) :: this + CLASS(base_type), INTENT(IN) :: key, val + INTEGER :: istat + ALLOCATE( this%key, SOURCE=key, STAT=istat ) + end SUBROUTINE dict_put +end module mod + +program test + use mod + type(dict_entry_type) :: t + type(base_type) :: a, b + call dict_put(t, a, b) + + if (.NOT. allocated(t%key)) call abort() + select type (x => t%key) + type is (base_type) + class default + call abort() + end select + deallocate(t%key) +end + diff --git a/gcc/testsuite/gfortran.dg/unlimited_polymorphic_26.f90 b/gcc/testsuite/gfortran.dg/unlimited_polymorphic_26.f90 new file mode 100644 index 0000000..1300069 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/unlimited_polymorphic_26.f90 @@ -0,0 +1,47 @@ +! { dg-do run } +! +! Test contributed by Valery Weber + +module mod + + TYPE, PUBLIC :: dict_entry_type + CLASS( * ), ALLOCATABLE :: key + CLASS( * ), ALLOCATABLE :: val + END TYPE dict_entry_type + + +contains + + SUBROUTINE dict_put ( this, key, val ) + CLASS(dict_entry_type), INTENT(INOUT) :: this + CLASS(*), INTENT(IN) :: key, val + INTEGER :: istat + ALLOCATE( this%key, SOURCE=key, STAT=istat ) + ALLOCATE( this%val, SOURCE=val, STAT=istat ) + end SUBROUTINE dict_put +end module mod + +program test + use mod + type(dict_entry_type) :: t + call dict_put(t, "foo", 42) + + if (.NOT. allocated(t%key)) call abort() + select type (x => t%key) + type is (CHARACTER(*)) + if (x /= "foo") call abort() + class default + call abort() + end select + deallocate(t%key) + + if (.NOT. allocated(t%val)) call abort() + select type (x => t%val) + type is (INTEGER) + if (x /= 42) call abort() + class default + call abort() + end select + deallocate(t%val) +end +