re PR fortran/34657 (program-unit MY_SUB imports symbol MY_SUB)
[gcc.git] / gcc / fortran / module.c
index 1769eada5fe672fa453562386c59a4781fc05cde..b62ad8d08e06728fbeb24b2fb6b5aea1b87f094b 100644 (file)
@@ -1,6 +1,7 @@
 /* Handle modules, which amounts to loading and saving symbols and
    their attendant structures.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+   2009, 2010, 2011
    Free Software Foundation, Inc.
    Contributed by Andy Vaught
 
@@ -72,12 +73,14 @@ along with GCC; see the file COPYING3.  If not see
 #include "match.h"
 #include "parse.h" /* FIXME */
 #include "md5.h"
+#include "constructor.h"
+#include "cpp.h"
 
 #define MODULE_EXTENSION ".mod"
 
 /* Don't put any single quote (') in MOD_VERSION, 
    if yout want it to be recognized.  */
-#define MOD_VERSION "3"
+#define MOD_VERSION "7"
 
 
 /* Structure that describes a position within a module file.  */
@@ -226,7 +229,7 @@ free_pi_tree (pointer_info *p)
   free_pi_tree (p->left);
   free_pi_tree (p->right);
 
-  gfc_free (p);
+  free (p);
 }
 
 
@@ -421,7 +424,7 @@ resolve_fixups (fixup_t *f, void *gp)
     {
       next = f->next;
       *(f->pointer) = gp;
-      gfc_free (f);
+      free (f);
     }
 }
 
@@ -493,7 +496,7 @@ free_rename (void)
   for (; gfc_rename_list; gfc_rename_list = next)
     {
       next = gfc_rename_list->next;
-      gfc_free (gfc_rename_list);
+      free (gfc_rename_list);
     }
 }
 
@@ -741,8 +744,7 @@ static int
 number_use_names (const char *name, bool interface)
 {
   int i = 0;
-  const char *c;
-  c = find_use_name_n (name, &i, interface);
+  find_use_name_n (name, &i, interface);
   return i;
 }
 
@@ -889,7 +891,7 @@ free_true_name (true_name *t)
   free_true_name (t->left);
   free_true_name (t->right);
 
-  gfc_free (t);
+  free (t);
 }
 
 
@@ -1223,7 +1225,7 @@ peek_atom (void)
 
   a = parse_atom ();
   if (a == ATOM_STRING)
-    gfc_free (atom_string);
+    free (atom_string);
 
   set_module_locus (&m);
   return a;
@@ -1298,7 +1300,7 @@ static void
 write_char (char out)
 {
   if (putc (out, module_fp) == EOF)
-    gfc_fatal_error ("Error writing modules file: %s", strerror (errno));
+    gfc_fatal_error ("Error writing modules file: %s", xstrerror (errno));
 
   /* Add this to our MD5.  */
   md5_process_bytes (&out, sizeof (out), &ctx);
@@ -1607,7 +1609,7 @@ mio_allocated_wide_string (const gfc_char_t *s, const size_t length)
     {
       char *quoted = quote_string (s, length);
       write_atom (ATOM_STRING, quoted);
-      gfc_free (quoted);
+      free (quoted);
       return s;
     }
   else
@@ -1616,7 +1618,7 @@ mio_allocated_wide_string (const gfc_char_t *s, const size_t length)
 
       require_atom (ATOM_STRING);
       unquoted = unquote_string (atom_string);
-      gfc_free (atom_string);
+      free (atom_string);
       return unquoted;
     }
 }
@@ -1642,7 +1644,7 @@ mio_pool_string (const char **stringp)
     {
       require_atom (ATOM_STRING);
       *stringp = atom_string[0] == '\0' ? NULL : gfc_get_string (atom_string);
-      gfc_free (atom_string);
+      free (atom_string);
     }
 }
 
@@ -1659,7 +1661,7 @@ mio_internal_string (char *string)
     {
       require_atom (ATOM_STRING);
       strcpy (string, atom_string);
-      gfc_free (atom_string);
+      free (atom_string);
     }
 }
 
@@ -1669,17 +1671,23 @@ typedef enum
   AB_POINTER, AB_TARGET, AB_DUMMY, AB_RESULT, AB_DATA,
   AB_IN_NAMELIST, AB_IN_COMMON, AB_FUNCTION, AB_SUBROUTINE, AB_SEQUENCE,
   AB_ELEMENTAL, AB_PURE, AB_RECURSIVE, AB_GENERIC, AB_ALWAYS_EXPLICIT,
-  AB_CRAY_POINTER, AB_CRAY_POINTEE, AB_THREADPRIVATE, AB_ALLOC_COMP,
-  AB_POINTER_COMP, AB_PRIVATE_COMP, AB_VALUE, AB_VOLATILE, AB_PROTECTED,
+  AB_CRAY_POINTER, AB_CRAY_POINTEE, AB_THREADPRIVATE,
+  AB_ALLOC_COMP, AB_POINTER_COMP, AB_PROC_POINTER_COMP, AB_PRIVATE_COMP,
+  AB_VALUE, AB_VOLATILE, AB_PROTECTED, AB_LOCK_COMP,
   AB_IS_BIND_C, AB_IS_C_INTEROP, AB_IS_ISO_C, AB_ABSTRACT, AB_ZERO_COMP,
-  AB_EXTENSION, AB_IS_CLASS, AB_PROCEDURE, AB_PROC_POINTER
+  AB_IS_CLASS, AB_PROCEDURE, AB_PROC_POINTER, AB_ASYNCHRONOUS, AB_CODIMENSION,
+  AB_COARRAY_COMP, AB_VTYPE, AB_VTAB, AB_CONTIGUOUS, AB_CLASS_POINTER,
+  AB_IMPLICIT_PURE
 }
 ab_attribute;
 
 static const mstring attr_bits[] =
 {
     minit ("ALLOCATABLE", AB_ALLOCATABLE),
+    minit ("ASYNCHRONOUS", AB_ASYNCHRONOUS),
     minit ("DIMENSION", AB_DIMENSION),
+    minit ("CODIMENSION", AB_CODIMENSION),
+    minit ("CONTIGUOUS", AB_CONTIGUOUS),
     minit ("EXTERNAL", AB_EXTERNAL),
     minit ("INTRINSIC", AB_INTRINSIC),
     minit ("OPTIONAL", AB_OPTIONAL),
@@ -1707,15 +1715,21 @@ static const mstring attr_bits[] =
     minit ("IS_ISO_C", AB_IS_ISO_C),
     minit ("VALUE", AB_VALUE),
     minit ("ALLOC_COMP", AB_ALLOC_COMP),
+    minit ("COARRAY_COMP", AB_COARRAY_COMP),
+    minit ("LOCK_COMP", AB_LOCK_COMP),
     minit ("POINTER_COMP", AB_POINTER_COMP),
+    minit ("PROC_POINTER_COMP", AB_PROC_POINTER_COMP),
     minit ("PRIVATE_COMP", AB_PRIVATE_COMP),
     minit ("ZERO_COMP", AB_ZERO_COMP),
     minit ("PROTECTED", AB_PROTECTED),
     minit ("ABSTRACT", AB_ABSTRACT),
-    minit ("EXTENSION", AB_EXTENSION),
     minit ("IS_CLASS", AB_IS_CLASS),
     minit ("PROCEDURE", AB_PROCEDURE),
     minit ("PROC_POINTER", AB_PROC_POINTER),
+    minit ("VTYPE", AB_VTYPE),
+    minit ("VTAB", AB_VTAB),
+    minit ("CLASS_POINTER", AB_CLASS_POINTER),
+    minit ("IMPLICIT_PURE", AB_IMPLICIT_PURE),
     minit (NULL, -1)
 };
 
