]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/fortran/expr.c
Update copyright years.
[thirdparty/gcc.git] / gcc / fortran / expr.c
index 1a531d92afcec043b09f118c29a14f3c30eeff24..3c221eb67d5a25f59796c6b36b4dcb851d1311cb 100644 (file)
@@ -1,5 +1,5 @@
 /* Routines for manipulation of expression nodes.
-   Copyright (C) 2000-2013 Free Software Foundation, Inc.
+   Copyright (C) 2000-2017 Free Software Foundation, Inc.
    Contributed by Andy Vaught
 
 This file is part of GCC.
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "options.h"
 #include "gfortran.h"
 #include "arith.h"
 #include "match.h"
@@ -144,7 +145,8 @@ gfc_get_constant_expr (bt type, int kind, locus *where)
   gfc_expr *e;
 
   if (!where)
-    gfc_internal_error ("gfc_get_constant_expr(): locus 'where' cannot be NULL");
+    gfc_internal_error ("gfc_get_constant_expr(): locus %<where%> cannot be "
+                       "NULL");
 
   e = gfc_get_expr ();
 
@@ -333,7 +335,7 @@ gfc_copy_expr (gfc_expr *p)
 
        case BT_HOLLERITH:
        case BT_LOGICAL:
-       case BT_DERIVED:
+       case_bt_struct:
        case BT_CLASS:
        case BT_ASSUMED:
          break;                /* Already done.  */
@@ -793,8 +795,6 @@ gfc_build_conversion (gfc_expr *e)
   p = gfc_get_expr ();
   p->expr_type = EXPR_FUNCTION;
   p->symtree = NULL;
-  p->value.function.actual = NULL;
-
   p->value.function.actual = gfc_get_actual_arglist ();
   p->value.function.actual->expr = e;
 
@@ -881,18 +881,17 @@ done:
 }
 
 
-/* Function to determine if an expression is constant or not.  This
  function expects that the expression has already been simplified.  */
+/* Determine if an expression is constant in the sense of F08:7.1.12.
* This function expects that the expression has already been simplified.  */
 
-int
+bool
 gfc_is_constant_expr (gfc_expr *e)
 {
   gfc_constructor *c;
   gfc_actual_arglist *arg;
-  gfc_symbol *sym;
 
   if (e == NULL)
-    return 1;
+    return true;
 
   switch (e->expr_type)
     {
@@ -902,7 +901,7 @@ gfc_is_constant_expr (gfc_expr *e)
                  || gfc_is_constant_expr (e->value.op.op2)));
 
     case EXPR_VARIABLE:
-      return 0;
+      return false;
 
     case EXPR_FUNCTION:
     case EXPR_PPC:
@@ -915,40 +914,21 @@ gfc_is_constant_expr (gfc_expr *e)
        {
          for (arg = e->value.function.actual; arg; arg = arg->next)
            if (!gfc_is_constant_expr (arg->expr))
-             return 0;
+             return false;
        }
 
-      /* Specification functions are constant.  */
-      /* F95, 7.1.6.2; F2003, 7.1.7  */
-      sym = NULL;
-      if (e->symtree)
-       sym = e->symtree->n.sym;
-      if (e->value.function.esym)
-       sym = e->value.function.esym;
-
-      if (sym
-         && sym->attr.function
-         && sym->attr.pure
-         && !sym->attr.intrinsic
-         && !sym->attr.recursive
-         && sym->attr.proc != PROC_INTERNAL
-         && sym->attr.proc != PROC_ST_FUNCTION
-         && sym->attr.proc != PROC_UNKNOWN
-         && gfc_sym_get_dummy_args (sym) == NULL)
-       return 1;
-
       if (e->value.function.isym
          && (e->value.function.isym->elemental
              || e->value.function.isym->pure
              || e->value.function.isym->inquiry
              || e->value.function.isym->transformational))
-       return 1;
+       return true;
 
-      return 0;
+      return false;
 
     case EXPR_CONSTANT:
     case EXPR_NULL:
-      return 1;
+      return true;
 
     case EXPR_SUBSTRING:
       return e->ref == NULL || (gfc_is_constant_expr (e->ref->u.ss.start)
@@ -962,14 +942,14 @@ gfc_is_constant_expr (gfc_expr *e)
 
       for (; c; c = gfc_constructor_next (c))
        if (!gfc_is_constant_expr (c->expr))
-         return 0;
+         return false;
 
-      return 1;
+      return true;
 
 
     default:
       gfc_internal_error ("gfc_is_constant_expr(): Unknown expression type");
-      return 0;
+      return false;
     }
 }
 
@@ -1209,7 +1189,7 @@ find_array_element (gfc_constructor_base base, gfc_array_ref *ar,
          goto depart;
        }
 
-      e = gfc_copy_expr (ar->start[i]);
+      e = ar->start[i];
       if (e->expr_type != EXPR_CONSTANT)
        {
          cons = NULL;
@@ -1258,8 +1238,6 @@ depart:
   mpz_clear (offset);
   mpz_clear (span);
   mpz_clear (tmp);
-  if (e)
-    gfc_free_expr (e);
   *rval = cons;
   return t;
 }
@@ -1270,12 +1248,23 @@ depart:
 static gfc_constructor *
 find_component_ref (gfc_constructor_base base, gfc_ref *ref)
 {
-  gfc_component *comp;
-  gfc_component *pick;
+  gfc_component *pick = ref->u.c.component;
   gfc_constructor *c = gfc_constructor_first (base);
 
-  comp = ref->u.c.sym->components;
-  pick = ref->u.c.component;
+  gfc_symbol *dt = ref->u.c.sym;
+  int ext = dt->attr.extension;
+
+  /* For extended types, check if the desired component is in one of the
+   * parent types.  */
+  while (ext > 0 && gfc_find_component (dt->components->ts.u.derived,
+                                       pick->name, true, true, NULL))
+    {
+      dt = dt->components->ts.u.derived;
+      c = gfc_constructor_first (c->expr->value.constructor);
+      ext--;
+    }
+
+  gfc_component *comp = dt->components;
   while (comp != pick)
     {
       comp = comp->next;
@@ -1530,13 +1519,12 @@ find_array_section (gfc_expr *expr, gfc_ref *ref)
        }
 
       limit = mpz_get_ui (ptr);
-      if (limit >= gfc_option.flag_max_array_constructor)
+      if (limit >= flag_max_array_constructor)
         {
          gfc_error ("The number of elements in the array constructor "
                     "at %L requires an increase of the allowed %d "
                     "upper limit.   See -fmax-array-constructor "
-                    "option", &expr->where,
-                    gfc_option.flag_max_array_constructor);
+                    "option", &expr->where, flag_max_array_constructor);
          return false;
        }
 
@@ -1639,7 +1627,7 @@ simplify_const_ref (gfc_expr *p)
 
            case AR_FULL:
              if (p->ref->next != NULL
-                 && (p->ts.type == BT_CHARACTER || p->ts.type == BT_DERIVED))
+                 && (p->ts.type == BT_CHARACTER || gfc_bt_struct (p->ts.type)))
                {
                  for (c = gfc_constructor_first (p->value.constructor);
                       c; c = gfc_constructor_next (c))
@@ -1649,7 +1637,7 @@ simplify_const_ref (gfc_expr *p)
                        return false;
                    }
 
