aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran
diff options
context:
space:
mode:
authorPaul Thomas <pault@gcc.gnu.org>2024-05-12 06:59:45 +0100
committerPaul Thomas <pault@gcc.gnu.org>2024-05-12 06:59:45 +0100
commitb9294757f82aae8de6d98c122cd4e3b98f685217 (patch)
tree4a8f6a62d58c5472ba8e69015bcd6015705e8e8c /gcc/fortran
parentd4974fd22730014e337fd7ec2471945ba8afb00e (diff)
downloadgcc-b9294757f82aae8de6d98c122cd4e3b98f685217.zip
gcc-b9294757f82aae8de6d98c122cd4e3b98f685217.tar.gz
gcc-b9294757f82aae8de6d98c122cd4e3b98f685217.tar.bz2
Fortran: Unlimited polymorphic intrinsic function arguments [PR84006]
2024-05-12 Paul Thomas <pault@gcc.gnu.org> gcc/fortran PR fortran/84006 PR fortran/100027 PR fortran/98534 * iresolve.cc (gfc_resolve_transfer): Emit a TODO error for unlimited polymorphic mold. * trans-expr.cc (gfc_resize_class_size_with_len): Use the fold even if a block is not available in which to fix the result. (trans_class_assignment): Enable correct assignment of character expressions to unlimited polymorphic variables using lhs _len field and rse string_length. * trans-intrinsic.cc (gfc_conv_intrinsic_storage_size): Extract the class expression so that the unlimited polymorphic class expression can be used in gfc_resize_class_size_with_len to obtain the storage size for character payloads. Guard the use of GFC_DECL_SAVED_DESCRIPTOR by testing for DECL_LANG_SPECIFIC to prevent the ICE. Also, invert the order to use the class expression extracted from the argument. (gfc_conv_intrinsic_transfer): In same way as 'storage_size', use the _len field to obtaining the correct length for arg 1. Add a branch for the element size in bytes of class expressions with provision to make use of the unlimited polymorphic _len field. Again, the class references are explicitly identified. 'mold_expr' was already declared. Use it instead of 'arg'. Do not fix 'dest_word_len' for deferred character sources because reallocation on assign makes use of it before it is assigned. gcc/testsuite/ PR fortran/84006 PR fortran/100027 * gfortran.dg/storage_size_7.f90: New test. PR fortran/98534 * gfortran.dg/transfer_class_4.f90: New test.
Diffstat (limited to 'gcc/fortran')
-rw-r--r--gcc/fortran/iresolve.cc4
-rw-r--r--gcc/fortran/trans-expr.cc15
-rw-r--r--gcc/fortran/trans-intrinsic.cc80
3 files changed, 79 insertions, 20 deletions
diff --git a/gcc/fortran/iresolve.cc b/gcc/fortran/iresolve.cc
index c961cdb..c63a4a8 100644
--- a/gcc/fortran/iresolve.cc
+++ b/gcc/fortran/iresolve.cc
@@ -3025,6 +3025,10 @@ gfc_resolve_transfer (gfc_expr *f, gfc_expr *source ATTRIBUTE_UNUSED,
}
}
+ if (UNLIMITED_POLY (mold))
+ gfc_error ("TODO: unlimited polymorphic MOLD in TRANSFER intrinsic at %L",
+ &mold->where);
+
f->ts = mold->ts;
if (size == NULL && mold->rank == 0)
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index bc8eb41..4590aa6 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -317,6 +317,8 @@ gfc_resize_class_size_with_len (stmtblock_t * block, tree class_expr, tree size)
size = gfc_evaluate_now (size, block);
tmp = gfc_evaluate_now (fold_convert (type , tmp), block);
}
+ else
+ tmp = fold_convert (type , tmp);
tmp2 = fold_build2_loc (input_location, MULT_EXPR,
type, size, tmp);
tmp = fold_build2_loc (input_location, GT_EXPR,
@@ -11994,15 +11996,24 @@ trans_class_assignment (stmtblock_t *block, gfc_expr *lhs, gfc_expr *rhs,
/* Take into account _len of unlimited polymorphic entities.
TODO: handle class(*) allocatable function results on rhs. */
- if (UNLIMITED_POLY (rhs) && rhs->expr_type == EXPR_VARIABLE)
+ if (UNLIMITED_POLY (rhs))
{
- tree len = trans_get_upoly_len (block, rhs);
+ tree len;
+ if (rhs->expr_type == EXPR_VARIABLE)
+ len = trans_get_upoly_len (block, rhs);
+ else
+ len = gfc_class_len_get (tmp);
len = fold_build2_loc (input_location, MAX_EXPR, size_type_node,
fold_convert (size_type_node, len),
size_one_node);
size = fold_build2_loc (input_location, MULT_EXPR, TREE_TYPE (size),
size, fold_convert (TREE_TYPE (size), len));
}
+ else if (rhs->ts.type == BT_CHARACTER && rse->string_length)
+ size = fold_build2_loc (input_location, MULT_EXPR,
+ gfc_charlen_type_node, size,
+ rse->string_length);
+
tmp = lse->expr;
class_han = GFC_CLASS_TYPE_P (TREE_TYPE (tmp))
diff --git a/gcc/fortran/trans-intrinsic.cc b/gcc/fortran/trans-intrinsic.cc
index 8304118..80dc342 100644
--- a/gcc/fortran/trans-intrinsic.cc
+++ b/gcc/fortran/trans-intrinsic.cc
@@ -8250,7 +8250,9 @@ gfc_conv_intrinsic_storage_size (gfc_se *se, gfc_expr *expr)
{
gfc_expr *arg;
gfc_se argse;
- tree type, result_type, tmp;
+ tree type, result_type, tmp, class_decl = NULL;
+ gfc_symbol *sym;
+ bool unlimited = false;
arg = expr->value.function.actual->expr;
@@ -8261,10 +8263,12 @@ gfc_conv_intrinsic_storage_size (gfc_se *se, gfc_expr *expr)
{
if (arg->ts.type == BT_CLASS)
{
+ unlimited = UNLIMITED_POLY (arg);
gfc_add_vptr_component (arg);
gfc_add_size_component (arg);
gfc_conv_expr (&argse, arg);
tmp = fold_convert (result_type, argse.expr);
+ class_decl = gfc_get_class_from_expr (argse.expr);
goto done;
}
@@ -8276,14 +8280,20 @@ gfc_conv_intrinsic_storage_size (gfc_se *se, gfc_expr *expr)
{
argse.want_pointer = 0;
gfc_conv_expr_descriptor (&argse, arg);
+ sym = arg->expr_type == EXPR_VARIABLE ? arg->symtree->n.sym : NULL;
if (arg->ts.type == BT_CLASS)
{
- if (arg->rank > 0)
+ unlimited = UNLIMITED_POLY (arg);
+ if (TREE_CODE (argse.expr) == COMPONENT_REF)
+ tmp = gfc_class_vtab_size_get (TREE_OPERAND (argse.expr, 0));
+ else if (arg->rank > 0 && sym
+ && DECL_LANG_SPECIFIC (sym->backend_decl))
tmp = gfc_class_vtab_size_get (
- GFC_DECL_SAVED_DESCRIPTOR (arg->symtree->n.sym->backend_decl));
+ GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl));
else
- tmp = gfc_class_vtab_size_get (TREE_OPERAND (argse.expr, 0));
+ gcc_unreachable ();
tmp = fold_convert (result_type, tmp);
+ class_decl = gfc_get_class_from_expr (argse.expr);
goto done;
}
type = gfc_get_element_type (TREE_TYPE (argse.expr));
@@ -8297,6 +8307,9 @@ gfc_conv_intrinsic_storage_size (gfc_se *se, gfc_expr *expr)
tmp = fold_convert (result_type, tmp);
done:
+ if (unlimited && class_decl)
+ tmp = gfc_resize_class_size_with_len (NULL, class_decl, tmp);
+
se->expr = fold_build2_loc (input_location, MULT_EXPR, result_type, tmp,
build_int_cst (result_type, BITS_PER_UNIT));
gfc_add_block_to_block (&se->pre, &argse.pre);
@@ -8419,7 +8432,10 @@ gfc_conv_intrinsic_transfer (gfc_se * se, gfc_expr * expr)
{
tmp = build_fold_indirect_ref_loc (input_location, argse.expr);
if (GFC_CLASS_TYPE_P (TREE_TYPE (tmp)))
- source = gfc_class_data_get (tmp);
+ {
+ source = gfc_class_data_get (tmp);
+ class_ref = tmp;
+ }
else
{
/* Array elements are evaluated as a reference to the data.
@@ -8446,9 +8462,17 @@ gfc_conv_intrinsic_transfer (gfc_se * se, gfc_expr * expr)
break;
case BT_CLASS:
if (class_ref != NULL_TREE)
- tmp = gfc_class_vtab_size_get (class_ref);
+ {
+ tmp = gfc_class_vtab_size_get (class_ref);
+ if (UNLIMITED_POLY (source_expr))
+ tmp = gfc_resize_class_size_with_len (NULL, class_ref, tmp);
+ }
else
- tmp = gfc_class_vtab_size_get (argse.expr);
+ {
+ tmp = gfc_class_vtab_size_get (argse.expr);
+ if (UNLIMITED_POLY (source_expr))
+ tmp = gfc_resize_class_size_with_len (NULL, argse.expr, tmp);
+ }
break;
default:
source_type = TREE_TYPE (build_fold_indirect_ref_loc (input_location,
@@ -8501,6 +8525,13 @@ gfc_conv_intrinsic_transfer (gfc_se * se, gfc_expr * expr)
if (arg->expr->ts.type == BT_CHARACTER)
tmp = size_of_string_in_bytes (arg->expr->ts.kind,
argse.string_length);
+ else if (arg->expr->ts.type == BT_CLASS)
+ {
+ class_ref = TREE_OPERAND (argse.expr, 0);
+ tmp = gfc_class_vtab_size_get (class_ref);
+ if (UNLIMITED_POLY (arg->expr))
+ tmp = gfc_resize_class_size_with_len (&argse.pre, class_ref, tmp);
+ }
else
tmp = fold_convert (gfc_array_index_type,
size_in_bytes (source_type));
@@ -8541,15 +8572,14 @@ gfc_conv_intrinsic_transfer (gfc_se * se, gfc_expr * expr)
if (arg->expr->rank == 0)
{
- gfc_conv_expr_reference (&argse, arg->expr);
+ gfc_conv_expr_reference (&argse, mold_expr);
mold_type = TREE_TYPE (build_fold_indirect_ref_loc (input_location,
argse.expr));
}
else
{
- gfc_init_se (&argse, NULL);
argse.want_pointer = 0;
- gfc_conv_expr_descriptor (&argse, arg->expr);
+ gfc_conv_expr_descriptor (&argse, mold_expr);
mold_type = gfc_get_element_type (TREE_TYPE (argse.expr));
}
@@ -8560,27 +8590,41 @@ gfc_conv_intrinsic_transfer (gfc_se * se, gfc_expr * expr)
{
/* If this TRANSFER is nested in another TRANSFER, use a type
that preserves all bits. */
- if (arg->expr->ts.type == BT_LOGICAL)
- mold_type = gfc_get_int_type (arg->expr->ts.kind);
+ if (mold_expr->ts.type == BT_LOGICAL)
+ mold_type = gfc_get_int_type (mold_expr->ts.kind);
}
/* Obtain the destination word length. */
- switch (arg->expr->ts.type)
+ switch (mold_expr->ts.type)
{
case BT_CHARACTER:
- tmp = size_of_string_in_bytes (arg->expr->ts.kind, argse.string_length);
- mold_type = gfc_get_character_type_len (arg->expr->ts.kind,
+ tmp = size_of_string_in_bytes (mold_expr->ts.kind, argse.string_length);
+ mold_type = gfc_get_character_type_len (mold_expr->ts.kind,
argse.string_length);
break;
case BT_CLASS:
- tmp = gfc_class_vtab_size_get (argse.expr);
+ if (scalar_mold)
+ class_ref = argse.expr;
+ else
+ class_ref = TREE_OPERAND (argse.expr, 0);
+ tmp = gfc_class_vtab_size_get (class_ref);
+ if (UNLIMITED_POLY (arg->expr))
+ tmp = gfc_resize_class_size_with_len (&argse.pre, class_ref, tmp);
break;
default:
tmp = fold_convert (gfc_array_index_type, size_in_bytes (mold_type));
break;
}
- dest_word_len = gfc_create_var (gfc_array_index_type, NULL);
- gfc_add_modify (&se->pre, dest_word_len, tmp);
+
+ /* Do not fix dest_word_len if it is a variable, since the temporary can wind
+ up being used before the assignment. */
+ if (mold_expr->ts.type == BT_CHARACTER && mold_expr->ts.deferred)
+ dest_word_len = tmp;
+ else
+ {
+ dest_word_len = gfc_create_var (gfc_array_index_type, NULL);
+ gfc_add_modify (&se->pre, dest_word_len, tmp);
+ }
/* Finally convert SIZE, if it is present. */
arg = arg->next;