class object of the 'declared' type. If vptr is not NULL, this is
used for the temporary class object.
optional_alloc_ptr is false when the dummy is neither allocatable
- nor a pointer; that's only relevant for the optional handling. */
+ nor a pointer; that's only relevant for the optional handling.
+ The optional argument 'derived_array' is used to preserve the parmse
+ expression for deallocation of allocatable components. Assumed rank
+ formal arguments made this necessary. */
void
gfc_conv_derived_to_class (gfc_se *parmse, gfc_expr *e,
gfc_typespec class_ts, tree vptr, bool optional,
- bool optional_alloc_ptr)
+ bool optional_alloc_ptr,
+ tree *derived_array)
{
gfc_symbol *vtab;
tree cond_optional = NULL_TREE;
{
gcc_assert (class_ts.u.derived->components->as->type
== AS_ASSUMED_RANK);
+ if (derived_array
+ && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (parmse->expr)))
+ {
+ *derived_array = gfc_create_var (TREE_TYPE (parmse->expr),
+ "array");
+ gfc_add_modify (&block, *derived_array , parmse->expr);
+ }
class_array_data_assign (&block, ctree, parmse->expr, false);
}
else
gfc_init_block (&block);
gfc_conv_descriptor_data_set (&block, ctree, null_pointer_node);
+ if (derived_array && *derived_array != NULL_TREE)
+ gfc_conv_descriptor_data_set (&block, *derived_array,
+ null_pointer_node);
tmp = build3_v (COND_EXPR, cond_optional, tmp,
gfc_finish_block (&block));
{
bool finalized = false;
bool non_unity_length_string = false;
+ tree derived_array = NULL_TREE;
e = arg->expr;
fsym = formal ? formal->sym : NULL;
&& e->expr_type == EXPR_VARIABLE
&& e->symtree->n.sym->attr.optional,
CLASS_DATA (fsym)->attr.class_pointer
- || CLASS_DATA (fsym)->attr.allocatable);
+ || CLASS_DATA (fsym)->attr.allocatable,
+ &derived_array);
}
else if (UNLIMITED_POLY (fsym) && e->ts.type != BT_CLASS
&& gfc_expr_attr (e).flavor != FL_PROCEDURE)
&& parm_rank == 0
&& parmse.loop;
+ /* Scalars passed to an assumed rank argument are converted to
+ a descriptor. Obtain the data field before deallocating any
+ allocatable components. */
+ if (parm_rank == 0 && GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (tmp)))
+ tmp = gfc_conv_descriptor_data_get (tmp);
+
if (scalar_res_outside_loop)
{
/* Go through the ss chain to find the argument and use
}
}
- if ((e->ts.type == BT_CLASS
- && GFC_CLASS_TYPE_P (TREE_TYPE (tmp)))
- || e->ts.type == BT_DERIVED)
+ STRIP_NOPS (tmp);
+
+ if (derived_array != NULL_TREE)
+ tmp = gfc_deallocate_alloc_comp (e->ts.u.derived,
+ derived_array,
+ parm_rank);
+ else if ((e->ts.type == BT_CLASS
+ && GFC_CLASS_TYPE_P (TREE_TYPE (tmp)))
+ || e->ts.type == BT_DERIVED)
tmp = gfc_deallocate_alloc_comp (e->ts.u.derived, tmp,
parm_rank);
else if (e->ts.type == BT_CLASS)
--- /dev/null
+! { dg-do run }
+!
+! Test the fix for PR98342.
+!
+! Contributed by Martin Stein <mscfd@gmx.net>
+!
+module mod
+ implicit none
+ private
+ public get_tuple, sel_rank1, sel_rank2, sel_rank3
+
+ type, public :: tuple
+ integer, dimension(:), allocatable :: t
+end type tuple
+
+contains
+
+function sel_rank1(x) result(s)
+ character(len=:), allocatable :: s
+ type(tuple), dimension(..), intent(in) :: x
+ select rank (x)
+ rank (0)
+ s = '10'
+ rank (1)
+ s = '11'
+ rank default
+ s = '?'
+ end select
+end function sel_rank1
+
+function sel_rank2(x) result(s)
+ character(len=:), allocatable :: s
+ class(tuple), dimension(..), intent(in) :: x
+ select rank (x)
+ rank (0)
+ s = '20'
+ rank (1)
+ s = '21'
+ rank default
+ s = '?'
+ end select
+end function sel_rank2
+
+function sel_rank3(x) result(s)
+ character(len=:), allocatable :: s
+ class(*), dimension(..), intent(in) :: x
+ select rank (x)
+ rank (0)
+ s = '30'
+ rank (1)
+ s = '31'
+ rank default
+ s = '?'
+ end select
+end function sel_rank3
+
+function get_tuple(t) result(a)
+ type(tuple) :: a
+ integer, dimension(:), intent(in) :: t
+ allocate(a%t, source=t)
+end function get_tuple
+
+end module mod
+
+
+program alloc_rank
+ use mod
+ implicit none
+
+ integer, dimension(1:3) :: x
+ character(len=:), allocatable :: output
+ type(tuple) :: z
+
+ x = [1,2,3]
+ z = get_tuple (x)
+ ! Derived type formal arg
+ output = sel_rank1(get_tuple (x)) ! runtime: Error in `./alloc_rank.x':
+ if (output .ne. '10') stop 1
+ output = sel_rank1([z]) ! This worked OK
+ if (output .ne. '11') stop 2
+
+ ! Class formal arg
+ output = sel_rank2(get_tuple (x)) ! runtime: Error in `./alloc_rank.x':
+ if (output .ne. '20') stop 3
+ output = sel_rank2([z]) ! This worked OK
+ if (output .ne. '21') stop 4
+
+ ! Unlimited polymorphic formal arg
+ output = sel_rank3(get_tuple (x)) ! runtime: Error in `./alloc_rank.x':
+ if (output .ne. '30') stop 5
+ output = sel_rank3([z]) ! runtime: segmentation fault
+ if (output .ne. '31') stop 6
+
+ deallocate (output)
+ deallocate (z%t)
+end program alloc_rank