[Patch, fortran] PR121384 - Wrongly initialized associate array descriptor when the target is wrapped in parenthesis

Paul Richard Thomas <[email protected]>
Newsgroups gmane.comp.gcc.patches,gmane.comp.gcc.fortran
Message-ID <CAGkQGiK6nmyc7LVmN7-8SafPpDY8gfXy0S_-TR_hRZRnCUi+xw@mail.gmail.com>
This one is actually very straightforward. Most of the patch consists
of moves of helper functions to allow a temporary to be constructed
for the selector.

Regtests on FC43/x86_64 - OK for mainline?

Once 17-branch is open, I will see if an extension to this patch can
be used to eliminate a lot of code in trans-stmt.cc.

Paul
submit.diff (text/x-patch, 20.3 KB)
From 691c7503f509423c3ffedbfa0bda5207281951bd Mon Sep 17 00:00:00 2001
From: Paul Thomas <[email protected]>
Date: Fri, 17 Apr 2026 06:00:03 +0100
Subject: [PATCH] Fortran: Fix wrongly initialized associate-name descriptor
 [PR121384]

2026-04-17  Paul Thomas  <[email protected]>

gcc/fortran
	PR fortran/121384
	* resolve.cc (add_comp_ref, build_assignment,
	add_code_to_chain, get_temp_from_expr,
	add_temp_assign_before_call) : Move to top of file and delete
	prototypes.
	(resolve_block_construct): Generate a temporary for subref
	array selectors enclosed in parantheses.

gcc/testsuite
	PR fortran/121384
	* gfortran.dg/associate_79.f90: New test.
---
 gcc/fortran/resolve.cc                     | 556 +++++++++++----------
 gcc/testsuite/gfortran.dg/associate_79.f90 |  43 ++
 2 files changed, 338 insertions(+), 261 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/associate_79.f90

diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index a5d9add9d2f..bf078a40206 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -204,6 +204,264 @@ check_proc_interface (gfc_symbol *ifc, locus *where)
 static void resolve_symbol (gfc_symbol *sym);
 
 
