OSDN Git Service

2010-06-26 Tobias Burnus <burnus@net-b.de>
[pf3gnuchains/gcc-fork.git] / gcc / fortran / decl.c
index 67ccfda..07c3acb 100644 (file)
@@ -1,5 +1,5 @@
 /* Declaration statement matcher
-   Copyright (C) 2002, 2004, 2005, 2006, 2007, 2008, 2009
+   Copyright (C) 2002, 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
    Contributed by Andy Vaught
 
@@ -25,7 +25,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "match.h"
 #include "parse.h"
 #include "flags.h"
-
+#include "constructor.h"
 
 /* Macros to access allocate memory for gfc_data_variable,
    gfc_data_value and gfc_data.  */
@@ -570,6 +570,62 @@ cleanup:
 
 /************************ Declaration statements *********************/
 
+
+/* Auxilliary function to merge DIMENSION and CODIMENSION array specs.  */
+
+static void
+merge_array_spec (gfc_array_spec *from, gfc_array_spec *to, bool copy)
+{
+  int i;
+
+  if (to->rank == 0 && from->rank > 0)
+    {
+      to->rank = from->rank;
+      to->type = from->type;
+      to->cray_pointee = from->cray_pointee;
+      to->cp_was_assumed = from->cp_was_assumed;
+
+      for (i = 0; i < to->corank; i++)
+       {
+         to->lower[from->rank + i] = to->lower[i];
+         to->upper[from->rank + i] = to->upper[i];
+       }
+      for (i = 0; i < from->rank; i++)
+       {
+         if (copy)
+           {
+             to->lower[i] = gfc_copy_expr (from->lower[i]);
+             to->upper[i] = gfc_copy_expr (from->upper[i]);
+           }
+         else
+           {
+             to->lower[i] = from->lower[i];
+             to->upper[i] = from->upper[i];
+           }
+       }
+    }
+  else if (to->corank == 0 && from->corank > 0)
+    {
+      to->corank = from->corank;
+      to->cotype = from->cotype;
+
+      for (i = 0; i < from->corank; i++)
+       {
+         if (copy)
+           {
+             to->lower[to->rank + i] = gfc_copy_expr (from->lower[i]);
+             to->upper[to->rank + i] = gfc_copy_expr (from->upper[i]);
+           }
+         else
+           {
+             to->lower[to->rank + i] = from->lower[i];
+             to->upper[to->rank + i] = from->upper[i];
+           }
+       }
+    }
+}
+
+
 /* Match an intent specification.  Since this can only happen after an
    INTENT word, a legal intent-spec must follow.  */
 
@@ -622,8 +678,8 @@ char_len_param_value (gfc_expr **expr)
              if (e->symtree->n.sym->ts.type == BT_UNKNOWN)
                goto syntax;
              if (e->symtree->n.sym->ts.type == BT_CHARACTER
-                 && e->symtree->n.sym->ts.cl
-                 && e->symtree->n.sym->ts.cl->length->ts.type == BT_UNKNOWN)
+                 && e->symtree->n.sym->ts.u.cl
+                 && e->symtree->n.sym->ts.u.cl->length->ts.type == BT_UNKNOWN)
                goto syntax;
            }
        }
@@ -658,7 +714,7 @@ match_char_length (gfc_expr **expr)
       if (gfc_notify_std (GFC_STD_F95_OBS, "Obsolescent feature: "
                          "Old-style character length at %C") == FAILURE)
        return MATCH_ERROR;
-      *expr = gfc_int_expr (length);
+      *expr = gfc_get_int_expr (gfc_default_integer_kind, NULL, length);
       return m;
     }
 
@@ -938,7 +994,7 @@ verify_c_interop_param (gfc_symbol *sym)
                           "because derived type '%s' is not C interoperable",
                           sym->name, &(sym->declared_at),
                           sym->ns->proc_name->name, 