@@ -1772,7 +1786,7 @@ static void
 mio_symbol_attribute (symbol_attribute *attr)
 {
   atom_type t;
-  unsigned ext_attr;
+  unsigned ext_attr,extension_level;
 
   mio_lparen ();
 
@@ -1781,16 +1795,27 @@ mio_symbol_attribute (symbol_attribute *attr)
   attr->proc = MIO_NAME (procedure_type) (attr->proc, procedures);
   attr->if_source = MIO_NAME (ifsrc) (attr->if_source, ifsrc_types);
   attr->save = MIO_NAME (save_state) (attr->save, save_status);
+  
   ext_attr = attr->ext_attr;
   mio_integer ((int *) &ext_attr);
   attr->ext_attr = ext_attr;
 
+  extension_level = attr->extension;
+  mio_integer ((int *) &extension_level);
+  attr->extension = extension_level;
+
   if (iomode == IO_OUTPUT)
     {
       if (attr->allocatable)
        MIO_NAME (ab_attribute) (AB_ALLOCATABLE, attr_bits);
+      if (attr->asynchronous)
+       MIO_NAME (ab_attribute) (AB_ASYNCHRONOUS, attr_bits);
       if (attr->dimension)
        MIO_NAME (ab_attribute) (AB_DIMENSION, attr_bits);
+      if (attr->codimension)
+       MIO_NAME (ab_attribute) (AB_CODIMENSION, attr_bits);
+      if (attr->contiguous)
+       MIO_NAME (ab_attribute) (AB_CONTIGUOUS, attr_bits);
       if (attr->external)
        MIO_NAME (ab_attribute) (AB_EXTERNAL, attr_bits);
       if (attr->intrinsic)
@@ -1799,6 +1824,8 @@ mio_symbol_attribute (symbol_attribute *attr)
        MIO_NAME (ab_attribute) (AB_OPTIONAL, attr_bits);
       if (attr->pointer)
        MIO_NAME (ab_attribute) (AB_POINTER, attr_bits);
+      if (attr->class_pointer)
+       MIO_NAME (ab_attribute) (AB_CLASS_POINTER, attr_bits);
       if (attr->is_protected)
        MIO_NAME (ab_attribute) (AB_PROTECTED, attr_bits);
       if (attr->value)
@@ -1837,6 +1864,8 @@ mio_symbol_attribute (symbol_attribute *attr)
        MIO_NAME (ab_attribute) (AB_ELEMENTAL, attr_bits);
       if (attr->pure)
        MIO_NAME (ab_attribute) (AB_PURE, attr_bits);
+      if (attr->implicit_pure)
+       MIO_NAME (ab_attribute) (AB_IMPLICIT_PURE, attr_bits);
       if (attr->recursive)
        MIO_NAME (ab_attribute) (AB_RECURSIVE, attr_bits);
       if (attr->always_explicit)
@@ -1855,18 +1884,26 @@ mio_symbol_attribute (symbol_attribute *attr)
        MIO_NAME (ab_attribute) (AB_ALLOC_COMP, attr_bits);
       if (attr->pointer_comp)
        MIO_NAME (ab_attribute) (AB_POINTER_COMP, attr_bits);
+      if (attr->proc_pointer_comp)
+       MIO_NAME (ab_attribute) (AB_PROC_POINTER_COMP, attr_bits);
       if (attr->private_comp)
        MIO_NAME (ab_attribute) (AB_PRIVATE_COMP, attr_bits);
+      if (attr->coarray_comp)
+       MIO_NAME (ab_attribute) (AB_COARRAY_COMP, attr_bits);
+      if (attr->lock_comp)
+       MIO_NAME (ab_attribute) (AB_LOCK_COMP, attr_bits);
       if (attr->zero_comp)
        MIO_NAME (ab_attribute) (AB_ZERO_COMP, attr_bits);
-      if (attr->extension)
-       MIO_NAME (ab_attribute) (AB_EXTENSION, attr_bits);
       if (attr->is_class)
        MIO_NAME (ab_attribute) (AB_IS_CLASS, attr_bits);
       if (attr->procedure)
        MIO_NAME (ab_attribute) (AB_PROCEDURE, attr_bits);
       if (attr->proc_pointer)
        MIO_NAME (ab_attribute) (AB_PROC_POINTER, attr_bits);
+      if (attr->vtype)
+       MIO_NAME (ab_attribute) (AB_VTYPE, attr_bits);
+      if (attr->vtab)
+       MIO_NAME (ab_attribute) (AB_VTAB, attr_bits);
 
       mio_rparen ();
 
@@ -1886,9 +1923,18 @@ mio_symbol_attribute (symbol_attribute *attr)
            case AB_ALLOCATABLE:
              attr->allocatable = 1;
              break;
+           case AB_ASYNCHRONOUS:
+             attr->asynchronous = 1;
+             break;
            case AB_DIMENSION:
              attr->dimension = 1;
              break;
+           case AB_CODIMENSION:
+             attr->codimension = 1;
+             break;
+           case AB_CONTIGUOUS:
+             attr->contiguous = 1;
+             break;
            case AB_EXTERNAL:
              attr->external = 1;
              break;
@@ -1901,6 +1947,9 @@ mio_symbol_attribute (symbol_attribute *attr)
            case AB_POINTER:
              attr->pointer = 1;
              break;
+           case AB_CLASS_POINTER:
+             attr->class_pointer = 1;
+             break;
            case AB_PROTECTED:
              attr->is_protected = 1;
              break;
@@ -1952,6 +2001,9 @@ mio_symbol_attribute (symbol_attribute *attr)
            case AB_PURE:
              attr->pure = 1;
              break;
+           case AB_IMPLICIT_PURE:
+             attr->implicit_pure = 1;
+             break;
            case AB_RECURSIVE:
              attr->recursive = 1;
              break;
@@ -1976,18 +2028,24 @@ mio_symbol_attribute (symbol_attribute *attr)
            case AB_ALLOC_COMP:
              attr->alloc_comp = 1;
              break;
+           case AB_COARRAY_COMP:
+             attr->coarray_comp = 1;
+             break;
+           case AB_LOCK_COMP:
+             attr->lock_comp = 1;
+             break;
            case AB_POINTER_COMP:
              attr->pointer_comp = 1;
              break;
+           case AB_PROC_POINTER_COMP:
+             attr->proc_pointer_comp = 1;
+             break;
            case AB_PRIVATE_COMP:
              attr->private_comp = 1;
              break;
            case AB_ZERO_COMP:
              attr->zero_comp = 1;
              break;
-           case AB_EXTENSION:
-             attr->extension = 1;
-             break;
            case AB_IS_CLASS:
              attr->is_class = 1;
              break;
@@ -1997,6 +2055,12 @@ mio_symbol_attribute (symbol_attribute *attr)
            case AB_PROC_POINTER:
              attr->proc_pointer = 1;
              break;
+           case AB_VTYPE:
+             attr->vtype = 1;
+             break;
+           case AB_VTAB:
+             attr->vtab = 1;
+             break;
            }
        }
     }
@@ -2066,6 +2130,8 @@ mio_typespec (gfc_typespec *ts)
   else
     mio_symbol_ref (&ts->u.derived);
 
+  mio_symbol_ref (&ts->interface);
+
   /* Add info for C interop and is_iso_c.  */
   mio_integer (&ts->is_c_interop);
   mio_integer (&ts->is_iso_c);
