OSDN Git Service

PR fortran/15586
[pf3gnuchains/gcc-fork.git] / gcc / fortran / decl.c
index 3a78efc..69c0fc8 100644 (file)
@@ -1,5 +1,5 @@
 /* Declaration statement matcher
-   Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
    Contributed by Andy Vaught
 
 This file is part of GCC.
@@ -16,23 +16,23 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 
 #include "config.h"
+#include "system.h"
 #include "gfortran.h"
 #include "match.h"
 #include "parse.h"
-#include <string.h>
 
 
-/* This flag is set if a an old-style length selector is matched
+/* This flag is set if an old-style length selector is matched
    during a type-declaration statement.  */
 
 static int old_char_selector;
 
-/* When variables aquire types and attributes from a declaration
+/* When variables acquire types and attributes from a declaration
    statement, they get them from the following static variables.  The
    first part of a declaration sets these variables and the second
    part copies these into symbol structures.  */
@@ -48,6 +48,405 @@ static int colon_seen;
 gfc_symbol *gfc_new_block;
 
 
+/********************* DATA statement subroutines *********************/
+
+/* Free a gfc_data_variable structure and everything beneath it.  */
+
+static void
+free_variable (gfc_data_variable * p)
+{
+  gfc_data_variable *q;
+
+  for (; p; p = q)
+    {
+      q = p->next;
+      gfc_free_expr (p->expr);
+      gfc_free_iterator (&p->iter, 0);
+      free_variable (p->list);
+
+      gfc_free (p);
+    }
+}
+
+
+/* Free a gfc_data_value structure and everything beneath it.  */
+
+static void
+free_value (gfc_data_value * p)
+{
+  gfc_data_value *q;
+
+  for (; p; p = q)
+    {
+      q = p->next;
+      gfc_free_expr (p->expr);
+      gfc_free (p);
+    }
+}
+
+
+/* Free a list of gfc_data structures.  */
+
+void
+gfc_free_data (gfc_data * p)
+{
+  gfc_data *q;
+
+  for (; p; p = q)
+    {
+      q = p->next;
+
+      free_variable (p->var);
+      free_value (p->value);
+
+      gfc_free (p);
+    }
+}
+
+
+static match var_element (gfc_data_variable *);
+
+/* Match a list of variables terminated by an iterator and a right
+   parenthesis.  */
+
+static match
+var_list (gfc_data_variable * parent)
+{
+  gfc_data_variable *tail, var;
+  match m;
+
+  m = var_element (&var);
+  if (m == MATCH_ERROR)
+    return MATCH_ERROR;
+  if (m == MATCH_NO)
+    goto syntax;
+
+  tail = gfc_get_data_variable ();
+  *tail = var;
+
+  parent->list = tail;
+
+  for (;;)
+    {
+      if (gfc_match_char (',') != MATCH_YES)
+       goto syntax;
+
+      m = gfc_match_iterator (&parent->iter, 1);
+      if (m == MATCH_YES)
+       break;
+      if (m == MATCH_ERROR)
+       return MATCH_ERROR;
+
+      m = var_element (&var);
+      if (m == MATCH_ERROR)
+       return MATCH_ERROR;
+      if (m == MATCH_NO)
+       goto syntax;
+
+      tail->next = gfc_get_data_variable ();
+      tail = tail->next;
+
+      *tail = var;
+    }
+
+  if (gfc_match_char (')') != MATCH_YES)
+    goto syntax;
+  return MATCH_YES;
+
+syntax:
+  gfc_syntax_error (ST_DATA);
+  return MATCH_ERROR;
+}
+
+
+/* Match a single element in a data variable list, which can be a
+   variable-iterator list.  */
+
+static match
+var_element (gfc_data_variable * new)
+{
+  match m;
+  gfc_symbol *sym;
+
+  memset (new, 0, sizeof (gfc_data_variable));
+
+  if (gfc_match_char ('(') == MATCH_YES)
+    return var_list (new);
+
+  m = gfc_match_variable (&new->expr, 0);
+  if (m != MATCH_YES)
+    return m;
+
+  sym = new->expr->symtree->n.sym;
+
+  if(sym->value != NULL)
+    {
+      gfc_error ("Variable '%s' at %C already has an initialization",
+                sym->name);
+      return MATCH_ERROR;
+    }
+
+#if 0 /* TODO: Find out where to move this message */
+  if (sym->attr.in_common)
+    /* See if sym is in the blank common block.  */
+    for (t = &sym->ns->blank_common; t; t = t->common_next)
+      if (sym == t->head)
+       {
+         gfc_error ("DATA statement at %C may not initialize variable "
+                    "'%s' from blank COMMON", sym->name);
+         return MATCH_ERROR;
+       }
+#endif
+
+  if (gfc_add_data (&sym->attr, sym->name, &new->expr->where) == FAILURE)
+    return MATCH_ERROR;
+
+  return MATCH_YES;
+}
+
+
+/* Match the top-level list of data variables.  */
+
+static match
+top_var_list (gfc_data * d)
+{
+  gfc_data_variable var, *tail, *new;
+  match m;
+
+  tail = NULL;
+
+  for (;;)
+    {
+      m = var_element (&var);
+      if (m == MATCH_NO)
+       goto syntax;
+      if (m == MATCH_ERROR)
+       return MATCH_ERROR;
+
+      new = gfc_get_data_variable ();
+      *new = var;
+
+      if (tail == NULL)
+       d->var = new;
+      else
+       tail->next = new;
+
+      tail = new;
+
+      if (gfc_match_char ('/') == MATCH_YES)
+       break;
+      if (gfc_match_char (',') != MATCH_YES)
+       goto syntax;
+    }
+
+  return MATCH_YES;
+
+syntax:
+  gfc_syntax_error (ST_DATA);
+  return MATCH_ERROR;
+}
+
+
+static match
+match_data_constant (gfc_expr ** result)
+{
+  char name[GFC_MAX_SYMBOL_LEN + 1];
+  gfc_symbol *sym;
+  gfc_expr *expr;
+  match m;
+
+  m = gfc_match_literal_constant (&expr, 1);
+  if (m == MATCH_YES)
+    {
+      *result = expr;
+      return MATCH_YES;
+    }
+
+  if (m == MATCH_ERROR)
+    return MATCH_ERROR;
+
+  m = gfc_match_null (result);
+  if (m != MATCH_NO)
+    return m;
+
+  m = gfc_match_name (name);
+  if (m != MATCH_YES)
+    return m;
+
+  if (gfc_find_symbol (name, NULL, 1, &sym))
+    return MATCH_ERROR;
+
+  if (sym == NULL
+      || (sym->attr.flavor != FL_PARAMETER && sym->attr.flavor != FL_DERIVED))
+    {
+      gfc_error ("Symbol '%s' must be a PARAMETER in DATA statement at %C",
+                name);
+      return MATCH_ERROR;
+    }
+  else if (sym->attr.flavor == FL_DERIVED)
+    return gfc_match_structure_constructor (sym, result);
+
+  *result = gfc_copy_expr (sym->value);
+  return MATCH_YES;
+}
+
+
+/* Match a list of values in a DATA statement.  The leading '/' has
+   already been seen at this point.  */
+
+static match
+top_val_list (gfc_data * data)
+{
+  gfc_data_value *new, *tail;
+  gfc_expr *expr;
+  const char *msg;
+  match m;
+
+  tail = NULL;
+
+  for (;;)
+    {
+      m = match_data_constant (&expr);
+      if (m == MATCH_NO)
+       goto syntax;
+      if (m == MATCH_ERROR)
+       return MATCH_ERROR;
+
+      new = gfc_get_data_value ();
+
+      if (tail == NULL)
+       data->value = new;
+      else
+       tail->next = new;
+
+      tail = new;
+
+      if (expr->ts.type != BT_INTEGER || gfc_match_char ('*') != MATCH_YES)
+       {
+         tail->expr = expr;
+         tail->repeat = 1;
+       }
+      else
+       {
+         signed int tmp;
+         msg = gfc_extract_int (expr, &tmp);
+         gfc_free_expr (expr);
+         if (msg != NULL)
+           {
+             gfc_error (msg);
+             return MATCH_ERROR;
+           }
+         tail->repeat = tmp;
+
+         m = match_data_constant (&tail->expr);
+         if (m == MATCH_NO)
+           goto syntax;
+         if (m == MATCH_ERROR)
+           return MATCH_ERROR;
+       }
+
+      if (gfc_match_char ('/') == MATCH_YES)
+       break;
+      if (gfc_match_char (',') == MATCH_NO)
+       goto syntax;
+    }
+
+  return MATCH_YES;
+
+syntax:
+  gfc_syntax_error (ST_DATA);
+  return MATCH_ERROR;
+}
+
+
+/* Matches an old style initialization.  */
+
+static match
+match_old_style_init (const char *name)
+{
+  match m;
+  gfc_symtree *st;
+  gfc_data *newdata;
+
+  /* Set up data structure to hold initializers.  */
+  gfc_find_sym_tree (name, NULL, 0, &st);
+         
+  newdata = gfc_get_data ();
+  newdata->var = gfc_get_data_variable ();
+  newdata->var->expr = gfc_get_variable_expr (st);
+
+  /* Match initial value list. This also eats the terminal
+     '/'.  */
+  m = top_val_list (newdata);
+  if (m != MATCH_YES)
+    {
+      gfc_free (newdata);
+      return m;
+    }
+
+  if (gfc_pure (NULL))
+    {
+      gfc_error ("Initialization at %C is not allowed in a PURE procedure");
+      gfc_free (newdata);
+      return MATCH_ERROR;
+    }
+
+  /* Chain in namespace list of DATA initializers.  */
+  newdata->next = gfc_current_ns->data;
+  gfc_current_ns->data = newdata;
+
+  return m;
+}
+
+/* Match the stuff following a DATA statement. If ERROR_FLAG is set,
+   we are matching a DATA statement and are therefore issuing an error
+   if we encounter something unexpected, if not, we're trying to match 
+   an old-style initialization expression of the form INTEGER I /2/.  */
+
+match
+gfc_match_data (void)
+{
+  gfc_data *new;
+  match m;
+
+  for (;;)
+    {
+      new = gfc_get_data ();
+      new->where = gfc_current_locus;
+
+      m = top_var_list (new);
+      if (m != MATCH_YES)
+       goto cleanup;
+
+      m = top_val_list (new);
+      if (m != MATCH_YES)
+       goto cleanup;
+
+      new->next = gfc_current_ns->data;
+      gfc_current_ns->data = new;
+
+      if (gfc_match_eos () == MATCH_YES)
+       break;
+
+      gfc_match_char (',');    /* Optional comma */
+    }
+
+  if (gfc_pure (NULL))
+    {
+      gfc_error ("DATA statement at %C is not allowed in a PURE procedure");
+      return MATCH_ERROR;
+    }
+
+  return MATCH_YES;
+
+cleanup:
+  gfc_free_data (new);
+  return MATCH_ERROR;
+}
+
+
+/************************ Declaration statements *********************/
+
 /* Match an intent specification.  Since this can only happen after an
    INTENT word, a legal intent-spec must follow.  */
 
