decl.c: Add decl_type_param_list...
[gcc.git] / gcc / fortran / trans-expr.c
index b8f47900bdf55f174d5509589fa7ccf41f15970d..b3104586ca6841122c1e6b637abaafe6ea9a9ebd 100644 (file)
@@ -1,5 +1,5 @@
 /* Expression translation
-   Copyright (C) 2002-2015 Free Software Foundation, Inc.
+   Copyright (C) 2002-2017 Free Software Foundation, Inc.
    Contributed by Paul Brook <paul@nowt.org>
    and Steven Bosscher <s.bosscher@student.tudelft.nl>
 
@@ -30,10 +30,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "trans.h"
 #include "stringpool.h"
 #include "diagnostic-core.h"   /* For fatal_error.  */
-#include "alias.h"
 #include "fold-const.h"
 #include "langhooks.h"
-#include "flags.h"
 #include "arith.h"
 #include "constructor.h"
 #include "trans-const.h"
@@ -74,6 +72,13 @@ gfc_conv_scalar_to_descriptor (gfc_se *se, tree scalar, symbol_attribute attr)
   desc = gfc_create_var (type, "desc");
   DECL_ARTIFICIAL (desc) = 1;
 
+  if (CONSTANT_CLASS_P (scalar))
+    {
+      tree tmp;
+      tmp = gfc_create_var (TREE_TYPE (scalar), "scalar");
+      gfc_add_modify (&se->pre, tmp, scalar);
+      scalar = tmp;
+    }
   if (!POINTER_TYPE_P (TREE_TYPE (scalar)))
     scalar = gfc_build_addr_expr (NULL_TREE, scalar);
   gfc_add_modify (&se->pre, gfc_conv_descriptor_dtype (desc),
@@ -90,6 +95,56 @@ gfc_conv_scalar_to_descriptor (gfc_se *se, tree scalar, symbol_attribute attr)
 }
 
 
+/* Get the coarray token from the ultimate array or component ref.
+   Returns a NULL_TREE, when the ref object is not allocatable or pointer.  */
+
+tree
+gfc_get_ultimate_alloc_ptr_comps_caf_token (gfc_se *outerse, gfc_expr *expr)
+{
+  gfc_symbol *sym = expr->symtree->n.sym;
+  bool is_coarray = sym->attr.codimension;
+  gfc_expr *caf_expr = gfc_copy_expr (expr);
+  gfc_ref *ref = caf_expr->ref, *last_caf_ref = NULL;
+
+  while (ref)
+    {
+      if (ref->type == REF_COMPONENT
+         && (ref->u.c.component->attr.allocatable
+             || ref->u.c.component->attr.pointer)
+         && (is_coarray || ref->u.c.component->attr.codimension))
+         last_caf_ref = ref;
+      ref = ref->next;
+    }
+
+  if (last_caf_ref == NULL)
+    return NULL_TREE;
+
+  tree comp = last_caf_ref->u.c.component->caf_token, caf;
+  gfc_se se;
+  bool comp_ref = !last_caf_ref->u.c.component->attr.dimension;
+  if (comp == NULL_TREE && comp_ref)
+    return NULL_TREE;
+  gfc_init_se (&se, outerse);
+  gfc_free_ref_list (last_caf_ref->next);
+  last_caf_ref->next = NULL;
+  caf_expr->rank = comp_ref ? 0 : last_caf_ref->u.c.component->as->rank;
+  se.want_pointer = comp_ref;
+  gfc_conv_expr (&se, caf_expr);
+  gfc_add_block_to_block (&outerse->pre, &se.pre);
+
+  if (TREE_CODE (se.expr) == COMPONENT_REF && comp_ref)
+    se.expr = TREE_OPERAND (se.expr, 0);
+  gfc_free_expr (caf_expr);
+
+  if (comp_ref)
+    caf = fold_build3_loc (input_location, COMPONENT_REF,
+                          TREE_TYPE (comp), se.expr, comp, NULL_TREE);
+  else
+    caf = gfc_conv_descriptor_token (se.expr);
+  return gfc_build_addr_expr (NULL_TREE, caf);
+}
+
+
 /* This is the seed for an eventual trans-class.c
 
    The following parameters should not be used directly since they might
@@ -103,6 +158,7 @@ gfc_conv_scalar_to_descriptor (gfc_se *se, tree scalar, symbol_attribute attr)
 #define VTABLE_DEF_INIT_FIELD 3
 #define VTABLE_COPY_FIELD 4
 #define VTABLE_FINAL_FIELD 5
+#define VTABLE_DEALLOCATE_FIELD 6
 
 
 tree
@@ -143,7 +199,7 @@ gfc_class_vptr_get (tree decl)
   tree vptr;
   /* For class arrays decl may be a temporary descriptor handle, the vptr is
      then available through the saved descriptor.  */
-  if (TREE_CODE (decl) == VAR_DECL && DECL_LANG_SPECIFIC (decl)
+  if (VAR_P (decl) && DECL_LANG_SPECIFIC (decl)
       && GFC_DECL_SAVED_DESCRIPTOR (decl))
     decl = GFC_DECL_SAVED_DESCRIPTOR (decl);
   if (POINTER_TYPE_P (TREE_TYPE (decl)))
@@ -162,7 +218,7 @@ gfc_class_len_get (tree decl)
   tree len;
   /* For class arrays decl may be a temporary descriptor handle, the len is
      then available through the saved descriptor.  */
-  if (TREE_CODE (decl) == VAR_DECL && DECL_LANG_SPECIFIC (decl)
+  if (VAR_P (decl) && DECL_LANG_SPECIFIC (decl)
       && GFC_DECL_SAVED_DESCRIPTOR (decl))
     decl = GFC_DECL_SAVED_DESCRIPTOR (decl);
   if (POINTER_TYPE_P (TREE_TYPE (decl)))
@@ -175,6 +231,29 @@ gfc_class_len_get (tree decl)
 }
 
 
+/* Try to get the _len component of a class.  When the class is not unlimited
+   poly, i.e. no _len field exists, then return a zero node.  */
+
+tree
+gfc_class_len_or_zero_get (tree decl)
+{
+  tree len;
+  /* For class arrays decl may be a temporary descriptor handle, the vptr is
+     then available through the saved descriptor.  */
+  if (VAR_P (decl) && DECL_LANG_SPECIFIC (decl)
+      && GFC_DECL_SAVED_DESCRIPTOR (decl))
+    decl = GFC_DECL_SAVED_DESCRIPTOR (decl);
+  if (POINTER_TYPE_P (TREE_TYPE (decl)))
+    decl = build_fold_indirect_ref_loc (input_location, decl);
+  len = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (decl)),
+                          CLASS_LEN_FIELD);
+  return len != NULL_TREE ? fold_build3_loc (input_location, COMPONENT_REF,
+                                            TREE_TYPE (len), decl, len,
+                                            NULL_TREE)
+                         : integer_zero_node;
+}
+
+
 /* Get the specified FIELD from the VPTR.  */
 
 static tree
@@ -222,6 +301,7 @@ VTAB_GET_FIELD_GEN (extends, VTABLE_EXTENDS_FIELD)
 VTAB_GET_FIELD_GEN (def_init, VTABLE_DEF_INIT_FIELD)
 VTAB_GET_FIELD_GEN (copy, VTABLE_COPY_FIELD)
 VTAB_GET_FIELD_GEN (final, VTABLE_FINAL_FIELD)
+VTAB_GET_FIELD_GEN (deallocate, VTABLE_DEALLOCATE_FIELD)
 
 
 /* The size field is returned as an array index type.  Therefore treat
@@ -252,6 +332,7 @@ gfc_vptr_size_get (tree vptr)
 
 #undef CLASS_DATA_FIELD
 #undef CLASS_VPTR_FIELD
+#undef CLASS_LEN_FIELD
 #undef VTABLE_HASH_FIELD
 #undef VTABLE_SIZE_FIELD
 #undef VTABLE_EXTENDS_FIELD
@@ -271,15 +352,14 @@ gfc_expr *
 gfc_find_and_cut_at_last_class_ref (gfc_expr *e)
 {
   gfc_expr *base_expr;
-  gfc_ref *ref, *class_ref, *tail, *array_ref;
+  gfc_ref *ref, *class_ref, *tail = NULL, *array_ref;
 
   /* Find the last class reference.  */
   class_ref = NULL;
   array_ref = NULL;
   for (ref = e->ref; ref; ref = ref->next)
     {
-      if (ref->type == REF_ARRAY
-         && ref->u.ar.type != AR_ELEMENT)
+      if (ref->type == REF_ARRAY && ref->u.ar.type != AR_ELEMENT)
        array_ref = ref;
 
       if (ref->type == REF_COMPONENT
@@ -288,11 +368,10 @@ gfc_find_and_cut_at_last_class_ref (gfc_expr *e)
          /* Component to the right of a part reference with nonzero rank
             must not have the ALLOCATABLE attribute.  If attempts are
             made to reference such a component reference, an error results
-            followed by anICE.  */
-         if (array_ref
-             && CLASS_DATA (ref->u.c.component)->attr.allocatable)
+            followed by an ICE.  */
+         if (array_ref && CLASS_DATA (ref->u.c.component)->attr.allocatable)
            return NULL;
-       class_ref = ref;
+         class_ref = ref;
        }
 
       if (ref->next == NULL)
@@ -306,7 +385,7 @@ gfc_find_and_cut_at_last_class_ref (gfc_expr *e)
       tail = class_ref->next;
       class_ref->next = NULL;
     }
-  else
+  else if (e->symtree && e->symtree->n.sym->ts.type == BT_CLASS)
     {
       tail = e->ref;
       e->ref = NULL;
@@ -320,7 +399,7 @@ gfc_find_and_cut_at_last_class_ref (gfc_expr *e)
       gfc_free_ref_list (class_ref->next);
       class_ref->next = tail;
     }
-  else
+  else if (e->symtree && e->symtree->n.sym->ts.type == BT_CLASS)
     {
       gfc_free_ref_list (e->ref);
       e->ref = tail;
@@ -408,9 +487,16 @@ gfc_get_vptr_from_expr (tree expr)
          else
            type = NULL_TREE;
        }
-      if (TREE_CODE (tmp) == VAR_DECL)
+      if (VAR_P (tmp) || TREE_CODE (tmp) == PARM_DECL)
        break;
     }
+
+  if (POINTER_TYPE_P (TREE_TYPE (tmp)))
+    tmp = build_fold_indirect_ref_loc (input_location, tmp);
+
+  if (GFC_CLASS_TYPE_P (TREE_TYPE (tmp)))
+    return gfc_class_vptr_get (tmp);
+
   return NULL_TREE;
 }
 
