diff --git a/gcc/fortran/coarray.cc b/gcc/fortran/coarray.cc
index 50029102eb9ad5a7e0adda212bfa5143c3851612..e5648e0d02798a219b534f46c6ce95ab30eb84ac 100644
--- a/gcc/fortran/coarray.cc
+++ b/gcc/fortran/coarray.cc
@@ -1351,12 +1351,6 @@ rewrite_caf_send (gfc_code *c)
       && arg->next->next && arg->next->next->expr->expr_type == EXPR_VARIABLE)
     return;
 
-  if (gfc_is_coindexed (rhs))
-    {
-      c->resolved_isym->id = GFC_ISYM_CAF_SENDGET;
-      return;
-    }
-
   send_to_remote_expr = create_send_callback (lhs, rhs);
   send_to_remote_hash_expr = gfc_get_expr ();
   send_to_remote_hash_expr->expr_type = EXPR_CONSTANT;
@@ -1372,6 +1366,28 @@ rewrite_caf_send (gfc_code *c)
   arg = arg->next;
   arg->expr = send_to_remote_expr;
   gfc_add_caf_accessor (send_to_remote_hash_expr, send_to_remote_expr);
+
+  if (gfc_is_coindexed (rhs))
+    {
+      gfc_expr *get_from_remote_expr, *get_from_remote_hash_expr;
+
+      c->resolved_isym = gfc_intrinsic_subroutine_by_id (GFC_ISYM_CAF_SENDGET);
+      get_from_remote_expr = create_get_callback (rhs);
+      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 = rhs->where;
+      mpz_init_set_ui (get_from_remote_hash_expr->value.integer,
+		       gfc_hash_value (get_from_remote_expr->symtree->n.sym));
+      arg->next = gfc_get_actual_arglist ();
+      arg = arg->next;
+      arg->expr = get_from_remote_hash_expr;
+      arg->next = gfc_get_actual_arglist ();
+      arg = arg->next;
+      arg->expr = get_from_remote_expr;
+      gfc_add_caf_accessor (get_from_remote_hash_expr, get_from_remote_expr);
+    }
 }
 
 static int
@@ -1451,7 +1467,9 @@ coindexed_code_callback (gfc_code **c, int *walk_subtrees,
 	    *walk_subtrees = 0;
 	    break;
 	  case GFC_ISYM_CAF_SENDGET:
-	    // rewrite_caf_sendget (*c);
+	    /* Seldomly this routine is called again with the symbol already
+	       changed to CAF_SENDGET.  Do not process the subtree again.  The
+	       rewrite has already been done by rewrite_caf_send ().  */
 	    *walk_subtrees = 0;
 	    break;
 	  case GFC_ISYM_ATOMIC_ADD:
diff --git a/gcc/fortran/gfortran.texi b/gcc/fortran/gfortran.texi
index 059022ea54393845cb6f33d1229e21ae6a61503a..36c203b27b3a993d98c2fff2b674e05d5f8e25c7 100644
--- a/gcc/fortran/gfortran.texi
+++ b/gcc/fortran/gfortran.texi
@@ -4214,6 +4214,7 @@ future implementation of teams.  It is about to change without further notice.
 * _gfortran_caf_get_from_remote:: Getting data from a remote image using a remote side accessor
 * _gfortran_caf_is_present_on_remote:: Check that a coarray or a part of it is allocated on the remote image
 * _gfortran_caf_send_to_remote:: Send data to a remote image using a remote side accessor to store it
+* _gfortran_caf_transfer_between_remotes:: Initiate data transfer between to remote images
 * _gfortran_caf_sendget_by_ref:: Sending data between remote images using enhanced references
 * _gfortran_caf_lock:: Locking a lock variable
 * _gfortran_caf_unlock:: Unlocking a lock variable
@@ -5153,6 +5154,111 @@ The implementation has to take care that it handles this case, e.g. using
 @end table
 
 
+@node _gfortran_caf_transfer_between_remotes
+@subsection @code{_gfortran_caf_transfer_between_remotes} --- Initiate data transfer between to remote images
+@cindex Coarray, _gfortran_caf_transfer_between_remotes
+
+@table @asis
+@item @emph{Description}:
+Initiates a transfer of data from one remote image to another remote image.
+The call modifies the memory of the receiving remote image given by
+@code{dst_image_index}.  The @code{src_image_index}'s memory is not modified.
+The call returns when the transfer has commenced.
+
+@item @emph{Syntax}:
+@code{void _gfortran_caf_transfer_between_remotes (caf_token_t dst_token,
+gfc_descriptor_t *opt_dst_desc, size_t *opt_dst_charlen,
+const int dst_image_index, const int dst_access_index, void *dst_add_data,
+const size_t dst_add_data_size, caf_token_t src_token,
+const gfc_descriptor_t *opt_src_desc, const size_t *opt_src_charlen,
+const int src_image_index, const int src_access_index, void *src_add_data,
+const size_t src_add_data_size, const size_t src_size,
+const bool scalar_transfer, int *dst_stat, int *src_stat, caf_team_t *dst_team,
+int *dst_team_number, caf_team_t *src_team, int *src_team_number)
+}
+
+@item @emph{Arguments}:
+@multitable @columnfractions .15 .70
+@item @var{dst_token} @tab intent(in)  An opaque pointer identifying the coarray
+on the receiving image.
+@item @var{opt_dst_desc} @tab intent(inout)  A pointer to the descriptor when
+the object identified by @var{dst_token} is an array with a descriptor.  The
+parameter needs to be set to @code{NULL}, when @var{dst_token} identifies a
+scalar or is an array without a descriptor.
+@item @var{opt_dst_charlen} @tab intent(in) When the object to modify on the
+receiving image is a char array with deferred length, then this parameter needs
+to be set to point to its length.  Else the parameter needs to be set to
+@code{NULL}.
+@item @var{dst_image_index} @tab intent(in)  The ID of the receiving/destination
+remote image; must be a positive number.  @code{this_image ()} is valid.
+@item @var{dst_access_index} @tab intent(in)  The index of the accessor to
+execute on the receiving image as returned by
+@code{_gfortran_caf_get_remote_function_index ()}.
+@item @var{dst_add_data} @tab intent(inout)  Additional data needed in the
+accessor on the receiving side.  I.e., when an array reference uses a local
+variable @var{v}, it is transported in this structure and all references in the
+accessor are rewritten to access the member.  The data in the structure of
+@var{dst_add_data} may be changed by the accessor, but these changes are lost to
+the calling Fortran program.
+@item @var{dst_add_data_size} @tab intent(in)  The size of the
+@var{dst_add_data} structure.
+@item @var{src_token} @tab intent(in)  An opaque pointer identifying the coarray
+on the sending image.
+@item @var{opt_src_desc} @tab intent(inout)  A pointer to the descriptor when
+the object identified by @var{src_token} is an array with a descriptor.  The
+parameter needs to be set to @code{NULL}, when @var{src_token} identifies a
+scalar or is an array without a descriptor.
+@item @var{opt_src_charlen} @tab intent(in) When the object to get from the
+source image is a char array with deferred length, then this parameter needs
+to be set to point to its length.  Else the parameter needs to be set to
+@code{NULL}.
+@item @var{src_image_index} @tab intent(in)  The ID of the sending/source
+remote image; must be a positive number.  @code{this_image ()} is valid.
+@item @var{src_access_index} @tab intent(in)  The index of the accessor to
+execute on the sending image as returned by
+@code{_gfortran_caf_get_remote_function_index ()}.
+@item @var{src_add_data} @tab intent(inout)  Additional data needed in the
+accessor on the sending side.  I.e., when an array reference uses a local
+variable @var{v}, it is transported in this structure and all references in the
+accessor are rewritten to access the member.  The data in the structure of
+@var{src_add_data} may be changed by the accessor, but these changes are lost to
+the calling Fortran program.
+@item @var{src_add_data_size} @tab intent(in)  The size of the
+@var{src_add_data} structure.
+@item @var{src_size} @tab intent(in) The size of data expected to be transferred
+between the images.  If the data type to get is a string or string array,
+then this needs to be set to the byte size of each character, i.e. @code{4} for
+a @code{CHARACTER (KIND=4)} string.  The length of the string is then given
+in @code{opt_src_charlen} and @code{opt_dst_charlen} (also for string arrays).
+@item @var{scalar_transfer} @tab intent(in)  Is set to true when the data to be
+transfered between the two images is not an array with a descriptor.
+@item @var{dst_stat} @tab intent(out) When non-@code{NULL} give the result of
+the operation on the receiving side, i.e., zero on success and non-zero on
+error.  When @code{NULL} and an error occurs, then an error message is printed
+and the program is terminated.
+@item @var{src_stat} @tab intent(out) When non-@code{NULL} give the result of
+the operation on the sending side, i.e., zero on success and non-zero on error.
+When @code{NULL} and an error occurs, then an error message is printed and the
+program is terminated.
+@item @var{dst_team} @tab intent(in)  The opaque team handle as returned by
+@code{FORM TEAM}.  Unused at the moment.
+@item @var{dst_team_number} @tab intent(in)  The number of the team this access
+is to be part of.  Unused at the moment.
+@item @var{src_team} @tab intent(in)  The opaque team handle as returned by
+@code{FORM TEAM}.  Unused at the moment.
+@item @var{src_team_number} @tab intent(in)  The number of the team this access
+is to be part of.  Unused at the moment.
+@end multitable
+
+@item @emph{NOTES}
+It is permitted to have both @code{dst_image_index} and @code{src_image_index}
+equal the current image; the memory to send the data to and the memory to read
+for the data may (partially) overlap.  The implementation has to take care that
+it handles this case, e.g. using @code{memmove} which handles (partially)
+overlapping memory.
+@end table
+
+
 @node _gfortran_caf_sendget_by_ref
 @subsection @code{_gfortran_caf_sendget_by_ref} --- Sending data between remote images using enhanced references on both sides
 @cindex Coarray, _gfortran_caf_sendget_by_ref
diff --git a/gcc/fortran/intrinsic.cc b/gcc/fortran/intrinsic.cc
index 99d5abcb9d5de464101e6a4f2c531a94102ef65b..30f532b5766b2a6460d4cc8d6ecf2e9fbde0599b 100644
--- a/gcc/fortran/intrinsic.cc
+++ b/gcc/fortran/intrinsic.cc
@@ -3898,6 +3898,10 @@ add_subroutines (void)
 	      "y", BT_REAL, dr, REQUIRED, INTENT_IN);
   make_from_module();
 
+  add_sym_2s (GFC_PREFIX ("caf_sendget"), GFC_ISYM_CAF_SENDGET, CLASS_IMPURE,
+	      BT_UNKNOWN, 0, GFC_STD_GNU, NULL, NULL, NULL, "x", BT_REAL, dr,
+	      REQUIRED, INTENT_OUT, "y", BT_REAL, dr, REQUIRED, INTENT_IN);
+  make_from_module ();
 
   /* More G77 compatibility garbage.  */
   add_sym_3s ("alarm", GFC_ISYM_ALARM, CLASS_IMPURE, BT_UNKNOWN, 0, GFC_STD_GNU,
diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc
index 37df931075bb0ed1d93e49d53a18a609944709f4..025ad539d25307b29758127b28dfe42c63ee2753 100644
--- a/gcc/fortran/trans-decl.cc
+++ b/gcc/fortran/trans-decl.cc
@@ -149,6 +149,7 @@ tree gfor_fndecl_caf_register_accessors_finish;
 tree gfor_fndecl_caf_get_remote_function_index;
 tree gfor_fndecl_caf_get_from_remote;
 tree gfor_fndecl_caf_send_to_remote;
+tree gfor_fndecl_caf_transfer_between_remotes;
 
 tree gfor_fndecl_caf_sync_all;
 tree gfor_fndecl_caf_sync_memory;
@@ -4144,9 +4145,19 @@ gfc_build_builtin_function_decls (void)
 	  pvoid_type_node, size_type_node, pint_type, pvoid_type_node,
 	  pint_type);
 
+      gfor_fndecl_caf_transfer_between_remotes
+	= gfc_build_library_function_decl_with_spec (
+	  get_identifier (PREFIX ("caf_transfer_between_remotes")),
+	  ". r r r r r r r r r r r r r r r r w w r r ", void_type_node, 20,
+	  pvoid_type_node, pvoid_type_node, psize_type, integer_type_node,
+	  integer_type_node, pvoid_type_node, size_type_node, pvoid_type_node,
+	  pvoid_type_node, psize_type, integer_type_node, integer_type_node,
+	  pvoid_type_node, size_type_node, size_type_node, boolean_type_node,
+	  pint_type, pint_type, pvoid_type_node, pint_type);
+
       gfor_fndecl_caf_sync_all = gfc_build_library_function_decl_with_spec (
-	get_identifier (PREFIX("caf_sync_all")), ". w w . ", void_type_node,
-	3, pint_type, pchar_type_node, size_type_node);
+	get_identifier (PREFIX ("caf_sync_all")), ". w w . ", void_type_node, 3,
+	pint_type, pchar_type_node, size_type_node);
 
       gfor_fndecl_caf_sync_memory = gfc_build_library_function_decl_with_spec (
 	get_identifier (PREFIX("caf_sync_memory")), ". w w . ", void_type_node,
diff --git a/gcc/fortran/trans-intrinsic.cc b/gcc/fortran/trans-intrinsic.cc
index 19286f7a0ae07e56d824496b4f7d3aa24efce1ae..84f18a533a9292b01bb440f5bbdd37083fa5f0b8 100644
--- a/gcc/fortran/trans-intrinsic.cc
+++ b/gcc/fortran/trans-intrinsic.cc
@@ -1041,632 +1041,636 @@ gfc_conv_intrinsic_exponent (gfc_se *se, gfc_expr *expr)
        } u;
      }  */
 
