OSDN Git Service

gcc/fortran:
[pf3gnuchains/gcc-fork.git] / gcc / fortran / resolve.c
index 9a06a98..aa3c809 100644 (file)
@@ -24,6 +24,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor,Boston, MA
 #include "system.h"
 #include "flags.h"
 #include "gfortran.h"
+#include "obstack.h"
+#include "bitmap.h"
 #include "arith.h"  /* For gfc_compare_expr().  */
 #include "dependency.h"
 
@@ -35,13 +37,17 @@ typedef enum seq_type
 }
 seq_type;
 
-/* Stack to push the current if we descend into a block during
-   resolution.  See resolve_branch() and resolve_code().  */
+/* Stack to keep track of the nesting of blocks as we move through the
+   code.  See resolve_branch() and resolve_code().  */
 
 typedef struct code_stack
 {
-  struct gfc_code *head, *current;
+  struct gfc_code *head, *current, *tail;
   struct code_stack *prev;
+
+  /* This bitmap keeps track of the targets valid for a branch from
+     inside this block.  */
+  bitmap reachable_labels;
 }
 code_stack;
 
@@ -66,6 +72,9 @@ static int specification_expr = 0;
 /* The id of the last entry seen.  */
 static int current_entry_id;
 
+/* We use bitmaps to determine if a branch target is valid.  */
+static bitmap_obstack labels_obstack;
+
 int
 gfc_is_formal_arg (void)
 {
@@ -280,18 +289,20 @@ resolve_contained_fntype (gfc_symbol *sym, gfc_namespace *ns)
     return;
 
   /* Try to find out of what the return type is.  */
-  if (sym->result != NULL)
-    sym = sym->result;
-
-  if (sym->ts.type == BT_UNKNOWN)
+  if (sym->result->ts.type == BT_UNKNOWN)
     {
-      t = gfc_set_default_type (sym, 0, ns);
+      t = gfc_set_default_type (sym->result, 0, ns);
 
-      if (t == FAILURE && !sym->attr.untyped)
+      if (t == FAILURE && !sym->result->attr.untyped)
        {
-         gfc_error ("Contained function '%s' at %L has no IMPLICIT type",
-                    sym->name, &sym->declared_at); /* FIXME */
-         sym->attr.untyped = 1;
+         if (sym->result == sym)
+           gfc_error ("Contained function '%s' at %L has no IMPLICIT type",
+                      sym->name, &sym->declared_at);
+         else
+           gfc_error ("Result '%s' of contained function '%s' at %L has "
+                      "no IMPLICIT type", sym->result->name, sym->name,
+                      &sym->result->declared_at);
+         sym->result->attr.untyped = 1;
        }
     }
 
@@ -301,9 +312,9 @@ resolve_contained_fntype (gfc_symbol *sym, gfc_namespace *ns)
      in external functions.  Internal function results are not on that list;
      ergo, not permitted.  */
 
-  if (sym->ts.type == BT_CHARACTER)
+  if (sym->result->ts.type == BT_CHARACTER)
     {
-      gfc_charlen *cl = sym->ts.cl;
+      gfc_charlen *cl = sym->result->ts.cl;
       if (!cl || !cl->length)
        gfc_error ("Character-valued internal function '%s' at %L must "
                   "not be assumed length", sym->name, &sym->declared_at);
@@ -583,6 +594,56 @@ resolve_entries (gfc_namespace *ns)
 }
 
 
+/* Resolve common blocks.  */
+static void
+resolve_common_blocks (gfc_symtree *common_root)
+{
+   gfc_symtree *symtree;
+   gfc_symbol *sym;
+
+   if (common_root == NULL)
+     return;
+
+   for (symtree = common_root; symtree->left; symtree = symtree->left);
+
+   for (; symtree; symtree = symtree->right)
+     {
+       gfc_find_symbol (symtree->name, gfc_current_ns, 0, &sym);
+       if (sym == NULL)
+         continue;
+
+       if (sym->attr.flavor == FL_PARAMETER)
+         {
+           gfc_error ("COMMON block '%s' at %L is used as PARAMETER at %L",
+                      sym->name, &symtree->n.common->where,
+                      &sym->declared_at);
+         }
+
+       if (sym->attr.intrinsic)
+         {
+           gfc_error ("COMMON block '%s' at %L is also an intrinsic "
+                      "procedure", sym->name,
+                      &symtree->n.common->where);
+         }
+       else if (sym->attr.result
+                ||(sym->attr.function && gfc_current_ns->proc_name == sym))
+         {
+           gfc_notify_std (GFC_STD_F2003, "Fortran 2003: COMMON block '%s' "
+                           "at %L that is also a function result", sym->name,
+                           &symtree->n.common->where);
+         }
+       else if (sym->attr.flavor == FL_PROCEDURE
+               && sym->attr.proc != PROC_INTERNAL
+               && sym->attr.proc != PROC_ST_FUNCTION)
+         {
+           gfc_notify_std (GFC_STD_F2003, "Fortran 2003: COMMON block '%s' "
+                           "at %L that is also a global procedure", sym->name,
+                           &symtree->n.common->where);
+         }
+     }
+}
+
+
 /* Resolve contained function types.  Because contained functions can call one
    another, they have to be worked out before any of the contained procedures
    can be resolved.
@@ -922,11 +983,24 @@ resolve_actual_arglist (gfc_actual_arglist *arg, procedure_type ptype)
                         &e->where);
            }
 
+         /* Check if a generic interface has a specific procedure
+           with the same name before emitting an error.  */
          if (sym->attr.generic)
            {
-             gfc_error ("GENERIC non-INTRINSIC procedure '%s' is not "
-                        "allowed as an actual argument at %L", sym->name,
-                        &e->where);
+             gfc_interface *p;
+             for (p = sym->generic; p; p = p->next)
+               if (strcmp (sym->name, p->sym->name) == 0)
+                 {
+                   e->symtree = gfc_find_symtree
+                                          (p->sym->ns->sym_root, sym->name);
+                   sym = p->sym;
+                   break;
+                 }
+
+             if (p == NULL || e->symtree == NULL)
+               gfc_error ("GENERIC non-INTRINSIC procedure '%s' is not "
+                               "allowed as an actual argument at %L", sym->name,
+                               &e->where);
            }
 
          /* If the symbol is the function that names the current (or
@@ -991,6 +1065,13 @@ resolve_actual_arglist (gfc_actual_arglist *arg, procedure_type ptype)
          e->ref->u.ar.as = sym->as;
        }
 
+      /* Expressions are assigned a default ts.type of BT_PROCEDURE in
+        primary.c (match_actual_arg). If above code determines that it
+        is a  variable instead, it needs to be resolved as it was not
+        done at the beginning of this function.  */
+      if (gfc_resolve_expr (e) != SUCCESS)
+       return FAILURE;
+
     argument_list:
       /* Check argument list functions %VAL, %LOC and %REF.  There is
         nothing to do for %REF.  */
@@ -1016,22 +1097,15 @@ resolve_actual_arglist (gfc_actual_arglist *arg, procedure_type ptype)
                 since same file external procedures are not resolvable
                 in gfortran, it is a good deal easier to leave them to
                 intrinsic.c.  */
-             if (ptype != PROC_UNKNOWN && ptype != PROC_EXTERNAL)
+             if (ptype != PROC_UNKNOWN
+                 && ptype != PROC_DUMMY
+                 && ptype != PROC_EXTERNAL
+                 && ptype != PROC_MODULE)
                {
                  gfc_error ("By-value argument at %L is not allowed "
                             "in this context", &e->where);
                  return FAILURE;
                }
-
-             if (((e->ts.type == BT_REAL || e->ts.type == BT_COMPLEX)
-                  && e->ts.kind > gfc_default_real_kind)
-                 || (e->ts.kind > gfc_default_integer_kind))
-               {
-                 gfc_error ("Kind of by-value argument at %L is larger "
-                            "than default kind", &e->where);
-                 return FAILURE;
-               }
-
            }
 
          /* Statement functions have already been excluded above.  */
@@ -1155,7 +1229,7 @@ resolve_elemental_actual (gfc_expr *expr, gfc_code *c)
          && formal_optional
          && arg->expr->rank
          && (set_by_optional || arg->expr->rank != rank)