@@ -2087,6 +2153,20 @@ mio_typespec (gfc_typespec *ts)
   else
     mio_charlen (&ts->u.cl);
 
+  /* So as not to disturb the existing API, use an ATOM_NAME to
+     transmit deferred characteristic for characters (F2003).  */
+  if (iomode == IO_OUTPUT)
+    {
+      if (ts->type == BT_CHARACTER && ts->deferred)
+       write_atom (ATOM_NAME, "DEFERRED_CL");
+    }
+  else if (peek_atom () != ATOM_RPAREN)
+    {
+      if (parse_atom () != ATOM_NAME)
+       bad_module ("Expected string");
+      ts->deferred = 1;
+    }
+
   mio_rparen ();
 }
 
@@ -2126,9 +2206,13 @@ mio_array_spec (gfc_array_spec **asp)
     }
 
   mio_integer (&as->rank);
+  mio_integer (&as->corank);
   as->type = MIO_NAME (array_type) (as->type, array_spec_types);
 
-  for (i = 0; i < as->rank; i++)
+  if (iomode == IO_INPUT && as->corank)
+    as->cotype = (as->type == AS_DEFERRED) ? AS_DEFERRED : AS_EXPLICIT;
+
+  for (i = 0; i < as->rank + as->corank; i++)
     {
       mio_expr (&as->lower[i]);
       mio_expr (&as->upper[i]);
@@ -2266,6 +2350,9 @@ mio_component_ref (gfc_component **cp, gfc_symbol *sym)
     {
       mio_internal_string (name);
 
+      if (sym && sym->attr.is_class)
+       sym = sym->components->ts.u.derived;
+
       /* It can happen that a component reference can be read before the
         associated derived type symbol has been loaded. Return now and
         wait for a later iteration of load_needed.  */
@@ -2275,14 +2362,10 @@ mio_component_ref (gfc_component **cp, gfc_symbol *sym)
       if (sym->components != NULL && p->u.pointer == NULL)
        {
          /* Symbol already loaded, so search by name.  */
-         for (q = sym->components; q; q = q->next)
-           if (strcmp (q->name, name) == 0)
-             break;
-
-         if (q == NULL)
-           gfc_internal_error ("mio_component_ref(): Component not found");
+         q = gfc_find_component (sym, name, true, true);
 
-         associate_integer_pointer (p, q);
+         if (q)
+           associate_integer_pointer (p, q);
        }
 
       /* Make sure this symbol will eventually be loaded.  */
@@ -2298,7 +2381,7 @@ static void mio_formal_arglist (gfc_formal_arglist **formal);
 static void mio_typebound_proc (gfc_typebound_proc** proc);
 
 static void
-mio_component (gfc_component *c)
+mio_component (gfc_component *c, int vtype)
 {
   pointer_info *p;
   int n;
@@ -2326,9 +2409,12 @@ mio_component (gfc_component *c)
   mio_array_spec (&c->as);
 
   mio_symbol_attribute (&c->attr);
+  if (c->ts.type == BT_CLASS)
+    c->attr.class_ok = 1;
   c->attr.access = MIO_NAME (gfc_access) (c->attr.access, access_types); 
 
-  mio_expr (&c->initializer);
+  if (!vtype)
+    mio_expr (&c->initializer);
 
   if (c->attr.proc_pointer)
     {
@@ -2363,7 +2449,7 @@ mio_component (gfc_component *c)
 
 
 static void
-mio_component_list (gfc_component **cp)
+mio_component_list (gfc_component **cp, int vtype)
 {
   gfc_component *c, *tail;
 
@@ -2372,7 +2458,7 @@ mio_component_list (gfc_component **cp)
   if (iomode == IO_OUTPUT)
     {
       for (c = *cp; c; c = c->next)
-       mio_component (c);
+       mio_component (c, vtype);
     }
   else
     {
@@ -2385,7 +2471,7 @@ mio_component_list (gfc_component **cp)
            break;
 
          c = gfc_get_component ();
-         mio_component (c);
+         mio_component (c, vtype);
 
          if (tail == NULL)
            *cp = c;
@@ -2609,15 +2695,15 @@ done:
 
 
 static void
-mio_constructor (gfc_constructor **cp)
+mio_constructor (gfc_constructor_base *cp)
 {
-  gfc_constructor *c, *tail;
+  gfc_constructor *c;
 
   mio_lparen ();
 
   if (iomode == IO_OUTPUT)
     {
-      for (c = *cp; c; c = c->next)
+      for (c = gfc_constructor_first (*cp); c; c = gfc_constructor_next (c))
        {
          mio_lparen ();
          mio_expr (&c->expr);
@@ -2627,19 +2713,9 @@ mio_constructor (gfc_constructor **cp)
     }
   else
     {
-      *cp = NULL;
-      tail = NULL;
-
       while (peek_atom () != ATOM_RPAREN)
        {
-         c = gfc_get_constructor ();
-
-         if (tail == NULL)
-           *cp = c;
-         else
-           tail->next = c;
-
-         tail = c;
+         c = gfc_constructor_append_expr (cp, NULL, NULL);
 
          mio_lparen ();
          mio_expr (&c->expr);
@@ -2744,13 +2820,13 @@ mio_gmp_integer (mpz_t *integer)
       if (mpz_set_str (*integer, atom_string, 10))
        bad_module ("Error converting integer");
 
-      gfc_free (atom_string);
+      free (atom_string);
     }
   else
     {
       p = mpz_get_str (NULL, 10, *integer);
       write_atom (ATOM_STRING, p);
-      gfc_free (p);
+      free (p);
     }
 }
 
@@ -2768,7 +2844,7 @@ mio_gmp_real (mpfr_t *real)
 
       mpfr_init (*real);
       mpfr_set_str (*real, atom_string, 16, GFC_RND_MODE);
-      gfc_free (atom_string);
+      free (atom_string);
     }
   else
     {
@@ -2777,7 +2853,7 @@ mio_gmp_real (mpfr_t *real)
       if (mpfr_nan_p (*real) || mpfr_inf_p (*real))
        {
          write_atom (ATOM_STRING, p);
-         gfc_free (p);
+         free (p);
          return;
        }
 
@@ -2795,8 +2871,8 @@ mio_gmp_real (mpfr_t *real)
 
       write_atom (ATOM_STRING, atom_string);
 
-      gfc_free (atom_string);
-      gfc_free (p);
+      free (atom_string);
+      free (p);
     }
 }
 
@@ -2922,6 +2998,8 @@ fix_mio_expr (gfc_expr *e)
     }
   else if (e->expr_type == EXPR_FUNCTION && e->value.function.name)
     {
+      gfc_symbol *sym;
+
       /* In some circumstances, a function used in an initialization
         expression, in one use associated module, can fail to be
         coupled to its symtree when used in a specification
@@ -2929,6 +3007,20 @@ fix_mio_expr (gfc_expr *e)
       fname = e->value.function.esym ? e->value.function.esym->name
                                     : e->value.function.isym->name;
       e->symtree = gfc_find_symtree (gfc_current_ns->sym_root, fname);
+
+      if (e->symtree)
+       return;
+
+      /* This is probably a reference to a private procedure from another
+        module.  To prevent a segfault, make a generic with no specific
+        instances.  If this module is used, without the required
+        specific coming from somewhere, the appropriate error message
+        is issued.  */
+      gfc_get_symbol (fname, gfc_current_ns, &sym);
+      sym->attr.flavor = FL_PROCEDURE;
+      sym->attr.generic = 1;
+      e->symtree = gfc_find_symtree (gfc_current_ns->sym_root, fname);
+      gfc_commit_symbol (sym);
     }
 }
 
@@ -3044,7 +3136,7 @@ mio_expr (gfc_expr **ep)
        {
          require_atom (ATOM_STRING);
          e->value.function.name = gfc_get_string (atom_string);
-         gfc_free (atom_string);
+         free (atom_string);
 
          mio_integer (&flag);
          if (flag)
@@ -3053,7 +3145,7 @@ mio_expr (gfc_expr **ep)
            {
              require_atom (ATOM_STRING);
              e->value.function.isym = gfc_find_function (atom_string);
-             gfc_free (atom_string);
+             free (atom_string);
            }
        }
 
@@ -3286,7 +3378,7 @@ mio_typebound_proc (gfc_typebound_proc** proc)
 
   if (iomode == IO_INPUT)
     {
-      *proc = gfc_get_typebound_proc ();
+      *proc = gfc_get_typebound_proc (NULL);
       (*proc)->where = gfc_current_locus;
     }
   gcc_assert (*proc);
@@ -3335,7 +3427,7 @@ mio_typebound_proc (gfc_typebound_proc** proc)
              require_atom (ATOM_STRING);
              sym_root = &current_f2k_derived->tb_sym_root;
              g->specific_st = gfc_get_tbp_symtree (sym_root, atom_string);
-             gfc_free (atom_string);
+             free (atom_string);
 
              g->next = (*proc)->u.generic;
              (*proc)->u.generic = g;
@@ -3386,7 +3478,7 @@ mio_full_typebound_tree (gfc_symtree** root)
 
          require_atom (ATOM_STRING);
          st = gfc_get_tbp_symtree (root, atom_string);
-         gfc_free (atom_string);
+         free (atom_string);
 
          mio_typebound_symtree (st);
        }
@@ -3469,7 +3561,7 @@ mio_f2k_derived (gfc_namespace *f2k)
   else
     while (peek_atom () != ATOM_RPAREN)
       {
-       gfc_intrinsic_op op;
+       gfc_intrinsic_op op = GFC_INTRINSIC_BEGIN; /* Silence GCC.  */
 
        mio_lparen ();
        mio_intrinsic_op (&op);
@@ -3547,7 +3639,7 @@ mio_symbol (gfc_symbol *sym)
   /* Note that components are always saved, even if they are supposed
      to be private.  Component access is checked during searching.  */
 
-  mio_component_list (&sym->components);
+  mio_component_list (&sym->components, sym->attr.vtype);
 
   if (sym->components != NULL)
     sym->component_access
@@ -3575,7 +3667,7 @@ mio_symbol (gfc_symbol *sym)
   mio_integer (&(sym->intmod_sym_id));
 
   if (sym->attr.flavor == FL_DERIVED)
-    mio_integer (&(sym->vindex));
+    mio_integer (&(sym->hash_value));
 
   mio_rparen ();
 }
@@ -3669,7 +3761,7 @@ skip_list (void)
          break;
 
        case ATOM_STRING:
-         gfc_free (atom_string);
+         free (atom_string);
          break;
 
        case ATOM_NAME:
@@ -3746,8 +3838,9 @@ load_generic_interfaces (void)
   const char *p;
   char name[GFC_MAX_SYMBOL_LEN + 1], module[GFC_MAX_SYMBOL_LEN + 1];
   gfc_symbol *sym;
-  gfc_interface *generic = NULL;
+  gfc_interface *generic = NULL, *gen = NULL;
   int n, i, renamed;
+  bool ambiguous_set = false;
 
   mio_lparen ();
 
@@ -3832,9 +3925,13 @@ load_generic_interfaces (void)
              sym = st->n.sym;
 
              if (st && !sym->attr.generic
+                    && !st->ambiguous
                     && sym->module
                     && strcmp(module, sym->module))
-               st->ambiguous = 1;
+               {
+                 ambiguous_set = true;
+                 st->ambiguous = 1;
+               }
            }
 
          sym->attr.use_only = only_flag;
@@ -3850,6 +3947,26 @@ load_generic_interfaces (void)
              sym->generic = generic;
              sym->attr.generic_copy = 1;
            }
+
+         /* If a procedure that is not generic has generic interfaces
+            that include itself, it is generic! We need to take care
+            to retain symbols ambiguous that were already so.  */
+         if (sym->attr.use_assoc
+               && !sym->attr.generic
+               && sym->attr.flavor == FL_PROCEDURE)
+           {
+             for (gen = generic; gen; gen = gen->next)
+               {
+                 if (gen->sym == sym)
+                   {
+                     sym->attr.generic = 1;
+                     if (ambiguous_set)
+                       st->ambiguous = 0;
+                     break;
+                   }
+               }
+           }
+
        }
     }
 