-static void
-conv_caf_vector_subscript_elem (stmtblock_t *block, int i, tree desc,
-				tree lower, tree upper, tree stride,
-				tree vector, int kind, tree nvec)
-{
-  tree field, type, tmp;
-
-  desc = gfc_build_array_ref (desc, gfc_rank_cst[i], NULL_TREE);
-  type = TREE_TYPE (desc);
-
-  field = gfc_advance_chain (TYPE_FIELDS (type), 0);
-  tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
-			 desc, field, NULL_TREE);
-  gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field), nvec));
-
-  /* Access union.  */
-  field = gfc_advance_chain (TYPE_FIELDS (type), 1);
-  desc = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
-			  desc, field, NULL_TREE);
-  type = TREE_TYPE (desc);
-
-  /* Access the inner struct.  */
-  field = gfc_advance_chain (TYPE_FIELDS (type), vector != NULL_TREE ? 0 : 1);
-  desc = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
-		      desc, field, NULL_TREE);
-  type = TREE_TYPE (desc);
-
-  if (vector != NULL_TREE)
-    {
-      /* Set vector and kind.  */
-      field = gfc_advance_chain (TYPE_FIELDS (type), 0);
-      tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
-			 desc, field, NULL_TREE);
-      gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field), vector));
-      field = gfc_advance_chain (TYPE_FIELDS (type), 1);
-      tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
-			 desc, field, NULL_TREE);
-      gfc_add_modify (block, tmp, build_int_cst (integer_type_node, kind));
-    }
-  else
-    {
-      /* Set dim.lower/upper/stride.  */
-      field = gfc_advance_chain (TYPE_FIELDS (type), 0);
-      tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
-			     desc, field, NULL_TREE);
-      gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field), lower));
-
-      field = gfc_advance_chain (TYPE_FIELDS (type), 1);
-      tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
-			     desc, field, NULL_TREE);
-      gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field), upper));
-
-      field = gfc_advance_chain (TYPE_FIELDS (type), 2);
-      tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
-			     desc, field, NULL_TREE);
-      gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field), stride));
-    }
-}
-
-
-static tree
-conv_caf_vector_subscript (stmtblock_t *block, tree desc, gfc_array_ref *ar)
-{
-  gfc_se argse;
-  tree var, lower, upper = NULL_TREE, stride = NULL_TREE, vector, nvec;
-  tree lbound, ubound, tmp;
-  int i;
-
-  var = gfc_create_var (gfc_get_caf_vector_type (ar->dimen), "vector");
-
-  for (i = 0; i < ar->dimen; i++)
-    switch (ar->dimen_type[i])
-      {
-      case DIMEN_RANGE:
-        if (ar->end[i])
-	  {
-	    gfc_init_se (&argse, NULL);
-	    gfc_conv_expr (&argse, ar->end[i]);
-	    gfc_add_block_to_block (block, &argse.pre);
-	    upper = gfc_evaluate_now (argse.expr, block);
-	  }
-        else
-	  upper = gfc_conv_descriptor_ubound_get (desc, gfc_rank_cst[i]);
-	if (ar->stride[i])
-	  {
-	    gfc_init_se (&argse, NULL);
-	    gfc_conv_expr (&argse, ar->stride[i]);
-	    gfc_add_block_to_block (block, &argse.pre);
-	    stride = gfc_evaluate_now (argse.expr, block);
-	  }
-	else
-	  stride = gfc_index_one_node;
-
-	/* Fall through.  */
-      case DIMEN_ELEMENT:
-	if (ar->start[i])
-	  {
-	    gfc_init_se (&argse, NULL);
-	    gfc_conv_expr (&argse, ar->start[i]);
-	    gfc_add_block_to_block (block, &argse.pre);
-	    lower = gfc_evaluate_now (argse.expr, block);
-	  }
-	else
-	  lower = gfc_conv_descriptor_lbound_get (desc, gfc_rank_cst[i]);
-	if (ar->dimen_type[i] == DIMEN_ELEMENT)
-	  {
-	    upper = lower;
-	    stride = gfc_index_one_node;
-	  }
-	vector = NULL_TREE;
-	nvec = size_zero_node;
-	conv_caf_vector_subscript_elem (block, i, var, lower, upper, stride,
-					vector, 0, nvec);
-	break;
-
-      case DIMEN_VECTOR:
-	gfc_init_se (&argse, NULL);
-	argse.descriptor_only = 1;
-	gfc_conv_expr_descriptor (&argse, ar->start[i]);
-	gfc_add_block_to_block (block, &argse.pre);
-	vector = argse.expr;
-	lbound = gfc_conv_descriptor_lbound_get (vector, gfc_rank_cst[0]);
-	ubound = gfc_conv_descriptor_ubound_get (vector, gfc_rank_cst[0]);
-	nvec = gfc_conv_array_extent_dim (lbound, ubound, NULL);
-        tmp = gfc_conv_descriptor_stride_get (vector, gfc_rank_cst[0]);
-	nvec = fold_build2_loc (input_location, TRUNC_DIV_EXPR,
-				TREE_TYPE (nvec), nvec, tmp);
-	lower = gfc_index_zero_node;
-	upper = gfc_index_zero_node;
-	stride = gfc_index_zero_node;
-	vector = gfc_conv_descriptor_data_get (vector);
-	conv_caf_vector_subscript_elem (block, i, var, lower, upper, stride,
-					vector, ar->start[i]->ts.kind, nvec);
-	break;
-      default:
-	gcc_unreachable();
-    }
-  return gfc_build_addr_expr (NULL_TREE, var);
-}
-
-
-static tree
-compute_component_offset (tree field, tree type)
-{
-  tree tmp;
-  if (DECL_FIELD_BIT_OFFSET (field) != NULL_TREE
-      && !integer_zerop (DECL_FIELD_BIT_OFFSET (field)))
-    {
-      tmp = fold_build2 (TRUNC_DIV_EXPR, type,
-			 DECL_FIELD_BIT_OFFSET (field),
-			 bitsize_unit_node);
-      return fold_build2 (PLUS_EXPR, type, DECL_FIELD_OFFSET (field), tmp);
-    }
-  else
-    return DECL_FIELD_OFFSET (field);
-}
-
-
-static tree
-conv_expr_ref_to_caf_ref (stmtblock_t *block, gfc_expr *expr)
-{
-  gfc_ref *ref = expr->ref, *last_comp_ref;
-  tree caf_ref = NULL_TREE, prev_caf_ref = NULL_TREE, reference_type, tmp, tmp2,
-      field, last_type, inner_struct, mode, mode_rhs, dim_array, dim, dim_type,
-      start, end, stride, vector, nvec;
-  gfc_se se;
-  bool ref_static_array = false;
-  tree last_component_ref_tree = NULL_TREE;
-  int i, last_type_n;
-
-  if (expr->symtree)
-    {
-      last_component_ref_tree = expr->symtree->n.sym->backend_decl;
-      ref_static_array = !expr->symtree->n.sym->attr.allocatable
-	  && !expr->symtree->n.sym->attr.pointer;
-    }
-
-  /* Prevent uninit-warning.  */
-  reference_type = NULL_TREE;
-
-  /* Skip refs upto the first coarray-ref.  */
-  last_comp_ref = NULL;
-  while (ref && (ref->type != REF_ARRAY || ref->u.ar.codimen == 0))
-    {
-      /* Remember the type of components skipped.  */
-      if (ref->type == REF_COMPONENT)
-	last_comp_ref = ref;
-      ref = ref->next;
-    }
-  /* When a component was skipped, get the type information of the last
-     component ref, else get the type from the symbol.  */
-  if (last_comp_ref)
-    {
-      last_type = gfc_typenode_for_spec (&last_comp_ref->u.c.component->ts);
-      last_type_n = last_comp_ref->u.c.component->ts.type;
-    }
-  else
-    {
-      last_type = gfc_typenode_for_spec (&expr->symtree->n.sym->ts);
-      last_type_n = expr->symtree->n.sym->ts.type;
-    }
-
-  while (ref)
-    {
-      if (ref->type == REF_ARRAY && ref->u.ar.codimen > 0
-	  && ref->u.ar.dimen == 0)
-	{
-	  /* Skip pure coindexes.  */
-	  ref = ref->next;
-	  continue;
-	}
-      tmp = gfc_create_var (gfc_get_caf_reference_type (), "caf_ref");
-      reference_type = TREE_TYPE (tmp);
-
-      if (caf_ref == NULL_TREE)
-	caf_ref = tmp;
-
-      /* Construct the chain of refs.  */
-      if (prev_caf_ref != NULL_TREE)
-	{
-	  field = gfc_advance_chain (TYPE_FIELDS (reference_type), 0);
-	  tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
-				  TREE_TYPE (field), prev_caf_ref, field,
-				  NULL_TREE);
-	  gfc_add_modify (block, tmp2, gfc_build_addr_expr (TREE_TYPE (field),
-							    tmp));
-	}
-      prev_caf_ref = tmp;
-
-      switch (ref->type)
-	{
-	case REF_COMPONENT:
-	  last_type = gfc_typenode_for_spec (&ref->u.c.component->ts);
-	  last_type_n = ref->u.c.component->ts.type;
-	  /* Set the type of the ref.  */
-	  field = gfc_advance_chain (TYPE_FIELDS (reference_type), 1);
-	  tmp = fold_build3_loc (input_location, COMPONENT_REF,
-				 TREE_TYPE (field), prev_caf_ref, field,
-				 NULL_TREE);
-	  gfc_add_modify (block, tmp, build_int_cst (integer_type_node,
-						     GFC_CAF_REF_COMPONENT));
-
-	  /* Ref the c in union u.  */
-	  field = gfc_advance_chain (TYPE_FIELDS (reference_type), 3);
-	  tmp = fold_build3_loc (input_location, COMPONENT_REF,
-				 TREE_TYPE (field), prev_caf_ref, field,
-				 NULL_TREE);
-	  field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (field)), 0);
-	  inner_struct = fold_build3_loc (input_location, COMPONENT_REF,
-				       TREE_TYPE (field), tmp, field,
-				       NULL_TREE);
-
-	  /* Set the offset.  */
-	  field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (inner_struct)), 0);
-	  tmp = fold_build3_loc (input_location, COMPONENT_REF,
-				 TREE_TYPE (field), inner_struct, field,
-				 NULL_TREE);
-	  /* Computing the offset is somewhat harder.  The bit_offset has to be
-	     taken into account.  When the bit_offset in the field_decl is non-
-	     null, divide it by the bitsize_unit and add it to the regular
-	     offset.  */
-	  tmp2 = compute_component_offset (ref->u.c.component->backend_decl,
-					   TREE_TYPE (tmp));
-	  gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (tmp), tmp2));
-
-	  /* Set caf_token_offset.  */
-	  field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (inner_struct)), 1);
-	  tmp = fold_build3_loc (input_location, COMPONENT_REF,
-				 TREE_TYPE (field), inner_struct, field,
-				 NULL_TREE);
-	  if ((ref->u.c.component->attr.allocatable
-	       || ref->u.c.component->attr.pointer)
-	      && ref->u.c.component->attr.dimension)
-	    {
-	      tree arr_desc_token_offset;
-	      /* Get the token field from the descriptor.  */
-	      arr_desc_token_offset = TREE_OPERAND (
-		    gfc_conv_descriptor_token (ref->u.c.component->backend_decl), 1);
-	      arr_desc_token_offset
-		  = compute_component_offset (arr_desc_token_offset,
-					      TREE_TYPE (tmp));
-	      tmp2 = fold_build2_loc (input_location, PLUS_EXPR,
-				      TREE_TYPE (tmp2), tmp2,
-				      arr_desc_token_offset);
-	    }
-	  else if (ref->u.c.component->caf_token)
-	    tmp2 = compute_component_offset (gfc_comp_caf_token (
-					       ref->u.c.component),
-					     TREE_TYPE (tmp));
-	  else
-	    tmp2 = integer_zero_node;
-	  gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (tmp), tmp2));
-
-	  /* Remember whether this ref was to a non-allocatable/non-pointer
-	     component so the next array ref can be tailored correctly.  */
-	  ref_static_array = !ref->u.c.component->attr.allocatable
-	      && !ref->u.c.component->attr.pointer;
-	  last_component_ref_tree = ref_static_array
-	      ? ref->u.c.component->backend_decl : NULL_TREE;
-	  break;
-	case REF_ARRAY:
-	  if (ref_static_array && ref->u.ar.as->type == AS_DEFERRED)
-	    ref_static_array = false;
-	  /* Set the type of the ref.  */
-	  field = gfc_advance_chain (TYPE_FIELDS (reference_type), 1);
-	  tmp = fold_build3_loc (input_location, COMPONENT_REF,
-				 TREE_TYPE (field), prev_caf_ref, field,
-				 NULL_TREE);
-	  gfc_add_modify (block, tmp, build_int_cst (integer_type_node,
-						     ref_static_array
-						     ? GFC_CAF_REF_STATIC_ARRAY
-						     : GFC_CAF_REF_ARRAY));
-
-	  /* Ref the a in union u.  */
-	  field = gfc_advance_chain (TYPE_FIELDS (reference_type), 3);
-	  tmp = fold_build3_loc (input_location, COMPONENT_REF,
-				 TREE_TYPE (field), prev_caf_ref, field,
-				 NULL_TREE);
-	  field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (field)), 1);
-	  inner_struct = fold_build3_loc (input_location, COMPONENT_REF,
-				       TREE_TYPE (field), tmp, field,
-				       NULL_TREE);
-
-	  /* Set the static_array_type in a for static arrays.  */
-	  if (ref_static_array)
-	    {
-	      field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (inner_struct)),
-					 1);
-	      tmp = fold_build3_loc (input_location, COMPONENT_REF,
-				     TREE_TYPE (field), inner_struct, field,
-				     NULL_TREE);
-	      gfc_add_modify (block, tmp, build_int_cst (TREE_TYPE (tmp),
-							 last_type_n));
-	    }
-	  /* Ref the mode in the inner_struct.  */
-	  field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (inner_struct)), 0);
-	  mode = fold_build3_loc (input_location, COMPONENT_REF,
-				  TREE_TYPE (field), inner_struct, field,
-				  NULL_TREE);
-	  /* Ref the dim in the inner_struct.  */
-	  field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (inner_struct)), 2);
-	  dim_array = fold_build3_loc (input_location, COMPONENT_REF,
-				       TREE_TYPE (field), inner_struct, field,
-				       NULL_TREE);
-	  for (i = 0; i < ref->u.ar.dimen; ++i)
-	    {
-	      /* Ref dim i.  */
-	      dim = gfc_build_array_ref (dim_array, gfc_rank_cst[i], NULL_TREE);
-	      dim_type = TREE_TYPE (dim);
-	      mode_rhs = start = end = stride = NULL_TREE;
-	      switch (ref->u.ar.dimen_type[i])
-		{
-		case DIMEN_RANGE:
-		  if (ref->u.ar.end[i])
-		    {
-		      gfc_init_se (&se, NULL);
-		      gfc_conv_expr (&se, ref->u.ar.end[i]);
-		      gfc_add_block_to_block (block, &se.pre);
-		      if (ref_static_array)
-			{
-			  /* Make the index zero-based, when reffing a static
-			     array.  */
-			  end = se.expr;
-			  gfc_init_se (&se, NULL);
-			  gfc_conv_expr (&se, ref->u.ar.as->lower[i]);
-			  gfc_add_block_to_block (block, &se.pre);
-			  se.expr = fold_build2 (MINUS_EXPR,
-						 gfc_array_index_type,
-						 end, fold_convert (
-						   gfc_array_index_type,
-						   se.expr));
-			}
-		      end = gfc_evaluate_now (fold_convert (
-						gfc_array_index_type,
-						se.expr),
-					      block);
-		    }
-		  else if (ref_static_array)
-		    end = fold_build2 (MINUS_EXPR,
-				       gfc_array_index_type,
-				       gfc_conv_array_ubound (
-					 last_component_ref_tree, i),
-				       gfc_conv_array_lbound (
-					 last_component_ref_tree, i));
-		  else
-		    {
-		      end = NULL_TREE;
-		      mode_rhs = build_int_cst (unsigned_char_type_node,
-						GFC_CAF_ARR_REF_OPEN_END);
-		    }
-		  if (ref->u.ar.stride[i])
-		    {
-		      gfc_init_se (&se, NULL);
-		      gfc_conv_expr (&se, ref->u.ar.stride[i]);
-		      gfc_add_block_to_block (block, &se.pre);
-		      stride = gfc_evaluate_now (fold_convert (
-						   gfc_array_index_type,
-						   se.expr),
-						 block);
-		      if (ref_static_array)
-			{
-			  /* Make the index zero-based, when reffing a static
-			     array.  */
-			  stride = fold_build2 (MULT_EXPR,
-						gfc_array_index_type,
-						gfc_conv_array_stride (
-						  last_component_ref_tree,
-						  i),
-						stride);
-			  gcc_assert (end != NULL_TREE);
-			  /* Multiply with the product of array's stride and
-			     the step of the ref to a virtual upper bound.
-			     We cannot compute the actual upper bound here or
-			     the caflib would compute the extend
-			     incorrectly.  */
-			  end = fold_build2 (MULT_EXPR, gfc_array_index_type,
-					     end, gfc_conv_array_stride (
-					       last_component_ref_tree,
-					       i));
-			  end = gfc_evaluate_now (end, block);
-			  stride = gfc_evaluate_now (stride, block);
-			}
-		    }
-		  else if (ref_static_array)
-		    {
-		      stride = gfc_conv_array_stride (last_component_ref_tree,
-						      i);
-		      end = fold_build2 (MULT_EXPR, gfc_array_index_type,
-					 end, stride);
-		      end = gfc_evaluate_now (end, block);
-		    }
-		  else
-		    /* Always set a ref stride of one to make caflib's
-		       handling easier.  */
-		    stride = gfc_index_one_node;
-
-		  /* Fall through.  */
-		case DIMEN_ELEMENT:
-		  if (ref->u.ar.start[i])
-		    {
-		      gfc_init_se (&se, NULL);
-		      gfc_conv_expr (&se, ref->u.ar.start[i]);
-		      gfc_add_block_to_block (block, &se.pre);
-		      if (ref_static_array)
-			{
-			  /* Make the index zero-based, when reffing a static
-			     array.  */
-			  start = fold_convert (gfc_array_index_type, se.expr);
-			  gfc_init_se (&se, NULL);
-			  gfc_conv_expr (&se, ref->u.ar.as->lower[i]);
-			  gfc_add_block_to_block (block, &se.pre);
-			  se.expr = fold_build2 (MINUS_EXPR,
-						 gfc_array_index_type,
-						 start, fold_convert (
-						   gfc_array_index_type,
-						   se.expr));
-			  /* Multiply with the stride.  */
-			  se.expr = fold_build2 (MULT_EXPR,
-						 gfc_array_index_type,
-						 se.expr,
-						 gfc_conv_array_stride (
-						   last_component_ref_tree,
-						   i));
-			}
-		      start = gfc_evaluate_now (fold_convert (
-						  gfc_array_index_type,
-						  se.expr),
-						block);
-		      if (mode_rhs == NULL_TREE)
-			mode_rhs = build_int_cst (unsigned_char_type_node,
-						  ref->u.ar.dimen_type[i]
-						  == DIMEN_ELEMENT
-						  ? GFC_CAF_ARR_REF_SINGLE
-						  : GFC_CAF_ARR_REF_RANGE);
-		    }
-		  else if (ref_static_array)
-		    {
-		      start = integer_zero_node;
-		      mode_rhs = build_int_cst (unsigned_char_type_node,
-						ref->u.ar.start[i] == NULL
-						? GFC_CAF_ARR_REF_FULL
-						: GFC_CAF_ARR_REF_RANGE);
-		    }
-		  else if (end == NULL_TREE)
-		    mode_rhs = build_int_cst (unsigned_char_type_node,
-					      GFC_CAF_ARR_REF_FULL);
-		  else
-		    mode_rhs = build_int_cst (unsigned_char_type_node,
-					      GFC_CAF_ARR_REF_OPEN_START);
-
-		  /* Ref the s in dim.  */
-		  field = gfc_advance_chain (TYPE_FIELDS (dim_type), 0);
-		  tmp = fold_build3_loc (input_location, COMPONENT_REF,
-					 TREE_TYPE (field), dim, field,
-					 NULL_TREE);
-
-		  /* Set start in s.  */
-		  if (start != NULL_TREE)
-		    {
-		      field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)),
-						 0);
-		      tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
-					      TREE_TYPE (field), tmp, field,
-					      NULL_TREE);
-		      gfc_add_modify (block, tmp2,
-				      fold_convert (TREE_TYPE (tmp2), start));
-		    }
-
-		  /* Set end in s.  */
-		  if (end != NULL_TREE)
-		    {
-		      field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)),
-						 1);
-		      tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
-					      TREE_TYPE (field), tmp, field,
-					      NULL_TREE);
-		      gfc_add_modify (block, tmp2,
-				      fold_convert (TREE_TYPE (tmp2), end));
-		    }
-
-		  /* Set end in s.  */
-		  if (stride != NULL_TREE)
-		    {
-		      field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)),
-						 2);
-		      tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
-					      TREE_TYPE (field), tmp, field,
-					      NULL_TREE);
-		      gfc_add_modify (block, tmp2,
-				      fold_convert (TREE_TYPE (tmp2), stride));
-		    }
-		  break;
-		case DIMEN_VECTOR:
-		  /* TODO: In case of static array.  */
-		  gcc_assert (!ref_static_array);
-		  mode_rhs = build_int_cst (unsigned_char_type_node,
-					    GFC_CAF_ARR_REF_VECTOR);
-		  gfc_init_se (&se, NULL);
-		  se.descriptor_only = 1;
-		  gfc_conv_expr_descriptor (&se, ref->u.ar.start[i]);
-		  gfc_add_block_to_block (block, &se.pre);
-		  vector = se.expr;
-		  tmp = gfc_conv_descriptor_lbound_get (vector,
-							gfc_rank_cst[0]);
-		  tmp2 = gfc_conv_descriptor_ubound_get (vector,
-							 gfc_rank_cst[0]);
-		  nvec = gfc_conv_array_extent_dim (tmp, tmp2, NULL);
-		  tmp = gfc_conv_descriptor_stride_get (vector,
-							gfc_rank_cst[0]);
-		  nvec = fold_build2_loc (input_location, TRUNC_DIV_EXPR,
-					  TREE_TYPE (nvec), nvec, tmp);
-		  vector = gfc_conv_descriptor_data_get (vector);
-
-		  /* Ref the v in dim.  */
-		  field = gfc_advance_chain (TYPE_FIELDS (dim_type), 1);
-		  tmp = fold_build3_loc (input_location, COMPONENT_REF,
-					 TREE_TYPE (field), dim, field,
-					 NULL_TREE);
-
-		  /* Set vector in v.  */
-		  field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)), 0);
-		  tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
-					  TREE_TYPE (field), tmp, field,
-					  NULL_TREE);
-		  gfc_add_modify (block, tmp2, fold_convert (TREE_TYPE (tmp2),
-							     vector));
-
-		  /* Set nvec in v.  */
-		  field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)), 1);
-		  tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
-					  TREE_TYPE (field), tmp, field,
-					  NULL_TREE);
-		  gfc_add_modify (block, tmp2, fold_convert (TREE_TYPE (tmp2),
-							     nvec));
-
-		  /* Set kind in v.  */
-		  field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)), 2);
-		  tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
-					  TREE_TYPE (field), tmp, field,
-					  NULL_TREE);
-		  gfc_add_modify (block, tmp2, build_int_cst (integer_type_node,
-						  ref->u.ar.start[i]->ts.kind));
-		  break;
-		default:
-		  gcc_unreachable ();
-		}
-	      /* Set the mode for dim i.  */
-	      tmp = gfc_build_array_ref (mode, gfc_rank_cst[i], NULL_TREE);
-	      gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (tmp),
-							mode_rhs));
-	    }
-
-	  /* Set the mode for dim i+1 to GFC_ARR_REF_NONE.  */
-	  if (i < GFC_MAX_DIMENSIONS)
-	    {
-	      tmp = gfc_build_array_ref (mode, gfc_rank_cst[i], NULL_TREE);
-	      gfc_add_modify (block, tmp,
-			      build_int_cst (unsigned_char_type_node,
-					     GFC_CAF_ARR_REF_NONE));
-	    }
-	  break;
-	default:
-	  gcc_unreachable ();
-	}
-
-      /* Set the size of the current type.  */
-      field = gfc_advance_chain (TYPE_FIELDS (reference_type), 2);
-      tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
-			     prev_caf_ref, field, NULL_TREE);
-      gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field),
-						TYPE_SIZE_UNIT (last_type)));
-
-      ref = ref->next;
-    }
-
-  if (prev_caf_ref != NULL_TREE)
-    {
-      field = gfc_advance_chain (TYPE_FIELDS (reference_type), 0);
-      tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
-			     prev_caf_ref, field, NULL_TREE);
-      gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field),
-						  null_pointer_node));
-    }
-  return caf_ref != NULL_TREE ? gfc_build_addr_expr (NULL_TREE, caf_ref)
-			      : NULL_TREE;
-}
+// static void
+// conv_caf_vector_subscript_elem (stmtblock_t *block, int i, tree desc,
+// 				tree lower, tree upper, tree stride,
+// 				tree vector, int kind, tree nvec)
+// {
+//   tree field, type, tmp;
+
+//   desc = gfc_build_array_ref (desc, gfc_rank_cst[i], NULL_TREE);
+//   type = TREE_TYPE (desc);
+
+//   field = gfc_advance_chain (TYPE_FIELDS (type), 0);
+//   tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
+// 			 desc, field, NULL_TREE);
+//   gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field), nvec));
+
+//   /* Access union.  */
+//   field = gfc_advance_chain (TYPE_FIELDS (type), 1);
+//   desc = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
+// 			  desc, field, NULL_TREE);
+//   type = TREE_TYPE (desc);
+
+//   /* Access the inner struct.  */
+//   field = gfc_advance_chain (TYPE_FIELDS (type), vector != NULL_TREE ? 0 :
+//   1); desc = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE
+//   (field),
+// 		      desc, field, NULL_TREE);
+//   type = TREE_TYPE (desc);
+
+//   if (vector != NULL_TREE)
+//     {
+//       /* Set vector and kind.  */
+//       field = gfc_advance_chain (TYPE_FIELDS (type), 0);
+//       tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE
+//       (field),
+// 			 desc, field, NULL_TREE);
+//       gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field), vector));
+//       field = gfc_advance_chain (TYPE_FIELDS (type), 1);
+//       tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE
+//       (field),
+// 			 desc, field, NULL_TREE);
+//       gfc_add_modify (block, tmp, build_int_cst (integer_type_node, kind));
+//     }
+//   else
+//     {
+//       /* Set dim.lower/upper/stride.  */
+//       field = gfc_advance_chain (TYPE_FIELDS (type), 0);
+//       tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE
+//       (field),
+// 			     desc, field, NULL_TREE);
+//       gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field), lower));
+
+//       field = gfc_advance_chain (TYPE_FIELDS (type), 1);
+//       tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE
+//       (field),
+// 			     desc, field, NULL_TREE);
+//       gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field), upper));
+
+//       field = gfc_advance_chain (TYPE_FIELDS (type), 2);
+//       tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE
+//       (field),
+// 			     desc, field, NULL_TREE);
+//       gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field), stride));
+//     }
+// }
+
+// static tree
+// conv_caf_vector_subscript (stmtblock_t *block, tree desc, gfc_array_ref *ar)
+// {
+//   gfc_se argse;
+//   tree var, lower, upper = NULL_TREE, stride = NULL_TREE, vector, nvec;
+//   tree lbound, ubound, tmp;
+//   int i;
+
+//   var = gfc_create_var (gfc_get_caf_vector_type (ar->dimen), "vector");
+
+//   for (i = 0; i < ar->dimen; i++)
+//     switch (ar->dimen_type[i])
+//       {
+//       case DIMEN_RANGE:
+//         if (ar->end[i])
+// 	  {
+// 	    gfc_init_se (&argse, NULL);
+// 	    gfc_conv_expr (&argse, ar->end[i]);
+// 	    gfc_add_block_to_block (block, &argse.pre);
+// 	    upper = gfc_evaluate_now (argse.expr, block);
+// 	  }
+//         else
+// 	  upper = gfc_conv_descriptor_ubound_get (desc, gfc_rank_cst[i]);
+// 	if (ar->stride[i])
+// 	  {
+// 	    gfc_init_se (&argse, NULL);
+// 	    gfc_conv_expr (&argse, ar->stride[i]);
+// 	    gfc_add_block_to_block (block, &argse.pre);
+// 	    stride = gfc_evaluate_now (argse.expr, block);
+// 	  }
+// 	else
+// 	  stride = gfc_index_one_node;
+
+// 	/* Fall through.  */
+//       case DIMEN_ELEMENT:
+// 	if (ar->start[i])
+// 	  {
+// 	    gfc_init_se (&argse, NULL);
+// 	    gfc_conv_expr (&argse, ar->start[i]);
+// 	    gfc_add_block_to_block (block, &argse.pre);
+// 	    lower = gfc_evaluate_now (argse.expr, block);
+// 	  }
+// 	else
+// 	  lower = gfc_conv_descriptor_lbound_get (desc, gfc_rank_cst[i]);
+// 	if (ar->dimen_type[i] == DIMEN_ELEMENT)
+// 	  {
+// 	    upper = lower;
+// 	    stride = gfc_index_one_node;
+// 	  }
+// 	vector = NULL_TREE;
+// 	nvec = size_zero_node;
+// 	conv_caf_vector_subscript_elem (block, i, var, lower, upper, stride,
+// 					vector, 0, nvec);
+// 	break;
+
+//       case DIMEN_VECTOR:
+// 	gfc_init_se (&argse, NULL);
+// 	argse.descriptor_only = 1;
+// 	gfc_conv_expr_descriptor (&argse, ar->start[i]);
+// 	gfc_add_block_to_block (block, &argse.pre);
+// 	vector = argse.expr;
+// 	lbound = gfc_conv_descriptor_lbound_get (vector, gfc_rank_cst[0]);
+// 	ubound = gfc_conv_descriptor_ubound_get (vector, gfc_rank_cst[0]);
+// 	nvec = gfc_conv_array_extent_dim (lbound, ubound, NULL);
+//         tmp = gfc_conv_descriptor_stride_get (vector, gfc_rank_cst[0]);
+// 	nvec = fold_build2_loc (input_location, TRUNC_DIV_EXPR,
+// 				TREE_TYPE (nvec), nvec, tmp);
+// 	lower = gfc_index_zero_node;
+// 	upper = gfc_index_zero_node;
+// 	stride = gfc_index_zero_node;
+// 	vector = gfc_conv_descriptor_data_get (vector);
+// 	conv_caf_vector_subscript_elem (block, i, var, lower, upper, stride,
+// 					vector, ar->start[i]->ts.kind, nvec);
+// 	break;
+//       default:
+// 	gcc_unreachable();
+//     }
+//   return gfc_build_addr_expr (NULL_TREE, var);
+// }
+
+// static tree
+// compute_component_offset (tree field, tree type)
+// {
+//   tree tmp;
+//   if (DECL_FIELD_BIT_OFFSET (field) != NULL_TREE
+//       && !integer_zerop (DECL_FIELD_BIT_OFFSET (field)))
+//     {
+//       tmp = fold_build2 (TRUNC_DIV_EXPR, type,
+// 			 DECL_FIELD_BIT_OFFSET (field),
+// 			 bitsize_unit_node);
+//       return fold_build2 (PLUS_EXPR, type, DECL_FIELD_OFFSET (field), tmp);
+//     }
+//   else
+//     return DECL_FIELD_OFFSET (field);
+// }
+
+// static tree
+// conv_expr_ref_to_caf_ref (stmtblock_t *block, gfc_expr *expr)
+// {
+//   gfc_ref *ref = expr->ref, *last_comp_ref;
+//   tree caf_ref = NULL_TREE, prev_caf_ref = NULL_TREE, reference_type, tmp,
+//   tmp2,
+//       field, last_type, inner_struct, mode, mode_rhs, dim_array, dim,
+//       dim_type, start, end, stride, vector, nvec;
+//   gfc_se se;
+//   bool ref_static_array = false;
+//   tree last_component_ref_tree = NULL_TREE;
+//   int i, last_type_n;
+
+//   if (expr->symtree)
+//     {
+//       last_component_ref_tree = expr->symtree->n.sym->backend_decl;
+//       ref_static_array = !expr->symtree->n.sym->attr.allocatable
+// 	  && !expr->symtree->n.sym->attr.pointer;
+//     }
+
+//   /* Prevent uninit-warning.  */
+//   reference_type = NULL_TREE;
+
+//   /* Skip refs upto the first coarray-ref.  */
+//   last_comp_ref = NULL;
+//   while (ref && (ref->type != REF_ARRAY || ref->u.ar.codimen == 0))
+//     {
+//       /* Remember the type of components skipped.  */
+//       if (ref->type == REF_COMPONENT)
+// 	last_comp_ref = ref;
+//       ref = ref->next;
+//     }
+//   /* When a component was skipped, get the type information of the last
+//      component ref, else get the type from the symbol.  */
+//   if (last_comp_ref)
+//     {
+//       last_type = gfc_typenode_for_spec (&last_comp_ref->u.c.component->ts);
+//       last_type_n = last_comp_ref->u.c.component->ts.type;
+//     }
+//   else
+//     {
+//       last_type = gfc_typenode_for_spec (&expr->symtree->n.sym->ts);
+//       last_type_n = expr->symtree->n.sym->ts.type;
+//     }
+
+//   while (ref)
+//     {
+//       if (ref->type == REF_ARRAY && ref->u.ar.codimen > 0
+// 	  && ref->u.ar.dimen == 0)
+// 	{
+// 	  /* Skip pure coindexes.  */
+// 	  ref = ref->next;
+// 	  continue;
+// 	}
+//       tmp = gfc_create_var (gfc_get_caf_reference_type (), "caf_ref");
+//       reference_type = TREE_TYPE (tmp);
+
+//       if (caf_ref == NULL_TREE)
+// 	caf_ref = tmp;
+
+//       /* Construct the chain of refs.  */
+//       if (prev_caf_ref != NULL_TREE)
+// 	{
+// 	  field = gfc_advance_chain (TYPE_FIELDS (reference_type), 0);
+// 	  tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
+// 				  TREE_TYPE (field), prev_caf_ref, field,
+// 				  NULL_TREE);
+// 	  gfc_add_modify (block, tmp2, gfc_build_addr_expr (TREE_TYPE (field),
+// 							    tmp));
+// 	}
+//       prev_caf_ref = tmp;
+
+//       switch (ref->type)
+// 	{
+// 	case REF_COMPONENT:
+// 	  last_type = gfc_typenode_for_spec (&ref->u.c.component->ts);
+// 	  last_type_n = ref->u.c.component->ts.type;
+// 	  /* Set the type of the ref.  */
+// 	  field = gfc_advance_chain (TYPE_FIELDS (reference_type), 1);
+// 	  tmp = fold_build3_loc (input_location, COMPONENT_REF,
+// 				 TREE_TYPE (field), prev_caf_ref, field,
+// 				 NULL_TREE);
+// 	  gfc_add_modify (block, tmp, build_int_cst (integer_type_node,
+// 						     GFC_CAF_REF_COMPONENT));
+
+// 	  /* Ref the c in union u.  */
+// 	  field = gfc_advance_chain (TYPE_FIELDS (reference_type), 3);
+// 	  tmp = fold_build3_loc (input_location, COMPONENT_REF,
+// 				 TREE_TYPE (field), prev_caf_ref, field,
+// 				 NULL_TREE);
+// 	  field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (field)), 0);
+// 	  inner_struct = fold_build3_loc (input_location, COMPONENT_REF,
+// 				       TREE_TYPE (field), tmp, field,
+// 				       NULL_TREE);
+
+// 	  /* Set the offset.  */
+// 	  field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (inner_struct)), 0);
+// 	  tmp = fold_build3_loc (input_location, COMPONENT_REF,
+// 				 TREE_TYPE (field), inner_struct, field,
+// 				 NULL_TREE);
+// 	  /* Computing the offset is somewhat harder.  The bit_offset has to be
+// 	     taken into account.  When the bit_offset in the field_decl is non-
+// 	     null, divide it by the bitsize_unit and add it to the regular
+// 	     offset.  */
+// 	  tmp2 = compute_component_offset (ref->u.c.component->backend_decl,
+// 					   TREE_TYPE (tmp));
+// 	  gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (tmp), tmp2));
+
+// 	  /* Set caf_token_offset.  */
+// 	  field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (inner_struct)), 1);
+// 	  tmp = fold_build3_loc (input_location, COMPONENT_REF,
+// 				 TREE_TYPE (field), inner_struct, field,
+// 				 NULL_TREE);
+// 	  if ((ref->u.c.component->attr.allocatable
+// 	       || ref->u.c.component->attr.pointer)
+// 	      && ref->u.c.component->attr.dimension)
+// 	    {
+// 	      tree arr_desc_token_offset;
+// 	      /* Get the token field from the descriptor.  */
+// 	      arr_desc_token_offset = TREE_OPERAND (
+// 		    gfc_conv_descriptor_token
+// (ref->u.c.component->backend_decl), 1); 	      arr_desc_token_offset
+// = compute_component_offset (arr_desc_token_offset,
+// TREE_TYPE (tmp)); 	      tmp2 = fold_build2_loc (input_location, PLUS_EXPR,
+// TREE_TYPE (tmp2), tmp2, 				      arr_desc_token_offset);
+// 	    }
+// 	  else if (ref->u.c.component->caf_token)
+// 	    tmp2 = compute_component_offset (gfc_comp_caf_token (
+// 					       ref->u.c.component),
+// 					     TREE_TYPE (tmp));
+// 	  else
+// 	    tmp2 = integer_zero_node;
+// 	  gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (tmp), tmp2));
+
+// 	  /* Remember whether this ref was to a non-allocatable/non-pointer
+// 	     component so the next array ref can be tailored correctly.  */
+// 	  ref_static_array = !ref->u.c.component->attr.allocatable
+// 	      && !ref->u.c.component->attr.pointer;
+// 	  last_component_ref_tree = ref_static_array
+// 	      ? ref->u.c.component->backend_decl : NULL_TREE;
+// 	  break;
+// 	case REF_ARRAY:
+// 	  if (ref_static_array && ref->u.ar.as->type == AS_DEFERRED)
+// 	    ref_static_array = false;
+// 	  /* Set the type of the ref.  */
+// 	  field = gfc_advance_chain (TYPE_FIELDS (reference_type), 1);
+// 	  tmp = fold_build3_loc (input_location, COMPONENT_REF,
+// 				 TREE_TYPE (field), prev_caf_ref, field,
+// 				 NULL_TREE);
+// 	  gfc_add_modify (block, tmp, build_int_cst (integer_type_node,
+// 						     ref_static_array
+// 						     ? GFC_CAF_REF_STATIC_ARRAY
+// 						     : GFC_CAF_REF_ARRAY));
+
+// 	  /* Ref the a in union u.  */
+// 	  field = gfc_advance_chain (TYPE_FIELDS (reference_type), 3);
+// 	  tmp = fold_build3_loc (input_location, COMPONENT_REF,
+// 				 TREE_TYPE (field), prev_caf_ref, field,
+// 				 NULL_TREE);
+// 	  field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (field)), 1);
+// 	  inner_struct = fold_build3_loc (input_location, COMPONENT_REF,
+// 				       TREE_TYPE (field), tmp, field,
+// 				       NULL_TREE);
+
+// 	  /* Set the static_array_type in a for static arrays.  */
+// 	  if (ref_static_array)
+// 	    {
+// 	      field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (inner_struct)),
+// 					 1);
+// 	      tmp = fold_build3_loc (input_location, COMPONENT_REF,
+// 				     TREE_TYPE (field), inner_struct, field,
+// 				     NULL_TREE);
+// 	      gfc_add_modify (block, tmp, build_int_cst (TREE_TYPE (tmp),
+// 							 last_type_n));
+// 	    }
+// 	  /* Ref the mode in the inner_struct.  */
+// 	  field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (inner_struct)), 0);
+// 	  mode = fold_build3_loc (input_location, COMPONENT_REF,
+// 				  TREE_TYPE (field), inner_struct, field,
+// 				  NULL_TREE);
+// 	  /* Ref the dim in the inner_struct.  */
+// 	  field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (inner_struct)), 2);
+// 	  dim_array = fold_build3_loc (input_location, COMPONENT_REF,
+// 				       TREE_TYPE (field), inner_struct, field,
+// 				       NULL_TREE);
+// 	  for (i = 0; i < ref->u.ar.dimen; ++i)
+// 	    {
+// 	      /* Ref dim i.  */
+// 	      dim = gfc_build_array_ref (dim_array, gfc_rank_cst[i], NULL_TREE);
+// 	      dim_type = TREE_TYPE (dim);
+// 	      mode_rhs = start = end = stride = NULL_TREE;
+// 	      switch (ref->u.ar.dimen_type[i])
+// 		{
+// 		case DIMEN_RANGE:
+// 		  if (ref->u.ar.end[i])
+// 		    {
+// 		      gfc_init_se (&se, NULL);
+// 		      gfc_conv_expr (&se, ref->u.ar.end[i]);
+// 		      gfc_add_block_to_block (block, &se.pre);
+// 		      if (ref_static_array)
+// 			{
+// 			  /* Make the index zero-based, when reffing a static
+// 			     array.  */
+// 			  end = se.expr;
+// 			  gfc_init_se (&se, NULL);
+// 			  gfc_conv_expr (&se, ref->u.ar.as->lower[i]);
+// 			  gfc_add_block_to_block (block, &se.pre);
+// 			  se.expr = fold_build2 (MINUS_EXPR,
+// 						 gfc_array_index_type,
+// 						 end, fold_convert (
+// 						   gfc_array_index_type,
+// 						   se.expr));
+// 			}
+// 		      end = gfc_evaluate_now (fold_convert (
+// 						gfc_array_index_type,
+// 						se.expr),
+// 					      block);
+// 		    }
+// 		  else if (ref_static_array)
+// 		    end = fold_build2 (MINUS_EXPR,
+// 				       gfc_array_index_type,
+// 				       gfc_conv_array_ubound (
+// 					 last_component_ref_tree, i),
+// 				       gfc_conv_array_lbound (
+// 					 last_component_ref_tree, i));
+// 		  else
+// 		    {
+// 		      end = NULL_TREE;
+// 		      mode_rhs = build_int_cst (unsigned_char_type_node,
+// 						GFC_CAF_ARR_REF_OPEN_END);
+// 		    }
+// 		  if (ref->u.ar.stride[i])
+// 		    {
+// 		      gfc_init_se (&se, NULL);
+// 		      gfc_conv_expr (&se, ref->u.ar.stride[i]);
+// 		      gfc_add_block_to_block (block, &se.pre);
+// 		      stride = gfc_evaluate_now (fold_convert (
+// 						   gfc_array_index_type,
+// 						   se.expr),
+// 						 block);
+// 		      if (ref_static_array)
+// 			{
+// 			  /* Make the index zero-based, when reffing a static
+// 			     array.  */
+// 			  stride = fold_build2 (MULT_EXPR,
+// 						gfc_array_index_type,
+// 						gfc_conv_array_stride (
+// 						  last_component_ref_tree,
+// 						  i),
+// 						stride);
+// 			  gcc_assert (end != NULL_TREE);
+// 			  /* Multiply with the product of array's stride and
+// 			     the step of the ref to a virtual upper bound.
+// 			     We cannot compute the actual upper bound here or
+// 			     the caflib would compute the extend
+// 			     incorrectly.  */
+// 			  end = fold_build2 (MULT_EXPR, gfc_array_index_type,
+// 					     end, gfc_conv_array_stride (
+// 					       last_component_ref_tree,
+// 					       i));
+// 			  end = gfc_evaluate_now (end, block);
+// 			  stride = gfc_evaluate_now (stride, block);
+// 			}
+// 		    }
+// 		  else if (ref_static_array)
+// 		    {
+// 		      stride = gfc_conv_array_stride (last_component_ref_tree,
+// 						      i);
+// 		      end = fold_build2 (MULT_EXPR, gfc_array_index_type,
+// 					 end, stride);
+// 		      end = gfc_evaluate_now (end, block);
+// 		    }
+// 		  else
+// 		    /* Always set a ref stride of one to make caflib's
+// 		       handling easier.  */
+// 		    stride = gfc_index_one_node;
+
+// 		  /* Fall through.  */
+// 		case DIMEN_ELEMENT:
+// 		  if (ref->u.ar.start[i])
+// 		    {
+// 		      gfc_init_se (&se, NULL);
+// 		      gfc_conv_expr (&se, ref->u.ar.start[i]);
+// 		      gfc_add_block_to_block (block, &se.pre);
+// 		      if (ref_static_array)
+// 			{
+// 			  /* Make the index zero-based, when reffing a static
+// 			     array.  */
+// 			  start = fold_convert (gfc_array_index_type, se.expr);
+// 			  gfc_init_se (&se, NULL);
+// 			  gfc_conv_expr (&se, ref->u.ar.as->lower[i]);
+// 			  gfc_add_block_to_block (block, &se.pre);
+// 			  se.expr = fold_build2 (MINUS_EXPR,
+// 						 gfc_array_index_type,
+// 						 start, fold_convert (
+// 						   gfc_array_index_type,
+// 						   se.expr));
+// 			  /* Multiply with the stride.  */
+// 			  se.expr = fold_build2 (MULT_EXPR,
+// 						 gfc_array_index_type,
+// 						 se.expr,
+// 						 gfc_conv_array_stride (
+// 						   last_component_ref_tree,
+// 						   i));
+// 			}
+// 		      start = gfc_evaluate_now (fold_convert (
+// 						  gfc_array_index_type,
+// 						  se.expr),
+// 						block);
+// 		      if (mode_rhs == NULL_TREE)
+// 			mode_rhs = build_int_cst (unsigned_char_type_node,
+// 						  ref->u.ar.dimen_type[i]
+// 						  == DIMEN_ELEMENT
+// 						  ? GFC_CAF_ARR_REF_SINGLE
+// 						  : GFC_CAF_ARR_REF_RANGE);
+// 		    }
+// 		  else if (ref_static_array)
+// 		    {
+// 		      start = integer_zero_node;
+// 		      mode_rhs = build_int_cst (unsigned_char_type_node,
+// 						ref->u.ar.start[i] == NULL
+// 						? GFC_CAF_ARR_REF_FULL
+// 						: GFC_CAF_ARR_REF_RANGE);
+// 		    }
+// 		  else if (end == NULL_TREE)
+// 		    mode_rhs = build_int_cst (unsigned_char_type_node,
+// 					      GFC_CAF_ARR_REF_FULL);
+// 		  else
+// 		    mode_rhs = build_int_cst (unsigned_char_type_node,
+// 					      GFC_CAF_ARR_REF_OPEN_START);
+
+// 		  /* Ref the s in dim.  */
+// 		  field = gfc_advance_chain (TYPE_FIELDS (dim_type), 0);
+// 		  tmp = fold_build3_loc (input_location, COMPONENT_REF,
+// 					 TREE_TYPE (field), dim, field,
+// 					 NULL_TREE);
+
+// 		  /* Set start in s.  */
+// 		  if (start != NULL_TREE)
+// 		    {
+// 		      field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)),
+// 						 0);
+// 		      tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
+// 					      TREE_TYPE (field), tmp, field,
+// 					      NULL_TREE);
+// 		      gfc_add_modify (block, tmp2,
+// 				      fold_convert (TREE_TYPE (tmp2), start));
+// 		    }
+
+// 		  /* Set end in s.  */
+// 		  if (end != NULL_TREE)
+// 		    {
+// 		      field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)),
+// 						 1);
+// 		      tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
+// 					      TREE_TYPE (field), tmp, field,
+// 					      NULL_TREE);
+// 		      gfc_add_modify (block, tmp2,
+// 				      fold_convert (TREE_TYPE (tmp2), end));
+// 		    }
+
+// 		  /* Set end in s.  */
+// 		  if (stride != NULL_TREE)
+// 		    {
+// 		      field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)),
+// 						 2);
+// 		      tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
+// 					      TREE_TYPE (field), tmp, field,
+// 					      NULL_TREE);
+// 		      gfc_add_modify (block, tmp2,
+// 				      fold_convert (TREE_TYPE (tmp2), stride));
+// 		    }
+// 		  break;
+// 		case DIMEN_VECTOR:
+// 		  /* TODO: In case of static array.  */
+// 		  gcc_assert (!ref_static_array);
+// 		  mode_rhs = build_int_cst (unsigned_char_type_node,
+// 					    GFC_CAF_ARR_REF_VECTOR);
+// 		  gfc_init_se (&se, NULL);
+// 		  se.descriptor_only = 1;
+// 		  gfc_conv_expr_descriptor (&se, ref->u.ar.start[i]);
+// 		  gfc_add_block_to_block (block, &se.pre);
+// 		  vector = se.expr;
+// 		  tmp = gfc_conv_descriptor_lbound_get (vector,
+// 							gfc_rank_cst[0]);
+// 		  tmp2 = gfc_conv_descriptor_ubound_get (vector,
+// 							 gfc_rank_cst[0]);
+// 		  nvec = gfc_conv_array_extent_dim (tmp, tmp2, NULL);
+// 		  tmp = gfc_conv_descriptor_stride_get (vector,
+// 							gfc_rank_cst[0]);
+// 		  nvec = fold_build2_loc (input_location, TRUNC_DIV_EXPR,
+// 					  TREE_TYPE (nvec), nvec, tmp);
+// 		  vector = gfc_conv_descriptor_data_get (vector);
+
+// 		  /* Ref the v in dim.  */
+// 		  field = gfc_advance_chain (TYPE_FIELDS (dim_type), 1);
+// 		  tmp = fold_build3_loc (input_location, COMPONENT_REF,
+// 					 TREE_TYPE (field), dim, field,
+// 					 NULL_TREE);
+
+// 		  /* Set vector in v.  */
+// 		  field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)), 0);
+// 		  tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
+// 					  TREE_TYPE (field), tmp, field,
+// 					  NULL_TREE);
+// 		  gfc_add_modify (block, tmp2, fold_convert (TREE_TYPE (tmp2),
+// 							     vector));
+
+// 		  /* Set nvec in v.  */
+// 		  field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)), 1);
+// 		  tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
+// 					  TREE_TYPE (field), tmp, field,
+// 					  NULL_TREE);
+// 		  gfc_add_modify (block, tmp2, fold_convert (TREE_TYPE (tmp2),
+// 							     nvec));
+
+// 		  /* Set kind in v.  */
+// 		  field = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (tmp)), 2);
+// 		  tmp2 = fold_build3_loc (input_location, COMPONENT_REF,
+// 					  TREE_TYPE (field), tmp, field,
+// 					  NULL_TREE);
+// 		  gfc_add_modify (block, tmp2, build_int_cst (integer_type_node,
+// 						  ref->u.ar.start[i]->ts.kind));
+// 		  break;
+// 		default:
+// 		  gcc_unreachable ();
+// 		}
+// 	      /* Set the mode for dim i.  */
+// 	      tmp = gfc_build_array_ref (mode, gfc_rank_cst[i], NULL_TREE);
+// 	      gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (tmp),
+// 							mode_rhs));
+// 	    }
+
+// 	  /* Set the mode for dim i+1 to GFC_ARR_REF_NONE.  */
+// 	  if (i < GFC_MAX_DIMENSIONS)
+// 	    {
+// 	      tmp = gfc_build_array_ref (mode, gfc_rank_cst[i], NULL_TREE);
+// 	      gfc_add_modify (block, tmp,
+// 			      build_int_cst (unsigned_char_type_node,
+// 					     GFC_CAF_ARR_REF_NONE));
+// 	    }
+// 	  break;
+// 	default:
+// 	  gcc_unreachable ();
+// 	}
+
+//       /* Set the size of the current type.  */
+//       field = gfc_advance_chain (TYPE_FIELDS (reference_type), 2);
+//       tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE
+//       (field),
+// 			     prev_caf_ref, field, NULL_TREE);
+//       gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field),
+// 						TYPE_SIZE_UNIT (last_type)));
+
+//       ref = ref->next;
+//     }
+
+//   if (prev_caf_ref != NULL_TREE)
+//     {
+//       field = gfc_advance_chain (TYPE_FIELDS (reference_type), 0);
+//       tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE
+//       (field),
+// 			     prev_caf_ref, field, NULL_TREE);
+//       gfc_add_modify (block, tmp, fold_convert (TREE_TYPE (field),
+// 						  null_pointer_node));
+//     }
+//   return caf_ref != NULL_TREE ? gfc_build_addr_expr (NULL_TREE, caf_ref)
+// 			      : NULL_TREE;
+// }
 
 static int caf_call_cnt = 0;
 