-         && !(isym && isym->generic_id == GFC_ISYM_CONVERSION))
+         && !(isym && isym->id == GFC_ISYM_CONVERSION))
        {
          gfc_warning ("'%s' at %L is an array and OPTIONAL; IF IT IS "
                       "MISSING, it cannot be the actual argument of an "
@@ -1315,7 +1389,7 @@ generic:
 
   /* Last ditch attempt.  See if the reference is to an intrinsic
      that possesses a matching interface.  14.1.2.4  */
-  if (!gfc_intrinsic_name (sym->name, 0))
+  if (sym && !gfc_intrinsic_name (sym->name, 0))
     {
       gfc_error ("There is no specific function for the generic '%s' at %L",
                 expr->symtree->n.sym->name, &expr->where);
@@ -1478,6 +1552,22 @@ set_type:
 }
 
 
+/* Return true, if the symbol is an external procedure.  */
+static bool
+is_external_proc (gfc_symbol *sym)
+{
+  if (!sym->attr.dummy && !sym->attr.contained
+       && !(sym->attr.intrinsic
+             || gfc_intrinsic_name (sym->name, sym->attr.subroutine))
+       && sym->attr.proc != PROC_ST_FUNCTION
+       && !sym->attr.use_assoc
+       && sym->name)
+    return true;
+  else
+    return false;
+}
+
+
 /* Figure out if a function reference is pure or not.  Also set the name
    of the function for a potential error message.  Return nonzero if the
    function is PURE, zero if not.  */
@@ -1487,6 +1577,8 @@ pure_function (gfc_expr *e, const char **name)
 {
   int pure;
 
+  *name = NULL;
+
   if (e->symtree != NULL
         && e->symtree->n.sym != NULL
         && e->symtree->n.sym->attr.proc == PROC_ST_FUNCTION)
@@ -1514,6 +1606,293 @@ pure_function (gfc_expr *e, const char **name)
 }
 
 
+static try
+is_scalar_expr_ptr (gfc_expr *expr)
+{
+  try retval = SUCCESS;
+  gfc_ref *ref;
+  int start;
+  int end;
+
+  /* See if we have a gfc_ref, which means we have a substring, array
+     reference, or a component.  */
+  if (expr->ref != NULL)
+    {
+      ref = expr->ref;
+      while (ref->next != NULL)
+        ref = ref->next;
+
+      switch (ref->type)
+        {
+        case REF_SUBSTRING:
+          if (ref->u.ss.length != NULL 
+              && ref->u.ss.length->length != NULL
+              && ref->u.ss.start
+              && ref->u.ss.start->expr_type == EXPR_CONSTANT 
+              && ref->u.ss.end
+              && ref->u.ss.end->expr_type == EXPR_CONSTANT)
+            {
+              start = (int) mpz_get_si (ref->u.ss.start->value.integer);
+              end = (int) mpz_get_si (ref->u.ss.end->value.integer);
+              if (end - start + 1 != 1)
+                retval = FAILURE;
+            }
+          else
+            retval = FAILURE;
+          break;
+        case REF_ARRAY:
+          if (ref->u.ar.type == AR_ELEMENT)
+            retval = SUCCESS;
+          else if (ref->u.ar.type == AR_FULL)
+            {
+              /* The user can give a full array if the array is of size 1.  */
+              if (ref->u.ar.as != NULL
+                  && ref->u.ar.as->rank == 1
+                  && ref->u.ar.as->type == AS_EXPLICIT
+                  && ref->u.ar.as->lower[0] != NULL
+                  && ref->u.ar.as->lower[0]->expr_type == EXPR_CONSTANT
+                  && ref->u.ar.as->upper[0] != NULL
+                  && ref->u.ar.as->upper[0]->expr_type == EXPR_CONSTANT)
+                {
+                 /* If we have a character string, we need to check if
+                    its length is one.  */
+                 if (expr->ts.type == BT_CHARACTER)
+                   {
+                     if (expr->ts.cl == NULL
+                         || expr->ts.cl->length == NULL
+                         || mpz_cmp_si (expr->ts.cl->length->value.integer, 1)
+                         != 0)
+                        retval = FAILURE;
+                   }
+                 else
+                   {
+                  /* We have constant lower and upper bounds.  If the
+                     difference between is 1, it can be considered a
+                     scalar.  */
+                  start = (int) mpz_get_si
+                                (ref->u.ar.as->lower[0]->value.integer);
+                  end = (int) mpz_get_si
+                              (ref->u.ar.as->upper[0]->value.integer);
+                  if (end - start + 1 != 1)
+                    retval = FAILURE;
+                }
+                }
+              else
+                retval = FAILURE;
+            }
+          else
+            retval = FAILURE;
+          break;
+        default:
+          retval = SUCCESS;
+          break;
+        }
+    }
+  else if (expr->ts.type == BT_CHARACTER && expr->rank == 0)
+    {
+      /* Character string.  Make sure it's of length 1.  */
+      if (expr->ts.cl == NULL
+          || expr->ts.cl->length == NULL
+          || mpz_cmp_si (expr->ts.cl->length->value.integer, 1) != 0)
+        retval = FAILURE;
+    }
+  else if (expr->rank != 0)
+    retval = FAILURE;
+
+  return retval;
+}
+
+
+/* Match one of the iso_c_binding functions (c_associated or c_loc)
+   and, in the case of c_associated, set the binding label based on
+   the arguments.  */
+
+static try
+gfc_iso_c_func_interface (gfc_symbol *sym, gfc_actual_arglist *args,
+                          gfc_symbol **new_sym)
+{
+  char name[GFC_MAX_SYMBOL_LEN + 1];
+  char binding_label[GFC_MAX_BINDING_LABEL_LEN + 1];
+  int optional_arg = 0;
+  try retval = SUCCESS;
+  gfc_symbol *args_sym;
+
+  if (args->expr->expr_type == EXPR_CONSTANT
+      || args->expr->expr_type == EXPR_OP
+      || args->expr->expr_type == EXPR_NULL)
+    {
+      gfc_error ("Argument to '%s' at %L is not a variable",
+                sym->name, &(args->expr->where));
+      return FAILURE;
+    }
+
+  args_sym = args->expr->symtree->n.sym;
+   
+  if (sym->intmod_sym_id == ISOCBINDING_ASSOCIATED)
+    {
+      /* If the user gave two args then they are providing something for
+        the optional arg (the second cptr).  Therefore, set the name and
+        binding label to the c_associated for two cptrs.  Otherwise,
+        set c_associated to expect one cptr.  */
+      if (args->next)
+       {
+         /* two args.  */
+         sprintf (name, "%s_2", sym->name);
+         sprintf (binding_label, "%s_2", sym->binding_label);
+         optional_arg = 1;
+       }
+      else
+       {
+         /* one arg.  */
+         sprintf (name, "%s_1", sym->name);
+         sprintf (binding_label, "%s_1", sym->binding_label);
+         optional_arg = 0;
+       }
+
+      /* Get a new symbol for the version of c_associated that
+        will get called.  */
+      *new_sym = get_iso_c_sym (sym, name, binding_label, optional_arg);
+    }
+  else if (sym->intmod_sym_id == ISOCBINDING_LOC
+          || sym->intmod_sym_id == ISOCBINDING_FUNLOC)
+    {
+      sprintf (name, "%s", sym->name);
+      sprintf (binding_label, "%s", sym->binding_label);
+
+      /* Error check the call.  */
+      if (args->next != NULL)
+        {
+          gfc_error_now ("More actual than formal arguments in '%s' "
+                         "call at %L", name, &(args->expr->where));
+          retval = FAILURE;
+        }
+      else if (sym->intmod_sym_id == ISOCBINDING_LOC)
+        {
+          /* Make sure we have either the target or pointer attribute.  */
+          if (!(args->expr->symtree->n.sym->attr.target)
+             && !(args->expr->symtree->n.sym->attr.pointer))
+            {
+              gfc_error_now ("Parameter '%s' to '%s' at %L must be either "
+                             "a TARGET or an associated pointer",
+                             args->expr->symtree->n.sym->name,
+                             sym->name, &(args->expr->where));
+              retval = FAILURE;
+            }
+
+          /* See if we have interoperable type and type param.  */
+          if (verify_c_interop (&(args->expr->symtree->n.sym->ts),
+                                args->expr->symtree->n.sym->name,
+                                &(args->expr->where)) == SUCCESS
+              || gfc_check_any_c_kind (&(args_sym->ts)) == SUCCESS)
+            {
+              if (args_sym->attr.target == 1)
+                {
+                  /* Case 1a, section 15.1.2.5, J3/04-007: variable that
+                     has the target attribute and is interoperable.  */
+                  /* Case 1b, section 15.1.2.5, J3/04-007: allocated
+                     allocatable variable that has the TARGET attribute and
+                     is not an array of zero size.  */
+                  if (args_sym->attr.allocatable == 1)
+                    {
+                      if (args_sym->attr.dimension != 0 
+                          && (args_sym->as && args_sym->as->rank == 0))
+                        {
+                          gfc_error_now ("Allocatable variable '%s' used as a "
+                                         "parameter to '%s' at %L must not be "
+                                         "an array of zero size",
+                                         args_sym->name, sym->name,
+                                         &(args->expr->where));
+                          retval = FAILURE;
+                        }
+                    }
+                  else
+                    {
+                      /* Make sure it's not a character string.  Arrays of
+                         any type should be ok if the variable is of a C
+                         interoperable type.  */
+                      if (args_sym->ts.type == BT_CHARACTER 
+                          && is_scalar_expr_ptr (args->expr) != SUCCESS)
+                        {
+                          gfc_error_now ("CHARACTER argument '%s' to '%s' at "
+                                         "%L must have a length of 1",
+                                         args_sym->name, sym->name,
+                                         &(args->expr->where));
+                          retval = FAILURE;
+                        }
+                    }
+                }
+              else if (args_sym->attr.pointer == 1
+                       && is_scalar_expr_ptr (args->expr) != SUCCESS)
+                {
+                  /* Case 1c, section 15.1.2.5, J3/04-007: an associated
+                     scalar pointer.  */
+                  gfc_error_now ("Argument '%s' to '%s' at %L must be an "
+                                 "associated scalar POINTER", args_sym->name,
+                                 sym->name, &(args->expr->where));
+                  retval = FAILURE;
+                }
+            }
+          else
+            {
+              /* The parameter is not required to be C interoperable.  If it
+                 is not C interoperable, it must be a nonpolymorphic scalar
+                 with no length type parameters.  It still must have either
+                 the pointer or target attribute, and it can be
+                 allocatable (but must be allocated when c_loc is called).  */
+              if (args_sym->attr.dimension != 0
+                  && is_scalar_expr_ptr (args->expr) != SUCCESS)
+                {
+                  gfc_error_now ("Parameter '%s' to '%s' at %L must be a "
+                                 "scalar", args_sym->name, sym->name,
+                                 &(args->expr->where));
+                  retval = FAILURE;
+                }
+              else if (args_sym->ts.type == BT_CHARACTER 
+                       && args_sym->ts.cl != NULL)
+                {
+                  gfc_error_now ("CHARACTER parameter '%s' to '%s' at %L "
+                                 "cannot have a length type parameter",
+                                 args_sym->name, sym->name,
+                                 &(args->expr->where));
+                  retval = FAILURE;
+                }
+            }
+        }
+      else if (sym->intmod_sym_id == ISOCBINDING_FUNLOC)
+        {
+          if (args->expr->symtree->n.sym->attr.flavor != FL_PROCEDURE)
+            {
+              /* TODO: Update this error message to allow for procedure
+                 pointers once they are implemented.  */
+              gfc_error_now ("Parameter '%s' to '%s' at %L must be a "
+                             "procedure",
+                             args->expr->symtree->n.sym->name, sym->name,
+                             &(args->expr->where));
+              retval = FAILURE;
+            }
+          else if (args->expr->symtree->n.sym->attr.is_c_interop != 1)
+            {
+              gfc_error_now ("Parameter '%s' to '%s' at %L must be C "
+                             "interoperable",
+                             args->expr->symtree->n.sym->name, sym->name,
+                             &(args->expr->where));
+              retval = FAILURE;
+            }
+        }
+      
+      /* for c_loc/c_funloc, the new symbol is the same as the old one */
+      *new_sym = sym;
+    }
+  else
+    {
+      gfc_internal_error ("gfc_iso_c_func_interface(): Unhandled "
+                         "iso_c_binding function: '%s'!\n", sym->name);
+    }
+
+  return retval;
+}
+
+
 /* Resolve a function call, which means resolving the arguments, then figuring
    out which entity the name refers to.  */
 /* TODO: Check procedure arguments so that an INTENT(IN) isn't passed
@@ -1539,11 +1918,8 @@ resolve_function (gfc_expr *expr)
       return FAILURE;
     }
 
-  /* If the procedure is not internal, a statement function or a module
-     procedure,it must be external and should be checked for usage.  */
-  if (sym && !sym->attr.dummy && !sym->attr.contained
-      && sym->attr.proc != PROC_ST_FUNCTION
-      && !sym->attr.use_assoc)
+  /* If the procedure is external, check for usage.  */
+  if (sym && is_external_proc (sym))
     resolve_global_procedure (sym, &expr->where, 0);
 
   /* Switch off assumed size checking and do this again for certain kinds
@@ -1556,7 +1932,20 @@ resolve_function (gfc_expr *expr)
   if (resolve_actual_arglist (expr->value.function.actual, p) == FAILURE)
       return FAILURE;
 
-  /* Resume assumed_size checking. */
+  /* Need to setup the call to the correct c_associated, depending on
+     the number of cptrs to user gives to compare.  */
+  if (sym && sym->attr.is_iso_c == 1)
+    {
+      if (gfc_iso_c_func_interface (sym, expr->value.function.actual, &sym)
+          == FAILURE)
+        return FAILURE;
+      
+      /* Get the symtree for the new symbol (resolved func).
+         the old one will be freed later, when it's no longer used.  */
+      gfc_find_sym_tree (sym->name, sym->ns, 1, &(expr->symtree));
+    }
+  
+  /* Resume assumed_size checking.  */
   need_full_assumed_size--;
 
   if (sym && sym->ts.type == BT_CHARACTER
@@ -1626,7 +2015,7 @@ resolve_function (gfc_expr *expr)
       t = FAILURE;
     }
 
-#define GENERIC_ID expr->value.function.isym->generic_id
+#define GENERIC_ID expr->value.function.isym->id
   else if (expr->value.function.actual != NULL
           && expr->value.function.isym != NULL
           && GENERIC_ID != GFC_ISYM_LBOUND
@@ -1663,6 +2052,7 @@ resolve_function (gfc_expr *expr)
 #undef GENERIC_ID
 
   need_full_assumed_size = temp;
+  name = NULL;
 
   if (!pure_function (expr, &name) && name)
     {
@@ -1725,8 +2115,6 @@ resolve_function (gfc_expr *expr)
       if (expr->symtree->n.sym->result
            && expr->symtree->n.sym->result->ts.type != BT_UNKNOWN)
        expr->ts = expr->symtree->n.sym->result->ts;
-      else
-       expr->ts = expr->symtree->n.sym->result->ts;
     }
 
   return t;
@@ -1824,6 +2212,164 @@ generic:
 }
 
 
+/* Set the name and binding label of the subroutine symbol in the call
+   expression represented by 'c' to include the type and kind of the
+   second parameter.  This function is for resolving the appropriate
+   version of c_f_pointer() and c_f_procpointer().  For example, a
+   call to c_f_pointer() for a default integer pointer could have a
+   name of c_f_pointer_i4.  If no second arg exists, which is an error
+   for these two functions, it defaults to the generic symbol's name
+   and binding label.  */
+
+static void
+set_name_and_label (gfc_code *c, gfc_symbol *sym,
+                    char *name, char *binding_label)
+{
+  gfc_expr *arg = NULL;
+  char type;
+  int kind;
+
+  /* The second arg of c_f_pointer and c_f_procpointer determines
+     the type and kind for the procedure name.  */
+  arg = c->ext.actual->next->expr;
+
+  if (arg != NULL)
+    {
+      /* Set up the name to have the given symbol's name,
+         plus the type and kind.  */
+      /* a derived type is marked with the type letter 'u' */
+      if (arg->ts.type == BT_DERIVED)
+        {
+          type = 'd';
+          kind = 0; /* set the kind as 0 for now */
+        }
+      else
+        {
+          type = gfc_type_letter (arg->ts.type);
+          kind = arg->ts.kind;
+        }
+      sprintf (name, "%s_%c%d", sym->name, type, kind);
+      /* Set up the binding label as the given symbol's label plus
+         the type and kind.  */
+      sprintf (binding_label, "%s_%c%d", sym->binding_label, type, kind);
+    }
+  else
+    {
+      /* If the second arg is missing, set the name and label as
+         was, cause it should at least be found, and the missing
+         arg error will be caught by compare_parameters().  */
+      sprintf (name, "%s", sym->name);
+      sprintf (binding_label, "%s", sym->binding_label);
+    }
+   
+  return;
+}
+
+
+/* Resolve a generic version of the iso_c_binding procedure given
+   (sym) to the specific one based on the type and kind of the
+   argument(s).  Currently, this function resolves c_f_pointer() and
+   c_f_procpointer based on the type and kind of the second argument
+   (FPTR).  Other iso_c_binding procedures aren't specially handled.
+   Upon successfully exiting, c->resolved_sym will hold the resolved
+   symbol.  Returns MATCH_ERROR if an error occurred; MATCH_YES
+   otherwise.  */
+
+match
+gfc_iso_c_sub_interface (gfc_code *c, gfc_symbol *sym)
+{
+  gfc_symbol *new_sym;
+  /* this is fine, since we know the names won't use the max */
+  char name[GFC_MAX_SYMBOL_LEN + 1];
+  char binding_label[GFC_MAX_BINDING_LABEL_LEN + 1];
+  /* default to success; will override if find error */
+  match m = MATCH_YES;
+  gfc_symbol *tmp_sym;
+
+  if ((sym->intmod_sym_id == ISOCBINDING_F_POINTER) ||
+      (sym->intmod_sym_id == ISOCBINDING_F_PROCPOINTER))
+    {
+      set_name_and_label (c, sym, name, binding_label);
+      
+      if (sym->intmod_sym_id == ISOCBINDING_F_POINTER)
+       {
+         if (c->ext.actual != NULL && c->ext.actual->next != NULL)
+           {
+             /* Make sure we got a third arg.  The type/rank of it will
+                be checked later if it's there (gfc_procedure_use()).  */
+             if (c->ext.actual->next->expr->rank != 0 &&
+                 c->ext.actual->next->next == NULL)
+               {
+                 m = MATCH_ERROR;
+                 gfc_error ("Missing SHAPE parameter for call to %s "
+                            "at %L", sym->name, &(c->loc));
+               }
+              /* Make sure the param is a POINTER.  No need to make sure
+                 it does not have INTENT(IN) since it is a POINTER.  */
+              tmp_sym = c->ext.actual->next->expr->symtree->n.sym;
+              if (tmp_sym != NULL && tmp_sym->attr.pointer != 1)
+                {
+                  gfc_error ("Argument '%s' to '%s' at %L "
+                             "must have the POINTER attribute",
+                             tmp_sym->name, sym->name, &(c->loc));
+                  m = MATCH_ERROR;
+                }
+           }
+       }
+      
+      if (m != MATCH_ERROR)
+       {
+         /* the 1 means to add the optional arg to formal list */
+         new_sym = get_iso_c_sym (sym, name, binding_label, 1);
+        
+         /* for error reporting, say it's declared where the original was */
+         new_sym->declared_at = sym->declared_at;
+       }
+    }
+  else if (sym->intmod_sym_id == ISOCBINDING_ASSOCIATED)
+    {
+      /* TODO: Figure out if this is even reacable; this part of the
+         conditional may not be necessary.  */
+      int num_args = 0;
+      if (c->ext.actual->next == NULL)
+       {
+         /* The user did not give two args, so resolve to the version
+            of c_associated expecting one arg.  */
+         num_args = 1;
+         /* get rid of the second arg */
+         /* TODO!! Should free up the memory here!  */
+         sym->formal->next = NULL;
+       }
+      else
+       {
+         num_args = 2;
+       }
+
+      new_sym = sym;
+      sprintf (name, "%s_%d", sym->name, num_args);
+      sprintf (binding_label, "%s_%d", sym->binding_label, num_args);
+      sym->name = gfc_get_string (name);
+      strcpy (sym->binding_label, binding_label);
+    }
+  else
+    {
+      /* no differences for c_loc or c_funloc */
+      new_sym = sym;
+    }
+
+  /* set the resolved symbol */
+  if (m != MATCH_ERROR)
+    {
+      gfc_procedure_use (new_sym, &c->ext.actual, &c->loc);
+      c->resolved_sym = new_sym;
+    }
+  else
+    c->resolved_sym = sym;
+  
+  return m;
+}
+
+
 /* Resolve a subroutine call known to be specific.  */
 
 static match
@@ -1831,6 +2377,12 @@ resolve_specific_s0 (gfc_code *c, gfc_symbol *sym)
 {
   match m;
 
+  if(sym->attr.is_iso_c)
+    {
+      m = gfc_iso_c_sub_interface (c,sym);
+      return m;
+    }
+  
   if (sym->attr.external || sym->attr.if_source == IFSRC_IFBODY)
     {
       if (sym->attr.dummy)
@@ -1959,12 +2511,8 @@ resolve_call (gfc_code *c)
       return FAILURE;
     }
 
-  /* If the procedure is not internal or module, it must be external and
-     should be checked for usage.  */
-  if (c->symtree && c->symtree->n.sym
-      && !c->symtree->n.sym->attr.dummy
-      && !c->symtree->n.sym->attr.contained
-      && !c->symtree->n.sym->attr.use_assoc)
+  /* If external, check for usage.  */
+  if (c->symtree && is_external_proc (c->symtree->n.sym))
     resolve_global_procedure (c->symtree->n.sym, &c->loc, 1);
 
   /* Subroutines without the RECURSIVE attribution are not allowed to
@@ -2001,7 +2549,7 @@ resolve_call (gfc_code *c)
   if (resolve_actual_arglist (c->ext.actual, ptype) == FAILURE)
     return FAILURE;
 
-  /* Resume assumed_size checking. */
+  /* Resume assumed_size checking.  */
   need_full_assumed_size--;
 
   t = SUCCESS;
@@ -2074,6 +2622,7 @@ resolve_operator (gfc_expr *e)
 {
   gfc_expr *op1, *op2;
   char msg[200];
+  bool dual_locus_error;
   try t;
 
   /* Resolve all subnodes-- give them types.  */
@@ -2099,6 +2648,14 @@ resolve_operator (gfc_expr *e)
 
   op1 = e->value.op.op1;
   op2 = e->value.op.op2;
+  dual_locus_error = false;
+
+  if ((op1 && op1->expr_type == EXPR_NULL)
+      || (op2 && op2->expr_type == EXPR_NULL))
+    {
+      sprintf (msg, _("Invalid context for NULL() pointer at %%L"));
+      goto bad_op;
+    }
 
   switch (e->value.op.operator)
     {
@@ -2175,14 +2732,18 @@ resolve_operator (gfc_expr *e)
          break;
        }
 
-      sprintf (msg, _("Operand of .NOT. operator at %%L is %s"),
+      sprintf (msg, _("Operand of .not. operator at %%L is %s"),
               gfc_typename (&op1->ts));
       goto bad_op;
 
     case INTRINSIC_GT:
+    case INTRINSIC_GT_OS:
     case INTRINSIC_GE:
+    case INTRINSIC_GE_OS:
     case INTRINSIC_LT:
+    case INTRINSIC_LT_OS:
     case INTRINSIC_LE:
+    case INTRINSIC_LE_OS:
       if (op1->ts.type == BT_COMPLEX || op2->ts.type == BT_COMPLEX)
        {
          strcpy (msg, _("COMPLEX quantities cannot be compared at %L"));
@@ -2192,7 +2753,9 @@ resolve_operator (gfc_expr *e)
       /* Fall through...  */
 
     case INTRINSIC_EQ:
+    case INTRINSIC_EQ_OS:
     case INTRINSIC_NE:
+    case INTRINSIC_NE_OS:
       if (op1->ts.type == BT_CHARACTER && op2->ts.type == BT_CHARACTER)
        {
          e->ts.type = BT_LOGICAL;
@@ -2212,7 +2775,7 @@ resolve_operator (gfc_expr *e)
       if (op1->ts.type == BT_LOGICAL && op2->ts.type == BT_LOGICAL)
        sprintf (msg,
                 _("Logicals at %%L must be compared with %s instead of %s"),
-                e->value.op.operator == INTRINSIC_EQ ? ".EQV." : ".NEQV.",
+                e->value.op.operator == INTRINSIC_EQ ? ".eqv." : ".neqv.",
                 gfc_op2string (e->value.op.operator));
       else
        sprintf (msg,
@@ -2223,7 +2786,9 @@ resolve_operator (gfc_expr *e)
       goto bad_op;
 
     case INTRINSIC_USER:
-      if (op2 == NULL)
+      if (e->value.op.uop->operator == NULL)
+       sprintf (msg, _("Unknown operator '%s' at %%L"), e->value.op.uop->name);
+      else if (op2 == NULL)
        sprintf (msg, _("Operand of user operator '%s' at %%L is %s"),
                 e->value.op.uop->name, gfc_typename (&op1->ts));
       else
@@ -2257,11 +2822,17 @@ resolve_operator (gfc_expr *e)
     case INTRINSIC_EQV:
     case INTRINSIC_NEQV:
     case INTRINSIC_EQ:
+    case INTRINSIC_EQ_OS:
     case INTRINSIC_NE:
+    case INTRINSIC_NE_OS:
     case INTRINSIC_GT:
+    case INTRINSIC_GT_OS:
     case INTRINSIC_GE:
+    case INTRINSIC_GE_OS:
     case INTRINSIC_LT:
+    case INTRINSIC_LT_OS:
     case INTRINSIC_LE:
+    case INTRINSIC_LE_OS:
 
       if (op1->rank == 0 && op2->rank == 0)
        e->rank = 0;
@@ -2298,12 +2869,14 @@ resolve_operator (gfc_expr *e)
            }
          else
            {
-             gfc_error ("Inconsistent ranks for operator at %L and %L",
-                        &op1->where, &op2->where);
-             t = FAILURE;
-
              /* Allow higher level expressions to work.  */
              e->rank = 0;
+
+             /* Try user-defined operators, and otherwise throw an error.  */
+             dual_locus_error = true;
+             sprintf (msg,
+                      _("Inconsistent ranks for operator at %%L and %%L"));
+             goto bad_op;
            }
        }
 
@@ -2342,7 +2915,10 @@ bad_op:
   if (gfc_extend_expr (e) == SUCCESS)
     return SUCCESS;
 
-  gfc_error (msg, &e->where);
+  if (dual_locus_error)
+    gfc_error (msg, &op1->where, &op2->where);
+  else
+    gfc_error (msg, &e->where);
 
   return FAILURE;
 }
@@ -2499,48 +3075,53 @@ check_dimension (int i, gfc_array_ref *ar, gfc_array_spec *as)
       break;
 
     case AR_SECTION:
-      if (compare_bound_int (ar->stride[i], 0) == CMP_EQ)
-       {
-         gfc_error ("Illegal stride of zero at %L", &ar->c_where[i]);
-         return FAILURE;
-       }
-
+      {
 #define AR_START (ar->start[i] ? ar->start[i] : as->lower[i])
 #define AR_END (ar->end[i] ? ar->end[i] : as->upper[i])
 
-      if (compare_bound (AR_START, AR_END) == CMP_EQ
-         && (compare_bound (AR_START, as->lower[i]) == CMP_LT
-             || compare_bound (AR_START, as->upper[i]) == CMP_GT))
-       goto bound;
+       comparison comp_start_end = compare_bound (AR_START, AR_END);
 
-      if (((compare_bound_int (ar->stride[i], 0) == CMP_GT
-           || ar->stride[i] == NULL)
-          && compare_bound (AR_START, AR_END) != CMP_GT)
-         || (compare_bound_int (ar->stride[i], 0) == CMP_LT
-             && compare_bound (AR_START, AR_END) != CMP_LT))
-       {
-         if (compare_bound (AR_START, as->lower[i]) == CMP_LT)
-           goto bound;
-         if (compare_bound (AR_START, as->upper[i]) == CMP_GT)
-           goto bound;
-       }
+       /* Check for zero stride, which is not allowed.  */
+       if (compare_bound_int (ar->stride[i], 0) == CMP_EQ)
+         {
+           gfc_error ("Illegal stride of zero at %L", &ar->c_where[i]);
+           return FAILURE;
+         }
 
-      mpz_init (last_value);
-      if (compute_last_value_for_triplet (AR_START, AR_END, ar->stride[i],
-                                         last_value))
-       {
-         if (compare_bound_mpz_t (as->lower[i], last_value) == CMP_GT
-             || compare_bound_mpz_t (as->upper[i], last_value) == CMP_LT)
-           {
-             mpz_clear (last_value);
+       /* if start == len || (stride > 0 && start < len)
+                          || (stride < 0 && start > len),
+          then the array section contains at least one element.  In this
+          case, there is an out-of-bounds access if
+          (start < lower || start > upper).  */
+       if (compare_bound (AR_START, AR_END) == CMP_EQ
+           || ((compare_bound_int (ar->stride[i], 0) == CMP_GT
+                || ar->stride[i] == NULL) && comp_start_end == CMP_LT)
+           || (compare_bound_int (ar->stride[i], 0) == CMP_LT
+               && comp_start_end == CMP_GT))
+         {
+           if (compare_bound (AR_START, as->lower[i]) == CMP_LT
+               || compare_bound (AR_START, as->upper[i]) == CMP_GT)
              goto bound;
-           }
-       }
-      mpz_clear (last_value);
+         }
+
+       /* If we can compute the highest index of the array section,
+          then it also has to be between lower and upper.  */
+       mpz_init (last_value);
+       if (compute_last_value_for_triplet (AR_START, AR_END, ar->stride[i],
+                                           last_value))
+         {
+           if (compare_bound_mpz_t (as->lower[i], last_value) == CMP_GT
+               || compare_bound_mpz_t (as->upper[i], last_value) == CMP_LT)
+             {
+               mpz_clear (last_value);
+               goto bound;
+             }
+         }
+       mpz_clear (last_value);
 
 #undef AR_START
 #undef AR_END
-
+      }
       break;
 
     default:
@@ -3174,6 +3755,75 @@ resolve_variable (gfc_expr *e)
 }
 
 
+/* Checks to see that the correct symbol has been host associated.
+   The only situation where this arises is that in which a twice
+   contained function is parsed after the host association is made.
+   Therefore, on detecting this, the line is rematched, having got
+   rid of the existing references and actual_arg_list.  */
+static bool
+check_host_association (gfc_expr *e)
+{
+  gfc_symbol *sym, *old_sym;
+  locus temp_locus;
+  gfc_expr *expr;
+  int n;
+  bool retval = e->expr_type == EXPR_FUNCTION;
+
+  if (e->symtree == NULL || e->symtree->n.sym == NULL)
+    return retval;
+
+  old_sym = e->symtree->n.sym;
+
+  if (old_sym->attr.use_assoc)
+    return retval;
+
+  if (gfc_current_ns->parent
+       && gfc_current_ns->parent->parent
+       && old_sym->ns != gfc_current_ns)
+    {
+      gfc_find_symbol (old_sym->name, gfc_current_ns->parent, 1, &sym);
+      if (sym && old_sym != sym && sym->attr.flavor == FL_PROCEDURE)
+       {
+         temp_locus = gfc_current_locus;
+         gfc_current_locus = e->where;
+
+         gfc_buffer_error (1);
+
+         gfc_free_ref_list (e->ref);
+         e->ref = NULL;
+
+         if (retval)
+           {
+             gfc_free_actual_arglist (e->value.function.actual);
+             e->value.function.actual = NULL;
+           }
+
+         if (e->shape != NULL)
+           {
+             for (n = 0; n < e->rank; n++)
+               mpz_clear (e->shape[n]);
+
+             gfc_free (e->shape);
+           }
+
+         gfc_match_rvalue (&expr);
+         gfc_clear_error ();
+         gfc_buffer_error (0);
+
+         gcc_assert (expr && sym == expr->symtree->n.sym);
+
+         *e = *expr;
+         gfc_free (expr);
+         sym->refs++;
+
+         gfc_current_locus = temp_locus;
+       }
+    }
+  /* This might have changed!  */
+  return e->expr_type == EXPR_FUNCTION;
+}
+
+
 /* Resolve an expression.  That is, make sure that types of operands agree
    with their operators, intrinsic operators are converted to function calls
    for overloaded types and unresolved function references are resolved.  */
@@ -3193,13 +3843,16 @@ gfc_resolve_expr (gfc_expr *e)
       break;
 
     case EXPR_FUNCTION:
-      t = resolve_function (e);
-      break;
-
     case EXPR_VARIABLE:
-      t = resolve_variable (e);
-      if (t == SUCCESS)
-       expression_rank (e);
+
+      if (check_host_association (e))
+       t = resolve_function (e);
+      else
+       {
+         t = resolve_variable (e);
+         if (t == SUCCESS)
+           expression_rank (e);
+       }
       break;
 
     case EXPR_SUBSTRING:
@@ -3225,7 +3878,7 @@ gfc_resolve_expr (gfc_expr *e)
        }
 
       /* This provides the opportunity for the length of constructors with
-        character valued function elements to propogate the string length
+        character valued function elements to propagate the string length
         to the expression.  */
       if (e->ts.type == BT_CHARACTER)
        gfc_resolve_character_array_constructor (e);
@@ -3268,15 +3921,26 @@ gfc_resolve_iterator_expr (gfc_expr *expr, bool real_ok,
       return FAILURE;
     }
 
-  if (!(expr->ts.type == BT_INTEGER
-       || (expr->ts.type == BT_REAL && real_ok)))
+  if (expr->ts.type != BT_INTEGER)
     {
-      if (real_ok)
-       gfc_error ("%s at %L must be INTEGER or REAL", _(name_msgid),
-                  &expr->where);
+      if (expr->ts.type == BT_REAL)
+       {
+         if (real_ok)
+           return gfc_notify_std (GFC_STD_F95_DEL,
+                                  "Deleted feature: %s at %L must be integer",
+                                  _(name_msgid), &expr->where);
+         else
+           {
+             gfc_error ("%s at %L must be INTEGER", _(name_msgid),
+                        &expr->where);
+             return FAILURE;
+           }
+       }
       else
-       gfc_error ("%s at %L must be INTEGER", _(name_msgid), &expr->where);
-      return FAILURE;
+       {
+         gfc_error ("%s at %L must be INTEGER", _(name_msgid), &expr->where);
+         return FAILURE;
+       }
     }
   return SUCCESS;
 }
@@ -3288,11 +3952,6 @@ gfc_resolve_iterator_expr (gfc_expr *expr, bool real_ok,
 try
 gfc_resolve_iterator (gfc_iterator *iter, bool real_ok)
 {
-
-  if (iter->var->ts.type == BT_REAL)
-    gfc_notify_std (GFC_STD_F95_DEL, "Obsolete: REAL DO loop iterator at %L",
-                   &iter->var->where);
-
   if (gfc_resolve_iterator_expr (iter->var, real_ok, "Loop variable")
       == FAILURE)
     return FAILURE;
@@ -4375,33 +5034,63 @@ resolve_transfer (gfc_code *code)
 
 /*********** Toplevel code resolution subroutines ***********/
 
+/* Find the set of labels that are reachable from this block.  We also
+   record the last statement in each block so that we don't have to do
+   a linear search to find the END DO statements of the blocks.  */
+     
+static void
+reachable_labels (gfc_code *block)
+{
+  gfc_code *c;
+
+  if (!block)
+    return;
+
+  cs_base->reachable_labels = bitmap_obstack_alloc (&labels_obstack);
+
+  /* Collect labels in this block.  */
+  for (c = block; c; c = c->next)
+    {
+      if (c->here)
+       bitmap_set_bit (cs_base->reachable_labels, c->here->value);
+
+      if (!c->next && cs_base->prev)
+       cs_base->prev->tail = c;
+    }
+
+  /* Merge with labels from parent block.  */
+  if (cs_base->prev)
+    {
+      gcc_assert (cs_base->prev->reachable_labels);
+      bitmap_ior_into (cs_base->reachable_labels,
+                      cs_base->prev->reachable_labels);
+    }
+}
+
 /* Given a branch to a label and a namespace, if the branch is conforming.
-   The code node described where the branch is located.  */
+   The code node describes where the branch is located.  */
 
 static void
 resolve_branch (gfc_st_label *label, gfc_code *code)
 {
-  gfc_code *block, *found;
   code_stack *stack;
-  gfc_st_label *lp;
 
   if (label == NULL)
     return;
-  lp = label;
 
   /* Step one: is this a valid branching target?  */
 
-  if (lp->defined == ST_LABEL_UNKNOWN)
+  if (label->defined == ST_LABEL_UNKNOWN)
     {
-      gfc_error ("Label %d referenced at %L is never defined", lp->value,
-                &lp->where);
+      gfc_error ("Label %d referenced at %L is never defined", label->value,
+                &label->where);
       return;
     }
 
-  if (lp->defined != ST_LABEL_TARGET)
+  if (label->defined != ST_LABEL_TARGET)
     {
       gfc_error ("Statement at %L is not a valid branch target statement "
-                "for the branch statement at %L", &lp->where, &code->loc);
+                "for the branch statement at %L", &label->where, &code->loc);
       return;
     }
 
@@ -4413,52 +5102,50 @@ resolve_branch (gfc_st_label *label, gfc_code *code)
       return;
     }
 
-  /* Step three: Try to find the label in the parse tree. To do this,
-     we traverse the tree block-by-block: first the block that
-     contains this GOTO, then the block that it is nested in, etc.  We
-     can ignore other blocks because branching into another block is
-     not allowed.  */
+  /* Step three:  See if the label is in the same block as the
+     branching statement.  The hard work has been done by setting up
+     the bitmap reachable_labels.  */
 
-  found = NULL;
-
-  for (stack = cs_base; stack; stack = stack->prev)
-    {
-      for (block = stack->head; block; block = block->next)
-       {
-         if (block->here == label)
-           {
-             found = block;
-             break;
-           }
-       }
-
-      if (found)
-       break;
-    }
-
-  if (found == NULL)
+  if (!bitmap_bit_p (cs_base->reachable_labels, label->value))
     {
       /* The label is not in an enclosing block, so illegal.  This was
-        allowed in Fortran 66, so we allow it as extension.  We also 
-        forego further checks if we run into this.  */
+        allowed in Fortran 66, so we allow it as extension.  No
+        further checks are necessary in this case.  */
       gfc_notify_std (GFC_STD_LEGACY, "Label at %L is not in the same block "
-                     "as the GOTO statement at %L", &lp->where, &code->loc);
+                     "as the GOTO statement at %L", &label->where,
+                     &code->loc);
       return;
     }
 
   /* Step four: Make sure that the branching target is legal if
-     the statement is an END {SELECT,DO,IF}.  */
+     the statement is an END {SELECT,IF}.  */
 
-  if (found->op == EXEC_NOP)
-    {
-      for (stack = cs_base; stack; stack = stack->prev)
-       if (stack->current->next == found)
-         break;
+  for (stack = cs_base; stack; stack = stack->prev)
+    if (stack->current->next && stack->current->next->here == label)
+      break;
 
-      if (stack == NULL)
-       gfc_notify_std (GFC_STD_F95_DEL, "Obsolete: GOTO at %L jumps to END "
-                       "of construct at %L", &code->loc, &found->loc);
+  if (stack && stack->current->next->op == EXEC_NOP)
+    {
+      gfc_notify_std (GFC_STD_F95_DEL, "Deleted feature: GOTO at %L jumps to "
+                     "END of construct at %L", &code->loc,
+                     &stack->current->next->loc);
+      return;  /* We know this is not an END DO.  */
     }
+
+  /* Step five: Make sure that we're not jumping to the end of a DO
+     loop from within the loop.  */
+
+  for (stack = cs_base; stack; stack = stack->prev)
+    if ((stack->current->op == EXEC_DO
+        || stack->current->op == EXEC_DO_WHILE)
+       && stack->tail->here == label && stack->tail->op == EXEC_NOP)
+      {
+       gfc_notify_std (GFC_STD_F95_DEL, "Deleted feature: GOTO at %L jumps "
+                       "to END of construct at %L", &code->loc,
+                       &stack->tail->loc);
+       return;
+
+      }
 }
 
 
@@ -4984,6 +5671,8 @@ resolve_code (gfc_code *code, gfc_namespace *ns)
   frame.head = code;
   cs_base = &frame;
 
+  reachable_labels (code);
+
   for (; code; code = code->next)
     {
       frame.current = code;
@@ -5115,8 +5804,9 @@ resolve_code (gfc_code *code, gfc_namespace *ns)
                rlen = mpz_get_si (code->expr2->ts.cl->length->value.integer);
 
              if (rlen && llen && rlen > llen)
-               gfc_warning_now ("rhs of CHARACTER assignment at %L will be "
-                                "truncated (%d/%d)", &code->loc, rlen, llen);
+               gfc_warning_now ("CHARACTER expression will be truncated "
+                                "in assignment (%d/%d) at %L",
+                                llen, rlen, &code->loc);
            }
 
          if (gfc_pure (NULL))
@@ -5130,17 +5820,20 @@ resolve_code (gfc_code *code, gfc_namespace *ns)
                  break;
                }
 
-             if (code->expr2->ts.type == BT_DERIVED
-                 && derived_pointer (code->expr2->ts.derived))
+             if (code->expr->ts.type == BT_DERIVED
+                   && code->expr->expr_type == EXPR_VARIABLE
+                   && derived_pointer (code->expr->ts.derived)
+                   && gfc_impure_variable (code->expr2->symtree->n.sym))
                {
-                 gfc_error ("Right side of assignment at %L is a derived "
-                            "type containing a POINTER in a PURE procedure",
+                 gfc_error ("The impure variable at %L is assigned to "
+                            "a derived type variable with a POINTER "
+                            "component in a PURE procedure (12.6)",
                             &code->expr2->where);
                  break;
                }
            }
 
-         gfc_check_assign (code->expr, code->expr2, 1);
+           gfc_check_assign (code->expr, code->expr2, 1);
          break;
 
        case EXEC_LABEL_ASSIGN:
@@ -5346,6 +6039,206 @@ resolve_values (gfc_symbol *sym)
 }
 
 