@@ -3952,7 +4069,7 @@ load_equiv (void)
          {
            head = eq->eq;
            gfc_free_expr (eq->expr);
-           gfc_free (eq);
+           free (eq);
          }
       }
 
@@ -3972,6 +4089,71 @@ load_equiv (void)
 }
 
 
+/* This function loads the sym_root of f2k_derived with the extensions to
+   the derived type.  */
+static void
+load_derived_extensions (void)
+{
+  int symbol, j;
+  gfc_symbol *derived;
+  gfc_symbol *dt;
+  gfc_symtree *st;
+  pointer_info *info;
+  char name[GFC_MAX_SYMBOL_LEN + 1];
+  char module[GFC_MAX_SYMBOL_LEN + 1];
+  const char *p;
+
+  mio_lparen ();
+  while (peek_atom () != ATOM_RPAREN)
+    {
+      mio_lparen ();
+      mio_integer (&symbol);
+      info = get_integer (symbol);
+      derived = info->u.rsym.sym;
+
+      /* This one is not being loaded.  */
+      if (!info || !derived)
+       {
+         while (peek_atom () != ATOM_RPAREN)
+           skip_list ();
+         continue;
+       }
+
+      gcc_assert (derived->attr.flavor == FL_DERIVED);
+      if (derived->f2k_derived == NULL)
+       derived->f2k_derived = gfc_get_namespace (NULL, 0);
+
+      while (peek_atom () != ATOM_RPAREN)
+       {
+         mio_lparen ();
+         mio_internal_string (name);
+         mio_internal_string (module);
+
+          /* Only use one use name to find the symbol.  */
+         j = 1;
+         p = find_use_name_n (name, &j, false);
+         if (p)
+           {
+             st = gfc_find_symtree (gfc_current_ns->sym_root, p);
+             dt = st->n.sym;
+             st = gfc_find_symtree (derived->f2k_derived->sym_root, name);
+             if (st == NULL)
+               {
+                 /* Only use the real name in f2k_derived to ensure a single
+                   symtree.  */
+                 st = gfc_new_symtree (&derived->f2k_derived->sym_root, name);
+                 st->n.sym = dt;
+                 st->n.sym->refs++;
+               }
+           }
+         mio_rparen ();
+       }
+      mio_rparen ();
+    }
+  mio_rparen ();
+}
+
+
 /* Recursive function to traverse the pointer_info tree and load a
    needed symbol.  We return nonzero if we load a symbol and stop the
    traversal, because the act of loading can alter the tree.  */