-                          sym->ts.derived->name);
+                          sym->ts.u.derived->name);
              else
                gfc_warning ("Variable '%s' at %L is a parameter to the "
                             "BIND(C) procedure '%s' but may not be C "
@@ -951,7 +1007,7 @@ verify_c_interop_param (gfc_symbol *sym)
              length of 1.  */
           if (sym->ts.type == BT_CHARACTER)
            {
-             gfc_charlen *cl = sym->ts.cl;
+             gfc_charlen *cl = sym->ts.u.cl;
              if (!cl || !cl->length || cl->length->expr_type != EXPR_CONSTANT
                   || mpz_cmp_si (cl->length->value.integer, 1) != 0)
                {
@@ -1025,6 +1081,7 @@ verify_c_interop_param (gfc_symbol *sym)
 }
 
 
+
 /* Function called by variable_decl() that adds a name to the symbol table.  */
 
 static gfc_try
@@ -1045,7 +1102,7 @@ build_sym (const char *name, gfc_charlen *cl,
     return FAILURE;
 
   if (sym->ts.type == BT_CHARACTER)
-    sym->ts.cl = cl;
+    sym->ts.u.cl = cl;
 
   /* Add dimension attribute if present.  */
   if (gfc_set_array_spec (sym, *as, var_locus) == FAILURE)
@@ -1056,6 +1113,7 @@ build_sym (const char *name, gfc_charlen *cl,
      dimension attribute.  */
   attr = current_attr;
   attr.dimension = 0;
+  attr.codimension = 0;
 
   if (gfc_copy_attr (&sym->attr, &attr, var_locus) == FAILURE)
     return FAILURE;
@@ -1097,6 +1155,14 @@ build_sym (const char *name, gfc_charlen *cl,
 
   sym->attr.implied_index = 0;
 
+  if (sym->ts.type == BT_CLASS)
+    {
+      sym->attr.class_ok = (sym->attr.dummy
+                             || sym->attr.pointer
+                             || sym->attr.allocatable) ? 1 : 0;
+      gfc_build_class_symbol (&sym->ts, &sym->attr, &sym->as, false);
+    }
+
   return SUCCESS;
 }
 
@@ -1250,58 +1316,66 @@ add_init_expr_to_sym (const char *name, gfc_expr **initp, locus *var_locus)
       /* Check if the assignment can happen. This has to be put off
         until later for a derived type variable.  */
       if (sym->ts.type != BT_DERIVED && init->ts.type != BT_DERIVED
+         && sym->ts.type != BT_CLASS && init->ts.type != BT_CLASS
          && gfc_check_assign_symbol (sym, init) == FAILURE)
        return FAILURE;
 
-      if (sym->ts.type == BT_CHARACTER && sym->ts.cl
+      if (sym->ts.type == BT_CHARACTER && sym->ts.u.cl
            && init->ts.type == BT_CHARACTER)
        {
          /* Update symbol character length according initializer.  */
          if (gfc_check_assign_symbol (sym, init) == FAILURE)
            return FAILURE;
 
-         if (sym->ts.cl->length == NULL)
+         if (sym->ts.u.cl->length == NULL)
            {
              int clen;
              /* If there are multiple CHARACTER variables declared on the
                 same line, we don't want them to share the same length.  */
-             sym->ts.cl = gfc_new_charlen (gfc_current_ns);
+             sym->ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL);
 
              if (sym->attr.flavor == FL_PARAMETER)
                {
                  if (init->expr_type == EXPR_CONSTANT)
                    {
                      clen = init->value.character.length;
-                     sym->ts.cl->length = gfc_int_expr (clen);
+                     sym->ts.u.cl->length
+                               = gfc_get_int_expr (gfc_default_integer_kind,
+                                                   NULL, clen);
                    }
                  else if (init->expr_type == EXPR_ARRAY)
                    {
-                     gfc_expr *p = init->value.constructor->expr;
-                     clen = p->value.character.length;
-                     sym->ts.cl->length = gfc_int_expr (clen);
+                     gfc_constructor *c;
+                     c = gfc_constructor_first (init->value.constructor);
+                     clen = c->expr->value.character.length;
+                     sym->ts.u.cl->length
+                               = gfc_get_int_expr (gfc_default_integer_kind,
+                                                   NULL, clen);
                    }
-                 else if (init->ts.cl && init->ts.cl->length)
-                   sym->ts.cl->length =
-                               gfc_copy_expr (sym->value->ts.cl->length);
+                 else if (init->ts.u.cl && init->ts.u.cl->length)
+                   sym->ts.u.cl->length =
+                               gfc_copy_expr (sym->value->ts.u.cl->length);
                }
            }
          /* Update initializer character length according symbol.  */
-         else if (sym->ts.cl->length->expr_type == EXPR_CONSTANT)
+         else if (sym->ts.u.cl->length->expr_type == EXPR_CONSTANT)
            {
-             int len = mpz_get_si (sym->ts.cl->length->value.integer);
-             gfc_constructor * p;
+             int len = mpz_get_si (sym->ts.u.cl->length->value.integer);
 
              if (init->expr_type == EXPR_CONSTANT)
                gfc_set_constant_character_len (len, init, -1);
              else if (init->expr_type == EXPR_ARRAY)
                {
+                 gfc_constructor *c;
+
                  /* Build a new charlen to prevent simplification from
                     deleting the length before it is resolved.  */
-                 init->ts.cl = gfc_new_charlen (gfc_current_ns);
-                 init->ts.cl->length = gfc_copy_expr (sym->ts.cl->length);
+                 init->ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL);
+                 init->ts.u.cl->length = gfc_copy_expr (sym->ts.u.cl->length);
 
-                 for (p = init->value.constructor; p; p = p->next)
-                   gfc_set_constant_character_len (len, p->expr, -1);
+                 for (c = gfc_constructor_first (init->value.constructor);
+                      c; c = gfc_constructor_next (c))
+                   gfc_set_constant_character_len (len, c->expr, -1);
                }
            }
        }
@@ -1325,38 +1399,27 @@ add_init_expr_to_sym (const char *name, gfc_expr **initp, locus *var_locus)
          if (init->ts.is_iso_c)
            sym->ts.f90_type = init->ts.f90_type;
        }
-      
+
       /* Add initializer.  Make sure we keep the ranks sane.  */
       if (sym->attr.dimension && init->rank == 0)
        {
          mpz_t size;
          gfc_expr *array;
-         gfc_constructor *c;
          int n;
          if (sym->attr.flavor == FL_PARAMETER
                && init->expr_type == EXPR_CONSTANT
                && spec_size (sym->as, &size) == SUCCESS
                && mpz_cmp_si (size, 0) > 0)
            {
-             array = gfc_start_constructor (init->ts.type, init->ts.kind,
-                                            &init->where);
-
-             array->value.constructor = c = NULL;
+             array = gfc_get_array_expr (init->ts.type, init->ts.kind,
+                                         &init->where);
              for (n = 0; n < (int)mpz_get_si (size); n++)
-               {
-                 if (array->value.constructor == NULL)
-                   {
-                     array->value.constructor = c = gfc_get_constructor ();
-                     c->expr = init;
-                   }
-                 else
-                   {
-                     c->next = gfc_get_constructor ();
-                     c = c->next;
-                     c->expr = gfc_copy_expr (init);
-                   }
-               }
-
+               gfc_constructor_append_expr (&array->value.constructor,
+                                            n == 0
+                                               ? init
+                                               : gfc_copy_expr (init),
+                                            &init->where);
+               
              array->shape = gfc_get_shape (sym->as->rank);
              for (n = 0; n < sym->as->rank; n++)
                spec_dimen_size (sym->as, n, &array->shape[n]);
@@ -1385,11 +1448,12 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init,
              gfc_array_spec **as)
 {
   gfc_component *c;
+  gfc_try t = SUCCESS;
 
-  /* If the current symbol is of the same derived type that we're
+  /* F03:C438/C439. If the current symbol is of the same derived type that we're
      constructing, it must have the pointer attribute.  */
-  if (current_ts.type == BT_DERIVED
-      && current_ts.derived == gfc_current_block ()
+  if ((current_ts.type == BT_DERIVED || current_ts.type == BT_CLASS)
+      && current_ts.u.derived == gfc_current_block ()
       && current_attr.pointer == 0)
     {
       gfc_error ("Component at %C must have the POINTER attribute");
@@ -1410,7 +1474,8 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init,
     return FAILURE;
 
   c->ts = current_ts;
-  c->ts.cl = cl;
+  if (c->ts.type == BT_CHARACTER)
+    c->ts.u.cl = cl;
   c->attr = current_attr;
 
   c->initializer = *init;
@@ -1418,36 +1483,40 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init,
 
   c->as = *as;
   if (c->as != NULL)
-    c->attr.dimension = 1;
+    {
+      if (c->as->corank)
+       c->attr.codimension = 1;
+      if (c->as->rank)
+       c->attr.dimension = 1;
+    }
   *as = NULL;
 
   /* Should this ever get more complicated, combine with similar section
      in add_init_expr_to_sym into a separate function.  */
-  if (c->ts.type == BT_CHARACTER && !c->attr.pointer && c->initializer && c->ts.cl
-      && c->ts.cl->length && c->ts.cl->length->expr_type == EXPR_CONSTANT)
+  if (c->ts.type == BT_CHARACTER && !c->attr.pointer && c->initializer && c->ts.u.cl
+      && c->ts.u.cl->length && c->ts.u.cl->length->expr_type == EXPR_CONSTANT)
     {
       int len;
 
-      gcc_assert (c->ts.cl && c->ts.cl->length);
-      gcc_assert (c->ts.cl->length->expr_type == EXPR_CONSTANT);
-      gcc_assert (c->ts.cl->length->ts.type == BT_INTEGER);
+      gcc_assert (c->ts.u.cl && c->ts.u.cl->length);
+      gcc_assert (c->ts.u.cl->length->expr_type == EXPR_CONSTANT);
+      gcc_assert (c->ts.u.cl->length->ts.type == BT_INTEGER);
 
-      len = mpz_get_si (c->ts.cl->length->value.integer);
+      len = mpz_get_si (c->ts.u.cl->length->value.integer);
 
       if (c->initializer->expr_type == EXPR_CONSTANT)
        gfc_set_constant_character_len (len, c->initializer, -1);
-      else if (mpz_cmp (c->ts.cl->length->value.integer,
-                       c->initializer->ts.cl->length->value.integer))
+      else if (mpz_cmp (c->ts.u.cl->length->value.integer,
+                       c->initializer->ts.u.cl->length->value.integer))
        {
-         bool has_ts;
-         gfc_constructor *ctor = c->initializer->value.constructor;
-
-         has_ts = (c->initializer->ts.cl
-                   && c->initializer->ts.cl->length_from_typespec);
+         gfc_constructor *ctor;
+         ctor = gfc_constructor_first (c->initializer->value.constructor);
 
          if (ctor)
            {
              int first_len;
+             bool has_ts = (c->initializer->ts.u.cl
+                            && c->initializer->ts.u.cl->length_from_typespec);
 
              /* Remember the length of the first element for checking
                 that all elements *in the constructor* have the same
@@ -1456,11 +1525,12 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init,
              gcc_assert (ctor->expr->ts.type == BT_CHARACTER);
              first_len = ctor->expr->value.character.length;
 
-             for (; ctor; ctor = ctor->next)
+             for ( ; ctor; ctor = gfc_constructor_next (ctor))
+               if (ctor->expr->expr_type == EXPR_CONSTANT)
                {
-                 if (ctor->expr->expr_type == EXPR_CONSTANT)
-                   gfc_set_constant_character_len (len, ctor->expr,
-                                                   has_ts ? -1 : first_len);
+                 gfc_set_constant_character_len (len, ctor->expr,
+                                                 has_ts ? -1 : first_len);
+                 ctor->expr->ts.u.cl->length = gfc_copy_expr (c->ts.u.cl->length);
                }
            }
        }
@@ -1468,15 +1538,7 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init,
 
   /* Check array components.  */
   if (!c->attr.dimension)
-    {
-      if (c->attr.allocatable)
-       {
-         gfc_error ("Allocatable component at %C must be an array");
-         return FAILURE;
-       }
-      else
-       return SUCCESS;
-    }
+    goto scalar;
 
   if (c->attr.pointer)
     {
@@ -1484,7 +1546,7 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init,
        {
          gfc_error ("Pointer array component of structure at %C must have a "
                     "deferred shape");
-         return FAILURE;
+         t = FAILURE;
        }
     }
   else if (c->attr.allocatable)
@@ -1493,7 +1555,7 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init,
        {
          gfc_error ("Allocatable component of structure at %C must have a "
                     "deferred shape");
-         return FAILURE;
+         t = FAILURE;
        }
     }
   else
@@ -1502,11 +1564,15 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init,
        {
          gfc_error ("Array component of structure at %C must have an "
                     "explicit shape");
-         return FAILURE;
+         t = FAILURE;
        }
     }
 
-  return SUCCESS;
+scalar:
+  if (c->ts.type == BT_CLASS)
+    gfc_build_class_symbol (&c->ts, &c->attr, &c->as, true);
+
+  return t;
 }
 
 
@@ -1516,7 +1582,6 @@ match
 gfc_match_null (gfc_expr **result)
 {
   gfc_symbol *sym;
-  gfc_expr *e;
   match m;
 
   m = gfc_match (" null ( )");
@@ -1538,12 +1603,7 @@ gfc_match_null (gfc_expr **result)
          || gfc_add_function (&sym->attr, sym->name, NULL) == FAILURE))
     return MATCH_ERROR;
 
-  e = gfc_get_expr ();
-  e->where = gfc_current_locus;
-  e->expr_type = EXPR_NULL;
-  e->ts.type = BT_UNKNOWN;
-
-  *result = e;
+  *result = gfc_get_null_expr (&gfc_current_locus);
 
   return MATCH_YES;
 }
@@ -1566,12 +1626,10 @@ variable_decl (int elem)
   match m;
   gfc_try t;
   gfc_symbol *sym;
-  locus old_locus;
 
   initializer = NULL;
   as = NULL;
   cp_as = NULL;
-  old_locus = gfc_current_locus;
 
   /* When we get here, we've just matched a list of attributes and
      maybe a type and a double colon.  The next thing we expect to see
@@ -1583,7 +1641,7 @@ variable_decl (int elem)
   var_locus = gfc_current_locus;
 
   /* Now we could see the optional array spec. or character length.  */
-  m = gfc_match_array_spec (&as);
+  m = gfc_match_array_spec (&as, true, true);
   if (gfc_option.flag_cray_pointer && m == MATCH_YES)
     cp_as = gfc_copy_array_spec (as);
   else if (m == MATCH_ERROR)
@@ -1591,6 +1649,8 @@ variable_decl (int elem)
 
   if (m == MATCH_NO)
     as = gfc_copy_array_spec (current_as);
+  else if (current_as)
+    merge_array_spec (current_as, as, true);
 
   char_len = NULL;
   cl = NULL;
@@ -1600,7 +1660,7 @@ variable_decl (int elem)
       switch (match_char_length (&char_len))
        {
        case MATCH_YES:
-         cl = gfc_new_charlen (gfc_current_ns);
+         cl = gfc_new_charlen (gfc_current_ns, NULL);
 
          cl->length = char_len;
          break;
@@ -1609,14 +1669,14 @@ variable_decl (int elem)
           element.  Also copy assumed lengths.  */
        case MATCH_NO:
          if (elem > 1
-             && (current_ts.cl->length == NULL
-                 || current_ts.cl->length->expr_type != EXPR_CONSTANT))
+             && (current_ts.u.cl->length == NULL
+                 || current_ts.u.cl->length->expr_type != EXPR_CONSTANT))
            {
-             cl = gfc_new_charlen (gfc_current_ns);
-             cl->length = gfc_copy_expr (current_ts.cl->length);
+             cl = gfc_new_charlen (gfc_current_ns, NULL);
+             cl->length = gfc_copy_expr (current_ts.u.cl->length);
            }
          else
-           cl = current_ts.cl;
+           cl = current_ts.u.cl;
 
          break;
 
@@ -1634,8 +1694,8 @@ variable_decl (int elem)
        {
          sym->ts.type = current_ts.type;
          sym->ts.kind = current_ts.kind;
-         sym->ts.cl = cl;
-         sym->ts.derived = current_ts.derived;
+         sym->ts.u.cl = cl;
+         sym->ts.u.derived = current_ts.u.derived;
          sym->ts.is_c_interop = current_ts.is_c_interop;
          sym->ts.is_iso_c = current_ts.is_iso_c;
          m = MATCH_YES;
@@ -1704,16 +1764,16 @@ variable_decl (int elem)
      specified in the procedure definition, except that the interface
      may specify a procedure that is not pure if the procedure is
      defined to be pure(12.3.2).  */
-  if (current_ts.type == BT_DERIVED
+  if ((current_ts.type == BT_DERIVED || current_ts.type == BT_CLASS)
       && gfc_current_ns->proc_name
       && gfc_current_ns->proc_name->attr.if_source == IFSRC_IFBODY
-      && current_ts.derived->ns != gfc_current_ns)
+      && current_ts.u.derived->ns != gfc_current_ns)
     {
       gfc_symtree *st;
-      st = gfc_find_symtree (gfc_current_ns->sym_root, current_ts.derived->name);
-      if (!(current_ts.derived->attr.imported
+      st = gfc_find_symtree (gfc_current_ns->sym_root, current_ts.u.derived->name);
+      if (!(current_ts.u.derived->attr.imported
                && st != NULL
-               && st->n.sym == current_ts.derived)
+               && st->n.sym == current_ts.u.derived)
            && !gfc_current_ns->has_import_set)
        {
            gfc_error ("the type of '%s' at %C has not been declared within the "
@@ -1775,7 +1835,7 @@ variable_decl (int elem)
              m = MATCH_ERROR;
            }
 
-         if (gfc_pure (NULL))
+         if (gfc_pure (NULL) && gfc_state_stack->state != COMP_DERIVED)
            {
              gfc_error ("Initialization of pointer at %C is not allowed in "
                         "a PURE procedure");
@@ -1803,7 +1863,8 @@ variable_decl (int elem)
              m = MATCH_ERROR;
            }
 
-         if (current_attr.flavor != FL_PARAMETER && gfc_pure (NULL))
+         if (current_attr.flavor != FL_PARAMETER && gfc_pure (NULL)
+             && gfc_state_stack->state != COMP_DERIVED)
            {
              gfc_error ("Initialization of variable at %C is not allowed in "
                         "a PURE procedure");
@@ -2103,11 +2164,12 @@ no_match:
   return m;
 }
 
+
 /* Match the various kind/length specifications in a CHARACTER
    declaration.  We don't return MATCH_NO.  */
 
-static match
-match_char_spec (gfc_typespec *ts)
+match
+gfc_match_char_spec (gfc_typespec *ts)
 {
   int kind, seen_length, is_iso_c;
   gfc_charlen *cl;
@@ -2234,14 +2296,14 @@ done:
     }
 
   /* Do some final massaging of the length values.  */
-  cl = gfc_new_charlen (gfc_current_ns);
+  cl = gfc_new_charlen (gfc_current_ns, NULL);
 
   if (seen_length == 0)
-    cl->length = gfc_int_expr (1);
+    cl->length = gfc_get_int_expr (gfc_default_integer_kind, NULL, 1);
   else
     cl->length = len;
 
-  ts->cl = cl;
+  ts->u.cl = cl;
   ts->kind = kind == 0 ? gfc_default_character_kind : kind;
 
   /* We have to know if it was a c interoperable kind so we can
@@ -2265,8 +2327,8 @@ done:
 }
 
 
-/* Matches a type specification.  If successful, sets the ts structure
-   to the matched specification.  This is necessary for FUNCTION and
+/* Matches a declaration-type-spec (F03:R502).  If successful, sets the ts
+   structure to the matched specification.  This is necessary for FUNCTION and
    IMPLICIT statements.
 
    If implicit_flag is nonzero, then we don't check for the optional
@@ -2274,13 +2336,13 @@ done:
    statement correctly.  */
 
 match
-gfc_match_type_spec (gfc_typespec *ts, int implicit_flag)
+gfc_match_decl_type_spec (gfc_typespec *ts, int implicit_flag)
 {
   char name[GFC_MAX_SYMBOL_LEN + 1];
   gfc_symbol *sym;
   match m;
   char c;
-  bool seen_deferred_kind;
+  bool seen_deferred_kind, matched_type;
 
   /* A belt and braces check that the typespec is correctly being treated
      as a deferred characteristic association.  */
@@ -2296,7 +2358,7 @@ gfc_match_type_spec (gfc_typespec *ts, int implicit_flag)
 
   if (gfc_match (" byte") == MATCH_YES)
     {
-      if (gfc_notify_std(GFC_STD_GNU, "Extension: BYTE type at %C")
+      if (gfc_notify_std (GFC_STD_GNU, "Extension: BYTE type at %C")
          == FAILURE)
        return MATCH_ERROR;
 
@@ -2312,47 +2374,88 @@ gfc_match_type_spec (gfc_typespec *ts, int implicit_flag)
       return MATCH_YES;
     }
 
-  if (gfc_match (" integer") == MATCH_YES)
+
+  m = gfc_match (" type ( %n", name);
+  matched_type = (m == MATCH_YES);
+  
+  if ((matched_type && strcmp ("integer", name) == 0)
+      || (!matched_type && gfc_match (" integer") == MATCH_YES))
     {
       ts->type = BT_INTEGER;
       ts->kind = gfc_default_integer_kind;
       goto get_kind;
     }
 
-  if (gfc_match (" character") == MATCH_YES)
+  if ((matched_type && strcmp ("character", name) == 0)
+      || (!matched_type && gfc_match (" character") == MATCH_YES))
     {
+      if (matched_type
+         && gfc_notify_std (GFC_STD_F2008, "Fortran 2008: TYPE with "
+                         "intrinsic-type-spec at %C") == FAILURE)
+       return MATCH_ERROR;
+
       ts->type = BT_CHARACTER;
       if (implicit_flag == 0)
-       return match_char_spec (ts);
+       m = gfc_match_char_spec (ts);
       else
-       return MATCH_YES;
+       m = MATCH_YES;
+
+      if (matched_type && m == MATCH_YES && gfc_match_char (')') != MATCH_YES)
+       m = MATCH_ERROR;
+
+      return m;
     }
 
-  if (gfc_match (" real") == MATCH_YES)
+  if ((matched_type && strcmp ("real", name) == 0)
+      || (!matched_type && gfc_match (" real") == MATCH_YES))
     {
       ts->type = BT_REAL;
       ts->kind = gfc_default_real_kind;
       goto get_kind;
     }
 
-  if (gfc_match (" double precision") == MATCH_YES)
+  if ((matched_type
+       && (strcmp ("doubleprecision", name) == 0
+          || (strcmp ("double", name) == 0
+              && gfc_match (" precision") == MATCH_YES)))
+      || (!matched_type && gfc_match (" double precision") == MATCH_YES))
     {
+      if (matched_type
+         && gfc_notify_std (GFC_STD_F2008, "Fortran 2008: TYPE with "
+                         "intrinsic-type-spec at %C") == FAILURE)
+       return MATCH_ERROR;
+      if (matched_type && gfc_match_char (')') != MATCH_YES)
+       return MATCH_ERROR;
+
       ts->type = BT_REAL;
       ts->kind = gfc_default_double_kind;
       return MATCH_YES;
     }
 
-  if (gfc_match (" complex") == MATCH_YES)
+  if ((matched_type && strcmp ("complex", name) == 0)
+      || (!matched_type && gfc_match (" complex") == MATCH_YES))
     {
       ts->type = BT_COMPLEX;
       ts->kind = gfc_default_complex_kind;
       goto get_kind;
     }
 
-  if (gfc_match (" double complex") == MATCH_YES)
+  if ((matched_type
+       && (strcmp ("doublecomplex", name) == 0
+          || (strcmp ("double", name) == 0
+              && gfc_match (" complex") == MATCH_YES)))
+      || (!matched_type && gfc_match (" double complex") == MATCH_YES))
     {
-      if (gfc_notify_std (GFC_STD_GNU, "DOUBLE COMPLEX at %C does not "
-                         "conform to the Fortran 95 standard") == FAILURE)
+      if (gfc_notify_std (GFC_STD_GNU, "Extension: DOUBLE COMPLEX at %C")
+         == FAILURE)
+       return MATCH_ERROR;
+
+      if (matched_type
+         && gfc_notify_std (GFC_STD_F2008, "Fortran 2008: TYPE with "
+                         "intrinsic-type-spec at %C") == FAILURE)
+       return MATCH_ERROR;
+
+      if (matched_type && gfc_match_char (')') != MATCH_YES)
        return MATCH_ERROR;
 
       ts->type = BT_COMPLEX;
@@ -2360,28 +2463,40 @@ gfc_match_type_spec (gfc_typespec *ts, int implicit_flag)
       return MATCH_YES;
     }
 
-  if (gfc_match (" logical") == MATCH_YES)
+  if ((matched_type && strcmp ("logical", name) == 0)
+      || (!matched_type && gfc_match (" logical") == MATCH_YES))
     {
       ts->type = BT_LOGICAL;
       ts->kind = gfc_default_logical_kind;
       goto get_kind;
     }
 
-  m = gfc_match (" type ( %n )", name);
-  if (m != MATCH_YES)
-    return m;
+  if (matched_type)
+    m = gfc_match_char (')');
+
+  if (m == MATCH_YES)
+    ts->type = BT_DERIVED;
+  else
+    {
+      m = gfc_match (" class ( %n )", name);
+      if (m != MATCH_YES)
+       return m;
+      ts->type = BT_CLASS;
 
-  ts->type = BT_DERIVED;
+      if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: CLASS statement at %C")
+                         == FAILURE)
+       return MATCH_ERROR;
+    }
 
   /* Defer association of the derived type until the end of the
      specification block.  However, if the derived type can be
      found, add it to the typespec.  */  
   if (gfc_matching_function)
     {
-      ts->derived = NULL;
+      ts->u.derived = NULL;
       if (gfc_current_state () != COMP_INTERFACE
            && !gfc_find_symbol (name, NULL, 1, &sym) && sym)
-       ts->derived = sym;
+       ts->u.derived = sym;
       return MATCH_YES;
     }
 
@@ -2414,28 +2529,48 @@ gfc_match_type_spec (gfc_typespec *ts, int implicit_flag)
     return MATCH_ERROR;
 
   gfc_set_sym_referenced (sym);
-  ts->derived = sym;
+  ts->u.derived = sym;
 
   return MATCH_YES;
 
 get_kind:
+  if (matched_type
+      && gfc_notify_std (GFC_STD_F2008, "Fortran 2008: TYPE with "
+                        "intrinsic-type-spec at %C") == FAILURE)
+    return MATCH_ERROR;
+
   /* For all types except double, derived and character, look for an
      optional kind specifier.  MATCH_NO is actually OK at this point.  */
   if (implicit_flag == 1)
-    return MATCH_YES;
+    {
+       if (matched_type && gfc_match_char (')') != MATCH_YES)
+         return MATCH_ERROR;
+
+       return MATCH_YES;
+    }
 
   if (gfc_current_form == FORM_FREE)
     {
-      c = gfc_peek_ascii_char();
-      if (!gfc_is_whitespace(c) && c != '*' && c != '('
+      c = gfc_peek_ascii_char ();
+      if (!gfc_is_whitespace (c) && c != '*' && c != '('
          && c != ':' && c != ',')
-       return MATCH_NO;
+        {
+         if (matched_type && c == ')')
+           {
+             gfc_next_ascii_char ();
+             return MATCH_YES;
+           }
+         return MATCH_NO;
+       }
     }
 
   m = gfc_match_kind_spec (ts, false);
   if (m == MATCH_NO && ts->type != BT_CHARACTER)
     m = gfc_match_old_kind_spec (ts);
 
+  if (matched_type && gfc_match_char (')') != MATCH_YES)
+    return MATCH_ERROR;
+
   /* Defer association of the KIND expression of function results
      until after USE and IMPORT statements.  */
   if ((gfc_current_state () == COMP_NONE && gfc_error_flag_test ())
@@ -2588,7 +2723,7 @@ gfc_match_implicit (void)
       gfc_clear_new_implicit ();
 
       /* A basic type is mandatory here.  */
-      m = gfc_match_type_spec (&ts, 1);
+      m = gfc_match_decl_type_spec (&ts, 1);
       if (m == MATCH_ERROR)
        goto error;
       if (m == MATCH_NO)
@@ -2605,11 +2740,12 @@ gfc_match_implicit (void)
          if ((c == '\n') || (c == ','))
            {
              /* Check for CHARACTER with no length parameter.  */
-             if (ts.type == BT_CHARACTER && !ts.cl)
+             if (ts.type == BT_CHARACTER && !ts.u.cl)
                {
                  ts.kind = gfc_default_character_kind;
-                 ts.cl = gfc_new_charlen (gfc_current_ns);
-                 ts.cl->length = gfc_int_expr (1);
+                 ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL);
+                 ts.u.cl->length = gfc_get_int_expr (gfc_default_integer_kind,
+                                                     NULL, 1);
                }
 
              /* Record the Successful match.  */
@@ -2626,7 +2762,7 @@ gfc_match_implicit (void)
 
       /* Last chance -- check <TYPE> <SELECTOR> (<RANGE>).  */
       if (ts.type == BT_CHARACTER)
-       m = match_char_spec (&ts);
+       m = gfc_match_char_spec (&ts);
       else
        {
          m = gfc_match_kind_spec (&ts, false);
@@ -2803,8 +2939,8 @@ match_attr_spec (void)
     DECL_IN, DECL_OUT, DECL_INOUT, DECL_INTRINSIC, DECL_OPTIONAL,
     DECL_PARAMETER, DECL_POINTER, DECL_PROTECTED, DECL_PRIVATE,
     DECL_PUBLIC, DECL_SAVE, DECL_TARGET, DECL_VALUE, DECL_VOLATILE,
-    DECL_IS_BIND_C, DECL_NONE,
-    GFC_DECL_END /* Sentinel */
+    DECL_IS_BIND_C, DECL_CODIMENSION, DECL_ASYNCHRONOUS, DECL_CONTIGUOUS,
+    DECL_NONE, GFC_DECL_END /* Sentinel */
   }
   decl_types;
 
@@ -2848,8 +2984,25 @@ match_attr_spec (void)
          switch (gfc_peek_ascii_char ())
            {
            case 'a':
-             if (match_string_p ("allocatable"))
-               d = DECL_ALLOCATABLE;
+             gfc_next_ascii_char ();
+             switch (gfc_next_ascii_char ())
+               {
+               case 'l':
+                 if (match_string_p ("locatable"))
+                   {
+                     /* Matched "allocatable".  */
+                     d = DECL_ALLOCATABLE;
+                   }
+                 break;
+
+               case 's':
+                 if (match_string_p ("ynchronous"))
+                   {
+                     /* Matched "asynchronous".  */
+                     d = DECL_ASYNCHRONOUS;
+                   }
+                 break;
+               }
              break;
 
            case 'b':
@@ -2861,6 +3014,27 @@ match_attr_spec (void)
                goto cleanup;
              break;
 
+           case 'c':
+             gfc_next_ascii_char ();
+             if ('o' != gfc_next_ascii_char ())
+               break;
+             switch (gfc_next_ascii_char ())
+               {
+               case 'd':
+                 if (match_string_p ("imension"))
+                   {
+                     d = DECL_CODIMENSION;
+                     break;
+                   }
+               case 'n':
+                 if (match_string_p ("tiguous"))
+                   {
+                     d = DECL_CONTIGUOUS;
+                     break;
+                   }
+               }
+             break;
+
            case 'd':
              if (match_string_p ("dimension"))
                d = DECL_DIMENSION;
@@ -3006,13 +3180,27 @@ match_attr_spec (void)
       seen[d]++;
       seen_at[d] = gfc_current_locus;
 
-      if (d == DECL_DIMENSION)
+      if (d == DECL_DIMENSION || d == DECL_CODIMENSION)
        {
-         m = gfc_match_array_spec (&current_as);
+         gfc_array_spec *as = NULL;
+
+         m = gfc_match_array_spec (&as, d == DECL_DIMENSION,
+                                   d == DECL_CODIMENSION);
+
+         if (current_as == NULL)
+           current_as = as;
+         else if (m == MATCH_YES)
+           {
+             merge_array_spec (as, current_as, false);
+             gfc_free (as);
+           }
 
          if (m == MATCH_NO)
            {
-             gfc_error ("Missing dimension specification at %C");
+             if (d == DECL_CODIMENSION)
+               gfc_error ("Missing codimension specification at %C");
+             else
+               gfc_error ("Missing dimension specification at %C");
              m = MATCH_ERROR;
            }
 
@@ -3031,6 +3219,15 @@ match_attr_spec (void)
          case DECL_ALLOCATABLE:
            attr = "ALLOCATABLE";
            break;
+         case DECL_ASYNCHRONOUS:
+           attr = "ASYNCHRONOUS";
+           break;
+         case DECL_CODIMENSION:
+           attr = "CODIMENSION";
+           break;
+         case DECL_CONTIGUOUS:
+           attr = "CONTIGUOUS";
+           break;
          case DECL_DIMENSION:
            attr = "DIMENSION";
            break;
@@ -3099,9 +3296,9 @@ match_attr_spec (void)
        continue;
 
       if (gfc_current_state () == COMP_DERIVED
-         && d != DECL_DIMENSION && d != DECL_POINTER
-         && d != DECL_PRIVATE   && d != DECL_PUBLIC
-         && d != DECL_NONE)
+         && d != DECL_DIMENSION && d != DECL_CODIMENSION
+         && d != DECL_POINTER   && d != DECL_PRIVATE
+         && d != DECL_PUBLIC && d != DECL_CONTIGUOUS && d != DECL_NONE)
        {
          if (d == DECL_ALLOCATABLE)
            {
@@ -3157,6 +3354,28 @@ match_attr_spec (void)
          t = gfc_add_allocatable (&current_attr, &seen_at[d]);
          break;
 
+       case DECL_ASYNCHRONOUS:
+         if (gfc_notify_std (GFC_STD_F2003,
+                             "Fortran 2003: ASYNCHRONOUS attribute at %C")
+             == FAILURE)
+           t = FAILURE;
+         else
+           t = gfc_add_asynchronous (&current_attr, NULL, &seen_at[d]);
+         break;
+
+       case DECL_CODIMENSION:
+         t = gfc_add_codimension (&current_attr, NULL, &seen_at[d]);
+         break;
+
+       case DECL_CONTIGUOUS:
+         if (gfc_notify_std (GFC_STD_F2008,
+                             "Fortran 2008: CONTIGUOUS attribute at %C")
+             == FAILURE)
+           t = FAILURE;
+         else
+           t = gfc_add_contiguous (&current_attr, NULL, &seen_at[d]);
+         break;
+
        case DECL_DIMENSION:
          t = gfc_add_dimension (&current_attr, NULL, &seen_at[d]);
          break;
@@ -3321,8 +3540,8 @@ set_com_block_bind_c (gfc_common_head *com_block, int is_bind_c)
 gfc_try
 verify_c_interop (gfc_typespec *ts)
 {
-  if (ts->type == BT_DERIVED && ts->derived != NULL)
-    return (ts->derived->ts.is_c_interop ? SUCCESS : FAILURE);
+  if (ts->type == BT_DERIVED && ts->u.derived != NULL)
+    return (ts->u.derived->ts.is_c_interop ? SUCCESS : FAILURE);
   else if (ts->is_c_interop != 1)
     return FAILURE;
   
@@ -3464,9 +3683,9 @@ verify_bind_c_sym (gfc_symbol *tmp_sym, gfc_typespec *ts,
 
       /* BIND(C) functions can not return a character string.  */
       if (bind_c_function && tmp_sym->ts.type == BT_CHARACTER)
-       if (tmp_sym->ts.cl == NULL || tmp_sym->ts.cl->length == NULL
-           || tmp_sym->ts.cl->length->expr_type != EXPR_CONSTANT
-           || mpz_cmp_si (tmp_sym->ts.cl->length->value.integer, 1) != 0)
+       if (tmp_sym->ts.u.cl == NULL || tmp_sym->ts.u.cl->length == NULL
+           || tmp_sym->ts.u.cl->length->expr_type != EXPR_CONSTANT
+           || mpz_cmp_si (tmp_sym->ts.u.cl->length->value.integer, 1) != 0)
          gfc_error ("Return type of BIND(C) function '%s' at %L cannot "
                         "be a character string", tmp_sym->name,
                         &(tmp_sym->declared_at));
@@ -3664,13 +3883,14 @@ gfc_match_data_decl (void)
 
   num_idents_on_line = 0;
   
-  m = gfc_match_type_spec (&current_ts, 0);
+  m = gfc_match_decl_type_spec (&current_ts, 0);
   if (m != MATCH_YES)
     return m;
 
-  if (current_ts.type == BT_DERIVED && gfc_current_state () != COMP_DERIVED)
+  if ((current_ts.type == BT_DERIVED || current_ts.type == BT_CLASS)
+       && gfc_current_state () != COMP_DERIVED)
     {
-      sym = gfc_use_derived (current_ts.derived);
+      sym = gfc_use_derived (current_ts.u.derived);
 
       if (sym == NULL)
        {
@@ -3678,7 +3898,7 @@ gfc_match_data_decl (void)
          goto cleanup;
        }
 
-      current_ts.derived = sym;
+      current_ts.u.derived = sym;
     }
 
   m = match_attr_spec ();
@@ -3688,21 +3908,22 @@ gfc_match_data_decl (void)
       goto cleanup;
     }
 
-  if (current_ts.type == BT_DERIVED && current_ts.derived->components == NULL
-      && !current_ts.derived->attr.zero_comp)
+  if ((current_ts.type == BT_DERIVED || current_ts.type == BT_CLASS)
+      && current_ts.u.derived->components == NULL
+      && !current_ts.u.derived->attr.zero_comp)
     {
 
       if (current_attr.pointer && gfc_current_state () == COMP_DERIVED)
        goto ok;
 
-      gfc_find_symbol (current_ts.derived->name,
-                      current_ts.derived->ns->parent, 1, &sym);
+      gfc_find_symbol (current_ts.u.derived->name,
+                      current_ts.u.derived->ns->parent, 1, &sym);
 
       /* Any symbol that we find had better be a type definition
         which has its components defined.  */
       if (sym != NULL && sym->attr.flavor == FL_DERIVED
-         && (current_ts.derived->components != NULL
-             || current_ts.derived->attr.zero_comp))
+         && (current_ts.u.derived->components != NULL
+             || current_ts.u.derived->attr.zero_comp))
        goto ok;
 
       /* Now we have an error, which we signal, and then fix up
@@ -3769,7 +3990,7 @@ gfc_match_prefix (gfc_typespec *ts)
 
 loop:
   if (!seen_type && ts != NULL
-      && gfc_match_type_spec (ts, 0) == MATCH_YES
+      && gfc_match_decl_type_spec (ts, 0) == MATCH_YES
       && gfc_match_space () == MATCH_YES)
     {
 
@@ -4167,7 +4388,7 @@ match_procedure_interface (gfc_symbol **proc_if)
 
   /* Get the type spec. for the procedure interface.  */
   old_loc = gfc_current_locus;
-  m = gfc_match_type_spec (&current_ts, 0);
+  m = gfc_match_decl_type_spec (&current_ts, 0);
   gfc_gobble_whitespace ();
   if (m == MATCH_YES || (m == MATCH_NO && gfc_peek_ascii_char () == ')'))
     goto got_ts;
@@ -4438,6 +4659,10 @@ match_ppc_decl (void)
       return MATCH_ERROR;
     }
 
+  if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: Procedure pointer "
+                     "component at %C") == FAILURE)
+    return MATCH_ERROR;
+
   /* Match PPC names.  */
   ts = current_ts;
   for(num=1;;num++)
@@ -4802,6 +5027,10 @@ gfc_match_entry (void)
   if (m != MATCH_YES)
     return m;
 
+  if (gfc_notify_std (GFC_STD_F2008_OBS, "Fortran 2008 obsolescent feature: "
+                     "ENTRY statement at %C") == FAILURE)
+    return MATCH_ERROR;
+
   state = gfc_current_state ();
   if (state != COMP_SUBROUTINE && state != COMP_FUNCTION)
     {
@@ -5049,6 +5278,10 @@ gfc_match_subroutine (void)
   if (get_proc_name (name, &sym, false))
     return MATCH_ERROR;
 
+  /* Set declared_at as it might point to, e.g., a PUBLIC statement, if
+     the symbol existed before. */
+  sym->declared_at = gfc_current_locus;
+
   if (add_hidden_procptr_result (sym) == SUCCESS)
     sym = sym->result;
 
@@ -5325,8 +5558,8 @@ set_enum_kind(void)
 
 
 /* Match any of the various end-block statements.  Returns the type of
-   END to the caller.  The END INTERFACE, END IF, END DO and END
-   SELECT statements cannot be replaced by a single END statement.  */
+   END to the caller.  The END INTERFACE, END IF, END DO, END SELECT
+   and END BLOCK statements cannot be replaced by a single END statement.  */
 
 match
 gfc_match_end (gfc_statement *st)
@@ -5347,11 +5580,23 @@ gfc_match_end (gfc_statement *st)
   block_name = gfc_current_block () == NULL
             ? NULL : gfc_current_block ()->name;
 
-  if (state == COMP_CONTAINS || state == COMP_DERIVED_CONTAINS)
+  switch (state)
     {
+    case COMP_ASSOCIATE:
+    case COMP_BLOCK:
+      if (!strcmp (block_name, "block@"))
+       block_name = NULL;
+      break;
+
+    case COMP_CONTAINS:
+    case COMP_DERIVED_CONTAINS:
       state = gfc_state_stack->previous->state;
       block_name = gfc_state_stack->previous->sym == NULL
                 ? NULL : gfc_state_stack->previous->sym->name;
+      break;
+
+    default:
+      break;
     }
 
   switch (state)
@@ -5400,6 +5645,18 @@ gfc_match_end (gfc_statement *st)
       eos_ok = 0;
       break;
 
+    case COMP_ASSOCIATE:
+      *st = ST_END_ASSOCIATE;
+      target = " associate";
+      eos_ok = 0;
+      break;
+
+    case COMP_BLOCK:
+      *st = ST_END_BLOCK;
+      target = " block";
+      eos_ok = 0;
+      break;
+
     case COMP_IF:
       *st = ST_ENDIF;
       target = " if";
@@ -5412,7 +5669,14 @@ gfc_match_end (gfc_statement *st)
       eos_ok = 0;
       break;
 
+    case COMP_CRITICAL:
+      *st = ST_END_CRITICAL;
+      target = " critical";
+      eos_ok = 0;
+      break;
+
     case COMP_SELECT:
+    case COMP_SELECT_TYPE:
       *st = ST_END_SELECT;
       target = " select";
       eos_ok = 0;
@@ -5446,7 +5710,14 @@ gfc_match_end (gfc_statement *st)
 
   if (gfc_match_eos () == MATCH_YES)
     {
-      if (!eos_ok)
+      if (!eos_ok && (*st == ST_END_SUBROUTINE || *st == ST_END_FUNCTION))
+       {
+         if (gfc_notify_std (GFC_STD_F2008, "Fortran 2008: END statement "
+                             "instead of %s statement at %L",
+                             gfc_ascii_statement (*st), &old_loc) == FAILURE)
+           goto cleanup;
+       }
+      else if (!eos_ok)
        {
          /* We would have required END [something].  */
          gfc_error ("%s statement expected at %L",
@@ -5469,10 +5740,11 @@ gfc_match_end (gfc_statement *st)
     {
 
       if (*st != ST_ENDDO && *st != ST_ENDIF && *st != ST_END_SELECT
-         && *st != ST_END_FORALL && *st != ST_END_WHERE)
+         && *st != ST_END_FORALL && *st != ST_END_WHERE && *st != ST_END_BLOCK
+         && *st != ST_END_ASSOCIATE && *st != ST_END_CRITICAL)
        return MATCH_YES;
 
-      if (gfc_current_block () == NULL)
+      if (!block_name)
        return MATCH_YES;
 
       gfc_error ("Expected block name of '%s' in %s statement at %C",
@@ -5554,11 +5826,15 @@ attr_decl1 (void)
 
   /* Deal with possible array specification for certain attributes.  */
   if (current_attr.dimension
+      || current_attr.codimension
       || current_attr.allocatable
       || current_attr.pointer
       || current_attr.target)
     {
-      m = gfc_match_array_spec (&as);
+      m = gfc_match_array_spec (&as, !current_attr.codimension,
+                               !current_attr.dimension
+                               && !current_attr.pointer
+                               && !current_attr.target);
       if (m == MATCH_ERROR)
        goto cleanup;
 
@@ -5578,6 +5854,14 @@ attr_decl1 (void)
          goto cleanup;
        }
 
+      if (current_attr.codimension && m == MATCH_NO)
+       {
+         gfc_error ("Missing array specification at %L in CODIMENSION "
+                    "statement", &var_locus);
+         m = MATCH_ERROR;
+         goto cleanup;
+       }
+
       if ((current_attr.allocatable || current_attr.pointer)
          && (m == MATCH_YES) && (as->type != AS_DEFERRED))
        {
@@ -5587,13 +5871,28 @@ attr_decl1 (void)
        }
     }
 
-  /* Update symbol table.  DIMENSION attribute is set
-     in gfc_set_array_spec().  */
-  if (current_attr.dimension == 0
-      && gfc_copy_attr (&sym->attr, &current_attr, &var_locus) == FAILURE)
+  /* Update symbol table.  DIMENSION attribute is set in
+     gfc_set_array_spec().  For CLASS variables, this must be applied
+     to the first component, or '$data' field.  */
+  if (sym->ts.type == BT_CLASS)
     {
-      m = MATCH_ERROR;
-      goto cleanup;
+      if (gfc_copy_attr (&CLASS_DATA (sym)->attr, &current_attr,&var_locus)
+         == FAILURE)
+       {
+         m = MATCH_ERROR;
+         goto cleanup;
+       }
+      sym->attr.class_ok = (sym->attr.class_ok || current_attr.allocatable
+                           || current_attr.pointer);
+    }
+  else
+    {
+      if (current_attr.dimension == 0 && current_attr.codimension == 0
+         && gfc_copy_attr (&sym->attr, &current_attr, &var_locus) == FAILURE)
+       {
+         m = MATCH_ERROR;
+         goto cleanup;
+       }
     }
 
   if (gfc_set_array_spec (sym, as, &var_locus) == FAILURE)
@@ -5687,7 +5986,7 @@ static match
 cray_pointer_decl (void)
 {
   match m;
-  gfc_array_spec *as;
+  gfc_array_spec *as = NULL;
   gfc_symbol *cptr; /* Pointer symbol.  */
   gfc_symbol *cpte; /* Pointee symbol.  */
   locus var_locus;
@@ -5756,7 +6055,7 @@ cray_pointer_decl (void)
        }
 
       /* Check for an optional array spec.  */
-      m = gfc_match_array_spec (&as);
+      m = gfc_match_array_spec (&as, true, false);
       if (m == MATCH_ERROR)
        {
          gfc_free_array_spec (as);
@@ -5835,6 +6134,13 @@ gfc_match_intent (void)
 {
   sym_intent intent;
 
+  /* This is not allowed within a BLOCK construct!  */
+  if (gfc_current_state () == COMP_BLOCK)
+    {
+      gfc_error ("INTENT is not allowed inside of BLOCK at %C");
+      return MATCH_ERROR;
+    }
+
   intent = match_intent_spec ();
   if (intent == INTENT_UNKNOWN)
     return MATCH_ERROR;
@@ -5860,6 +6166,12 @@ gfc_match_intrinsic (void)
 match
 gfc_match_optional (void)
 {
+  /* This is not allowed within a BLOCK construct!  */
+  if (gfc_current_state () == COMP_BLOCK)
+    {
+      gfc_error ("OPTIONAL is not allowed inside of BLOCK at %C");
+      return MATCH_ERROR;
+    }
 
   gfc_clear_attr (&current_attr);
   current_attr.optional = 1;
@@ -5903,6 +6215,30 @@ gfc_match_allocatable (void)
 
 
 match
+gfc_match_codimension (void)
+{
+  gfc_clear_attr (&current_attr);
+  current_attr.codimension = 1;
+
+  return attr_decl ();
+}
+
+
+match
+gfc_match_contiguous (void)
+{
+  if (gfc_notify_std (GFC_STD_F2008, "Fortran 2008: CONTIGUOUS statement at %C")
+      == FAILURE)
+    return MATCH_ERROR;
+
+  gfc_clear_attr (&current_attr);
+  current_attr.contiguous = 1;
+
+  return attr_decl ();
+}
+
+
+match
 gfc_match_dimension (void)
 {
   gfc_clear_attr (&current_attr);
@@ -6151,6 +6487,7 @@ do_parm (void)
   gfc_symbol *sym;
   gfc_expr *init;
   match m;
+  gfc_try t;
 
   m = gfc_match_symbol (&sym, 0);
   if (m == MATCH_NO)
@@ -6192,35 +6529,8 @@ do_parm (void)
       goto cleanup;
     }
 
-  if (sym->ts.type == BT_CHARACTER
-      && sym->ts.cl != NULL
-      && sym->ts.cl->length != NULL
-      && sym->ts.cl->length->expr_type == EXPR_CONSTANT
-      && init->expr_type == EXPR_CONSTANT
-      && init->ts.type == BT_CHARACTER)
-    gfc_set_constant_character_len (
-      mpz_get_si (sym->ts.cl->length->value.integer), init, -1);
-  else if (sym->ts.type == BT_CHARACTER && sym->ts.cl != NULL
-          && sym->ts.cl->length == NULL)
-       {
-         int clen;
-         if (init->expr_type == EXPR_CONSTANT)
-           {
-             clen = init->value.character.length;
-             sym->ts.cl->length = gfc_int_expr (clen);
-           }
-         else if (init->expr_type == EXPR_ARRAY)
-           {
-             gfc_expr *p = init->value.constructor->expr;
-             clen = p->value.character.length;
-             sym->ts.cl->length = gfc_int_expr (clen);
-           }
-         else if (init->ts.cl && init->ts.cl->length)
-           sym->ts.cl->length = gfc_copy_expr (sym->value->ts.cl->length);
-       }
-
-  sym->value = init;
-  return MATCH_YES;
+  t = add_init_expr_to_sym (sym->name, &init, &gfc_current_locus);
+  return (t == SUCCESS) ? MATCH_YES : MATCH_ERROR;
 
 cleanup:
   gfc_free_expr (init);
@@ -6343,6 +6653,13 @@ gfc_match_value (void)
   gfc_symbol *sym;
   match m;
 
+  /* This is not allowed within a BLOCK construct!  */
+  if (gfc_current_state () == COMP_BLOCK)
+    {
+      gfc_error ("VALUE is not allowed inside of BLOCK at %C");
+      return MATCH_ERROR;
+    }
+
   if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: VALUE statement at %C")
       == FAILURE)
     return MATCH_ERROR;
@@ -6409,11 +6726,19 @@ gfc_match_volatile (void)
   for(;;)
     {
       /* VOLATILE is special because it can be added to host-associated 
-        symbols locally.  */
+        symbols locally. Except for coarrays. */
       m = gfc_match_symbol (&sym, 1);
       switch (m)
        {
        case MATCH_YES:
+         /* F2008, C560+C561. VOLATILE for host-/use-associated variable or
+            for variable in a BLOCK which is defined outside of the BLOCK.  */
+         if (sym->ns != gfc_current_ns && sym->attr.codimension)
+           {
+             gfc_error ("Specifying VOLATILE for coarray variable '%s' at "
+                        "%C, which is use-/host-associated", sym->name);
+             return MATCH_ERROR;
+           }
          if (gfc_add_volatile (&sym->attr, sym->name, &gfc_current_locus)
              == FAILURE)
            return MATCH_ERROR;
@@ -6441,6 +6766,59 @@ syntax:
 }
 
 
+match
+gfc_match_asynchronous (void)
+{
+  gfc_symbol *sym;
+  match m;
+
+  if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: ASYNCHRONOUS statement at %C")
+      == FAILURE)
+    return MATCH_ERROR;
+
+  if (gfc_match (" ::") == MATCH_NO && gfc_match_space () == MATCH_NO)
+    {
+      return MATCH_ERROR;
+    }
+
+  if (gfc_match_eos () == MATCH_YES)
+    goto syntax;
+
+  for(;;)
+    {
+      /* ASYNCHRONOUS is special because it can be added to host-associated 
+        symbols locally.  */
+      m = gfc_match_symbol (&sym, 1);
+      switch (m)
+       {
+       case MATCH_YES:
+         if (gfc_add_asynchronous (&sym->attr, sym->name, &gfc_current_locus)
+             == FAILURE)
+           return MATCH_ERROR;
+         goto next_item;
+
+       case MATCH_NO:
+         break;
+
+       case MATCH_ERROR:
+         return MATCH_ERROR;
+       }
+
+    next_item:
+      if (gfc_match_eos () == MATCH_YES)
+       break;
+      if (gfc_match_char (',') != MATCH_YES)
+       goto syntax;
+    }
+
+  return MATCH_YES;
+
+syntax:
+  gfc_error ("Syntax error in ASYNCHRONOUS statement at %C");
+  return MATCH_ERROR;
+}
+
+
 /* Match a module procedure statement.  Note that we have to modify
    symbols in the parent's namespace because the current one was there
    to receive symbols that are in an interface's formal argument list.  */
@@ -6466,7 +6844,10 @@ gfc_match_modproc (void)
 
   module_ns = gfc_current_ns->parent;
   for (; module_ns; module_ns = module_ns->parent)
-    if (module_ns->proc_name->attr.flavor == FL_MODULE)
+    if (module_ns->proc_name->attr.flavor == FL_MODULE
+       || module_ns->proc_name->attr.flavor == FL_PROGRAM
+       || (module_ns->proc_name->attr.flavor == FL_PROCEDURE
+           && !module_ns->proc_name->attr.contained))
       break;
 
   if (module_ns == NULL)
@@ -6478,6 +6859,7 @@ gfc_match_modproc (void)
 
   for (;;)
     {
+      locus old_locus = gfc_current_locus;
       bool last = false;
 
       m = gfc_match_name (name);
@@ -6498,6 +6880,13 @@ gfc_match_modproc (void)
       if (gfc_get_symbol (name, module_ns, &sym))
        return MATCH_ERROR;
 
+      if (sym->attr.intrinsic)
+       {
+         gfc_error ("Intrinsic procedure at %L cannot be a MODULE "
+                    "PROCEDURE", &old_locus);
+         return MATCH_ERROR;
+       }
+
       if (sym->attr.proc != PROC_MODULE
          && gfc_add_procedure (&sym->attr, PROC_MODULE,
                                sym->name, NULL) == FAILURE)
@@ -6507,6 +6896,7 @@ gfc_match_modproc (void)
        return MATCH_ERROR;
 
       sym->attr.mod_proc = 1;
+      sym->declared_at = old_locus;
 
       if (last)
        break;
@@ -6643,6 +7033,46 @@ gfc_get_type_attr_spec (symbol_attribute *attr, char *name)
 }
 
 
+/* Assign a hash value for a derived type. The algorithm is that of
+   SDBM. The hashed string is '[module_name #] derived_name'.  */
+static unsigned int
+hash_value (gfc_symbol *sym)
+{
+  unsigned int hash = 0;
+  const char *c;
+  int i, len;
+
+  /* Hash of the module or procedure name.  */
+  if (sym->module != NULL)
+    c = sym->module;
+  else if (sym->ns && sym->ns->proc_name
+            && sym->ns->proc_name->attr.flavor == FL_MODULE)
+    c = sym->ns->proc_name->name;
+  else
+    c = NULL;
+
+  if (c)
+    { 
+      len = strlen (c);
+      for (i = 0; i < len; i++, c++)
+       hash =  (hash << 6) + (hash << 16) - hash + (*c);
+
+      /* Disambiguate between 'a' in 'aa' and 'aa' in 'a'.  */ 
+      hash =  (hash << 6) + (hash << 16) - hash + '#';
+    }
+
+  /* Hash of the derived type name.  */
+  len = strlen (sym->name);
+  c = sym->name;
+  for (i = 0; i < len; i++, c++)
+    hash = (hash << 6) + (hash << 16) - hash + (*c);
+
+  /* Return the hash but take the modulus for the sake of module read,
+     even though this slightly increases the chance of collision.  */
+  return (hash % 100000000);
+}
+
+
 /* Match the beginning of a derived type declaration.  If a type name
    was the result of a function, then it is possible to have a symbol
    already to be known as a derived type yet have no components.  */
@@ -6748,13 +7178,23 @@ gfc_match_derived_decl (void)
 
       /* Add the extended derived type as the first component.  */
       gfc_add_component (sym, parent, &p);
-      sym->attr.extension = attr.extension;
       extended->refs++;
       gfc_set_sym_referenced (extended);
 
       p->ts.type = BT_DERIVED;
-      p->ts.derived = extended;
+      p->ts.u.derived = extended;
       p->initializer = gfc_default_initializer (&p->ts);
+      
+      /* Set extension level.  */
+      if (extended->attr.extension == 255)
+       {
+         /* Since the extension field is 8 bit wide, we can only have
+            up to 255 extension levels.  */
+         gfc_error ("Maximum extension level reached with type '%s' at %L",
+                    extended->name, &extended->declared_at);
+         return MATCH_ERROR;
+       }
+      sym->attr.extension = extended->attr.extension + 1;
 
       /* Provide the links between the extended type and its extension.  */
       if (!extended->f2k_derived)
@@ -6763,6 +7203,10 @@ gfc_match_derived_decl (void)
       st->n.sym = sym;
     }
 
+  if (!sym->hash_value)
+    /* Set the hash for the compound name for this type.  */
+    sym->hash_value = hash_value (sym);
+
   /* Take over the ABSTRACT attribute.  */
   sym->attr.abstract = attr.abstract;
 
@@ -6773,22 +7217,14 @@ gfc_match_derived_decl (void)
 
 
 /* Cray Pointees can be declared as: 
-      pointer (ipt, a (n,m,...,*)) 
-   By default, this is treated as an AS_ASSUMED_SIZE array.  We'll
-   cheat and set a constant bound of 1 for the last dimension, if this
-   is the case. Since there is no bounds-checking for Cray Pointees,
-   this will be okay.  */
+      pointer (ipt, a (n,m,...,*))  */
 
 match
 gfc_mod_pointee_as (gfc_array_spec *as)
 {
   as->cray_pointee = true; /* This will be useful to know later.  */
   if (as->type == AS_ASSUMED_SIZE)
-    {
-      as->type = AS_EXPLICIT;
-      as->upper[as->rank - 1] = gfc_int_expr (1);
-      as->cp_was_assumed = true;
-    }
+    as->cp_was_assumed = true;
   else if (as->type == AS_ASSUMED_SHAPE)
     {
       gfc_error ("Cray Pointee at %C cannot be assumed shape array");
@@ -6832,12 +7268,7 @@ static gfc_expr *
 enum_initializer (gfc_expr *last_initializer, locus where)
 {
   gfc_expr *result;
-
-  result = gfc_get_expr ();
-  result->expr_type = EXPR_CONSTANT;
-  result->ts.type = BT_INTEGER;
-  result->ts.kind = gfc_c_int_kind;
-  result->where = where;
+  result = gfc_get_constant_expr (BT_INTEGER, gfc_c_int_kind, &where);
 
   mpz_init (result->value.integer);
 
@@ -6928,10 +7359,9 @@ enumerator_decl (void)
 
   if (initializer == NULL || initializer->ts.type != BT_INTEGER)
     {
-      gfc_error("ENUMERATOR %L not initialized with integer expression",
-               &var_locus);
+      gfc_error ("ENUMERATOR %L not initialized with integer expression",
+                &var_locus);
       m = MATCH_ERROR;
-      gfc_free_enum_history ();
       goto cleanup;
     }
 
@@ -6997,7 +7427,10 @@ gfc_match_enumerator_def (void)
     {
       m = enumerator_decl ();
       if (m == MATCH_ERROR)
-       goto cleanup;
+       {
+         gfc_free_enum_history ();
+         goto cleanup;
+       }
       if (m == MATCH_NO)
        break;
 
@@ -7227,14 +7660,15 @@ match_procedure_in_type (void)
 {
   char name[GFC_MAX_SYMBOL_LEN + 1];
   char target_buf[GFC_MAX_SYMBOL_LEN + 1];
-  char* target = NULL;
-  gfc_typebound_proc* tb;
+  char* target = NULL, *ifc = NULL;
+  gfc_typebound_proc tb;
   bool seen_colons;
   bool seen_attrs;
   match m;
   gfc_symtree* stree;
   gfc_namespace* ns;
   gfc_symbol* block;
+  int num;
 
   /* Check current state.  */
   gcc_assert (gfc_state_stack->state == COMP_DERIVED_CONTAINS);
@@ -7259,28 +7693,26 @@ match_procedure_in_type (void)
          return MATCH_ERROR;
        }
 
-      target = target_buf;
+      ifc = target_buf;
     }
 
   /* Construct the data structure.  */
-  tb = gfc_get_typebound_proc ();
-  tb->where = gfc_current_locus;
-  tb->is_generic = 0;
+  tb.where = gfc_current_locus;
+  tb.is_generic = 0;
 
   /* Match binding attributes.  */
-  m = match_binding_attributes (tb, false, false);
+  m = match_binding_attributes (&tb, false, false);
   if (m == MATCH_ERROR)
     return m;
   seen_attrs = (m == MATCH_YES);
 
-  /* Check that attribute DEFERRED is given iff an interface is specified, which
-     means target != NULL.  */
-  if (tb->deferred && !target)
+  /* Check that attribute DEFERRED is given if an interface is specified.  */
+  if (tb.deferred && !ifc)
     {
       gfc_error ("Interface must be specified for DEFERRED binding at %C");
       return MATCH_ERROR;
     }
-  if (target && !tb->deferred)
+  if (ifc && !tb.deferred)
     {
       gfc_error ("PROCEDURE(interface) at %C should be declared DEFERRED");
       return MATCH_ERROR;
@@ -7297,97 +7729,103 @@ match_procedure_in_type (void)
       return MATCH_ERROR;
     }
 
-  /* Match the binding name.  */ 
-  m = gfc_match_name (name);
-  if (m == MATCH_ERROR)
-    return m;
-  if (m == MATCH_NO)
-    {
-      gfc_error ("Expected binding name at %C");
-      return MATCH_ERROR;
-    }
-
-  /* Try to match the '=> target', if it's there.  */
-  m = gfc_match (" =>");
-  if (m == MATCH_ERROR)
-    return m;
-  if (m == MATCH_YES)
+  /* Match the binding names.  */ 
+  for(num=1;;num++)
     {
-      if (tb->deferred)
+      m = gfc_match_name (name);
+      if (m == MATCH_ERROR)
+       return m;
+      if (m == MATCH_NO)
        {
-         gfc_error ("'=> target' is invalid for DEFERRED binding at %C");
+         gfc_error ("Expected binding name at %C");
          return MATCH_ERROR;
        }
 
-      if (!seen_colons)
-       {
-         gfc_error ("'::' needed in PROCEDURE binding with explicit target"
-                    " at %C");
-         return MATCH_ERROR;
-       }
+      if (num>1 && gfc_notify_std (GFC_STD_F2008, "Fortran 2008: PROCEDURE list"
+                                  " at %C") == FAILURE)
+       return MATCH_ERROR;
 
-      m = gfc_match_name (target_buf);
+      /* Try to match the '=> target', if it's there.  */
+      target = ifc;
+      m = gfc_match (" =>");
       if (m == MATCH_ERROR)
        return m;
-      if (m == MATCH_NO)
+      if (m == MATCH_YES)
        {
-         gfc_error ("Expected binding target after '=>' at %C");
-         return MATCH_ERROR;
+         if (tb.deferred)
+           {
+             gfc_error ("'=> target' is invalid for DEFERRED binding at %C");
+             return MATCH_ERROR;
+           }
+
+         if (!seen_colons)
+           {
+             gfc_error ("'::' needed in PROCEDURE binding with explicit target"
+                        " at %C");
+             return MATCH_ERROR;
+           }
+
+         m = gfc_match_name (target_buf);
+         if (m == MATCH_ERROR)
+           return m;
+         if (m == MATCH_NO)
+           {
+             gfc_error ("Expected binding target after '=>' at %C");
+             return MATCH_ERROR;
+           }
+         target = target_buf;
        }
-      target = target_buf;
-    }
 
-  /* Now we should have the end.  */
-  m = gfc_match_eos ();
-  if (m == MATCH_ERROR)
-    return m;
-  if (m == MATCH_NO)
-    {
-      gfc_error ("Junk after PROCEDURE declaration at %C");
-      return MATCH_ERROR;
-    }
+      /* If no target was found, it has the same name as the binding.  */
+      if (!target)
+       target = name;
 
-  /* If no target was found, it has the same name as the binding.  */
-  if (!target)
-    target = name;
+      /* Get the namespace to insert the symbols into.  */
+      ns = block->f2k_derived;
+      gcc_assert (ns);
 
-  /* Get the namespace to insert the symbols into.  */
-  ns = block->f2k_derived;
-  gcc_assert (ns);
+      /* If the binding is DEFERRED, check that the containing type is ABSTRACT.  */
+      if (tb.deferred && !block->attr.abstract)
+       {
+         gfc_error ("Type '%s' containing DEFERRED binding at %C "
+                    "is not ABSTRACT", block->name);
+         return MATCH_ERROR;
+       }
 
-  /* If the binding is DEFERRED, check that the containing type is ABSTRACT.  */
-  if (tb->deferred && !block->attr.abstract)
-    {
-      gfc_error ("Type '%s' containing DEFERRED binding at %C is not ABSTRACT",
-                block->name);
-      return MATCH_ERROR;
-    }
+      /* See if we already have a binding with this name in the symtree which
+        would be an error.  If a GENERIC already targetted this binding, it may
+        be already there but then typebound is still NULL.  */
+      stree = gfc_find_symtree (ns->tb_sym_root, name);
+      if (stree && stree->n.tb)
+       {
+         gfc_error ("There is already a procedure with binding name '%s' for "
+                    "the derived type '%s' at %C", name, block->name);
+         return MATCH_ERROR;
+       }
 
-  /* See if we already have a binding with this name in the symtree which would
-     be an error.  If a GENERIC already targetted this binding, it may be
-     already there but then typebound is still NULL.  */
-  stree = gfc_find_symtree (ns->tb_sym_root, name);
-  if (stree && stree->n.tb)
-    {
-      gfc_error ("There's already a procedure with binding name '%s' for the"
-                " derived type '%s' at %C", name, block->name);
-      return MATCH_ERROR;
-    }
+      /* Insert it and set attributes.  */
 
-  /* Insert it and set attributes.  */
+      if (!stree)
+       {
+         stree = gfc_new_symtree (&ns->tb_sym_root, name);
+         gcc_assert (stree);
+       }
+      stree->n.tb = gfc_get_typebound_proc (&tb);
 
-  if (!stree)
-    {
-      stree = gfc_new_symtree (&ns->tb_sym_root, name);
-      gcc_assert (stree);
+      if (gfc_get_sym_tree (target, gfc_current_ns, &stree->n.tb->u.specific,
+                           false))
+       return MATCH_ERROR;
+      gfc_set_sym_referenced (stree->n.tb->u.specific->n.sym);
+  
+      if (gfc_match_eos () == MATCH_YES)
+       return MATCH_YES;
+      if (gfc_match_char (',') != MATCH_YES)
+       goto syntax;
     }
-  stree->n.tb = tb;
-
-  if (gfc_get_sym_tree (target, gfc_current_ns, &tb->u.specific, false))
-    return MATCH_ERROR;
-  gfc_set_sym_referenced (tb->u.specific->n.sym);
 
-  return MATCH_YES;
+syntax:
+  gfc_error ("Syntax error in PROCEDURE statement at %C");
+  return MATCH_ERROR;
 }
 
 
@@ -7397,11 +7835,13 @@ match
 gfc_match_generic (void)
 {
   char name[GFC_MAX_SYMBOL_LEN + 1];
+  char bind_name[GFC_MAX_SYMBOL_LEN + 16]; /* Allow space for OPERATOR(...).  */
   gfc_symbol* block;
   gfc_typebound_proc tbattr; /* Used for match_binding_attributes.  */
   gfc_typebound_proc* tb;
-  gfc_symtree* st;
   gfc_namespace* ns;
+  interface_type op_type;
+  gfc_intrinsic_op op;
   match m;
 
   /* Check current state.  */
@@ -7428,49 +7868,126 @@ gfc_match_generic (void)
       goto error;
     }
 
-  /* The binding name and =>.  */
-  m = gfc_match (" %n =>", name);
+  /* Match the binding name; depending on type (operator / generic) format
+     it for future error messages into bind_name.  */
+  m = gfc_match_generic_spec (&op_type, name, &op);
   if (m == MATCH_ERROR)
     return MATCH_ERROR;
   if (m == MATCH_NO)
     {
-      gfc_error ("Expected generic name at %C");
+      gfc_error ("Expected generic name or operator descriptor at %C");
+      goto error;
+    }
+
+  switch (op_type)
+    {
+    case INTERFACE_GENERIC:
+      snprintf (bind_name, sizeof (bind_name), "%s", name);
+      break;
+    case INTERFACE_USER_OP:
+      snprintf (bind_name, sizeof (bind_name), "OPERATOR(.%s.)", name);
+      break;
+    case INTERFACE_INTRINSIC_OP:
+      snprintf (bind_name, sizeof (bind_name), "OPERATOR(%s)",
+               gfc_op2string (op));
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  /* Match the required =>.  */
+  if (gfc_match (" =>") != MATCH_YES)
+    {
+      gfc_error ("Expected '=>' at %C");
       goto error;
     }
+  
+  /* Try to find existing GENERIC binding with this name / for this operator;
+     if there is something, check that it is another GENERIC and then extend
+     it rather than building a new node.  Otherwise, create it and put it
+     at the right position.  */
 
-  /* If there's already something with this name, check that it is another
-     GENERIC and then extend that rather than build a new node.  */
-  st = gfc_find_symtree (ns->tb_sym_root, name);
-  if (st)
+  switch (op_type)
     {
-      gcc_assert (st->n.tb);
-      tb = st->n.tb;
+    case INTERFACE_USER_OP:
+    case INTERFACE_GENERIC:
+      {
+       const bool is_op = (op_type == INTERFACE_USER_OP);
+       gfc_symtree* st;
+
+       st = gfc_find_symtree (is_op ? ns->tb_uop_root : ns->tb_sym_root, name);
+       if (st)
+         {
+           tb = st->n.tb;
+           gcc_assert (tb);
+         }
+       else
+         tb = NULL;
+
+       break;
+      }
 
+    case INTERFACE_INTRINSIC_OP:
+      tb = ns->tb_op[op];
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  if (tb)
+    {
       if (!tb->is_generic)
        {
+         gcc_assert (op_type == INTERFACE_GENERIC);
          gfc_error ("There's already a non-generic procedure with binding name"
                     " '%s' for the derived type '%s' at %C",
-                    name, block->name);
+                    bind_name, block->name);
          goto error;
        }
 
       if (tb->access != tbattr.access)
        {
          gfc_error ("Binding at %C must have the same access as already"
-                    " defined binding '%s'", name);
+                    " defined binding '%s'", bind_name);
          goto error;
        }
     }
   else
     {
-      st = gfc_new_symtree (&ns->tb_sym_root, name);
-      gcc_assert (st);
-
-      st->n.tb = tb = gfc_get_typebound_proc ();
+      tb = gfc_get_typebound_proc (NULL);
       tb->where = gfc_current_locus;
       tb->access = tbattr.access;
       tb->is_generic = 1;
       tb->u.generic = NULL;
+
+      switch (op_type)
+       {
+       case INTERFACE_GENERIC:
+       case INTERFACE_USER_OP:
+         {
+           const bool is_op = (op_type == INTERFACE_USER_OP);
+           gfc_symtree* st;
+
+           st = gfc_new_symtree (is_op ? &ns->tb_uop_root : &ns->tb_sym_root,
+                                 name);
+           gcc_assert (st);
+           st->n.tb = tb;
+
+           break;
+         }
+         
+       case INTERFACE_INTRINSIC_OP:
+         ns->tb_op[op] = tb;
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
     }
 
   /* Now, match all following names as specific targets.  */
@@ -7495,7 +8012,7 @@ gfc_match_generic (void)
        if (target_st == target->specific_st)
          {
            gfc_error ("'%s' already defined as specific binding for the"
-                      " generic '%s' at %C", name, st->name);
+                      " generic '%s' at %C", name, bind_name);
            goto error;
          }
 
@@ -7533,8 +8050,18 @@ gfc_match_final_decl (void)
   bool first, last;
   gfc_symbol* block;
 
+  if (gfc_current_form == FORM_FREE)
+    {
+      char c = gfc_peek_ascii_char ();
+      if (!gfc_is_whitespace (c) && c != ':')
+       return MATCH_NO;
+    }
+  
   if (gfc_state_stack->state != COMP_DERIVED_CONTAINS)
     {
+      if (gfc_current_form == FORM_FIXED)
+       return MATCH_NO;
+
       gfc_error ("FINAL declaration at %C must be inside a derived type "
                 "CONTAINS section");
       return MATCH_ERROR;