+/* Verify the binding labels for common blocks that are BIND(C).  The label
+   for a BIND(C) common block must be identical in all scoping units in which
+   the common block is declared.  Further, the binding label can not collide
+   with any other global entity in the program.  */
+
+static void
+resolve_bind_c_comms (gfc_symtree *comm_block_tree)
+{
+  if (comm_block_tree->n.common->is_bind_c == 1)
+    {
+      gfc_gsymbol *binding_label_gsym;
+      gfc_gsymbol *comm_name_gsym;
+
+      /* See if a global symbol exists by the common block's name.  It may
+         be NULL if the common block is use-associated.  */
+      comm_name_gsym = gfc_find_gsymbol (gfc_gsym_root,
+                                         comm_block_tree->n.common->name);
+      if (comm_name_gsym != NULL && comm_name_gsym->type != GSYM_COMMON)
+        gfc_error ("Binding label '%s' for common block '%s' at %L collides "
+                   "with the global entity '%s' at %L",
+                   comm_block_tree->n.common->binding_label,
+                   comm_block_tree->n.common->name,
+                   &(comm_block_tree->n.common->where),
+                   comm_name_gsym->name, &(comm_name_gsym->where));
+      else if (comm_name_gsym != NULL
+              && strcmp (comm_name_gsym->name,
+                         comm_block_tree->n.common->name) == 0)
+        {
+          /* TODO: Need to make sure the fields of gfc_gsymbol are initialized
+             as expected.  */
+          if (comm_name_gsym->binding_label == NULL)
+            /* No binding label for common block stored yet; save this one.  */
+            comm_name_gsym->binding_label =
+              comm_block_tree->n.common->binding_label;
+          else
+            if (strcmp (comm_name_gsym->binding_label,
+                        comm_block_tree->n.common->binding_label) != 0)
+              {
+                /* Common block names match but binding labels do not.  */
+                gfc_error ("Binding label '%s' for common block '%s' at %L "
+                           "does not match the binding label '%s' for common "
+                           "block '%s' at %L",
+                           comm_block_tree->n.common->binding_label,
+                           comm_block_tree->n.common->name,
+                           &(comm_block_tree->n.common->where),
+                           comm_name_gsym->binding_label,
+                           comm_name_gsym->name,
+                           &(comm_name_gsym->where));
+                return;
+              }
+        }
+
+      /* There is no binding label (NAME="") so we have nothing further to
+         check and nothing to add as a global symbol for the label.  */
+      if (comm_block_tree->n.common->binding_label[0] == '\0' )
+        return;
+      
+      binding_label_gsym =
+        gfc_find_gsymbol (gfc_gsym_root,
+                          comm_block_tree->n.common->binding_label);
+      if (binding_label_gsym == NULL)
+        {
+          /* Need to make a global symbol for the binding label to prevent
+             it from colliding with another.  */
+          binding_label_gsym =
+            gfc_get_gsymbol (comm_block_tree->n.common->binding_label);
+          binding_label_gsym->sym_name = comm_block_tree->n.common->name;
+          binding_label_gsym->type = GSYM_COMMON;
+        }
+      else
+        {
+          /* If comm_name_gsym is NULL, the name common block is use
+             associated and the name could be colliding.  */
+          if (binding_label_gsym->type != GSYM_COMMON)
+            gfc_error ("Binding label '%s' for common block '%s' at %L "
+                       "collides with the global entity '%s' at %L",
+                       comm_block_tree->n.common->binding_label,
+                       comm_block_tree->n.common->name,
+                       &(comm_block_tree->n.common->where),
+                       binding_label_gsym->name,
+                       &(binding_label_gsym->where));
+          else if (comm_name_gsym != NULL
+                  && (strcmp (binding_label_gsym->name,
+                              comm_name_gsym->binding_label) != 0)
+                  && (strcmp (binding_label_gsym->sym_name,
+                              comm_name_gsym->name) != 0))
+            gfc_error ("Binding label '%s' for common block '%s' at %L "
+                       "collides with global entity '%s' at %L",
+                       binding_label_gsym->name, binding_label_gsym->sym_name,
+                       &(comm_block_tree->n.common->where),
+                       comm_name_gsym->name, &(comm_name_gsym->where));
+        }
+    }
+  
+  return;
+}
+
+
+/* Verify any BIND(C) derived types in the namespace so we can report errors
+   for them once, rather than for each variable declared of that type.  */
+
+static void
+resolve_bind_c_derived_types (gfc_symbol *derived_sym)
+{
+  if (derived_sym != NULL && derived_sym->attr.flavor == FL_DERIVED
+      && derived_sym->attr.is_bind_c == 1)
+    verify_bind_c_derived_type (derived_sym);
+  
+  return;
+}
+
+
+/* Verify that any binding labels used in a given namespace do not collide 
+   with the names or binding labels of any global symbols.  */
+
+static void
+gfc_verify_binding_labels (gfc_symbol *sym)
+{
+  int has_error = 0;
+  
+  if (sym != NULL && sym->attr.is_bind_c && sym->attr.is_iso_c == 0 
+      && sym->attr.flavor != FL_DERIVED && sym->binding_label[0] != '\0')
+    {
+      gfc_gsymbol *bind_c_sym;
+
+      bind_c_sym = gfc_find_gsymbol (gfc_gsym_root, sym->binding_label);
+      if (bind_c_sym != NULL 
+          && strcmp (bind_c_sym->name, sym->binding_label) == 0)
+        {
+          if (sym->attr.if_source == IFSRC_DECL 
+              && (bind_c_sym->type != GSYM_SUBROUTINE 
+                  && bind_c_sym->type != GSYM_FUNCTION) 
+              && ((sym->attr.contained == 1 
+                   && strcmp (bind_c_sym->sym_name, sym->name) != 0) 
+                  || (sym->attr.use_assoc == 1 
+                      && (strcmp (bind_c_sym->mod_name, sym->module) != 0))))
+            {
+              /* Make sure global procedures don't collide with anything.  */
+              gfc_error ("Binding label '%s' at %L collides with the global "
+                         "entity '%s' at %L", sym->binding_label,
+                         &(sym->declared_at), bind_c_sym->name,
+                         &(bind_c_sym->where));
+              has_error = 1;
+            }
+          else if (sym->attr.contained == 0 
+                   && (sym->attr.if_source == IFSRC_IFBODY 
+                       && sym->attr.flavor == FL_PROCEDURE) 
+                   && (bind_c_sym->sym_name != NULL 
+                       && strcmp (bind_c_sym->sym_name, sym->name) != 0))
+            {
+              /* Make sure procedures in interface bodies don't collide.  */
+              gfc_error ("Binding label '%s' in interface body at %L collides "
+                         "with the global entity '%s' at %L",
+                         sym->binding_label,
+                         &(sym->declared_at), bind_c_sym->name,
+                         &(bind_c_sym->where));
+              has_error = 1;
+            }
+          else if (sym->attr.contained == 0 
+                   && (sym->attr.if_source == IFSRC_UNKNOWN))
+            if ((sym->attr.use_assoc 
+                 && (strcmp (bind_c_sym->mod_name, sym->module) != 0)) 
+                || sym->attr.use_assoc == 0)
+              {
+                gfc_error ("Binding label '%s' at %L collides with global "
+                           "entity '%s' at %L", sym->binding_label,
+                           &(sym->declared_at), bind_c_sym->name,
+                           &(bind_c_sym->where));
+                has_error = 1;
+              }
+
+          if (has_error != 0)
+            /* Clear the binding label to prevent checking multiple times.  */
+            sym->binding_label[0] = '\0';
+        }
+      else if (bind_c_sym == NULL)
+       {
+         bind_c_sym = gfc_get_gsymbol (sym->binding_label);
+         bind_c_sym->where = sym->declared_at;
+         bind_c_sym->sym_name = sym->name;
+
+          if (sym->attr.use_assoc == 1)
+            bind_c_sym->mod_name = sym->module;
+          else
+            if (sym->ns->proc_name != NULL)
+              bind_c_sym->mod_name = sym->ns->proc_name->name;
+
+          if (sym->attr.contained == 0)
+            {
+              if (sym->attr.subroutine)
+                bind_c_sym->type = GSYM_SUBROUTINE;
+              else if (sym->attr.function)
+                bind_c_sym->type = GSYM_FUNCTION;
+            }
+        }
+    }
+  return;
+}
+
+
 /* Resolve an index expression.  */
 
 static try
