[PATCH 3/7] Fortran: Allow to use non-pure/non-elemental functions in
 coarray indexes [PR107635]

Extract calls to non-pure or non-elemental functions from index
expressions on a coarray.

gcc/fortran/ChangeLog:

        PR fortran/107635

        * rewrite.cc (get_arrayspec_from_expr): Treat array result of
        function calls correctly.
        (remove_coarray_from_derived_type): Prevent memory loss.
        (add_caf_get_from_remote): Correct locus.
        (find_comp): New function to find or create a new component in a
        derived type.
        (check_add_new_comp_handle_array): Handle allocatable arrays or
        non-pure/non-elemental functions in indexes of coarrays.
        (check_add_new_component): Use above function.
        (create_get_parameter_type): Rename to
        create_caf_add_data_parameter_type.
        (create_caf_add_data_parameter_type): Renaming of variable and
        make the additional data a coarray.
        (remove_caf_ref): Factor out to reuse in other caf-functions.
        (create_get_callback): Use function factored out, set locus
        correctly and ensure a kind is set for parameters.
        (add_caf_get_intrinsic): Rename to add_caf_get_from_remote and
        rename some variables.
        (coindexed_expr_callback): Skip over function created by the
        rewriter.
        (coindexed_code_callback): Filter some intrinsics not to
        process.
        (gfc_rewrite): Rewrite also contained functions.
        * trans-intrinsic.cc (gfc_conv_intrinsic_caf_get): Reflect
        changed order on caf_get_from_remote ().

libgfortran/ChangeLog:

        * caf/libcaf.h (_gfortran_caf_register_accessor): Reflect
        changed parameter order.
        * caf/single.c (struct accessor_hash_t): Same.
        (_gfortran_caf_register_accessor): Call accessor using a token
        for accessing arrays with a descriptor on the source side.

gcc/testsuite/ChangeLog:

        * gfortran.dg/coarray_lib_comm_1.f90: Adapt scan expression.
        * gfortran.dg/coarray/get_with_fn_parameter.f90: New test.
        * gfortran.dg/coarray/get_with_scalar_fn.f90: New test.


--
Andre Vehreschild * Email: vehre ad gmx dot de
From b49b88f98d6cb63058c480e8646603f4dd82f83a Mon Sep 17 00:00:00 2001
From: Andre Vehreschild <ve...@gcc.gnu.org>
Date: Wed, 22 Jan 2025 13:36:21 +0100
Subject: [PATCH 3/7] Fortran: Allow to use non-pure/non-elemental functions in
 coarray indexes [PR107635]

Extract calls to non-pure or non-elemental functions from index
expressions on a coarray.

gcc/fortran/ChangeLog:

	PR fortran/107635

	* rewrite.cc (get_arrayspec_from_expr): Treat array result of
	function calls correctly.
	(remove_coarray_from_derived_type): Prevent memory loss.
	(add_caf_get_from_remote): Correct locus.
	(find_comp): New function to find or create a new component in a
	derived type.
	(check_add_new_comp_handle_array): Handle allocatable arrays or
	non-pure/non-elemental functions in indexes of coarrays.
	(check_add_new_component): Use above function.
	(create_get_parameter_type): Rename to
	create_caf_add_data_parameter_type.
	(create_caf_add_data_parameter_type): Renaming of variable and
	make the additional data a coarray.
	(remove_caf_ref): Factor out to reuse in other caf-functions.
	(create_get_callback): Use function factored out, set locus
	correctly and ensure a kind is set for parameters.
	(add_caf_get_intrinsic): Rename to add_caf_get_from_remote and
	rename some variables.
	(coindexed_expr_callback): Skip over function created by the
	rewriter.
	(coindexed_code_callback): Filter some intrinsics not to
	process.
	(gfc_rewrite): Rewrite also contained functions.
	* trans-intrinsic.cc (gfc_conv_intrinsic_caf_get): Reflect
	changed order on caf_get_from_remote ().

libgfortran/ChangeLog:

	* caf/libcaf.h (_gfortran_caf_register_accessor): Reflect
	changed parameter order.
	* caf/single.c (struct accessor_hash_t): Same.
	(_gfortran_caf_register_accessor): Call accessor using a token
	for accessing arrays with a descriptor on the source side.

gcc/testsuite/ChangeLog:

	* gfortran.dg/coarray_lib_comm_1.f90: Adapt scan expression.
	* gfortran.dg/coarray/get_with_fn_parameter.f90: New test.
	* gfortran.dg/coarray/get_with_scalar_fn.f90: New test.
---
 gcc/fortran/rewrite.cc                        | 557 +++++++++++++-----
 gcc/fortran/trans-intrinsic.cc                |   3 +-
 .../coarray/get_with_fn_parameter.f90         |  29 +
 .../coarray/get_with_scalar_fn.f90            |  30 +
 .../gfortran.dg/coarray_lib_comm_1.f90        |   2 +-
 libgfortran/caf/libcaf.h                      |   5 +-
 libgfortran/caf/single.c                      |  23 +-
 7 files changed, 499 insertions(+), 150 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/coarray/get_with_fn_parameter.f90
 create mode 100644 gcc/testsuite/gfortran.dg/coarray/get_with_scalar_fn.f90

diff --git a/gcc/fortran/rewrite.cc b/gcc/fortran/rewrite.cc
index 298b58081a4..3caa65c40fd 100644
--- a/gcc/fortran/rewrite.cc
+++ b/gcc/fortran/rewrite.cc
@@ -34,10 +34,16 @@ along with GCC; see the file COPYING3.  If not see
 #include "bitmap.h"
 #include "gfortran.h"

+/* The code tree element that is currently processed.  */
 static gfc_code **current_code;

+/* Code that is inserted into the current caf_accessor at the beginning.  */
+static gfc_code *caf_accessor_prepend = nullptr;
+
 static bool caf_on_lhs = false;