@@ -4054,9 +4236,23 @@ read_cleanup (pointer_info *p)
 
   if (p->type == P_SYMBOL && p->u.rsym.state == USED && !p->u.rsym.referenced)
     {
+      gfc_namespace *ns;
       /* Add hidden symbols to the symtree.  */
       q = get_integer (p->u.rsym.ns);
-      st = gfc_get_unique_symtree ((gfc_namespace *) q->u.pointer);
+      ns = (gfc_namespace *) q->u.pointer;
+
+      if (!p->u.rsym.sym->attr.vtype
+           && !p->u.rsym.sym->attr.vtab)
+       st = gfc_get_unique_symtree (ns);
+      else
+       {
+         /* There is no reason to use 'unique_symtrees' for vtabs or
+            vtypes - their name is fine for a symtree and reduces the
+            namespace pollution.  */
+         st = gfc_find_symtree (ns->sym_root, p->u.rsym.sym->name);
+         if (!st)
+           st = gfc_new_symtree (&ns->sym_root, p->u.rsym.sym->name);
+       }
 
       st->n.sym = p->u.rsym.sym;
       st->n.sym->refs++;
@@ -4082,10 +4278,20 @@ check_for_ambiguous (gfc_symbol *st_sym, pointer_info *info)
   module_locus locus;
   symbol_attribute attr;
 
+  if (st_sym->ns->proc_name && st_sym->name == st_sym->ns->proc_name->name)
+    {
+      gfc_error ("'%s' of module '%s', imported at %C, is also the name of the "
+                "current program unit", st_sym->name, module_name);
+      return true;
+    }
+
   rsym = info->u.rsym.sym;
   if (st_sym == rsym)
     return false;
 
+  if (st_sym->attr.vtab || st_sym->attr.vtype)
+    return false;
+
   /* If the existing symbol is generic from a different module and
      the new symbol is generic there can be no ambiguity.  */
   if (st_sym->attr.generic
@@ -4113,7 +4319,7 @@ check_for_ambiguous (gfc_symbol *st_sym, pointer_info *info)
 static void
 read_module (void)
 {
-  module_locus operator_interfaces, user_operators;
+  module_locus operator_interfaces, user_operators, extensions;
   const char *p;
   char name[GFC_MAX_SYMBOL_LEN + 1];
   int i;
@@ -4130,8 +4336,11 @@ read_module (void)
   skip_list ();
   skip_list ();
 
-  /* Skip commons and equivalences for now.  */
+  /* Skip commons, equivalences and derived type extensions for now.  */
+  skip_list ();
   skip_list ();
+
+  get_module_locus (&extensions);
   skip_list ();
 
   mio_lparen ();
@@ -4224,6 +4433,11 @@ read_module (void)
          if (p == NULL && strcmp (name, module_name) == 0)
            p = name;
 
+         /* Exception: Always import vtabs & vtypes.  */
+         if (p == NULL && (strncmp (name, "__vtab_", 5) == 0
+                           || strncmp (name, "__vtype_", 6) == 0))
+           p = name;
+
          /* Skip symtree nodes not in an ONLY clause, unless there
             is an existing symtree loaded from another USE statement.  */
          if (p == NULL)
@@ -4384,7 +4598,10 @@ read_module (void)
                 module_name);
     }
 
-  gfc_check_interfaces (gfc_current_ns);
+  /* Now we should be in a position to fill f2k_derived with derived type
+     extensions, since everything has been loaded.  */
+  set_module_locus (&extensions);
+  load_derived_extensions ();
 
   /* Clean up symbol nodes that were never loaded, create references
      to hidden symbols.  */
@@ -4399,8 +4616,8 @@ read_module (void)
    PRIVATE, then private, and otherwise it is public unless the default
    access in this context has been declared PRIVATE.  */
 
-bool
-gfc_check_access (gfc_access specific_access, gfc_access default_access)
+static bool
+check_access (gfc_access specific_access, gfc_access default_access)
 {
   if (specific_access == ACCESS_PUBLIC)
     return TRUE;
@@ -4414,6 +4631,16 @@ gfc_check_access (gfc_access specific_access, gfc_access default_access)
 }
 
 
+bool
+gfc_check_symbol_access (gfc_symbol *sym)
+{
+  if (sym->attr.vtab || sym->attr.vtype)
+    return true;
+  else
+    return check_access (sym->attr.access, sym->ns->default_access);
+}
+
+
 /* A structure to remember which commons we've already written.  */
 
 struct written_common
@@ -4451,7 +4678,7 @@ free_written_common (struct written_common *w)
   if (w->right)
     free_written_common (w->right);
 
-  gfc_free (w);
+  free (w);
 }
 
 /* Write a common block to the module -- recursive helper function.  */
@@ -4594,6 +4821,42 @@ write_equiv (void)
 }
 
 
+/* Write derived type extensions to the module.  */
+
+static void
+write_dt_extensions (gfc_symtree *st)
+{
+  if (!gfc_check_symbol_access (st->n.sym))
+    return;
+  if (!(st->n.sym->ns && st->n.sym->ns->proc_name
+       && st->n.sym->ns->proc_name->attr.flavor == FL_MODULE))
+    return;
+
+  mio_lparen ();
+  mio_pool_string (&st->n.sym->name);
+  if (st->n.sym->module != NULL)
+    mio_pool_string (&st->n.sym->module);
+  else
+    mio_internal_string (module_name);
+  mio_rparen ();
+}
+
+static void
+write_derived_extensions (gfc_symtree *st)
+{
+  if (!((st->n.sym->attr.flavor == FL_DERIVED)
+         && (st->n.sym->f2k_derived != NULL)
+         && (st->n.sym->f2k_derived->sym_root != NULL)))
+    return;
+
+  mio_lparen ();
+  mio_symbol_ref (&(st->n.sym));
+  gfc_traverse_symtree (st->n.sym->f2k_derived->sym_root,
+                       write_dt_extensions);
+  mio_rparen ();
+}
+
+
 /* Write a symbol to the module.  */
 
 static void
@@ -4647,7 +4910,7 @@ write_symbol0 (gfc_symtree *st)
       && !sym->attr.subroutine && !sym->attr.function)
     dont_write = true;
 
-  if (!gfc_check_access (sym->attr.access, sym->ns->default_access))
+  if (!gfc_check_symbol_access (sym))
     dont_write = true;
 
   if (!dont_write)
@@ -4704,8 +4967,7 @@ write_operator (gfc_user_op *uop)
   static char nullstring[] = "";
   const char *p = nullstring;
 
-  if (uop->op == NULL
-      || !gfc_check_access (uop->access, uop->ns->default_access))
+  if (uop->op == NULL || !check_access (uop->access, uop->ns->default_access))
     return;
 
   mio_symbol_interface (&uop->name, &p, &uop->op);
@@ -4729,8 +4991,7 @@ write_generic (gfc_symtree *st)
   if (!sym || check_unique_name (st->name))
     return;
 
-  if (sym->generic == NULL
-      || !gfc_check_access (sym->attr.access, sym->ns->default_access))
+  if (sym->generic == NULL || !gfc_check_symbol_access (sym))
     return;
 
   if (sym->module == NULL)
@@ -4755,7 +5016,7 @@ write_symtree (gfc_symtree *st)
        && sym->ns->proc_name->attr.if_source == IFSRC_IFBODY)
     return;
 