@@ -5368,6 +6261,8 @@ resolve_index_expr (gfc_expr *e)
 static try
 resolve_charlen (gfc_charlen *cl)
 {
+  int i;
+
   if (cl->resolved)
     return SUCCESS;
 
@@ -5381,11 +6276,20 @@ resolve_charlen (gfc_charlen *cl)
       return FAILURE;
     }
 
+  /* "If the character length parameter value evaluates to a negative
+     value, the length of character entities declared is zero."  */
+  if (cl->length && !gfc_extract_int (cl->length, &i) && i <= 0)
+    {
+      gfc_warning_now ("CHARACTER variable has zero length at %L",
+                      &cl->length->where);
+      gfc_replace_expr (cl->length, gfc_int_expr (0));
+    }
+
   return SUCCESS;
 }
 
 
-/* Test for non-constant shape arrays. */
+/* Test for non-constant shape arrays.  */
 
 static bool
 is_non_constant_shape_array (gfc_symbol *sym)
@@ -5485,7 +6389,7 @@ apply_default_init (gfc_symbol *sym)
 }
 
 
-/* Resolution of common features of flavors variable and procedure. */
+/* Resolution of common features of flavors variable and procedure.  */
 
 static try
 resolve_fl_var_and_proc (gfc_symbol *sym, int mp_flag)