+static int caf_sym_cnt = 0;
+
 static gfc_array_spec *
 get_arrayspec_from_expr (gfc_expr *expr)
 {
@@ -49,6 +55,9 @@ get_arrayspec_from_expr (gfc_expr *expr)
   if (expr->rank == 0)
     return NULL;

+  if (expr->expr_type == EXPR_FUNCTION)
+    return gfc_copy_array_spec (expr->symtree->n.sym->as);
+
   /* Follow any component references.  */
   if (expr->expr_type == EXPR_VARIABLE || expr->expr_type == EXPR_CONSTANT)
     {
@@ -158,6 +167,9 @@ get_arrayspec_from_expr (gfc_expr *expr)
 		    break;

 		  case AR_FULL:
+		    if (dst_as)
+		      /* Prevent memory loss.  */
+		      gfc_free_array_spec (dst_as);
 		    dst_as = gfc_copy_array_spec (src_as);
 		    break;
 		  }
@@ -206,6 +218,7 @@ remove_coarray_from_derived_type (gfc_symbol *base, gfc_namespace *ns,

       p = n;
     }
+  derived->declared_at = base->declared_at;
   gfc_set_sym_referenced (derived);
   gfc_commit_symbol (derived);
   base->ts.u.derived = derived;
@@ -236,6 +249,7 @@ split_expr_at_caf_ref (gfc_expr *expr, gfc_namespace *ns,
   gfc_ref *caf_ref = NULL;
   gfc_symtree *st;
   gfc_symbol *base;
+  bool created;

   gcc_assert (expr->expr_type == EXPR_VARIABLE);
   if (!expr->symtree->n.sym->attr.codimension)
@@ -251,8 +265,9 @@ split_expr_at_caf_ref (gfc_expr *expr, gfc_namespace *ns,
 	}
     }

-  gcc_assert (!gfc_get_sym_tree (!caf_ref ? expr->symtree->name : "base", ns,
-				 &st, false));
+  created = !gfc_get_sym_tree (!caf_ref ? expr->symtree->name : "base", ns, &st,
+			       false);
+  gcc_assert (created);
   st->n.sym->attr.flavor = FL_PARAMETER;
   st->n.sym->attr.dummy = 1;
   st->n.sym->attr.intent = INTENT_IN;
@@ -307,8 +322,239 @@ split_expr_at_caf_ref (gfc_expr *expr, gfc_namespace *ns,
   gfc_expression_rank (*post_caf_ref_expr);
 }

+static void add_caf_get_from_remote (gfc_expr *e);
+
+static gfc_component *
+find_comp (gfc_symbol *type, gfc_expr *e, int *cnt, const bool is_var)
+{
+  char *temp_name = nullptr;
+  gfc_component *comp = type->components;
+
+  /* For variables:
+     - look up same name or create new
+     all else:
+     - create unique new
+  */
+  if (is_var)
+    {
+      ++(*cnt);
+      free (temp_name);
+      temp_name = xasprintf ("caf_temp_%s_%d", e->symtree->name, *cnt);
+      while (comp && strcmp (comp->name, temp_name) != 0)
+	comp = comp->next;
+      if (!comp)
+	{
+	  const bool added = gfc_add_component (type, temp_name, &comp);
+	  gcc_assert (added);
+	}
+    }
+  else
+    {
+      int r = -1;
+      /* Components are always appended, i.e., when searching to add a unique
+	 one just iterating forward is sufficient.  */
+      do
+	{
+	  ++(*cnt);
+	  free (temp_name);
+	  temp_name = xasprintf ("caf_temp_%s_%d", e->symtree->name, *cnt);
+
+	  while (comp && (r = strcmp (comp->name, temp_name)) <= 0)
+	    comp = comp->next;
+	}
+      while (comp && r <= 0);
+      {
+	const bool added = gfc_add_component (type, temp_name, &comp);
+	gcc_assert (added);
+      }
+    }
+
+  comp->loc = e->where;
+  comp->ts = e->ts;
+  free (temp_name);
+
+  return comp;
+}
+
 static void
-check_add_new_component (gfc_symbol *type, gfc_expr *e, gfc_symbol *get_data)
+check_add_new_comp_handle_array (gfc_expr *e, gfc_symbol *type,
+				 gfc_symbol *add_data)
+{
+  gfc_component *comp;
+  int cnt = -1;
+  gfc_symtree *caller_image;
+  gfc_code *pre_code = caf_accessor_prepend;
+  bool static_array_or_scalar = true;
+  symbol_attribute e_attr = gfc_expr_attr (e);
+
+  gfc_free_shape (&e->shape, e->rank);
+
+  /* When already code to prepend into the accessor exists, go to
+     the end of the chain.  */
+  for (; pre_code && pre_code->next; pre_code = pre_code->next)
+    ;
+
+  comp = find_comp (type, e, &cnt,
+		    e->symtree->n.sym->attr.flavor == FL_VARIABLE
+		      || e->symtree->n.sym->attr.flavor == FL_PARAMETER);
+
+  if (e->expr_type == EXPR_FUNCTION
+      || (e->expr_type == EXPR_VARIABLE && e_attr.dimension
+	  && e_attr.allocatable))
+    {
+      gfc_code *code;
+      gfc_symtree *st;
+      const bool created
+	= !gfc_get_sym_tree (comp->name, gfc_current_ns, &st, false, &e->where);
+      gcc_assert (created);
+
+      st->n.sym->ts = e->ts;
+      gfc_set_sym_referenced (st->n.sym);
+      code = gfc_get_code (EXEC_ASSIGN);
+      code->loc = e->where;
+      code->expr1 = gfc_get_variable_expr (st);
+      code->expr2 = XCNEW (gfc_expr);
+      *(code->expr2) = *e;
+      code->next = *current_code;
+      *current_code = code;
+
+      if (e_attr.dimension)
+	{
+	  gfc_array_spec *as = get_arrayspec_from_expr (e);
+	  static_array_or_scalar = gfc_is_compile_time_shape (as);
+
+	  comp->attr.dimension = 1;
+	  st->n.sym->attr.dimension = 1;
+	  st->n.sym->as = as;
+
+	  if (!static_array_or_scalar)
+	    {
+	      comp->attr.allocatable = 1;
+	      st->n.sym->attr.allocatable = 1;
+	    }
+	  code->expr1->rank = as->rank;
+	  gfc_add_full_array_ref (code->expr1, gfc_copy_array_spec (as));
+	  comp->as = gfc_copy_array_spec (as);
+	}
+
+      gfc_expression_rank (code->expr1);
+      comp->initializer = gfc_get_variable_expr (st);
+      gfc_commit_symbol (st->n.sym);
+    }
+  else
+    {
+      comp->initializer = gfc_copy_expr (e);
+      if (e_attr.dimension)
+	{
+	  comp->attr.dimension = 1;
+	  comp->as = get_arrayspec_from_expr (e);
+	}
+    }
+  comp->initializer->where = e->where;
+  comp->attr.access = ACCESS_PRIVATE;
+  memset (e, 0, sizeof (gfc_expr));
+  e->ts = comp->initializer->ts;
+  e->expr_type = EXPR_VARIABLE;
+  e->where = comp->initializer->where;
+
+  if (comp->as && comp->as->rank)
+    {
+      if (static_array_or_scalar)
+	{
+	  e->ref = gfc_get_ref ();
+	  e->ref->type = REF_ARRAY;
+	  e->ref->u.ar.as = gfc_copy_array_spec (add_data->as);
+	  e->ref->u.ar.codimen = 1;
+	  e->ref->u.ar.dimen_type[0] = DIMEN_THIS_IMAGE;
+	}
+      else
+	{
+	  gfc_code *c;
+	  gfc_symtree *lv, *ad;
+	  bool created = !gfc_get_sym_tree (comp->name, add_data->ns, &lv,
+					    false, &e->where);
+	  gcc_assert (created);
+
+	  lv->n.sym->ts = e->ts;
+	  lv->n.sym->attr.dimension = 1;
+	  lv->n.sym->attr.allocatable = 1;
+	  lv->n.sym->attr.flavor = FL_VARIABLE;
+	  lv->n.sym->as = gfc_copy_array_spec (comp->as);
+	  gfc_set_sym_referenced (lv->n.sym);
+	  gfc_commit_symbol (lv->n.sym);
+	  c = gfc_get_code (EXEC_ASSIGN);
+	  c->loc = e->where;
+	  c->expr1 = gfc_get_variable_expr (lv);
+	  c->expr1->where = e->where;
+
+	  created = !gfc_find_sym_tree (add_data->name, add_data->ns, 0, &ad);
+	  gcc_assert (created);
+	  c->expr2 = gfc_get_variable_expr (ad);
+	  c->expr2->where = e->where;
+	  c->expr2->ts = comp->initializer->ts;
+	  c->expr2->ref = gfc_get_ref ();
+	  c->expr2->ref->type = REF_ARRAY;
+	  c->expr2->ref->u.ar.as = gfc_copy_array_spec (add_data->as);
+	  c->expr2->ref->u.ar.codimen = 1;
+	  c->expr2->ref->u.ar.dimen_type[0] = DIMEN_ELEMENT;
+	  caller_image
+	    = gfc_find_symtree_in_proc ("caller_image", add_data->ns);
+	  gcc_assert (caller_image);
+	  c->expr2->ref->u.ar.start[0] = gfc_get_variable_expr (caller_image);
+	  c->expr2->ref->u.ar.start[0]->where = e->where;
+	  created = gfc_find_component (ad->n.sym->ts.u.derived, comp->name,
+					false, true, &c->expr2->ref->next)
+		    != nullptr;
+	  gcc_assert (created);
+	  c->expr2->rank = comp->as->rank;
+	  gfc_add_full_array_ref (c->expr2, gfc_copy_array_spec (comp->as));
+	  gfc_set_sym_referenced (ad->n.sym);
+	  gfc_commit_symbol (ad->n.sym);
+	  if (pre_code)
+	    pre_code->next = c;
+	  else
+	    caf_accessor_prepend = c;
+	  add_caf_get_from_remote (c->expr2);
+
+	  e->symtree = lv;
+	  gfc_expression_rank (e);
+	  gfc_add_full_array_ref (e, gfc_copy_array_spec (comp->as));
+	}
+    }
+  else
+    {
+      e->ref = gfc_get_ref ();
+      e->ref->type = REF_ARRAY;
+      e->ref->u.ar.as = gfc_copy_array_spec (add_data->as);
+      e->ref->u.ar.codimen = 1;
+      e->ref->u.ar.dimen_type[0] = DIMEN_THIS_IMAGE;
+    }
+
+  if (static_array_or_scalar)
+    {
+      const bool created
+	= gfc_find_component (add_data->ts.u.derived, comp->name, false, true,
+			      &e->ref);
+      gcc_assert (created);
+      e->symtree = gfc_find_symtree (add_data->ns->sym_root, add_data->name);
+      gcc_assert (e->symtree);
+      if (IS_CLASS_ARRAY (e->ref->u.c.component)
+	  || e->ref->u.c.component->attr.dimension)
+	{
+	  gfc_add_full_array_ref (e, e->ref->u.c.component->ts.type == BT_CLASS
+				       ? CLASS_DATA (e->ref->u.c.component)->as
+				       : e->ref->u.c.component->as);
+	  e->ref->next->u.ar.dimen
+	    = e->ref->u.c.component->ts.type == BT_CLASS
+		? CLASS_DATA (e->ref->u.c.component)->as->rank
+		: e->ref->u.c.component->as->rank;
+	}
+      gfc_expression_rank (e);
+    }
+}
+
+static void
+check_add_new_component (gfc_symbol *type, gfc_expr *e, gfc_symbol *add_data)
 {
   if (e)
     {
@@ -318,87 +564,28 @@ check_add_new_component (gfc_symbol *type, gfc_expr *e, gfc_symbol *get_data)
 	case EXPR_NULL:
 	  break;
 	case EXPR_OP:
-	  check_add_new_component (type, e->value.op.op1, get_data);
+	  check_add_new_component (type, e->value.op.op1, add_data);
 	  if (e->value.op.op2)
-	    check_add_new_component (type, e->value.op.op2, get_data);
+	    check_add_new_component (type, e->value.op.op2, add_data);
 	  break;
 	case EXPR_COMPCALL:
 	  for (gfc_actual_arglist *actual = e->value.compcall.actual; actual;
 	       actual = actual->next)
-	    check_add_new_component (type, actual->expr, get_data);
+	    check_add_new_component (type, actual->expr, add_data);
 	  break;
 	case EXPR_FUNCTION:
 	  if (!e->symtree->n.sym->attr.pure
 	      && !e->symtree->n.sym->attr.elemental)
-	    {
-	      // Treat non-pure functions.
-	      gfc_error ("Sorry, not yet able to call a non-pure/non-elemental"
-			 " function %s in a coarray reference;  use a temporary"
-			 " for the function's result instead",
-			 e->symtree->n.sym->name);
-	    }
-	  for (gfc_actual_arglist *actual = e->value.function.actual; actual;
-	       actual = actual->next)
-	    check_add_new_component (type, actual->expr, get_data);
+	    /* Treat non-pure/non-elemental functions.  */
+	    check_add_new_comp_handle_array (e, type, add_data);
+	  else
+	    for (gfc_actual_arglist *actual = e->value.function.actual; actual;
+		 actual = actual->next)
+	      check_add_new_component (type, actual->expr, add_data);
 	  break;
 	case EXPR_VARIABLE:
-	  {
-	    gfc_component *comp;
-	    gfc_ref *ref;
-	    int old_rank = e->rank;
-
-	    /* Can't use gfc_find_component here, because type is not yet
-	       complete.  */
-	    comp = type->components;
-	    while (comp)
-	      {
-		if (strcmp (comp->name, e->symtree->name) == 0)
-		  break;
-		comp = comp->next;
-	      }
-	    if (!comp)
-	      {
-		gcc_assert (gfc_add_component (type, e->symtree->name, &comp));
-		/* Take a copy of e, before modifying it.  */
-		gfc_expr *init = gfc_copy_expr (e);
-		if (e->ref)
-		  {
-		    switch (e->ref->type)
-		      {
-		      case REF_ARRAY:
-			comp->as = get_arrayspec_from_expr (e);
-			comp->attr.dimension = e->ref->u.ar.dimen != 0;
-			comp->ts = e->ts;
-			break;
-		      case REF_COMPONENT:
-			comp->ts = e->ref->u.c.sym->ts;
-			break;
-		      default:
-			gcc_unreachable ();
-			break;
-		      }
-		  }
-		else
-		  comp->ts = e->ts;
-		comp->attr.access = ACCESS_PRIVATE;
-		comp->initializer = init;
-	      }
-	    else
-	      gcc_assert (comp->ts.type == e->ts.type
-			  && comp->ts.u.derived == e->ts.u.derived);
-
-	    ref = e->ref;
-	    e->ref = NULL;
-	    gcc_assert (gfc_find_component (get_data->ts.u.derived,
-					    e->symtree->name, false, true,
-					    &e->ref));
-	    e->symtree
-	      = gfc_find_symtree (get_data->ns->sym_root, get_data->name);
-	    e->ref->next = ref;
-	    gfc_free_shape (&e->shape, old_rank);
-	    gfc_expression_rank (e);
+	    check_add_new_comp_handle_array (e, type, add_data);
 	    break;
-	  }
 	case EXPR_ARRAY:
 	case EXPR_PPC:
 	case EXPR_STRUCTURE:
@@ -410,8 +597,8 @@ check_add_new_component (gfc_symbol *type, gfc_expr *e, gfc_symbol *get_data)
 }

 static gfc_symbol *
-create_get_parameter_type (gfc_expr *expr, gfc_namespace *ns,
-			   gfc_symbol *get_data)
+create_caf_add_data_parameter_type (gfc_expr *expr, gfc_namespace *ns,
+				    gfc_symbol *add_data)
 {
   static int type_cnt = 0;
   char tname[GFC_MAX_SYMBOL_LEN + 1];
@@ -421,11 +608,21 @@ create_get_parameter_type (gfc_expr *expr, gfc_namespace *ns,
   gcc_assert (expr->expr_type == EXPR_VARIABLE);

   strcpy (tname, expr->symtree->name);
-  name = xasprintf ("@_rget_data_t_%s_%d", tname, ++type_cnt);
+  name = xasprintf ("@_caf_add_data_t_%s_%d", tname, ++type_cnt);
   gfc_get_symbol (name, ns, &type);

   type->attr.flavor = FL_DERIVED;
-  get_data->ts.u.derived = type;
+  add_data->ts.u.derived = type;
+  add_data->attr.codimension = 1;
+  add_data->as = gfc_get_array_spec ();
+  add_data->as->corank = 1;
+  add_data->as->type = AS_EXPLICIT;
+  add_data->as->cotype = AS_DEFERRED;
+  add_data->as->lower[0]
+    = gfc_get_constant_expr (BT_INTEGER, gfc_default_integer_kind,
+			     &expr->where);
+  mpz_init (add_data->as->lower[0]->value.integer);
+  mpz_set_si (add_data->as->lower[0]->value.integer, 1);

   for (gfc_ref *ref = expr->ref; ref; ref = ref->next)
     {
@@ -434,31 +631,81 @@ create_get_parameter_type (gfc_expr *expr, gfc_namespace *ns,
 	  gfc_array_ref *ar = &ref->u.ar;
 	  for (int i = 0; i < ar->dimen; ++i)
 	    {
-	      check_add_new_component (type, ar->start[i], get_data);
-	      check_add_new_component (type, ar->end[i], get_data);
-	      check_add_new_component (type, ar->stride[i], get_data);
+	      check_add_new_component (type, ar->start[i], add_data);
+	      check_add_new_component (type, ar->end[i], add_data);
+	      check_add_new_component (type, ar->stride[i], add_data);
 	    }
 	}
     }

+  type->declared_at = expr->where;
   gfc_set_sym_referenced (type);
   gfc_commit_symbol (type);
   return type;
 }

+static void
+remove_caf_ref (gfc_expr *expr, const bool conv_to_this_image_cafref = false)
+{
+  gfc_ref *ref = expr->ref, **pref = &expr->ref;
+  while (ref && (ref->type != REF_ARRAY || ref->u.ar.codimen == 0))
+    {
+      ref = ref->next;
+      pref = &ref->next;
+    }
+  if (ref && ref->type == REF_ARRAY && ref->u.ar.codimen != 0)
+    {
+      if (ref->u.ar.dimen != 0)
+	{
+	  ref->u.ar.codimen = 0;
+	  pref = &ref->next;
+	  ref = ref->next;
+	}
+      else
+	{
+	  if (conv_to_this_image_cafref)
+	    {
+	      for (int i = ref->u.ar.dimen;
+		   i < ref->u.ar.dimen + ref->u.ar.codimen; ++i)
+		ref->u.ar.dimen_type[i] = DIMEN_THIS_IMAGE;
+	    }
+	  else
+	    {
+	      expr->ref = ref->next;
+	      ref->next = NULL;
+	      gfc_free_ref_list (ref);
+	      ref = expr->ref;
+	      pref = &expr->ref;
+	    }
+	}
+    }
+  if (ref && ref->type == REF_COMPONENT)
+    {
+      gfc_find_component (expr->symtree->n.sym->ts.u.derived,
+			  ref->u.c.component->name, false, true, pref);
+      if (*pref && *pref != ref)
+	{
+	  (*pref)->next = ref->next;
+	  ref->next = NULL;
+	  gfc_free_ref_list (ref);
+	}
+    }
+}
+
 static gfc_expr *
 create_get_callback (gfc_expr *expr)
 {
-  static int cnt = 0;
   gfc_namespace *ns;
   gfc_symbol *extproc, *proc, *buffer, *free_buffer, *base, *get_data,
-    *old_buffer_data;
+    *old_buffer_data, *caller_image;
   char tname[GFC_MAX_SYMBOL_LEN + 1];
   char *name;
   const char *mname;
   gfc_expr *cb, *post_caf_ref_expr;
   gfc_code *code;
   int expr_rank = expr->rank;
+  gfc_code *backup_caf_accessor_prepend = caf_accessor_prepend;
+  caf_accessor_prepend = nullptr;

   /* Find the top-level namespace.  */
   for (ns = gfc_current_ns; ns->parent; ns = ns->parent)
@@ -472,8 +719,9 @@ create_get_callback (gfc_expr *expr)
     mname = expr->symtree->n.sym->module;
   else
     mname = "main";
-  name = xasprintf ("_caf_rget_%s_%s_%d", mname, tname, ++cnt);
+  name = xasprintf ("_caf_rget_%s_%s_%d", mname, tname, ++caf_sym_cnt);
   gfc_get_symbol (name, ns, &extproc);
+  extproc->declared_at = expr->where;
   gfc_set_sym_referenced (extproc);
   ++extproc->refs;
   gfc_commit_symbol (extproc);
@@ -492,6 +740,7 @@ create_get_callback (gfc_expr *expr)
   proc->attr.host_assoc = 1;
   proc->attr.always_explicit = 1;
   ++proc->refs;
+  proc->declared_at = expr->where;
   gfc_commit_symbol (proc);
   free (name);

@@ -502,18 +751,29 @@ create_get_callback (gfc_expr *expr)
   gfc_set_sym_referenced (proc);
   /* Set up formal arguments.  */
   gfc_formal_arglist **argptr = &proc->formal;
-#define ADD_ARG(name, nsym, stype, sintent)                                    \
+#define ADD_ARG(name, nsym, stype, skind, sintent)                             \
   gfc_get_symbol (name, sub_ns, &nsym);                                        \
   nsym->ts.type = stype;                                                       \
+  nsym->ts.kind = skind;                                                       \
   nsym->attr.flavor = FL_PARAMETER;                                            \
   nsym->attr.dummy = 1;                                                        \
   nsym->attr.intent = sintent;                                                 \
+  nsym->declared_at = expr->where;                                             \
   gfc_set_sym_referenced (nsym);                                               \
   *argptr = gfc_get_formal_arglist ();                                         \
   (*argptr)->sym = nsym;                                                       \
   argptr = &(*argptr)->next

-  ADD_ARG ("buffer", buffer, expr->ts.type, INTENT_INOUT);
+  name = xasprintf ("add_data_%s_%s_%d", mname, tname, caf_sym_cnt);
+  ADD_ARG (name, get_data, BT_DERIVED, 0, INTENT_IN);
+  gfc_commit_symbol (get_data);
+  free (name);
+
+  ADD_ARG ("caller_image", caller_image, BT_INTEGER, gfc_default_integer_kind,
+	   INTENT_IN);
+  gfc_commit_symbol (caller_image);
+
+  ADD_ARG ("buffer", buffer, expr->ts.type, expr->ts.kind, INTENT_INOUT);
   buffer->ts = expr->ts;
   if (expr_rank)
     {
@@ -553,8 +813,9 @@ create_get_callback (gfc_expr *expr)
       buffer->ts.u.cl->length = nullptr;
     }
   gfc_commit_symbol (buffer);
-  ADD_ARG ("free_buffer", free_buffer, BT_LOGICAL, INTENT_OUT);
-  free_buffer->ts.kind = gfc_default_logical_kind;
+
+  ADD_ARG ("free_buffer", free_buffer, BT_LOGICAL, gfc_default_logical_kind,
+	   INTENT_OUT);
   gfc_commit_symbol (free_buffer);

   // ADD_ARG (expr->symtree->name, base, BT_VOID, INTENT_IN);
@@ -564,10 +825,7 @@ create_get_callback (gfc_expr *expr)
   *argptr = gfc_get_formal_arglist ();
   (*argptr)->sym = base;
   argptr = &(*argptr)->next;
-
   gfc_commit_symbol (base);
-  ADD_ARG ("get_data", get_data, BT_DERIVED, INTENT_IN);
-  gfc_commit_symbol (get_data);
 #undef ADD_ARG

   /* Set up code.  */
@@ -578,8 +836,10 @@ create_get_callback (gfc_expr *expr)
       gfc_get_symbol ("old_buffer_data", sub_ns, &old_buffer_data);
       old_buffer_data->ts.type = BT_VOID;
       old_buffer_data->attr.flavor = FL_VARIABLE;
+      old_buffer_data->declared_at = expr->where;
       gfc_set_sym_referenced (old_buffer_data);
       gfc_commit_symbol (old_buffer_data);
+      code->loc = expr->where;
       code->expr1 = gfc_lval_expr_from_sym (old_buffer_data);
       code->expr2 = gfc_build_intrinsic_call (ns, GFC_ISYM_C_LOC, "C_LOC",
 					      gfc_current_locus, 1,
@@ -591,39 +851,12 @@ create_get_callback (gfc_expr *expr)
     code = sub_ns->code = gfc_get_code (EXEC_POINTER_ASSIGN);

   /* Code: buffer = expr;  */
+  code->loc = expr->where;
   code->expr1 = gfc_lval_expr_from_sym (buffer);
   code->expr2 = post_caf_ref_expr;
-  gfc_ref *ref = code->expr2->ref, **pref = &code->expr2->ref;
-  if (ref && ref->type == REF_ARRAY && ref->u.ar.codimen != 0)
-    {
-      if (ref->u.ar.dimen != 0)
-	{
-	  ref->u.ar.codimen = 0;
-	  pref = &ref->next;
-	  ref = ref->next;
-	}
-      else
-	{
-	  code->expr2->ref = ref->next;
-	  ref->next = NULL;
-	  gfc_free_ref_list (ref);
-	  ref = code->expr2->ref;
-	  pref = &code->expr2->ref;
-	}
-    }
-  if (ref && ref->type == REF_COMPONENT)
-    {
-      gfc_find_component (code->expr2->symtree->n.sym->ts.u.derived,
-			  ref->u.c.component->name, false, false, pref);
-      if (*pref != ref)
-	{
-	  (*pref)->next = ref->next;
-	  ref->next = NULL;
-	  gfc_free_ref_list (ref);
-	}
-    }
+  remove_caf_ref (post_caf_ref_expr);
   get_data->ts.u.derived
-    = create_get_parameter_type (code->expr2, ns, get_data);
+    = create_caf_add_data_parameter_type (code->expr2, ns, get_data);
   if (code->expr2->rank == 0)
     code->expr2 = gfc_build_intrinsic_call (ns, GFC_ISYM_C_LOC, "C_LOC",
 					    gfc_current_locus, 1, code->expr2);
@@ -632,6 +865,7 @@ create_get_callback (gfc_expr *expr)
    *       *free_buffer = 0; for rank == 0.  */
   code->next = gfc_get_code (EXEC_ASSIGN);
   code = code->next;
+  code->loc = expr->where;
   code->expr1 = gfc_lval_expr_from_sym (free_buffer);
   if (expr->rank != 0)
     {
@@ -653,13 +887,24 @@ create_get_callback (gfc_expr *expr)
   cb = gfc_lval_expr_from_sym (extproc);
   cb->ts.interface = extproc;

+  if (caf_accessor_prepend)
+    {
+      gfc_code *c = caf_accessor_prepend;
+      /* Find last in chain.  */
+      for (; c->next; c = c->next)
+	;
+      c->next = sub_ns->code;
+      sub_ns->code = caf_accessor_prepend;
+    }
+  caf_accessor_prepend = backup_caf_accessor_prepend;
   return cb;
 }

-static void
-add_caf_get_intrinsic (gfc_expr *e)
+void
+add_caf_get_from_remote (gfc_expr *e)
 {
-  gfc_expr *wrapper, *tmp_expr, *rget_expr, *rget_hash_expr;
+  gfc_expr *wrapper, *tmp_expr, *get_from_remote_expr,
+    *get_from_remote_hash_expr;
   gfc_ref *ref;
   int n;

@@ -675,18 +920,19 @@ add_caf_get_intrinsic (gfc_expr *e)

   tmp_expr = XCNEW (gfc_expr);
   *tmp_expr = *e;
-  rget_expr = create_get_callback (tmp_expr);
-  rget_hash_expr = gfc_get_expr ();
-  rget_hash_expr->expr_type = EXPR_CONSTANT;
-  rget_hash_expr->ts.type = BT_INTEGER;
-  rget_hash_expr->ts.kind = gfc_default_integer_kind;
-  rget_hash_expr->where = tmp_expr->where;
-  mpz_init_set_ui (rget_hash_expr->value.integer,
-		   gfc_hash_value (rget_expr->symtree->n.sym));
+  get_from_remote_expr = create_get_callback (tmp_expr);
+  get_from_remote_hash_expr = gfc_get_expr ();
+  get_from_remote_hash_expr->expr_type = EXPR_CONSTANT;
+  get_from_remote_hash_expr->ts.type = BT_INTEGER;
+  get_from_remote_hash_expr->ts.kind = gfc_default_integer_kind;
+  get_from_remote_hash_expr->where = tmp_expr->where;
+  mpz_init_set_ui (get_from_remote_hash_expr->value.integer,
+		   gfc_hash_value (get_from_remote_expr->symtree->n.sym));
   wrapper = gfc_build_intrinsic_call (gfc_current_ns, GFC_ISYM_CAF_GET,
 				      "caf_get", tmp_expr->where, 3, tmp_expr,
-				      rget_hash_expr, rget_expr);
-  gfc_add_caf_accessor (rget_hash_expr, rget_expr);
+				      get_from_remote_hash_expr,
+				      get_from_remote_expr);
+  gfc_add_caf_accessor (get_from_remote_hash_expr, get_from_remote_expr);
   wrapper->ts = e->ts;
   wrapper->rank = e->rank;
   wrapper->corank = e->corank;
@@ -700,19 +946,33 @@ static int
 coindexed_expr_callback (gfc_expr **e, int *walk_subtrees,
 			 void *data ATTRIBUTE_UNUSED)
 {
-  if ((*e)->expr_type == EXPR_VARIABLE)
+  *walk_subtrees = 1;
+
+  switch ((*e)->expr_type)
     {
+    case EXPR_VARIABLE:
       if (!caf_on_lhs && gfc_is_coindexed (*e))
 	{
-	  add_caf_get_intrinsic (*e);
+	  add_caf_get_from_remote (*e);
 	  *walk_subtrees = 0;
-	  return 0;
 	}
       /* Clear the flag to rewrite caf_gets in sub expressions of the lhs.  */
       caf_on_lhs = false;
+      break;
+    case EXPR_FUNCTION:
+      if ((*e)->value.function.isym)
+	switch ((*e)->value.function.isym->id)
+	  {
+	  case GFC_ISYM_CAF_GET:
+	    *walk_subtrees = 0;
+	    break;
+	  default:
+	    break;
+	  }
+    default:
+      break;
     }

-  *walk_subtrees = 1;
   return 0;
 }

@@ -740,6 +1000,22 @@ coindexed_code_callback (gfc_code **c, int *walk_subtrees,
     case EXEC_EVENT_WAIT:
       *walk_subtrees = 0;
       break;
+    case EXEC_CALL:
+      *walk_subtrees
+	= !((*c)->resolved_isym
+	    && ((*c)->resolved_isym->id == GFC_ISYM_CAF_SEND
+		|| (*c)->resolved_isym->id == GFC_ISYM_ATOMIC_ADD
+		|| (*c)->resolved_isym->id == GFC_ISYM_ATOMIC_AND
+		|| (*c)->resolved_isym->id == GFC_ISYM_ATOMIC_CAS
+		|| (*c)->resolved_isym->id == GFC_ISYM_ATOMIC_DEF
+		|| (*c)->resolved_isym->id == GFC_ISYM_ATOMIC_FETCH_ADD
+		|| (*c)->resolved_isym->id == GFC_ISYM_ATOMIC_FETCH_AND
+		|| (*c)->resolved_isym->id == GFC_ISYM_ATOMIC_FETCH_OR
+		|| (*c)->resolved_isym->id == GFC_ISYM_ATOMIC_FETCH_XOR
+		|| (*c)->resolved_isym->id == GFC_ISYM_ATOMIC_OR
+		|| (*c)->resolved_isym->id == GFC_ISYM_ATOMIC_REF
+		|| (*c)->resolved_isym->id == GFC_ISYM_ATOMIC_XOR));
+      break;
     default:
       *walk_subtrees = 1;
       break;
@@ -754,8 +1030,13 @@ gfc_rewrite (gfc_namespace *ns)
   gfc_current_ns = ns;

   if (flag_coarray == GFC_FCOARRAY_LIB)
-    gfc_code_walker (&ns->code, coindexed_code_callback,
-		     coindexed_expr_callback, NULL);
+    {
+      gfc_code_walker (&ns->code, coindexed_code_callback,
+		       coindexed_expr_callback, NULL);
+
+      for (gfc_namespace *cns = ns->contained; cns; cns = cns->sibling)
+	gfc_rewrite (cns);
+    }

   gfc_current_ns = saved_ns;
 }
diff --git a/gcc/fortran/trans-intrinsic.cc b/gcc/fortran/trans-intrinsic.cc
index 20309aa9776..1a28bfa7a58 100644
--- a/gcc/fortran/trans-intrinsic.cc
+++ b/gcc/fortran/trans-intrinsic.cc
@@ -1811,8 +1811,7 @@ gfc_conv_intrinsic_caf_get (gfc_se *se, gfc_expr *expr, tree lhs,
   gfc_namespace *ns;
   gfc_expr *get_fn_hash = expr->value.function.actual->next->expr,
 	   *get_fn_expr = expr->value.function.actual->next->next->expr;
-  gfc_symbol *add_data_sym
-    = get_fn_expr->symtree->n.sym->formal->next->next->next->sym;
+  gfc_symbol *add_data_sym = get_fn_expr->symtree->n.sym->formal->sym;

   gcc_assert (flag_coarray == GFC_FCOARRAY_LIB);

diff --git a/gcc/testsuite/gfortran.dg/coarray/get_with_fn_parameter.f90 b/gcc/testsuite/gfortran.dg/coarray/get_with_fn_parameter.f90
new file mode 100644
index 00000000000..ac88fec9332
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/coarray/get_with_fn_parameter.f90
@@ -0,0 +1,29 @@
+!{ dg-do run }
+
+! Check that non-pure/non-elemental functions in caf(fn(..))[..]
+! are outlined to be called on this image.
+
+program get_with_fn_parameter
+
+  implicit none
+
+  integer, allocatable :: caf(:)[:]
+  integer, parameter :: i = 10
+  integer :: j
+
+  allocate(caf(i)[*], source = (/(j, j= 1, 10 )/))
+  if (any(caf(fn(i))[1] /= fn(i))) stop 1
+  deallocate(caf)
+
+contains
+
+function fn(n)
+  integer, intent(in) :: n
+  integer :: fn(n)
+  integer :: i
+
+  fn = (/(i, i = 1, n)/)
+end function
+
+end program
+
diff --git a/gcc/testsuite/gfortran.dg/coarray/get_with_scalar_fn.f90 b/gcc/testsuite/gfortran.dg/coarray/get_with_scalar_fn.f90
new file mode 100644
index 00000000000..df402b982cc
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/coarray/get_with_scalar_fn.f90
@@ -0,0 +1,30 @@
+!{ dg-do run }
+
+! Check that non-pure/non-elemental functions in caf(fn(..))[..]
+! are outlined to be called on this image.
+
+program get_with_fn_parameter
+
+  implicit none
+
+  integer, allocatable :: caf(:)[:]
+  integer, parameter :: i = 10
+  integer :: n
+
+  allocate(caf(i)[*], source =(/(n, n = i, 1, -1)/))
+  do n = 1, i
+    if (caf(pivot(n))[1] /= i - pivot(n) + 1) stop n
+  end do
+  deallocate(caf)
+
+contains
+
+function pivot(n)
+  integer, intent(in) :: n
+  integer :: pivot
+
+  pivot = i - n + 1
+end function
+
+end program
+
diff --git a/gcc/testsuite/gfortran.dg/coarray_lib_comm_1.f90 b/gcc/testsuite/gfortran.dg/coarray_lib_comm_1.f90
index b73b7b1dd56..56f2a6c5c7a 100644
--- a/gcc/testsuite/gfortran.dg/coarray_lib_comm_1.f90
+++ b/gcc/testsuite/gfortran.dg/coarray_lib_comm_1.f90
@@ -39,5 +39,5 @@ if (any (A-B /= 0)) STOP 4
 end

 ! { dg-final { scan-tree-dump-times "_gfortran_caf_get_from_remote" 4 "original" } }
-! { dg-final { scan-tree-dump-times "_gfortran_caf_sendget \\\(caf_token.., \\\(integer\\\(kind=\[48\]\\\)\\\) parm.\[0-9\]+.data - \\\(integer\\\(kind=\[48\]\\\)\\\) a, 1, &parm.\[0-9\]+, 0B, caf_token.., \\\(integer\\\(kind=\[48\]\\\)\\\) parm.\[0-9\]+.data - \\\(integer\\\(kind=\[48\]\\\)\\\) a, 1, &parm.\[0-9\]+, 0B, 4, 4, 1, 0B\\\);" 1 "original" } }
+! { dg-final { scan-tree-dump-times "_gfortran_caf_sendget \\\(caf_token.\[0-9\]+, \\\(integer\\\(kind=\[48\]\\\)\\\) parm.\[0-9\]+.data - \\\(integer\\\(kind=\[48\]\\\)\\\) a, 1, &parm.\[0-9\]+, 0B, caf_token.\[0-9\]+, \\\(integer\\\(kind=\[48\]\\\)\\\) parm.\[0-9\]+.data - \\\(integer\\\(kind=\[48\]\\\)\\\) a, 1, &parm.\[0-9\]+, 0B, 4, 4, 1, 0B\\\);" 1 "original" } }

diff --git a/libgfortran/caf/libcaf.h b/libgfortran/caf/libcaf.h
index 0917fad91f8..4f41f5dcb67 100644
--- a/libgfortran/caf/libcaf.h
+++ b/libgfortran/caf/libcaf.h
@@ -234,8 +234,9 @@ void _gfortran_caf_sendget_by_ref (
 	int *src_stat, int dst_type, int src_type);

 void _gfortran_caf_register_accessor (
-  const int hash, void (*accessor) (void **, int32_t *, void *, void *,
-				    size_t *, const size_t *));
+  const int hash,
+  void (*accessor) (void *, const int *, void **, int32_t *, void *,
+		    caf_token_t, const size_t, size_t *, const size_t *));

 void _gfortran_caf_register_accessors_finish (void);

diff --git a/libgfortran/caf/single.c b/libgfortran/caf/single.c
index 11d0efb0ad1..573da1b85bf 100644
--- a/libgfortran/caf/single.c
+++ b/libgfortran/caf/single.c
@@ -57,13 +57,17 @@ typedef struct caf_single_token *caf_single_token_t;
 /* Global variables.  */
 caf_static_t *caf_static_list = NULL;

-typedef void (*accessor_t) (void **, int32_t *, void *, void *, size_t *,
+typedef void (*accessor_t) (void *, const int *, void **, int32_t *, void *,
+			    caf_token_t, const size_t, size_t *,
 			    const size_t *);
 struct accessor_hash_t
 {
   int hash;
   int pad;
-  accessor_t accessor;
+  union
+  {
+    accessor_t accessor;
+  } u;
 };

 static struct accessor_hash_t *accessor_hash_table = NULL;
@@ -2874,7 +2878,7 @@ _gfortran_caf_register_accessor (const int hash, accessor_t accessor)
       accessor_hash_table_state = AHT_OPEN;
     }
   accessor_hash_table[aht_size].hash = hash;
-  accessor_hash_table[aht_size].accessor = accessor;
+  accessor_hash_table[aht_size].u.accessor = accessor;
   ++aht_size;
 }

@@ -2919,7 +2923,7 @@ _gfortran_caf_get_remote_function_index (const int hash)
 void
 _gfortran_caf_get_from_remote (
   caf_token_t token, const gfc_descriptor_t *opt_src_desc,
-  const size_t *opt_src_charlen, const int image_index __attribute__ ((unused)),
+  const size_t *opt_src_charlen, const int image_index,
   const size_t dst_size __attribute__ ((unused)), void **dst_data,
   size_t *opt_dst_charlen, gfc_descriptor_t *opt_dst_desc,
   const bool may_realloc_dst, const int getter_index, void *get_data,
@@ -2932,6 +2936,10 @@ _gfortran_caf_get_from_remote (
   int32_t free_buffer;
   void *dst_ptr = opt_dst_desc ? (void *)opt_dst_desc : dst_data;
   void *old_dst_data_ptr = NULL;
+  struct caf_single_token cb_token;
+  cb_token.memptr = get_data;
+  cb_token.desc = NULL;
+  cb_token.owning_memory = false;

   if (stat)
     *stat = 0;
@@ -2942,9 +2950,10 @@ _gfortran_caf_get_from_remote (
       opt_dst_desc->base_addr = NULL;
     }

-  accessor_hash_table[getter_index].accessor (dst_ptr, &free_buffer, src_ptr,
-					      get_data, opt_dst_charlen,
-					      opt_src_charlen);
+  accessor_hash_table[getter_index].u.accessor (get_data, &image_index, dst_ptr,
+						&free_buffer, src_ptr,
+						&cb_token, 0, opt_dst_charlen,
+						opt_src_charlen);
   if (opt_dst_desc && old_dst_data_ptr && !may_realloc_dst
       && opt_dst_desc->base_addr != old_dst_data_ptr)
     {
--
2.48.1

Reply via email to