@@ -489,7 +575,14 @@ gfc_conv_derived_to_class (gfc_se *parmse, gfc_expr *e,
   if (optional)
     cond_optional = gfc_conv_expr_present (e->symtree->n.sym);
 
-  if (parmse->ss && parmse->ss->info->useflags)
+  if (parmse->expr && POINTER_TYPE_P (TREE_TYPE (parmse->expr)))
+    {
+      /* If there is a ready made pointer to a derived type, use it
+        rather than evaluating the expression again.  */
+      tmp = fold_convert (TREE_TYPE (ctree), parmse->expr);
+      gfc_add_modify (&parmse->pre, ctree, tmp);
+    }
+  else if (parmse->ss && parmse->ss->info && parmse->ss->info->useflags)
     {
       /* For an array reference in an elemental procedure call we need
         to retain the ss to provide the scalarized array reference.  */
@@ -500,7 +593,6 @@ gfc_conv_derived_to_class (gfc_se *parmse, gfc_expr *e,
                          cond_optional, tmp,
                          fold_convert (TREE_TYPE (tmp), null_pointer_node));
       gfc_add_modify (&parmse->pre, ctree, tmp);
-
     }
   else
     {
@@ -770,7 +862,7 @@ gfc_conv_intrinsic_to_class (gfc_se *parmse, gfc_expr *e,
     {
       ctree = gfc_class_len_get (var);
       /* When the actual arg is a char array, then set the _len component of the
-       unlimited polymorphic entity, too.  */
+        unlimited polymorphic entity to the length of the string.  */
       if (e->ts.type == BT_CHARACTER)
        {
          /* Start with parmse->string_length because this seems to be set to a
@@ -942,8 +1034,13 @@ gfc_conv_class_to_class (gfc_se *parmse, gfc_expr *e, gfc_typespec class_ts,
        && e->symtree && e->symtree->n.sym->ts.type == BT_CLASS)
     {
       tmp = e->symtree->n.sym->backend_decl;
+
+      if (TREE_CODE (tmp) == FUNCTION_DECL)
+       tmp = gfc_get_fake_result_decl (e->symtree->n.sym, 0);
+
       if (DECL_LANG_SPECIFIC (tmp) && GFC_DECL_SAVED_DESCRIPTOR (tmp))
        tmp = GFC_DECL_SAVED_DESCRIPTOR (tmp);
+
       slen = integer_zero_node;
     }
   else
@@ -994,6 +1091,12 @@ gfc_conv_class_to_class (gfc_se *parmse, gfc_expr *e, gfc_typespec class_ts,
        tmp = integer_zero_node;
       gfc_add_modify (&parmse->pre, ctree,
                      fold_convert (TREE_TYPE (ctree), tmp));
+
+      /* Return the len component, except in the case of scalarized array
+       references, where the dynamic type cannot change.  */
+      if (!elemental && full_array && copyback)
+         gfc_add_modify (&parmse->post, tmp,
+                         fold_convert (TREE_TYPE (tmp), ctree));
     }
 
   if (optional)
@@ -1105,7 +1208,14 @@ gfc_copy_class_to_class (tree from, tree to, tree nelems, bool unlimited)
        }
       else
        {
-         from_data = gfc_class_data_get (from);
+         /* Check that from is a class.  When the class is part of a coarray,
+            then from is a common pointer and is to be used as is.  */
+         tmp = POINTER_TYPE_P (TREE_TYPE (from))
+             ? build_fold_indirect_ref (from) : from;
+         from_data =
+             (GFC_CLASS_TYPE_P (TREE_TYPE (tmp))
+              || (DECL_P (tmp) && GFC_DECL_CLASS (tmp)))
+             ? gfc_class_data_get (from) : from;
          is_from_desc = GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (from_data));
        }
      }
@@ -1115,7 +1225,7 @@ gfc_copy_class_to_class (tree from, tree to, tree nelems, bool unlimited)
   if (unlimited)
     {
       if (from != NULL_TREE && unlimited)
-       from_len = gfc_class_len_get (from);
+       from_len = gfc_class_len_or_zero_get (from);
       else
        from_len = integer_zero_node;
     }
@@ -1137,6 +1247,7 @@ gfc_copy_class_to_class (tree from, tree to, tree nelems, bool unlimited)
       stmtblock_t body;
       stmtblock_t ifbody;
       gfc_loopinfo loop;
+      tree orig_nelems = nelems; /* Needed for bounds check.  */
 
       gfc_init_block (&body);
       tmp = fold_build2_loc (input_location, MINUS_EXPR,
@@ -1164,6 +1275,31 @@ gfc_copy_class_to_class (tree from, tree to, tree nelems, bool unlimited)
        }
       vec_safe_push (args, to_ref);
 
+      /* Add bounds check.  */
+      if ((gfc_option.rtcheck & GFC_RTCHECK_BOUNDS) > 0 && is_from_desc)
+       {
+         char *msg;
+         const char *name = "<<unknown>>";
+         tree from_len;
+
+         if (DECL_P (to))
+           name = (const char *)(DECL_NAME (to)->identifier.id.str);
+
+         from_len = gfc_conv_descriptor_size (from_data, 1);
+         tmp = fold_build2_loc (input_location, NE_EXPR,
+                                 boolean_type_node, from_len, orig_nelems);
+         msg = xasprintf ("Array bound mismatch for dimension %d "
+                          "of array '%s' (%%ld/%%ld)",
+                          1, name);
+
+         gfc_trans_runtime_check (true, false, tmp, &body,
+                                  &gfc_current_locus, msg,
+                            fold_convert (long_integer_type_node, orig_nelems),
+                              fold_convert (long_integer_type_node, from_len));
+
+         free (msg);
+       }
+
       tmp = build_call_vec (fcn_type, fcn, args);
 
       /* Build the body of the loop.  */
@@ -1328,8 +1464,13 @@ gfc_trans_class_init_assign (gfc_code *code)
   rhs->rank = 0;
 
   if (code->expr1->ts.type == BT_CLASS
-       && CLASS_DATA (code->expr1)->attr.dimension)
-    tmp = gfc_trans_class_array_init_assign (rhs, lhs, code->expr1);
+      && CLASS_DATA (code->expr1)->attr.dimension)
+    {
+      gfc_array_spec *tmparr = gfc_get_array_spec ();
+      *tmparr = *CLASS_DATA (code->expr1)->as;
+      gfc_add_full_array_ref (lhs, tmparr);
+      tmp = gfc_trans_class_array_init_assign (rhs, lhs, code->expr1);
+    }
   else
     {
       sz = gfc_copy_expr (code->expr1);
@@ -1374,114 +1515,6 @@ gfc_trans_class_init_assign (gfc_code *code)
 }
 
 
-/* Translate an assignment to a CLASS object
-   (pointer or ordinary assignment).  */
-
-tree
-gfc_trans_class_assign (gfc_expr *expr1, gfc_expr *expr2, gfc_exec_op op)
-{
-  stmtblock_t block;
-  tree tmp;
-  gfc_expr *lhs;
-  gfc_expr *rhs;
-  gfc_ref *ref;
-
-  gfc_start_block (&block);
-
-  ref = expr1->ref;
-  while (ref && ref->next)
-     ref = ref->next;
-
-  /* Class valued proc_pointer assignments do not need any further
-     preparation.  */
-  if (ref && ref->type == REF_COMPONENT
-       && ref->u.c.component->attr.proc_pointer
-       && expr2->expr_type == EXPR_VARIABLE
-       && expr2->symtree->n.sym->attr.flavor == FL_PROCEDURE
-       && op == EXEC_POINTER_ASSIGN)
-    goto assign;
-
-  if (expr2->ts.type != BT_CLASS)
-    {
-      /* Insert an additional assignment which sets the '_vptr' field.  */
-      gfc_symbol *vtab = NULL;
-      gfc_symtree *st;
-
-      lhs = gfc_copy_expr (expr1);
-      gfc_add_vptr_component (lhs);
-
-      if (UNLIMITED_POLY (expr1)
-         && expr2->expr_type == EXPR_NULL && expr2->ts.type == BT_UNKNOWN)
-       {
-         rhs = gfc_get_null_expr (&expr2->where);
-         goto assign_vptr;
-       }
-
-      if (expr2->expr_type == EXPR_NULL)
-       vtab = gfc_find_vtab (&expr1->ts);
-      else
-       vtab = gfc_find_vtab (&expr2->ts);
-      gcc_assert (vtab);
-
-      rhs = gfc_get_expr ();
-      rhs->expr_type = EXPR_VARIABLE;
-      gfc_find_sym_tree (vtab->name, vtab->ns, 1, &st);
-      rhs->symtree = st;
-      rhs->ts = vtab->ts;
-assign_vptr:
-      tmp = gfc_trans_pointer_assignment (lhs, rhs);
-      gfc_add_expr_to_block (&block, tmp);
-
-      gfc_free_expr (lhs);
-      gfc_free_expr (rhs);
-    }
-  else if (expr1->ts.type == BT_DERIVED && UNLIMITED_POLY (expr2))
-    {
-      /* F2003:C717 only sequence and bind-C types can come here.  */
-      gcc_assert (expr1->ts.u.derived->attr.sequence
-                 || expr1->ts.u.derived->attr.is_bind_c);
-      gfc_add_data_component (expr2);
-      goto assign;
-    }
-  else if (CLASS_DATA (expr2)->attr.dimension && expr2->expr_type != EXPR_FUNCTION)
-    {
-      /* Insert an additional assignment which sets the '_vptr' field.  */
-      lhs = gfc_copy_expr (expr1);
-      gfc_add_vptr_component (lhs);
-
-      rhs = gfc_copy_expr (expr2);
-      gfc_add_vptr_component (rhs);
-
-      tmp = gfc_trans_pointer_assignment (lhs, rhs);
-      gfc_add_expr_to_block (&block, tmp);
-
-      gfc_free_expr (lhs);
-      gfc_free_expr (rhs);
-    }
-
-  /* Do the actual CLASS assignment.  */
-  if (expr2->ts.type == BT_CLASS
-      && !CLASS_DATA (expr2)->attr.dimension)
-    op = EXEC_ASSIGN;
-  else if (expr2->expr_type != EXPR_FUNCTION || expr2->ts.type != BT_CLASS
-          || !CLASS_DATA (expr2)->attr.dimension)
-    gfc_add_data_component (expr1);
-
-assign:
-
-  if (op == EXEC_ASSIGN)
-    tmp = gfc_trans_assignment (expr1, expr2, false, true);
-  else if (op == EXEC_POINTER_ASSIGN)
-    tmp = gfc_trans_pointer_assignment (expr1, expr2);
-  else
-    gcc_unreachable();
-
-  gfc_add_expr_to_block (&block, tmp);
-
-  return gfc_finish_block (&block);
-}
-
-
 /* End of prototype trans-class.c  */
 
 
@@ -1784,69 +1817,54 @@ gfc_get_tree_for_caf_expr (gfc_expr *expr)
 {
   tree caf_decl;
   bool found = false;
-  gfc_ref *ref, *comp_ref = NULL;
+  gfc_ref *ref;
 
   gcc_assert (expr && expr->expr_type == EXPR_VARIABLE);
 
   /* Not-implemented diagnostic.  */
+  if (expr->symtree->n.sym->ts.type == BT_CLASS
+      && UNLIMITED_POLY (expr->symtree->n.sym)
+      && CLASS_DATA (expr->symtree->n.sym)->attr.codimension)
+    gfc_error ("Sorry, coindexed access to an unlimited polymorphic object at "
+              "%L is not supported", &expr->where);
+
   for (ref = expr->ref; ref; ref = ref->next)
     if (ref->type == REF_COMPONENT)
       {
-        comp_ref = ref;
-       if ((ref->u.c.component->ts.type == BT_CLASS
-            && !CLASS_DATA (ref->u.c.component)->attr.codimension
-            && (CLASS_DATA (ref->u.c.component)->attr.pointer
-                || CLASS_DATA (ref->u.c.component)->attr.allocatable))
-           || (ref->u.c.component->ts.type != BT_CLASS
-               && !ref->u.c.component->attr.codimension
-               && (ref->u.c.component->attr.pointer
-                   || ref->u.c.component->attr.allocatable)))
-         gfc_error ("Sorry, coindexed access to a pointer or allocatable "
-                    "component of the coindexed coarray at %L is not yet "
-                    "supported", &expr->where);
+       if (ref->u.c.component->ts.type == BT_CLASS
+           && UNLIMITED_POLY (ref->u.c.component)
+           && CLASS_DATA (ref->u.c.component)->attr.codimension)
+         gfc_error ("Sorry, coindexed access to an unlimited polymorphic "
+                    "component at %L is not supported", &expr->where);
       }
-  if ((!comp_ref
-       && ((expr->symtree->n.sym->ts.type == BT_CLASS
-           && CLASS_DATA (expr->symtree->n.sym)->attr.alloc_comp)
-          || (expr->symtree->n.sym->ts.type == BT_DERIVED
-              && expr->symtree->n.sym->ts.u.derived->attr.alloc_comp)))
-      || (comp_ref
-         && ((comp_ref->u.c.component->ts.type == BT_CLASS
-              && CLASS_DATA (comp_ref->u.c.component)->attr.alloc_comp)
-             || (comp_ref->u.c.component->ts.type == BT_DERIVED
-                 && comp_ref->u.c.component->ts.u.derived->attr.alloc_comp))))
-    gfc_error ("Sorry, coindexed coarray at %L with allocatable component is "
-              "not yet supported", &expr->where);
-
-  if (expr->rank)
-    {
-      /* Without the new array descriptor, access like "caf[i]%a(:)%b" is in
-        general not possible as the required stride multiplier might be not
-        a multiple of c_sizeof(b). In case of noncoindexed access, the
-        scalarizer often takes care of it - for coarrays, it always fails.  */
-      for (ref = expr->ref; ref; ref = ref->next)
-        if (ref->type == REF_COMPONENT
-           && ((ref->u.c.component->ts.type == BT_CLASS
-                && CLASS_DATA (ref->u.c.component)->attr.codimension)
-               || (ref->u.c.component->ts.type != BT_CLASS
-                   && ref->u.c.component->attr.codimension)))
-         break;
-      if (ref == NULL)
-       ref = expr->ref;
-      for ( ; ref; ref = ref->next)
-       if (ref->type == REF_ARRAY && ref->u.ar.dimen)
-         break;
-      for ( ; ref; ref = ref->next)
-       if (ref->type == REF_COMPONENT)
-         gfc_error ("Sorry, coindexed access at %L to a scalar component "
-                    "with an array partref is not yet supported",
-                    &expr->where);
-    }
 
-  caf_decl = expr->symtree->n.sym->backend_decl;
-  gcc_assert (caf_decl);
+  /* Make sure the backend_decl is present before accessing it.  */
+  caf_decl = expr->symtree->n.sym->backend_decl == NULL_TREE
+      ? gfc_get_symbol_decl (expr->symtree->n.sym)
+      : expr->symtree->n.sym->backend_decl;
+
   if (expr->symtree->n.sym->ts.type == BT_CLASS)
-    caf_decl = gfc_class_data_get (caf_decl);
+    {
+      if (expr->ref && expr->ref->type == REF_ARRAY)
+       {
+         caf_decl = gfc_class_data_get (caf_decl);
+         if (CLASS_DATA (expr->symtree->n.sym)->attr.codimension)
+           return caf_decl;
+       }
+      for (ref = expr->ref; ref; ref = ref->next)
+       {
+         if (ref->type == REF_COMPONENT
+             && strcmp (ref->u.c.component->name, "_data") != 0)
+           {
+             caf_decl = gfc_class_data_get (caf_decl);
+             if (CLASS_DATA (expr->symtree->n.sym)->attr.codimension)
+               return caf_decl;
+             break;
+           }
+         else if (ref->type == REF_ARRAY && ref->u.ar.dimen)
+           break;
+       }
+    }
   if (expr->symtree->n.sym->attr.codimension)
     return caf_decl;
 
@@ -1864,7 +1882,14 @@ gfc_get_tree_for_caf_expr (gfc_expr *expr)
                                    TREE_TYPE (comp->backend_decl), caf_decl,
                                    comp->backend_decl, NULL_TREE);
        if (comp->ts.type == BT_CLASS)
