On 13/06/21 15:46, José Rui Faustino de Sousa wrote:
Hi All!
Proposed patch to:
And again I forgot to add the patch...
Sorry for the inconvenience.
Best regards,
José Rui
diff --git a/gcc/fortran/class.c b/gcc/fortran/class.c
index 93118ad..5670d18 100644
--- a/gcc/fortran/class.c
+++ b/gcc/fortran/class.c
@@ -443,7 +443,7 @@ gfc_is_class_container_ref (gfc_expr *e)
component to the corresponding type (or the declared type, given by ts). */
gfc_expr *
-gfc_class_initializer (gfc_typespec *ts, gfc_expr *init_expr)
+gfc_class_initializer (gfc_typespec *ts, gfc_expr *init_expr, bool pointer)
{
gfc_expr *init;
gfc_component *comp;
@@ -464,7 +464,10 @@ gfc_class_initializer (gfc_typespec *ts, gfc_expr *init_expr)
if (strcmp (comp->name, "_vptr") == 0 && vtab)
ctor->expr = gfc_lval_expr_from_sym (vtab);
else if (init_expr && init_expr->expr_type != EXPR_NULL)
- ctor->expr = gfc_copy_expr (init_expr);
+ ctor->expr = gfc_copy_expr (init_expr);
+ else if (strcmp (comp->name, "_data") == 0 && pointer)
+ ctor->expr = (init_expr && init_expr->expr_type == EXPR_NULL)
+ ? (gfc_get_null_expr (NULL)) : (NULL);
else
ctor->expr = gfc_get_null_expr (NULL);
gfc_constructor_append (&init->value.constructor, ctor);
diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c
index 956003e..32b2849 100644
--- a/gcc/fortran/expr.c
+++ b/gcc/fortran/expr.c
@@ -4433,15 +4433,19 @@ bool
gfc_check_assign_symbol (gfc_symbol *sym, gfc_component *comp, gfc_expr *rvalue)
{
gfc_expr lvalue;
+ gfc_array_spec *as;
bool r;
- bool pointer, proc_pointer;
+ bool is_class, pointer, proc_pointer;
memset (&lvalue, '\0', sizeof (gfc_expr));
+ is_class = (sym->ts.type == BT_CLASS) && CLASS_DATA (sym);
+ as = is_class ? (CLASS_DATA (sym)->as) : (sym->as);
+
lvalue.expr_type = EXPR_VARIABLE;
lvalue.ts = sym->ts;
- if (sym->as)
- lvalue.rank = sym->as->rank;
+ if (as)
+ lvalue.rank = as->rank;
lvalue.symtree = XCNEW (gfc_symtree);
lvalue.symtree->n.sym = sym;
lvalue.where = sym->declared_at;
@@ -4461,7 +4465,7 @@ gfc_check_assign_symbol (gfc_symbol *sym, gfc_component *comp, gfc_expr *rvalue)
}
else
{
- pointer = sym->ts.type == BT_CLASS && CLASS_DATA (sym)
+ pointer = is_class
? CLASS_DATA (sym)->attr.class_pointer : sym->attr.pointer;
proc_pointer = sym->attr.proc_pointer;
}
@@ -4883,32 +4887,21 @@ get_union_initializer (gfc_symbol *union_type, gfc_component **map_p)
}
static bool
-class_allocatable (gfc_component *comp)
-{
- return comp->ts.type == BT_CLASS && CLASS_DATA (comp)
- && CLASS_DATA (comp)->attr.allocatable;
-}
-
-static bool
-class_pointer (gfc_component *comp)
-{
- return comp->ts.type == BT_CLASS && CLASS_DATA (comp)
- && CLASS_DATA (comp)->attr.pointer;
-}
-
-static bool
comp_allocatable (gfc_component *comp)
{
- return comp->attr.allocatable || class_allocatable (comp);
+ if (comp->ts.type == BT_CLASS && CLASS_DATA (comp))
+ return CLASS_DATA (comp)->attr.allocatable;
+ return comp->attr.allocatable;
}
static bool
comp_pointer (gfc_component *comp)
{
- return comp->attr.pointer
- || comp->attr.proc_pointer
- || comp->attr.class_pointer
- || class_pointer (comp);
+ if (comp->attr.proc_pointer)
+ return true;
+ if (comp->ts.type == BT_CLASS && CLASS_DATA (comp))
+ return CLASS_DATA (comp)->attr.class_pointer;
+ return comp->attr.pointer;
}
/* Fetch or generate an initializer for the given component.
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index cbc95d3..52a76bc 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -3673,7 +3673,7 @@ void gfc_add_class_array_ref (gfc_expr *);
bool gfc_is_class_array_ref (gfc_expr *, bool *);
bool gfc_is_class_scalar_expr (gfc_expr *);
bool gfc_is_class_container_ref (gfc_expr *e);
-gfc_expr *gfc_class_initializer (gfc_typespec *, gfc_expr *);
+gfc_expr *gfc_class_initializer (gfc_typespec *, gfc_expr *, bool);
unsigned int gfc_hash_value (gfc_symbol *);
gfc_expr *gfc_get_len_component (gfc_expr *e, int);
bool gfc_build_class_symbol (gfc_typespec *, symbol_attribute *,
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index a6bcd2b..891f82a 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -406,20 +406,288 @@ gfc_conv_descriptor_ubound_set (stmtblock_t *block, tree desc,
gfc_add_modify (block, t, fold_convert (TREE_TYPE (t), value));
}
+
+/* Create a new dtype constructor. */
+
+static tree
+build_init_dtype (tree ctor, int rank)
+{
+ tree type;
+ tree field;
+ tree value;
+ tree init;
+ vec<constructor_elt, va_gc> *vlst = NULL;
+
+ gcc_assert (TREE_CODE (ctor) == CONSTRUCTOR);
+ type = TREE_TYPE (ctor);
+
+ value = gfc_get_expr_from_ctor (ctor, 0);
+ if (value == NULL_TREE)
+ value = integer_zero_node;
+ if (!TREE_CONSTANT (value) || TREE_SIDE_EFFECTS (value))
+ value = (DECL_INITIAL (value))
+ ? (DECL_INITIAL (value)) : (integer_zero_node);
+
+ field = gfc_advance_chain (TYPE_FIELDS (type), 0);
+ gcc_assert (field != NULL_TREE);
+ value = fold_convert (TREE_TYPE (field), value);
+ CONSTRUCTOR_APPEND_ELT (vlst, field, value);
+
+ field = gfc_advance_chain (TYPE_FIELDS (type), 2);
+ gcc_assert (field != NULL_TREE);
+ value = build_int_cst (TREE_TYPE (field), rank);
+ CONSTRUCTOR_APPEND_ELT (vlst, field, value);
+
+ value = gfc_get_expr_from_ctor (ctor, 3);
+ if (value == NULL_TREE)
+ value = integer_zero_node;
+ field = gfc_advance_chain (TYPE_FIELDS (type), 3);
+ gcc_assert (field != NULL_TREE);
+ CONSTRUCTOR_APPEND_ELT (vlst, field, value);
+
+ init = build_constructor (type, vlst);
+ TREE_CONSTANT (init) = 1;
+
+ return init;
+}
+
+
+/* Find the old dtype constructor and create a new one. */
+
+static tree
+build_init_desc_dtype (tree desc, int rank, tree chain)
+{
+ tree type;
+ tree field;
+ tree cref;
+ tree value;
+
+ type = TREE_TYPE (desc);
+ gcc_assert (GFC_DESCRIPTOR_TYPE_P (type));
+
+ field = gfc_advance_chain (TYPE_FIELDS (type), DTYPE_FIELD);
+ gcc_assert (field != NULL_TREE);
+ type = TREE_TYPE (field);
+ cref = fold_build3_loc (input_location, COMPONENT_REF, type,
+ desc, field, NULL_TREE);
+
+ value = gfc_get_expr_from_chain (cref, chain);
+ gcc_assert (value != NULL_TREE);
+
+ return build_init_dtype (value, rank);
+}
+
+
+/* Append one of dim fields to vector. */
+
+static bool
+append_init_dim (tree base, unsigned field_idx, tree chain,
+ vec<constructor_elt, va_gc> **vlst)
+{
+ tree type, field, cref, value;
+
+ type = TREE_TYPE (base);
+ gcc_assert (TREE_CODE (type) == RECORD_TYPE);
+
+ field = gfc_advance_chain (TYPE_FIELDS (type), field_idx);
+ gcc_assert (field != NULL_TREE);
+ type = TREE_TYPE (field);
+ cref = fold_build3_loc (input_location, COMPONENT_REF, type,
+ base, field, NULL_TREE);
+
+ value = gfc_get_expr_from_chain (cref, chain);
+ if (value == NULL_TREE)
+ return false;
+ gcc_assert (TREE_CONSTANT (value) && !TREE_SIDE_EFFECTS (value));
+
+ CONSTRUCTOR_APPEND_ELT (*vlst, field, fold_convert (type, value));
+ return true;
+}
+
+
+/* Create a dim constructor. */
+
+static tree
+build_init_dim (tree base, tree chain)
+{
+ tree init = NULL_TREE;
+ vec<constructor_elt, va_gc> *vlst = NULL;
+
+ append_init_dim (base, STRIDE_SUBFIELD, chain, &vlst);
+ append_init_dim (base, LBOUND_SUBFIELD, chain, &vlst);
+ append_init_dim (base, UBOUND_SUBFIELD, chain, &vlst);
+
+ if (!vec_safe_is_empty (vlst))
+ {
+ init = build_constructor (TREE_TYPE (base), vlst);
+ TREE_CONSTANT (init) = 1;
+ }
+
+ return init;
+}
+
+
+/* Create the dim array constructor. */
+
+static tree
+build_init_desc_dim (tree desc, int rank, tree chain)
+{
+ tree type;
+ tree field;
+ tree cref;
+ tree base;
+ tree idim;
+ tree init;
+ vec<constructor_elt, va_gc> *vlst = NULL;
+ int idx;
+
+ type = TREE_TYPE (desc);
+ gcc_assert (GFC_DESCRIPTOR_TYPE_P (type));
+
+ field = gfc_advance_chain (TYPE_FIELDS (type), DIMENSION_FIELD);
+ gcc_assert (field != NULL_TREE);
+ type = TREE_TYPE (field);
+ cref = fold_build3_loc (input_location, COMPONENT_REF, type,
+ desc, field, NULL_TREE);
+
+ for (idx = 0; idx<rank; idx++)
+ {
+ idim = build_int_cst (gfc_array_index_type, idx);
+ base = gfc_build_array_ref (cref, idim, NULL);
+ init = build_init_dim (base, chain);
+ if (init == NULL_TREE)
+ continue;
+ CONSTRUCTOR_APPEND_ELT (vlst, NULL_TREE, init);
+ }
+
+ init = NULL_TREE;
+ if (!vec_safe_is_empty (vlst))
+ {
+ init = build_constructor (type, vlst);
+ TREE_CONSTANT (init) = 1;
+ }
+
+ return init;
+}
+
+
+/* Append the field to the vector. */
+
+static bool
+append_desc_field (tree desc, int rank, unsigned field_idx, tree chain,
+ vec<constructor_elt, va_gc> **vlst)
+{
+ tree field, type, cref, value;
+
+ type = TREE_TYPE (desc);
+ gcc_assert (GFC_DESCRIPTOR_TYPE_P (type));
+
+ field = gfc_advance_chain (TYPE_FIELDS (type), field_idx);
+ gcc_assert (field != NULL_TREE);
+ type = TREE_TYPE (field);
+ cref = fold_build3_loc (input_location, COMPONENT_REF, type,
+ desc, field, NULL_TREE);
+
+ switch (field_idx)
+ {
+ case DTYPE_FIELD:
+ {
+ value = build_init_desc_dtype (desc, rank, chain);
+ break;
+ }
+ case DIMENSION_FIELD:
+ {
+ value = build_init_desc_dim (desc, rank, chain);
+ break;
+ }
+ default:
+ value = gfc_get_expr_from_chain (cref, chain);
+ break;
+ }
+
+ if (value == NULL_TREE)
+ return false;
+ gcc_assert (TREE_CONSTANT (value) && !TREE_SIDE_EFFECTS (value));
+
+ value = fold_convert (type, value);
+ CONSTRUCTOR_APPEND_ELT (*vlst, field, value);
+ return true;
+}
+
+/* Create an array descriptor constructor. */
+
+static tree
+build_init_descriptor (tree desc, int rank, tree chain)
+{
+ tree type;
+ tree init;
+ vec<constructor_elt, va_gc> *vlst = NULL;
+
+ type = TREE_TYPE (desc);
+ gcc_assert (GFC_DESCRIPTOR_TYPE_P (type));
+
+ append_desc_field (desc, rank, DATA_FIELD, chain, &vlst);
+ append_desc_field (desc, rank, OFFSET_FIELD, chain, &vlst);
+ append_desc_field (desc, rank, DTYPE_FIELD, chain, &vlst);
+ append_desc_field (desc, rank, SPAN_FIELD, chain, &vlst);
+ append_desc_field (desc, rank, DIMENSION_FIELD, chain, &vlst);
+
+ init = NULL_TREE;
+ if (!vec_safe_is_empty (vlst))
+ {
+ init = build_constructor (type, vlst);
+ TREE_CONSTANT (init) = 1;
+ }
+
+ return init;
+}
+
+
+/* Build a descriptor containing only a dtype. */
+
+tree
+gfc_build_init_descriptor_dtype (tree type, int rank)
+{
+ tree tmp;
+ tree field;
+ tree dtype;
+
+ gcc_assert (GFC_DESCRIPTOR_TYPE_P (type));
+
+ tmp = gfc_get_element_type (type);
+ dtype = gfc_get_dtype_rank_type (rank, tmp, true);
+ field = gfc_advance_chain (TYPE_FIELDS (type), DTYPE_FIELD);
+ dtype = fold_convert (TREE_TYPE (field), dtype);
+ tmp = build_constructor_single (type, field, dtype);
+ TREE_CONSTANT (tmp) = 1;
+
+ return tmp;
+}
+
+
/* Build a null array descriptor constructor. */
tree
-gfc_build_null_descriptor (tree type)
+gfc_build_null_descriptor (tree type, int rank)
{
tree field;
- tree tmp;
+ tree tmp, dtype;
+ vec<constructor_elt, va_gc> *v = NULL;
gcc_assert (GFC_DESCRIPTOR_TYPE_P (type));
- gcc_assert (DATA_FIELD == 0);
- field = TYPE_FIELDS (type);
+
+ field = gfc_advance_chain (TYPE_FIELDS (type), DATA_FIELD);
+ CONSTRUCTOR_APPEND_ELT (v, field,
+ fold_convert (TREE_TYPE (field), null_pointer_node));
+
+ tmp = gfc_get_element_type (type);
+ dtype = gfc_get_dtype_rank_type (rank, tmp, true);
+ field = gfc_advance_chain (TYPE_FIELDS (type), DTYPE_FIELD);
+ CONSTRUCTOR_APPEND_ELT (v, field,
+ fold_convert (TREE_TYPE (field), dtype));
/* Set a NULL data pointer. */
- tmp = build_constructor_single (type, field, null_pointer_node);
+ tmp = build_constructor (type, v);
TREE_CONSTANT (tmp) = 1;
/* All other fields are ignored. */
@@ -427,6 +695,52 @@ gfc_build_null_descriptor (tree type)
}
+/* Build a null array descriptor constructor. */
+
+tree
+gfc_build_init_descriptor (tree decl, int rank, gfc_expr * expr)
+{
+ gfc_se lse;
+ stmtblock_t block;
+ tree type;
+ tree init;
+
+ type = TREE_TYPE (decl);
+ if (expr == NULL)
+ return gfc_build_init_descriptor_dtype (type, rank);
+ if (expr && expr->expr_type == EXPR_NULL)
+ return gfc_build_null_descriptor (type, rank);
+
+ gcc_assert (GFC_DESCRIPTOR_TYPE_P (type));
+ gcc_assert (expr->expr_type == EXPR_VARIABLE);
+
+ gfc_start_block (&block);
+ gfc_init_se (&lse, NULL);
+ lse.expr = decl;
+
+ /* Assign directly to the LHS's descriptor. */
+ lse.unlimited_polymorphic =
+ gfc_class_unlimited_poly (DECL_CONTEXT (decl));
+ lse.direct_byref = 1;
+ gfc_conv_expr_descriptor (&lse, expr);
+
+ gfc_add_block_to_block (&block, &lse.pre);
+ gfc_add_block_to_block (&block, &lse.post);
+ init = gfc_finish_block (&block);
+
+ /* gcc_assert (TREE_CODE (init) == BIND_EXPR);
+ decl = BIND_EXPR_VARS (init);
+ gcc_assert (VAR_P (decl));
+ init = BIND_EXPR_BODY (init);
+ gcc_assert (TREE_CODE (init) == STATEMENT_LIST); */
+
+ init = build_init_descriptor (decl, rank, init);
+
+ TREE_CONSTANT (init) = 1;
+ return init;
+}
+
+
/* Modify a descriptor such that the lbound of a given dimension is the value
specified. This also updates ubound and offset accordingly. */
@@ -890,15 +1204,41 @@ gfc_get_array_span (tree desc, gfc_expr *expr)
/* Generate an initializer for a static pointer or allocatable array. */
-void
+tree
gfc_trans_static_array_pointer (gfc_symbol * sym)
{
- tree type;
+ tree type, init;
+ bool is_class;
+ bool is_pointer;
+ symbol_attribute *attr;
+ gfc_array_spec *as;
+ int rank;
gcc_assert (TREE_STATIC (sym->backend_decl));
- /* Just zero the data member. */
type = TREE_TYPE (sym->backend_decl);
- DECL_INITIAL (sym->backend_decl) = gfc_build_null_descriptor (type);
+ gcc_assert (GFC_DESCRIPTOR_TYPE_P (type));
+
+ is_class = (sym->ts.type == BT_CLASS) && CLASS_DATA (sym);
+ attr = is_class ? &(CLASS_DATA (sym)->attr) : &(sym->attr);
+ is_pointer = is_class ? attr->class_pointer : attr->pointer;
+ as = is_class ? (CLASS_DATA (sym)->as) : (sym->as);
+ rank = as ? as->rank : 0;
+
+ if (attr->allocatable
+ || (sym->value && sym->value->expr_type == EXPR_NULL))
+ init = gfc_build_null_descriptor (type, rank);
+ else if (is_pointer)
+ {
+ if (sym->value)
+ init = gfc_build_init_descriptor (sym->backend_decl, rank, sym->value);
+ else
+ init = gfc_build_init_descriptor_dtype (type, rank);
+ }
+ else
+ gcc_unreachable ();
+
+ DECL_INITIAL (sym->backend_decl) = init;
+ return init;
}
@@ -6128,7 +6468,7 @@ gfc_conv_array_initializer (tree type, gfc_expr * expr)
if (expr->expr_type == EXPR_CONSTANT)
gfc_conv_constant (&se, expr);
else
- gfc_conv_structure (&se, expr, 1);
+ gfc_conv_structure_initializer (&se, expr);
CONSTRUCTOR_APPEND_ELT (v, build2 (RANGE_EXPR, gfc_array_index_type,
TYPE_MIN_VALUE (TYPE_DOMAIN (type)),
@@ -6211,7 +6551,7 @@ gfc_conv_array_initializer (tree type, gfc_expr * expr)
break;
case EXPR_STRUCTURE:
- gfc_conv_structure (&se, c->expr, 1);
+ gfc_conv_structure_initializer (&se, c->expr);
break;
default:
@@ -6234,7 +6574,7 @@ gfc_conv_array_initializer (tree type, gfc_expr * expr)
break;
case EXPR_NULL:
- return gfc_build_null_descriptor (type);
+ return gfc_build_null_descriptor (type, expr->rank);
default:
gcc_unreachable ();
diff --git a/gcc/fortran/trans-array.h b/gcc/fortran/trans-array.h
index e4d443d..2413c7d 100644
--- a/gcc/fortran/trans-array.h
+++ b/gcc/fortran/trans-array.h
@@ -70,7 +70,7 @@ tree gfc_alloc_allocatable_for_assignment (gfc_loopinfo*, gfc_expr*, gfc_expr*);
/* Add initialization for deferred arrays. */
void gfc_trans_deferred_array (gfc_symbol *, gfc_wrapped_block *);
/* Generate an initializer for a static pointer or allocatable array. */
-void gfc_trans_static_array_pointer (gfc_symbol *);
+tree gfc_trans_static_array_pointer (gfc_symbol *);
/* Get the procedure interface for a function call. */
gfc_symbol *gfc_get_proc_ifc_for_expr (gfc_expr *);
@@ -129,7 +129,9 @@ void gfc_set_delta (gfc_loopinfo *);
/* Resolve array assignment dependencies. */
void gfc_conv_resolve_dependencies (gfc_loopinfo *, gfc_ss *, gfc_ss *);
/* Build a null array descriptor constructor. */
-tree gfc_build_null_descriptor (tree);
+tree gfc_build_null_descriptor (tree, int);
+/* Build an array descriptor constructor. */
+tree gfc_build_init_descriptor (tree, int, gfc_expr*);
/* Get a single array element. */
void gfc_conv_array_ref (gfc_se *, gfc_array_ref *, gfc_expr *, locus *);
diff --git a/gcc/fortran/trans-common.c b/gcc/fortran/trans-common.c
index a11cf4c..9242641 100644
--- a/gcc/fortran/trans-common.c
+++ b/gcc/fortran/trans-common.c
@@ -705,11 +705,7 @@ create_common (gfc_common_head *com, segment_info *head, bool saw_equiv)
if (s->sym->value)
{
/* Add the initializer for this field. */
- tmp = gfc_conv_initializer (s->sym->value, &s->sym->ts,
- TREE_TYPE (s->field),
- s->sym->attr.dimension,
- s->sym->attr.pointer
- || s->sym->attr.allocatable, false);
+ tmp = gfc_conv_sym_initializer (s->field, s->sym);
CONSTRUCTOR_APPEND_ELT (v, s->field, tmp);
}
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index c32bd05..dd53643 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -1374,7 +1374,10 @@ gfc_create_string_length (gfc_symbol * sym)
sym->ts.u.cl->backend_decl = length;
if (static_length)
- TREE_STATIC (length) = 1;
+ {
+ TREE_STATIC (length) = 1;
+ DECL_INITIAL (length) = build_int_cst (gfc_charlen_type_node, 0);
+ }
if (sym->ns->proc_name->attr.flavor == FL_MODULE
&& (sym->attr.access != ACCESS_PRIVATE || sym->attr.public_used))
@@ -1861,12 +1864,11 @@ gfc_get_symbol_decl (gfc_symbol * sym)
&& sym->value && sym->value->expr_type != EXPR_NULL
&& sym->value->ts.u.cl->length)
{
+ tree tmp;
gfc_expr *len = sym->value->ts.u.cl->length;
- DECL_INITIAL (length) = gfc_conv_initializer (len, &len->ts,
- TREE_TYPE (length),
- false, false, false);
- DECL_INITIAL (length) = fold_convert (gfc_charlen_type_node,
- DECL_INITIAL (length));
+
+ tmp = gfc_conv_expr_initializer (length, len);
+ DECL_INITIAL (length) = fold_convert (gfc_charlen_type_node, tmp);
}
else
gcc_assert (!sym->value || sym->value->expr_type == EXPR_NULL);
@@ -1917,13 +1919,7 @@ gfc_get_symbol_decl (gfc_symbol * sym)
every time the procedure is entered. The TREE_STATIC is
in this case due to -fmax-stack-var-size=. */
- DECL_INITIAL (decl) = gfc_conv_initializer (sym->value, &sym->ts,
- TREE_TYPE (decl), sym->attr.dimension
- || (sym->attr.codimension
- && sym->attr.allocatable),
- sym->attr.pointer || sym->attr.allocatable
- || sym->ts.type == BT_CLASS,
- sym->attr.proc_pointer);
+ DECL_INITIAL (decl) = gfc_conv_sym_initializer (decl, sym);
}
if (!TREE_STATIC (decl)
@@ -2057,10 +2053,7 @@ get_proc_pointer_decl (gfc_symbol *sym)
if (TREE_STATIC (decl) && sym->value)
{
/* Add static initializer. */
- DECL_INITIAL (decl) = gfc_conv_initializer (sym->value, &sym->ts,
- TREE_TYPE (decl),
- sym->attr.dimension,
- false, true);
+ DECL_INITIAL (decl) = gfc_conv_sym_initializer (decl, sym);
}
/* Handle threadprivate procedure pointers. */
@@ -4811,8 +4804,10 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block)
|| (CLASS_DATA (sym)->attr.codimension
&& flag_coarray != GFC_FCOARRAY_LIB))
{
+ int rank = CLASS_DATA (sym)->as->rank;
+
tmp = gfc_class_data_get (sym->backend_decl);
- tmp = gfc_build_null_descriptor (TREE_TYPE (tmp));
+ tmp = gfc_build_null_descriptor (TREE_TYPE (tmp), rank);
}
else
tmp = null_pointer_node;
@@ -5555,6 +5550,8 @@ static void
gfc_emit_parameter_debug_info (gfc_symbol *sym)
{
tree decl;
+ gfc_array_spec *as;
+ bool is_class;
if (sym->attr.flavor != FL_PARAMETER
&& (sym->attr.flavor != FL_VARIABLE || sym->attr.referenced))
@@ -5576,6 +5573,9 @@ gfc_emit_parameter_debug_info (gfc_symbol *sym)
|| sym->attr.assign)
return;
+ is_class = (sym->ts.type == BT_CLASS) && CLASS_DATA (sym);
+ as = is_class ? (CLASS_DATA (sym)->as) : (sym->as);
+
if (sym->ts.type == BT_CHARACTER)
{
gfc_conv_const_charlen (sym->ts.u.cl);
@@ -5586,16 +5586,16 @@ gfc_emit_parameter_debug_info (gfc_symbol *sym)
else if (sym->ts.type == BT_DERIVED && sym->ts.u.derived->attr.alloc_comp)
return;
- if (sym->as)
+ if (as)
{
int n;
- if (sym->as->type != AS_EXPLICIT)
+ if (as->type != AS_EXPLICIT)
return;
- for (n = 0; n < sym->as->rank; n++)
- if (sym->as->lower[n]->expr_type != EXPR_CONSTANT
- || sym->as->upper[n] == NULL
- || sym->as->upper[n]->expr_type != EXPR_CONSTANT)
+ for (n = 0; n < as->rank; n++)
+ if (as->lower[n]->expr_type != EXPR_CONSTANT
+ || as->upper[n] == NULL
+ || as->upper[n]->expr_type != EXPR_CONSTANT)
return;
}
@@ -5620,10 +5620,7 @@ gfc_emit_parameter_debug_info (gfc_symbol *sym)
TREE_USED (decl) = 1;
if (DECL_CONTEXT (decl) && TREE_CODE (DECL_CONTEXT (decl)) == NAMESPACE_DECL)
TREE_PUBLIC (decl) = 1;
- DECL_INITIAL (decl) = gfc_conv_initializer (sym->value, &sym->ts,
- TREE_TYPE (decl),
- sym->attr.dimension,
- false, false);
+ DECL_INITIAL (decl) = gfc_conv_sym_initializer (decl, sym);
debug_hooks->early_global_decl (decl);
}
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index de406ad..6842207 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -256,6 +256,25 @@ gfc_class_vptr_get (tree decl)
}
+/* Try to find if a type is unlimited polymorphic. */
+
+bool
+gfc_class_unlimited_poly (tree type)
+{
+ tree len;
+
+ if (POINTER_TYPE_P (type))
+ type = TREE_TYPE (type);
+ if (TREE_CODE (type) != RECORD_TYPE)
+ return false;
+ if (!GFC_CLASS_TYPE_P (type))
+ return false;
+
+ len = gfc_advance_chain (TYPE_FIELDS (type), CLASS_LEN_FIELD);
+ return len != NULL_TREE;
+}
+
+
tree
gfc_class_len_get (tree decl)
{
@@ -7956,11 +7975,15 @@ gfc_conv_array_constructor_expr (gfc_se * se, gfc_expr * expr)
The other parameters describe the variable of the component being
initialized. EXPR may be null. */
-tree
-gfc_conv_initializer (gfc_expr * expr, gfc_typespec * ts, tree type,
- bool array, bool pointer, bool procptr)
+static tree
+gfc_conv_initializer_common (tree decl, gfc_expr * expr, gfc_typespec *ts, int rank,
+ bool allocatable, bool pointer, bool procptr)
{
gfc_se se;
+ tree type;
+ bool arrayish, is_null;
+
+ type = TREE_TYPE (decl);
if (flag_coarray != GFC_FCOARRAY_LIB && ts->type == BT_DERIVED
&& ts->u.derived->from_intmod == INTMOD_ISO_FORTRAN_ENV
@@ -7985,12 +8008,20 @@ gfc_conv_initializer (gfc_expr * expr, gfc_typespec * ts, tree type,
gcc_unreachable ();
}
- if (array && !procptr)
+ is_null = (expr && expr->expr_type == EXPR_NULL);
+
+ arrayish = ((TREE_CODE (type) == ARRAY_TYPE && GFC_ARRAY_TYPE_P (type))
+ || GFC_DESCRIPTOR_TYPE_P (type));
+
+ if (arrayish && !procptr)
{
tree ctor;
+
/* Arrays need special handling. */
- if (pointer)
- ctor = gfc_build_null_descriptor (type);
+ if (allocatable || is_null)
+ ctor = gfc_build_null_descriptor (type, rank);
+ else if (pointer)
+ ctor = gfc_build_init_descriptor (decl, rank, expr);
/* Special case assigning an array to zero. */
else if (is_zero_initializer_p (expr))
ctor = build_constructor (type, NULL);
@@ -7999,18 +8030,21 @@ gfc_conv_initializer (gfc_expr * expr, gfc_typespec * ts, tree type,
TREE_STATIC (ctor) = 1;
return ctor;
}
- else if (pointer || procptr)
+ else if (allocatable || pointer || procptr)
{
if (ts->type == BT_CLASS && !procptr)
{
gfc_init_se (&se, NULL);
- gfc_conv_structure (&se, gfc_class_initializer (ts, expr), 1);
+ gfc_conv_structure_initializer (&se,
+ gfc_class_initializer (ts, expr, pointer));
gcc_assert (TREE_CODE (se.expr) == CONSTRUCTOR);
TREE_STATIC (se.expr) = 1;
return se.expr;
}
- else if (!expr || expr->expr_type == EXPR_NULL)
+ else if ((allocatable && !procptr) || is_null)
return fold_convert (type, null_pointer_node);
+ else if (expr == NULL)
+ return NULL_TREE;
else
{
gfc_init_se (&se, NULL);
@@ -8027,10 +8061,11 @@ gfc_conv_initializer (gfc_expr * expr, gfc_typespec * ts, tree type,
case_bt_struct:
case BT_CLASS:
gfc_init_se (&se, NULL);
- if (ts->type == BT_CLASS && expr->expr_type == EXPR_NULL)
- gfc_conv_structure (&se, gfc_class_initializer (ts, expr), 1);
+ if (ts->type == BT_CLASS && is_null)
+ gfc_conv_structure_initializer (&se,
+ gfc_class_initializer (ts, expr, false));
else
- gfc_conv_structure (&se, expr, 1);
+ gfc_conv_structure_initializer (&se, expr);
gcc_assert (TREE_CODE (se.expr) == CONSTRUCTOR);
TREE_STATIC (se.expr) = 1;
return se.expr;
@@ -8053,6 +8088,65 @@ gfc_conv_initializer (gfc_expr * expr, gfc_typespec * ts, tree type,
}
}
+
+tree
+gfc_conv_sym_initializer (tree decl, gfc_symbol * sym)
+{
+ tree ctor;
+ symbol_attribute *attr;
+ gfc_array_spec *as;
+ bool is_class, is_pointer;
+ int rank;
+
+ is_class = (sym->ts.type == BT_CLASS) && CLASS_DATA (sym);
+ attr = is_class ? &(CLASS_DATA (sym)->attr) : &(sym->attr);
+ is_pointer = is_class ? attr->class_pointer : attr->pointer;
+ as = is_class ? (CLASS_DATA (sym)->as) : (sym->as);
+ rank = as ? as->rank : 0;
+
+ ctor = gfc_conv_initializer_common (decl, sym->value, &sym->ts, rank,
+ attr->allocatable, is_pointer,
+ sym->attr.proc_pointer);
+ return ctor;
+}
+
+
+tree
+gfc_conv_comp_initializer (tree decl, gfc_component * c, gfc_expr * expr)
+{
+ tree ctor;
+ symbol_attribute *attr;
+ gfc_array_spec *as;
+ bool is_class, is_pointer;
+ int rank;
+
+ is_class = (c->ts.type == BT_CLASS) && CLASS_DATA (c);
+ attr = is_class ? &(CLASS_DATA (c)->attr) : &(c->attr);
+ is_pointer = is_class ? attr->class_pointer : attr->pointer;
+ as = is_class ? (CLASS_DATA (c)->as) : (c->as);
+ rank = as ? as->rank : 0;
+
+ ctor = gfc_conv_initializer_common (decl, expr, &c->ts, rank,
+ attr->allocatable, is_pointer,
+ c->attr.proc_pointer);
+ return ctor;
+}
+
+
+tree
+gfc_conv_expr_initializer (tree decl, gfc_expr * expr)
+{
+ tree ctor;
+ symbol_attribute attr;
+
+ attr = gfc_expr_attr (expr);
+ ctor = gfc_conv_initializer_common (decl, expr, &expr->ts, expr->rank,
+ attr.allocatable, attr.pointer,
+ attr.proc_pointer);
+ return ctor;
+}
+
+
static tree
gfc_trans_subarray_assign (tree dest, gfc_component * cm, gfc_expr * expr)
{
@@ -8474,8 +8568,7 @@ gfc_trans_subcomponent_assign (tree dest, gfc_component * cm, gfc_expr * expr,
{
/* NULL initialization for CLASS components. */
tmp = gfc_trans_structure_assign (dest,
- gfc_class_initializer (&cm->ts, expr),
- false);
+ gfc_class_initializer (&cm->ts, expr, cm->attr.class_pointer), false);
gfc_add_expr_to_block (&block, tmp);
}
else if ((cm->attr.dimension || cm->attr.codimension)
@@ -8834,56 +8927,57 @@ gfc_conv_union_initializer (vec<constructor_elt, va_gc> *v,
/* Add the map initializer on top. */
if (ctor != NULL && ctor->expr != NULL)
{
+ tree val;
+
gcc_assert (ctor->expr->expr_type == EXPR_STRUCTURE);
- tree val = gfc_conv_initializer (ctor->expr, &un->ts,
- TREE_TYPE (un->backend_decl),
- un->attr.dimension, un->attr.pointer,
- un->attr.proc_pointer);
+ val = gfc_conv_comp_initializer (un->backend_decl, un, ctor->expr);
CONSTRUCTOR_APPEND_ELT (v, un->backend_decl, val);
}
}
+/* Build an expression for a constructor. */
+
+static void
+gfc_conv_structure (gfc_se * se, gfc_expr * expr)
+{
+ tree type;
+ tree tmp;
+
+ gcc_assert (se->ss == NULL);
+ gcc_assert (expr->expr_type == EXPR_STRUCTURE);
+ type = gfc_typenode_for_spec (&expr->ts);
+
+ /* Create a temporary variable and fill it in. */
+ se->expr = gfc_create_var (type, expr->ts.u.derived->name);
+ /* The symtree in expr is NULL, if the code to generate is for
+ initializing the static members only. */
+ tmp = gfc_trans_structure_assign (se->expr, expr, expr->symtree != NULL,
+ se->want_coarray);
+ gfc_add_expr_to_block (&se->pre, tmp);
+ return;
+}
+
+
/* Build an expression for a constructor. If init is nonzero then
this is part of a static variable initializer. */
void
-gfc_conv_structure (gfc_se * se, gfc_expr * expr, int init)
+gfc_conv_structure_initializer (gfc_se * se, gfc_expr * expr)
{
gfc_constructor *c;
gfc_component *cm;
tree val;
tree type;
- tree tmp;
vec<constructor_elt, va_gc> *v = NULL;
gcc_assert (se->ss == NULL);
gcc_assert (expr->expr_type == EXPR_STRUCTURE);
- type = gfc_typenode_for_spec (&expr->ts);
-
- if (!init)
- {
- /* Create a temporary variable and fill it in. */
- se->expr = gfc_create_var (type, expr->ts.u.derived->name);
- /* The symtree in expr is NULL, if the code to generate is for
- initializing the static members only. */
- tmp = gfc_trans_structure_assign (se->expr, expr, expr->symtree != NULL,
- se->want_coarray);
- gfc_add_expr_to_block (&se->pre, tmp);
- return;
- }
cm = expr->ts.u.derived->components;
for (c = gfc_constructor_first (expr->value.constructor);
c; c = gfc_constructor_next (c), cm = cm->next)
{
- /* Skip absent members in default initializers and allocatable
- components. Although the latter have a default initializer
- of EXPR_NULL,... by default, the static nullify is not needed
- since this is done every time we come into scope. */
- if (!c->expr || (cm->attr.allocatable && cm->attr.flavor != FL_PROCEDURE))
- continue;
-
if (cm->initializer && cm->initializer->expr_type != EXPR_NULL
&& strcmp (cm->name, "_extends") == 0
&& cm->initializer->symtree)
@@ -8903,27 +8997,39 @@ gfc_conv_structure (gfc_se * se, gfc_expr * expr, int init)
val));
}
else if (cm->ts.type == BT_INTEGER && strcmp (cm->name, "_len") == 0)
- CONSTRUCTOR_APPEND_ELT (v, cm->backend_decl,
- fold_convert (TREE_TYPE (cm->backend_decl),
- integer_zero_node));
+ {
+ tree len = integer_zero_node;
+
+ if (c->expr && c->expr->ts.type == BT_CHARACTER)
+ {
+ gcc_assert (c->expr->ts.u.cl);
+ if (c->expr->ts.u.cl->backend_decl)
+ len = c->expr->ts.u.cl->backend_decl;
+ if (!TREE_CONSTANT (len) || TREE_SIDE_EFFECTS (len))
+ if (DECL_INITIAL (len))
+ len = DECL_INITIAL (len);
+ }
+
+ len = fold_convert (TREE_TYPE (cm->backend_decl), len);
+ CONSTRUCTOR_APPEND_ELT (v, cm->backend_decl, len);
+ }
else if (cm->ts.type == BT_UNION)
gfc_conv_union_initializer (v, cm, c->expr);
else
{
- val = gfc_conv_initializer (c->expr, &cm->ts,
- TREE_TYPE (cm->backend_decl),
- cm->attr.dimension, cm->attr.pointer,
- cm->attr.proc_pointer);
- val = unshare_expr_without_location (val);
-
- /* Append it to the constructor list. */
- CONSTRUCTOR_APPEND_ELT (v, cm->backend_decl, val);
+ val = gfc_conv_comp_initializer (cm->backend_decl, cm, c->expr);
+ if (val)
+ {
+ val = unshare_expr_without_location (val);
+ /* Append it to the constructor list. */
+ CONSTRUCTOR_APPEND_ELT (v, cm->backend_decl, val);
+ }
}
}
+ type = gfc_typenode_for_spec (&expr->ts);
se->expr = build_constructor (type, v);
- if (init)
- TREE_CONSTANT (se->expr) = 1;
+ TREE_CONSTANT (se->expr) = 1;
}
@@ -9034,7 +9140,7 @@ gfc_conv_expr (gfc_se * se, gfc_expr * expr)
break;
case EXPR_STRUCTURE:
- gfc_conv_structure (se, expr, 0);
+ gfc_conv_structure (se, expr);
break;
case EXPR_ARRAY:
diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c
index 5582e40..c525b9a 100644
--- a/gcc/fortran/trans-types.c
+++ b/gcc/fortran/trans-types.c
@@ -1480,7 +1480,7 @@ gfc_get_desc_dim_type (void)
unknown cases abort. */
tree
-gfc_get_dtype_rank_type (int rank, tree etype)
+gfc_get_dtype_rank_type (int rank, tree etype, bool static_flag)
{
tree ptype;
tree size;
@@ -1558,6 +1558,14 @@ gfc_get_dtype_rank_type (int rank, tree etype)
gcc_assert (size);
STRIP_NOPS (size);
+ if (TREE_CODE (size) == SAVE_EXPR)
+ size = TREE_OPERAND (size, 0);
+ STRIP_NOPS (size);
+ if (static_flag && (!TREE_CONSTANT (size) || TREE_SIDE_EFFECTS (size)))
+ size = (DECL_INITIAL (size))
+ ? (DECL_INITIAL (size)) : (integer_zero_node);
+
+ STRIP_NOPS (size);
size = fold_convert (size_type_node, size);
tmp = get_dtype_type_node ();
field = gfc_advance_chain (TYPE_FIELDS (tmp),
diff --git a/gcc/fortran/trans-types.h b/gcc/fortran/trans-types.h
index 3b45ce2..e6243e6 100644
--- a/gcc/fortran/trans-types.h
+++ b/gcc/fortran/trans-types.h
@@ -113,7 +113,7 @@ int gfc_return_by_reference (gfc_symbol *);
int gfc_is_nodesc_array (gfc_symbol *);
/* Return the DTYPE for an array. */
-tree gfc_get_dtype_rank_type (int, tree);
+tree gfc_get_dtype_rank_type (int, tree, bool static_flag = false);
tree gfc_get_dtype (tree, int *rank = NULL);
tree gfc_get_ppc_type (gfc_component *);
diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c
index f26e91b..27efdda 100644
--- a/gcc/fortran/trans.c
+++ b/gcc/fortran/trans.c
@@ -1774,6 +1774,89 @@ gfc_call_realloc (stmtblock_t * block, tree mem, tree size)
}
+/* Simple equality check. */
+
+bool
+tree_ref_equal (tree a, tree b)
+{
+ int len, idx;
+
+ if (a == b)
+ return true;
+ if (!a || !b)
+ return false;
+ len = TREE_OPERAND_LENGTH (a);
+ if (len == 0 || len != TREE_OPERAND_LENGTH (b))
+ return false;
+ for (idx=0; idx<len; idx++)
+ if (!tree_ref_equal (TREE_OPERAND (a, idx), TREE_OPERAND (b, idx)))
+ return false;
+ return true;
+}
+
+/* Get RHS for given LHS in a MODIFY_EXPR. */
+
+tree
+gfc_get_expr_from_chain (tree base, tree chain)
+{
+ tree stmt;
+
+ switch (TREE_CODE (chain))
+ {
+ case MODIFY_EXPR:
+ {
+ stmt = chain;
+ gcc_assert (TREE_OPERAND_LENGTH (stmt) == 2);
+ if (tree_ref_equal (base, TREE_OPERAND (stmt, 0)))
+ return TREE_OPERAND (stmt, 1);
+ break;
+ }
+ case STATEMENT_LIST:
+ {
+ tree_stmt_iterator iter;
+
+ for (iter = tsi_start (chain); !tsi_end_p (iter); tsi_next (&iter))
+ {
+ stmt = tsi_stmt (iter);
+ if (TREE_CODE (stmt) != MODIFY_EXPR)
+ continue;
+ gcc_assert (TREE_OPERAND_LENGTH (stmt) == 2);
+ if (tree_ref_equal (base, TREE_OPERAND (stmt, 0)))
+ return TREE_OPERAND (stmt, 1);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return NULL_TREE;
+}
+
+
+/* Get value from CONSTRUCTOR. */
+
+tree
+gfc_get_expr_from_ctor (tree ctor, int index)
+{
+ tree type, field, findx, value;
+ unsigned idx;
+
+ gcc_assert (TREE_CODE (ctor) == CONSTRUCTOR);
+ type = TREE_TYPE (ctor);
+
+ field = gfc_advance_chain (TYPE_FIELDS (type), index);
+ gcc_assert (field != NULL_TREE);
+ FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, findx, value)
+ {
+ value = (field == findx) ? (STRIP_NOPS (value)) : (NULL_TREE);
+ if (value)
+ break;
+ }
+
+ return value;
+}
+
+
/* Add an expression to another one, either at the front or the back. */
static void
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index d1d4a1d..2d8ef7f 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -424,6 +424,7 @@ gfc_wrapped_block;
tree gfc_class_set_static_fields (tree, tree, tree);
tree gfc_class_data_get (tree);
tree gfc_class_vptr_get (tree);
+bool gfc_class_unlimited_poly (tree);
tree gfc_class_len_get (tree);
tree gfc_class_len_or_zero_get (tree);
tree gfc_resize_class_size_with_len (stmtblock_t *, tree, tree);
@@ -566,7 +567,7 @@ tree gfc_trans_scalar_assign (gfc_se *, gfc_se *, gfc_typespec, bool, bool,
void gfc_trans_common (gfc_namespace *);
/* Translate a derived type constructor. */
-void gfc_conv_structure (gfc_se *, gfc_expr *, int);
+void gfc_conv_structure_initializer (gfc_se *, gfc_expr *);
/* Return an expression which determines if a dummy parameter is present. */
tree gfc_conv_expr_present (gfc_symbol *, bool use_saved_decl = false);
@@ -590,6 +591,10 @@ void gfc_conv_string_length (gfc_charlen *, gfc_expr *, stmtblock_t *);
/* Ensure type sizes can be gimplified. */
void gfc_trans_vla_type_sizes (gfc_symbol *, stmtblock_t *);
+/* Get RHS from LHS in a list of statements. */
+tree gfc_get_expr_from_chain (tree, tree);
+/* Get value from CONSTRUCTOR. */
+tree gfc_get_expr_from_ctor (tree, int);
/* Add an expression to the end of a block. */
void gfc_add_expr_to_block (stmtblock_t *, tree);
/* Add an expression to the beginning of a block. */
@@ -654,7 +659,9 @@ bool gfc_get_module_backend_decl (gfc_symbol *);
tree gfc_get_symbol_decl (gfc_symbol *);
/* Build a static initializer. */
-tree gfc_conv_initializer (gfc_expr *, gfc_typespec *, tree, bool, bool, bool);
+tree gfc_conv_sym_initializer (tree, gfc_symbol *);
+tree gfc_conv_comp_initializer (tree, gfc_component *, gfc_expr *);
+tree gfc_conv_expr_initializer (tree, gfc_expr *);
/* Assign a default initializer to a derived type. */
void gfc_init_default_dt (gfc_symbol *, stmtblock_t *, bool);
diff --git a/gcc/testsuite/gfortran.dg/class_allocate_14.f90 b/gcc/testsuite/gfortran.dg/class_allocate_14.f90
index d251477..8914365 100644
--- a/gcc/testsuite/gfortran.dg/class_allocate_14.f90
+++ b/gcc/testsuite/gfortran.dg/class_allocate_14.f90
@@ -25,6 +25,6 @@ call sub()
call sub2()
end
-! { dg-final { scan-tree-dump-times "static struct __class_m_T_1_0a b = {._data={.data=0B}, ._vptr=&__vtab_m_T};" 1 "original" } }
+! { dg-final { scan-tree-dump-times "static struct __class_m_T_1_0a b = {._data={.data=0B, .dtype={.elem_len=4, .rank=1, .type=5}}, ._vptr=&__vtab_m_T};" 1 "original" } }
! { dg-final { scan-tree-dump-times "static struct __class_m_T_a y = {._data=0B, ._vptr=&__vtab_m_T};" 1 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/init_flag_19.f03 b/gcc/testsuite/gfortran.dg/init_flag_19.f03
index bbcee8a..39dbc29 100644
--- a/gcc/testsuite/gfortran.dg/init_flag_19.f03
+++ b/gcc/testsuite/gfortran.dg/init_flag_19.f03
@@ -30,7 +30,7 @@ end
! { dg-final { scan-tree-dump-times "\.ival *= *0" 1 "original" } }
! { dg-final { scan-tree-dump-times "\.rval *= *0" 1 "original" } }
! { dg-final { scan-tree-dump-times "\.bt_ptr *= *0" 1 "original" } }
-! { dg-final { scan-tree-dump-times "\.bt_alloc *= *0" 1 "original" } }
-! { dg-final { scan-tree-dump-times "\.class_alloc(?: *= *\{)?\._data *= *0" 1 "original" } }
-! { dg-final { scan-tree-dump-times "\.class_ptr(?: *= *\{)?\._data *= *0" 1 "original" } }
-! { dg-final { scan-tree-dump-times "calloc(?: *= *\{)?\._data *= *0" 1 "original" } }
+! { dg-final { scan-tree-dump-times "\.bt_alloc *= *0" 2 "original" } }
+! { dg-final { scan-tree-dump-times "\.class_alloc(?: *= *\{)?\._data *= *0" 2 "original" } }
+! { dg-final { scan-tree-dump-times "\.class_ptr *= *\{\._data *= *0" 1 "original" } }
+! { dg-final { scan-tree-dump-times "calloc(?: *= *\{)?\._data *= *0" 2 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/init_workout.f90 b/gcc/testsuite/gfortran.dg/init_workout.f90
new file mode 100644
index 0000000..528624b
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/init_workout.f90
@@ -0,0 +1,306 @@
+! { dg-do run }
+!
+! Test the fix for PR101047/101048
+!
+
+program save_p
+
+ implicit none
+
+ integer :: i
+ integer, parameter :: n = 11
+ integer, parameter :: m = 7
+ integer, parameter :: r = 3
+ integer, parameter :: s = 7
+ integer, parameter :: u(*) = [(i, i=1,n)]
+ character, parameter :: v(*) = [(achar(i+iachar("A")-1), i=1,n)]
+ character(len=m), parameter :: w(*) = [(repeat(achar(i+iachar("A")-1), m), i=1,n)]
+
+ type :: foo_t
+ integer :: i
+ end type foo_t
+
+ type, extends(foo_t) :: bar_t
+ integer :: a(n)
+ end type bar_t
+
+ integer, target :: a(n) = u
+ integer, save, pointer :: pi1(:)
+ integer, pointer :: pi2(:) =>null()
+ integer, pointer :: pi3(:) =>a
+ integer, pointer :: pi4(:) =>a(r:s)
+
+ character, target :: c1(n) = v
+ character, save, pointer :: pc1(:)
+ character, pointer :: pc2(:) =>null()
+ character, pointer :: pc3(:) =>c1
+ character, pointer :: pc4(:) =>c1(r:s)
+
+ character(len=m), target :: cl(n) = w
+ character(len=m), save, pointer :: pl1(:)
+ character(len=m), pointer :: pl2(:) =>null()
+ character(len=m), pointer :: pl3(:) =>cl
+ character(len=m), pointer :: pl4(:) =>cl(r:s)
+
+ character(len=:), save, pointer :: pd1(:)
+ character(len=:), pointer :: pd2(:) =>null()
+ character(len=:), pointer :: pd3(:) =>c1
+ character(len=:), pointer :: pd4(:) =>c1(r:s)
+ character(len=:), pointer :: pd5(:) =>cl
+ character(len=:), pointer :: pd6(:) =>cl(r:s)
+
+ type(foo_t), target :: f(n) = [(foo_t(i), i=1,n)]
+ type(foo_t), save, pointer :: pf1(:)
+ type(foo_t), pointer :: pf2(:) =>null()
+ type(foo_t), pointer :: pf3(:) =>f
+ type(foo_t), pointer :: pf4(:) =>f(r:s)
+
+ type(bar_t), target :: b(n) = [(bar_t(i, i*u), i=1,n)]
+ type(bar_t), save, pointer :: pb1(:)
+ type(bar_t), pointer :: pb2(:) =>null()
+ type(bar_t), pointer :: pb3(:) =>b
+ type(bar_t), pointer :: pb4(:) =>b(r:s)
+
+ class(foo_t), save, pointer :: pf5(:)
+ class(foo_t), pointer :: pf6(:) =>null()
+ class(foo_t), pointer :: pf7(:) =>f
+ class(foo_t), pointer :: pf8(:) =>f(r:s)
+ class(foo_t), pointer :: pf9(:) =>b
+ class(foo_t), pointer :: pfa(:) =>b(r:s)
+
+ class(bar_t), save, pointer :: pb5(:)
+ class(bar_t), pointer :: pb6(:) =>null()
+ class(bar_t), pointer :: pb7(:) =>b
+ class(bar_t), pointer :: pb8(:) =>b(r:s)
+
+ class(*), save, pointer :: pu1(:)
+ class(*), pointer :: pu2(:) =>null()
+ class(*), pointer :: pu3(:) =>a
+ class(*), pointer :: pu4(:) =>a(r:s)
+ class(*), pointer :: pu5(:) =>c1
+ class(*), pointer :: pu6(:) =>c1(r:s)
+ class(*), pointer :: pu7(:) =>cl
+ class(*), pointer :: pu8(:) =>cl(r:s)
+ class(*), pointer :: pu9(:) =>f
+ class(*), pointer :: pua(:) =>f(r:s)
+ class(*), pointer :: pub(:) =>b
+ class(*), pointer :: puc(:) =>b(r:s)
+
+ nullify(pi1)
+ if(associated(pi2)) stop 1
+ !
+ if(.not.associated(pi3)) stop 2
+ if(.not.associated(pi3, a)) stop 3
+ if(any(pi3/=u)) stop 4
+ !
+ if(.not.associated(pi4)) stop 5
+ if(.not.associated(pi4, a(r:s))) stop 6
+ if(any(pi4/=u(r:s))) stop 7
+ !
+ nullify(pc1)
+ if(associated(pc2)) stop 8
+ !
+ if(.not.associated(pc3)) stop 9
+ if(.not.associated(pc3, c1)) stop 10
+ if(any(pc3/=v)) stop 11
+ !
+ if(.not.associated(pc4)) stop 12
+ if(.not.associated(pc4, c1(r:s))) stop 13
+ if(any(pc4/=v(r:s))) stop 14
+ !
+ nullify(pl1)
+ if(associated(pl2)) stop 15
+ !
+ if(.not.associated(pl3)) stop 16
+ if(.not.associated(pl3, cl)) stop 17
+ if(any(pl3/=w)) stop 18
+ !
+ if(.not.associated(pl4)) stop 19
+ if(.not.associated(pl4, cl(r:s))) stop 20
+ if(any(pl4/=w(r:s))) stop 21
+ !
+ nullify(pd1)
+ if(associated(pd2)) stop 22
+ !
+ if(.not.associated(pd3)) stop 23
+ if(.not.associated(pd3, c1)) stop 24
+ if(any(pd3/=v)) stop 25
+ !
+ if(.not.associated(pd4)) stop 26
+ if(.not.associated(pd4, c1(r:s))) stop 27
+ if(any(pd4/=v(r:s))) stop 28
+ !
+ if(.not.associated(pd5)) stop 29
+ if(.not.associated(pd5, cl)) stop 30
+ if(any(pd5/=w)) stop 31
+ !
+ if(.not.associated(pd6)) stop 32
+ if(.not.associated(pd6, cl(r:s))) stop 33
+ if(any(pd6/=w(r:s))) stop 34
+ !
+ nullify(pf1)
+ if(associated(pf2)) stop 35
+ !
+ if(.not.associated(pf3)) stop 36
+ if(.not.associated(pf3, f)) stop 37
+ if(any(pf3(:)%i/=u)) stop 38
+ !
+ if(.not.associated(pf4)) stop 39
+ if(.not.associated(pf4, f(r:s))) stop 40
+ if(any(pf4(:)%i/=u(r:s))) stop 41
+ !
+ nullify(pb1)
+ if(associated(pb2)) stop 42
+ !
+ if(.not.associated(pb3)) stop 43
+ if(.not.associated(pb3, b)) stop 44
+ if(any(pb3(:)%i/=u)) stop 45
+ do i = 1, n
+ if(any(pb3(i)%a/=i*u)) stop 46
+ end do
+ !
+ if(.not.associated(pb4)) stop 47
+ if(.not.associated(pb4, b(r:s))) stop 48
+ if(any(pb4(:)%i/=u(r:s))) stop 49
+ do i = 1, s-r+1
+ if(any(pb4(i)%a/=(r+i-1)*u)) stop 50
+ end do
+ !
+ nullify(pf5)
+ if(associated(pf6)) stop 51
+ !
+ if(.not.associated(pf7)) stop 52
+ if(.not.associated(pf7, f)) stop 53
+ if(any(pf7(:)%i/=u)) stop 54
+ !
+ if(.not.associated(pf8)) stop 55
+ if(.not.associated(pf8, f(r:s))) stop 56
+ if(any(pf8(:)%i/=u(r:s))) stop 57
+ !
+ if(.not.associated(pf9)) stop 58
+ if(.not.associated(pf9, b)) stop 59
+ if(any(pf9(:)%i/=u)) stop 60
+ !
+ if(.not.associated(pfa)) stop 61
+ if(.not.associated(pfa, b(r:s))) stop 62
+ if(any(pfa(:)%i/=u(r:s))) stop 63
+ !
+ nullify(pb5)
+ if(associated(pb6)) stop 64
+ !
+ if(.not.associated(pb7)) stop 65
+ if(.not.associated(pb7, b)) stop 66
+ if(any(pb7(:)%i/=u)) stop 67
+ do i = 1, n
+ if(any(pb7(i)%a/=i*u)) stop 68
+ end do
+ !
+ if(.not.associated(pb8)) stop 69
+ if(.not.associated(pb8, b(r:s))) stop 70
+ if(any(pb8(:)%i/=u(r:s))) stop 71
+ do i = 1, s-r+1
+ if(any(pb8(i)%a/=(r+i-1)*u)) stop 72
+ end do
+ !
+ nullify(pu1)
+ if(associated(pu2)) stop 73
+ !
+ if(.not.associated(pu3)) stop 29
+ if(.not.associated(pu3, a)) stop 74
+ select type(pu3)
+ type is(integer)
+ if(any(pu3/=a)) stop 75
+ class default
+ stop 76
+ end select
+ !
+ if(.not.associated(pu4)) stop 77
+ if(.not.associated(pu4, a(r:s))) stop 78
+ select type(pu4)
+ type is(integer)
+ if(any(pu4/=a(r:s))) stop 79
+ class default
+ stop 80
+ end select
+ !
+ if(.not.associated(pu5)) stop 81
+ if(.not.associated(pu5, c1)) stop 82
+ select type(pu5)
+ type is(character(len=*))
+ if(any(pu5/=c1)) stop 83
+ class default
+ stop 84
+ end select
+ !
+ if(.not.associated(pu6)) stop 85
+ if(.not.associated(pu6, c1(r:s))) stop 86
+ select type(pu6)
+ type is(character(len=*))
+ if(any(pu6/=c1(r:s))) stop 87
+ class default
+ stop 88
+ end select
+ !
+ if(.not.associated(pu7)) stop 89
+ if(.not.associated(pu7, cl)) stop 90
+ select type(pu7)
+ type is(character(len=*))
+ if(any(pu7/=cl)) stop 91
+ class default
+ stop 91
+ end select
+ !
+ if(.not.associated(pu8)) stop 92
+ if(.not.associated(pu8, cl(r:s))) stop 93
+ select type(pu8)
+ type is(character(len=*))
+ if(any(pu8/=cl(r:s))) stop 94
+ class default
+ stop 95
+ end select
+ !
+ if(.not.associated(pu9)) stop 95
+ if(.not.associated(pu9, f)) stop 96
+ select type(pu9)
+ type is(foo_t)
+ if(any(pu9(:)%i/=u)) stop 97
+ class default
+ stop 98
+ end select
+ !
+ if(.not.associated(pua)) stop 99
+ if(.not.associated(pua, f(r:s))) stop 100
+ select type(pua)
+ type is(foo_t)
+ if(any(pua(:)%i/=u(r:s))) stop 101
+ class default
+ stop 102
+ end select
+ !
+ if(.not.associated(pub)) stop 102
+ if(.not.associated(pub, b)) stop 103
+ select type(pub)
+ type is(bar_t)
+ if(any(pub(:)%i/=u)) stop 104
+ do i = 1, n
+ if(any(pub(i)%a/=i*u)) stop 105
+ end do
+ class default
+ stop 98
+ end select
+ !
+ if(.not.associated(puc)) stop 106
+ if(.not.associated(puc, b(r:s))) stop 107
+ select type(puc)
+ type is(bar_t)
+ if(any(puc(:)%i/=u(r:s))) stop 108
+ do i = 1, s-r+1
+ if(any(puc(i)%a/=(r+i-1)*u)) stop 109
+ end do
+ class default
+ stop 110
+ end select
+ stop
+
+end program save_p
+