@@ -1802,16 +1806,48 @@ conv_shape_to_cst (gfc_expr *e)
   return fold_convert (size_type_node, tmp);
 }
 
+static void
+conv_stat_and_team (stmtblock_t *block, gfc_expr *expr, tree *stat, tree *team)
+{
+  gfc_expr *stat_e, *team_e;
+
+  stat_e = gfc_find_stat_co (expr);
+  if (stat_e)
+    {
+      gfc_se stat_se;
+      gfc_init_se (&stat_se, NULL);
+      gfc_conv_expr_reference (&stat_se, stat_e);
+      *stat = stat_se.expr;
+      gfc_add_block_to_block (block, &stat_se.pre);
+      gfc_add_block_to_block (block, &stat_se.post);
+    }
+  else
+    *stat = null_pointer_node;
+
+  team_e = gfc_find_team_co (expr);
+  if (team_e)
+    {
+      gfc_se team_se;
+      gfc_init_se (&team_se, NULL);
+      gfc_conv_expr_reference (&team_se, team_e);
+      *team = team_se.expr;
+      gfc_add_block_to_block (block, &team_se.pre);
+      gfc_add_block_to_block (block, &team_se.post);
+    }
+  else
+    *team = null_pointer_node;
+}
+
 /* Get data from a remote coarray.  */
 
 static void
 gfc_conv_intrinsic_caf_get (gfc_se *se, gfc_expr *expr, tree lhs,
 			    bool may_realloc, symbol_attribute *caf_attr)
 {
-  gfc_expr *array_expr, *tmp_stat;
+  gfc_expr *array_expr;
   tree caf_decl, token, image_index, tmp, res_var, type, stat, dest_size,
     dest_data, opt_dest_desc, get_fn_index_tree, add_data_tree, add_data_size,
-    opt_src_desc, opt_src_charlen, opt_dest_charlen;
+    opt_src_desc, opt_src_charlen, opt_dest_charlen, team;
   symbol_attribute caf_attr_store;
   gfc_namespace *ns;
   gfc_expr *get_fn_hash = expr->value.function.actual->next->expr,
@@ -1842,19 +1878,7 @@ gfc_conv_intrinsic_caf_get (gfc_se *se, gfc_expr *expr, tree lhs,
 
   res_var = lhs;
 
-  tmp_stat = gfc_find_stat_co (expr);
-
-  if (tmp_stat)
-    {
-      gfc_se stat_se;
-      gfc_init_se (&stat_se, NULL);
-      gfc_conv_expr_reference (&stat_se, tmp_stat);
-      stat = stat_se.expr;
-      gfc_add_block_to_block (&se->pre, &stat_se.pre);
-      gfc_add_block_to_block (&se->post, &stat_se.post);
-    }
-  else
-    stat = null_pointer_node;
+  conv_stat_and_team (&se->pre, expr, &stat, &team);
 
   get_fn_index_tree
     = conv_caf_func_index (&se->pre, ns, "__caf_get_from_remote_fn_index_%d",
@@ -1958,7 +1982,7 @@ gfc_conv_intrinsic_caf_get (gfc_se *se, gfc_expr *expr, tree lhs,
     input_location, gfor_fndecl_caf_get_from_remote, 15, token, opt_src_desc,
     opt_src_charlen, image_index, dest_size, dest_data, opt_dest_charlen,
     opt_dest_desc, constant_boolean_node (may_realloc, boolean_type_node),
-    get_fn_index_tree, add_data_tree, add_data_size, stat, null_pointer_node,
+    get_fn_index_tree, add_data_tree, add_data_size, stat, team,
     null_pointer_node);
 
   gfc_add_expr_to_block (&se->pre, tmp);
@@ -2014,8 +2038,7 @@ gfc_conv_intrinsic_caf_is_present_remote (gfc_se *se, gfc_expr *e)
 static tree
 conv_caf_send_to_remote (gfc_code *code)
 {
-  gfc_expr *lhs_expr, *rhs_expr, *lhs_hash, *receiver_fn_expr, *tmp_stat,
-    *tmp_team;
+  gfc_expr *lhs_expr, *rhs_expr, *lhs_hash, *receiver_fn_expr;
   gfc_symbol *add_data_sym;
   gfc_se lhs_se, rhs_se;
   stmtblock_t block;
@@ -2041,9 +2064,6 @@ conv_caf_send_to_remote (gfc_code *code)
 
   gfc_init_block (&block);
 
-  lhs_stat = null_pointer_node;
-  lhs_team = null_pointer_node;
-
   /* LHS.  */
   gfc_init_se (&lhs_se, NULL);
   caf_decl = gfc_get_tree_for_caf_expr (lhs_expr);
@@ -2089,6 +2109,7 @@ conv_caf_send_to_remote (gfc_code *code)
   gfc_init_se (&rhs_se, NULL);
   if (rhs_expr->rank == 0)
     {
+      rhs_se.want_pointer = rhs_expr->ts.type == BT_CHARACTER;
       gfc_conv_expr (&rhs_se, rhs_expr);
       gfc_add_block_to_block (&block, &rhs_se.pre);
       opt_rhs_desc = null_pointer_node;
@@ -2111,7 +2132,7 @@ conv_caf_send_to_remote (gfc_code *code)
 				   gfc_trans_force_lval (&block, rhs_se.expr));
 	  opt_rhs_charlen
 	    = build_zero_cst (build_pointer_type (size_type_node));
-	  rhs_size = rhs_se.expr->typed.type->type_common.size_unit;
+	  rhs_size = TREE_TYPE (rhs_se.expr)->type_common.size_unit;
 	}
     }
   else
@@ -2149,29 +2170,7 @@ conv_caf_send_to_remote (gfc_code *code)
     }
   gfc_add_block_to_block (&block, &rhs_se.pre);
 
-  tmp_stat = gfc_find_stat_co (lhs_expr);
-
-  if (tmp_stat)
-    {
-      gfc_se stat_se;
-      gfc_init_se (&stat_se, NULL);
-      gfc_conv_expr_reference (&stat_se, tmp_stat);
-      lhs_stat = stat_se.expr;
-      gfc_add_block_to_block (&block, &stat_se.pre);
-      gfc_add_block_to_block (&block, &stat_se.post);
-    }
-
-  tmp_team = gfc_find_team_co (lhs_expr);
-
-  if (tmp_team)
-    {
-      gfc_se team_se;
-      gfc_init_se (&team_se, NULL);
-      gfc_conv_expr_reference (&team_se, tmp_team);
-      lhs_team = team_se.expr;
-      gfc_add_block_to_block (&block, &team_se.pre);
-      gfc_add_block_to_block (&block, &team_se.post);
-    }
+  conv_stat_and_team (&block, lhs_expr, &lhs_stat, &lhs_team);
 
   receiver_fn_index_tree
     = conv_caf_func_index (&block, ns, "__caf_send_to_remote_fn_index_%d",
@@ -2203,447 +2202,225 @@ conv_caf_send_to_remote (gfc_code *code)
   return gfc_finish_block (&block);
 }
 
-static bool
-has_ref_after_cafref (gfc_expr *expr)
-{
-  for (gfc_ref *ref = expr->ref; ref; ref = ref->next)
-    if (ref->type == REF_ARRAY && ref->u.ar.codimen)
-      return ref->next;
-  return false;
-}
+// static bool
+// has_ref_after_cafref (gfc_expr *expr)
+// {
+//   for (gfc_ref *ref = expr->ref; ref; ref = ref->next)
+//     if (ref->type == REF_ARRAY && ref->u.ar.codimen)
+//       return ref->next;
+//   return false;
+// }
 
 /* Send-get data to a remote coarray.  */
 
 static tree
 conv_caf_sendget (gfc_code *code)
 {
-  gfc_expr *lhs_expr, *rhs_expr, *tmp_stat, *tmp_team;
-  gfc_se lhs_se, rhs_se;
+  /* lhs stuff  */
+  gfc_expr *lhs_expr, *lhs_hash, *receiver_fn_expr;
+  gfc_symbol *lhs_add_data_sym;
+  gfc_se lhs_se;
+  tree lhs_caf_decl, lhs_token, opt_lhs_charlen,
+    opt_lhs_desc = NULL_TREE, receiver_fn_index_tree, lhs_image_index,
+    lhs_add_data_tree, lhs_add_data_size, lhs_stat, lhs_team;
+  int transfer_rank;
+
+  /* rhs stuff  */
+  gfc_expr *rhs_expr, *rhs_hash, *sender_fn_expr;
+  gfc_symbol *rhs_add_data_sym;
+  gfc_se rhs_se;
+  tree rhs_caf_decl, rhs_token, opt_rhs_charlen,
+    opt_rhs_desc = NULL_TREE, sender_fn_index_tree, rhs_image_index,
+    rhs_add_data_tree, rhs_add_data_size, rhs_stat, rhs_team;
+
+  /* shared  */
   stmtblock_t block;
-  tree caf_decl, token, offset, image_index, tmp, lhs_kind, rhs_kind;
-  tree may_require_tmp, src_stat, dst_stat, dst_team;
-  tree lhs_type = NULL_TREE;
-  tree vec = null_pointer_node, rhs_vec = null_pointer_node;
-  symbol_attribute lhs_caf_attr, rhs_caf_attr;
-  bool lhs_is_coindexed, rhs_is_coindexed;
+  gfc_namespace *ns;
+  tree tmp, rhs_size;
 
   gcc_assert (flag_coarray == GFC_FCOARRAY_LIB);
+  gcc_assert (code->resolved_isym->id == GFC_ISYM_CAF_SENDGET);
+
+  lhs_expr = code->ext.actual->expr;
+  rhs_expr = code->ext.actual->next->expr;
+  lhs_hash = code->ext.actual->next->next->expr;
+  receiver_fn_expr = code->ext.actual->next->next->next->expr;
+  rhs_hash = code->ext.actual->next->next->next->next->expr;
+  sender_fn_expr = code->ext.actual->next->next->next->next->next->expr;
+
+  lhs_add_data_sym = receiver_fn_expr->symtree->n.sym->formal->sym;
+  rhs_add_data_sym = sender_fn_expr->symtree->n.sym->formal->sym;
+
+  ns = lhs_expr->expr_type == EXPR_VARIABLE
+	   && !lhs_expr->symtree->n.sym->attr.associate_var
+	 ? lhs_expr->symtree->n.sym->ns
+	 : gfc_current_ns;
 
-  lhs_expr
-    = code->ext.actual->expr->expr_type == EXPR_FUNCTION
-	  && code->ext.actual->expr->value.function.isym->id == GFC_ISYM_CAF_GET
-	? code->ext.actual->expr->value.function.actual->expr
-	: code->ext.actual->expr;
-  rhs_expr = code->ext.actual->next->expr->expr_type == EXPR_FUNCTION
-		 && code->ext.actual->next->expr->value.function.isym->id
-		      == GFC_ISYM_CAF_GET
-	       ? code->ext.actual->next->expr->value.function.actual->expr
-	       : code->ext.actual->next->expr;
-  lhs_is_coindexed = gfc_is_coindexed (lhs_expr);
-  rhs_is_coindexed = gfc_is_coindexed (rhs_expr);
-  may_require_tmp = gfc_check_dependency (lhs_expr, rhs_expr, true) == 0
-		    ? boolean_false_node : boolean_true_node;
   gfc_init_block (&block);
 
-  lhs_caf_attr = gfc_caf_attr (lhs_expr);
-  rhs_caf_attr = gfc_caf_attr (rhs_expr);
-  src_stat = dst_stat = null_pointer_node;
-  dst_team = null_pointer_node;
+  lhs_stat = null_pointer_node;
+  lhs_team = null_pointer_node;
+  rhs_stat = null_pointer_node;
+  rhs_team = null_pointer_node;
 
   /* LHS.  */
   gfc_init_se (&lhs_se, NULL);
+  lhs_caf_decl = gfc_get_tree_for_caf_expr (lhs_expr);
+  if (TREE_CODE (TREE_TYPE (lhs_caf_decl)) == REFERENCE_TYPE)
+    lhs_caf_decl = build_fold_indirect_ref_loc (input_location, lhs_caf_decl);
   if (lhs_expr->rank == 0)
     {
-      if (lhs_expr->ts.type == BT_CHARACTER && lhs_expr->ts.deferred)
+      if (lhs_expr->ts.type == BT_CHARACTER)
 	{
-	  lhs_se.expr = gfc_get_tree_for_caf_expr (lhs_expr);
-	  if (!POINTER_TYPE_P (TREE_TYPE (lhs_se.expr)))
-	    lhs_se.expr = gfc_build_addr_expr (NULL_TREE, lhs_se.expr);
+	  gfc_conv_string_length (lhs_expr->ts.u.cl, lhs_expr, &block);
+	  lhs_se.string_length = lhs_expr->ts.u.cl->backend_decl;
+	  opt_lhs_charlen = gfc_build_addr_expr (
+	    NULL_TREE, gfc_trans_force_lval (&block, lhs_se.string_length));
 	}
       else
-	{
-	  symbol_attribute attr;
-	  gfc_clear_attr (&attr);
-	  gfc_conv_expr (&lhs_se, lhs_expr);
-	  lhs_type = TREE_TYPE (lhs_se.expr);
-	  if (lhs_is_coindexed)
-	    lhs_se.expr = gfc_conv_scalar_to_descriptor (&lhs_se, lhs_se.expr,
-							 attr);
-	  lhs_se.expr = gfc_build_addr_expr (NULL_TREE, lhs_se.expr);
-	}
-    }
-  else if ((lhs_caf_attr.alloc_comp || lhs_caf_attr.pointer_comp)
-	   && lhs_caf_attr.codimension)
-    {
-      lhs_se.want_pointer = 1;
-      gfc_conv_expr_descriptor (&lhs_se, lhs_expr);
-      /* Using gfc_conv_expr_descriptor, we only get the descriptor, but that
-	 has the wrong type if component references are done.  */
-      lhs_type = gfc_typenode_for_spec (&lhs_expr->ts);
-      tmp = build_fold_indirect_ref_loc (input_location, lhs_se.expr);
-      gfc_add_modify (&lhs_se.pre, gfc_conv_descriptor_dtype (tmp),
-		      gfc_get_dtype_rank_type (
-			gfc_has_vector_subscript (lhs_expr)
-			? gfc_find_array_ref (lhs_expr)->dimen
-			: lhs_expr->rank,
-		      lhs_type));
+	opt_lhs_charlen = build_zero_cst (build_pointer_type (size_type_node));
+      opt_lhs_desc = null_pointer_node;
     }
   else
     {
-      bool has_vector = gfc_has_vector_subscript (lhs_expr);
-
-      if (lhs_is_coindexed || !has_vector)
-	{
-	  /* If has_vector, pass descriptor for whole array and the
-	     vector bounds separately.  */
-	  gfc_array_ref *ar, ar2;
-	  bool has_tmp_lhs_array = false;
-	  if (has_vector)
-	    {
-	      has_tmp_lhs_array = true;
-	      ar = gfc_find_array_ref (lhs_expr);
-	      ar2 = *ar;
-	      memset (ar, '\0', sizeof (*ar));
-	      ar->as = ar2.as;
-	      ar->type = AR_FULL;
-	    }
-	  lhs_se.want_pointer = 1;
-	  gfc_conv_expr_descriptor (&lhs_se, lhs_expr);
-	  /* Using gfc_conv_expr_descriptor, we only get the descriptor, but
-	     that has the wrong type if component references are done.  */
-	  lhs_type = gfc_typenode_for_spec (&lhs_expr->ts);
-	  tmp = build_fold_indirect_ref_loc (input_location, lhs_se.expr);
-	  gfc_add_modify (&lhs_se.pre, gfc_conv_descriptor_dtype (tmp),
-			  gfc_get_dtype_rank_type (has_vector ? ar2.dimen
-							      : lhs_expr->rank,
-						   lhs_type));
-	  if (has_tmp_lhs_array)
-	    {
-	      vec = conv_caf_vector_subscript (&block, lhs_se.expr, &ar2);
-	      *ar = ar2;
-	    }
-	}
-      else if (rhs_is_coindexed)
-	{
-	  /* Special casing for arr1 ([...]) = arr2[...], i.e. caf_get to
-	     indexed array expression.  This is rewritten to:
-
-	     tmp_array = arr2[...]
-	     arr1 ([...]) = tmp_array
-
-	     because using the standard gfc_conv_expr (lhs_expr) did the
-	     assignment with lhs and rhs exchanged.  */
-
-	  gfc_ss *lss_for_tmparray, *lss_real;
-	  gfc_loopinfo loop;
-	  gfc_se se;
-	  stmtblock_t body;
-	  tree tmparr_desc, src;
-	  tree index = gfc_index_zero_node;
-	  tree stride = gfc_index_zero_node;
-	  int n;
-
-	  /* Walk both sides of the assignment, once to get the shape of the
-	     temporary array to create right.  */
-	  lss_for_tmparray = gfc_walk_expr (lhs_expr);
-	  /* And a second time to be able to create an assignment of the
-	     temporary to the lhs_expr.  gfc_trans_create_temp_array replaces
-	     the tree in the descriptor with the one for the temporary
-	     array.  */
-	  lss_real = gfc_walk_expr (lhs_expr);
-	  gfc_init_loopinfo (&loop);
-	  gfc_add_ss_to_loop (&loop, lss_for_tmparray);
-	  gfc_add_ss_to_loop (&loop, lss_real);
-	  gfc_conv_ss_startstride (&loop);
-	  gfc_conv_loop_setup (&loop, &lhs_expr->where);
-	  lhs_type = gfc_typenode_for_spec (&lhs_expr->ts);
-	  gfc_trans_create_temp_array (&lhs_se.pre, &lhs_se.post,
-				       lss_for_tmparray, lhs_type, NULL_TREE,
-				       false, true, false,
-				       &lhs_expr->where);
-	  tmparr_desc = lss_for_tmparray->info->data.array.descriptor;
-	  gfc_start_scalarized_body (&loop, &body);
-	  gfc_init_se (&se, NULL);
-	  gfc_copy_loopinfo_to_se (&se, &loop);
-	  se.ss = lss_real;
-	  gfc_conv_expr (&se, lhs_expr);
-	  gfc_add_block_to_block (&body, &se.pre);
-
-	  /* Walk over all indexes of the loop.  */
-	  for (n = loop.dimen - 1; n > 0; --n)
-	    {
-	      tmp = loop.loopvar[n];
-	      tmp = fold_build2_loc (input_location, MINUS_EXPR,
-				     gfc_array_index_type, tmp, loop.from[n]);
-	      tmp = fold_build2_loc (input_location, PLUS_EXPR,
-				     gfc_array_index_type, tmp, index);
-
-	      stride = fold_build2_loc (input_location, MINUS_EXPR,
-					gfc_array_index_type,
-					loop.to[n - 1], loop.from[n - 1]);
-	      stride = fold_build2_loc (input_location, PLUS_EXPR,
-					gfc_array_index_type,
-					stride, gfc_index_one_node);
-
-	      index = fold_build2_loc (input_location, MULT_EXPR,
-				       gfc_array_index_type, tmp, stride);
-	    }
-
-	  index = fold_build2_loc (input_location, MINUS_EXPR,
-				   gfc_array_index_type,
-				   index, loop.from[0]);
-
-	  index = fold_build2_loc (input_location, PLUS_EXPR,
-				   gfc_array_index_type,
-				   loop.loopvar[0], index);
-
-	  src = build_fold_indirect_ref (gfc_conv_array_data (tmparr_desc));
-	  src = gfc_build_array_ref (src, index, NULL);
-	  /* Now create the assignment of lhs_expr = tmp_array.  */
-	  gfc_add_modify (&body, se.expr, src);
-	  gfc_add_block_to_block (&body, &se.post);
-	  lhs_se.expr = gfc_build_addr_expr (NULL_TREE, tmparr_desc);
-	  gfc_trans_scalarizing_loops (&loop, &body);
-	  gfc_add_block_to_block (&loop.pre, &loop.post);
-	  gfc_add_expr_to_block (&lhs_se.post, gfc_finish_block (&loop.pre));
-	  gfc_free_ss (lss_for_tmparray);
-	  gfc_free_ss (lss_real);
-	}
-    }
-
-  lhs_kind = build_int_cst (integer_type_node, lhs_expr->ts.kind);
-
-  /* Special case: RHS is a coarray but LHS is not; this code path avoids a
-     temporary and a loop.  */
-  if (!lhs_is_coindexed && rhs_is_coindexed
-      && (!lhs_caf_attr.codimension
-	  || !(lhs_expr->rank > 0
-	       && (lhs_caf_attr.allocatable || lhs_caf_attr.pointer))))
-    {
-      bool lhs_may_realloc = lhs_expr->rank > 0 && lhs_caf_attr.allocatable;
-      gfc_init_se (&rhs_se, NULL);
-      if (lhs_expr->rank == 0 && lhs_caf_attr.allocatable)
-	{
-	  gfc_se scal_se;
-	  gfc_init_se (&scal_se, NULL);
-	  scal_se.want_pointer = 1;
-	  gfc_conv_expr (&scal_se, lhs_expr);
-	  /* Ensure scalar on lhs is allocated.  */
-	  gfc_add_block_to_block (&block, &scal_se.pre);
-
-	  gfc_allocate_using_malloc (&scal_se.pre, scal_se.expr,
-				    TYPE_SIZE_UNIT (
-				       gfc_typenode_for_spec (&lhs_expr->ts)),
-				    NULL_TREE);
-	  tmp = fold_build2 (EQ_EXPR, logical_type_node, scal_se.expr,
-			     null_pointer_node);
-	  tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node,
-				 tmp, gfc_finish_block (&scal_se.pre),
-				 build_empty_stmt (input_location));
-	  gfc_add_expr_to_block (&block, tmp);
-	}
-      else
-	lhs_may_realloc = lhs_may_realloc
-	    && gfc_full_array_ref_p (lhs_expr->ref, NULL);
+      gfc_conv_expr_descriptor (&lhs_se, lhs_expr);
       gfc_add_block_to_block (&block, &lhs_se.pre);
-      gfc_conv_intrinsic_caf_get (&rhs_se, code->ext.actual->next->expr,
-				  lhs_se.expr, lhs_may_realloc, &rhs_caf_attr);
-      gfc_add_block_to_block (&block, &rhs_se.pre);
-      gfc_add_block_to_block (&block, &rhs_se.post);
-      gfc_add_block_to_block (&block, &lhs_se.post);
-      return gfc_finish_block (&block);
+      opt_lhs_desc = lhs_se.expr;
+      if (lhs_expr->ts.type == BT_CHARACTER)
+	opt_lhs_charlen = gfc_build_addr_expr (
+	  NULL_TREE, gfc_trans_force_lval (&block, lhs_se.string_length));
+      else
+	opt_lhs_charlen = build_zero_cst (build_pointer_type (size_type_node));
+      if (!TYPE_LANG_SPECIFIC (TREE_TYPE (lhs_caf_decl))->rank
+	  || GFC_ARRAY_TYPE_P (TREE_TYPE (lhs_caf_decl)))
+	opt_lhs_desc = null_pointer_node;
+      else
+	opt_lhs_desc
+	  = gfc_build_addr_expr (NULL_TREE,
+				 gfc_trans_force_lval (&block, opt_lhs_desc));
     }
 
-  gfc_add_block_to_block (&block, &lhs_se.pre);
-
   /* Obtain token, offset and image index for the LHS.  */
-  caf_decl = gfc_get_tree_for_caf_expr (lhs_expr);
-  if (TREE_CODE (TREE_TYPE (caf_decl)) == REFERENCE_TYPE)
-    caf_decl = build_fold_indirect_ref_loc (input_location, caf_decl);
-  image_index = gfc_caf_get_image_index (&block, lhs_expr, caf_decl);
-  tmp = lhs_se.expr;
-  if (lhs_caf_attr.alloc_comp)
-    gfc_get_caf_token_offset (&lhs_se, &token, NULL, caf_decl, NULL_TREE,
-			      NULL);
-  else
-    gfc_get_caf_token_offset (&lhs_se, &token, &offset, caf_decl, tmp,
-			      lhs_expr);
-  lhs_se.expr = tmp;
+  lhs_image_index = gfc_caf_get_image_index (&block, lhs_expr, lhs_caf_decl);
+  gfc_get_caf_token_offset (&lhs_se, &lhs_token, NULL, lhs_caf_decl, NULL,
+			    lhs_expr);
 
   /* RHS.  */
+  rhs_caf_decl = gfc_get_tree_for_caf_expr (rhs_expr);
+  if (TREE_CODE (TREE_TYPE (rhs_caf_decl)) == REFERENCE_TYPE)
+    rhs_caf_decl = build_fold_indirect_ref_loc (input_location, rhs_caf_decl);
+  transfer_rank = rhs_expr->rank;
+  gfc_expression_rank (rhs_expr);
   gfc_init_se (&rhs_se, NULL);
-  if (rhs_expr->expr_type == EXPR_FUNCTION && rhs_expr->value.function.isym
-      && rhs_expr->value.function.isym->id == GFC_ISYM_CONVERSION)
-    rhs_expr = rhs_expr->value.function.actual->expr;
   if (rhs_expr->rank == 0)
     {
-      symbol_attribute attr;
-      gfc_clear_attr (&attr);
       gfc_conv_expr (&rhs_se, rhs_expr);
-      rhs_se.expr = gfc_conv_scalar_to_descriptor (&rhs_se, rhs_se.expr, attr);
-      rhs_se.expr = gfc_build_addr_expr (NULL_TREE, rhs_se.expr);
-    }
-  else if ((rhs_caf_attr.alloc_comp || rhs_caf_attr.pointer_comp)
-	   && rhs_caf_attr.codimension)
-    {
-      tree tmp2;
-      rhs_se.want_pointer = 1;
-      gfc_conv_expr_descriptor (&rhs_se, rhs_expr);
-      /* Using gfc_conv_expr_descriptor, we only get the descriptor, but that
-	 has the wrong type if component references are done.  */
-      tmp2 = gfc_typenode_for_spec (&rhs_expr->ts);
-      tmp = build_fold_indirect_ref_loc (input_location, rhs_se.expr);
-      gfc_add_modify (&rhs_se.pre, gfc_conv_descriptor_dtype (tmp),
-		      gfc_get_dtype_rank_type (
-			gfc_has_vector_subscript (rhs_expr)
-			? gfc_find_array_ref (rhs_expr)->dimen
-			: rhs_expr->rank,
-		      tmp2));
-    }
-  else
-    {
-      /* If has_vector, pass descriptor for whole array and the
-         vector bounds separately.  */
-      gfc_array_ref *ar, ar2;
-      bool has_vector = false;
-      tree tmp2;
-
-      if (rhs_is_coindexed && gfc_has_vector_subscript (rhs_expr))
+      gfc_add_block_to_block (&block, &rhs_se.pre);
+      opt_rhs_desc = null_pointer_node;
+      if (rhs_expr->ts.type == BT_CHARACTER)
 	{
-          has_vector = true;
-          ar = gfc_find_array_ref (rhs_expr);
-	  ar2 = *ar;
-	  memset (ar, '\0', sizeof (*ar));
-	  ar->as = ar2.as;
-	  ar->type = AR_FULL;
+	  opt_rhs_charlen = gfc_build_addr_expr (
+	    NULL_TREE, gfc_trans_force_lval (&block, rhs_se.string_length));
+	  rhs_size = build_int_cstu (size_type_node, rhs_expr->ts.kind);
 	}
-      rhs_se.want_pointer = 1;
-      gfc_conv_expr_descriptor (&rhs_se, rhs_expr);
-      /* Using gfc_conv_expr_descriptor, we only get the descriptor, but that
-         has the wrong type if component references are done.  */
-      tmp = build_fold_indirect_ref_loc (input_location, rhs_se.expr);
-      tmp2 = gfc_typenode_for_spec (&rhs_expr->ts);
-      gfc_add_modify (&rhs_se.pre, gfc_conv_descriptor_dtype (tmp),
-                      gfc_get_dtype_rank_type (has_vector ? ar2.dimen
-							  : rhs_expr->rank,
-		      tmp2));
-      if (has_vector)
-	{
-	  rhs_vec = conv_caf_vector_subscript (&block, rhs_se.expr, &ar2);
-	  *ar = ar2;
+      else
+	{
+	  opt_rhs_charlen
+	    = build_zero_cst (build_pointer_type (size_type_node));
+	  rhs_size = TREE_TYPE (rhs_se.expr)->type_common.size_unit;
 	}
     }
-
-  gfc_add_block_to_block (&block, &rhs_se.pre);
-
-  rhs_kind = build_int_cst (integer_type_node, rhs_expr->ts.kind);
-
-  tmp_stat = gfc_find_stat_co (lhs_expr);
-
-  if (tmp_stat)
-    {
-      gfc_se stat_se;
-      gfc_init_se (&stat_se, NULL);
-      gfc_conv_expr_reference (&stat_se, tmp_stat);
-      dst_stat = stat_se.expr;
-      gfc_add_block_to_block (&block, &stat_se.pre);
-      gfc_add_block_to_block (&block, &stat_se.post);
-    }
-
-  tmp_team = gfc_find_team_co (lhs_expr);
-
-  if (tmp_team)
-    {
-      gfc_se team_se;
-      gfc_init_se (&team_se, NULL);
-      gfc_conv_expr_reference (&team_se, tmp_team);
-      dst_team = team_se.expr;
-      gfc_add_block_to_block (&block, &team_se.pre);
-      gfc_add_block_to_block (&block, &team_se.post);
-    }
-
-  if (!rhs_is_coindexed)
+  else if (!TYPE_LANG_SPECIFIC (TREE_TYPE (rhs_caf_decl))->rank
+	   || GFC_ARRAY_TYPE_P (TREE_TYPE (rhs_caf_decl)))
     {
-      if (lhs_caf_attr.alloc_comp || lhs_caf_attr.pointer_comp
-	  || has_ref_after_cafref (lhs_expr))
+      rhs_se.data_not_needed = 1;
+      gfc_conv_expr_descriptor (&rhs_se, rhs_expr);
+      gfc_add_block_to_block (&block, &rhs_se.pre);
+      if (rhs_expr->ts.type == BT_CHARACTER)
 	{
-	  tree reference, dst_realloc;
-	  reference = conv_expr_ref_to_caf_ref (&block, lhs_expr);
-	  dst_realloc
-	    = lhs_caf_attr.allocatable ? boolean_true_node : boolean_false_node;
-	  tmp = build_call_expr_loc (input_location,
-				     gfor_fndecl_caf_send_by_ref,
-				     10, token, image_index, rhs_se.expr,
-				     reference, lhs_kind, rhs_kind,
-				     may_require_tmp, dst_realloc, src_stat,
-				     build_int_cst (integer_type_node,
-						    lhs_expr->ts.type));
+	  opt_rhs_charlen = gfc_build_addr_expr (
+	    NULL_TREE, gfc_trans_force_lval (&block, rhs_se.string_length));
+	  rhs_size = build_int_cstu (size_type_node, rhs_expr->ts.kind);
 	}
       else
-	tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_send, 11,
-				   token, offset, image_index, lhs_se.expr, vec,
-				   rhs_se.expr, lhs_kind, rhs_kind,
-				   may_require_tmp, src_stat, dst_team);
+	{
+	  opt_rhs_charlen
+	    = build_zero_cst (build_pointer_type (size_type_node));
+	  rhs_size = TREE_TYPE (rhs_se.expr)->type_common.size_unit;
+	}
+      opt_rhs_desc = null_pointer_node;
     }
   else
     {
-      tree rhs_token, rhs_offset, rhs_image_index;
-
-      /* It guarantees memory consistency within the same segment.  */
-      tmp = gfc_build_string_const (strlen ("memory") + 1, "memory");
-      tmp = build5_loc (input_location, ASM_EXPR, void_type_node,
-			  gfc_build_string_const (1, ""), NULL_TREE, NULL_TREE,
-			  tree_cons (NULL_TREE, tmp, NULL_TREE), NULL_TREE);
-      ASM_VOLATILE_P (tmp) = 1;
-      gfc_add_expr_to_block (&block, tmp);
-
-      caf_decl = gfc_get_tree_for_caf_expr (rhs_expr);
-      if (TREE_CODE (TREE_TYPE (caf_decl)) == REFERENCE_TYPE)
-	caf_decl = build_fold_indirect_ref_loc (input_location, caf_decl);
-      rhs_image_index = gfc_caf_get_image_index (&block, rhs_expr, caf_decl);
-      tmp = rhs_se.expr;
-      if (rhs_caf_attr.alloc_comp || rhs_caf_attr.pointer_comp
-	  || has_ref_after_cafref (lhs_expr))
+      gfc_ref *arr_ref = rhs_expr->ref;
+      while (arr_ref && arr_ref->type != REF_ARRAY)
+	arr_ref = arr_ref->next;
+      rhs_se.force_tmp
+	= (rhs_expr->shape == NULL
+	   && (!arr_ref || !gfc_full_array_ref_p (arr_ref, nullptr)))
+	  || !gfc_is_simply_contiguous (rhs_expr, false, false);
+      gfc_conv_expr_descriptor (&rhs_se, rhs_expr);
+      gfc_add_block_to_block (&block, &rhs_se.pre);
+      opt_rhs_desc = rhs_se.expr;
+      if (rhs_expr->ts.type == BT_CHARACTER)
 	{
-	  tmp_stat = gfc_find_stat_co (lhs_expr);
-
-	  if (tmp_stat)
-	    {
-	      gfc_se stat_se;
-	      gfc_init_se (&stat_se, NULL);
-	      gfc_conv_expr_reference (&stat_se, tmp_stat);
-	      src_stat = stat_se.expr;
-	      gfc_add_block_to_block (&block, &stat_se.pre);
-	      gfc_add_block_to_block (&block, &stat_se.post);
-	    }
-
-	  gfc_get_caf_token_offset (&rhs_se, &rhs_token, NULL, caf_decl,
-				    NULL_TREE, NULL);
-	  tree lhs_reference, rhs_reference;
-	  lhs_reference = conv_expr_ref_to_caf_ref (&block, lhs_expr);
-	  rhs_reference = conv_expr_ref_to_caf_ref (&block, rhs_expr);
-	  tmp = build_call_expr_loc (input_location,
-				     gfor_fndecl_caf_sendget_by_ref, 13,
-				     token, image_index, lhs_reference,
-				     rhs_token, rhs_image_index, rhs_reference,
-				     lhs_kind, rhs_kind, may_require_tmp,
-				     dst_stat, src_stat,
-				     build_int_cst (integer_type_node,
-						    lhs_expr->ts.type),
-				     build_int_cst (integer_type_node,
-						    rhs_expr->ts.type));
+	  opt_rhs_charlen = gfc_build_addr_expr (
+	    NULL_TREE, gfc_trans_force_lval (&block, rhs_se.string_length));
+	  rhs_size = build_int_cstu (size_type_node, rhs_expr->ts.kind);
 	}
       else
 	{
-	  gfc_get_caf_token_offset (&rhs_se, &rhs_token, &rhs_offset, caf_decl,
-				    tmp, rhs_expr);
-	  tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_sendget,
-				     14, token, offset, image_index,
-				     lhs_se.expr, vec, rhs_token, rhs_offset,
-				     rhs_image_index, tmp, rhs_vec, lhs_kind,
-				     rhs_kind, may_require_tmp, src_stat);
+	  opt_rhs_charlen
+	    = build_zero_cst (build_pointer_type (size_type_node));
+	  rhs_size = fold_build2 (
+	    MULT_EXPR, size_type_node,
+	    fold_convert (size_type_node,
+			  rhs_expr->shape
+			    ? conv_shape_to_cst (rhs_expr)
+			    : gfc_conv_descriptor_size (rhs_se.expr,
+							rhs_expr->rank)),
+	    fold_convert (size_type_node,
+			  gfc_conv_descriptor_span_get (rhs_se.expr)));
 	}
+
+      opt_rhs_desc = gfc_build_addr_expr (NULL_TREE, opt_rhs_desc);
     }