-         caf_decl = gfc_class_data_get (caf_decl);
+         {
+           caf_decl = gfc_class_data_get (caf_decl);
+           if (CLASS_DATA (comp)->attr.codimension)
+             {
+               found = true;
+               break;
+             }
+         }
        if (comp->attr.codimension)
          {
            found = true;
@@ -1879,8 +1904,8 @@ gfc_get_tree_for_caf_expr (gfc_expr *expr)
 /* Obtain the Coarray token - and optionally also the offset.  */
 
 void
-gfc_get_caf_token_offset (tree *token, tree *offset, tree caf_decl, tree se_expr,
-                         gfc_expr *expr)
+gfc_get_caf_token_offset (gfc_se *se, tree *token, tree *offset, tree caf_decl,
+                         tree se_expr, gfc_expr *expr)
 {
   tree tmp;
 
@@ -1935,7 +1960,47 @@ gfc_get_caf_token_offset (tree *token, tree *offset, tree caf_decl, tree se_expr
   *offset = fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type,
                             *offset, fold_convert (gfc_array_index_type, tmp));
 
-  if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (caf_decl)))
+  if (expr->symtree->n.sym->ts.type == BT_DERIVED
+      && expr->symtree->n.sym->attr.codimension
+      && expr->symtree->n.sym->ts.u.derived->attr.alloc_comp)
+    {
+      gfc_expr *base_expr = gfc_copy_expr (expr);
+      gfc_ref *ref = base_expr->ref;
+      gfc_se base_se;
+
+      // Iterate through the refs until the last one.
+      while (ref->next)
+         ref = ref->next;
+
+      if (ref->type == REF_ARRAY
+         && ref->u.ar.type != AR_FULL)
+       {
+         const int ranksum = ref->u.ar.dimen + ref->u.ar.codimen;
+         int i;
+         for (i = 0; i < ranksum; ++i)
+           {
+             ref->u.ar.start[i] = NULL;
+             ref->u.ar.end[i] = NULL;
+           }
+         ref->u.ar.type = AR_FULL;
+       }
+      gfc_init_se (&base_se, NULL);
+      if (gfc_caf_attr (base_expr).dimension)
+       {
+         gfc_conv_expr_descriptor (&base_se, base_expr);
+         tmp = gfc_conv_descriptor_data_get (base_se.expr);
+       }
+      else
+       {
+         gfc_conv_expr (&base_se, base_expr);
+         tmp = base_se.expr;
+       }
+
+      gfc_free_expr (base_expr);
+      gfc_add_block_to_block (&se->pre, &base_se.pre);
+      gfc_add_block_to_block (&se->post, &base_se.post);
+    }
+  else if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (caf_decl)))
     tmp = gfc_conv_descriptor_data_get (caf_decl);
   else
    {
@@ -1966,6 +2031,12 @@ gfc_caf_get_image_index (stmtblock_t *block, gfc_expr *e, tree desc)
       break;
   gcc_assert (ref != NULL);
 
+  if (ref->u.ar.dimen_type[ref->u.ar.dimen] == DIMEN_THIS_IMAGE)
+    {
+      return build_call_expr_loc (input_location, gfor_fndecl_caf_this_image, 1,
+                                 integer_zero_node);
+    }
+
   img_idx = integer_zero_node;
   extent = integer_one_node;
   if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)))
@@ -2073,6 +2144,7 @@ flatten_array_ctors_without_strlen (gfc_expr* e)
        }
 
       /* Otherwise, fall through to handle constructor elements.  */
+      gcc_fallthrough ();
     case EXPR_STRUCTURE:
       for (c = gfc_constructor_first (e->value.constructor);
           c; c = gfc_constructor_next (c))
@@ -2098,9 +2170,7 @@ gfc_conv_string_length (gfc_charlen * cl, gfc_expr * expr, stmtblock_t * pblock)
 
   gfc_init_se (&se, NULL);
 
-  if (!cl->length
-       && cl->backend_decl
-       && TREE_CODE (cl->backend_decl) == VAR_DECL)
+  if (!cl->length && cl->backend_decl && VAR_P (cl->backend_decl))
     return;
 
   /* If cl->length is NULL, use gfc_conv_expr to obtain the string length but
@@ -2207,7 +2277,7 @@ gfc_conv_substring (gfc_se * se, gfc_ref * ref, int kind,
        msg = xasprintf ("Substring out of bounds: lower bound (%%ld) of '%s' "
                         "is less than one", name);
       else
-       msg = xasprintf ("Substring out of bounds: lower bound (%%ld)"
+       msg = xasprintf ("Substring out of bounds: lower bound (%%ld) "
                         "is less than one");
       gfc_trans_runtime_check (true, false, fault, &se->pre, where, msg,
                               fold_convert (long_integer_type_node,
@@ -2268,6 +2338,7 @@ gfc_conv_component_ref (gfc_se * se, gfc_ref * ref)
   tree tmp;
   tree decl;
   tree field;
+  tree context;
 
   c = ref->u.c.component;
 
@@ -2278,15 +2349,20 @@ gfc_conv_component_ref (gfc_se * se, gfc_ref * ref)
   field = c->backend_decl;
   gcc_assert (field && TREE_CODE (field) == FIELD_DECL);
   decl = se->expr;
+  context = DECL_FIELD_CONTEXT (field);
 
   /* Components can correspond to fields of different containing
      types, as components are created without context, whereas
      a concrete use of a component has the type of decl as context.
      So, if the type doesn't match, we search the corresponding
      FIELD_DECL in the parent type.  To not waste too much time
-     we cache this result in norestrict_decl.  */
+     we cache this result in norestrict_decl.
+     On the other hand, if the context is a UNION or a MAP (a
+     RECORD_TYPE within a UNION_TYPE) always use the given FIELD_DECL.  */
 
-  if (DECL_FIELD_CONTEXT (field) != TREE_TYPE (decl))
+  if (context != TREE_TYPE (decl)
+      && !(   TREE_CODE (TREE_TYPE (field)) == UNION_TYPE /* Field is union */
+           || TREE_CODE (context) == UNION_TYPE))         /* Field is map */
     {
       tree f2 = c->norestrict_decl;
       if (!f2 || DECL_FIELD_CONTEXT (f2) != TREE_TYPE (decl))
@@ -2468,8 +2544,10 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr)
       if (se_expr)
        se->expr = se_expr;
 
-      /* Procedure actual arguments.  */
-      else if (sym->attr.flavor == FL_PROCEDURE
+      /* Procedure actual arguments.  Look out for temporary variables
+        with the same attributes as function values.  */
+      else if (!sym->attr.temporary
+              && sym->attr.flavor == FL_PROCEDURE
               && se->expr != current_function_decl)
        {
          if (!sym->attr.dummy && !sym->attr.proc_pointer)
@@ -2791,9 +2869,9 @@ gfc_conv_cst_int_power (gfc_se * se, tree lhs, tree rhs)
     return 0;
 
   m = wrhs.to_shwi ();
-  /* There's no ABS for HOST_WIDE_INT, so here we go. It also takes care
-     of the asymmetric range of the integer type.  */
-  n = (unsigned HOST_WIDE_INT) (m < 0 ? -m : m);
+  /* Use the wide_int's routine to reliably get the absolute value on all
+     platforms.  Then convert it to a HOST_WIDE_INT like above.  */
+  n = wi::abs (wrhs).to_shwi ();
 
   type = TREE_TYPE (lhs);
   sgn = tree_int_cst_sgn (rhs);
@@ -3596,7 +3674,7 @@ conv_base_obj_fcn_val (gfc_se * se, tree base_object, gfc_expr * expr)
   gfc_ref *ref;
   tree var;
 
-  if (TREE_CODE (base_object) != VAR_DECL)
+  if (!VAR_P (base_object))
     {
       var = gfc_create_var (TREE_TYPE (base_object), NULL);
       gfc_add_modify (&se->pre, var, base_object);
@@ -3867,6 +3945,10 @@ gfc_add_interface_mapping (gfc_interface_mapping * mapping,
   if (sym->attr.flavor == FL_PROCEDURE)
     value = se->expr;
 
+  /* If the argument is a pass-by-value scalar, use the value as is.  */
+  else if (!sym->attr.dimension && sym->attr.value)
+    value = se->expr;
+
   /* If the argument is either a string or a pointer to a string,
      convert it to a boundless character type.  */
   else if (!sym->attr.dimension && sym->ts.type == BT_CHARACTER)
@@ -4039,6 +4121,16 @@ gfc_map_intrinsic_function (gfc_expr *expr, gfc_interface_mapping *mapping)
       new_expr = gfc_copy_expr (arg1->ts.u.cl->length);
       break;
 
+    case GFC_ISYM_LEN_TRIM:
+      new_expr = gfc_copy_expr (arg1);
+      gfc_apply_interface_mapping_to_expr (mapping, new_expr);
+
+      if (!new_expr)
+       return false;
+
+      gfc_replace_expr (arg1, new_expr);
+      return true;
+
     case GFC_ISYM_SIZE:
       if (!sym->as || sym->as->rank == 0)
        return false;
@@ -4598,10 +4690,11 @@ expr_may_alias_variables (gfc_expr *e, bool array_may_alias)
     {
       gfc_symbol *proc_ifc = gfc_get_proc_ifc_for_expr (e);
 
-      if ((proc_ifc->result->ts.type == BT_CLASS
-          && proc_ifc->result->ts.u.derived->attr.is_class
-          && CLASS_DATA (proc_ifc->result)->attr.class_pointer)
-         || proc_ifc->result->attr.pointer)
+      if (proc_ifc->result != NULL
+         && ((proc_ifc->result->ts.type == BT_CLASS
+              && proc_ifc->result->ts.u.derived->attr.is_class
+              && CLASS_DATA (proc_ifc->result)->attr.class_pointer)
+             || proc_ifc->result->attr.pointer))
        return true;
       else
        return false;
@@ -4725,8 +4818,9 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
      is the third and fourth argument to such a function call a value
      denoting the number of elements to copy (i.e., most of the time the
      length of a deferred length string).  */
-  ulim_copy = formal == NULL && UNLIMITED_POLY (sym)
-      && strcmp ("_copy", comp->name) == 0;
+  ulim_copy = (formal == NULL)
+              && UNLIMITED_POLY (sym)
+              && comp && (strcmp ("_copy", comp->name) == 0);
 
   /* Evaluate the arguments.  */
   for (arg = args, argc = 0; arg != NULL;
@@ -5129,7 +5223,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
                        ptr = gfc_class_data_get (ptr);
 
                      tmp = gfc_deallocate_scalar_with_status (ptr, NULL_TREE,
-                                                              true, e, e->ts);
+                                                              NULL_TREE, true,
+                                                              e, e->ts);
                      gfc_add_expr_to_block (&block, tmp);
                      tmp = fold_build2_loc (input_location, MODIFY_EXPR,
                                             void_type_node, ptr,
@@ -5238,7 +5333,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
                  tmp = gfc_deallocate_with_status (ptr, NULL_TREE,
                                                    NULL_TREE, NULL_TREE,
                                                    NULL_TREE, true, e,
-                                                   false);
+                                                   GFC_CAF_COARRAY_NOCOARRAY);
                  gfc_add_expr_to_block (&block, tmp);
                  tmp = fold_build2_loc (input_location, MODIFY_EXPR,
                                         void_type_node, ptr,
@@ -5359,9 +5454,24 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
              if (fsym && fsym->attr.allocatable
                  && fsym->attr.intent == INTENT_OUT)
                {
+                 if (fsym->ts.type == BT_DERIVED
+                     && fsym->ts.u.derived->attr.alloc_comp)
+                 {
+                   // deallocate the components first
+                   tmp = gfc_deallocate_alloc_comp (fsym->ts.u.derived,
+                                                    parmse.expr, e->rank);
+                   if (tmp != NULL_TREE)
+                     gfc_add_expr_to_block (&se->pre, tmp);
+                 }
+
                  tmp = build_fold_indirect_ref_loc (input_location,
                                                     parmse.expr);
-                 tmp = gfc_trans_dealloc_allocated (tmp, false, e);
+                 if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (tmp)))
+                   tmp = gfc_conv_descriptor_data_get (tmp);
+                 tmp = gfc_deallocate_with_status (tmp, NULL_TREE, NULL_TREE,
+                                                   NULL_TREE, NULL_TREE, true,
+                                                   e,
+                                                   GFC_CAF_COARRAY_NOCOARRAY);
                  if (fsym->attr.optional
                      && e->expr_type == EXPR_VARIABLE
                      && e->symtree->n.sym->attr.optional)
@@ -5473,7 +5583,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
            {
              tree local_tmp;
              local_tmp = gfc_evaluate_now (tmp, &se->pre);
-             local_tmp = gfc_copy_alloc_comp (e->ts.u.derived, local_tmp, tmp, parm_rank);
+             local_tmp = gfc_copy_alloc_comp (e->ts.u.derived, local_tmp, tmp,
+                                              parm_rank, 0);
              gfc_add_expr_to_block (&se->post, local_tmp);
            }
 
@@ -5489,7 +5600,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 
          tmp = gfc_deallocate_alloc_comp (e->ts.u.derived, tmp, parm_rank);
 
-         gfc_add_expr_to_block (&se->post, tmp);
+         gfc_prepend_expr_to_block (&post, tmp);
         }
 
       /* Add argument checking of passing an unallocated/NULL actual to
@@ -5601,7 +5712,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
          else
            {
              tmp = parmse.string_length;
-             if (TREE_CODE (tmp) != VAR_DECL)
+             if (!VAR_P (tmp) && TREE_CODE (tmp) != COMPONENT_REF)
                tmp = gfc_evaluate_now (parmse.string_length, &se->pre);
              parmse.string_length = gfc_build_addr_expr (NULL_TREE, tmp);
            }
@@ -5621,7 +5732,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
       if (sym->name[0] == '_' && e && e->ts.type == BT_CHARACTER
          && strncmp (sym->name, "__vtab_CHARACTER", 16) == 0
          && arg->next && arg->next->expr
-         && arg->next->expr->ts.type == BT_DERIVED
+         && (arg->next->expr->ts.type == BT_DERIVED
+             || arg->next->expr->ts.type == BT_CLASS)
          && arg->next->expr->ts.u.derived->attr.unlimited_polymorphic)
        vec_safe_push (stringargs, parmse.string_length);
 
@@ -5729,8 +5841,10 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 
   if (comp)
     ts = comp->ts;
+  else if (sym->ts.type == BT_CLASS)
+    ts = CLASS_DATA (sym)->ts;
   else
-   ts = sym->ts;
+    ts = sym->ts;
 
   if (ts.type == BT_CHARACTER && sym->attr.is_bind_c)
     se->string_length = build_int_cst (gfc_charlen_type_node, 1);
@@ -5785,8 +5899,9 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
       len = cl.backend_decl;
     }
 
-  byref = (comp && (comp->attr.dimension || comp->ts.type == BT_CHARACTER))
-         || (!comp && gfc_return_by_reference (sym));
+  byref = (comp && (comp->attr.dimension
+          || (comp->ts.type == BT_CHARACTER && !sym->attr.is_bind_c)))
+          || (!comp && gfc_return_by_reference (sym));
   if (byref)
     {
       if (se->direct_byref)
@@ -5798,7 +5913,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
                && GFC_DESCRIPTOR_TYPE_P
                        (TREE_TYPE (TREE_TYPE (TREE_TYPE (se->expr)))))
            se->expr = build_fold_indirect_ref_loc (input_location,
-                                               se->expr);
+                                                   se->expr);
 
          /* If the lhs of an assignment x = f(..) is allocatable and
             f2003 is allowed, we must do the automatic reallocation.
@@ -5902,6 +6017,19 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
          type = gfc_get_character_type (ts.kind, ts.u.cl);
          type = build_pointer_type (type);
 
+         /* Emit a DECL_EXPR for the VLA type.  */
+         tmp = TREE_TYPE (type);
+         if (TYPE_SIZE (tmp)
+             && TREE_CODE (TYPE_SIZE (tmp)) != INTEGER_CST)
+           {
+             tmp = build_decl (input_location, TYPE_DECL, NULL_TREE, tmp);
+             DECL_ARTIFICIAL (tmp) = 1;
+             DECL_IGNORED_P (tmp) = 1;
+             tmp = fold_build1_loc (input_location, DECL_EXPR,
+                                    TREE_TYPE (tmp), tmp);
+             gfc_add_expr_to_block (&se->pre, tmp);
+           }
+
          /* Return an address to a char[0:len-1]* temporary for
             character pointers.  */
          if ((!comp && (sym->attr.pointer || sym->attr.allocatable))
@@ -5940,8 +6068,11 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
       if (ts.type == BT_CHARACTER && ts.deferred)
        {
          tmp = len;
-         if (TREE_CODE (tmp) != VAR_DECL)
+         if (!VAR_P (tmp))
            tmp = gfc_evaluate_now (len, &se->pre);
+         TREE_STATIC (tmp) = 1;
+         gfc_add_modify (&se->pre, tmp,
+                         build_int_cst (TREE_TYPE (tmp), 0));
          tmp = gfc_build_addr_expr (NULL_TREE, tmp);
          vec_safe_push (retargs, tmp);
        }
@@ -6001,7 +6132,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
      after use. This necessitates the creation of a temporary to
      hold the result to prevent duplicate calls.  */
   if (!byref && sym->ts.type != BT_CHARACTER
-      && sym->attr.allocatable && !sym->attr.dimension)
+      && ((sym->attr.allocatable && !sym->attr.dimension && !comp)
+         || (comp && comp->attr.allocatable && !comp->attr.dimension)))
     {
       tmp = gfc_create_var (TREE_TYPE (se->expr), NULL);
       gfc_add_modify (&se->pre, tmp, se->expr);
@@ -6081,19 +6213,41 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
        }
     }
 
+  /* Associate the rhs class object's meta-data with the result, when the
+     result is a temporary.  */
+  if (args && args->expr && args->expr->ts.type == BT_CLASS
+      && sym->ts.type == BT_CLASS && result != NULL_TREE && DECL_P (result)
+      && !GFC_CLASS_TYPE_P (TREE_TYPE (result)))
+    {
+      gfc_se parmse;
+      gfc_expr *class_expr = gfc_find_and_cut_at_last_class_ref (args->expr);
+
+      gfc_init_se (&parmse, NULL);
+      parmse.data_not_needed = 1;
+      gfc_conv_expr (&parmse, class_expr);
+      if (!DECL_LANG_SPECIFIC (result))
+       gfc_allocate_lang_decl (result);
+      GFC_DECL_SAVED_DESCRIPTOR (result) = parmse.expr;
+      gfc_free_expr (class_expr);
+      gcc_assert (parmse.pre.head == NULL_TREE
+                 && parmse.post.head == NULL_TREE);
+    }
+
   /* Follow the function call with the argument post block.  */
   if (byref)
     {
       gfc_add_block_to_block (&se->pre, &post);
 
       /* Transformational functions of derived types with allocatable
-         components must have the result allocatable components copied.  */
+        components must have the result allocatable components copied when the
+        argument is actually given.  */
       arg = expr->value.function.actual;
       if (result && arg && expr->rank
-           && expr->value.function.isym
-           && expr->value.function.isym->transformational
-           && arg->expr->ts.type == BT_DERIVED
-           && arg->expr->ts.u.derived->attr.alloc_comp)
+         && expr->value.function.isym
+         && expr->value.function.isym->transformational
+         && arg->expr
+         && arg->expr->ts.type == BT_DERIVED
+         && arg->expr->ts.u.derived->attr.alloc_comp)
        {
          tree tmp2;
          /* Copy the allocatable components.  We have to use a
@@ -6101,7 +6255,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
             from being corrupted.  */
          tmp2 = gfc_evaluate_now (result, &se->pre);
          tmp = gfc_copy_alloc_comp (arg->expr->ts.u.derived,
-                                    result, tmp2, expr->rank);
+                                    result, tmp2, expr->rank, 0);
          gfc_add_expr_to_block (&se->pre, tmp);
          tmp = gfc_copy_allocatable_data (result, tmp2, TREE_TYPE(tmp2),
                                           expr->rank);
@@ -6111,7 +6265,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
          tmp = gfc_conv_descriptor_data_get (tmp2);
          tmp = gfc_deallocate_with_status (tmp, NULL_TREE, NULL_TREE,
                                            NULL_TREE, NULL_TREE, true,
-                                           NULL, false);
+                                           NULL, GFC_CAF_COARRAY_NOCOARRAY);
          gfc_add_expr_to_block (&se->pre, tmp);
        }
     }