-  if (!gfc_check_access (sym->attr.access, sym->ns->default_access)
+  if (!gfc_check_symbol_access (sym)
       || (sym->attr.flavor == FL_PROCEDURE && sym->attr.generic
          && !sym->attr.subroutine && !sym->attr.function))
     return;
@@ -4786,8 +5047,8 @@ write_module (void)
       if (i == INTRINSIC_USER)
        continue;
 
-      mio_interface (gfc_check_access (gfc_current_ns->operator_access[i],
-                                      gfc_current_ns->default_access)
+      mio_interface (check_access (gfc_current_ns->operator_access[i],
+                                  gfc_current_ns->default_access)
                     ? &gfc_current_ns->op[i] : NULL);
     }
 
@@ -4820,6 +5081,13 @@ write_module (void)
   write_char ('\n');
   write_char ('\n');
 
+  mio_lparen ();
+  gfc_traverse_symtree (gfc_current_ns->sym_root,
+                       write_derived_extensions);
+  mio_rparen ();
+  write_char ('\n');
+  write_char ('\n');
+
   /* Write symbol information.  First we traverse all symbols in the
      primary namespace, writing those that need to be written.
      Sometimes writing one symbol will cause another to need to be
@@ -4943,11 +5211,14 @@ gfc_dump_module (const char *name, int dump_flag)
       return;
     }
 
+  if (gfc_cpp_makedep ())
+    gfc_cpp_add_target (filename);
+
   /* Write the module to the temporary file.  */
   module_fp = fopen (filename_tmp, "w");
   if (module_fp == NULL)
     gfc_fatal_error ("Can't open module file '%s' for writing at %C: %s",
-                    filename_tmp, strerror (errno));
+                    filename_tmp, xstrerror (errno));
 
   /* Write the header, including space reserved for the MD5 sum.  */
   now = time (NULL);
@@ -4985,7 +5256,7 @@ gfc_dump_module (const char *name, int dump_flag)
 
   if (fclose (module_fp))
     gfc_fatal_error ("Error writing module file '%s' for writing: %s",
-                    filename_tmp, strerror (errno));
+                    filename_tmp, xstrerror (errno));
 
   /* Read the MD5 from the header of the old module file and compare.  */
   if (read_md5_from_module_file (filename, md5_old) != 0
@@ -4994,64 +5265,49 @@ gfc_dump_module (const char *name, int dump_flag)
       /* Module file have changed, replace the old one.  */
       if (unlink (filename) && errno != ENOENT)
        gfc_fatal_error ("Can't delete module file '%s': %s", filename,
-                        strerror (errno));
+                        xstrerror (errno));
       if (rename (filename_tmp, filename))
        gfc_fatal_error ("Can't rename module file '%s' to '%s': %s",
-                        filename_tmp, filename, strerror (errno));
+                        filename_tmp, filename, xstrerror (errno));
     }
   else
     {
       if (unlink (filename_tmp))
        gfc_fatal_error ("Can't delete temporary module file '%s': %s",
-                        filename_tmp, strerror (errno));
+                        filename_tmp, xstrerror (errno));
     }
 }
 
 
 static void
-sort_iso_c_rename_list (void)
+create_intrinsic_function (const char *name, gfc_isym_id id,
+                          const char *modname, intmod_id module)
 {
-  gfc_use_rename *tmp_list = NULL;
-  gfc_use_rename *curr;
-  gfc_use_rename *kinds_used[ISOCBINDING_NUMBER] = {NULL};
-  int c_kind;
-  int i;
+  gfc_intrinsic_sym *isym;
+  gfc_symtree *tmp_symtree;
+  gfc_symbol *sym;
 
-  for (curr = gfc_rename_list; curr; curr = curr->next)
+  tmp_symtree = gfc_find_symtree (gfc_current_ns->sym_root, name);
+  if (tmp_symtree)
     {
-      c_kind = get_c_kind (curr->use_name, c_interop_kinds_table);
-      if (c_kind == ISOCBINDING_INVALID || c_kind == ISOCBINDING_LAST)
-       {
-         gfc_error ("Symbol '%s' referenced at %L does not exist in "
-                    "intrinsic module ISO_C_BINDING.", curr->use_name,
-                    &curr->where);
-       }
-      else
-       /* Put it in the list.  */
-       kinds_used[c_kind] = curr;
+      if (strcmp (modname, tmp_symtree->n.sym->module) == 0)
+        return;
+      gfc_error ("Symbol '%s' already declared", name);
     }
 
-  /* Make a new (sorted) rename list.  */
-  i = 0;
-  while (i < ISOCBINDING_NUMBER && kinds_used[i] == NULL)
-    i++;
+  gfc_get_sym_tree (name, gfc_current_ns, &tmp_symtree, false);
+  sym = tmp_symtree->n.sym;
 
-  if (i < ISOCBINDING_NUMBER)
-    {
-      tmp_list = kinds_used[i];
+  isym = gfc_intrinsic_function_by_id (id);
+  gcc_assert (isym);
 
-      i++;
-      curr = tmp_list;
-      for (; i < ISOCBINDING_NUMBER; i++)
-       if (kinds_used[i] != NULL)
-         {
-           curr->next = kinds_used[i];
-           curr = curr->next;
-           curr->next = NULL;
-         }
-    }
+  sym->attr.flavor = FL_PROCEDURE;
+  sym->attr.intrinsic = 1;
 
-  gfc_rename_list = tmp_list;
+  sym->module = gfc_get_string (modname);
+  sym->attr.use_assoc = 1;
+  sym->from_intmod = module;
+  sym->intmod_sym_id = id;
 }
 
 
@@ -5068,7 +5324,6 @@ import_iso_c_binding_module (void)
   const char *iso_c_module_name = "__iso_c_binding";
   gfc_use_rename *u;
   int i;
-  char *local_name;
 
   /* Look only in the current namespace.  */
   mod_symtree = gfc_find_symtree (gfc_current_ns->sym_root, iso_c_module_name);
@@ -5093,57 +5348,63 @@ import_iso_c_binding_module (void)
 
   /* Generate the symbols for the named constants representing
      the kinds for intrinsic data types.  */
-  if (only_flag)
+  for (i = 0; i < ISOCBINDING_NUMBER; i++)
     {
-      /* Sort the rename list because there are dependencies between types
-        and procedures (e.g., c_loc needs c_ptr).  */
-      sort_iso_c_rename_list ();
-      
+      bool found = false;
       for (u = gfc_rename_list; u; u = u->next)
-       {
-         i = get_c_kind (u->use_name, c_interop_kinds_table);
+       if (strcmp (c_interop_kinds_table[i].name, u->use_name) == 0)
+         {
+           u->found = 1;
+           found = true;
+           switch (i)
+             {
+#define NAMED_FUNCTION(a,b,c,d) \
+               case a: \
+                 create_intrinsic_function (u->local_name[0] ? u->local_name \
+                                                             : u->use_name, \
+                                            (gfc_isym_id) c, \
+                                             iso_c_module_name, \
+                                             INTMOD_ISO_C_BINDING); \
+                 break;
+#include "iso-c-binding.def"
+#undef NAMED_FUNCTION
+
+               default:
+                 generate_isocbinding_symbol (iso_c_module_name,
+                                              (iso_c_binding_symbol) i,
+                                              u->local_name[0] ? u->local_name
+                                                               : u->use_name);
+             }
+         }
 
-         if (i == ISOCBINDING_INVALID || i == ISOCBINDING_LAST)
-           {
-             gfc_error ("Symbol '%s' referenced at %L does not exist in "
-                        "intrinsic module ISO_C_BINDING.", u->use_name,
-                        &u->where);
-             continue;
-           }
-         
-         generate_isocbinding_symbol (iso_c_module_name,
-                                      (iso_c_binding_symbol) i,
-                                      u->local_name);
-       }
-    }
-  else
-    {
-      for (i = 0; i < ISOCBINDING_NUMBER; i++)
-       {
-         local_name = NULL;
-         for (u = gfc_rename_list; u; u = u->next)
-           {
-             if (strcmp (c_interop_kinds_table[i].name, u->use_name) == 0)
-               {
-                 local_name = u->local_name;
-                 u->found = 1;
+      if (!found && !only_flag)
+       switch (i)
+         {
+#define NAMED_FUNCTION(a,b,c,d) \
+           case a: \
+             if ((gfc_option.allow_std & d) == 0) \
+               continue; \
+             create_intrinsic_function (b, (gfc_isym_id) c, \
+                                        iso_c_module_name, \
+                                        INTMOD_ISO_C_BINDING); \
                  break;
-               }
-           }
-         generate_isocbinding_symbol (iso_c_module_name,
-                                      (iso_c_binding_symbol) i,
-                                      local_name);
-       }
+#include "iso-c-binding.def"
+#undef NAMED_FUNCTION
 
-      for (u = gfc_rename_list; u; u = u->next)
-       {
-         if (u->found)
-           continue;
+           default:
+             generate_isocbinding_symbol (iso_c_module_name,
+                                          (iso_c_binding_symbol) i, NULL);
+         }
+   }
 
-         gfc_error ("Symbol '%s' referenced at %L not found in intrinsic "
-                    "module ISO_C_BINDING", u->use_name, &u->where);
-       }
-    }
+   for (u = gfc_rename_list; u; u = u->next)
+     {
+      if (u->found)
+       continue;
+
+      gfc_error ("Symbol '%s' referenced at %L not found in intrinsic "
+                "module ISO_C_BINDING", u->use_name, &u->where);
+     }
 }
 
 