+  gfc_add_block_to_block (&block, &rhs_se.pre);
+
+  /* Obtain token, offset and image index for the RHS.  */
+  rhs_image_index = gfc_caf_get_image_index (&block, rhs_expr, rhs_caf_decl);
+  gfc_get_caf_token_offset (&rhs_se, &rhs_token, NULL, rhs_caf_decl, NULL,
+			    rhs_expr);
+
+  /* stat and team.  */
+  conv_stat_and_team (&block, lhs_expr, &lhs_stat, &lhs_team);
+  conv_stat_and_team (&block, rhs_expr, &rhs_stat, &rhs_team);
+
+  sender_fn_index_tree
+    = conv_caf_func_index (&block, ns, "__caf_transfer_from_fn_index_%d",
+			   rhs_hash);
+  rhs_add_data_tree
+    = conv_caf_add_call_data (&block, ns,
+			      "__caf_transfer_from_remote_add_data_%d",
+			      rhs_add_data_sym, &rhs_add_data_size);
+  receiver_fn_index_tree
+    = conv_caf_func_index (&block, ns, "__caf_transfer_to_remote_fn_index_%d",
+			   lhs_hash);
+  lhs_add_data_tree
+    = conv_caf_add_call_data (&block, ns,
+			      "__caf_transfer_to_remote_add_data_%d",
+			      lhs_add_data_sym, &lhs_add_data_size);
+  ++caf_call_cnt;
+
+  tmp = build_call_expr_loc (
+    input_location, gfor_fndecl_caf_transfer_between_remotes, 20, lhs_token,
+    opt_lhs_desc, opt_lhs_charlen, lhs_image_index, receiver_fn_index_tree,
+    lhs_add_data_tree, lhs_add_data_size, rhs_token, opt_rhs_desc,
+    opt_rhs_charlen, rhs_image_index, sender_fn_index_tree, rhs_add_data_tree,
+    rhs_add_data_size, rhs_size,
+    transfer_rank == 0 ? boolean_true_node : boolean_false_node, lhs_stat,
+    lhs_team, null_pointer_node, rhs_stat, rhs_team, null_pointer_node);
+
   gfc_add_expr_to_block (&block, tmp);
   gfc_add_block_to_block (&block, &lhs_se.post);
   gfc_add_block_to_block (&block, &rhs_se.post);