@@ -6314,33 +6468,19 @@ gfc_trans_string_copy (stmtblock_t * block, tree dlength, tree dest,
       return;
     }
 
+  /* The string copy algorithm below generates code like
+
+     if (dlen > 0) {
+         memmove (dest, src, min(dlen, slen));
+         if (slen < dlen)
+             memset(&dest[slen], ' ', dlen - slen);
+     }
+  */
+
   /* Do nothing if the destination length is zero.  */
   cond = fold_build2_loc (input_location, GT_EXPR, boolean_type_node, dlen,
                          build_int_cst (size_type_node, 0));
 
-  /* The following code was previously in _gfortran_copy_string:
-
-       // The two strings may overlap so we use memmove.
-       void
-       copy_string (GFC_INTEGER_4 destlen, char * dest,
-                    GFC_INTEGER_4 srclen, const char * src)
-       {
-         if (srclen >= destlen)
-           {
-             // This will truncate if too long.
-             memmove (dest, src, destlen);
-           }
-         else
-           {
-             memmove (dest, src, srclen);
-             // Pad with spaces.
-             memset (&dest[srclen], ' ', destlen - srclen);
-           }
-       }
-
-     We're now doing it here for better optimization, but the logic
-     is the same.  */
-
   /* For non-default character kinds, we have to multiply the string
      length by the base type size.  */
   chartype = gfc_get_char_type (dkind);
@@ -6363,31 +6503,42 @@ gfc_trans_string_copy (stmtblock_t * block, tree dlength, tree dest,
   else
     src = gfc_build_addr_expr (pvoid_type_node, src);
 
-  /* Truncate string if source is too long.  */
-  cond2 = fold_build2_loc (input_location, GE_EXPR, boolean_type_node, slen,
-                          dlen);
+  /* First do the memmove. */
+  tmp2 = fold_build2_loc (input_location, MIN_EXPR, TREE_TYPE (dlen), dlen,
+                         slen);
   tmp2 = build_call_expr_loc (input_location,
                              builtin_decl_explicit (BUILT_IN_MEMMOVE),
-                             3, dest, src, dlen);
+                             3, dest, src, tmp2);
+  stmtblock_t tmpblock2;
+  gfc_init_block (&tmpblock2);
+  gfc_add_expr_to_block (&tmpblock2, tmp2);
 
-  /* Else copy and pad with spaces.  */
-  tmp3 = build_call_expr_loc (input_location,
-                             builtin_decl_explicit (BUILT_IN_MEMMOVE),
-                             3, dest, src, slen);
+  /* If the destination is longer, fill the end with spaces.  */
+  cond2 = fold_build2_loc (input_location, LT_EXPR, boolean_type_node, slen,
+                          dlen);
+
+  /* Wstringop-overflow appears at -O3 even though this warning is not
+     explicitly available in fortran nor can it be switched off. If the
+     source length is a constant, its negative appears as a very large
+     postive number and triggers the warning in BUILTIN_MEMSET. Fixing
+     the result of the MINUS_EXPR suppresses this spurious warning.  */
+  tmp = fold_build2_loc (input_location, MINUS_EXPR,
+                        TREE_TYPE(dlen), dlen, slen);
+  if (slength && TREE_CONSTANT (slength))
+    tmp = gfc_evaluate_now (tmp, block);
 
   tmp4 = fold_build_pointer_plus_loc (input_location, dest, slen);
-  tmp4 = fill_with_spaces (tmp4, chartype,
-                          fold_build2_loc (input_location, MINUS_EXPR,
-                                           TREE_TYPE(dlen), dlen, slen));
+  tmp4 = fill_with_spaces (tmp4, chartype, tmp);
 
   gfc_init_block (&tempblock);
-  gfc_add_expr_to_block (&tempblock, tmp3);
   gfc_add_expr_to_block (&tempblock, tmp4);
   tmp3 = gfc_finish_block (&tempblock);
 
   /* The whole copy_string function is there.  */
   tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond2,
-                        tmp2, tmp3);
+                        tmp3, build_empty_stmt (input_location));
+  gfc_add_expr_to_block (&tmpblock2, tmp);
+  tmp = gfc_finish_block (&tmpblock2);
   tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, cond, tmp,
                         build_empty_stmt (input_location));
   gfc_add_expr_to_block (block, tmp);