@@ -5526,6 +6430,21 @@ resolve_fl_var_and_proc (gfc_symbol *sym, int mp_flag)
 }
 
 
+static gfc_component *
+has_default_initializer (gfc_symbol *der)
+{
+  gfc_component *c;
+  for (c = der->components; c; c = c->next)
+    if ((c->ts.type != BT_DERIVED && c->initializer)
+        || (c->ts.type == BT_DERIVED
+              && !c->pointer
+              && has_default_initializer (c->ts.derived)))
+      break;
+
+  return c;
+}
+
+
 /* Resolve symbols with flavor variable.  */
 
 static try
@@ -5534,7 +6453,7 @@ resolve_fl_variable (gfc_symbol *sym, int mp_flag)
   int flag;
   int i;
   gfc_expr *e;
-  gfc_expr *constructor_expr;
+  gfc_component *c;
   const char *auto_save_msg;
 
   auto_save_msg = "automatic object '%s' at %L cannot have the "
@@ -5613,13 +6532,14 @@ resolve_fl_variable (gfc_symbol *sym, int mp_flag)
              || sym->as->upper[i] == NULL
              || sym->as->upper[i]->expr_type != EXPR_CONSTANT)
            {
-             flag = 1;
+             flag = 2;
              break;
            }
        }
 