@@ -131,29 +530,34 @@ syntax:
 }
 
 
-/* Special subroutine for finding a symbol.  If we're compiling a
-   function or subroutine and the parent compilation unit is an
-   interface, then check to see if the name we've been given is the
-   name of the interface (located in another namespace).  If so,
-   return that symbol.  If not, use gfc_get_symbol().  */
+/* Special subroutine for finding a symbol.  Check if the name is found
+   in the current name space.  If not, and we're compiling a function or
+   subroutine and the parent compilation unit is an interface, then check
+   to see if the name we've been given is the name of the interface
+   (located in another namespace).  */
 
 static int
 find_special (const char *name, gfc_symbol ** result)
 {
   gfc_state_data *s;
+  int i;
 
+  i = gfc_get_symbol (name, NULL, result);
+  if (i==0) 
+    goto end;
+  
   if (gfc_current_state () != COMP_SUBROUTINE
       && gfc_current_state () != COMP_FUNCTION)
-    goto normal;
+    goto end;
 
   s = gfc_state_stack->previous;
   if (s == NULL)
-    goto normal;
+    goto end;
 
   if (s->state != COMP_INTERFACE)
-    goto normal;
+    goto end;
   if (s->sym == NULL)
-    goto normal;               /* Nameless interface */
+    goto end;                  /* Nameless interface */
 
   if (strcmp (name, s->sym->name) == 0)
     {
@@ -161,8 +565,8 @@ find_special (const char *name, gfc_symbol ** result)
       return 0;
     }
 
-normal:
-  return gfc_get_symbol (name, NULL, result);
+end:
+  return i;
 }
 
 