+/*************Helper functions for modifying code*********************/
+
+/* Add a component reference onto an expression.  */
+
+static void
+add_comp_ref (gfc_expr *e, gfc_component *c)
+{
+  gfc_ref **ref;
+  ref = &(e->ref);
+  while (*ref)
+    ref = &((*ref)->next);
+  *ref = gfc_get_ref ();
+  (*ref)->type = REF_COMPONENT;
+  (*ref)->u.c.sym = e->ts.u.derived;
+  (*ref)->u.c.component = c;
+  e->ts = c->ts;
+
+  /* Add a full array ref, as necessary.  */
+  if (c->as)
+    {
+      gfc_add_full_array_ref (e, c->as);
+      e->rank = c->as->rank;
+      e->corank = c->as->corank;
+    }
+}
+
+
+/* Build an assignment.  Keep the argument 'op' for future use, so that
+   pointer assignments can be made.  */
+
+static gfc_code *
+build_assignment (gfc_exec_op op, gfc_expr *expr1, gfc_expr *expr2,
+		  gfc_component *comp1, gfc_component *comp2, locus loc)
+{
+  gfc_code *this_code;
+
+  this_code = gfc_get_code (op);
+  this_code->next = NULL;
+  this_code->expr1 = gfc_copy_expr (expr1);
+  this_code->expr2 = gfc_copy_expr (expr2);
+  this_code->loc = loc;
+  if (comp1 && comp2)
+    {
+      add_comp_ref (this_code->expr1, comp1);
+      add_comp_ref (this_code->expr2, comp2);
+    }
+
+  return this_code;
+}
+
+
+/* Makes a temporary variable expression based on the characteristics of
+   a given variable expression.  If allocatable is set, the temporary is
+   unconditionally allocatable*/
+
+static gfc_expr*
+get_temp_from_expr (gfc_expr *e, gfc_namespace *ns,
+		    bool allocatable = false)
+{
+  static int serial = 0;
+  char name[GFC_MAX_SYMBOL_LEN];
+  gfc_symtree *tmp;
+  gfc_array_spec *as;
+  gfc_array_ref *aref;
+  gfc_ref *ref;
+
+  sprintf (name, GFC_PREFIX("DA%d"), serial++);
+  gfc_get_sym_tree (name, ns, &tmp, false);
+  gfc_add_type (tmp->n.sym, &e->ts, NULL);
+
+  if (e->expr_type == EXPR_CONSTANT && e->ts.type == BT_CHARACTER)
+    tmp->n.sym->ts.u.cl->length = gfc_get_int_expr (gfc_charlen_int_kind,
+						    NULL,
+						    e->value.character.length);
+
+  as = NULL;
+  ref = NULL;
+  aref = NULL;
+
+  /* Obtain the arrayspec for the temporary.  */
+   if (e->rank && e->expr_type != EXPR_ARRAY
+       && e->expr_type != EXPR_FUNCTION
+       && e->expr_type != EXPR_OP)
+    {
+      aref = gfc_find_array_ref (e);
+      if (e->expr_type == EXPR_VARIABLE
+	  && e->symtree->n.sym->as == aref->as)
+	as = aref->as;
+      else
+	{
+	  for (ref = e->ref; ref; ref = ref->next)
+	    if (ref->type == REF_COMPONENT
+		&& ref->u.c.component->as == aref->as)
+	      {
+		as = aref->as;
+		break;
+	      }
+	}
+    }
+
+  /* Add the attributes and the arrayspec to the temporary.  */
+  tmp->n.sym->attr = gfc_expr_attr (e);
+  tmp->n.sym->attr.function = 0;
+  tmp->n.sym->attr.proc_pointer = 0;
+  tmp->n.sym->attr.result = 0;
+  tmp->n.sym->attr.flavor = FL_VARIABLE;
+  tmp->n.sym->attr.dummy = 0;
+  tmp->n.sym->attr.use_assoc = 0;
+  tmp->n.sym->attr.intent = INTENT_UNKNOWN;
+
+
+  if (as && !allocatable)
+    {
+      tmp->n.sym->as = gfc_copy_array_spec (as);
+      if (!ref)
+	ref = e->ref;
+      if (as->type == AS_DEFERRED)
+	tmp->n.sym->attr.allocatable = 1;
+    }
+  else if ((e->rank || e->corank)
+	   && (e->expr_type == EXPR_ARRAY || e->expr_type == EXPR_FUNCTION
+	       || e->expr_type == EXPR_OP || allocatable))
+    {
+      tmp->n.sym->as = gfc_get_array_spec ();
+      tmp->n.sym->as->type = AS_DEFERRED;
+      tmp->n.sym->as->rank = e->rank;
+      tmp->n.sym->as->corank = e->corank;
+      tmp->n.sym->attr.allocatable = 1;
+      tmp->n.sym->attr.dimension = e->rank ? 1 : 0;
+      tmp->n.sym->attr.codimension = e->corank ? 1 : 0;
+    }
+  else
+    tmp->n.sym->attr.dimension = 0;
+
+  gfc_set_sym_referenced (tmp->n.sym);
+  gfc_commit_symbol (tmp->n.sym);
+  e = gfc_lval_expr_from_sym (tmp->n.sym);
+
+  /* Should the lhs be a section, use its array ref for the
+     temporary expression.  */
+  if (aref && aref->type != AR_FULL && !allocatable)
+    {
+      gfc_free_ref_list (e->ref);
+      e->ref = gfc_copy_ref (ref);
+    }
+  return e;
+}
+
+
+/* Helper function to take an argument in a subroutine call with a dependency
+   on another argument, copy it to an allocatable temporary and use the
+   temporary in the call expression. The new code is embedded in a block to
+   ensure local, automatic deallocation.  */
+
+static void
+add_temp_assign_before_call (gfc_code *code, gfc_namespace *ns,
+			     gfc_expr **rhsptr)
+{
+  gfc_namespace *block_ns;
+  gfc_expr *tmp_var;
+
+  /* Wrap the new code in a block so that the temporary is deallocated.  */
+  block_ns = gfc_build_block_ns (ns);
+
+  /* As it stands, the block_ns does not not stand up to resolution because the
+     the assignment would be converted to a call and, in any case, the modified
+     call fails in gfc_check_conformance.  */
+  block_ns->resolved = 1;
+
+  /* Assign the original expression to the temporary.  */
+  tmp_var = get_temp_from_expr (*rhsptr, block_ns, true);
+  block_ns->code = build_assignment (EXEC_ASSIGN, tmp_var, *rhsptr,
+				     NULL, NULL, (*rhsptr)->where);
+
+  /* Transfer the call to the block and terminate block code.  */
+  *rhsptr = gfc_copy_expr (tmp_var);
+  block_ns->code->next = gfc_get_code (EXEC_NOP);
+  *(block_ns->code->next) = *code;
+  block_ns->code->next->next = NULL;
+
+  /* Convert the original code to execute the block.  */
+  code->op = EXEC_BLOCK;
+  code->ext.block.ns = block_ns;
+  code->ext.block.assoc = NULL;
+  code->expr1 = code->expr2 = NULL;
+}
+
+
+/* Add one line of code to the code chain, making sure that 'head' and
+   'tail' are appropriately updated.  */
+
+static void
+add_code_to_chain (gfc_code **this_code, gfc_code **head, gfc_code **tail)
+{
+  gcc_assert (this_code);
+  if (*head == NULL)
+    *head = *tail = *this_code;
+  else
+    *tail = gfc_append_code (*tail, *this_code);
+  *this_code = NULL;
+}
+
+
+/* Generate a final call from a variable expression  */
+
+static void
+generate_final_call (gfc_expr *tmp_expr, gfc_code **head, gfc_code **tail)
+{
+  gfc_code *this_code;
+  gfc_expr *final_expr = NULL;
+  gfc_expr *size_expr;
+  gfc_expr *fini_coarray;
+
+  gcc_assert (tmp_expr->expr_type == EXPR_VARIABLE);
+  if (!gfc_is_finalizable (tmp_expr->ts.u.derived, &final_expr) || !final_expr)
+    return;
+
+  /* Now generate the finalizer call.  */
+  this_code = gfc_get_code (EXEC_CALL);
+  this_code->symtree = final_expr->symtree;
+  this_code->resolved_sym = final_expr->symtree->n.sym;
+
+  //* Expression to be finalized  */
+  this_code->ext.actual = gfc_get_actual_arglist ();
+  this_code->ext.actual->expr = gfc_copy_expr (tmp_expr);
+
+  /* size_expr = STORAGE_SIZE (...) / NUMERIC_STORAGE_SIZE.  */
+  this_code->ext.actual->next = gfc_get_actual_arglist ();
+  size_expr = gfc_get_expr ();
+  size_expr->where = gfc_current_locus;
+  size_expr->expr_type = EXPR_OP;
+  size_expr->value.op.op = INTRINSIC_DIVIDE;
+  size_expr->value.op.op1
+	= gfc_build_intrinsic_call (gfc_current_ns, GFC_ISYM_STORAGE_SIZE,
+				    "storage_size", gfc_current_locus, 2,
+				    gfc_lval_expr_from_sym (tmp_expr->symtree->n.sym),
+				    gfc_get_int_expr (gfc_index_integer_kind,
+						      NULL, 0));
+  size_expr->value.op.op2 = gfc_get_int_expr (gfc_index_integer_kind, NULL,
+					      gfc_character_storage_size);
+  size_expr->value.op.op1->ts = size_expr->value.op.op2->ts;
+  size_expr->ts = size_expr->value.op.op1->ts;
+  this_code->ext.actual->next->expr = size_expr;
+
+  /* fini_coarray  */
+  this_code->ext.actual->next->next = gfc_get_actual_arglist ();
+  fini_coarray = gfc_get_constant_expr (BT_LOGICAL, gfc_default_logical_kind,
+					&tmp_expr->where);
+  fini_coarray->value.logical = (int)gfc_expr_attr (tmp_expr).codimension;
+  this_code->ext.actual->next->next->expr = fini_coarray;
+
+  add_code_to_chain (&this_code, head, tail);
+
+}
+
+/**********End of helper functions for modifying code*****************/
+
+
 /* Resolve the interface for a PROCEDURE declaration or procedure pointer.  */
 
 static bool