@@ -5172,29 +5433,112 @@ create_int_parameter (const char *name, int value, const char *modname,
   sym->attr.flavor = FL_PARAMETER;
   sym->ts.type = BT_INTEGER;
   sym->ts.kind = gfc_default_integer_kind;
-  sym->value = gfc_int_expr (value);
+  sym->value = gfc_get_int_expr (gfc_default_integer_kind, NULL, value);
   sym->attr.use_assoc = 1;
   sym->from_intmod = module;
   sym->intmod_sym_id = id;
 }
 
 
+/* Value is already contained by the array constructor, but not
+   yet the shape.  */
+
+static void
+create_int_parameter_array (const char *name, int size, gfc_expr *value,
+                           const char *modname, intmod_id module, int id)
+{
+  gfc_symtree *tmp_symtree;
+  gfc_symbol *sym;
+
+  tmp_symtree = gfc_find_symtree (gfc_current_ns->sym_root, name);
+  if (tmp_symtree != NULL)
+    {
+      if (strcmp (modname, tmp_symtree->n.sym->module) == 0)
+       return;
+      else
+       gfc_error ("Symbol '%s' already declared", name);
+    }
+
+  gfc_get_sym_tree (name, gfc_current_ns, &tmp_symtree, false);
+  sym = tmp_symtree->n.sym;
+
+  sym->module = gfc_get_string (modname);
+  sym->attr.flavor = FL_PARAMETER;
+  sym->ts.type = BT_INTEGER;
+  sym->ts.kind = gfc_default_integer_kind;
+  sym->attr.use_assoc = 1;
+  sym->from_intmod = module;
+  sym->intmod_sym_id = id;
+  sym->attr.dimension = 1;
+  sym->as = gfc_get_array_spec ();
+  sym->as->rank = 1;
+  sym->as->type = AS_EXPLICIT;
+  sym->as->lower[0] = gfc_get_int_expr (gfc_default_integer_kind, NULL, 1);
+  sym->as->upper[0] = gfc_get_int_expr (gfc_default_integer_kind, NULL, size); 
+
+  sym->value = value;
+  sym->value->shape = gfc_get_shape (1);
+  mpz_init_set_ui (sym->value->shape[0], size);
+}
+
+
+/* Add an derived type for a given module.  */
+
+static void
+create_derived_type (const char *name, const char *modname,
+                     intmod_id module, int id)
+{
+  gfc_symtree *tmp_symtree;
+  gfc_symbol *sym;
+
+  tmp_symtree = gfc_find_symtree (gfc_current_ns->sym_root, name);
+  if (tmp_symtree != NULL)
+    {
+      if (strcmp (modname, tmp_symtree->n.sym->module) == 0)
+       return;
+      else
+       gfc_error ("Symbol '%s' already declared", name);
+    }
+
+  gfc_get_sym_tree (name, gfc_current_ns, &tmp_symtree, false);
+  sym = tmp_symtree->n.sym;
+
+  sym->module = gfc_get_string (modname);
+  sym->from_intmod = module;
+  sym->intmod_sym_id = id;
+  sym->attr.flavor = FL_DERIVED;
+  sym->attr.private_comp = 1;
+  sym->attr.zero_comp = 1;
+  sym->attr.use_assoc = 1;
+}
+
+
+
 /* USE the ISO_FORTRAN_ENV intrinsic module.  */
 
 static void
 use_iso_fortran_env_module (void)
 {
   static char mod[] = "iso_fortran_env";
-  const char *local_name;
   gfc_use_rename *u;
   gfc_symbol *mod_sym;
   gfc_symtree *mod_symtree;
-  int i;
+  gfc_expr *expr;
+  int i, j;
 
   intmod_sym symbol[] = {
 #define NAMED_INTCST(a,b,c,d) { a, b, 0, d },
 #include "iso-fortran-env.def"
 #undef NAMED_INTCST
+#define NAMED_KINDARRAY(a,b,c,d) { a, b, 0, d },
+#include "iso-fortran-env.def"
+#undef NAMED_KINDARRAY
+#define NAMED_DERIVED_TYPE(a,b,c,d) { a, b, 0, d },
+#include "iso-fortran-env.def"
+#undef NAMED_DERIVED_TYPE
+#define NAMED_FUNCTION(a,b,c,d) { a, b, c, d },
+#include "iso-fortran-env.def"
+#undef NAMED_FUNCTION
     { ISOFORTRANENV_INVALID, NULL, -1234, 0 } };
 
   i = 0;
@@ -5221,48 +5565,91 @@ use_iso_fortran_env_module (void)
                 "non-intrinsic module name used previously", mod);
 
   /* Generate the symbols for the module integer named constants.  */