@@ -186,7 +590,7 @@ get_proc_name (const char *name, gfc_symbol ** result)
   if (*result == NULL)
     return rc;
 
-  /* Deal with ENTRY problem */
+  /* ??? Deal with ENTRY problem */
 
   st = gfc_new_symtree (&gfc_current_ns->sym_root, name);
 
@@ -199,7 +603,8 @@ get_proc_name (const char *name, gfc_symbol ** result)
   if (sym->ns->proc_name != NULL
       && sym->ns->proc_name->attr.flavor == FL_MODULE
       && sym->attr.proc != PROC_MODULE
-      && gfc_add_procedure (&sym->attr, PROC_MODULE, NULL) == FAILURE)
+      && gfc_add_procedure (&sym->attr, PROC_MODULE,
+                           sym->name, NULL) == FAILURE)
     rc = 2;
 
   return rc;
@@ -216,7 +621,8 @@ build_sym (const char *name, gfc_charlen * cl,
   symbol_attribute attr;
   gfc_symbol *sym;
 
-  if (find_special (name, &sym))
+  /* if (find_special (name, &sym)) */
+  if (gfc_get_symbol (name, NULL, &sym))
     return FAILURE;
 
   /* Start updating the symbol table.  Add basic type attribute
@@ -246,6 +652,30 @@ build_sym (const char *name, gfc_charlen * cl,
   return SUCCESS;
 }
 
+/* Set character constant to the given length. The constant will be padded or
+   truncated.  */
+
+void
+gfc_set_constant_character_len (int len, gfc_expr * expr)
+{
+  char * s;
+  int slen;
+
+  gcc_assert (expr->expr_type == EXPR_CONSTANT);
+  gcc_assert (expr->ts.type == BT_CHARACTER && expr->ts.kind == 1);
+
+  slen = expr->value.character.length;
+  if (len != slen)
+    {
+      s = gfc_getmem (len);
+      memcpy (s, expr->value.character.string, MIN (len, slen));
+      if (len > slen)
+       memset (&s[slen], ' ', len - slen);
+      gfc_free (expr->value.character.string);
+      expr->value.character.string = s;
+      expr->value.character.length = len;
+    }
+}
 
 /* Function called by variable_decl() that adds an initialization
    expression to a symbol.  */
@@ -305,11 +735,48 @@ add_init_expr_to_sym (const char *name, gfc_expr ** initp,
          return FAILURE;
        }
 
-      /* Checking a derived type parameter has to be put off until later.  */
+      /* Check if the assignment can happen. This has to be put off
+        until later for a derived type variable.  */
       if (sym->ts.type != BT_DERIVED && init->ts.type != BT_DERIVED
          && gfc_check_assign_symbol (sym, init) == FAILURE)
        return FAILURE;
 
+      if (sym->ts.type == BT_CHARACTER && sym->ts.cl)
+       {
+         /* Update symbol character length according initializer.  */
+         if (sym->ts.cl->length == NULL)
+           {
+             /* If there are multiple CHARACTER variables declared on
+                the same line, we don't want them to share the same
+               length.  */
+             sym->ts.cl = gfc_get_charlen ();
+             sym->ts.cl->next = gfc_current_ns->cl_list;
+             gfc_current_ns->cl_list = sym->ts.cl;
+
+             if (init->expr_type == EXPR_CONSTANT)
+               sym->ts.cl->length =
+                       gfc_int_expr (init->value.character.length);
+             else if (init->expr_type == EXPR_ARRAY)
+               sym->ts.cl->length = gfc_copy_expr (init->ts.cl->length);
+           }
+         /* Update initializer character length according symbol.  */
+         else if (sym->ts.cl->length->expr_type == EXPR_CONSTANT)
+           {
+             int len = mpz_get_si (sym->ts.cl->length->value.integer);
+             gfc_constructor * p;
+
+             if (init->expr_type == EXPR_CONSTANT)
+               gfc_set_constant_character_len (len, init);
+             else if (init->expr_type == EXPR_ARRAY)
+               {
+                 gfc_free_expr (init->ts.cl->length);
+                 init->ts.cl->length = gfc_copy_expr (sym->ts.cl->length);
+                 for (p = init->value.constructor; p; p = p->next)
+                   gfc_set_constant_character_len (len, p->expr);
+               }
+           }
+       }
+
       /* Add initializer.  Make sure we keep the ranks sane.  */
       if (sym->attr.dimension && init->rank == 0)
        init->rank = sym->as->rank;
@@ -418,8 +885,9 @@ gfc_match_null (gfc_expr ** result)
   gfc_intrinsic_symbol (sym);
 
   if (sym->attr.proc != PROC_INTRINSIC
-      && (gfc_add_procedure (&sym->attr, PROC_INTRINSIC, NULL) == FAILURE
-         || gfc_add_function (&sym->attr, NULL) == FAILURE))
+      && (gfc_add_procedure (&sym->attr, PROC_INTRINSIC,
+                            sym->name, NULL) == FAILURE
+         || gfc_add_function (&sym->attr, sym->name, NULL) == FAILURE))
     return MATCH_ERROR;
 
   e = gfc_get_expr ();
