aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran
diff options
context:
space:
mode:
authorHarald Anlauf <anlauf@gmx.de>2024-12-14 20:26:47 +0100
committerHarald Anlauf <anlauf@gmx.de>2024-12-21 20:30:56 +0100
commitd637e6d069ade775a4b61f51fff61fe4cce01c36 (patch)
treee1d61d33bedabbb00ad0c83e3a153b6dec5d520a /gcc/fortran
parent145e462d557af537d90ef6da1391a57603c6fcf0 (diff)
downloadgcc-d637e6d069ade775a4b61f51fff61fe4cce01c36.zip
gcc-d637e6d069ade775a4b61f51fff61fe4cce01c36.tar.gz
gcc-d637e6d069ade775a4b61f51fff61fe4cce01c36.tar.bz2
Fortran: fix passing of NULL() to assumed-rank, derived type dummy [PR104819]
PR fortran/104819 gcc/fortran/ChangeLog: * interface.cc (compare_parameter): For the rank check, NULL() inherits the rank of a provided MOLD argument. (gfc_compare_actual_formal): Adjust check of NULL() actual argument against formal to accept F2008 enhancements (allocatable dummy). NULL() with MOLD argument retains a pointer/allocatable attribute. * trans-expr.cc (conv_null_actual): Implement passing NULL() to derived-type dummy with pointer/allocatable attribute, and ensure that the actual rank is passed to an assumed-rank dummy. (gfc_conv_procedure_call): Use it. gcc/testsuite/ChangeLog: * gfortran.dg/null_actual_7.f90: New test.
Diffstat (limited to 'gcc/fortran')
-rw-r--r--gcc/fortran/interface.cc42
-rw-r--r--gcc/fortran/trans-expr.cc49
2 files changed, 80 insertions, 11 deletions
diff --git a/gcc/fortran/interface.cc b/gcc/fortran/interface.cc
index fd39c01..8730269 100644
--- a/gcc/fortran/interface.cc
+++ b/gcc/fortran/interface.cc
@@ -2756,7 +2756,8 @@ compare_parameter (gfc_symbol *formal, gfc_expr *actual,
rank_check = where != NULL && !is_elemental && formal_as
&& (formal_as->type == AS_ASSUMED_SHAPE
|| formal_as->type == AS_DEFERRED)
- && actual->expr_type != EXPR_NULL;
+ && !(actual->expr_type == EXPR_NULL
+ && actual->ts.type == BT_UNKNOWN);
/* Skip rank checks for NO_ARG_CHECK. */
if (formal->attr.ext_attr & (1 << EXT_ATTR_NO_ARG_CHECK))
@@ -3230,6 +3231,7 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,
gfc_array_ref *actual_arr_ref;
gfc_array_spec *fas, *aas;
bool pointer_dummy, pointer_arg, allocatable_arg;
+ bool procptr_dummy, optional_dummy, allocatable_dummy;
bool ok = true;
@@ -3382,15 +3384,33 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,
goto match;
}
+ /* Allow passing of NULL() as disassociated pointer, procedure
+ pointer, or unallocated allocatable (F2008+) to a respective dummy
+ argument. */
+ pointer_dummy = ((f->sym->ts.type != BT_CLASS
+ && f->sym->attr.pointer)
+ || (f->sym->ts.type == BT_CLASS
+ && CLASS_DATA (f->sym)->attr.class_pointer));
+
+ procptr_dummy = ((f->sym->ts.type != BT_CLASS
+ && f->sym->attr.proc_pointer)
+ || (f->sym->ts.type == BT_CLASS
+ && CLASS_DATA (f->sym)->attr.proc_pointer));
+
+ optional_dummy = f->sym->attr.optional;
+
+ allocatable_dummy = ((f->sym->ts.type != BT_CLASS
+ && f->sym->attr.allocatable)
+ || (f->sym->ts.type == BT_CLASS
+ && CLASS_DATA (f->sym)->attr.allocatable));
+
if (a->expr->expr_type == EXPR_NULL
- && ((f->sym->ts.type != BT_CLASS && !f->sym->attr.pointer
- && (f->sym->attr.allocatable || !f->sym->attr.optional
- || (gfc_option.allow_std & GFC_STD_F2008) == 0))
- || (f->sym->ts.type == BT_CLASS
- && !CLASS_DATA (f->sym)->attr.class_pointer
- && (CLASS_DATA (f->sym)->attr.allocatable
- || !f->sym->attr.optional
- || (gfc_option.allow_std & GFC_STD_F2008) == 0))))
+ && !pointer_dummy
+ && !procptr_dummy
+ && !(optional_dummy
+ && (gfc_option.allow_std & GFC_STD_F2008) != 0)
+ && !(allocatable_dummy
+ && (gfc_option.allow_std & GFC_STD_F2008) != 0))
{
if (where
&& (!f->sym->attr.optional
@@ -3589,7 +3609,9 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,
pointer_dummy = f->sym->attr.pointer;
}
- if (a->expr->expr_type != EXPR_VARIABLE)
+ if (a->expr->expr_type != EXPR_VARIABLE
+ && !(a->expr->expr_type == EXPR_NULL
+ && a->expr->ts.type != BT_UNKNOWN))
{
aas = NULL;
pointer_arg = false;
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 44a50c0..e3a4f59 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -6398,7 +6398,7 @@ conv_dummy_value (gfc_se * parmse, gfc_expr * e, gfc_symbol * fsym,
static void
conv_null_actual (gfc_se * parmse, gfc_expr * e, gfc_symbol * fsym)
{
- gcc_assert (fsym && !fsym->attr.optional);
+ gcc_assert (fsym && e->expr_type == EXPR_NULL);
/* Obtain the character length for a NULL() actual with a character
MOLD argument. Otherwise substitute a suitable dummy length.
@@ -6461,6 +6461,44 @@ conv_null_actual (gfc_se * parmse, gfc_expr * e, gfc_symbol * fsym)
}
}
}
+ else if (fsym->ts.type == BT_DERIVED)
+ {
+ if (e->ts.type != BT_UNKNOWN)
+ /* MOLD is present. Pass a corresponding temporary NULL pointer.
+ For an assumed-rank dummy we provide a descriptor that passes
+ the correct rank. */
+ {
+ tree rank;
+ tree tmp = parmse->expr;
+
+ tmp = gfc_conv_scalar_to_descriptor (parmse, tmp, gfc_expr_attr (e));
+ rank = gfc_conv_descriptor_rank (tmp);
+ gfc_add_modify (&parmse->pre, rank,
+ build_int_cst (TREE_TYPE (rank), e->rank));
+ gfc_conv_descriptor_data_set (&parmse->pre, tmp, null_pointer_node);
+ parmse->expr = gfc_build_addr_expr (NULL_TREE, tmp);
+ }
+ else
+ /* MOLD is not present. Use attributes from dummy argument, which is
+ not allowed to be assumed-rank. */
+ {
+ int dummy_rank;
+ tree tmp = parmse->expr;
+
+ if (fsym->attr.allocatable && fsym->attr.intent == INTENT_UNKNOWN)
+ fsym->attr.intent = INTENT_IN;
+ tmp = gfc_conv_scalar_to_descriptor (parmse, tmp, fsym->attr);
+ dummy_rank = fsym->as ? fsym->as->rank : 0;
+ if (dummy_rank > 0)
+ {
+ tree rank = gfc_conv_descriptor_rank (tmp);
+ gfc_add_modify (&parmse->pre, rank,
+ build_int_cst (TREE_TYPE (rank), dummy_rank));
+ }
+ gfc_conv_descriptor_data_set (&parmse->pre, tmp, null_pointer_node);
+ parmse->expr = gfc_build_addr_expr (NULL_TREE, tmp);
+ }
+ }
}
@@ -6699,6 +6737,15 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
}
}
}
+ else if (e->expr_type == EXPR_NULL
+ && (e->ts.type == BT_UNKNOWN || e->ts.type == BT_DERIVED)
+ && fsym && attr && (attr->pointer || attr->allocatable)
+ && fsym->ts.type == BT_DERIVED)
+ {
+ gfc_init_se (&parmse, NULL);
+ gfc_conv_expr_reference (&parmse, e);
+ conv_null_actual (&parmse, e, fsym);
+ }
else if (arg->expr->expr_type == EXPR_NULL
&& fsym && !fsym->attr.pointer
&& (fsym->ts.type != BT_CLASS