@@ -4133,9 +4391,6 @@ check_import_status (gfc_expr *e)
    argument which is not INTENT_IN and requires a temporary, build a temporary
    for the INTENT_IN actual argument as well.  */
 
-static void
-add_temp_assign_before_call (gfc_code *, gfc_namespace *, gfc_expr **);
-
 static void
 resolve_elemental_dependencies (gfc_code *c)
 {
@@ -12876,14 +13131,47 @@ static void
 resolve_block_construct (gfc_code* code)
 {
   gfc_namespace *ns = code->ext.block.ns;
+  gfc_association_list *assoc;
+  gfc_expr *tmp_var, *tgt;
+  gfc_code *tmp_code, *old_code;
+  gfc_exec_op op;
+
+  /* For an ASSOCIATE block, the associations (and their targets) will, for the
+     main part, be resolved by gfc_resolve_symbol, during resolution of the
+     BLOCK's namespace.  */
+
+  assoc = code->ext.block.assoc;
+
+  /* Subref arrays that are encloded in parentheses need a temporary.  */
+  for (; assoc; assoc = assoc->next)
+    {
+      if (assoc && assoc->st && assoc->st->n.sym->assoc
+	  && !assoc->st->n.sym->attr.select_type_temporary
+	  && (tgt = assoc->st->n.sym->assoc->target)
+	  && gfc_resolve_expr (tgt)
+	  && tgt->expr_type == EXPR_OP
+	  && tgt->value.op.op == INTRINSIC_PARENTHESES
+	  && is_subref_array (tgt->value.op.op1))
+	{
+	  if (gfc_expr_attr (tgt->value.op.op1).pointer)
+	    op = EXEC_POINTER_ASSIGN;
+	  else
+	    op = EXEC_ASSIGN;
+	  tmp_var = get_temp_from_expr (tgt->value.op.op1, ns->parent, true);
+	  tmp_code = build_assignment (op, tmp_var, tgt->value.op.op1,
+				       NULL, NULL, assoc->where);
+	  assoc->st->n.sym->assoc->target = gfc_copy_expr (tmp_var);
+	  old_code = gfc_get_code (EXEC_NOP);
+	  *old_code = *code;
+	  *code = *tmp_code;
+	  code->next = old_code;
+	  free (tmp_code);
+	}
+    }
 
-  /* For an ASSOCIATE block, the associations (and their targets) will be
-     resolved by gfc_resolve_symbol, during resolution of the BLOCK's
-     namespace.  */
   gfc_resolve (ns);
 }
 
-
 /* Resolve lists of blocks found in IF, SELECT CASE, WHERE, FORALL, GOTO and
    DO code nodes.  */
 
@@ -13312,263 +13600,9 @@ resolve_ordinary_assign (gfc_code *code, gfc_namespace *ns)
 }
 
 