@@ -439,7 +907,7 @@ gfc_match_null (gfc_expr ** result)
    symbol table or the current interface.  */
 
 static match
-variable_decl (void)
+variable_decl (int elem)
 {
   char name[GFC_MAX_SYMBOL_LEN + 1];
   gfc_expr *initializer, *char_len;
@@ -483,8 +951,20 @@ variable_decl (void)
          cl->length = char_len;
          break;
 
+       /* Non-constant lengths need to be copied after the first
+          element.  */
        case MATCH_NO:
-         cl = current_ts.cl;
+         if (elem > 1 && current_ts.cl->length
+               && current_ts.cl->length->expr_type != EXPR_CONSTANT)
+           {
+             cl = gfc_get_charlen ();
+             cl->next = gfc_current_ns->cl_list;
+             gfc_current_ns->cl_list = cl;
+             cl->length = gfc_copy_expr (current_ts.cl->length);
+           }
+         else
+           cl = current_ts.cl;
+
          break;
 
        case MATCH_ERROR:
@@ -494,7 +974,7 @@ variable_decl (void)
 
   /* OK, we've successfully matched the declaration.  Now put the
      symbol in the current namespace, because it might be used in the
-     optional intialization expression for this symbol, e.g. this is
+     optional initialization expression for this symbol, e.g. this is
      perfectly legal:
 
      integer, parameter :: i = huge(i)
@@ -524,6 +1004,24 @@ variable_decl (void)
       goto cleanup;
     }
 
+  /* We allow old-style initializations of the form
+       integer i /2/, j(4) /3*3, 1/
+     (if no colon has been seen). These are different from data
+     statements in that initializers are only allowed to apply to the
+     variable immediately preceding, i.e.
+       integer i, j /1, 2/
+     is not allowed. Therefore we have to do some work manually, that
+     could otherwise be left to the matchers for DATA statements.  */
+
+  if (!colon_seen && gfc_match (" /") == MATCH_YES)
+    {
+      if (gfc_notify_std (GFC_STD_GNU, "Extension: Old-style "
+                         "initialization at %C") == FAILURE)
+       return MATCH_ERROR;
+     
+      return match_old_style_init (name);
+    }
+
   /* The double colon must be present in order to have initializers.
      Otherwise the statement is ambiguous with an assignment statement.  */
   if (colon_seen)
@@ -596,7 +1094,7 @@ variable_decl (void)
     t = add_init_expr_to_sym (name, &initializer, &var_locus);
   else
     {
-      if (current_ts.type == BT_DERIVED && !initializer)
+      if (current_ts.type == BT_DERIVED && !current_attr.pointer && !initializer)
        initializer = gfc_default_initializer (&current_ts);
       t = build_struct (name, cl, &initializer, &as);
     }
@@ -632,7 +1130,7 @@ gfc_match_old_kind_spec (gfc_typespec * ts)
   if (ts->type == BT_COMPLEX && ts->kind == 16)
     ts->kind = 8;
 
-  if (gfc_validate_kind (ts->type, ts->kind) == -1)
+  if (gfc_validate_kind (ts->type, ts->kind, true) < 0)
     {
       gfc_error ("Old-style kind %d not supported for type %s at %C",
                 ts->kind, gfc_basic_typename (ts->type));
@@ -692,7 +1190,7 @@ gfc_match_kind_spec (gfc_typespec * ts)
   gfc_free_expr (e);
   e = NULL;
 
-  if (gfc_validate_kind (ts->type, ts->kind) == -1)
+  if (gfc_validate_kind (ts->type, ts->kind, true) < 0)
     {
       gfc_error ("Kind %d not supported for type %s at %C", ts->kind,
                 gfc_basic_typename (ts->type));
@@ -727,7 +1225,7 @@ match_char_spec (gfc_typespec * ts)
   gfc_expr *len;
   match m;
 
-  kind = gfc_default_character_kind ();
+  kind = gfc_default_character_kind;
   len = NULL;
   seen_length = 0;
 
@@ -790,7 +1288,7 @@ match_char_spec (gfc_typespec * ts)
 
       gfc_match_small_int (&kind);
 
-      if (gfc_validate_kind (BT_CHARACTER, kind) == -1)
+      if (gfc_validate_kind (BT_CHARACTER, kind, true) < 0)
        {
          gfc_error ("Kind %d is not a CHARACTER kind at %C", kind);
          return MATCH_YES;
@@ -833,7 +1331,7 @@ syntax:
   m = MATCH_ERROR;
 
 done:
-  if (m == MATCH_YES && gfc_validate_kind (BT_CHARACTER, kind) == -1)
+  if (m == MATCH_YES && gfc_validate_kind (BT_CHARACTER, kind, true) < 0)
     {
       gfc_error ("Kind %d is not a CHARACTER kind at %C", kind);
       m = MATCH_ERROR;
@@ -888,10 +1386,28 @@ match_type_spec (gfc_typespec * ts, int implicit_flag)
 
   gfc_clear_ts (ts);
 
+  if (gfc_match (" byte") == MATCH_YES)
+    {
+      if (gfc_notify_std(GFC_STD_GNU, "Extension: BYTE type at %C") 
+         == FAILURE)
+       return MATCH_ERROR;
+
+      if (gfc_validate_kind (BT_INTEGER, 1, true) < 0)
+       {
+         gfc_error ("BYTE type used at %C "
+                    "is not available on the target machine");
+         return MATCH_ERROR;
+       }
+      
+      ts->type = BT_INTEGER;
+      ts->kind = 1;
+      return MATCH_YES;
+    }
+
   if (gfc_match (" integer") == MATCH_YES)
     {
       ts->type = BT_INTEGER;
-      ts->kind = gfc_default_integer_kind ();
+      ts->kind = gfc_default_integer_kind;
       goto get_kind;
     }
 
@@ -907,35 +1423,35 @@ match_type_spec (gfc_typespec * ts, int implicit_flag)
   if (gfc_match (" real") == MATCH_YES)
     {
       ts->type = BT_REAL;
-      ts->kind = gfc_default_real_kind ();
+      ts->kind = gfc_default_real_kind;
       goto get_kind;
     }
 
   if (gfc_match (" double precision") == MATCH_YES)
     {
       ts->type = BT_REAL;
-      ts->kind = gfc_default_double_kind ();
+      ts->kind = gfc_default_double_kind;
       return MATCH_YES;
     }
 
   if (gfc_match (" complex") == MATCH_YES)
     {
       ts->type = BT_COMPLEX;
-      ts->kind = gfc_default_complex_kind ();
+      ts->kind = gfc_default_complex_kind;
       goto get_kind;
     }
 
   if (gfc_match (" double complex") == MATCH_YES)
     {
       ts->type = BT_COMPLEX;
-      ts->kind = gfc_default_double_kind ();
+      ts->kind = gfc_default_double_kind;
       return MATCH_YES;
     }
 
   if (gfc_match (" logical") == MATCH_YES)
     {
       ts->type = BT_LOGICAL;
-      ts->kind = gfc_default_logical_kind ();
+      ts->kind = gfc_default_logical_kind;
       goto get_kind;
     }
 
@@ -951,7 +1467,7 @@ match_type_spec (gfc_typespec * ts, int implicit_flag)
     }
 
   if (sym->attr.flavor != FL_DERIVED
-      && gfc_add_flavor (&sym->attr, FL_DERIVED, NULL) == FAILURE)
+      && gfc_add_flavor (&sym->attr, FL_DERIVED, sym->name, NULL) == FAILURE)
     return MATCH_ERROR;
 
   ts->type = BT_DERIVED;
@@ -1141,7 +1657,7 @@ gfc_match_implicit (void)
              /* Check for CHARACTER with no length parameter.  */
              if (ts.type == BT_CHARACTER && !ts.cl)
                {
-                 ts.kind = gfc_default_character_kind ();
+                 ts.kind = gfc_default_character_kind;
                  ts.cl = gfc_get_charlen ();
                  ts.cl->next = gfc_current_ns->cl_list;
                  gfc_current_ns->cl_list = ts.cl;
@@ -1376,6 +1892,20 @@ match_attr_spec (void)
          goto cleanup;
        }
 
+      if ((d == DECL_PRIVATE || d == DECL_PUBLIC)
+            && gfc_current_state () != COMP_MODULE)
+       {
+         if (d == DECL_PRIVATE)
+           attr = "PRIVATE";
+         else
+           attr = "PUBLIC";
+
+         gfc_error ("%s attribute at %L is not allowed outside of a MODULE",
+                    attr, &seen_at[d]);
+         m = MATCH_ERROR;
+         goto cleanup;
+       }
+
       switch (d)
        {
        case DECL_ALLOCATABLE:
@@ -1383,7 +1913,7 @@ match_attr_spec (void)
          break;
 
        case DECL_DIMENSION:
-         t = gfc_add_dimension (&current_attr, &seen_at[d]);
+         t = gfc_add_dimension (&current_attr, NULL, &seen_at[d]);
          break;
 
        case DECL_EXTERNAL:
@@ -1411,7 +1941,7 @@ match_attr_spec (void)
          break;
 
        case DECL_PARAMETER:
-         t = gfc_add_flavor (&current_attr, FL_PARAMETER, &seen_at[d]);
+         t = gfc_add_flavor (&current_attr, FL_PARAMETER, NULL, &seen_at[d]);
          break;
 
        case DECL_POINTER:
@@ -1419,15 +1949,17 @@ match_attr_spec (void)
          break;
 
        case DECL_PRIVATE:
-         t = gfc_add_access (&current_attr, ACCESS_PRIVATE, &seen_at[d]);
+         t = gfc_add_access (&current_attr, ACCESS_PRIVATE, NULL,
+                             &seen_at[d]);
          break;
 
        case DECL_PUBLIC:
-         t = gfc_add_access (&current_attr, ACCESS_PUBLIC, &seen_at[d]);
+         t = gfc_add_access (&current_attr, ACCESS_PUBLIC, NULL,
+                             &seen_at[d]);
          break;
 
        case DECL_SAVE:
-         t = gfc_add_save (&current_attr, &seen_at[d]);
+         t = gfc_add_save (&current_attr, NULL, &seen_at[d]);
          break;
 
        case DECL_TARGET:
@@ -1463,6 +1995,7 @@ gfc_match_data_decl (void)
 {
   gfc_symbol *sym;
   match m;
+  int elem;
 
   m = match_type_spec (&current_ts, 0);
   if (m != MATCH_YES)
@@ -1514,10 +2047,12 @@ ok:
   if (m == MATCH_NO && current_ts.type == BT_CHARACTER && old_char_selector)
     gfc_match_char (',');
 
-  /* Give the types/attributes to symbols that follow.  */
+  /* Give the types/attributes to symbols that follow. Give the element
+     a number so that repeat character length expressions can be copied.  */
+  elem = 1;
   for (;;)
     {
-      m = variable_decl ();
+      m = variable_decl (elem++);
       if (m == MATCH_ERROR)
        goto cleanup;
       if (m == MATCH_NO)
@@ -1662,7 +2197,7 @@ gfc_match_formal_arglist (gfc_symbol * progname, int st_flag, int null_flag)
          dummy procedure.  We don't apply these attributes to formal
          arguments of statement functions.  */
       if (sym != NULL && !st_flag
-         && (gfc_add_dummy (&sym->attr, NULL) == FAILURE
+         && (gfc_add_dummy (&sym->attr, sym->name, NULL) == FAILURE
              || gfc_missing_attr (&sym->attr, NULL) == FAILURE))
        {
          m = MATCH_ERROR;
@@ -1762,8 +2297,8 @@ match_result (gfc_symbol * function, gfc_symbol ** result)
   if (gfc_get_symbol (name, NULL, &r))
     return MATCH_ERROR;
 
-  if (gfc_add_flavor (&r->attr, FL_VARIABLE, NULL) == FAILURE
-      || gfc_add_result (&r->attr, NULL) == FAILURE)
+  if (gfc_add_flavor (&r->attr, FL_VARIABLE, r->name, NULL) == FAILURE
+      || gfc_add_result (&r->attr, r->name, NULL) == FAILURE)
     return MATCH_ERROR;
 
   *result = r;
@@ -1833,7 +2368,7 @@ gfc_match_function_decl (void)
   /* Make changes to the symbol.  */
   m = MATCH_ERROR;
 
-  if (gfc_add_function (&sym->attr, NULL) == FAILURE)
+  if (gfc_add_function (&sym->attr, sym->name, NULL) == FAILURE)
     goto cleanup;
 
   if (gfc_missing_attr (&sym->attr, NULL) == FAILURE
@@ -1871,79 +2406,137 @@ cleanup:
 match
 gfc_match_entry (void)
 {
-  gfc_symbol *function, *result, *entry;
+  gfc_symbol *proc;
+  gfc_symbol *result;
+  gfc_symbol *entry;
   char name[GFC_MAX_SYMBOL_LEN + 1];
   gfc_compile_state state;
   match m;
+  gfc_entry_list *el;
 
   m = gfc_match_name (name);
   if (m != MATCH_YES)
     return m;
 
+  state = gfc_current_state ();
+  if (state != COMP_SUBROUTINE && state != COMP_FUNCTION)
+    {
+      switch (state)
+       {
+         case COMP_PROGRAM:
+           gfc_error ("ENTRY statement at %C cannot appear within a PROGRAM");
+           break;
+         case COMP_MODULE:
+           gfc_error ("ENTRY statement at %C cannot appear within a MODULE");
+           break;
+         case COMP_BLOCK_DATA:
+           gfc_error
+             ("ENTRY statement at %C cannot appear within a BLOCK DATA");
+           break;
+         case COMP_INTERFACE:
+           gfc_error
+             ("ENTRY statement at %C cannot appear within an INTERFACE");
+           break;
+         case COMP_DERIVED:
+           gfc_error
+             ("ENTRY statement at %C cannot appear "
+              "within a DERIVED TYPE block");
+           break;
+         case COMP_IF:
+           gfc_error
+             ("ENTRY statement at %C cannot appear within an IF-THEN block");
+           break;
+         case COMP_DO:
+           gfc_error
+             ("ENTRY statement at %C cannot appear within a DO block");
+           break;
+         case COMP_SELECT:
+           gfc_error
+             ("ENTRY statement at %C cannot appear within a SELECT block");
+           break;
+         case COMP_FORALL:
+           gfc_error
+             ("ENTRY statement at %C cannot appear within a FORALL block");
+           break;
+         case COMP_WHERE:
+           gfc_error
+             ("ENTRY statement at %C cannot appear within a WHERE block");
+           break;
+         case COMP_CONTAINS:
+           gfc_error
+             ("ENTRY statement at %C cannot appear "
+              "within a contained subprogram");
+           break;
+         default:
+           gfc_internal_error ("gfc_match_entry(): Bad state");
+       }
+      return MATCH_ERROR;
+    }
+
+  if (gfc_current_ns->parent != NULL
+      && gfc_current_ns->parent->proc_name
+      && gfc_current_ns->parent->proc_name->attr.flavor != FL_MODULE)
+    {
+      gfc_error("ENTRY statement at %C cannot appear in a "
+               "contained procedure");
+      return MATCH_ERROR;
+    }
+
   if (get_proc_name (name, &entry))
     return MATCH_ERROR;
 
-  gfc_enclosing_unit (&state);
-  switch (state)
+  proc = gfc_current_block ();
+
+  if (state == COMP_SUBROUTINE)
     {
-    case COMP_SUBROUTINE:
+      /* An entry in a subroutine.  */
       m = gfc_match_formal_arglist (entry, 0, 1);
       if (m != MATCH_YES)
        return MATCH_ERROR;
 
-      if (gfc_current_state () != COMP_SUBROUTINE)
-       goto exec_construct;
-
-      if (gfc_add_entry (&entry->attr, NULL) == FAILURE
-         || gfc_add_subroutine (&entry->attr, NULL) == FAILURE)
+      if (gfc_add_entry (&entry->attr, entry->name, NULL) == FAILURE
+         || gfc_add_subroutine (&entry->attr, entry->name, NULL) == FAILURE)
        return MATCH_ERROR;
-
-      break;
-
-    case COMP_FUNCTION:
-      m = gfc_match_formal_arglist (entry, 0, 0);
+    }
+  else
+    {
+      /* An entry in a function.  */
+      m = gfc_match_formal_arglist (entry, 0, 1);
       if (m != MATCH_YES)
        return MATCH_ERROR;
 
-      if (gfc_current_state () != COMP_FUNCTION)
-       goto exec_construct;
-      function = gfc_state_stack->sym;
-
       result = NULL;
 
       if (gfc_match_eos () == MATCH_YES)
        {
-         if (gfc_add_entry (&entry->attr, NULL) == FAILURE
-             || gfc_add_function (&entry->attr, NULL) == FAILURE)
+         if (gfc_add_entry (&entry->attr, entry->name, NULL) == FAILURE
+             || gfc_add_function (&entry->attr, entry->name, NULL) == FAILURE)
            return MATCH_ERROR;
 
-         entry->result = function->result;
-
+         entry->result = entry;
        }
       else
        {
-         m = match_result (function, &result);
+         m = match_result (proc, &result);
          if (m == MATCH_NO)
            gfc_syntax_error (ST_ENTRY);
          if (m != MATCH_YES)
            return MATCH_ERROR;
 
-         if (gfc_add_result (&result->attr, NULL) == FAILURE
-             || gfc_add_entry (&entry->attr, NULL) == FAILURE
-             || gfc_add_function (&entry->attr, NULL) == FAILURE)
+         if (gfc_add_result (&result->attr, result->name, NULL) == FAILURE
+             || gfc_add_entry (&entry->attr, result->name, NULL) == FAILURE
+             || gfc_add_function (&entry->attr, result->name,
+                                  NULL) == FAILURE)
            return MATCH_ERROR;
+
+         entry->result = result;
        }
 
-      if (function->attr.recursive && result == NULL)
+      if (proc->attr.recursive && result == NULL)
        {
          gfc_error ("RESULT attribute required in ENTRY statement at %C");
          return MATCH_ERROR;
        }
-
-      break;
-
-    default:
-      goto exec_construct;
     }
 
   if (gfc_match_eos () != MATCH_YES)
@@ -1952,13 +2545,23 @@ gfc_match_entry (void)
       return MATCH_ERROR;
     }
 
-  return MATCH_YES;
+  entry->attr.recursive = proc->attr.recursive;
+  entry->attr.elemental = proc->attr.elemental;
+  entry->attr.pure = proc->attr.pure;
 
-exec_construct:
-  gfc_error ("ENTRY statement at %C cannot appear within %s",
-            gfc_state_name (gfc_current_state ()));
+  el = gfc_get_entry_list ();
+  el->sym = entry;
+  el->next = gfc_current_ns->entries;
+  gfc_current_ns->entries = el;
+  if (el->next)
+    el->id = el->next->id + 1;
+  else
+    el->id = 1;
 
-  return MATCH_ERROR;
+  new_st.op = EXEC_ENTRY;
+  new_st.ext.entry = el;
+
+  return MATCH_YES;
 }
 
 
@@ -1988,7 +2591,7 @@ gfc_match_subroutine (void)
     return MATCH_ERROR;
   gfc_new_block = sym;
 
-  if (gfc_add_subroutine (&sym->attr, NULL) == FAILURE)
+  if (gfc_add_subroutine (&sym->attr, sym->name, NULL) == FAILURE)
     return MATCH_ERROR;
 
   if (gfc_match_formal_arglist (sym, 0, 1) != MATCH_YES)
@@ -2007,7 +2610,7 @@ gfc_match_subroutine (void)
 }
 
 
-/* Return nonzero if we're currenly compiling a contained procedure.  */
+/* Return nonzero if we're currently compiling a contained procedure.  */
 
 static int
 contained_procedure (void)
@@ -2138,8 +2741,8 @@ gfc_match_end (gfc_statement * st)
       if (!eos_ok)
        {
          /* We would have required END [something]  */
-         gfc_error ("%s statement expected at %C",
-                    gfc_ascii_statement (*st));
+         gfc_error ("%s statement expected at %L",
+                    gfc_ascii_statement (*st), &old_loc);
          goto cleanup;
        }
 
@@ -2275,7 +2878,7 @@ attr_decl1 (void)
 
   if ((current_attr.external || current_attr.intrinsic)
       && sym->attr.flavor != FL_PROCEDURE
-      && gfc_add_flavor (&sym->attr, FL_PROCEDURE, NULL) == FAILURE)
+      && gfc_add_flavor (&sym->attr, FL_PROCEDURE, sym->name, NULL) == FAILURE)
     {
       m = MATCH_ERROR;
       goto cleanup;
@@ -2402,7 +3005,7 @@ gfc_match_dimension (void)
 {
 
   gfc_clear_attr (&current_attr);
-  gfc_add_dimension (&current_attr, NULL);
+  gfc_add_dimension (&current_attr, NULL, NULL);
 
   return attr_decl ();
 }
@@ -2455,7 +3058,7 @@ access_attr_decl (gfc_statement st)
          if (gfc_add_access (&sym->attr,
                              (st ==
                               ST_PUBLIC) ? ACCESS_PUBLIC : ACCESS_PRIVATE,
-                             NULL) == FAILURE)
+                             sym->name, NULL) == FAILURE)
            return MATCH_ERROR;
 
          break;
@@ -2598,12 +3201,22 @@ do_parm (void)
     }
 
   if (gfc_check_assign_symbol (sym, init) == FAILURE
-      || gfc_add_flavor (&sym->attr, FL_PARAMETER, NULL) == FAILURE)
+      || gfc_add_flavor (&sym->attr, FL_PARAMETER, sym->name, NULL) == FAILURE)
     {
       m = MATCH_ERROR;
       goto cleanup;
     }
 
+  if (sym->ts.type == BT_CHARACTER
+      && sym->ts.cl != NULL
+      && sym->ts.cl->length != NULL
+      && sym->ts.cl->length->expr_type == EXPR_CONSTANT
+      && init->expr_type == EXPR_CONSTANT
+      && init->ts.type == BT_CHARACTER
+      && init->ts.kind == 1)
+    gfc_set_constant_character_len (
+      mpz_get_si (sym->ts.cl->length->value.integer), init);
+
   sym->value = init;
   return MATCH_YES;
 
@@ -2682,7 +3295,8 @@ gfc_match_save (void)
       switch (m)
        {
        case MATCH_YES:
-         if (gfc_add_save (&sym->attr, &gfc_current_locus) == FAILURE)
+         if (gfc_add_save (&sym->attr, sym->name,
+                           &gfc_current_locus) == FAILURE)
            return MATCH_ERROR;
          goto next_item;
 
@@ -2721,7 +3335,7 @@ syntax:
 
 /* Match a module procedure statement.  Note that we have to modify
    symbols in the parent's namespace because the current one was there
-   to receive symbols that are in a interface's formal argument list.  */
+   to receive symbols that are in an interface's formal argument list.  */
 
 match
 gfc_match_modproc (void)
@@ -2751,7 +3365,8 @@ gfc_match_modproc (void)
        return MATCH_ERROR;
 
       if (sym->attr.proc != PROC_MODULE
-         && gfc_add_procedure (&sym->attr, PROC_MODULE, NULL) == FAILURE)
+         && gfc_add_procedure (&sym->attr, PROC_MODULE,
+                               sym->name, NULL) == FAILURE)
        return MATCH_ERROR;
 
       if (gfc_add_interface (sym) == FAILURE)
@@ -2798,7 +3413,7 @@ loop:
          return MATCH_ERROR;
        }
 
-      if (gfc_add_access (&attr, ACCESS_PRIVATE, NULL) == FAILURE)
+      if (gfc_add_access (&attr, ACCESS_PRIVATE, NULL, NULL) == FAILURE)
        return MATCH_ERROR;
       goto loop;
     }
@@ -2811,7 +3426,7 @@ loop:
          return MATCH_ERROR;
        }
 