-  if (only_flag)
-    for (u = gfc_rename_list; u; u = u->next)
-      {
-       for (i = 0; symbol[i].name; i++)
-         if (strcmp (symbol[i].name, u->use_name) == 0)
-           break;
-
-       if (symbol[i].name == NULL)
-         {
-           gfc_error ("Symbol '%s' referenced at %L does not exist in "
-                      "intrinsic module ISO_FORTRAN_ENV", u->use_name,
-                      &u->where);
-           continue;
-         }
 
-       if ((gfc_option.flag_default_integer || gfc_option.flag_default_real)
-           && symbol[i].id == ISOFORTRANENV_NUMERIC_STORAGE_SIZE)
-         gfc_warning_now ("Use of the NUMERIC_STORAGE_SIZE named constant "
-                          "from intrinsic module ISO_FORTRAN_ENV at %L is "
-                          "incompatible with option %s", &u->where,
-                          gfc_option.flag_default_integer
-                            ? "-fdefault-integer-8" : "-fdefault-real-8");
-
-       create_int_parameter (u->local_name[0] ? u->local_name
-                                              : symbol[i].name,
-                             symbol[i].value, mod, INTMOD_ISO_FORTRAN_ENV,
-                             symbol[i].id);
-      }
-  else
+  for (i = 0; symbol[i].name; i++)
     {
-      for (i = 0; symbol[i].name; i++)
+      bool found = false;
+      for (u = gfc_rename_list; u; u = u->next)
        {
-         local_name = NULL;
-         for (u = gfc_rename_list; u; u = u->next)
+         if (strcmp (symbol[i].name, u->use_name) == 0)
            {
-             if (strcmp (symbol[i].name, u->use_name) == 0)
+             found = true;
+             u->found = 1;
+
+             if (gfc_notify_std (symbol[i].standard, "The symbol '%s', "
+                                 "referrenced at %C, is not in the selected "
+                                 "standard", symbol[i].name) == FAILURE)
+               continue;
+
+             if ((gfc_option.flag_default_integer || gfc_option.flag_default_real)
+                 && symbol[i].id == ISOFORTRANENV_NUMERIC_STORAGE_SIZE)
+               gfc_warning_now ("Use of the NUMERIC_STORAGE_SIZE named "
+                                "constant from intrinsic module "
+                                "ISO_FORTRAN_ENV at %C is incompatible with "
+                                "option %s",
+                                gfc_option.flag_default_integer
+                                  ? "-fdefault-integer-8"
+                                  : "-fdefault-real-8");
+             switch (symbol[i].id)
                {
-                 local_name = u->local_name;
-                 u->found = 1;
+#define NAMED_INTCST(a,b,c,d) \
+               case a:
+#include "iso-fortran-env.def"
+#undef NAMED_INTCST
+                 create_int_parameter (u->local_name[0] ? u->local_name
+                                                        : u->use_name,
+                                       symbol[i].value, mod,
+                                       INTMOD_ISO_FORTRAN_ENV, symbol[i].id);
+                 break;
+
+#define NAMED_KINDARRAY(a,b,KINDS,d) \
+               case a:\
+                 expr = gfc_get_array_expr (BT_INTEGER, \
+                                            gfc_default_integer_kind,\
+                                            NULL); \
+                 for (j = 0; KINDS[j].kind != 0; j++) \
+                   gfc_constructor_append_expr (&expr->value.constructor, \
+                       gfc_get_int_expr (gfc_default_integer_kind, NULL, \
+                                         KINDS[j].kind), NULL); \
+                 create_int_parameter_array (u->local_name[0] ? u->local_name \
+                                                        : u->use_name, \
+                                             j, expr, mod, \
+                                             INTMOD_ISO_FORTRAN_ENV, \
+                                             symbol[i].id); \
+                 break;
+#include "iso-fortran-env.def"
+#undef NAMED_KINDARRAY
+
+#define NAMED_DERIVED_TYPE(a,b,TYPE,STD) \
+               case a:
+#include "iso-fortran-env.def"
+                  create_derived_type (u->local_name[0] ? u->local_name
+                                                       : u->use_name,
+                                      mod, INTMOD_ISO_FORTRAN_ENV,
+                                      symbol[i].id);
                  break;
+#undef NAMED_DERIVED_TYPE
+
+#define NAMED_FUNCTION(a,b,c,d) \
+               case a:
+#include "iso-fortran-env.def"
+#undef NAMED_FUNCTION
+                 create_intrinsic_function (u->local_name[0] ? u->local_name
+                                                             : u->use_name,
+                                            (gfc_isym_id) symbol[i].value, mod,
+                                            INTMOD_ISO_FORTRAN_ENV);
+                 break;
+
+               default:
+                 gcc_unreachable ();
                }
            }
+       }
+
+      if (!found && !only_flag)
+       {
+         if ((gfc_option.allow_std & symbol[i].standard) == 0)
+           continue;
 
          if ((gfc_option.flag_default_integer || gfc_option.flag_default_real)
              && symbol[i].id == ISOFORTRANENV_NUMERIC_STORAGE_SIZE)
@@ -5272,19 +5659,60 @@ use_iso_fortran_env_module (void)
                             gfc_option.flag_default_integer
                                ? "-fdefault-integer-8" : "-fdefault-real-8");
 
-         create_int_parameter (local_name ? local_name : symbol[i].name,
-                               symbol[i].value, mod, INTMOD_ISO_FORTRAN_ENV,
-                               symbol[i].id);
+         switch (symbol[i].id)
+           {
+#define NAMED_INTCST(a,b,c,d) \
+           case a:
+#include "iso-fortran-env.def"
+#undef NAMED_INTCST
+             create_int_parameter (symbol[i].name, symbol[i].value, mod,
+                                   INTMOD_ISO_FORTRAN_ENV, symbol[i].id);
+             break;
+
+#define NAMED_KINDARRAY(a,b,KINDS,d) \
+           case a:\
+             expr = gfc_get_array_expr (BT_INTEGER, gfc_default_integer_kind, \
+                                        NULL); \
+             for (j = 0; KINDS[j].kind != 0; j++) \
+               gfc_constructor_append_expr (&expr->value.constructor, \
+                      gfc_get_int_expr (gfc_default_integer_kind, NULL, \
+                                        KINDS[j].kind), NULL); \
+            create_int_parameter_array (symbol[i].name, j, expr, mod, \
+                                        INTMOD_ISO_FORTRAN_ENV, symbol[i].id);\
+            break;
+#include "iso-fortran-env.def"
+#undef NAMED_KINDARRAY
+
+#define NAMED_DERIVED_TYPE(a,b,TYPE,STD) \
+         case a:
+#include "iso-fortran-env.def"
+           create_derived_type (symbol[i].name, mod, INTMOD_ISO_FORTRAN_ENV,
+                                symbol[i].id);
+           break;
+#undef NAMED_DERIVED_TYPE
+
+#define NAMED_FUNCTION(a,b,c,d) \
+               case a:
+#include "iso-fortran-env.def"
+#undef NAMED_FUNCTION
+                 create_intrinsic_function (symbol[i].name,
+                                            (gfc_isym_id) symbol[i].value, mod,
+                                            INTMOD_ISO_FORTRAN_ENV);
+                 break;
+
+         default:
+           gcc_unreachable ();
+         }
        }
+    }
 
-      for (u = gfc_rename_list; u; u = u->next)
-       {
-         if (u->found)
-           continue;
+  for (u = gfc_rename_list; u; u = u->next)
+    {
+      if (u->found)
+       continue;
 
-         gfc_error ("Symbol '%s' referenced at %L not found in intrinsic "
+      gfc_error ("Symbol '%s' referenced at %L not found in intrinsic "
                     "module ISO_FORTRAN_ENV", u->use_name, &u->where);
-       }
     }
 }
 
@@ -5340,7 +5768,7 @@ gfc_use_module (void)
 
   if (module_fp == NULL)
     gfc_fatal_error ("Can't open module file '%s' for reading at %C: %s",
-                    filename, strerror (errno));
+                    filename, xstrerror (errno));
 
   /* Check that we haven't already USEd an intrinsic module with the
      same name.  */
@@ -5379,10 +5807,12 @@ gfc_use_module (void)
 
          if (strcmp (atom_string, MOD_VERSION))
            {
-             gfc_fatal_error ("Wrong module version '%s' (expected '"
-                              MOD_VERSION "') for file '%s' opened"
-                              " at %C", atom_string, filename);
+             gfc_fatal_error ("Wrong module version '%s' (expected '%s') "
+                              "for file '%s' opened at %C", atom_string,
+                              MOD_VERSION, filename);
            }
+
+         free (atom_string);
        }
 
       if (c == '\n')
@@ -5429,10 +5859,10 @@ gfc_free_use_stmts (gfc_use_list *use_stmts)
       for (; use_stmts->rename; use_stmts->rename = next_rename)
        {
          next_rename = use_stmts->rename->next;
-         gfc_free (use_stmts->rename);
+         free (use_stmts->rename);
        }
       next = use_stmts->next;
-      gfc_free (use_stmts);
+      free (use_stmts);
     }
 }