@@ -6612,6 +6763,11 @@ gfc_conv_initializer (gfc_expr * expr, gfc_typespec * ts, tree type,
 {
   gfc_se se;
 
+  if (flag_coarray != GFC_FCOARRAY_LIB && ts->type == BT_DERIVED
+      && ts->u.derived->from_intmod == INTMOD_ISO_FORTRAN_ENV
+      && ts->u.derived->intmod_sym_id == ISOFORTRAN_EVENT_TYPE)
+    return build_constructor (type, NULL);
+
   if (!(expr || pointer || procptr))
     return NULL_TREE;
 
@@ -6674,7 +6830,7 @@ gfc_conv_initializer (gfc_expr * expr, gfc_typespec * ts, tree type,
     {
       switch (ts->type)
        {
-       case BT_DERIVED:
+       case_bt_struct:
        case BT_CLASS:
          gfc_init_se (&se, NULL);
          if (ts->type == BT_CLASS && expr->expr_type == EXPR_NULL)
@@ -6819,18 +6975,20 @@ gfc_trans_alloc_subarray_assign (tree dest, gfc_component * cm,
   gfc_add_modify (&block, dest, se.expr);
 
   /* Deal with arrays of derived types with allocatable components.  */
-  if (cm->ts.type == BT_DERIVED
+  if (gfc_bt_struct (cm->ts.type)
        && cm->ts.u.derived->attr.alloc_comp)
+    // TODO: Fix caf_mode
     tmp = gfc_copy_alloc_comp (cm->ts.u.derived,
                               se.expr, dest,
-                              cm->as->rank);
+                              cm->as->rank, 0);
   else if (cm->ts.type == BT_CLASS && expr->ts.type == BT_DERIVED
           && CLASS_DATA(cm)->attr.allocatable)
     {
       if (cm->ts.u.derived->attr.alloc_comp)
+       // TODO: Fix caf_mode
        tmp = gfc_copy_alloc_comp (expr->ts.u.derived,
                                   se.expr, dest,
-                                  expr->rank);
+                                  expr->rank, 0);
       else
        {
          tmp = TREE_TYPE (dest);
@@ -6992,7 +7150,7 @@ alloc_scalar_allocatable_for_subcomponent_assignment (stmtblock_t *block,
       /* Ensure that cm->ts.u.cl->backend_decl is a componentref to _%s_length
         component.  */
       sprintf (name, "_%s_length", cm->name);
-      strlen = gfc_find_component (sym, name, true, true);
+      strlen = gfc_find_component (sym, name, true, true, NULL);
       lhs_cl_size = fold_build3_loc (input_location, COMPONENT_REF,
                                     gfc_charlen_type_node,
                                     TREE_OPERAND (comp, 0),
@@ -7128,7 +7286,7 @@ gfc_trans_subcomponent_assign (tree dest, gfc_component * cm, gfc_expr * expr,
     {
       if (cm->attr.allocatable && expr->expr_type == EXPR_NULL)
        gfc_conv_descriptor_data_set (&block, dest, null_pointer_node);
-      else if (cm->attr.allocatable)
+      else if (cm->attr.allocatable || cm->attr.pdt_array)
        {
          tmp = gfc_trans_alloc_subarray_assign (dest, cm, expr);
          gfc_add_expr_to_block (&block, tmp);
@@ -7153,6 +7311,12 @@ gfc_trans_subcomponent_assign (tree dest, gfc_component * cm, gfc_expr * expr,
       tmp = gfc_trans_alloc_subarray_assign (tmp, cm, expr);
       gfc_add_expr_to_block (&block, tmp);
     }
+  else if (init && cm->attr.allocatable && expr->expr_type == EXPR_NULL)
+    {
+      /* NULL initialization for allocatable components.  */
+      gfc_add_modify (&block, dest, fold_convert (TREE_TYPE (dest),
+                                                 null_pointer_node));
+    }
   else if (init && (cm->attr.allocatable
           || (cm->ts.type == BT_CLASS && CLASS_DATA (cm)->attr.allocatable
               && expr->ts.type != BT_CLASS)))
@@ -7204,6 +7368,29 @@ gfc_trans_subcomponent_assign (tree dest, gfc_component * cm, gfc_expr * expr,
                        fold_convert (TREE_TYPE (tmp), se.expr));
       gfc_add_block_to_block (&block, &se.post);
     }
+  else if (expr->ts.type == BT_UNION)
+    {
+      tree tmp;
+      gfc_constructor *c = gfc_constructor_first (expr->value.constructor);
+      /* We mark that the entire union should be initialized with a contrived
+         EXPR_NULL expression at the beginning.  */
+      if (c != NULL && c->n.component == NULL
+         && c->expr != NULL && c->expr->expr_type == EXPR_NULL)
+        {
+          tmp = build2_loc (input_location, MODIFY_EXPR, void_type_node,
+                           dest, build_constructor (TREE_TYPE (dest), NULL));
+         gfc_add_expr_to_block (&block, tmp);
+          c = gfc_constructor_next (c);
+        }
+      /* The following constructor expression, if any, represents a specific
+         map intializer, as given by the user.  */
+      if (c != NULL && c->expr != NULL)
+        {
+          gcc_assert (expr->expr_type == EXPR_STRUCTURE);
+         tmp = gfc_trans_structure_assign (dest, expr, expr->symtree != NULL);
+         gfc_add_expr_to_block (&block, tmp);
+        }
+    }
   else if (expr->ts.type == BT_DERIVED && expr->ts.f90_type != BT_VOID)
     {
       if (expr->expr_type != EXPR_STRUCTURE)
@@ -7227,8 +7414,9 @@ gfc_trans_subcomponent_assign (tree dest, gfc_component * cm, gfc_expr * expr,
          if (cm->ts.u.derived->attr.alloc_comp
              && expr->expr_type != EXPR_NULL)
            {
+             // TODO: Fix caf_mode
              tmp = gfc_copy_alloc_comp (cm->ts.u.derived, se.expr,
-                                        dest, expr->rank);
+                                        dest, expr->rank, 0);
              gfc_add_expr_to_block (&block, tmp);
              if (dealloc != NULL_TREE)
                gfc_add_expr_to_block (&block, dealloc);
@@ -7294,13 +7482,14 @@ gfc_trans_subcomponent_assign (tree dest, gfc_component * cm, gfc_expr * expr,
 /* Assign a derived type constructor to a variable.  */
 
 tree
-gfc_trans_structure_assign (tree dest, gfc_expr * expr, bool init)
+gfc_trans_structure_assign (tree dest, gfc_expr * expr, bool init, bool coarray)
 {
   gfc_constructor *c;
   gfc_component *cm;
   stmtblock_t block;
   tree field;
   tree tmp;
+  gfc_se se;
 
   gfc_start_block (&block);
   cm = expr->ts.u.derived->components;
@@ -7309,9 +7498,8 @@ gfc_trans_structure_assign (tree dest, gfc_expr * expr, bool init)
       && (expr->ts.u.derived->intmod_sym_id == ISOCBINDING_PTR
           || expr->ts.u.derived->intmod_sym_id == ISOCBINDING_FUNPTR))
     {
-      gfc_se se, lse;
+      gfc_se lse;
 
-      gcc_assert (cm->backend_decl == NULL);
       gfc_init_se (&se, NULL);
       gfc_init_se (&lse, NULL);
       gfc_conv_expr (&se, gfc_constructor_first (expr->value.constructor)->expr);
@@ -7322,6 +7510,9 @@ gfc_trans_structure_assign (tree dest, gfc_expr * expr, bool init)
       return gfc_finish_block (&block);
     }
 
+  if (coarray)
+    gfc_init_se (&se, NULL);
+
   for (c = gfc_constructor_first (expr->value.constructor);
        c; c = gfc_constructor_next (c), cm = cm->next)
     {
@@ -7329,6 +7520,65 @@ gfc_trans_structure_assign (tree dest, gfc_expr * expr, bool init)
       if (!c->expr && !cm->attr.allocatable)
        continue;
 
+      /* Register the component with the caf-lib before it is initialized.
+        Register only allocatable components, that are not coarray'ed
+        components (%comp[*]).  Only register when the constructor is not the
+        null-expression.  */
+      if (coarray && !cm->attr.codimension
+         && (cm->attr.allocatable || cm->attr.pointer)
+         && (!c->expr || c->expr->expr_type == EXPR_NULL))
+       {
+         tree token, desc, size;
+         bool is_array = cm->ts.type == BT_CLASS
+             ? CLASS_DATA (cm)->attr.dimension : cm->attr.dimension;
+
+         field = cm->backend_decl;
+         field = fold_build3_loc (input_location, COMPONENT_REF,
+                                  TREE_TYPE (field), dest, field, NULL_TREE);
+         if (cm->ts.type == BT_CLASS)
+           field = gfc_class_data_get (field);
+
+         token = is_array ? gfc_conv_descriptor_token (field)
+                          : fold_build3_loc (input_location, COMPONENT_REF,
+                                             TREE_TYPE (cm->caf_token), dest,
+                                             cm->caf_token, NULL_TREE);
+
+         if (is_array)
+           {
+             /* The _caf_register routine looks at the rank of the array
+                descriptor to decide whether the data registered is an array
+                or not.  */
+             int rank = cm->ts.type == BT_CLASS ? CLASS_DATA (cm)->as->rank
+                                                : cm->as->rank;
+             /* When the rank is not known just set a positive rank, which
+                suffices to recognize the data as array.  */
+             if (rank < 0)
+               rank = 1;
+             size = integer_zero_node;
+             desc = field;
+             gfc_add_modify (&block, gfc_conv_descriptor_dtype (desc),
+                             build_int_cst (gfc_array_index_type, rank));
+           }
+         else
+           {
+             desc = gfc_conv_scalar_to_descriptor (&se, field,
+                                                   cm->ts.type == BT_CLASS
+                                                   ? CLASS_DATA (cm)->attr
+                                                   : cm->attr);
+             size = TYPE_SIZE_UNIT (TREE_TYPE (field));
+           }
+         gfc_add_block_to_block (&block, &se.pre);
+         tmp =  build_call_expr_loc (input_location, gfor_fndecl_caf_register,
+                                     7, size, build_int_cst (
+                                       integer_type_node,
+                                       GFC_CAF_COARRAY_ALLOC_REGISTER_ONLY),
+                                     gfc_build_addr_expr (pvoid_type_node,
+                                                          token),
+                                     gfc_build_addr_expr (NULL_TREE, desc),
+                                     null_pointer_node, null_pointer_node,
+                                     integer_zero_node);
+         gfc_add_expr_to_block (&block, tmp);
+       }
       field = cm->backend_decl;
       tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
                             dest, field, NULL_TREE);
@@ -7347,6 +7597,43 @@ gfc_trans_structure_assign (tree dest, gfc_expr * expr, bool init)
   return gfc_finish_block (&block);
 }
 
+void
+gfc_conv_union_initializer (vec<constructor_elt, va_gc> *v,
+                            gfc_component *un, gfc_expr *init)
+{
+  gfc_constructor *ctor;
+
+  if (un->ts.type != BT_UNION || un == NULL || init == NULL)
+    return;
+
+  ctor = gfc_constructor_first (init->value.constructor);
+
+  if (ctor == NULL || ctor->expr == NULL)
+    return;
+
+  gcc_assert (init->expr_type == EXPR_STRUCTURE);
+
+  /* If we have an 'initialize all' constructor, do it first.  */
+  if (ctor->expr->expr_type == EXPR_NULL)
+    {
+      tree union_type = TREE_TYPE (un->backend_decl);
+      tree val = build_constructor (union_type, NULL);
+      CONSTRUCTOR_APPEND_ELT (v, un->backend_decl, val);
+      ctor = gfc_constructor_next (ctor);
+    }
+
+  /* Add the map initializer on top.  */
+  if (ctor != NULL && ctor->expr != NULL)
+    {
+      gcc_assert (ctor->expr->expr_type == EXPR_STRUCTURE);
+      tree val = gfc_conv_initializer (ctor->expr, &un->ts,
+                                       TREE_TYPE (un->backend_decl),
+                                       un->attr.dimension, un->attr.pointer,
+                                       un->attr.proc_pointer);
+      CONSTRUCTOR_APPEND_ELT (v, un->backend_decl, val);
+    }
+}
+
 /* Build an expression for a constructor. If init is nonzero then
    this is part of a static variable initializer.  */
 
@@ -7370,7 +7657,8 @@ gfc_conv_structure (gfc_se * se, gfc_expr * expr, int init)
       se->expr = gfc_create_var (type, expr->ts.u.derived->name);
       /* The symtree in expr is NULL, if the code to generate is for
         initializing the static members only.  */
-      tmp = gfc_trans_structure_assign (se->expr, expr, expr->symtree != NULL);
+      tmp = gfc_trans_structure_assign (se->expr, expr, expr->symtree != NULL,
+                                       se->want_coarray);
       gfc_add_expr_to_block (&se->pre, tmp);
       return;
     }
@@ -7409,6 +7697,8 @@ gfc_conv_structure (gfc_se * se, gfc_expr * expr, int init)
        CONSTRUCTOR_APPEND_ELT (v, cm->backend_decl,
                                fold_convert (TREE_TYPE (cm->backend_decl),
                                              integer_zero_node));
+      else if (cm->ts.type == BT_UNION)
+        gfc_conv_union_initializer (v, cm, c->expr);
       else
        {
          val = gfc_conv_initializer (c->expr, &cm->ts,
@@ -7421,6 +7711,7 @@ gfc_conv_structure (gfc_se * se, gfc_expr * expr, int init)
          CONSTRUCTOR_APPEND_ELT (v, cm->backend_decl, val);
        }
     }
+
   se->expr = build_constructor (type, v);
   if (init)
     TREE_CONSTANT (se->expr) = 1;
@@ -7674,6 +7965,247 @@ gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr)
 }
 
 
+/* Get the _len component for an unlimited polymorphic expression.  */
+
+static tree
+trans_get_upoly_len (stmtblock_t *block, gfc_expr *expr)
+{
+  gfc_se se;
+  gfc_ref *ref = expr->ref;
+
+  gfc_init_se (&se, NULL);
+  while (ref && ref->next)
+    ref = ref->next;
+  gfc_add_len_component (expr);
+  gfc_conv_expr (&se, expr);
+  gfc_add_block_to_block (block, &se.pre);
+  gcc_assert (se.post.head == NULL_TREE);
+  if (ref)
+    {
+      gfc_free_ref_list (ref->next);
+      ref->next = NULL;
+    }
+  else
+    {
+      gfc_free_ref_list (expr->ref);
+      expr->ref = NULL;
+    }
+  return se.expr;
+}
+
+
+/* Assign _vptr and _len components as appropriate.  BLOCK should be a
+   statement-list outside of the scalarizer-loop.  When code is generated, that
+   depends on the scalarized expression, it is added to RSE.PRE.
+   Returns le's _vptr tree and when set the len expressions in to_lenp and
+   from_lenp to form a le%_vptr%_copy (re, le, [from_lenp, to_lenp])
+   expression.  */
+
+static tree
+trans_class_vptr_len_assignment (stmtblock_t *block, gfc_expr * le,
+                                gfc_expr * re, gfc_se *rse,
+                                tree * to_lenp, tree * from_lenp)
+{
+  gfc_se se;
+  gfc_expr * vptr_expr;
+  tree tmp, to_len = NULL_TREE, from_len = NULL_TREE, lhs_vptr;
+  bool set_vptr = false, temp_rhs = false;
+  stmtblock_t *pre = block;
+
+  /* Create a temporary for complicated expressions.  */
+  if (re->expr_type != EXPR_VARIABLE && re->expr_type != EXPR_NULL
+      && rse->expr != NULL_TREE && !DECL_P (rse->expr))
+    {
+      tmp = gfc_create_var (TREE_TYPE (rse->expr), "rhs");
+      pre = &rse->pre;
+      gfc_add_modify (&rse->pre, tmp, rse->expr);
+      rse->expr = tmp;
+      temp_rhs = true;
+    }
+
+  /* Get the _vptr for the left-hand side expression.  */
+  gfc_init_se (&se, NULL);
+  vptr_expr = gfc_find_and_cut_at_last_class_ref (le);
+  if (vptr_expr != NULL && gfc_expr_attr (vptr_expr).class_ok)
+    {
+      /* Care about _len for unlimited polymorphic entities.  */
+      if (UNLIMITED_POLY (vptr_expr)
+         || (vptr_expr->ts.type == BT_DERIVED
+             && vptr_expr->ts.u.derived->attr.unlimited_polymorphic))
+       to_len = trans_get_upoly_len (block, vptr_expr);
+      gfc_add_vptr_component (vptr_expr);
+      set_vptr = true;
+    }
+  else
+    vptr_expr = gfc_lval_expr_from_sym (gfc_find_vtab (&le->ts));
+  se.want_pointer = 1;
+  gfc_conv_expr (&se, vptr_expr);
+  gfc_free_expr (vptr_expr);
+  gfc_add_block_to_block (block, &se.pre);
+  gcc_assert (se.post.head == NULL_TREE);
+  lhs_vptr = se.expr;
+  STRIP_NOPS (lhs_vptr);
+
+  /* Set the _vptr only when the left-hand side of the assignment is a
+     class-object.  */
+  if (set_vptr)
+    {
+      /* Get the vptr from the rhs expression only, when it is variable.
+        Functions are expected to be assigned to a temporary beforehand.  */
+      vptr_expr = re->expr_type == EXPR_VARIABLE
+         ? gfc_find_and_cut_at_last_class_ref (re)
+         : NULL;
+      if (vptr_expr != NULL && vptr_expr->ts.type == BT_CLASS)
+       {
+         if (to_len != NULL_TREE)
+           {
+             /* Get the _len information from the rhs.  */
+             if (UNLIMITED_POLY (vptr_expr)
+                 || (vptr_expr->ts.type == BT_DERIVED
+                     && vptr_expr->ts.u.derived->attr.unlimited_polymorphic))
+               from_len = trans_get_upoly_len (block, vptr_expr);
+           }
+         gfc_add_vptr_component (vptr_expr);
+       }
+      else
+       {
+         if (re->expr_type == EXPR_VARIABLE
+             && DECL_P (re->symtree->n.sym->backend_decl)
+             && DECL_LANG_SPECIFIC (re->symtree->n.sym->backend_decl)
+             && GFC_DECL_SAVED_DESCRIPTOR (re->symtree->n.sym->backend_decl)
+             && GFC_CLASS_TYPE_P (TREE_TYPE (GFC_DECL_SAVED_DESCRIPTOR (
+                                          re->symtree->n.sym->backend_decl))))
+           {
+             vptr_expr = NULL;
+             se.expr = gfc_class_vptr_get (GFC_DECL_SAVED_DESCRIPTOR (
+                                            re->symtree->n.sym->backend_decl));
+             if (to_len)
+               from_len = gfc_class_len_get (GFC_DECL_SAVED_DESCRIPTOR (
+                                            re->symtree->n.sym->backend_decl));
+           }
+         else if (temp_rhs && re->ts.type == BT_CLASS)
+           {
+             vptr_expr = NULL;
+             se.expr = gfc_class_vptr_get (rse->expr);
+           }
+         else if (re->expr_type != EXPR_NULL)
+           /* Only when rhs is non-NULL use its declared type for vptr
+              initialisation.  */
+           vptr_expr = gfc_lval_expr_from_sym (gfc_find_vtab (&re->ts));
+         else
+           /* When the rhs is NULL use the vtab of lhs' declared type.  */
+           vptr_expr = gfc_lval_expr_from_sym (gfc_find_vtab (&le->ts));
+       }
+
+      if (vptr_expr)
+       {
+         gfc_init_se (&se, NULL);
+         se.want_pointer = 1;
+         gfc_conv_expr (&se, vptr_expr);
+         gfc_free_expr (vptr_expr);
+         gfc_add_block_to_block (block, &se.pre);
+         gcc_assert (se.post.head == NULL_TREE);
+       }
+      gfc_add_modify (pre, lhs_vptr, fold_convert (TREE_TYPE (lhs_vptr),
+                                               se.expr));
+
+      if (to_len != NULL_TREE)
+       {
+         /* The _len component needs to be set.  Figure how to get the
+            value of the right-hand side.  */
+         if (from_len == NULL_TREE)
+           {
+             if (rse->string_length != NULL_TREE)
+               from_len = rse->string_length;
+             else if (re->ts.type == BT_CHARACTER && re->ts.u.cl->length)
+               {
+                 from_len = gfc_get_expr_charlen (re);
+                 gfc_init_se (&se, NULL);
+                 gfc_conv_expr (&se, re->ts.u.cl->length);
+                 gfc_add_block_to_block (block, &se.pre);
+                 gcc_assert (se.post.head == NULL_TREE);
+                 from_len = gfc_evaluate_now (se.expr, block);
+               }
+             else
+               from_len = integer_zero_node;
+           }
+         gfc_add_modify (pre, to_len, fold_convert (TREE_TYPE (to_len),
+                                                    from_len));
+       }
+    }
+
+  /* Return the _len trees only, when requested.  */
+  if (to_lenp)
+    *to_lenp = to_len;
+  if (from_lenp)
+    *from_lenp = from_len;
+  return lhs_vptr;
+}
+
+
+/* Assign tokens for pointer components.  */
+
+static void
+trans_caf_token_assign (gfc_se *lse, gfc_se *rse, gfc_expr *expr1,
+                       gfc_expr *expr2)
+{
+  symbol_attribute lhs_attr, rhs_attr;
+  tree tmp, lhs_tok, rhs_tok;
+  /* Flag to indicated component refs on the rhs.  */
+  bool rhs_cr;
+
+  lhs_attr = gfc_caf_attr (expr1);
+  if (expr2->expr_type != EXPR_NULL)
+    {
+      rhs_attr = gfc_caf_attr (expr2, false, &rhs_cr);
+      if (lhs_attr.codimension && rhs_attr.codimension)
+       {
+         lhs_tok = gfc_get_ultimate_alloc_ptr_comps_caf_token (lse, expr1);
+         lhs_tok = build_fold_indirect_ref (lhs_tok);
+
+         if (rhs_cr)
+           rhs_tok = gfc_get_ultimate_alloc_ptr_comps_caf_token (rse, expr2);
+         else
+           {
+             tree caf_decl;
+             caf_decl = gfc_get_tree_for_caf_expr (expr2);
+             gfc_get_caf_token_offset (rse, &rhs_tok, NULL, caf_decl,
+                                       NULL_TREE, NULL);
+           }
+         tmp = build2_loc (input_location, MODIFY_EXPR, void_type_node,
+                           lhs_tok,
+                           fold_convert (TREE_TYPE (lhs_tok), rhs_tok));
+         gfc_prepend_expr_to_block (&lse->post, tmp);
+       }
+    }
+  else if (lhs_attr.codimension)
+    {
+      lhs_tok = gfc_get_ultimate_alloc_ptr_comps_caf_token (lse, expr1);
+      lhs_tok = build_fold_indirect_ref (lhs_tok);
+      tmp = build2_loc (input_location, MODIFY_EXPR, void_type_node,
+                       lhs_tok, null_pointer_node);
+      gfc_prepend_expr_to_block (&lse->post, tmp);
+    }
+}
+
+/* Indentify class valued proc_pointer assignments.  */
+
+static bool
+pointer_assignment_is_proc_pointer (gfc_expr * expr1, gfc_expr * expr2)
+{
+  gfc_ref * ref;
+
+  ref = expr1->ref;
+  while (ref && ref->next)
+     ref = ref->next;
+
+  return ref && ref->type == REF_COMPONENT
+      && ref->u.c.component->attr.proc_pointer
+      && expr2->expr_type == EXPR_VARIABLE
+      && expr2->symtree->n.sym->attr.flavor == FL_PROCEDURE;
+}
+
+
 tree
 gfc_trans_pointer_assign (gfc_code * code)
 {
@@ -7686,20 +8218,22 @@ gfc_trans_pointer_assign (gfc_code * code)
 tree
 gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
 {
-  gfc_expr *expr1_vptr = NULL;
   gfc_se lse;
   gfc_se rse;
   stmtblock_t block;
   tree desc;
   tree tmp;
   tree decl;
-  bool scalar;
+  bool scalar, non_proc_pointer_assign;
   gfc_ss *ss;
 
   gfc_start_block (&block);
 
   gfc_init_se (&lse, NULL);
 
+  /* Usually testing whether this is not a proc pointer assignment.  */
+  non_proc_pointer_assign = !pointer_assignment_is_proc_pointer (expr1, expr2);
+
   /* Check whether the expression is a scalar or not; we cannot use
      expr1->rank as it can be nonzero for proc pointers.  */
   ss = gfc_walk_expr (expr1);
@@ -7708,7 +8242,7 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
     gfc_free_ss_chain (ss);
 
   if (expr1->ts.type == BT_DERIVED && expr2->ts.type == BT_CLASS
-      && expr2->expr_type != EXPR_FUNCTION)
+      && expr2->expr_type != EXPR_FUNCTION && non_proc_pointer_assign)
     {
       gfc_add_data_component (expr2);
       /* The following is required as gfc_add_data_component doesn't
@@ -7725,6 +8259,13 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
       rse.want_pointer = 1;
       gfc_conv_expr (&rse, expr2);
 
+      if (non_proc_pointer_assign && expr1->ts.type == BT_CLASS)
+       {
+         trans_class_vptr_len_assignment (&block, expr1, expr2, &rse, NULL,
+                                          NULL);
+         lse.expr = gfc_class_data_get (lse.expr);
+       }
+
       if (expr1->symtree->n.sym->attr.proc_pointer
          && expr1->symtree->n.sym->attr.dummy)
        lse.expr = build_fold_indirect_ref_loc (input_location,
@@ -7738,27 +8279,6 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
       gfc_add_block_to_block (&block, &lse.pre);
       gfc_add_block_to_block (&block, &rse.pre);
 
-      /* For string assignments to unlimited polymorphic pointers add an
-        assignment of the string_length to the _len component of the
-        pointer.  */
-      if ((expr1->ts.type == BT_CLASS || expr1->ts.type == BT_DERIVED)
-         && expr1->ts.u.derived->attr.unlimited_polymorphic
-         && (expr2->ts.type == BT_CHARACTER ||
-             ((expr2->ts.type == BT_DERIVED || expr2->ts.type == BT_CLASS)
-              && expr2->ts.u.derived->attr.unlimited_polymorphic)))
-       {
-         gfc_expr *len_comp;
-         gfc_se se;
-         len_comp = gfc_get_len_component (expr1);
-         gfc_init_se (&se, NULL);
-         gfc_conv_expr (&se, len_comp);
-
-         /* ptr % _len = len (str)  */
-         gfc_add_modify (&block, se.expr, rse.string_length);
-         lse.string_length = se.expr;
-         gfc_free_expr (len_comp);
-       }
-
       /* Check character lengths if character expression.  The test is only
         really added if -fbounds-check is enabled.  Exclude deferred
         character length lefthand sides.  */
@@ -7785,12 +8305,14 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
                            build_int_cst (gfc_charlen_type_node, 0));
        }
 
-      if (expr1->ts.type == BT_DERIVED && expr2->ts.type == BT_CLASS)
-       rse.expr = gfc_class_data_get (rse.expr);
-
       gfc_add_modify (&block, lse.expr,
                      fold_convert (TREE_TYPE (lse.expr), rse.expr));
 
+      /* Also set the tokens for pointer components in derived typed
+        coarrays.  */
+      if (flag_coarray == GFC_FCOARRAY_LIB)
+       trans_caf_token_assign (&lse, &rse, expr1, expr2);
+
       gfc_add_block_to_block (&block, &rse.post);
       gfc_add_block_to_block (&block, &lse.post);
     }
@@ -7798,6 +8320,7 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
     {
       gfc_ref* remap;
       bool rank_remap;
+      tree expr1_vptr = NULL_TREE;
       tree strlen_lhs;
       tree strlen_rhs = NULL_TREE;
 
@@ -7814,9 +8337,6 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
       gfc_init_se (&lse, NULL);
       if (remap)
        lse.descriptor_only = 1;
-      if (expr2->expr_type == EXPR_FUNCTION && expr2->ts.type == BT_CLASS
-         && expr1->ts.type == BT_CLASS)
-       expr1_vptr = gfc_copy_expr (expr1);
       gfc_conv_expr_descriptor (&lse, expr1);
       strlen_lhs = lse.string_length;
       desc = lse.expr;
@@ -7842,16 +8362,15 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
                rse.expr = gfc_class_data_get (rse.expr);
              else
                {
+                 expr1_vptr = trans_class_vptr_len_assignment (&block, expr1,
+                                                               expr2, &rse,
+                                                               NULL, NULL);
                  gfc_add_block_to_block (&block, &rse.pre);
                  tmp = gfc_create_var (TREE_TYPE (rse.expr), "ptrtemp");
                  gfc_add_modify (&lse.pre, tmp, rse.expr);
 
-                 gfc_add_vptr_component (expr1_vptr);
-                 gfc_init_se (&rse, NULL);
-                 rse.want_pointer = 1;
-                 gfc_conv_expr (&rse, expr1_vptr);
-                 gfc_add_modify (&lse.pre, rse.expr,
-                                 fold_convert (TREE_TYPE (rse.expr),
+                 gfc_add_modify (&lse.pre, expr1_vptr,
+                                 fold_convert (TREE_TYPE (expr1_vptr),
                                                gfc_class_vptr_get (tmp)));
                  rse.expr = gfc_class_data_get (tmp);
                }
@@ -7868,17 +8387,21 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
                                               bound, bound, 0,
                                               GFC_ARRAY_POINTER_CONT, false);
              tmp = gfc_create_var (tmp, "ptrtemp");
-             lse.descriptor_only = 0;
-             lse.expr = tmp;
-             lse.direct_byref = 1;
-             gfc_conv_expr_descriptor (&lse, expr2);
-             strlen_rhs = lse.string_length;
+             rse.descriptor_only = 0;
+             rse.expr = tmp;
+             rse.direct_byref = 1;
+             gfc_conv_expr_descriptor (&rse, expr2);
+             strlen_rhs = rse.string_length;
              rse.expr = tmp;
            }
          else
            {
              gfc_conv_expr_descriptor (&rse, expr2);
              strlen_rhs = rse.string_length;
+             if (expr1->ts.type == BT_CLASS)
+               expr1_vptr = trans_class_vptr_len_assignment (&block, expr1,
+                                                             expr2, &rse,
+                                                             NULL, NULL);
            }
        }
       else if (expr2->expr_type == EXPR_VARIABLE)
@@ -7897,12 +8420,22 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
              gfc_init_se (&rse, NULL);
              rse.descriptor_only = 1;
              gfc_conv_expr (&rse, expr2);
+             if (expr1->ts.type == BT_CLASS)
+               trans_class_vptr_len_assignment (&block, expr1, expr2, &rse,
+                                                NULL, NULL);
              tmp = gfc_get_element_type (TREE_TYPE (rse.expr));
              tmp = fold_convert (gfc_array_index_type, size_in_bytes (tmp));
              if (!INTEGER_CST_P (tmp))
                gfc_add_block_to_block (&lse.post, &rse.pre);
              gfc_add_modify (&lse.post, GFC_DECL_SPAN(decl), tmp);
            }
+         else if (expr1->ts.type == BT_CLASS)
+           {
+             rse.expr = NULL_TREE;
+             rse.string_length = NULL_TREE;
+             trans_class_vptr_len_assignment (&block, expr1, expr2, &rse,
+                                              NULL, NULL);
+           }
        }
       else if (expr2->expr_type == EXPR_FUNCTION && expr2->ts.type == BT_CLASS)
        {
@@ -7916,16 +8449,15 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
            }
          else
            {
+             expr1_vptr = trans_class_vptr_len_assignment (&block, expr1,
+                                                           expr2, &rse, NULL,
+                                                           NULL);
              gfc_add_block_to_block (&block, &rse.pre);
              tmp = gfc_create_var (TREE_TYPE (rse.expr), "ptrtemp");
              gfc_add_modify (&lse.pre, tmp, rse.expr);
 
-             gfc_add_vptr_component (expr1_vptr);
-             gfc_init_se (&rse, NULL);
-             rse.want_pointer = 1;
-             gfc_conv_expr (&rse, expr1_vptr);
-             gfc_add_modify (&lse.pre, rse.expr,
-                             fold_convert (TREE_TYPE (rse.expr),
+             gfc_add_modify (&lse.pre, expr1_vptr,
+                             fold_convert (TREE_TYPE (expr1_vptr),
                                        gfc_class_vptr_get (tmp)));
              rse.expr = gfc_class_data_get (tmp);
              gfc_add_modify (&lse.pre, desc, rse.expr);
@@ -7944,9 +8476,6 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
          gfc_add_modify (&lse.pre, desc, tmp);
        }
 
-      if (expr1_vptr)
-       gfc_free_expr (expr1_vptr);
-
       gfc_add_block_to_block (&block, &lse.pre);
       if (rank_remap)
        gfc_add_block_to_block (&block, &rse.pre);
@@ -8174,7 +8703,7 @@ gfc_conv_string_parameter (gfc_se * se)
 
 tree
 gfc_trans_scalar_assign (gfc_se * lse, gfc_se * rse, gfc_typespec ts,
-                        bool deep_copy, bool dealloc)
+                        bool deep_copy, bool dealloc, bool in_coarray)
 {
   stmtblock_t block;
   tree tmp;
@@ -8196,7 +8725,6 @@ gfc_trans_scalar_assign (gfc_se * lse, gfc_se * rse, gfc_typespec ts,
 
       if (rse->string_length != NULL_TREE)
        {
-         gcc_assert (rse->string_length != NULL_TREE);
          gfc_conv_string_parameter (rse);
          gfc_add_block_to_block (&block, &rse->pre);
          rlen = rse->string_length;
@@ -8205,7 +8733,7 @@ gfc_trans_scalar_assign (gfc_se * lse, gfc_se * rse, gfc_typespec ts,
       gfc_trans_string_copy (&block, llen, lse->expr, ts.kind, rlen,
                             rse->expr, ts.kind);
     }
-  else if (ts.type == BT_DERIVED && ts.u.derived->attr.alloc_comp)
+  else if (gfc_bt_struct (ts.type) && ts.u.derived->attr.alloc_comp)
     {
       tree tmp_var = NULL_TREE;
       cond = NULL_TREE;
@@ -8252,13 +8780,16 @@ gfc_trans_scalar_assign (gfc_se * lse, gfc_se * rse, gfc_typespec ts,
         same as the lhs.  */
       if (deep_copy)
        {
-         tmp = gfc_copy_alloc_comp (ts.u.derived, rse->expr, lse->expr, 0);
+         int caf_mode = in_coarray ? (GFC_STRUCTURE_CAF_MODE_ENABLE_COARRAY
+                                      | GFC_STRUCTURE_CAF_MODE_IN_COARRAY) : 0;
+         tmp = gfc_copy_alloc_comp (ts.u.derived, rse->expr, lse->expr, 0,
+                                    caf_mode);
          tmp = build3_v (COND_EXPR, cond, build_empty_stmt (input_location),
                          tmp);
          gfc_add_expr_to_block (&block, tmp);
        }
     }
-  else if (ts.type == BT_DERIVED || ts.type == BT_CLASS)
+  else if (gfc_bt_struct (ts.type) || ts.type == BT_CLASS)
     {
       gfc_add_block_to_block (&block, &lse->pre);
       gfc_add_block_to_block (&block, &rse->pre);
@@ -8817,8 +9348,8 @@ gfc_trans_array_constructor_copy (gfc_expr * expr1, gfc_expr * expr2)
 
 /* Tells whether the expression is to be treated as a variable reference.  */
 
-static bool
-expr_is_variable (gfc_expr *expr)
+bool
+gfc_expr_is_variable (gfc_expr *expr)
 {
   gfc_expr *arg;
   gfc_component *comp;
@@ -8831,7 +9362,7 @@ expr_is_variable (gfc_expr *expr)
   if (arg)
     {
       gcc_assert (expr->value.function.isym->id == GFC_ISYM_TRANSPOSE);
-      return expr_is_variable (arg);
+      return gfc_expr_is_variable (arg);
     }
 
   /* A data-pointer-returning function should be considered as a variable
@@ -8893,10 +9424,11 @@ is_scalar_reallocatable_lhs (gfc_expr *expr)
        && !expr->ref)
     return true;
 
-  /* All that can be left are allocatable components.  */
-  if ((expr->symtree->n.sym->ts.type != BT_DERIVED
+  /* All that can be left are allocatable components.  However, we do
+     not check for allocatable components here because the expression
+     could be an allocatable component of a pointer component.  */
+  if (expr->symtree->n.sym->ts.type != BT_DERIVED
        && expr->symtree->n.sym->ts.type != BT_CLASS)
-       || !expr->symtree->n.sym->ts.u.derived->attr.alloc_comp)
     return false;
 
   /* Find an allocatable component ref last.  */
@@ -8978,7 +9510,25 @@ alloc_scalar_allocatable_for_assignment (stmtblock_t *block,
   size_in_bytes = fold_build2_loc (input_location, MAX_EXPR, size_type_node,
                                   size_in_bytes, size_one_node);
 
-  if (expr1->ts.type == BT_DERIVED && expr1->ts.u.derived->attr.alloc_comp)
+  if (gfc_caf_attr (expr1).codimension && flag_coarray == GFC_FCOARRAY_LIB)
+    {
+      tree caf_decl, token;
+      gfc_se caf_se;
+      symbol_attribute attr;
+
+      gfc_clear_attr (&attr);
+      gfc_init_se (&caf_se, NULL);
+
+      caf_decl = gfc_get_tree_for_caf_expr (expr1);
+      gfc_get_caf_token_offset (&caf_se, &token, NULL, caf_decl, NULL_TREE,
+                               NULL);
+      gfc_add_block_to_block (block, &caf_se.pre);
+      gfc_allocate_allocatable (block, lse.expr, size_in_bytes,
+                               gfc_build_addr_expr (NULL_TREE, token),
+                               NULL_TREE, NULL_TREE, NULL_TREE, jump_label1,
+                               expr1, 1);
+    }
+  else if (expr1->ts.type == BT_DERIVED && expr1->ts.u.derived->attr.alloc_comp)
     {
       tmp = build_call_expr_loc (input_location,
                                 builtin_decl_explicit (BUILT_IN_CALLOC),
@@ -9133,14 +9683,122 @@ is_runtime_conformable (gfc_expr *expr1, gfc_expr *expr2)
   return false;
 }
 
+
+static tree
+trans_class_assignment (stmtblock_t *block, gfc_expr *lhs, gfc_expr *rhs,
+                       gfc_se *lse, gfc_se *rse, bool use_vptr_copy,
+                       bool class_realloc)
+{
+  tree tmp, fcn, stdcopy, to_len, from_len, vptr;
+  vec<tree, va_gc> *args = NULL;
+
+  vptr = trans_class_vptr_len_assignment (block, lhs, rhs, rse, &to_len,
+                                        &from_len);
+
+  /* Generate allocation of the lhs.  */
+  if (class_realloc)
+    {
+      stmtblock_t alloc;
+      tree class_han;
+
+      tmp = gfc_vptr_size_get (vptr);
+      class_han = GFC_CLASS_TYPE_P (TREE_TYPE (lse->expr))
+         ? gfc_class_data_get (lse->expr) : lse->expr;
+      gfc_init_block (&alloc);
+      gfc_allocate_using_malloc (&alloc, class_han, tmp, NULL_TREE);
+      tmp = fold_build2_loc (input_location, EQ_EXPR,
+                            boolean_type_node, class_han,
+                            build_int_cst (prvoid_type_node, 0));
+      tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node,
+                            gfc_unlikely (tmp,
+                                          PRED_FORTRAN_FAIL_ALLOC),
+                            gfc_finish_block (&alloc),
+                            build_empty_stmt (input_location));
+      gfc_add_expr_to_block (&lse->pre, tmp);
+    }
+
+  fcn = gfc_vptr_copy_get (vptr);
+
+  tmp = GFC_CLASS_TYPE_P (TREE_TYPE (rse->expr))
+      ? gfc_class_data_get (rse->expr) : rse->expr;
+  if (use_vptr_copy)
+    {
+      if (!POINTER_TYPE_P (TREE_TYPE (tmp))
+         || INDIRECT_REF_P (tmp)
+         || (rhs->ts.type == BT_DERIVED
+             && rhs->ts.u.derived->attr.unlimited_polymorphic
+             && !rhs->ts.u.derived->attr.pointer
+             && !rhs->ts.u.derived->attr.allocatable)
+         || (UNLIMITED_POLY (rhs)
+             && !CLASS_DATA (rhs)->attr.pointer
+             && !CLASS_DATA (rhs)->attr.allocatable))
+       vec_safe_push (args, gfc_build_addr_expr (NULL_TREE, tmp));
+      else
+       vec_safe_push (args, tmp);
+      tmp = GFC_CLASS_TYPE_P (TREE_TYPE (lse->expr))
+         ? gfc_class_data_get (lse->expr) : lse->expr;
+      if (!POINTER_TYPE_P (TREE_TYPE (tmp))
+         || INDIRECT_REF_P (tmp)
+         || (lhs->ts.type == BT_DERIVED
+             && lhs->ts.u.derived->attr.unlimited_polymorphic
+             && !lhs->ts.u.derived->attr.pointer
+             && !lhs->ts.u.derived->attr.allocatable)
+         || (UNLIMITED_POLY (lhs)
+             && !CLASS_DATA (lhs)->attr.pointer
+             && !CLASS_DATA (lhs)->attr.allocatable))
+       vec_safe_push (args, gfc_build_addr_expr (NULL_TREE, tmp));
+      else
+       vec_safe_push (args, tmp);
+
+      stdcopy = build_call_vec (TREE_TYPE (TREE_TYPE (fcn)), fcn, args);
+
+      if (to_len != NULL_TREE && !integer_zerop (from_len))
+       {
+         tree extcopy;
+         vec_safe_push (args, from_len);
+         vec_safe_push (args, to_len);
+         extcopy = build_call_vec (TREE_TYPE (TREE_TYPE (fcn)), fcn, args);
+
+         tmp = fold_build2_loc (input_location, GT_EXPR,
+                                boolean_type_node, from_len,
+                                integer_zero_node);
+         return fold_build3_loc (input_location, COND_EXPR,
+                                 void_type_node, tmp,
+                                 extcopy, stdcopy);
+       }
+      else
+       return stdcopy;
+    }
+  else
+    {
+      tree rhst = GFC_CLASS_TYPE_P (TREE_TYPE (lse->expr))
+         ? gfc_class_data_get (lse->expr) : lse->expr;
+      stmtblock_t tblock;
+      gfc_init_block (&tblock);
+      if (!POINTER_TYPE_P (TREE_TYPE (tmp)))
+       tmp = gfc_build_addr_expr (NULL_TREE, tmp);
+      if (!POINTER_TYPE_P (TREE_TYPE (rhst)))
+       rhst = gfc_build_addr_expr (NULL_TREE, rhst);
+      /* When coming from a ptr_copy lhs and rhs are swapped.  */
+      gfc_add_modify_loc (input_location, &tblock, rhst,
+                         fold_convert (TREE_TYPE (rhst), tmp));
+      return gfc_finish_block (&tblock);
+    }
+}
+
 /* Subroutine of gfc_trans_assignment that actually scalarizes the
    assignment.  EXPR1 is the destination/LHS and EXPR2 is the source/RHS.
    init_flag indicates initialization expressions and dealloc that no
-   deallocate prior assignment is needed (if in doubt, set true).  */
+   deallocate prior assignment is needed (if in doubt, set true).
+   When PTR_COPY is set and expr1 is a class type, then use the _vptr-copy
+   routine instead of a pointer assignment.  Alias resolution is only done,
+   when MAY_ALIAS is set (the default).  This flag is used by ALLOCATE()
+   where it is known, that newly allocated memory on the lhs can never be
+   an alias of the rhs.  */
 
 static tree
 gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
-                       bool dealloc)
+                       bool dealloc, bool use_vptr_copy, bool may_alias)
 {
   gfc_se lse;
   gfc_se rse;
@@ -9155,6 +9813,9 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
   bool scalar_to_array;
   tree string_length;
   int n;
+  bool maybe_workshare = false, lhs_refs_comp = false, rhs_refs_comp = false;
+  symbol_attribute lhs_caf_attr, rhs_caf_attr, lhs_attr;
+  bool is_poly_assign;
 
   /* Assignment of the form lhs = rhs.  */
   gfc_start_block (&block);
@@ -9175,6 +9836,27 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
          || gfc_is_alloc_class_scalar_function (expr2)))
     expr2->must_finalize = 1;
 
+  /* Checking whether a class assignment is desired is quite complicated and
+     needed at two locations, so do it once only before the information is
+     needed.  */
+  lhs_attr = gfc_expr_attr (expr1);
+  is_poly_assign = (use_vptr_copy || lhs_attr.pointer
+                   || (lhs_attr.allocatable && !lhs_attr.dimension))
+                  && (expr1->ts.type == BT_CLASS
+                      || gfc_is_class_array_ref (expr1, NULL)
+                      || gfc_is_class_scalar_expr (expr1)
+                      || gfc_is_class_array_ref (expr2, NULL)
+                      || gfc_is_class_scalar_expr (expr2));
+
+
+  /* Only analyze the expressions for coarray properties, when in coarray-lib
+     mode.  */
+  if (flag_coarray == GFC_FCOARRAY_LIB)
+    {
+      lhs_caf_attr = gfc_caf_attr (expr1, false, &lhs_refs_comp);
+      rhs_caf_attr = gfc_caf_attr (expr2, false, &rhs_refs_comp);
+    }
+
   if (lss != gfc_ss_terminator)
     {
       /* The assignment needs scalarization.  */
@@ -9195,6 +9877,10 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
       if (rss == gfc_ss_terminator)
        /* The rhs is scalar.  Add a ss for the expression.  */
        rss = gfc_get_scalar_ss (gfc_ss_terminator, expr2);
+      /* When doing a class assign, then the handle to the rhs needs to be a
+        pointer to allow for polymorphism.  */
+      if (is_poly_assign && expr2->rank == 0 && !UNLIMITED_POLY (expr2))
+       rss->info->type = GFC_SS_REFERENCE;
 
       /* Associate the SS with the loop.  */
       gfc_add_ss_to_loop (&loop, lss);
@@ -9206,7 +9892,8 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
       for (n = 0; n < GFC_MAX_DIMENSIONS; n++)
        loop.reverse[n] = GFC_ENABLE_REVERSE;
       /* Resolve any data dependencies in the statement.  */
-      gfc_conv_resolve_dependencies (&loop, lss, rss);
+      if (may_alias)
+       gfc_conv_resolve_dependencies (&loop, lss, rss);
       /* Setup the scalarizing loops.  */
       gfc_conv_loop_setup (&loop, &expr2->where);
 
@@ -9229,8 +9916,13 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
        }
 
       /* Allow the scalarizer to workshare array assignments.  */
-      if ((ompws_flags & OMPWS_WORKSHARE_FLAG) && loop.temp_ss == NULL)
-       ompws_flags |= OMPWS_SCALARIZER_WS;
+      if ((ompws_flags & (OMPWS_WORKSHARE_FLAG | OMPWS_SCALARIZER_BODY))
+         == OMPWS_WORKSHARE_FLAG
+         && loop.temp_ss == NULL)
+       {
+         maybe_workshare = true;
+         ompws_flags |= OMPWS_SCALARIZER_WS | OMPWS_SCALARIZER_BODY;
+       }
 
       /* Start the scalarized loop body.  */
       gfc_start_scalarized_body (&loop, &body);
@@ -9241,6 +9933,8 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
   l_is_temp = (lss != gfc_ss_terminator && loop.temp_ss != NULL);
 
   /* Translate the expression.  */
+  rse.want_coarray = flag_coarray == GFC_FCOARRAY_LIB && init_flag
+      && lhs_caf_attr.codimension;
   gfc_conv_expr (&rse, expr2);
 
   /* Deal with the case of a scalar class function assigned to a derived type.  */
@@ -9252,8 +9946,13 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
     }
 
   /* Stabilize a string length for temporaries.  */
-  if (expr2->ts.type == BT_CHARACTER)
+  if (expr2->ts.type == BT_CHARACTER && !expr1->ts.deferred
+      && !(VAR_P (rse.string_length)
+          || TREE_CODE (rse.string_length) == PARM_DECL
+          || TREE_CODE (rse.string_length) == INDIRECT_REF))
     string_length = gfc_evaluate_now (rse.string_length, &rse.pre);
+  else if (expr2->ts.type == BT_CHARACTER)
+    string_length = rse.string_length;
   else
     string_length = NULL_TREE;
 
@@ -9264,14 +9963,46 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
        lse.string_length = string_length;
     }
   else
-    gfc_conv_expr (&lse, expr1);
+    {
+      gfc_conv_expr (&lse, expr1);
+      if (gfc_option.rtcheck & GFC_RTCHECK_MEM
+         && !init_flag
+         && gfc_expr_attr (expr1).allocatable
+         && expr1->rank
+         && !expr2->rank)
+       {
+         tree cond;
+         const char* msg;
+
+         tmp = INDIRECT_REF_P (lse.expr)
+             ? gfc_build_addr_expr (NULL_TREE, lse.expr) : lse.expr;
+
+         /* We should only get array references here.  */
+         gcc_assert (TREE_CODE (tmp) == POINTER_PLUS_EXPR
+                     || TREE_CODE (tmp) == ARRAY_REF);
+
+         /* 'tmp' is either the pointer to the array(POINTER_PLUS_EXPR)
+            or the array itself(ARRAY_REF).  */
+         tmp = TREE_OPERAND (tmp, 0);
+
+         /* Provide the address of the array.  */
+         if (TREE_CODE (lse.expr) == ARRAY_REF)
+           tmp = gfc_build_addr_expr (NULL_TREE, tmp);
+
+         cond = fold_build2_loc (input_location, EQ_EXPR, boolean_type_node,
+                                 tmp, build_int_cst (TREE_TYPE (tmp), 0));
+         msg = _("Assignment of scalar to unallocated array");
+         gfc_trans_runtime_check (true, false, cond, &loop.pre,
+                                  &expr1->where, msg);
+       }
+    }
 
   /* Assignments of scalar derived types with allocatable components
      to arrays must be done with a deep copy and the rhs temporary
      must have its components deallocated afterwards.  */
   scalar_to_array = (expr2->ts.type == BT_DERIVED
                       && expr2->ts.u.derived->attr.alloc_comp
-                      && !expr_is_variable (expr2)
+                      && !gfc_expr_is_variable (expr2)
                       && expr1->rank && !expr2->rank);
   scalar_to_array |= (expr1->ts.type == BT_DERIVED
                                    && expr1->rank
@@ -9287,8 +10018,14 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
      the function call must happen before the (re)allocation of the lhs -
      otherwise the character length of the result is not known.
      NOTE: This relies on having the exact dependence of the length type
-     parameter available to the caller; gfortran saves it in the .mod files.  */
-  if (flag_realloc_lhs && expr2->ts.type == BT_CHARACTER && expr1->ts.deferred)
+     parameter available to the caller; gfortran saves it in the .mod files.
+     NOTE ALSO: The concatenation operation generates a temporary pointer,
+     whose allocation must go to the innermost loop.  */
+  if (flag_realloc_lhs
+      && expr2->ts.type == BT_CHARACTER && expr1->ts.deferred
+      && !(lss != gfc_ss_terminator
+          && expr2->expr_type == EXPR_OP
+          && expr2->value.op.op == INTRINSIC_CONCAT))
     gfc_add_block_to_block (&block, &rse.pre);
 
   /* Nullify the allocatable components corresponding to those of the lhs
@@ -9297,9 +10034,9 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
      nullification occurs before the call to the finalizer. In the case of
      a scalar to array assignment, this is done in gfc_trans_scalar_assign
      as part of the deep copy.  */
-  if (!scalar_to_array && (expr1->ts.type == BT_DERIVED)
-                                             && (gfc_is_alloc_class_array_function (expr2)
-                                                     || gfc_is_alloc_class_scalar_function (expr2)))
+  if (!scalar_to_array && expr1->ts.type == BT_DERIVED
+                      && (gfc_is_alloc_class_array_function (expr2)
+                          || gfc_is_alloc_class_scalar_function (expr2)))
     {
       tmp = rse.expr;
       tmp = gfc_nullify_alloc_comp (expr1->ts.u.derived, rse.expr, 0);
@@ -9308,16 +10045,54 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
        gfc_add_block_to_block (&loop.post, &rse.post);
     }
 
-  tmp = gfc_trans_scalar_assign (&lse, &rse, expr1->ts,
-                                expr_is_variable (expr2) || scalar_to_array
-                                || expr2->expr_type == EXPR_ARRAY,
-                                !(l_is_temp || init_flag) && dealloc);
+  if (is_poly_assign)
+    tmp = trans_class_assignment (&body, expr1, expr2, &lse, &rse,
+                                 use_vptr_copy || (lhs_attr.allocatable
+                                                   && !lhs_attr.dimension),
+                                 flag_realloc_lhs && !lhs_attr.pointer);
+  else if (flag_coarray == GFC_FCOARRAY_LIB
+          && lhs_caf_attr.codimension && rhs_caf_attr.codimension
+          && ((lhs_caf_attr.allocatable && lhs_refs_comp)
+              || (rhs_caf_attr.allocatable && rhs_refs_comp)))
+    {
+      /* Only detour to caf_send[get][_by_ref] () when the lhs or rhs is an
+        allocatable component, because those need to be accessed via the
+        caf-runtime.  No need to check for coindexes here, because resolve
+        has rewritten those already.  */
+      gfc_code code;
+      gfc_actual_arglist a1, a2;
+      /* Clear the structures to prevent accessing garbage.  */
+      memset (&code, '\0', sizeof (gfc_code));
+      memset (&a1, '\0', sizeof (gfc_actual_arglist));
+      memset (&a2, '\0', sizeof (gfc_actual_arglist));
+      a1.expr = expr1;
+      a1.next = &a2;
+      a2.expr = expr2;
+      a2.next = NULL;
+      code.ext.actual = &a1;
+      code.resolved_isym = gfc_intrinsic_subroutine_by_id (GFC_ISYM_CAF_SEND);
+      tmp = gfc_conv_intrinsic_subroutine (&code);
+    }
+  else
+    tmp = gfc_trans_scalar_assign (&lse, &rse, expr1->ts,
+                                  gfc_expr_is_variable (expr2)
+                                  || scalar_to_array
+                                  || expr2->expr_type == EXPR_ARRAY,
+                                  !(l_is_temp || init_flag) && dealloc,
+                                  expr1->symtree->n.sym->attr.codimension);
+  /* Add the pre blocks to the body.  */
+  gfc_add_block_to_block (&body, &rse.pre);
+  gfc_add_block_to_block (&body, &lse.pre);
   gfc_add_expr_to_block (&body, tmp);
+  /* Add the post blocks to the body.  */
+  gfc_add_block_to_block (&body, &rse.post);
+  gfc_add_block_to_block (&body, &lse.post);
 
   if (lss == gfc_ss_terminator)
     {
       /* F2003: Add the code for reallocation on assignment.  */
-      if (flag_realloc_lhs && is_scalar_reallocatable_lhs (expr1))
+      if (flag_realloc_lhs && is_scalar_reallocatable_lhs (expr1)
+         && !is_poly_assign)
        alloc_scalar_allocatable_for_assignment (&block, string_length,
                                                 expr1, expr2);
 
@@ -9358,11 +10133,9 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
 
       /* F2003: Allocate or reallocate lhs of allocatable array.  */
       if (flag_realloc_lhs
-           && gfc_is_reallocatable_lhs (expr1)
-           && !gfc_expr_attr (expr1).codimension
-           && !gfc_is_coindexed (expr1)
-           && expr2->rank
-           && !is_runtime_conformable (expr1, expr2))
+         && gfc_is_reallocatable_lhs (expr1)
+         && expr2->rank
+         && !is_runtime_conformable (expr1, expr2))
        {
          realloc_lhs_warning (expr1->ts.type, true, &expr1->where);
          ompws_flags &= ~OMPWS_SCALARIZER_WS;
@@ -9371,6 +10144,9 @@ gfc_trans_assignment_1 (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
            gfc_add_expr_to_block (&loop.code[expr1->rank - 1], tmp);
        }
 
+      if (maybe_workshare)
+       ompws_flags &= ~OMPWS_SCALARIZER_BODY;
+
       /* Generate the copying loops.  */
       gfc_trans_scalarizing_loops (&loop, &body);
 
@@ -9412,7 +10188,7 @@ copyable_array_p (gfc_expr * expr)
     case BT_CHARACTER:
       return false;
 
-    case BT_DERIVED:
+    case_bt_struct:
       return !expr->ts.u.derived->attr.alloc_comp;
 
     default:
@@ -9426,7 +10202,7 @@ copyable_array_p (gfc_expr * expr)
 
 tree
 gfc_trans_assignment (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
-                     bool dealloc)
+                     bool dealloc, bool use_vptr_copy, bool may_alias)
 {
   tree tmp;
 
@@ -9469,13 +10245,14 @@ gfc_trans_assignment (gfc_expr * expr1, gfc_expr * expr2, bool init_flag,
     }
 
   /* Fallback to the scalarizer to generate explicit loops.  */
-  return gfc_trans_assignment_1 (expr1, expr2, init_flag, dealloc);
+  return gfc_trans_assignment_1 (expr1, expr2, init_flag, dealloc,
+                                use_vptr_copy, may_alias);
 }
 
 tree
 gfc_trans_init_assign (gfc_code * code)
 {
-  return gfc_trans_assignment (code->expr1, code->expr2, true, false);
+  return gfc_trans_assignment (code->expr1, code->expr2, true, false, true);
 }
 
 tree