-      if (gfc_add_access (&attr, ACCESS_PUBLIC, NULL) == FAILURE)
+      if (gfc_add_access (&attr, ACCESS_PUBLIC, NULL, NULL) == FAILURE)
        return MATCH_ERROR;
       goto loop;
     }
@@ -2854,9 +3469,9 @@ loop:
      components.  The ways this can happen is via a function
      definition, an INTRINSIC statement or a subtype in another
      derived type that is a pointer.  The first part of the AND clause
-     is true if a the symbol is not the return value of a function. */
+     is true if a the symbol is not the return value of a function.  */
   if (sym->attr.flavor != FL_DERIVED
-      && gfc_add_flavor (&sym->attr, FL_DERIVED, NULL) == FAILURE)
+      && gfc_add_flavor (&sym->attr, FL_DERIVED, sym->name, NULL) == FAILURE)
     return MATCH_ERROR;
 
   if (sym->components != NULL)
@@ -2868,7 +3483,7 @@ loop:
     }
 
   if (attr.access != ACCESS_UNKNOWN
-      && gfc_add_access (&sym->attr, attr.access, NULL) == FAILURE)
+      && gfc_add_access (&sym->attr, attr.access, sym->name, NULL) == FAILURE)
     return MATCH_ERROR;
 
   gfc_new_block = sym;