-      /* Also, they must not have the SAVE attribute.  */
-      if (flag && sym->attr.save)
+      /* Also, they must not have the SAVE attribute.
+        SAVE_IMPLICIT is checked below.  */
+      if (flag && sym->attr.save == SAVE_EXPLICIT)
        {
          gfc_error (auto_save_msg, sym->name, &sym->declared_at);
          return FAILURE;
@@ -5627,7 +6547,7 @@ resolve_fl_variable (gfc_symbol *sym, int mp_flag)
   }
 
   /* Reject illegal initializers.  */
-  if (sym->value && flag)
+  if (!sym->mark && sym->value && flag)
     {
       if (sym->attr.allocatable)
        gfc_error ("Allocatable '%s' at %L cannot have an initializer",
@@ -5635,7 +6555,8 @@ resolve_fl_variable (gfc_symbol *sym, int mp_flag)
       else if (sym->attr.external)
        gfc_error ("External '%s' at %L cannot have an initializer",
                   sym->name, &sym->declared_at);
-      else if (sym->attr.dummy)
+      else if (sym->attr.dummy
+       && !(sym->ts.type == BT_DERIVED && sym->attr.intent == INTENT_OUT))
        gfc_error ("Dummy '%s' at %L cannot have an initializer",
                   sym->name, &sym->declared_at);
       else if (sym->attr.intrinsic)
@@ -5644,16 +6565,20 @@ resolve_fl_variable (gfc_symbol *sym, int mp_flag)
       else if (sym->attr.result)
        gfc_error ("Function result '%s' at %L cannot have an initializer",
                   sym->name, &sym->declared_at);
-      else
+      else if (flag == 2)
        gfc_error ("Automatic array '%s' at %L cannot have an initializer",
                   sym->name, &sym->declared_at);
+      else
+       goto no_init_error;
       return FAILURE;
     }
 
+no_init_error:
   /* Check to see if a derived type is blocked from being host associated
      by the presence of another class I symbol in the same namespace.
      14.6.1.3 of the standard and the discussion on comp.lang.fortran.  */
-  if (sym->ts.type == BT_DERIVED && sym->ns != sym->ts.derived->ns)
+  if (sym->ts.type == BT_DERIVED && sym->ns != sym->ts.derived->ns
+       && sym->ns->proc_name->attr.if_source != IFSRC_IFBODY)
     {
       gfc_symbol *s;
       gfc_find_symbol (sym->ts.derived->name, sym->ns, 0, &s);
@@ -5668,18 +6593,19 @@ resolve_fl_variable (gfc_symbol *sym, int mp_flag)
        }
     }
 
+  /* Do not use gfc_default_initializer to test for a default initializer
+     in the fortran because it generates a hidden default for allocatable
+     components.  */
+  c = NULL;
+  if (sym->ts.type == BT_DERIVED && !(sym->value || flag))
+    c = has_default_initializer (sym->ts.derived);
+
   /* 4th constraint in section 11.3:  "If an object of a type for which
      component-initialization is specified (R429) appears in the
      specification-part of a module and does not have the ALLOCATABLE
      or POINTER attribute, the object shall have the SAVE attribute."  */