@@ -2659,6 +2436,451 @@ conv_caf_sendget (gfc_code *code)
   return gfc_finish_block (&block);
 }
 
+// static tree
+// conv_caf_sendget (gfc_code *code)
+// {
+//   gfc_expr *lhs_expr, *rhs_expr, *tmp_stat, *tmp_team;
+//   gfc_se lhs_se, rhs_se;
+//   stmtblock_t block;
+//   tree caf_decl, token, offset, image_index, tmp, lhs_kind, rhs_kind;
+//   tree may_require_tmp, src_stat, dst_stat, dst_team;
+//   tree lhs_type = NULL_TREE;
+//   tree vec = null_pointer_node, rhs_vec = null_pointer_node;
+//   symbol_attribute lhs_caf_attr, rhs_caf_attr;
+//   bool lhs_is_coindexed, rhs_is_coindexed;
+
+//   gcc_assert (flag_coarray == GFC_FCOARRAY_LIB);
+
+//   lhs_expr
+//     = code->ext.actual->expr->expr_type == EXPR_FUNCTION
+// 	  && code->ext.actual->expr->value.function.isym->id == GFC_ISYM_CAF_GET
+// 	? code->ext.actual->expr->value.function.actual->expr
+// 	: code->ext.actual->expr;
+//   rhs_expr = code->ext.actual->next->expr->expr_type == EXPR_FUNCTION
+// 		 && code->ext.actual->next->expr->value.function.isym->id
+// 		      == GFC_ISYM_CAF_GET
+// 	       ? code->ext.actual->next->expr->value.function.actual->expr
+// 	       : code->ext.actual->next->expr;
+//   lhs_is_coindexed = gfc_is_coindexed (lhs_expr);
+//   rhs_is_coindexed = gfc_is_coindexed (rhs_expr);
+//   may_require_tmp = gfc_check_dependency (lhs_expr, rhs_expr, true) == 0
+// 		    ? boolean_false_node : boolean_true_node;
+//   gfc_init_block (&block);
+
+//   lhs_caf_attr = gfc_caf_attr (lhs_expr);
+//   rhs_caf_attr = gfc_caf_attr (rhs_expr);
+//   src_stat = dst_stat = null_pointer_node;
+//   dst_team = null_pointer_node;
+
+//   /* LHS.  */
+//   gfc_init_se (&lhs_se, NULL);
+//   if (lhs_expr->rank == 0)
+//     {
+//       if (lhs_expr->ts.type == BT_CHARACTER && lhs_expr->ts.deferred)
+// 	{
+// 	  lhs_se.expr = gfc_get_tree_for_caf_expr (lhs_expr);
+// 	  if (!POINTER_TYPE_P (TREE_TYPE (lhs_se.expr)))
+// 	    lhs_se.expr = gfc_build_addr_expr (NULL_TREE, lhs_se.expr);
+// 	}
+//       else
+// 	{
+// 	  symbol_attribute attr;
+// 	  gfc_clear_attr (&attr);
+// 	  gfc_conv_expr (&lhs_se, lhs_expr);
+// 	  lhs_type = TREE_TYPE (lhs_se.expr);
+// 	  if (lhs_is_coindexed)
+// 	    lhs_se.expr = gfc_conv_scalar_to_descriptor (&lhs_se, lhs_se.expr,
+// 							 attr);
+// 	  lhs_se.expr = gfc_build_addr_expr (NULL_TREE, lhs_se.expr);
+// 	}
+//     }
+//   else if ((lhs_caf_attr.alloc_comp || lhs_caf_attr.pointer_comp)
+// 	   && lhs_caf_attr.codimension)
+//     {
+//       lhs_se.want_pointer = 1;
+//       gfc_conv_expr_descriptor (&lhs_se, lhs_expr);
+//       /* Using gfc_conv_expr_descriptor, we only get the descriptor, but that
+// 	 has the wrong type if component references are done.  */
+//       lhs_type = gfc_typenode_for_spec (&lhs_expr->ts);
+//       tmp = build_fold_indirect_ref_loc (input_location, lhs_se.expr);
+//       gfc_add_modify (&lhs_se.pre, gfc_conv_descriptor_dtype (tmp),
+// 		      gfc_get_dtype_rank_type (
+// 			gfc_has_vector_subscript (lhs_expr)
+// 			? gfc_find_array_ref (lhs_expr)->dimen
+// 			: lhs_expr->rank,
+// 		      lhs_type));
+//     }
+//   else
+//     {
+//       bool has_vector = gfc_has_vector_subscript (lhs_expr);
+
+//       if (lhs_is_coindexed || !has_vector)
+// 	{
+// 	  /* If has_vector, pass descriptor for whole array and the
+// 	     vector bounds separately.  */
+// 	  gfc_array_ref *ar, ar2;
+// 	  bool has_tmp_lhs_array = false;
+// 	  if (has_vector)
+// 	    {
+// 	      has_tmp_lhs_array = true;
+// 	      ar = gfc_find_array_ref (lhs_expr);
+// 	      ar2 = *ar;
+// 	      memset (ar, '\0', sizeof (*ar));
+// 	      ar->as = ar2.as;
+// 	      ar->type = AR_FULL;
+// 	    }
+// 	  lhs_se.want_pointer = 1;
+// 	  gfc_conv_expr_descriptor (&lhs_se, lhs_expr);
+// 	  /* Using gfc_conv_expr_descriptor, we only get the descriptor, but
+// 	     that has the wrong type if component references are done.  */
+// 	  lhs_type = gfc_typenode_for_spec (&lhs_expr->ts);
+// 	  tmp = build_fold_indirect_ref_loc (input_location, lhs_se.expr);
+// 	  gfc_add_modify (&lhs_se.pre, gfc_conv_descriptor_dtype (tmp),
+// 			  gfc_get_dtype_rank_type (has_vector ? ar2.dimen
+// 							      : lhs_expr->rank,
+// 						   lhs_type));
+// 	  if (has_tmp_lhs_array)
+// 	    {
+// 	      vec = conv_caf_vector_subscript (&block, lhs_se.expr, &ar2);
+// 	      *ar = ar2;
+// 	    }
+// 	}
+//       else if (rhs_is_coindexed)
+// 	{
+// 	  /* Special casing for arr1 ([...]) = arr2[...], i.e. caf_get to
+// 	     indexed array expression.  This is rewritten to:
+
+// 	     tmp_array = arr2[...]
+// 	     arr1 ([...]) = tmp_array
+
+// 	     because using the standard gfc_conv_expr (lhs_expr) did the
+// 	     assignment with lhs and rhs exchanged.  */
+
+// 	  gfc_ss *lss_for_tmparray, *lss_real;
+// 	  gfc_loopinfo loop;
+// 	  gfc_se se;
+// 	  stmtblock_t body;
+// 	  tree tmparr_desc, src;
+// 	  tree index = gfc_index_zero_node;
+// 	  tree stride = gfc_index_zero_node;
+// 	  int n;
+
+// 	  /* Walk both sides of the assignment, once to get the shape of the
+// 	     temporary array to create right.  */
+// 	  lss_for_tmparray = gfc_walk_expr (lhs_expr);
+// 	  /* And a second time to be able to create an assignment of the
+// 	     temporary to the lhs_expr.  gfc_trans_create_temp_array replaces
+// 	     the tree in the descriptor with the one for the temporary
+// 	     array.  */
+// 	  lss_real = gfc_walk_expr (lhs_expr);
+// 	  gfc_init_loopinfo (&loop);
+// 	  gfc_add_ss_to_loop (&loop, lss_for_tmparray);
+// 	  gfc_add_ss_to_loop (&loop, lss_real);
+// 	  gfc_conv_ss_startstride (&loop);
+// 	  gfc_conv_loop_setup (&loop, &lhs_expr->where);
+// 	  lhs_type = gfc_typenode_for_spec (&lhs_expr->ts);
+// 	  gfc_trans_create_temp_array (&lhs_se.pre, &lhs_se.post,
+// 				       lss_for_tmparray, lhs_type, NULL_TREE,
+// 				       false, true, false,
+// 				       &lhs_expr->where);
+// 	  tmparr_desc = lss_for_tmparray->info->data.array.descriptor;
+// 	  gfc_start_scalarized_body (&loop, &body);
+// 	  gfc_init_se (&se, NULL);
+// 	  gfc_copy_loopinfo_to_se (&se, &loop);
+// 	  se.ss = lss_real;
+// 	  gfc_conv_expr (&se, lhs_expr);
+// 	  gfc_add_block_to_block (&body, &se.pre);
+
+// 	  /* Walk over all indexes of the loop.  */
+// 	  for (n = loop.dimen - 1; n > 0; --n)
+// 	    {
+// 	      tmp = loop.loopvar[n];
+// 	      tmp = fold_build2_loc (input_location, MINUS_EXPR,
+// 				     gfc_array_index_type, tmp, loop.from[n]);
+// 	      tmp = fold_build2_loc (input_location, PLUS_EXPR,
+// 				     gfc_array_index_type, tmp, index);
+
+// 	      stride = fold_build2_loc (input_location, MINUS_EXPR,
+// 					gfc_array_index_type,
+// 					loop.to[n - 1], loop.from[n - 1]);
+// 	      stride = fold_build2_loc (input_location, PLUS_EXPR,
+// 					gfc_array_index_type,
+// 					stride, gfc_index_one_node);
+
+// 	      index = fold_build2_loc (input_location, MULT_EXPR,
+// 				       gfc_array_index_type, tmp, stride);
+// 	    }
+
+// 	  index = fold_build2_loc (input_location, MINUS_EXPR,
+// 				   gfc_array_index_type,
+// 				   index, loop.from[0]);
+
+// 	  index = fold_build2_loc (input_location, PLUS_EXPR,
+// 				   gfc_array_index_type,
+// 				   loop.loopvar[0], index);
+
+// 	  src = build_fold_indirect_ref (gfc_conv_array_data (tmparr_desc));
+// 	  src = gfc_build_array_ref (src, index, NULL);
+// 	  /* Now create the assignment of lhs_expr = tmp_array.  */
+// 	  gfc_add_modify (&body, se.expr, src);
+// 	  gfc_add_block_to_block (&body, &se.post);
+// 	  lhs_se.expr = gfc_build_addr_expr (NULL_TREE, tmparr_desc);
+// 	  gfc_trans_scalarizing_loops (&loop, &body);
+// 	  gfc_add_block_to_block (&loop.pre, &loop.post);
+// 	  gfc_add_expr_to_block (&lhs_se.post, gfc_finish_block (&loop.pre));
+// 	  gfc_free_ss (lss_for_tmparray);
+// 	  gfc_free_ss (lss_real);
+// 	}
+//     }
+
+//   lhs_kind = build_int_cst (integer_type_node, lhs_expr->ts.kind);
+
+//   /* Special case: RHS is a coarray but LHS is not; this code path avoids a
+//      temporary and a loop.  */
+//   if (!lhs_is_coindexed && rhs_is_coindexed
+//       && (!lhs_caf_attr.codimension
+// 	  || !(lhs_expr->rank > 0
+// 	       && (lhs_caf_attr.allocatable || lhs_caf_attr.pointer))))
+//     {
+//       bool lhs_may_realloc = lhs_expr->rank > 0 && lhs_caf_attr.allocatable;
+//       gfc_init_se (&rhs_se, NULL);
+//       if (lhs_expr->rank == 0 && lhs_caf_attr.allocatable)
+// 	{
+// 	  gfc_se scal_se;
+// 	  gfc_init_se (&scal_se, NULL);
+// 	  scal_se.want_pointer = 1;
+// 	  gfc_conv_expr (&scal_se, lhs_expr);
+// 	  /* Ensure scalar on lhs is allocated.  */
+// 	  gfc_add_block_to_block (&block, &scal_se.pre);
+
+// 	  gfc_allocate_using_malloc (&scal_se.pre, scal_se.expr,
+// 				    TYPE_SIZE_UNIT (
+// 				       gfc_typenode_for_spec (&lhs_expr->ts)),
+// 				    NULL_TREE);
+// 	  tmp = fold_build2 (EQ_EXPR, logical_type_node, scal_se.expr,
+// 			     null_pointer_node);
+// 	  tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node,
+// 				 tmp, gfc_finish_block (&scal_se.pre),
+// 				 build_empty_stmt (input_location));
+// 	  gfc_add_expr_to_block (&block, tmp);
+// 	}
+//       else
+// 	lhs_may_realloc = lhs_may_realloc
+// 	    && gfc_full_array_ref_p (lhs_expr->ref, NULL);
+//       gfc_add_block_to_block (&block, &lhs_se.pre);
+//       gfc_conv_intrinsic_caf_get (&rhs_se, code->ext.actual->next->expr,
+// 				  lhs_se.expr, lhs_may_realloc, &rhs_caf_attr);
+//       gfc_add_block_to_block (&block, &rhs_se.pre);
+//       gfc_add_block_to_block (&block, &rhs_se.post);
+//       gfc_add_block_to_block (&block, &lhs_se.post);
+//       return gfc_finish_block (&block);
+//     }
+
+//   gfc_add_block_to_block (&block, &lhs_se.pre);
+
+//   /* Obtain token, offset and image index for the LHS.  */
+//   caf_decl = gfc_get_tree_for_caf_expr (lhs_expr);
+//   if (TREE_CODE (TREE_TYPE (caf_decl)) == REFERENCE_TYPE)
+//     caf_decl = build_fold_indirect_ref_loc (input_location, caf_decl);
+//   image_index = gfc_caf_get_image_index (&block, lhs_expr, caf_decl);
+//   tmp = lhs_se.expr;
+//   if (lhs_caf_attr.alloc_comp)
+//     gfc_get_caf_token_offset (&lhs_se, &token, NULL, caf_decl, NULL_TREE,
+// 			      NULL);
+//   else
+//     gfc_get_caf_token_offset (&lhs_se, &token, &offset, caf_decl, tmp,
+// 			      lhs_expr);
+//   lhs_se.expr = tmp;
+
+//   /* RHS.  */
+//   gfc_init_se (&rhs_se, NULL);
+//   if (rhs_expr->expr_type == EXPR_FUNCTION && rhs_expr->value.function.isym
+//       && rhs_expr->value.function.isym->id == GFC_ISYM_CONVERSION)
+//     rhs_expr = rhs_expr->value.function.actual->expr;
+//   if (rhs_expr->rank == 0)
+//     {
+//       symbol_attribute attr;
+//       gfc_clear_attr (&attr);
+//       gfc_conv_expr (&rhs_se, rhs_expr);
+//       rhs_se.expr = gfc_conv_scalar_to_descriptor (&rhs_se, rhs_se.expr,
+//       attr); rhs_se.expr = gfc_build_addr_expr (NULL_TREE, rhs_se.expr);
+//     }
+//   else if ((rhs_caf_attr.alloc_comp || rhs_caf_attr.pointer_comp)
+// 	   && rhs_caf_attr.codimension)
+//     {
+//       tree tmp2;
+//       rhs_se.want_pointer = 1;
+//       gfc_conv_expr_descriptor (&rhs_se, rhs_expr);
+//       /* Using gfc_conv_expr_descriptor, we only get the descriptor, but that
+// 	 has the wrong type if component references are done.  */
+//       tmp2 = gfc_typenode_for_spec (&rhs_expr->ts);
+//       tmp = build_fold_indirect_ref_loc (input_location, rhs_se.expr);
+//       gfc_add_modify (&rhs_se.pre, gfc_conv_descriptor_dtype (tmp),
+// 		      gfc_get_dtype_rank_type (
+// 			gfc_has_vector_subscript (rhs_expr)
+// 			? gfc_find_array_ref (rhs_expr)->dimen
+// 			: rhs_expr->rank,
+// 		      tmp2));
+//     }
+//   else
+//     {
+//       /* If has_vector, pass descriptor for whole array and the
+//          vector bounds separately.  */
+//       gfc_array_ref *ar, ar2;
+//       bool has_vector = false;
+//       tree tmp2;
+
+//       if (rhs_is_coindexed && gfc_has_vector_subscript (rhs_expr))
+// 	{
+//           has_vector = true;
+//           ar = gfc_find_array_ref (rhs_expr);
+// 	  ar2 = *ar;
+// 	  memset (ar, '\0', sizeof (*ar));
+// 	  ar->as = ar2.as;
+// 	  ar->type = AR_FULL;
+// 	}
+//       rhs_se.want_pointer = 1;
+//       gfc_conv_expr_descriptor (&rhs_se, rhs_expr);
+//       /* Using gfc_conv_expr_descriptor, we only get the descriptor, but that
+//          has the wrong type if component references are done.  */
+//       tmp = build_fold_indirect_ref_loc (input_location, rhs_se.expr);
+//       tmp2 = gfc_typenode_for_spec (&rhs_expr->ts);
+//       gfc_add_modify (&rhs_se.pre, gfc_conv_descriptor_dtype (tmp),
+//                       gfc_get_dtype_rank_type (has_vector ? ar2.dimen
+// 							  : rhs_expr->rank,
+// 		      tmp2));
+//       if (has_vector)
+// 	{
+// 	  rhs_vec = conv_caf_vector_subscript (&block, rhs_se.expr, &ar2);
+// 	  *ar = ar2;
+// 	}
+//     }
+
+//   gfc_add_block_to_block (&block, &rhs_se.pre);
+
+//   rhs_kind = build_int_cst (integer_type_node, rhs_expr->ts.kind);
+
+//   tmp_stat = gfc_find_stat_co (lhs_expr);
+
+//   if (tmp_stat)
+//     {
+//       gfc_se stat_se;
+//       gfc_init_se (&stat_se, NULL);
+//       gfc_conv_expr_reference (&stat_se, tmp_stat);
+//       dst_stat = stat_se.expr;
+//       gfc_add_block_to_block (&block, &stat_se.pre);
+//       gfc_add_block_to_block (&block, &stat_se.post);
+//     }
+
+//   tmp_team = gfc_find_team_co (lhs_expr);
+
+//   if (tmp_team)
+//     {
+//       gfc_se team_se;
+//       gfc_init_se (&team_se, NULL);
+//       gfc_conv_expr_reference (&team_se, tmp_team);
+//       dst_team = team_se.expr;
+//       gfc_add_block_to_block (&block, &team_se.pre);
+//       gfc_add_block_to_block (&block, &team_se.post);
+//     }
+
+//   if (!rhs_is_coindexed)
+//     {
+//       if (lhs_caf_attr.alloc_comp || lhs_caf_attr.pointer_comp
+// 	  || has_ref_after_cafref (lhs_expr))
+// 	{
+// 	  tree reference, dst_realloc;
+// 	  reference = conv_expr_ref_to_caf_ref (&block, lhs_expr);
+// 	  dst_realloc
+// 	    = lhs_caf_attr.allocatable ? boolean_true_node : boolean_false_node;
+// 	  tmp = build_call_expr_loc (input_location,
+// 				     gfor_fndecl_caf_send_by_ref,
+// 				     10, token, image_index, rhs_se.expr,
+// 				     reference, lhs_kind, rhs_kind,
+// 				     may_require_tmp, dst_realloc, src_stat,
+// 				     build_int_cst (integer_type_node,
+// 						    lhs_expr->ts.type));
+// 	}
+//       else
+// 	tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_send, 11,
+// 				   token, offset, image_index, lhs_se.expr, vec,
+// 				   rhs_se.expr, lhs_kind, rhs_kind,
+// 				   may_require_tmp, src_stat, dst_team);
+//     }
+//   else
+//     {
+//       tree rhs_token, rhs_offset, rhs_image_index;
+
+//       /* It guarantees memory consistency within the same segment.  */
+//       tmp = gfc_build_string_const (strlen ("memory") + 1, "memory");
+//       tmp = build5_loc (input_location, ASM_EXPR, void_type_node,
+// 			  gfc_build_string_const (1, ""), NULL_TREE, NULL_TREE,
+// 			  tree_cons (NULL_TREE, tmp, NULL_TREE), NULL_TREE);
+//       ASM_VOLATILE_P (tmp) = 1;
+//       gfc_add_expr_to_block (&block, tmp);
+
+//       caf_decl = gfc_get_tree_for_caf_expr (rhs_expr);
+//       if (TREE_CODE (TREE_TYPE (caf_decl)) == REFERENCE_TYPE)
+// 	caf_decl = build_fold_indirect_ref_loc (input_location, caf_decl);
+//       rhs_image_index = gfc_caf_get_image_index (&block, rhs_expr, caf_decl);
+//       tmp = rhs_se.expr;
+//       if (rhs_caf_attr.alloc_comp || rhs_caf_attr.pointer_comp
+// 	  || has_ref_after_cafref (lhs_expr))
+// 	{
+// 	  tmp_stat = gfc_find_stat_co (lhs_expr);
+
+// 	  if (tmp_stat)
+// 	    {
+// 	      gfc_se stat_se;
+// 	      gfc_init_se (&stat_se, NULL);
+// 	      gfc_conv_expr_reference (&stat_se, tmp_stat);
+// 	      src_stat = stat_se.expr;
+// 	      gfc_add_block_to_block (&block, &stat_se.pre);
+// 	      gfc_add_block_to_block (&block, &stat_se.post);
+// 	    }
+
+// 	  gfc_get_caf_token_offset (&rhs_se, &rhs_token, NULL, caf_decl,
+// 				    NULL_TREE, NULL);
+// 	  tree lhs_reference, rhs_reference;
+// 	  lhs_reference = conv_expr_ref_to_caf_ref (&block, lhs_expr);
+// 	  rhs_reference = conv_expr_ref_to_caf_ref (&block, rhs_expr);
+// 	  tmp = build_call_expr_loc (input_location,
+// 				     gfor_fndecl_caf_sendget_by_ref, 13,
+// 				     token, image_index, lhs_reference,
+// 				     rhs_token, rhs_image_index, rhs_reference,
+// 				     lhs_kind, rhs_kind, may_require_tmp,
+// 				     dst_stat, src_stat,
+// 				     build_int_cst (integer_type_node,
+// 						    lhs_expr->ts.type),
+// 				     build_int_cst (integer_type_node,
+// 						    rhs_expr->ts.type));
+// 	}
+//       else
+// 	{
+// 	  gfc_get_caf_token_offset (&rhs_se, &rhs_token, &rhs_offset, caf_decl,
+// 				    tmp, rhs_expr);
+// 	  tmp = build_call_expr_loc (input_location, gfor_fndecl_caf_sendget,
+// 				     14, token, offset, image_index,
+// 				     lhs_se.expr, vec, rhs_token, rhs_offset,
+// 				     rhs_image_index, tmp, rhs_vec, lhs_kind,
+// 				     rhs_kind, may_require_tmp, src_stat);
+// 	}
+//     }
+//   gfc_add_expr_to_block (&block, tmp);
+//   gfc_add_block_to_block (&block, &lhs_se.post);
+//   gfc_add_block_to_block (&block, &rhs_se.post);
+
+//   /* It guarantees memory consistency within the same segment.  */
+//   tmp = gfc_build_string_const (strlen ("memory") + 1, "memory");
+//   tmp = build5_loc (input_location, ASM_EXPR, void_type_node,
+// 		    gfc_build_string_const (1, ""), NULL_TREE, NULL_TREE,
+// 		    tree_cons (NULL_TREE, tmp, NULL_TREE), NULL_TREE);
+//   ASM_VOLATILE_P (tmp) = 1;
+//   gfc_add_expr_to_block (&block, tmp);
+
+//   return gfc_finish_block (&block);
+// }
+
 static void
 trans_this_image (gfc_se * se, gfc_expr *expr)
 {
diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h
index 8b76a277c07c362701909cb748bf99a7b8070845..fcb091a3cc6cdc473a8fd7b61b5dec4c711e9474 100644
--- a/gcc/fortran/trans.h
+++ b/gcc/fortran/trans.h
@@ -897,6 +897,7 @@ extern GTY(()) tree gfor_fndecl_caf_register_accessors_finish;
 extern GTY(()) tree gfor_fndecl_caf_get_remote_function_index;
 extern GTY(()) tree gfor_fndecl_caf_get_from_remote;
 extern GTY(()) tree gfor_fndecl_caf_send_to_remote;
+extern GTY(()) tree gfor_fndecl_caf_transfer_between_remotes;
 
 extern GTY(()) tree gfor_fndecl_caf_sync_all;
 extern GTY(()) tree gfor_fndecl_caf_sync_memory;
diff --git a/gcc/testsuite/gfortran.dg/coarray_lib_comm_1.f90 b/gcc/testsuite/gfortran.dg/coarray_lib_comm_1.f90
index 56f2a6c5c7a2990b3bc7e3e36c8df5f3677b42f0..9da15053290d3542f3322ef9dae97c1a176030d5 100644
--- a/gcc/testsuite/gfortran.dg/coarray_lib_comm_1.f90
+++ b/gcc/testsuite/gfortran.dg/coarray_lib_comm_1.f90
@@ -39,5 +39,7 @@ 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.\[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" } }
+! { dg-final { scan-tree-dump-times "_gfortran_caf_transfer_between_remotes" 1 "original" } }
+! { dg-final { scan-tree-dump-not "_gfortran_caf_transfer_get" "original" } }
+! { dg-final { scan-tree-dump-not "_gfortran_caf_transfer_send" "original" } }
 
diff --git a/libgfortran/caf/libcaf.h b/libgfortran/caf/libcaf.h
index 0af1813bbd5649b8d87a55c81248e71def9f98a6..ef3dacfd8e761380ceecf3cbd2050328ecc5db62 100644
--- a/libgfortran/caf/libcaf.h
+++ b/libgfortran/caf/libcaf.h
@@ -261,6 +261,18 @@ void _gfortran_caf_send_to_remote (
   void *add_data, const size_t add_data_size, int *stat, caf_team_t *team,
   int *team_number);
 
+void _gfortran_caf_transfer_between_remotes (
+  caf_token_t dst_token, gfc_descriptor_t *opt_dst_desc,
+  size_t *opt_dst_charlen, const int dst_image_index,
+  const int dst_access_index, void *dst_add_data,
+  const size_t dst_add_data_size, caf_token_t src_token,
+  const gfc_descriptor_t *opt_src_desc, const size_t *opt_src_charlen,
+  const int src_image_index, const int src_access_index, void *src_add_data,
+  const size_t src_add_data_size, const size_t src_size,
+  const bool scalar_transfer, int *dst_stat, int *src_stat,
+  caf_team_t *dst_team, int *dst_team_number, caf_team_t *src_team,
+  int *src_team_number);
+
 void _gfortran_caf_atomic_define (caf_token_t, size_t, int, void *, int *,
 				  int, int);
 void _gfortran_caf_atomic_ref (caf_token_t, size_t, int, void *, int *,
diff --git a/libgfortran/caf/single.c b/libgfortran/caf/single.c
index 625e1a71148bb9265c9fdcf5261781ff9e0b5114..1f7a9022e39e32e5b4ce5b85d1b129c0ab7a2fe8 100644
--- a/libgfortran/caf/single.c
+++ b/libgfortran/caf/single.c
@@ -3023,6 +3023,75 @@ _gfortran_caf_send_to_remote (
 						  opt_src_charlen);
 }
 
+void
+_gfortran_caf_transfer_between_remotes (
+  caf_token_t dst_token, gfc_descriptor_t *opt_dst_desc,
+  size_t *opt_dst_charlen, const int dst_image_index,
+  const int dst_access_index, void *dst_add_data,
+  const size_t dst_add_data_size __attribute__ ((unused)),
+  caf_token_t src_token, const gfc_descriptor_t *opt_src_desc,
+  const size_t *opt_src_charlen, const int src_image_index,
+  const int src_access_index, void *src_add_data,
+  const size_t src_add_data_size __attribute__ ((unused)),
+  const size_t src_size, const bool scalar_transfer, int *dst_stat,
+  int *src_stat, caf_team_t *dst_team __attribute__ ((unused)),
+  int *dst_team_number __attribute__ ((unused)),
+  caf_team_t *src_team __attribute__ ((unused)),
+  int *src_team_number __attribute__ ((unused)))
+{
+  caf_single_token_t src_single_token = TOKEN (src_token),
+		     dst_single_token = TOKEN (dst_token);
+  void *src_ptr
+    = opt_src_desc ? (void *) opt_src_desc : src_single_token->memptr;
+  int32_t free_buffer;
+  void *dst_ptr
+    = opt_dst_desc ? (void *) opt_dst_desc : dst_single_token->memptr;
+  void *transfer_ptr, *buffer;
+  GFC_FULL_ARRAY_DESCRIPTOR (GFC_MAX_DIMENSIONS, void) *transfer_desc = NULL;
+  struct caf_single_token cb_token;
+  cb_token.memptr = src_add_data;
+  cb_token.desc = NULL;
+  cb_token.owning_memory = false;
+
+  if (src_stat)
+    *src_stat = 0;
+
+  if (!scalar_transfer)
+    {
+      const size_t desc_size = sizeof (*transfer_desc);
+      transfer_desc = alloca (desc_size);
+      memset (transfer_desc, 0, desc_size);
+      transfer_ptr = transfer_desc;
+    }
+  else if (opt_dst_charlen)
+    transfer_ptr = alloca (*opt_dst_charlen * src_size);
+  else
+    {
+      buffer = NULL;
+      transfer_ptr = &buffer;
+    }
+
+  accessor_hash_table[src_access_index].u.getter (
+    src_add_data, &src_image_index, transfer_ptr, &free_buffer, src_ptr,
+    &cb_token, 0, opt_dst_charlen, opt_src_charlen);
+
+  if (dst_stat)
+    *dst_stat = 0;
+
+  if (scalar_transfer)
+    transfer_ptr = *(void **) transfer_ptr;
+
+  cb_token.memptr = dst_add_data;
+  accessor_hash_table[dst_access_index].u.receiver (dst_add_data,
+						    &dst_image_index, dst_ptr,
+						    transfer_ptr, &cb_token, 0,
+						    opt_dst_charlen,
+						    opt_src_charlen);
+
+  if (free_buffer)
+    free (transfer_desc ? transfer_desc->base_addr : transfer_ptr);
+}
+
 void
 _gfortran_caf_atomic_define (caf_token_t token, size_t offset,
 			     int image_index __attribute__ ((unused)),