-/* Add a component reference onto an expression.  */
-
-static void
-add_comp_ref (gfc_expr *e, gfc_component *c)
-{
-  gfc_ref **ref;
-  ref = &(e->ref);
-  while (*ref)
-    ref = &((*ref)->next);
-  *ref = gfc_get_ref ();
-  (*ref)->type = REF_COMPONENT;
-  (*ref)->u.c.sym = e->ts.u.derived;
-  (*ref)->u.c.component = c;
-  e->ts = c->ts;
-
-  /* Add a full array ref, as necessary.  */
-  if (c->as)
-    {
-      gfc_add_full_array_ref (e, c->as);
-      e->rank = c->as->rank;
-      e->corank = c->as->corank;
-    }
-}
-
-
-/* Build an assignment.  Keep the argument 'op' for future use, so that
-   pointer assignments can be made.  */
-
-static gfc_code *
-build_assignment (gfc_exec_op op, gfc_expr *expr1, gfc_expr *expr2,
-		  gfc_component *comp1, gfc_component *comp2, locus loc)
-{
-  gfc_code *this_code;
-
-  this_code = gfc_get_code (op);
-  this_code->next = NULL;
-  this_code->expr1 = gfc_copy_expr (expr1);
-  this_code->expr2 = gfc_copy_expr (expr2);
-  this_code->loc = loc;
-  if (comp1 && comp2)
-    {
-      add_comp_ref (this_code->expr1, comp1);
-      add_comp_ref (this_code->expr2, comp2);
-    }
-
-  return this_code;
-}
-
-
-/* Makes a temporary variable expression based on the characteristics of
-   a given variable expression.  If allocatable is set, the temporary is
-   unconditionally allocatable*/
-
-static gfc_expr*
-get_temp_from_expr (gfc_expr *e, gfc_namespace *ns,
-		    bool allocatable = false)
-{
-  static int serial = 0;
-  char name[GFC_MAX_SYMBOL_LEN];
-  gfc_symtree *tmp;
-  gfc_array_spec *as;
-  gfc_array_ref *aref;
-  gfc_ref *ref;
-
-  sprintf (name, GFC_PREFIX("DA%d"), serial++);
-  gfc_get_sym_tree (name, ns, &tmp, false);
-  gfc_add_type (tmp->n.sym, &e->ts, NULL);
-
-  if (e->expr_type == EXPR_CONSTANT && e->ts.type == BT_CHARACTER)
-    tmp->n.sym->ts.u.cl->length = gfc_get_int_expr (gfc_charlen_int_kind,
-						    NULL,
-						    e->value.character.length);
-
-  as = NULL;
-  ref = NULL;
-  aref = NULL;
-
-  /* Obtain the arrayspec for the temporary.  */
-   if (e->rank && e->expr_type != EXPR_ARRAY
-       && e->expr_type != EXPR_FUNCTION
-       && e->expr_type != EXPR_OP)
-    {
-      aref = gfc_find_array_ref (e);
-      if (e->expr_type == EXPR_VARIABLE
-	  && e->symtree->n.sym->as == aref->as)
-	as = aref->as;
-      else
-	{
-	  for (ref = e->ref; ref; ref = ref->next)
-	    if (ref->type == REF_COMPONENT
-		&& ref->u.c.component->as == aref->as)
-	      {
-		as = aref->as;
-		break;
-	      }
-	}
-    }
-
-  /* Add the attributes and the arrayspec to the temporary.  */
-  tmp->n.sym->attr = gfc_expr_attr (e);
-  tmp->n.sym->attr.function = 0;
-  tmp->n.sym->attr.proc_pointer = 0;
-  tmp->n.sym->attr.result = 0;
-  tmp->n.sym->attr.flavor = FL_VARIABLE;
-  tmp->n.sym->attr.dummy = 0;
-  tmp->n.sym->attr.use_assoc = 0;
-  tmp->n.sym->attr.intent = INTENT_UNKNOWN;
-
-
-  if (as && !allocatable)
-    {
-      tmp->n.sym->as = gfc_copy_array_spec (as);
-      if (!ref)
-	ref = e->ref;
-      if (as->type == AS_DEFERRED)
-	tmp->n.sym->attr.allocatable = 1;
-    }
-  else if ((e->rank || e->corank)
-	   && (e->expr_type == EXPR_ARRAY || e->expr_type == EXPR_FUNCTION
-	       || e->expr_type == EXPR_OP || allocatable))
-    {
-      tmp->n.sym->as = gfc_get_array_spec ();
-      tmp->n.sym->as->type = AS_DEFERRED;
-      tmp->n.sym->as->rank = e->rank;
-      tmp->n.sym->as->corank = e->corank;
-      tmp->n.sym->attr.allocatable = 1;
-      tmp->n.sym->attr.dimension = e->rank ? 1 : 0;
-      tmp->n.sym->attr.codimension = e->corank ? 1 : 0;
-    }
-  else
-    tmp->n.sym->attr.dimension = 0;
-
-  gfc_set_sym_referenced (tmp->n.sym);
-  gfc_commit_symbol (tmp->n.sym);
-  e = gfc_lval_expr_from_sym (tmp->n.sym);
-
-  /* Should the lhs be a section, use its array ref for the
-     temporary expression.  */
-  if (aref && aref->type != AR_FULL && !allocatable)
-    {
-      gfc_free_ref_list (e->ref);
-      e->ref = gfc_copy_ref (ref);
-    }
-  return e;
-}
-
-
-/* Helper function to take an argument in a subroutine call with a dependency
-   on another argument, copy it to an allocatable temporary and use the
-   temporary in the call expression. The new code is embedded in a block to
-   ensure local, automatic deallocation.  */
-
-static void
-add_temp_assign_before_call (gfc_code *code, gfc_namespace *ns,
-			     gfc_expr **rhsptr)
-{
-  gfc_namespace *block_ns;
-  gfc_expr *tmp_var;
-
-  /* Wrap the new code in a block so that the temporary is deallocated.  */
-  block_ns = gfc_build_block_ns (ns);
-
-  /* As it stands, the block_ns does not not stand up to resolution because the
-     the assignment would be converted to a call and, in any case, the modified
-     call fails in gfc_check_conformance.  */
-  block_ns->resolved = 1;
-
-  /* Assign the original expression to the temporary.  */
-  tmp_var = get_temp_from_expr (*rhsptr, block_ns, true);
-  block_ns->code = build_assignment (EXEC_ASSIGN, tmp_var, *rhsptr,
-				     NULL, NULL, (*rhsptr)->where);
-
-  /* Transfer the call to the block and terminate block code.  */
-  *rhsptr = gfc_copy_expr (tmp_var);
-  block_ns->code->next = gfc_get_code (EXEC_NOP);
-  *(block_ns->code->next) = *code;
-  block_ns->code->next->next = NULL;
-
-  /* Convert the original code to execute the block.  */
-  code->op = EXEC_BLOCK;
-  code->ext.block.ns = block_ns;
-  code->ext.block.assoc = NULL;
-  code->expr1 = code->expr2 = NULL;
-}
-
-
-/* Add one line of code to the code chain, making sure that 'head' and
-   'tail' are appropriately updated.  */
-
-static void
-add_code_to_chain (gfc_code **this_code, gfc_code **head, gfc_code **tail)
-{
-  gcc_assert (this_code);
-  if (*head == NULL)
-    *head = *tail = *this_code;
-  else
-    *tail = gfc_append_code (*tail, *this_code);
-  *this_code = NULL;
-}
-
-
-/* Generate a final call from a variable expression  */
-
-static void
-generate_final_call (gfc_expr *tmp_expr, gfc_code **head, gfc_code **tail)
-{
-  gfc_code *this_code;
-  gfc_expr *final_expr = NULL;
-  gfc_expr *size_expr;
-  gfc_expr *fini_coarray;
-
-  gcc_assert (tmp_expr->expr_type == EXPR_VARIABLE);
-  if (!gfc_is_finalizable (tmp_expr->ts.u.derived, &final_expr) || !final_expr)
-    return;
-
-  /* Now generate the finalizer call.  */
-  this_code = gfc_get_code (EXEC_CALL);
-  this_code->symtree = final_expr->symtree;
-  this_code->resolved_sym = final_expr->symtree->n.sym;
-
-  //* Expression to be finalized  */
-  this_code->ext.actual = gfc_get_actual_arglist ();
-  this_code->ext.actual->expr = gfc_copy_expr (tmp_expr);
-
-  /* size_expr = STORAGE_SIZE (...) / NUMERIC_STORAGE_SIZE.  */
-  this_code->ext.actual->next = gfc_get_actual_arglist ();
-  size_expr = gfc_get_expr ();
-  size_expr->where = gfc_current_locus;
-  size_expr->expr_type = EXPR_OP;
-  size_expr->value.op.op = INTRINSIC_DIVIDE;
-  size_expr->value.op.op1
-	= gfc_build_intrinsic_call (gfc_current_ns, GFC_ISYM_STORAGE_SIZE,
-				    "storage_size", gfc_current_locus, 2,
-				    gfc_lval_expr_from_sym (tmp_expr->symtree->n.sym),
-				    gfc_get_int_expr (gfc_index_integer_kind,
-						      NULL, 0));
-  size_expr->value.op.op2 = gfc_get_int_expr (gfc_index_integer_kind, NULL,
-					      gfc_character_storage_size);
-  size_expr->value.op.op1->ts = size_expr->value.op.op2->ts;
-  size_expr->ts = size_expr->value.op.op1->ts;
-  this_code->ext.actual->next->expr = size_expr;
-
-  /* fini_coarray  */
-  this_code->ext.actual->next->next = gfc_get_actual_arglist ();
-  fini_coarray = gfc_get_constant_expr (BT_LOGICAL, gfc_default_logical_kind,
-					&tmp_expr->where);
-  fini_coarray->value.logical = (int)gfc_expr_attr (tmp_expr).codimension;
-  this_code->ext.actual->next->next->expr = fini_coarray;
-
-  add_code_to_chain (&this_code, head, tail);
-
-}
-
 /* Counts the potential number of part array references that would
    result from resolution of typebound defined assignments.  */
 