-
-  constructor_expr = NULL;
-  if (sym->ts.type == BT_DERIVED && !(sym->value || flag))
-    constructor_expr = gfc_default_initializer (&sym->ts);
-
-  if (sym->ns->proc_name
+  if (c && sym->ns->proc_name
       && sym->ns->proc_name->attr.flavor == FL_MODULE
-      && constructor_expr
       && !sym->ns->save_all && !sym->attr.save
       && !sym->attr.pointer && !sym->attr.allocatable)
     {
@@ -5719,6 +6645,11 @@ resolve_fl_procedure (gfc_symbol *sym, int mp_flag)
   if (sym->ts.type == BT_CHARACTER)
     {
       gfc_charlen *cl = sym->ts.cl;
+
+      if (cl && cl->length && gfc_is_constant_expr (cl->length)
+            && resolve_charlen (cl) == FAILURE)
+       return FAILURE;
+
       if (!cl || !cl->length || cl->length->expr_type != EXPR_CONSTANT)
        {
          if (sym->attr.proc == PROC_ST_FUNCTION)
@@ -5742,11 +6673,13 @@ resolve_fl_procedure (gfc_symbol *sym, int mp_flag)
   /* Ensure that derived type for are not of a private type.  Internal
      module procedures are excluded by 2.2.3.3 - ie. they are not
      externally accessible and can access all the objects accessible in
-     the host. */
+     the host.  */
   if (!(sym->ns->parent
        && sym->ns->parent->proc_name->attr.flavor == FL_MODULE)
       && gfc_check_access(sym->attr.access, sym->ns->default_access))
     {
+      gfc_interface *iface;
+
       for (arg = sym->formal; arg; arg = arg->next)
        {
          if (arg->sym
@@ -5764,6 +6697,59 @@ resolve_fl_procedure (gfc_symbol *sym, int mp_flag)
              return FAILURE;
            }
        }
+
+      /* PUBLIC interfaces may expose PRIVATE procedures that take types
+        PRIVATE to the containing module.  */
+      for (iface = sym->generic; iface; iface = iface->next)
+       {
+         for (arg = iface->sym->formal; arg; arg = arg->next)
+           {
+             if (arg->sym
+                 && arg->sym->ts.type == BT_DERIVED
+                 && !arg->sym->ts.derived->attr.use_assoc
+                 && !gfc_check_access (arg->sym->ts.derived->attr.access,
+                                       arg->sym->ts.derived->ns->default_access))
+               {
+                 gfc_error_now ("Procedure '%s' in PUBLIC interface '%s' at %L takes "
+                                "dummy arguments of '%s' which is PRIVATE",
+                                iface->sym->name, sym->name, &iface->sym->declared_at,
+                                gfc_typename(&arg->sym->ts));
+                 /* Stop this message from recurring.  */
+                 arg->sym->ts.derived->attr.access = ACCESS_PUBLIC;
+                 return FAILURE;
+               }
+            }
+       }
+
+      /* PUBLIC interfaces may expose PRIVATE procedures that take types
+        PRIVATE to the containing module.  */
+      for (iface = sym->generic; iface; iface = iface->next)
+       {
+         for (arg = iface->sym->formal; arg; arg = arg->next)
+           {
+             if (arg->sym
+                 && arg->sym->ts.type == BT_DERIVED
+                 && !arg->sym->ts.derived->attr.use_assoc
+                 && !gfc_check_access (arg->sym->ts.derived->attr.access,
+                                       arg->sym->ts.derived->ns->default_access))
+               {
+                 gfc_error_now ("Procedure '%s' in PUBLIC interface '%s' at %L takes "
+                                "dummy arguments of '%s' which is PRIVATE",
+                                iface->sym->name, sym->name, &iface->sym->declared_at,
+                                gfc_typename(&arg->sym->ts));
+                 /* Stop this message from recurring.  */
+                 arg->sym->ts.derived->attr.access = ACCESS_PUBLIC;
+                 return FAILURE;
+               }
+            }
+       }
+    }
+
+  if (sym->attr.function && sym->value && sym->attr.proc != PROC_ST_FUNCTION)
+    {
+      gfc_error ("Function '%s' at %L cannot have an initializer",
+                sym->name, &sym->declared_at);
+      return FAILURE;
     }
 
   /* An external symbol may not have an initializer because it is taken to be
@@ -5824,6 +6810,53 @@ resolve_fl_procedure (gfc_symbol *sym, int mp_flag)
                        "'%s' at %L is obsolescent in fortran 95",
                        sym->name, &sym->declared_at);
     }
+
+  if (sym->attr.is_bind_c && sym->attr.is_c_interop != 1)
+    {
+      gfc_formal_arglist *curr_arg;
+      int has_non_interop_arg = 0;
+
+      if (verify_bind_c_sym (sym, &(sym->ts), sym->attr.in_common,
+                             sym->common_block) == FAILURE)
+        {
+          /* Clear these to prevent looking at them again if there was an
+             error.  */
+          sym->attr.is_bind_c = 0;
+          sym->attr.is_c_interop = 0;
+          sym->ts.is_c_interop = 0;
+        }
+      else
+        {
+          /* So far, no errors have been found.  */
+          sym->attr.is_c_interop = 1;
+          sym->ts.is_c_interop = 1;
+        }
+      
+      curr_arg = sym->formal;
+      while (curr_arg != NULL)
+        {
+          /* Skip implicitly typed dummy args here.  */
+         if (curr_arg->sym->attr.implicit_type == 0)
+           if (verify_c_interop_param (curr_arg->sym) == FAILURE)
+             /* If something is found to fail, record the fact so we
+                can mark the symbol for the procedure as not being
+                BIND(C) to try and prevent multiple errors being
+                reported.  */
+             has_non_interop_arg = 1;
+          
+          curr_arg = curr_arg->next;
+        }
+
+      /* See if any of the arguments were not interoperable and if so, clear
+        the procedure symbol to prevent duplicate error messages.  */
+      if (has_non_interop_arg != 0)
+       {
+         sym->attr.is_c_interop = 0;
+         sym->ts.is_c_interop = 0;
+         sym->attr.is_bind_c = 0;
+       }
+    }
+  
   return SUCCESS;
 }
 
@@ -5907,16 +6940,16 @@ resolve_fl_derived (gfc_symbol *sym)
     }
 
   /* Add derived type to the derived type list.  */
-  for (dt_list = sym->ns->derived_types; dt_list; dt_list = dt_list->next)
+  for (dt_list = gfc_derived_types; dt_list; dt_list = dt_list->next)
     if (sym == dt_list->derived)
       break;
 
   if (dt_list == NULL)
     {
       dt_list = gfc_get_dt_list ();
-      dt_list->next = sym->ns->derived_types;
+      dt_list->next = gfc_derived_types;
       dt_list->derived = sym;
-      sym->ns->derived_types = dt_list;
+      gfc_derived_types = dt_list;
     }
 
   return SUCCESS;