-                 if (p->ts.type == BT_DERIVED
+                 if (gfc_bt_struct (p->ts.type)
                        && p->ref->next
                        && (c = gfc_constructor_first (p->value.constructor)))
                    {
@@ -1916,7 +1904,6 @@ gfc_simplify_expr (gfc_expr *p, int type)
 
     case EXPR_COMPCALL:
     case EXPR_PPC:
-      gcc_unreachable ();
       break;
     }
 
@@ -1958,7 +1945,7 @@ scalarize_intrinsic_call (gfc_expr *e)
   for (; a; a = a->next)
     {
       n++;
-      if (a->expr->expr_type != EXPR_ARRAY)
+      if (!a->expr || a->expr->expr_type != EXPR_ARRAY)
        continue;
       array_arg = n;
       expr = gfc_copy_expr (a->expr);
@@ -2197,18 +2184,18 @@ check_alloc_comp_init (gfc_expr *e)
   gfc_constructor *ctor;
 
   gcc_assert (e->expr_type == EXPR_STRUCTURE);
-  gcc_assert (e->ts.type == BT_DERIVED);
+  gcc_assert (e->ts.type == BT_DERIVED || e->ts.type == BT_CLASS);
 
   for (comp = e->ts.u.derived->components,
        ctor = gfc_constructor_first (e->value.constructor);
        comp; comp = comp->next, ctor = gfc_constructor_next (ctor))
     {
-      if (comp->attr.allocatable
+      if (comp->attr.allocatable && ctor->expr
           && ctor->expr->expr_type != EXPR_NULL)
         {
-         gfc_error("Invalid initialization expression for ALLOCATABLE "
-                   "component '%s' in structure constructor at %L",
-                   comp->name, &ctor->expr->where);
+         gfc_error ("Invalid initialization expression for ALLOCATABLE "
+                    "component %qs in structure constructor at %L",
+                    comp->name, &ctor->expr->where);
          return false;
        }
     }
@@ -2288,8 +2275,8 @@ check_inquiry (gfc_expr *e, int not_restricted)
        if (strcmp (functions[i], name) == 0)
          break;
 
-       if (functions[i] == NULL)
-         return MATCH_ERROR;
+      if (functions[i] == NULL)
+       return MATCH_ERROR;
     }
 
   /* At this point we have an inquiry function with a variable argument.  The
@@ -2317,7 +2304,7 @@ check_inquiry (gfc_expr *e, int not_restricted)
            && (ap->expr->symtree->n.sym->ts.u.cl->length == NULL
                || ap->expr->symtree->n.sym->ts.deferred))
          {
-           gfc_error ("Assumed or deferred character length variable '%s' "
+           gfc_error ("Assumed or deferred character length variable %qs "
                        " in constant expression at %L",
                        ap->expr->symtree->n.sym->name,
                        &ap->expr->where);
@@ -2383,8 +2370,8 @@ check_transformational (gfc_expr *e)
 
   if (functions[i] == NULL)
     {
-      gfc_error("transformational intrinsic '%s' at %L is not permitted "
-               "in an initialization expression", name, &e->where);
+      gfc_error ("transformational intrinsic %qs at %L is not permitted "
+                "in an initialization expression", name, &e->where);
       return MATCH_ERROR;
     }
 
@@ -2462,14 +2449,36 @@ gfc_check_init_expr (gfc_expr *e)
       t = false;
 
       {
-       gfc_intrinsic_sym* isym;
-       gfc_symbol* sym;
+       bool conversion;
+       gfc_intrinsic_sym* isym = NULL;
+       gfc_symbol* sym = e->symtree->n.sym;
+
+       /* Simplify here the intrinsics from the IEEE_ARITHMETIC and
+          IEEE_EXCEPTIONS modules.  */
+       int mod = sym->from_intmod;
+       if (mod == INTMOD_NONE && sym->generic)
+         mod = sym->generic->sym->from_intmod;
+       if (mod == INTMOD_IEEE_ARITHMETIC || mod == INTMOD_IEEE_EXCEPTIONS)
+         {
+           gfc_expr *new_expr = gfc_simplify_ieee_functions (e);
+           if (new_expr)
+             {
+               gfc_replace_expr (e, new_expr);
+               t = true;
+               break;
+             }
+         }
 
-       sym = e->symtree->n.sym;
-       if (!gfc_is_intrinsic (sym, 0, e->where)
-           || (m = gfc_intrinsic_func_interface (e, 0)) != MATCH_YES)
+       /* If a conversion function, e.g., __convert_i8_i4, was inserted
+          into an array constructor, we need to skip the error check here.
+           Conversion errors are  caught below in scalarize_intrinsic_call.  */
+       conversion = e->value.function.isym
+                  && (e->value.function.isym->conversion == 1);
+
+       if (!conversion && (!gfc_is_intrinsic (sym, 0, e->where)
+           || (m = gfc_intrinsic_func_interface (e, 0)) != MATCH_YES))
          {
-           gfc_error ("Function '%s' in initialization expression at %L "
+           gfc_error ("Function %qs in initialization expression at %L "
                       "must be an intrinsic function",
                       e->symtree->n.sym->name, &e->where);
            break;
@@ -2481,7 +2490,7 @@ gfc_check_init_expr (gfc_expr *e)
            && (m = check_transformational (e)) == MATCH_NO
            && (m = check_elemental (e)) == MATCH_NO)
          {
-           gfc_error ("Intrinsic function '%s' at %L is not permitted "
+           gfc_error ("Intrinsic function %qs at %L is not permitted "
                       "in an initialization expression",
                       e->symtree->n.sym->name, &e->where);
            m = MATCH_ERROR;
@@ -2494,7 +2503,7 @@ gfc_check_init_expr (gfc_expr *e)
           array argument.  */
        isym = gfc_find_function (e->symtree->n.sym->name);
        if (isym && isym->elemental
-           && (t = scalarize_intrinsic_call(e)))
+           && (t = scalarize_intrinsic_call (e)))
          break;
       }
 
@@ -2516,8 +2525,8 @@ gfc_check_init_expr (gfc_expr *e)
             is invalid.  */
          if (!e->symtree->n.sym->value)
            {
-             gfc_error("PARAMETER '%s' is used at %L before its definition "
-                       "is complete", e->symtree->n.sym->name, &e->where);
+             gfc_error ("PARAMETER %qs is used at %L before its definition "
+                        "is complete", e->symtree->n.sym->name, &e->where);
              t = false;
            }
          else
@@ -2536,25 +2545,25 @@ gfc_check_init_expr (gfc_expr *e)
          switch (e->symtree->n.sym->as->type)
            {
              case AS_ASSUMED_SIZE:
-               gfc_error ("Assumed size array '%s' at %L is not permitted "
+               gfc_error ("Assumed size array %qs at %L is not permitted "
                           "in an initialization expression",
                           e->symtree->n.sym->name, &e->where);
                break;
 
              case AS_ASSUMED_SHAPE:
-               gfc_error ("Assumed shape array '%s' at %L is not permitted "
+               gfc_error ("Assumed shape array %qs at %L is not permitted "
                           "in an initialization expression",
                           e->symtree->n.sym->name, &e->where);
                break;
 
              case AS_DEFERRED:
-               gfc_error ("Deferred array '%s' at %L is not permitted "
+               gfc_error ("Deferred array %qs at %L is not permitted "
                           "in an initialization expression",
                           e->symtree->n.sym->name, &e->where);
                break;
 
              case AS_EXPLICIT:
-               gfc_error ("Array '%s' at %L is a variable, which does "
+               gfc_error ("Array %qs at %L is a variable, which does "
                           "not reduce to a constant expression",
                           e->symtree->n.sym->name, &e->where);
                break;
@@ -2564,7 +2573,7 @@ gfc_check_init_expr (gfc_expr *e)
          }
        }
       else
-       gfc_error ("Parameter '%s' at %L has not been declared or is "
+       gfc_error ("Parameter %qs at %L has not been declared or is "
                   "a variable, which does not reduce to a constant "
                   "expression", e->symtree->n.sym->name, &e->where);
 
@@ -2576,14 +2585,18 @@ gfc_check_init_expr (gfc_expr *e)
       break;
 
     case EXPR_SUBSTRING:
-      t = gfc_check_init_expr (e->ref->u.ss.start);
-      if (!t)
-       break;
-
-      t = gfc_check_init_expr (e->ref->u.ss.end);
-      if (t)
-       t = gfc_simplify_expr (e, 0);
+      if (e->ref)
+       {
+         t = gfc_check_init_expr (e->ref->u.ss.start);
+         if (!t)
+           break;
 
+         t = gfc_check_init_expr (e->ref->u.ss.end);
+         if (t)
+           t = gfc_simplify_expr (e, 0);
+       }
+      else
+       t = false;
       break;
 
     case EXPR_STRUCTURE:
@@ -2706,7 +2719,8 @@ restricted_args (gfc_actual_arglist *a)
 /************* Restricted/specification expressions *************/
 
 
-/* Make sure a non-intrinsic function is a specification function.  */
+/* Make sure a non-intrinsic function is a specification function,
+ * see F08:7.1.11.5.  */
 
 static bool
 external_spec_function (gfc_expr *e)
@@ -2715,34 +2729,58 @@ external_spec_function (gfc_expr *e)
 
   f = e->value.function.esym;
 
+  /* IEEE functions allowed are "a reference to a transformational function
+     from the intrinsic module IEEE_ARITHMETIC or IEEE_EXCEPTIONS", and
+     "inquiry function from the intrinsic modules IEEE_ARITHMETIC and
+     IEEE_EXCEPTIONS".  */
+  if (f->from_intmod == INTMOD_IEEE_ARITHMETIC
+      || f->from_intmod == INTMOD_IEEE_EXCEPTIONS)
+    {
+      if (!strcmp (f->name, "ieee_selected_real_kind")
+         || !strcmp (f->name, "ieee_support_rounding")
+         || !strcmp (f->name, "ieee_support_flag")
+         || !strcmp (f->name, "ieee_support_halting")
+         || !strcmp (f->name, "ieee_support_datatype")
+         || !strcmp (f->name, "ieee_support_denormal")
+         || !strcmp (f->name, "ieee_support_divide")
+         || !strcmp (f->name, "ieee_support_inf")
+         || !strcmp (f->name, "ieee_support_io")
+         || !strcmp (f->name, "ieee_support_nan")
+         || !strcmp (f->name, "ieee_support_sqrt")
+         || !strcmp (f->name, "ieee_support_standard")
+         || !strcmp (f->name, "ieee_support_underflow_control"))
+       goto function_allowed;
+    }
+
   if (f->attr.proc == PROC_ST_FUNCTION)
     {
-      gfc_error ("Specification function '%s' at %L cannot be a statement "
+      gfc_error ("Specification function %qs at %L cannot be a statement "
                 "function", f->name, &e->where);
       return false;
     }
 
   if (f->attr.proc == PROC_INTERNAL)
     {
-      gfc_error ("Specification function '%s' at %L cannot be an internal "
+      gfc_error ("Specification function %qs at %L cannot be an internal "
                 "function", f->name, &e->where);
       return false;
     }
 
   if (!f->attr.pure && !f->attr.elemental)
     {
-      gfc_error ("Specification function '%s' at %L must be PURE", f->name,
+      gfc_error ("Specification function %qs at %L must be PURE", f->name,
                 &e->where);
       return false;
     }
 
-  if (f->attr.recursive)
-    {
-      gfc_error ("Specification function '%s' at %L cannot be RECURSIVE",
-                f->name, &e->where);
+  /* F08:7.1.11.6. */
+  if (f->attr.recursive
+      && !gfc_notify_std (GFC_STD_F2003,
+                         "Specification function '%s' "
+                         "at %L cannot be RECURSIVE",  f->name, &e->where))
       return false;
-    }
 
+function_allowed:
   return restricted_args (e->value.function.actual);
 }
 
@@ -2818,6 +2856,18 @@ check_references (gfc_ref* ref, bool (*checker) (gfc_expr*))
   return check_references (ref->next, checker);
 }
 
+/*  Return true if ns is a parent of the current ns.  */
+
+static bool
+is_parent_of_current_ns (gfc_namespace *ns)
+{
+  gfc_namespace *p;
+  for (p = gfc_current_ns->parent; p; p = p->parent)
+    if (ns == p)
+      return true;
+
+  return false;
+}
 
 /* Verify that an expression is a restricted expression.  Like its
    cousin check_init_expr(), an error message is generated if we
@@ -2872,21 +2922,21 @@ check_restricted (gfc_expr *e)
       if (sym->attr.dummy && sym->ns == gfc_current_ns
          && sym->ns->proc_name && sym->ns->proc_name->attr.elemental)
        {
-         gfc_error ("Dummy argument '%s' not allowed in expression at %L",
+         gfc_error ("Dummy argument %qs not allowed in expression at %L",
                     sym->name, &e->where);
          break;
        }
 
       if (sym->attr.optional)
        {
-         gfc_error ("Dummy argument '%s' at %L cannot be OPTIONAL",
+         gfc_error ("Dummy argument %qs at %L cannot be OPTIONAL",
                     sym->name, &e->where);
          break;
        }
 
       if (sym->attr.intent == INTENT_OUT)
        {
-         gfc_error ("Dummy argument '%s' at %L cannot be INTENT(OUT)",
+         gfc_error ("Dummy argument %qs at %L cannot be INTENT(OUT)",
                     sym->name, &e->where);
          break;
        }
@@ -2906,9 +2956,7 @@ check_restricted (gfc_expr *e)
            || sym->attr.dummy
            || sym->attr.implied_index
            || sym->attr.flavor == FL_PARAMETER
-           || (sym->ns && sym->ns == gfc_current_ns->parent)
-           || (sym->ns && gfc_current_ns->parent
-                 && sym->ns == gfc_current_ns->parent->parent)
+           || is_parent_of_current_ns (sym->ns)
            || (sym->ns->proc_name != NULL
                  && sym->ns->proc_name->attr.flavor == FL_MODULE)
            || (gfc_is_formal_arg () && (sym->ns == gfc_current_ns)))
@@ -2917,7 +2965,7 @@ check_restricted (gfc_expr *e)
          break;
        }
 
-      gfc_error ("Variable '%s' cannot appear in the expression at %L",
+      gfc_error ("Variable %qs cannot appear in the expression at %L",
                 sym->name, &e->where);
       /* Prevent a repetition of the error.  */
       e->error = 1;
@@ -2980,7 +3028,7 @@ gfc_specification_expr (gfc_expr *e)
       && !gfc_pure (e->symtree->n.sym)
       && (!comp || !comp->attr.pure))
     {
-      gfc_error ("Function '%s' at %L must be PURE",
+      gfc_error ("Function %qs at %L must be PURE",
                 e->symtree->n.sym->name, &e->where);
       /* Prevent repeat error messages.  */
       e->symtree->n.sym->attr.pure = 1;
@@ -3059,10 +3107,14 @@ gfc_check_conformance (gfc_expr *op1, gfc_expr *op2, const char *optype_msgid, .
 
 
 /* Given an assignable expression and an arbitrary expression, make
-   sure that the assignment can take place.  */
+   sure that the assignment can take place.  Only add a call to the intrinsic
+   conversion routines, when allow_convert is set.  When this assign is a
+   coarray call, then the convert is done by the coarray routine implictly and
+   adding the intrinsic conversion would do harm in most cases.  */
 
 bool
-gfc_check_assign (gfc_expr *lvalue, gfc_expr *rvalue, int conform)
+gfc_check_assign (gfc_expr *lvalue, gfc_expr *rvalue, int conform,
+                 bool allow_convert)
 {
   gfc_symbol *sym;
   gfc_ref *ref;
@@ -3095,19 +3147,22 @@ gfc_check_assign (gfc_expr *lvalue, gfc_expr *rvalue, int conform)
        bad_proc = true;
 
       /* (ii) The assignment is in the main program; or  */
-      if (gfc_current_ns->proc_name->attr.is_main_program)
+      if (gfc_current_ns->proc_name
+         && gfc_current_ns->proc_name->attr.is_main_program)
        bad_proc = true;
 
       /* (iii) A module or internal procedure...  */
-      if ((gfc_current_ns->proc_name->attr.proc == PROC_INTERNAL
-          || gfc_current_ns->proc_name->attr.proc == PROC_MODULE)
+      if (gfc_current_ns->proc_name
+         && (gfc_current_ns->proc_name->attr.proc == PROC_INTERNAL
+             || gfc_current_ns->proc_name->attr.proc == PROC_MODULE)
          && gfc_current_ns->parent
          && (!(gfc_current_ns->parent->proc_name->attr.function
                || gfc_current_ns->parent->proc_name->attr.subroutine)
              || gfc_current_ns->parent->proc_name->attr.is_main_program))
        {
          /* ... that is not a function...  */
-         if (!gfc_current_ns->proc_name->attr.function)
+         if (gfc_current_ns->proc_name
+             && !gfc_current_ns->proc_name->attr.function)
            bad_proc = true;
 
          /* ... or is not an entry and has a different name.  */
@@ -3126,7 +3181,7 @@ gfc_check_assign (gfc_expr *lvalue, gfc_expr *rvalue, int conform)
 
       if (bad_proc)
        {
-         gfc_error ("'%s' at %L is not a VALUE", sym->name, &lvalue->where);
+         gfc_error ("%qs at %L is not a VALUE", sym->name, &lvalue->where);
          return false;
        }
     }
@@ -3159,9 +3214,10 @@ gfc_check_assign (gfc_expr *lvalue, gfc_expr *rvalue, int conform)
     }
 
   /* This is possibly a typo: x = f() instead of x => f().  */
-  if (gfc_option.warn_surprising
+  if (warn_surprising
       && rvalue->expr_type == EXPR_FUNCTION && gfc_expr_attr (rvalue).pointer)
-    gfc_warning ("POINTER-valued function appears on right-hand side of "
+    gfc_warning (OPT_Wsurprising,
+                "POINTER-valued function appears on right-hand side of "
                 "assignment at %L", &rvalue->where);
 
   /* Check size of array assignments.  */
@@ -3172,7 +3228,7 @@ gfc_check_assign (gfc_expr *lvalue, gfc_expr *rvalue, int conform)
   if (rvalue->is_boz && lvalue->ts.type != BT_INTEGER
       && lvalue->symtree->n.sym->attr.data
       && !gfc_notify_std (GFC_STD_GNU, "BOZ literal at %L used to "
-                         "initialize non-integer variable '%s'", 
+                         "initialize non-integer variable %qs",
                          &rvalue->where, lvalue->symtree->n.sym->name))
     return false;
   else if (rvalue->is_boz && !lvalue->symtree->n.sym->attr.data
@@ -3185,10 +3241,11 @@ gfc_check_assign (gfc_expr *lvalue, gfc_expr *rvalue, int conform)
   if (rvalue->is_boz && lvalue->ts.type != BT_INTEGER)
     {
       int rc;
-      if (gfc_option.warn_surprising)
-        gfc_warning ("BOZ literal at %L is bitwise transferred "
-                     "non-integer symbol '%s'", &rvalue->where,
-                     lvalue->symtree->n.sym->name);
+      if (warn_surprising)
+       gfc_warning (OPT_Wsurprising,
+                    "BOZ literal at %L is bitwise transferred "
+                    "non-integer symbol %qs", &rvalue->where,
+                    lvalue->symtree->n.sym->name);
       if (!gfc_convert_boz (rvalue, &lvalue->ts))
        return false;
       if ((rc = gfc_range_check (rvalue)) != ARITH_OK)
@@ -3196,66 +3253,19 @@ gfc_check_assign (gfc_expr *lvalue, gfc_expr *rvalue, int conform)
          if (rc == ARITH_UNDERFLOW)
            gfc_error ("Arithmetic underflow of bit-wise transferred BOZ at %L"
                       ". This check can be disabled with the option "
-                      "-fno-range-check", &rvalue->where);
+                      "%<-fno-range-check%>", &rvalue->where);
          else if (rc == ARITH_OVERFLOW)
            gfc_error ("Arithmetic overflow of bit-wise transferred BOZ at %L"
                       ". This check can be disabled with the option "
-                      "-fno-range-check", &rvalue->where);
+                      "%<-fno-range-check%>", &rvalue->where);
          else if (rc == ARITH_NAN)
            gfc_error ("Arithmetic NaN of bit-wise transferred BOZ at %L"
                       ". This check can be disabled with the option "
-                      "-fno-range-check", &rvalue->where);
+                      "%<-fno-range-check%>", &rvalue->where);
          return false;
        }
     }
 
-  /*  Warn about type-changing conversions for REAL or COMPLEX constants.
-      If lvalue and rvalue are mixed REAL and complex, gfc_compare_types
-      will warn anyway, so there is no need to to so here.  */
-
-  if (rvalue->expr_type == EXPR_CONSTANT && lvalue->ts.type == rvalue->ts.type
-      && (lvalue->ts.type == BT_REAL || lvalue->ts.type == BT_COMPLEX))
-    {
-      if (lvalue->ts.kind < rvalue->ts.kind && gfc_option.gfc_warn_conversion)
-       {
-         /* As a special bonus, don't warn about REAL rvalues which are not
-            changed by the conversion if -Wconversion is specified.  */
-         if (rvalue->ts.type == BT_REAL && mpfr_number_p (rvalue->value.real))
-           {
-             /* Calculate the difference between the constant and the rounded
-                value and check it against zero.  */
-             mpfr_t rv, diff;
-             gfc_set_model_kind (lvalue->ts.kind);
-             mpfr_init (rv);
-             gfc_set_model_kind (rvalue->ts.kind);
-             mpfr_init (diff);
-
-             mpfr_set (rv, rvalue->value.real, GFC_RND_MODE);
-             mpfr_sub (diff, rv, rvalue->value.real, GFC_RND_MODE);
-
-             if (!mpfr_zero_p (diff))
-               gfc_warning ("Change of value in conversion from "
-                            " %s to %s at %L", gfc_typename (&rvalue->ts),
-                            gfc_typename (&lvalue->ts), &rvalue->where);
-
-             mpfr_clear (rv);
-             mpfr_clear (diff);
-           }
-         else
-           gfc_warning ("Possible change of value in conversion from %s "
-                        "to %s at %L",gfc_typename (&rvalue->ts),
-                        gfc_typename (&lvalue->ts), &rvalue->where);
-
-       }
-      else if (gfc_option.warn_conversion_extra
-              && lvalue->ts.kind > rvalue->ts.kind)
-       {
-         gfc_warning ("Conversion from %s to %s at %L",
-                      gfc_typename (&rvalue->ts),
-                      gfc_typename (&lvalue->ts), &rvalue->where);
-       }
-    }
-
   if (gfc_compare_types (&lvalue->ts, &rvalue->ts))
     return true;
 
@@ -3282,12 +3292,15 @@ gfc_check_assign (gfc_expr *lvalue, gfc_expr *rvalue, int conform)
      kind values can be converted into one another.  */
   if (lvalue->ts.type == BT_CHARACTER && rvalue->ts.type == BT_CHARACTER)
     {
-      if (lvalue->ts.kind != rvalue->ts.kind)
-       gfc_convert_chartype (rvalue, &lvalue->ts);
-
-      return true;
+      if (lvalue->ts.kind != rvalue->ts.kind && allow_convert)
+       return gfc_convert_chartype (rvalue, &lvalue->ts);
+      else
+       return true;
     }
 
+  if (!allow_convert)
+    return true;
+
   return gfc_convert_type (rvalue, &lvalue->ts, 1);
 }
 
@@ -3315,7 +3328,7 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
   if (lhs_attr.flavor == FL_PROCEDURE && lhs_attr.use_assoc
       && !lhs_attr.proc_pointer)
     {
-      gfc_error ("'%s' in the pointer assignment at %L cannot be an "
+      gfc_error ("%qs in the pointer assignment at %L cannot be an "
                 "l-value since it is a procedure",
                 lvalue->symtree->n.sym->name, &lvalue->where);
       return false;
@@ -3338,13 +3351,13 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
 
          if (ref->u.ar.type != AR_SECTION)
            {
-             gfc_error ("Expected bounds specification for '%s' at %L",
+             gfc_error ("Expected bounds specification for %qs at %L",
                         lvalue->symtree->n.sym->name, &lvalue->where);
              return false;
            }
 
          if (!gfc_notify_std (GFC_STD_F2003, "Bounds specification "
-                              "for '%s' in pointer assignment at %L", 
+                              "for %qs in pointer assignment at %L",
                               lvalue->symtree->n.sym->name, &lvalue->where))
            return false;
 
@@ -3411,7 +3424,7 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
     {
       char err[200];
       gfc_symbol *s1,*s2;
-      gfc_component *comp;
+      gfc_component *comp1, *comp2;
       const char *name;
 
       attr = gfc_expr_attr (rvalue);
@@ -3445,7 +3458,7 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
              for (ns = gfc_current_ns; ns; ns = ns->parent)
                if (sym == ns->proc_name)
                  {
-                   gfc_error ("Function result '%s' is invalid as proc-target "
+                   gfc_error ("Function result %qs is invalid as proc-target "
                               "in procedure pointer assignment at %L",
                               sym->name, &rvalue->where);
                    return false;
@@ -3454,7 +3467,7 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
        }
       if (attr.abstract)
        {
-         gfc_error ("Abstract interface '%s' is invalid "
+         gfc_error ("Abstract interface %qs is invalid "
                     "in procedure pointer assignment at %L",
                     rvalue->symtree->name, &rvalue->where);
          return false;
@@ -3464,20 +3477,20 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
        {
          if (attr.proc == PROC_ST_FUNCTION)
            {
-             gfc_error ("Statement function '%s' is invalid "
+             gfc_error ("Statement function %qs is invalid "
                         "in procedure pointer assignment at %L",
                         rvalue->symtree->name, &rvalue->where);
              return false;
            }
          if (attr.proc == PROC_INTERNAL &&
-             !gfc_notify_std(GFC_STD_F2008, "Internal procedure '%s' "
+             !gfc_notify_std(GFC_STD_F2008, "Internal procedure %qs "
                              "is invalid in procedure pointer assignment "
                              "at %L", rvalue->symtree->name, &rvalue->where))
            return false;
          if (attr.intrinsic && gfc_intrinsic_actual_ok (rvalue->symtree->name,
                                                         attr.subroutine) == 0)
            {
-             gfc_error ("Intrinsic '%s' at %L is invalid in procedure pointer "
+             gfc_error ("Intrinsic %qs at %L is invalid in procedure pointer "
                         "assignment", rvalue->symtree->name, &rvalue->where);
              return false;
            }
@@ -3485,7 +3498,7 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
       /* Check for F08:C730.  */
       if (attr.elemental && !attr.intrinsic)
        {
-         gfc_error ("Nonintrinsic elemental procedure '%s' is invalid "
+         gfc_error ("Nonintrinsic elemental procedure %qs is invalid "
                     "in procedure pointer assignment at %L",
                     rvalue->symtree->name, &rvalue->where);
          return false;
@@ -3515,9 +3528,9 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
            }
        }
 
-      comp = gfc_get_proc_ptr_comp (lvalue);
-      if (comp)
-       s1 = comp->ts.interface;
+      comp1 = gfc_get_proc_ptr_comp (lvalue);
+      if (comp1)
+       s1 = comp1->ts.interface;
       else
        {
          s1 = lvalue->symtree->n.sym;
@@ -3525,23 +3538,27 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
            s1 = s1->ts.interface;
        }
 
-      comp = gfc_get_proc_ptr_comp (rvalue);
-      if (comp)
+      comp2 = gfc_get_proc_ptr_comp (rvalue);
+      if (comp2)
        {
          if (rvalue->expr_type == EXPR_FUNCTION)
            {
-             s2 = comp->ts.interface->result;
+             s2 = comp2->ts.interface->result;
              name = s2->name;
            }
          else
            {
-             s2 = comp->ts.interface;
-             name = comp->name;
+             s2 = comp2->ts.interface;
+             name = comp2->name;
            }
        }
       else if (rvalue->expr_type == EXPR_FUNCTION)
        {
-         s2 = rvalue->symtree->n.sym->result;
+         if (rvalue->value.function.esym)
+           s2 = rvalue->value.function.esym->result;
+         else
+           s2 = rvalue->symtree->n.sym->result;
+
          name = s2->name;
        }
       else
@@ -3553,9 +3570,34 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
       if (s2 && s2->attr.proc_pointer && s2->ts.interface)
        s2 = s2->ts.interface;
 
+      /* Special check for the case of absent interface on the lvalue.
+       * All other interface checks are done below. */
+      if (!s1 && comp1 && comp1->attr.subroutine && s2 && s2->attr.function)
+       {
+         gfc_error ("Interface mismatch in procedure pointer assignment "
+                    "at %L: '%s' is not a subroutine", &rvalue->where, name);
+         return false;
+       }
+
       if (s1 == s2 || !s1 || !s2)
        return true;
 
+      /* F08:7.2.2.4 (4)  */
+      if (s1->attr.if_source == IFSRC_UNKNOWN
+         && gfc_explicit_interface_required (s2, err, sizeof(err)))
+       {
+         gfc_error ("Explicit interface required for %qs at %L: %s",
+                    s1->name, &lvalue->where, err);
+         return false;
+       }
+      if (s2->attr.if_source == IFSRC_UNKNOWN
+         && gfc_explicit_interface_required (s1, err, sizeof(err)))
+       {
+         gfc_error ("Explicit interface required for %qs at %L: %s",
+                    s2->name, &rvalue->where, err);
+         return false;
+       }
+
       if (!gfc_compare_interfaces (s1, s2, name, 0, 1,
                                   err, sizeof(err), NULL, NULL))
        {
@@ -3564,11 +3606,13 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
          return false;
        }
 
-      if (!gfc_compare_interfaces (s2, s1, name, 0, 1,
-                                  err, sizeof(err), NULL, NULL))
+      /* Check F2008Cor2, C729.  */
+      if (!s2->attr.intrinsic && s2->attr.if_source == IFSRC_UNKNOWN
+         && !s2->attr.external && !s2->attr.subroutine && !s2->attr.function)
        {
-         gfc_error ("Interface mismatch in procedure pointer assignment "
-                    "at %L: %s", &rvalue->where, err);
+         gfc_error ("Procedure pointer target %qs at %L must be either an "
+                    "intrinsic, host or use associated, referenced or have "
+                    "the EXTERNAL attribute", s2->name, &rvalue->where);
          return false;
        }
 
@@ -3583,11 +3627,10 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
               || (lvalue->ts.type == BT_DERIVED
                   && (lvalue->ts.u.derived->attr.is_bind_c
                       || lvalue->ts.u.derived->attr.sequence))))
-       gfc_error ("Data-pointer-object &L must be unlimited "
-                  "polymorphic, a sequence derived type or of a "
-                  "type with the BIND attribute assignment at %L "
-                  "to be compatible with an unlimited polymorphic "
-                  "target", &lvalue->where);
+       gfc_error ("Data-pointer-object at %L must be unlimited "
+                  "polymorphic, or of a type with the BIND or SEQUENCE "
+                  "attribute, to be compatible with an unlimited "
+                  "polymorphic target", &lvalue->where);
       else
        gfc_error ("Different types in pointer assignment at %L; "
                   "attempted assignment of %s to %s", &lvalue->where,
@@ -3609,11 +3652,9 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
       return false;
     }
 
-    /* Make sure the vtab is present.  */
-  if (lvalue->ts.type == BT_CLASS && rvalue->ts.type == BT_DERIVED)
-    gfc_find_derived_vtab (rvalue->ts.u.derived);
-  else if (UNLIMITED_POLY (lvalue) && !UNLIMITED_POLY (rvalue))
-    gfc_find_intrinsic_vtab (&rvalue->ts);
+  /* Make sure the vtab is present.  */
+  if (lvalue->ts.type == BT_CLASS && !UNLIMITED_POLY (rvalue))
+    gfc_find_vtab (&rvalue->ts);
 
   /* Check rank remapping.  */
   if (rank_remap)
@@ -3637,7 +3678,7 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
         and F2008 must be allowed.  */
       if (rvalue->rank != 1)
        {
-         if (!gfc_is_simply_contiguous (rvalue, true))
+         if (!gfc_is_simply_contiguous (rvalue, true, false))
            {
              gfc_error ("Rank remapping target must be rank 1 or"
                         " simply contiguous at %L", &rvalue->where);
@@ -3687,8 +3728,7 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
     }
 
   if (is_implicit_pure && gfc_impure_variable (rvalue->symtree->n.sym))
-    gfc_current_ns->proc_name->attr.implicit_pure = 0;
-
+    gfc_unset_implicit_pure (gfc_current_ns->proc_name);
 
   if (gfc_has_vector_index (rvalue))
     {
@@ -3720,7 +3760,7 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
     }
 
   /* Warn if it is the LHS pointer may lives longer than the RHS target.  */
-  if (gfc_option.warn_target_lifetime
+  if (warn_target_lifetime
       && rvalue->expr_type == EXPR_VARIABLE
       && !rvalue->symtree->n.sym->attr.save
       && !attr.pointer && !rvalue->symtree->n.sym->attr.host_assoc
@@ -3747,10 +3787,14 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
            ns && ns->proc_name && ns->proc_name->attr.flavor != FL_PROCEDURE;
            ns = ns->parent)
        if (ns->parent == lvalue->symtree->n.sym->ns)
-         warn = true;
+         {
+           warn = true;
+           break;
+         }
 
       if (warn)
-       gfc_warning ("Pointer at %L in pointer assignment might outlive the "
+       gfc_warning (OPT_Wtarget_lifetime,
+                    "Pointer at %L in pointer assignment might outlive the "
                     "pointer target", &lvalue->where);
     }
 
@@ -3801,9 +3845,20 @@ gfc_check_assign_symbol (gfc_symbol *sym, gfc_component *comp, gfc_expr *rvalue)
   if (pointer || proc_pointer)
     r = gfc_check_pointer_assign (&lvalue, rvalue);
   else
-    r = gfc_check_assign (&lvalue, rvalue, 1);
+    {
+      /* If a conversion function, e.g., __convert_i8_i4, was inserted
+        into an array constructor, we should check if it can be reduced
+        as an initialization expression.  */
+      if (rvalue->expr_type == EXPR_FUNCTION
+         && rvalue->value.function.isym
+         && (rvalue->value.function.isym->conversion == 1))
+       gfc_check_init_expr (rvalue);
+
+      r = gfc_check_assign (&lvalue, rvalue, 1);
+    }
 
   free (lvalue.symtree);
+  free (lvalue.ref);
 
   if (!r)
     return r;
@@ -3858,6 +3913,237 @@ gfc_check_assign_symbol (gfc_symbol *sym, gfc_component *comp, gfc_expr *rvalue)
 }
 
 
+/* Build an initializer for a local integer, real, complex, logical, or
+   character variable, based on the command line flags finit-local-zero,
+   finit-integer=, finit-real=, finit-logical=, and finit-character=.  */
+
+gfc_expr *
+gfc_build_default_init_expr (gfc_typespec *ts, locus *where)
+{
+  int char_len;
+  gfc_expr *init_expr;
+  int i;
+
+  /* Try to build an initializer expression.  */
+  init_expr = gfc_get_constant_expr (ts->type, ts->kind, where);
+
+  /* We will only initialize integers, reals, complex, logicals, and
+     characters, and only if the corresponding command-line flags
+     were set.  Otherwise, we free init_expr and return null.  */
+  switch (ts->type)
+    {
+    case BT_INTEGER:
+      if (gfc_option.flag_init_integer != GFC_INIT_INTEGER_OFF)
+        mpz_set_si (init_expr->value.integer,
+                         gfc_option.flag_init_integer_value);
+      else
+        {
+          gfc_free_expr (init_expr);
+          init_expr = NULL;
+        }
+      break;
+
+    case BT_REAL:
+      switch (flag_init_real)
+        {
+        case GFC_INIT_REAL_SNAN:
+          init_expr->is_snan = 1;
+          /* Fall through.  */
+        case GFC_INIT_REAL_NAN:
+          mpfr_set_nan (init_expr->value.real);
+          break;
+
+        case GFC_INIT_REAL_INF:
+          mpfr_set_inf (init_expr->value.real, 1);
+          break;
+
+        case GFC_INIT_REAL_NEG_INF:
+          mpfr_set_inf (init_expr->value.real, -1);
+          break;
+
+        case GFC_INIT_REAL_ZERO:
+          mpfr_set_ui (init_expr->value.real, 0.0, GFC_RND_MODE);
+          break;
+
+        default:
+          gfc_free_expr (init_expr);
+          init_expr = NULL;
+          break;
+        }
+      break;
+
+    case BT_COMPLEX:
+      switch (flag_init_real)
+        {
+        case GFC_INIT_REAL_SNAN:
+          init_expr->is_snan = 1;
+          /* Fall through.  */
+        case GFC_INIT_REAL_NAN:
+          mpfr_set_nan (mpc_realref (init_expr->value.complex));
+          mpfr_set_nan (mpc_imagref (init_expr->value.complex));
+          break;
+
+        case GFC_INIT_REAL_INF:
+          mpfr_set_inf (mpc_realref (init_expr->value.complex), 1);
+          mpfr_set_inf (mpc_imagref (init_expr->value.complex), 1);
+          break;
+
+        case GFC_INIT_REAL_NEG_INF:
+          mpfr_set_inf (mpc_realref (init_expr->value.complex), -1);
+          mpfr_set_inf (mpc_imagref (init_expr->value.complex), -1);
+          break;
+
+        case GFC_INIT_REAL_ZERO:
+          mpc_set_ui (init_expr->value.complex, 0, GFC_MPC_RND_MODE);
+          break;
+
+        default:
+          gfc_free_expr (init_expr);
+          init_expr = NULL;
+          break;
+        }
+      break;
+
+    case BT_LOGICAL:
+      if (gfc_option.flag_init_logical == GFC_INIT_LOGICAL_FALSE)
+        init_expr->value.logical = 0;
+      else if (gfc_option.flag_init_logical == GFC_INIT_LOGICAL_TRUE)
+        init_expr->value.logical = 1;
+      else
+        {
+          gfc_free_expr (init_expr);
+          init_expr = NULL;
+        }
+      break;
+
+    case BT_CHARACTER:
+      /* For characters, the length must be constant in order to
+         create a default initializer.  */
+      if (gfc_option.flag_init_character == GFC_INIT_CHARACTER_ON
+          && ts->u.cl->length
+          && ts->u.cl->length->expr_type == EXPR_CONSTANT)
+        {
+          char_len = mpz_get_si (ts->u.cl->length->value.integer);
+          init_expr->value.character.length = char_len;
+          init_expr->value.character.string = gfc_get_wide_string (char_len+1);
+          for (i = 0; i < char_len; i++)
+            init_expr->value.character.string[i]
+              = (unsigned char) gfc_option.flag_init_character_value;
+        }
+      else
+        {
+          gfc_free_expr (init_expr);
+          init_expr = NULL;
+        }
+      if (!init_expr && gfc_option.flag_init_character == GFC_INIT_CHARACTER_ON
+          && ts->u.cl->length && flag_max_stack_var_size != 0)
+        {
+          gfc_actual_arglist *arg;
+          init_expr = gfc_get_expr ();
+          init_expr->where = *where;
+          init_expr->ts = *ts;
+          init_expr->expr_type = EXPR_FUNCTION;
+          init_expr->value.function.isym =
+                gfc_intrinsic_function_by_id (GFC_ISYM_REPEAT);
+          init_expr->value.function.name = "repeat";
+          arg = gfc_get_actual_arglist ();
+          arg->expr = gfc_get_character_expr (ts->kind, where, NULL, 1);
+          arg->expr->value.character.string[0] =
+            gfc_option.flag_init_character_value;
+          arg->next = gfc_get_actual_arglist ();
+          arg->next->expr = gfc_copy_expr (ts->u.cl->length);
+          init_expr->value.function.actual = arg;
+        }
+      break;
+
+    default:
+     gfc_free_expr (init_expr);
+     init_expr = NULL;
+    }
+
+  return init_expr;
+}
+
+/* Apply an initialization expression to a typespec. Can be used for symbols or
+   components. Similar to add_init_expr_to_sym in decl.c; could probably be
+   combined with some effort.  */
+
+void
+gfc_apply_init (gfc_typespec *ts, symbol_attribute *attr, gfc_expr *init)
+{
+  if (ts->type == BT_CHARACTER && !attr->pointer && init
+      && ts->u.cl
+      && ts->u.cl->length && ts->u.cl->length->expr_type == EXPR_CONSTANT)
+    {
+      int len;
+
+      gcc_assert (ts->u.cl && ts->u.cl->length);
+      gcc_assert (ts->u.cl->length->expr_type == EXPR_CONSTANT);
+      gcc_assert (ts->u.cl->length->ts.type == BT_INTEGER);
+
+      len = mpz_get_si (ts->u.cl->length->value.integer);
+
+      if (init->expr_type == EXPR_CONSTANT)
+        gfc_set_constant_character_len (len, init, -1);
+      else if (init
+               && init->ts.u.cl
+               && mpz_cmp (ts->u.cl->length->value.integer,
+                           init->ts.u.cl->length->value.integer))
+        {
+          gfc_constructor *ctor;
+          ctor = gfc_constructor_first (init->value.constructor);
+
+          if (ctor)
+            {
+              int first_len;
+              bool has_ts = (init->ts.u.cl
+                             && init->ts.u.cl->length_from_typespec);
+
+              /* Remember the length of the first element for checking
+                 that all elements *in the constructor* have the same
+                 length.  This need not be the length of the LHS!  */
+              gcc_assert (ctor->expr->expr_type == EXPR_CONSTANT);
+              gcc_assert (ctor->expr->ts.type == BT_CHARACTER);
+              first_len = ctor->expr->value.character.length;
+
+              for ( ; ctor; ctor = gfc_constructor_next (ctor))
+                if (ctor->expr->expr_type == EXPR_CONSTANT)
+                {
+                  gfc_set_constant_character_len (len, ctor->expr,
+                                                  has_ts ? -1 : first_len);
+                 if (!ctor->expr->ts.u.cl)
+                   ctor->expr->ts.u.cl
+                     = gfc_new_charlen (gfc_current_ns, ts->u.cl);
+                 else
+                    ctor->expr->ts.u.cl->length
+                     = gfc_copy_expr (ts->u.cl->length);
+                }
+            }
+        }
+    }
+}
+
+
+/* Check whether an expression is a structure constructor and whether it has
+   other values than NULL.  */
+
+bool
+is_non_empty_structure_constructor (gfc_expr * e)
+{
+  if (e->expr_type != EXPR_STRUCTURE)
+    return false;
+
+  gfc_constructor *cons = gfc_constructor_first (e->value.constructor);
+  while (cons)
+    {
+      if (!cons->expr || cons->expr->expr_type != EXPR_NULL)
+       return true;
+      cons = gfc_constructor_next (cons);
+    }
+  return false;
+}
+
+
 /* Check for default initializer; sym->value is not enough
    as it is also set for EXPR_NULL of allocatables.  */
 
@@ -3866,12 +4152,15 @@ gfc_has_default_initializer (gfc_symbol *der)
 {
   gfc_component *c;
 
-  gcc_assert (der->attr.flavor == FL_DERIVED);
+  gcc_assert (gfc_fl_struct (der->attr.flavor));
   for (c = der->components; c; c = c->next)
-    if (c->ts.type == BT_DERIVED)
+    if (gfc_bt_struct (c->ts.type))
       {
-        if (!c->attr.pointer
-            && gfc_has_default_initializer (c->ts.u.derived))
+        if (!c->attr.pointer && !c->attr.proc_pointer
+            && !(c->attr.allocatable && der == c->ts.u.derived)
+            && ((c->initializer
+                 && is_non_empty_structure_constructor (c->initializer))
+                || gfc_has_default_initializer (c->ts.u.derived)))
          return true;
        if (c->attr.pointer && c->initializer)
          return true;
@@ -3886,21 +4175,157 @@ gfc_has_default_initializer (gfc_symbol *der)
 }
 
 
-/* Get an expression for a default initializer.  */
+/*
+   Generate an initializer expression which initializes the entirety of a union.
+   A normal structure constructor is insufficient without undue effort, because
+   components of maps may be oddly aligned/overlapped. (For example if a
+   character is initialized from one map overtop a real from the other, only one
+   byte of the real is actually initialized.)  Unfortunately we don't know the
+   size of the union right now, so we can't generate a proper initializer, but
+   we use a NULL expr as a placeholder and do the right thing later in
+   gfc_trans_subcomponent_assign.
+ */
+static gfc_expr *
+generate_union_initializer (gfc_component *un)
+{
+  if (un == NULL || un->ts.type != BT_UNION)
+    return NULL;
+
+  gfc_expr *placeholder = gfc_get_null_expr (&un->loc);
+  placeholder->ts = un->ts;
+  return placeholder;
+}
+
+
+/* Get the user-specified initializer for a union, if any. This means the user
+   has said to initialize component(s) of a map.  For simplicity's sake we
+   only allow the user to initialize the first map.  We don't have to worry
+   about overlapping initializers as they are released early in resolution (see
+   resolve_fl_struct).   */
+
+static gfc_expr *
+get_union_initializer (gfc_symbol *union_type, gfc_component **map_p)
+{
+  gfc_component *map;
+  gfc_expr *init=NULL;
+
+  if (!union_type || union_type->attr.flavor != FL_UNION)
+    return NULL;
+
+  for (map = union_type->components; map; map = map->next)
+    {
+      if (gfc_has_default_initializer (map->ts.u.derived))
+        {
+          init = gfc_default_initializer (&map->ts);
+          if (map_p)
+            *map_p = map;
+          break;
+        }
+    }
+
+  if (map_p && !init)
+    *map_p = NULL;
+
+  return init;
+}
+
+/* Fetch or generate an initializer for the given component.
+   Only generate an initializer if generate is true.  */
+
+static gfc_expr *
+component_initializer (gfc_typespec *ts, gfc_component *c, bool generate)
+{
+  gfc_expr *init = NULL;
+
+  /* See if we can find the initializer immediately.  */
+  if (c->initializer || !generate
+      || (ts->type == BT_CLASS && !c->attr.allocatable))
+    return c->initializer;
+
+  /* Recursively handle derived type components.  */
+  if (c->ts.type == BT_DERIVED || c->ts.type == BT_CLASS)
+    init = gfc_generate_initializer (&c->ts, true);
+
+  else if (c->ts.type == BT_UNION && c->ts.u.derived->components)
+    {
+      gfc_component *map = NULL;
+      gfc_constructor *ctor;
+      gfc_expr *user_init;
+
+      /* If we don't have a user initializer and we aren't generating one, this
+         union has no initializer.  */
+      user_init = get_union_initializer (c->ts.u.derived, &map);
+      if (!user_init && !generate)
+        return NULL;
+
+      /* Otherwise use a structure constructor.  */
+      init = gfc_get_structure_constructor_expr (c->ts.type, c->ts.kind,
+                                                 &c->loc);
+      init->ts = c->ts;
+
+      /* If we are to generate an initializer for the union, add a constructor
+         which initializes the whole union first.  */
+      if (generate)
+        {
+          ctor = gfc_constructor_get ();
+          ctor->expr = generate_union_initializer (c);
+          gfc_constructor_append (&init->value.constructor, ctor);
+        }
+
+      /* If we found an initializer in one of our maps, apply it.  Note this
+         is applied _after_ the entire-union initializer above if any.  */
+      if (user_init)
+        {
+          ctor = gfc_constructor_get ();
+          ctor->expr = user_init;
+          ctor->n.component = map;
+          gfc_constructor_append (&init->value.constructor, ctor);
+        }
+    }
+
+  /* Treat simple components like locals.  */
+  else
+    {
+      init = gfc_build_default_init_expr (&c->ts, &c->loc);
+      gfc_apply_init (&c->ts, &c->attr, init);
+    }
+
+  return init;
+}
+
+
+/* Get an expression for a default initializer of a derived type.  */
 
 gfc_expr *
 gfc_default_initializer (gfc_typespec *ts)
 {
-  gfc_expr *init;
+  return gfc_generate_initializer (ts, false);
+}
+
+
+/* Get or generate an expression for a default initializer of a derived type.
+   If -finit-derived is specified, generate default initialization expressions
+   for components that lack them when generate is set.  */
+
+gfc_expr *
+gfc_generate_initializer (gfc_typespec *ts, bool generate)
+{
+  gfc_expr *init, *tmp;
   gfc_component *comp;
+  generate = flag_init_derived && generate;
 
   /* See if we have a default initializer in this, but not in nested
-     types (otherwise we could use gfc_has_default_initializer()).  */
-  for (comp = ts->u.derived->components; comp; comp = comp->next)
-    if (comp->initializer || comp->attr.allocatable
-       || (comp->ts.type == BT_CLASS && CLASS_DATA (comp)
-           && CLASS_DATA (comp)->attr.allocatable))
-      break;
+     types (otherwise we could use gfc_has_default_initializer()).
+     We don't need to check if we are going to generate them.  */
+  comp = ts->u.derived->components;
+  if (!generate)
+    {
+      for (; comp; comp = comp->next)
+        if (comp->initializer || comp->attr.allocatable
+            || (comp->ts.type == BT_CLASS && CLASS_DATA (comp)
+                && CLASS_DATA (comp)->attr.allocatable))
+          break;
+    }
 
   if (!comp)
     return NULL;
@@ -3913,11 +4338,19 @@ gfc_default_initializer (gfc_typespec *ts)
     {
       gfc_constructor *ctor = gfc_constructor_get();
 
-      if (comp->initializer)
+      /* Fetch or generate an initializer for the component.  */
+      tmp = component_initializer (ts, comp, generate);
+      if (tmp)
        {
-         ctor->expr = gfc_copy_expr (comp->initializer);
-         if ((comp->ts.type != comp->initializer->ts.type
-              || comp->ts.kind != comp->initializer->ts.kind)
+         /* Save the component ref for STRUCTUREs and UNIONs.  */
+         if (ts->u.derived->attr.flavor == FL_STRUCT
+             || ts->u.derived->attr.flavor == FL_UNION)
+           ctor->n.component = comp;
+
+          /* If the initializer was not generated, we need a copy.  */
+          ctor->expr = comp->initializer ? gfc_copy_expr (tmp) : tmp;
+         if ((comp->ts.type != tmp->ts.type
+              || comp->ts.kind != tmp->ts.kind)
              && !comp->attr.pointer && !comp->attr.proc_pointer)
            gfc_convert_type_warn (ctor->expr, &comp->ts, 2, false);
        }
@@ -3927,6 +4360,7 @@ gfc_default_initializer (gfc_typespec *ts)
        {
          ctor->expr = gfc_get_expr ();
          ctor->expr->expr_type = EXPR_NULL;
+         ctor->expr->where = init->where;
          ctor->expr->ts = comp->ts;
        }
 
@@ -3951,9 +4385,10 @@ gfc_get_variable_expr (gfc_symtree *var)
   e->symtree = var;
   e->ts = var->n.sym->ts;
 
-  if ((var->n.sym->as != NULL && var->n.sym->ts.type != BT_CLASS)
-      || (var->n.sym->ts.type == BT_CLASS && CLASS_DATA (var->n.sym)
-         && CLASS_DATA (var->n.sym)->as))
+  if (var->n.sym->attr.flavor != FL_PROCEDURE
+      && ((var->n.sym->as != NULL && var->n.sym->ts.type != BT_CLASS)
+          || (var->n.sym->ts.type == BT_CLASS && CLASS_DATA (var->n.sym)
+              && CLASS_DATA (var->n.sym)->as)))
     {
       e->rank = var->n.sym->ts.type == BT_CLASS
                ? CLASS_DATA (var->n.sym)->as->rank : var->n.sym->as->rank;
@@ -4000,6 +4435,7 @@ gfc_expr *
 gfc_lval_expr_from_sym (gfc_symbol *sym)
 {
   gfc_expr *lval;
+  gfc_array_spec *as;
   lval = gfc_get_expr ();
   lval->expr_type = EXPR_VARIABLE;
   lval->where = sym->declared_at;
@@ -4007,10 +4443,10 @@ gfc_lval_expr_from_sym (gfc_symbol *sym)
   lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name);
 
   /* It will always be a full array.  */
-  lval->rank = sym->as ? sym->as->rank : 0;
+  as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as;
+  lval->rank = as ? as->rank : 0;
   if (lval->rank)
-    gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ?
-                           CLASS_DATA (sym)->as : sym->as);
+    gfc_add_full_array_ref (lval, as);
   return lval;
 }
 
@@ -4252,6 +4688,40 @@ gfc_is_proc_ptr_comp (gfc_expr *expr)
 }
 
 
+/* Determine if an expression is a function with an allocatable class scalar
+   result.  */
+bool
+gfc_is_alloc_class_scalar_function (gfc_expr *expr)
+{
+  if (expr->expr_type == EXPR_FUNCTION
+      && expr->value.function.esym
+      && expr->value.function.esym->result
+      && expr->value.function.esym->result->ts.type == BT_CLASS
+      && !CLASS_DATA (expr->value.function.esym->result)->attr.dimension
+      && CLASS_DATA (expr->value.function.esym->result)->attr.allocatable)
+    return true;
+
+  return false;
+}
+
+
+/* Determine if an expression is a function with an allocatable class array
+   result.  */
+bool
+gfc_is_alloc_class_array_function (gfc_expr *expr)
+{
+  if (expr->expr_type == EXPR_FUNCTION
+      && expr->value.function.esym
+      && expr->value.function.esym->result
+      && expr->value.function.esym->result->ts.type == BT_CLASS
+      && CLASS_DATA (expr->value.function.esym->result)->attr.dimension
+      && CLASS_DATA (expr->value.function.esym->result)->attr.allocatable)
+    return true;
+
+  return false;
+}
+
+
 /* Walk an expression tree and check each variable encountered for being typed.
    If strict is not set, a top-level variable is tolerated untyped in -std=gnu
    mode as is a basic arithmetic expression using those; this is for things in
@@ -4328,6 +4798,23 @@ gfc_ref_this_image (gfc_ref *ref)
   return true;
 }
 
+gfc_expr *
+gfc_find_stat_co(gfc_expr *e)
+{
+  gfc_ref *ref;
+
+  for (ref = e->ref; ref; ref = ref->next)
+    if (ref->type == REF_ARRAY && ref->u.ar.codimen > 0)
+      return ref->u.ar.stat;
+
+  if (e->value.function.actual->expr)
+    for (ref = e->value.function.actual->expr->ref; ref;
+        ref = ref->next)
+      if (ref->type == REF_ARRAY && ref->u.ar.codimen > 0)
+       return ref->u.ar.stat;
+
+  return NULL;
+}
 
 bool
 gfc_is_coindexed (gfc_expr *e)
@@ -4505,7 +4992,7 @@ gfc_has_ultimate_pointer (gfc_expr *e)
    a "(::1)" is accepted.  */
 
 bool
-gfc_is_simply_contiguous (gfc_expr *expr, bool strict)
+gfc_is_simply_contiguous (gfc_expr *expr, bool strict, bool permit_element)
 {
   bool colon;
   int i;
@@ -4519,13 +5006,13 @@ gfc_is_simply_contiguous (gfc_expr *expr, bool strict)
   else if (expr->expr_type != EXPR_VARIABLE)
     return false;
 
-  if (expr->rank == 0)
+  if (!permit_element && expr->rank == 0)
     return false;
 
   for (ref = expr->ref; ref; ref = ref->next)
     {
       if (ar)
-       return false; /* Array shall be last part-ref. */
+       return false; /* Array shall be last part-ref.  */
 
       if (ref->type == REF_COMPONENT)
        part_ref  = ref;
@@ -4640,6 +5127,7 @@ gfc_build_intrinsic_call (gfc_namespace *ns, gfc_isym_id id, const char* name,
   result->symtree->n.sym->intmod_sym_id = id;
   result->symtree->n.sym->attr.flavor = FL_PROCEDURE;
   result->symtree->n.sym->attr.intrinsic = 1;
+  result->symtree->n.sym->attr.artificial = 1;
 
   va_start (ap, numarg);
   atail = NULL;
@@ -4679,9 +5167,9 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, bool alloc_obj,
   bool is_pointer;
   bool check_intentin;
   bool ptr_component;
-  bool unlimited;
   symbol_attribute attr;
   gfc_ref* ref;
+  int i;
 
   if (e->expr_type == EXPR_VARIABLE)
     {
@@ -4694,8 +5182,6 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, bool alloc_obj,
       sym = e->value.function.esym ? e->value.function.esym : e->symtree->n.sym;
     }
 
-  unlimited = e->ts.type == BT_CLASS && UNLIMITED_POLY (sym);
-
   attr = gfc_expr_attr (e);
   if (!pointer && e->expr_type == EXPR_FUNCTION && attr.pointer)
     {
@@ -4718,7 +5204,7 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, bool alloc_obj,
   if (!pointer && sym->attr.flavor == FL_PARAMETER)
     {
       if (context)
-       gfc_error ("Named constant '%s' in variable definition context (%s)"
+       gfc_error ("Named constant %qs in variable definition context (%s)"
                   " at %L", sym->name, context, &e->where);
       return false;
     }
@@ -4727,7 +5213,7 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, bool alloc_obj,
       && !(sym->attr.flavor == FL_PROCEDURE && sym->attr.proc_pointer))
     {
       if (context)
-       gfc_error ("'%s' in variable definition context (%s) at %L is not"
+       gfc_error ("%qs in variable definition context (%s) at %L is not"
                   " a variable", sym->name, context, &e->where);
       return false;
     }
@@ -4735,7 +5221,7 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, bool alloc_obj,
   /* Find out whether the expr is a pointer; this also means following
      component references to the last one.  */
   is_pointer = (attr.pointer || attr.proc_pointer);
-  if (pointer && !is_pointer && !unlimited)
+  if (pointer && !is_pointer)
     {
       if (context)
        gfc_error ("Non-POINTER in pointer association context (%s)"
@@ -4743,6 +5229,15 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, bool alloc_obj,
       return false;
     }
 
+  if (e->ts.type == BT_DERIVED
+      && e->ts.u.derived == NULL)
+    {
+      if (context)
+       gfc_error ("Type inaccessible in variable definition context (%s) "
+                  "at %L", context, &e->where);
+      return false;
+    }
+
   /* F2008, C1303.  */
   if (!alloc_obj
       && (attr.lock_comp
@@ -4756,13 +5251,27 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, bool alloc_obj,
       return false;
     }
 
+  /* TS18508, C702/C203.  */
+  if (!alloc_obj
+      && (attr.lock_comp
+         || (e->ts.type == BT_DERIVED
+             && e->ts.u.derived->from_intmod == INTMOD_ISO_FORTRAN_ENV
+             && e->ts.u.derived->intmod_sym_id == ISOFORTRAN_EVENT_TYPE)))
+    {
+      if (context)
+       gfc_error ("LOCK_EVENT in variable definition context (%s) at %L",
+                  context, &e->where);
+      return false;
+    }
+
   /* INTENT(IN) dummy argument.  Check this, unless the object itself is the
      component of sub-component of a pointer; we need to distinguish
      assignment to a pointer component from pointer-assignment to a pointer
      component.  Note that (normal) assignment to procedure pointers is not
      possible.  */
   check_intentin = !own_scope;
-  ptr_component = (sym->ts.type == BT_CLASS && CLASS_DATA (sym))
+  ptr_component = (sym->ts.type == BT_CLASS && sym->ts.u.derived
+                  && CLASS_DATA (sym))
                  ? CLASS_DATA (sym)->attr.class_pointer : sym->attr.pointer;
   for (ref = e->ref; ref && check_intentin; ref = ref->next)
     {
@@ -4780,7 +5289,7 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, bool alloc_obj,
       if (pointer && is_pointer)
        {
          if (context)
-           gfc_error ("Dummy argument '%s' with INTENT(IN) in pointer"
+           gfc_error ("Dummy argument %qs with INTENT(IN) in pointer"
                       " association context (%s) at %L",
                       sym->name, context, &e->where);
          return false;
@@ -4788,7 +5297,7 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, bool alloc_obj,
       if (!pointer && !is_pointer && !sym->attr.pointer)
        {
          if (context)
-           gfc_error ("Dummy argument '%s' with INTENT(IN) in variable"
+           gfc_error ("Dummy argument %qs with INTENT(IN) in variable"
                       " definition context (%s) at %L",
                       sym->name, context, &e->where);
          return false;
@@ -4801,7 +5310,7 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, bool alloc_obj,
       if (pointer && is_pointer)
        {
          if (context)
-           gfc_error ("Variable '%s' is PROTECTED and can not appear in a"
+           gfc_error ("Variable %qs is PROTECTED and can not appear in a"
                       " pointer association context (%s) at %L",
                       sym->name, context, &e->where);
          return false;
@@ -4809,7 +5318,7 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, bool alloc_obj,
       if (!pointer && !is_pointer)
        {
          if (context)
-           gfc_error ("Variable '%s' is PROTECTED and can not appear in a"
+           gfc_error ("Variable %qs is PROTECTED and can not appear in a"
                       " variable definition context (%s) at %L",
                       sym->name, context, &e->where);
          return false;
@@ -4821,7 +5330,7 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, bool alloc_obj,
   if (!pointer && !own_scope && gfc_pure (NULL) && gfc_impure_variable (sym))
     {
       if (context)
-       gfc_error ("Variable '%s' can not appear in a variable definition"
+       gfc_error ("Variable %qs can not appear in a variable definition"
                   " context (%s) at %L in PURE procedure",
                   sym->name, context, &e->where);
       return false;
@@ -4880,11 +5389,11 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, bool alloc_obj,
          if (context)
            {
              if (assoc->target->expr_type == EXPR_VARIABLE)
-               gfc_error ("'%s' at %L associated to vector-indexed target can"
+               gfc_error ("%qs at %L associated to vector-indexed target can"
                           " not be used in a variable definition context (%s)",
                           name, &e->where, context);
              else
-               gfc_error ("'%s' at %L associated to expression can"
+               gfc_error ("%qs at %L associated to expression can"
                           " not be used in a variable definition context (%s)",
                           name, &e->where, context);
            }
@@ -4895,7 +5404,7 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, bool alloc_obj,
       if (!gfc_check_vardef_context (assoc->target, pointer, false, false, NULL))
        {
          if (context)
-           gfc_error ("Associate-name '%s' can not appear in a variable"
+           gfc_error ("Associate-name %qs can not appear in a variable"
                       " definition context (%s) at %L because its target"
                       " at %L can not, either",
                       name, context, &e->where,
@@ -4904,5 +5413,51 @@ gfc_check_vardef_context (gfc_expr* e, bool pointer, bool alloc_obj,
        }
     }
 
+  /* Check for same value in vector expression subscript.  */
+
+  if (e->rank > 0)
+    for (ref = e->ref; ref != NULL; ref = ref->next)
+      if (ref->type == REF_ARRAY && ref->u.ar.type == AR_SECTION)
+       for (i = 0; i < GFC_MAX_DIMENSIONS
+              && ref->u.ar.dimen_type[i] != 0; i++)
+         if (ref->u.ar.dimen_type[i] == DIMEN_VECTOR)
+           {
+             gfc_expr *arr = ref->u.ar.start[i];
+             if (arr->expr_type == EXPR_ARRAY)
+               {
+                 gfc_constructor *c, *n;
+                 gfc_expr *ec, *en;
+
+                 for (c = gfc_constructor_first (arr->value.constructor);
+                      c != NULL; c = gfc_constructor_next (c))
+                   {
+                     if (c == NULL || c->iterator != NULL)
+                       continue;
+
+                     ec = c->expr;
+
+                     for (n = gfc_constructor_next (c); n != NULL;
+                          n = gfc_constructor_next (n))
+                       {
+                         if (n->iterator != NULL)
+                           continue;
+
+                         en = n->expr;
+                         if (gfc_dep_compare_expr (ec, en) == 0)
+                           {
+                             if (context)
+                               gfc_error_now ("Elements with the same value "
+                                              "at %L and %L in vector "
+                                              "subscript in a variable "
+                                              "definition context (%s)",
+                                              &(ec->where), &(en->where),
+                                              context);
+                             return false;
+                           }
+                       }
+                   }
+               }
+           }
+
   return true;
 }