-
 static int
 nonscalar_typebound_assign (gfc_symbol *derived, int depth)
 {
diff --git a/gcc/testsuite/gfortran.dg/associate_79.f90 b/gcc/testsuite/gfortran.dg/associate_79.f90
new file mode 100644
index 00000000000..ff657e6499e
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/associate_79.f90
@@ -0,0 +1,43 @@
+! { dg-do run }
+! Test the fix for PR121384
+! Contributed by Mikael Morin  <[email protected]>
+program test
+  implicit none
+  type :: t
+    integer :: i,j
+  end type
+  type(t) :: a(5)
+  class(t), allocatable :: c(:)
+  a = [ t(2,3), t(5,7), t(11,13), t(17,19), t(23,29) ]
+  associate (x => (a%i))
+    if (rank(x) /= 1) error stop 11
+    if (any(shape(x) /= [5])) error stop 12
+    if (any(x /= [2,5,11,17,23])) error stop 13
+    x(1) = 3
+  end associate
+  if  (a(1)%i /= 2) stop 14
+  associate (x => (a%j))
+    if (rank(x) /= 1) error stop 21
+    if (any(shape(x) /= [5])) error stop 22
+    if (any(x /= [3,7,13,19,29])) error stop 23
+    x(1) = 4
+  end associate
+  if  (a(1)%j /= 3) stop 24
+
+! Check the class variants
+  c = a
+  associate (x => (c%i))
+    if (rank(x) /= 1) error stop 31
+    if (any(shape(x) /= [5])) error stop 32
+    if (any(x /= [2,5,11,17,23])) error stop 33
+    x(1) = 3
+  end associate
+  if  (c(1)%i /= 2) stop 34
+  associate (x => (c%j))
+    if (rank(x) /= 1) error stop 41
+    if (any(shape(x) /= [5])) error stop 42
+    if (any(x /= [3,7,13,19,29])) error stop 43
+    x(1) = 4
+  end associate
+  if  (c(1)%j /= 3) stop 44
+end program
-- 
2.53.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.