@@ -5972,16 +7005,21 @@ resolve_fl_namelist (gfc_symbol *sym)
     }
 
   /* 14.1.2 A module or internal procedure represent local entities
-     of the same type as a namelist member and so are not allowed.
-     Note that this is sometimes caught by check_conflict so the
-     same message has been used.  */
+     of the same type as a namelist member and so are not allowed.  */
   for (nl = sym->namelist; nl; nl = nl->next)
     {
       if (nl->sym->ts.kind != 0 && nl->sym->attr.flavor == FL_VARIABLE)
        continue;
+
+      if (nl->sym->attr.function && nl->sym == nl->sym->result)
+       if ((nl->sym == sym->ns->proc_name)
+              ||
+           (sym->ns->parent && nl->sym == sym->ns->parent->proc_name))
+         continue;
+
       nlsym = NULL;
-      if (sym->ns->parent && nl->sym && nl->sym->name)
-       gfc_find_symbol (nl->sym->name, sym->ns->parent, 0, &nlsym);
+      if (nl->sym && nl->sym->name)
+       gfc_find_symbol (nl->sym->name, sym->ns, 1, &nlsym);
       if (nlsym && nlsym->attr.flavor == FL_PROCEDURE)
        {
          gfc_error ("PROCEDURE attribute conflicts with NAMELIST "
@@ -6038,9 +7076,7 @@ resolve_fl_parameter (gfc_symbol *sym)
 static void
 resolve_symbol (gfc_symbol *sym)
 {
-  /* Zero if we are checking a formal namespace.  */
-  static int formal_ns_flag = 1;
-  int formal_ns_save, check_constant, mp_flag;
+  int check_constant, mp_flag;
   gfc_symtree *symtree;
   gfc_symtree *this_symtree;
   gfc_namespace *ns;
@@ -6090,6 +7126,34 @@ resolve_symbol (gfc_symbol *sym)
      can.  */
   mp_flag = (sym->result != NULL && sym->result != sym);
 
+
+  /* Make sure that the intrinsic is consistent with its internal 
+     representation. This needs to be done before assigning a default 
+     type to avoid spurious warnings.  */
+  if (sym->attr.flavor != FL_MODULE && sym->attr.intrinsic)
+    {
+      if (gfc_intrinsic_name (sym->name, 0))
+       {
+         if (sym->ts.type != BT_UNKNOWN && gfc_option.warn_surprising)
+           gfc_warning ("Type specified for intrinsic function '%s' at %L is ignored",
+                        sym->name, &sym->declared_at);
+       }
+      else if (gfc_intrinsic_name (sym->name, 1))
+       {
+         if (sym->ts.type != BT_UNKNOWN)
+           {
+             gfc_error ("Intrinsic subroutine '%s' at %L shall not have a type specifier", 
+                        sym->name, &sym->declared_at);
+             return;
+           }
+       }
+      else
+       {
+         gfc_error ("Intrinsic '%s' at %L does not exist", sym->name, &sym->declared_at);
+         return;
+       }
+     }
+
   /* Assign default type to symbols that need one and don't have one.  */
   if (sym->ts.type == BT_UNKNOWN)
     {
@@ -6147,10 +7211,92 @@ resolve_symbol (gfc_symbol *sym)
   if (sym->attr.value && !sym->attr.dummy)
     {
       gfc_error ("'%s' at %L cannot have the VALUE attribute because "
-                "it is not a dummy", sym->name, &sym->declared_at);
+                "it is not a dummy argument", sym->name, &sym->declared_at);
       return;
     }
 
+  if (sym->attr.value && sym->ts.type == BT_CHARACTER)
+    {
+      gfc_charlen *cl = sym->ts.cl;
+      if (!cl || !cl->length || cl->length->expr_type != EXPR_CONSTANT)
+       {
+         gfc_error ("Character dummy variable '%s' at %L with VALUE "
+                    "attribute must have constant length",
+                    sym->name, &sym->declared_at);
+         return;
+       }
+
+      if (sym->ts.is_c_interop
+         && mpz_cmp_si (cl->length->value.integer, 1) != 0)
+       {
+         gfc_error ("C interoperable character dummy variable '%s' at %L "
+                    "with VALUE attribute must have length one",
+                    sym->name, &sym->declared_at);
+         return;
+       }
+    }
+
+  /* If the symbol is marked as bind(c), verify it's type and kind.  Do not
+     do this for something that was implicitly typed because that is handled
+     in gfc_set_default_type.  Handle dummy arguments and procedure
+     definitions separately.  Also, anything that is use associated is not
+     handled here but instead is handled in the module it is declared in.
+     Finally, derived type definitions are allowed to be BIND(C) since that
+     only implies that they're interoperable, and they are checked fully for
+     interoperability when a variable is declared of that type.  */
+  if (sym->attr.is_bind_c && sym->attr.implicit_type == 0 &&
+      sym->attr.use_assoc == 0 && sym->attr.dummy == 0 &&
+      sym->attr.flavor != FL_PROCEDURE && sym->attr.flavor != FL_DERIVED)
+    {
+      try t = SUCCESS;
+      
+      /* First, make sure the variable is declared at the
+        module-level scope (J3/04-007, Section 15.3).  */
+      if (sym->ns->proc_name->attr.flavor != FL_MODULE &&
+          sym->attr.in_common == 0)
+       {
+         gfc_error ("Variable '%s' at %L cannot be BIND(C) because it "
+                    "is neither a COMMON block nor declared at the "
+                    "module level scope", sym->name, &(sym->declared_at));
+         t = FAILURE;
+       }
+      else if (sym->common_head != NULL)
+        {
+          t = verify_com_block_vars_c_interop (sym->common_head);
+        }
+      else
+       {
+         /* If type() declaration, we need to verify that the components
+            of the given type are all C interoperable, etc.  */
+         if (sym->ts.type == BT_DERIVED &&
+              sym->ts.derived->attr.is_c_interop != 1)
+            {
+              /* Make sure the user marked the derived type as BIND(C).  If
+                 not, call the verify routine.  This could print an error
+                 for the derived type more than once if multiple variables
+                 of that type are declared.  */
+              if (sym->ts.derived->attr.is_bind_c != 1)
+                verify_bind_c_derived_type (sym->ts.derived);
+              t = FAILURE;
+            }
+         
+         /* Verify the variable itself as C interoperable if it
+             is BIND(C).  It is not possible for this to succeed if
+             the verify_bind_c_derived_type failed, so don't have to handle
+             any error returned by verify_bind_c_derived_type.  */
+          t = verify_bind_c_sym (sym, &(sym->ts), sym->attr.in_common,
+                                 sym->common_block);
+       }
+
+      if (t == FAILURE)
+        {
+          /* clear the is_bind_c flag to prevent reporting errors more than
+             once if something failed.  */
+          sym->attr.is_bind_c = 0;
+          return;
+        }
+    }
+
   /* If a derived type symbol has reached this point, without its
      type being declared, we have an error.  Notice that most
      conditions that produce undefined derived types have already
@@ -6214,12 +7360,6 @@ resolve_symbol (gfc_symbol *sym)
       break;
     }
 
-  /* Make sure that intrinsic exist */
-  if (sym->attr.flavor != FL_MODULE && sym->attr.intrinsic
-      && !gfc_intrinsic_name(sym->name, 0)
-      && !gfc_intrinsic_name(sym->name, 1))
-    gfc_error("Intrinsic at %L does not exist", &sym->declared_at);
-
   /* Resolve array specifier. Check as well some constraints
      on COMMON blocks.  */
 
@@ -6236,17 +7376,11 @@ resolve_symbol (gfc_symbol *sym)
   formal_arg_flag = 0;
 
   /* Resolve formal namespaces.  */
-
-  if (formal_ns_flag && sym != NULL && sym->formal_ns != NULL)
-    {
-      formal_ns_save = formal_ns_flag;
-      formal_ns_flag = 0;
-      gfc_resolve (sym->formal_ns);
-      formal_ns_flag = formal_ns_save;
-    }
+  if (sym->formal_ns && sym->formal_ns != gfc_current_ns)
+    gfc_resolve (sym->formal_ns);
 
   /* Check threadprivate restrictions.  */
-  if (sym->attr.threadprivate && !sym->attr.save
+  if (sym->attr.threadprivate && !sym->attr.save && !sym->ns->save_all
       && (!sym->attr.in_common
          && sym->module == NULL
          && (sym->ns->proc_name == NULL
@@ -6431,7 +7565,9 @@ check_data_variable (gfc_data_variable *var, locus *where)
          values.left -= 1;
          mpz_sub_ui (size, size, 1);
 
-         gfc_assign_data_value (var->expr, values.vnode->expr, offset);
+         t = gfc_assign_data_value (var->expr, values.vnode->expr, offset);
+         if (t == FAILURE)
+           break;
 
          if (mark == AR_FULL)
            mpz_add_ui (offset, offset, 1);
@@ -6618,21 +7754,36 @@ resolve_data (gfc_data * d)
 }
 
 
+/* 12.6 Constraint: In a pure subprogram any variable which is in common or
+   accessed by host or use association, is a dummy argument to a pure function,
+   is a dummy argument with INTENT (IN) to a pure subroutine, or an object that
+   is storage associated with any such variable, shall not be used in the
+   following contexts: (clients of this function).  */
+
 /* Determines if a variable is not 'pure', ie not assignable within a pure
    procedure.  Returns zero if assignment is OK, nonzero if there is a
    problem.  */
-
 int
 gfc_impure_variable (gfc_symbol *sym)
 {
+  gfc_symbol *proc;
+
   if (sym->attr.use_assoc || sym->attr.in_common)
     return 1;
 
   if (sym->ns != gfc_current_ns)
     return !sym->attr.function;
 
-  /* TODO: Check storage association through EQUIVALENCE statements */
+  proc = sym->ns->proc_name;
+  if (sym->attr.dummy && gfc_pure (proc)
+       && ((proc->attr.subroutine && sym->attr.intent == INTENT_IN)
+               ||
+            proc->attr.function))
+    return 1;
 
+  /* TODO: Sort out what can be storage associated, if anything, and include
+     it here.  In principle equivalences should be scanned but it does not
+     seem to be possible to storage associate an impure variable this way.  */
   return 0;
 }
 
@@ -6785,7 +7936,7 @@ resolve_equivalence_derived (gfc_symbol *derived, gfc_symbol *sym, gfc_expr *e)
       return FAILURE;
     }
 
-  /* Shall not have allocatable components. */
+  /* Shall not have allocatable components.  */
   if (derived->attr.alloc_comp)
     {
       gfc_error ("Derived type variable '%s' at %L cannot have ALLOCATABLE "
@@ -6810,14 +7961,6 @@ resolve_equivalence_derived (gfc_symbol *derived, gfc_symbol *sym, gfc_expr *e)
                     sym->name, &e->where);
          return FAILURE;
        }
-
-      if (c->initializer)
-       {
-         gfc_error ("Derived type variable '%s' at %L with default "
-                    "initializer cannot be an EQUIVALENCE object",
-                    sym->name, &e->where);
-         return FAILURE;
-       }
     }
   return SUCCESS;
 }
@@ -6940,21 +8083,6 @@ resolve_equivalence (gfc_equiv *eq)
              break;
        }
 
-      /* An equivalence statement cannot have more than one initialized
-        object.  */
-      if (sym->value)
-       {
-         if (value_name != NULL)
-           {
-             gfc_error ("Initialized objects '%s' and '%s' cannot both "
-                        "be in the EQUIVALENCE statement at %L",
-                        value_name, sym->name, &e->where);
-             continue;
-           }
-         else
-           value_name = sym->name;
-       }
-
       /* Shall not equivalence common block variables in a PURE procedure.  */
       if (sym->ns->proc_name
          && sym->ns->proc_name->attr.pure
@@ -7081,7 +8209,7 @@ resolve_equivalence (gfc_equiv *eq)
 }
 
 
-/* Resolve function and ENTRY types, issue diagnostics if needed. */
+/* Resolve function and ENTRY types, issue diagnostics if needed.  */
 
 static void
 resolve_fntype (gfc_namespace *ns)
@@ -7117,22 +8245,7 @@ resolve_fntype (gfc_namespace *ns)
                 sym->name, &sym->declared_at, sym->ts.derived->name);
     }
 
-  /* Make sure that the type of a module derived type function is in the
-     module namespace, by copying it from the namespace's derived type
-     list, if necessary.  */
-  if (sym->ts.type == BT_DERIVED
-      && sym->ns->proc_name->attr.flavor == FL_MODULE
-      && sym->ts.derived->ns
-      && sym->ns != sym->ts.derived->ns)
-    {
-      gfc_dt_list *dt = sym->ns->derived_types;
-
-      for (; dt; dt = dt->next)
-       if (gfc_compare_derived_types (sym->ts.derived, dt->derived))
-         sym->ts.derived = dt->derived;
-    }
-
-  if (ns->entries)
+    if (ns->entries)
     for (el = ns->entries->next; el; el = el->next)
       {
        if (el->sym->result == el->sym
@@ -7229,8 +8342,15 @@ resolve_types (gfc_namespace *ns)
 
   resolve_entries (ns);
 
+  resolve_common_blocks (ns->common_root);
+
   resolve_contained_functions (ns);
 
+  gfc_traverse_ns (ns, resolve_bind_c_derived_types);
+
+  for (cl = ns->cl_list; cl; cl = cl->next)
+    resolve_charlen (cl);
+
   gfc_traverse_ns (ns, resolve_symbol);
 
   resolve_fntype (ns);
@@ -7248,9 +8368,6 @@ resolve_types (gfc_namespace *ns)
   forall_flag = 0;
   gfc_check_interfaces (ns);
 
-  for (cl = ns->cl_list; cl; cl = cl->next)
-    resolve_charlen (cl);
-
   gfc_traverse_ns (ns, resolve_values);
 
   if (ns->save_all)
@@ -7263,6 +8380,11 @@ resolve_types (gfc_namespace *ns)
   iter_stack = NULL;
   gfc_traverse_ns (ns, gfc_formalize_init_value);
 
+  gfc_traverse_ns (ns, gfc_verify_binding_labels);
+
+  if (ns->common_root != NULL)
+    gfc_traverse_symtree (ns->common_root, resolve_bind_c_comms);
+
   for (eq = ns->equiv; eq; eq = eq->next)
     resolve_equivalence (eq);
 
@@ -7288,7 +8410,10 @@ resolve_codes (gfc_namespace *ns)
   cs_base = NULL;
   /* Set to an out of range value.  */
   current_entry_id = -1;
+
+  bitmap_obstack_initialize (&labels_obstack);
   resolve_code (ns->code, ns);
+  bitmap_obstack_release (&labels_obstack);
 }