OSDN Git Service

2006-01-26 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / fortran / decl.c
index 2ecd143..7a80f81 100644 (file)
@@ -1,5 +1,5 @@
 /* Declaration statement matcher
-   Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
    Contributed by Andy Vaught
 
 This file is part of GCC.
@@ -43,6 +43,30 @@ static symbol_attribute current_attr;
 static gfc_array_spec *current_as;
 static int colon_seen;
 
+/* Initializer of the previous enumerator.  */
+
+static gfc_expr *last_initializer;
+
+/* History of all the enumerators is maintained, so that
+   kind values of all the enumerators could be updated depending
+   upon the maximum initialized value.  */
+
+typedef struct enumerator_history
+{
+  gfc_symbol *sym;
+  gfc_expr *initializer;
+  struct enumerator_history *next;
+}
+enumerator_history;
+
+/* Header of enum history chain.  */
+
+static enumerator_history *enum_history = NULL;
+
+/* Pointer of enum history node containing largest initializer.  */
+
+static enumerator_history *max_enum = NULL;
+
 /* gfc_new_block points to the symbol of a newly matched block.  */
 
 gfc_symbol *gfc_new_block;
@@ -179,24 +203,19 @@ var_element (gfc_data_variable * new)
 
   sym = new->expr->symtree->n.sym;
 
-  if(sym->value != NULL)
+  if (!sym->attr.function && gfc_current_ns->parent && gfc_current_ns->parent == sym->ns)
     {
-      gfc_error ("Variable '%s' at %C already has an initialization",
-                sym->name);
+      gfc_error ("Host associated variable '%s' may not be in the DATA "
+                "statement at %C.", 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_current_state () != COMP_BLOCK_DATA
+       && sym->attr.in_common
+       && gfc_notify_std (GFC_STD_GNU, "Extension: initialization of "
+                          "common block variable '%s' in DATA statement at %C",
+                          sym->name) == FAILURE)
+    return MATCH_ERROR;
 
   if (gfc_add_data (&sym->attr, sym->name, &new->expr->where) == FAILURE)
     return MATCH_ERROR;
@@ -496,7 +515,7 @@ match_char_length (gfc_expr ** expr)
   if (m != MATCH_YES)
     return m;
 
-  m = gfc_match_small_literal_int (&length);
+  m = gfc_match_small_literal_int (&length, NULL);
   if (m == MATCH_ERROR)
     return m;
 
@@ -584,17 +603,42 @@ get_proc_name (const char *name, gfc_symbol ** result)
   int rc;
 
   if (gfc_current_ns->parent == NULL)
-    return gfc_get_symbol (name, NULL, result);
+    rc = gfc_get_symbol (name, NULL, result);
+  else
+    rc = gfc_get_symbol (name, gfc_current_ns->parent, result);
 
-  rc = gfc_get_symbol (name, gfc_current_ns->parent, result);
-  if (*result == NULL)
-    return rc;
+  sym = *result;
 
-  /* ??? Deal with ENTRY problem */
+  if (sym && !sym->new && gfc_current_state () != COMP_INTERFACE)
+    {
+      /* Trap another encompassed procedure with the same name.  All
+        these conditions are necessary to avoid picking up an entry
+        whose name clashes with that of the encompassing procedure;
+        this is handled using gsymbols to register unique,globally
+        accessible names.  */
+      if (sym->attr.flavor != 0
+           && sym->attr.proc != 0
+           && sym->formal)
+       gfc_error_now ("Procedure '%s' at %C is already defined at %L",
+                      name, &sym->declared_at);
+
+      /* Trap declarations of attributes in encompassing scope.  The
+        signature for this is that ts.kind is set.  Legitimate
+        references only set ts.type.  */
+      if (sym->ts.kind != 0
+           && sym->attr.proc == 0
+           && gfc_current_ns->parent != NULL
+           && sym->attr.access == 0)
+       gfc_error_now ("Procedure '%s' at %C has an explicit interface"
+                      " and must not have attributes declared at %L",
+                      name, &sym->declared_at);
+    }
+
+  if (gfc_current_ns->parent == NULL || *result == NULL)
+    return rc;
 
   st = gfc_new_symtree (&gfc_current_ns->sym_root, name);
 
-  sym = *result;
   st->n.sym = sym;
   sym->refs++;
 
@@ -677,6 +721,63 @@ gfc_set_constant_character_len (int len, gfc_expr * expr)
     }
 }
 
+
+/* Function to create and update the enumerator history 
+   using the information passed as arguments.
+   Pointer "max_enum" is also updated, to point to 
+   enum history node containing largest initializer.  
+
+   SYM points to the symbol node of enumerator.
+   INIT points to its enumerator value.   */
+
+static void 
+create_enum_history(gfc_symbol *sym, gfc_expr *init)
+{
+  enumerator_history *new_enum_history;
+  gcc_assert (sym != NULL && init != NULL);
+
+  new_enum_history = gfc_getmem (sizeof (enumerator_history));
+
+  new_enum_history->sym = sym;
+  new_enum_history->initializer = init;
+  new_enum_history->next = NULL;
+
+  if (enum_history == NULL)
+    {
+      enum_history = new_enum_history;
+      max_enum = enum_history;
+    }
+  else
+    {
+      new_enum_history->next = enum_history;
+      enum_history = new_enum_history;
+
+      if (mpz_cmp (max_enum->initializer->value.integer, 
+                  new_enum_history->initializer->value.integer) < 0)
+        max_enum = new_enum_history;
+    }
+}
+
+
+/* Function to free enum kind history.  */ 
+
+void 
+gfc_free_enum_history(void)
+{
+  enumerator_history *current = enum_history;  
+  enumerator_history *next;  
+
+  while (current != NULL)
+    {
+      next = current->next;
+      gfc_free (current);
+      current = next;
+    }
+  max_enum = NULL;
+  enum_history = NULL;
+}
+
+
 /* Function called by variable_decl() that adds an initialization
    expression to a symbol.  */
 
@@ -785,6 +886,10 @@ add_init_expr_to_sym (const char *name, gfc_expr ** initp,
       *initp = NULL;
     }
 
+  /* Maintain enumerator history.  */
+  if (gfc_current_state () == COMP_ENUM)
+    create_enum_history (sym, init);
+
   return SUCCESS;
 }
 
@@ -912,13 +1017,18 @@ variable_decl (int elem)
   char name[GFC_MAX_SYMBOL_LEN + 1];
   gfc_expr *initializer, *char_len;
   gfc_array_spec *as;
+  gfc_array_spec *cp_as; /* Extra copy for Cray Pointees.  */
   gfc_charlen *cl;
   locus var_locus;
   match m;
   try t;
+  gfc_symbol *sym;
+  locus old_locus;
 
   initializer = NULL;
   as = NULL;
+  cp_as = NULL;
+  old_locus = gfc_current_locus;
 
   /* When we get here, we've just matched a list of attributes and
      maybe a type and a double colon.  The next thing we expect to see
@@ -931,10 +1041,21 @@ variable_decl (int elem)
 
   /* Now we could see the optional array spec. or character length.  */
   m = gfc_match_array_spec (&as);
-  if (m == MATCH_ERROR)
+  if (gfc_option.flag_cray_pointer && m == MATCH_YES)
+    cp_as = gfc_copy_array_spec (as);
+  else if (m == MATCH_ERROR)
     goto cleanup;
+
   if (m == MATCH_NO)
     as = gfc_copy_array_spec (current_as);
+  else if (gfc_current_state () == COMP_ENUM)
+    {
+      gfc_error ("Enumerator cannot be array at %C");
+      gfc_free_enum_history ();
+      m = MATCH_ERROR;
+      goto cleanup;
+    }
+
 
   char_len = NULL;
   cl = NULL;
@@ -972,6 +1093,49 @@ variable_decl (int elem)
        }
     }
 
+  /*  If this symbol has already shown up in a Cray Pointer declaration,
+      then we want to set the type & bail out. */
+  if (gfc_option.flag_cray_pointer)
+    {
+      gfc_find_symbol (name, gfc_current_ns, 1, &sym);
+      if (sym != NULL && sym->attr.cray_pointee)
+       {
+         sym->ts.type = current_ts.type;
+         sym->ts.kind = current_ts.kind;
+         sym->ts.cl = cl;
+         sym->ts.derived = current_ts.derived;
+         m = MATCH_YES;
+       
+         /* Check to see if we have an array specification.  */
+         if (cp_as != NULL)
+           {
+             if (sym->as != NULL)
+               {
+                 gfc_error ("Duplicate array spec for Cray pointee at %C.");
+                 gfc_free_array_spec (cp_as);
+                 m = MATCH_ERROR;
+                 goto cleanup;
+               }
+             else
+               {
+                 if (gfc_set_array_spec (sym, cp_as, &var_locus) == FAILURE)
+                   gfc_internal_error ("Couldn't set pointee array spec.");
+             
+                 /* Fix the array spec.  */
+                 m = gfc_mod_pointee_as (sym->as);  
+                 if (m == MATCH_ERROR)
+                   goto cleanup;
+               }
+           }     
+         goto cleanup;
+       }
+      else
+       {
+         gfc_free_array_spec (cp_as);
+       }
+    }
+  
+    
   /* OK, we've successfully matched the declaration.  Now put the
      symbol in the current namespace, because it might be used in the
      optional initialization expression for this symbol, e.g. this is
@@ -1087,6 +1251,30 @@ variable_decl (int elem)
        }
     }
 
+  /* Check if we are parsing an enumeration and if the current enumerator
+     variable has an initializer or not. If it does not have an
+     initializer, the initialization value of the previous enumerator 
+     (stored in last_initializer) is incremented by 1 and is used to
+     initialize the current enumerator.  */
+  if (gfc_current_state () == COMP_ENUM)
+    {
+      if (initializer == NULL)
+        initializer = gfc_enum_initializer (last_initializer, old_locus);
+      if (initializer == NULL || initializer->ts.type != BT_INTEGER)
+        {
+          gfc_error("ENUMERATOR %L not initialized with integer expression",
+                   &var_locus);
+          m = MATCH_ERROR; 
+          gfc_free_enum_history ();
+          goto cleanup;
+        }
+
+      /* Store this current initializer, for the next enumerator
+        variable to be parsed.  */
+      last_initializer = initializer;
+    }
+
   /* Add the initializer.  Note that it is fine if initializer is
      NULL here, because we sometimes also need to check if a
      declaration *must* have an initialization expression.  */
@@ -1116,28 +1304,40 @@ match
 gfc_match_old_kind_spec (gfc_typespec * ts)
 {
   match m;
+  int original_kind;
 
   if (gfc_match_char ('*') != MATCH_YES)
     return MATCH_NO;
 
-  m = gfc_match_small_literal_int (&ts->kind);
+  m = gfc_match_small_literal_int (&ts->kind, NULL);
   if (m != MATCH_YES)
     return MATCH_ERROR;
 
+  original_kind = ts->kind;
+
   /* Massage the kind numbers for complex types.  */
-  if (ts->type == BT_COMPLEX && ts->kind == 8)
-    ts->kind = 4;
-  if (ts->type == BT_COMPLEX && ts->kind == 16)
-    ts->kind = 8;
+  if (ts->type == BT_COMPLEX)
+    {
+      if (ts->kind % 2)
+        {
+          gfc_error ("Old-style type declaration %s*%d not supported at %C",
+                     gfc_basic_typename (ts->type), original_kind);
+          return MATCH_ERROR;
+        }
+      ts->kind /= 2;
+    }
 
   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));
-
+      gfc_error ("Old-style type declaration %s*%d not supported at %C",
+                 gfc_basic_typename (ts->type), original_kind);
       return MATCH_ERROR;
     }
 
+  if (gfc_notify_std (GFC_STD_GNU, "Nonstandard type declaration %s*%d at %C",
+                     gfc_basic_typename (ts->type), original_kind) == FAILURE)
+    return MATCH_ERROR;
+
   return MATCH_YES;
 }
 
@@ -1443,6 +1643,10 @@ match_type_spec (gfc_typespec * ts, int implicit_flag)
 
   if (gfc_match (" double complex") == MATCH_YES)
     {
+      if (gfc_notify_std (GFC_STD_GNU, "DOUBLE COMPLEX at %C does not "
+                         "conform to the Fortran 95 standard") == FAILURE)
+       return MATCH_ERROR;
+
       ts->type = BT_COMPLEX;
       ts->kind = gfc_default_double_kind;
       return MATCH_YES;
@@ -1789,6 +1993,12 @@ match_attr_spec (void)
       d = (decl_types) gfc_match_strings (decls);
       if (d == DECL_NONE || d == DECL_COLON)
        break;
+       
+      if (gfc_current_state () == COMP_ENUM)
+        {
+          gfc_error ("Enumerator cannot have attributes %C");
+          return MATCH_ERROR;
+        }
 
       seen[d]++;
       seen_at[d] = gfc_current_locus;
@@ -1808,6 +2018,18 @@ match_attr_spec (void)
        }
     }
 
+  /* If we are parsing an enumeration and have ensured that no other
+     attributes are present we can now set the parameter attribute.  */
+  if (gfc_current_state () == COMP_ENUM)
+    {
+      t = gfc_add_flavor (&current_attr, FL_PARAMETER, NULL, NULL);
+      if (t == FAILURE)
+        {
+          m = MATCH_ERROR;
+          goto cleanup;
+        }
+    }
+
   /* No double colon, so assume that we've been looking at something
      else the whole time.  */
   if (d == DECL_NONE)
@@ -2027,17 +2249,21 @@ gfc_match_data_decl (void)
       if (current_attr.pointer && gfc_current_state () == COMP_DERIVED)
        goto ok;
 
-      if (gfc_find_symbol (current_ts.derived->name,
-                          current_ts.derived->ns->parent, 1, &sym) == 0)
-       goto ok;
+      gfc_find_symbol (current_ts.derived->name,
+                        current_ts.derived->ns->parent, 1, &sym);
 
-      /* Hope that an ambiguous symbol is itself masked by a type definition.  */
-      if (sym != NULL && sym->attr.flavor == FL_DERIVED)
+      /* Any symbol that we find had better be a type definition
+         which has its components defined.  */
+      if (sym != NULL && sym->attr.flavor == FL_DERIVED
+           && current_ts.derived->components != NULL)
        goto ok;
 
-      gfc_error ("Derived type at %C has not been previously defined");
-      m = MATCH_ERROR;
-      goto cleanup;
+      /* Now we have an error, which we signal, and then fix up
+        because the knock-on is plain and simple confusing.  */
+      gfc_error_now ("Derived type at %C has not been previously defined "
+                "and so cannot appear in a derived type definition.");
+      current_attr.pointer = 1;
+      goto ok;
     }
 
 ok:
@@ -2345,7 +2571,12 @@ gfc_match_function_decl (void)
 
   m = gfc_match_formal_arglist (sym, 0, 0);
   if (m == MATCH_NO)
-    gfc_error ("Expected formal argument list in function definition at %C");
+    {
+      gfc_error ("Expected formal argument list in function "
+                "definition at %C");
+      m = MATCH_ERROR;
+      goto cleanup;
+    }
   else if (m == MATCH_ERROR)
     goto cleanup;
 
@@ -2400,6 +2631,29 @@ cleanup:
   return m;
 }
 
+/* This is mostly a copy of parse.c(add_global_procedure) but modified to pass the
+   name of the entry, rather than the gfc_current_block name, and to return false
+   upon finding an existing global entry.  */
+
+static bool
+add_global_entry (const char * name, int sub)
+{
+  gfc_gsymbol *s;
+
+  s = gfc_get_gsymbol(name);
+
+  if (s->defined
+       || (s->type != GSYM_UNKNOWN && s->type != (sub ? GSYM_SUBROUTINE : GSYM_FUNCTION)))
+    global_used(s, NULL);
+  else
+    {
+      s->type = sub ? GSYM_SUBROUTINE : GSYM_FUNCTION;
+      s->where = gfc_current_locus;
+      s->defined = 1;
+      return true;
+    }
+  return false;
+}
 
 /* Match an ENTRY statement.  */
 
@@ -2413,6 +2667,7 @@ gfc_match_entry (void)
   gfc_compile_state state;
   match m;
   gfc_entry_list *el;
+  locus old_loc;
 
   m = gfc_match_name (name);
   if (m != MATCH_YES)
@@ -2490,6 +2745,9 @@ gfc_match_entry (void)
   if (state == COMP_SUBROUTINE)
     {
       /* An entry in a subroutine.  */
+      if (!add_global_entry (name, 1))
+       return MATCH_ERROR;
+
       m = gfc_match_formal_arglist (entry, 0, 1);
       if (m != MATCH_YES)
        return MATCH_ERROR;
@@ -2500,8 +2758,29 @@ gfc_match_entry (void)
     }
   else
     {
-      /* An entry in a function.  */
-      m = gfc_match_formal_arglist (entry, 0, 1);
+      /* An entry in a function.
+         We need to take special care because writing
+            ENTRY f()
+         as
+            ENTRY f
+         is allowed, whereas
+            ENTRY f() RESULT (r)
+         can't be written as
+            ENTRY f RESULT (r).  */
+      if (!add_global_entry (name, 0))
+       return MATCH_ERROR;
+
+      old_loc = gfc_current_locus;
+      if (gfc_match_eos () == MATCH_YES)
+       {
+         gfc_current_locus = old_loc;
+         /* Match the empty argument list, and add the interface to
+            the symbol.  */
+         m = gfc_match_formal_arglist (entry, 0, 1);
+       }
+      else
+       m = gfc_match_formal_arglist (entry, 0, 0);
+
       if (m != MATCH_YES)
        return MATCH_ERROR;
 
@@ -2626,6 +2905,40 @@ contained_procedure (void)
   return 0;
 }
 
+/* Set the kind of each enumerator.  The kind is selected such that it is 
+   interoperable with the corresponding C enumeration type, making
+   sure that -fshort-enums is honored.  */
+
+static void
+set_enum_kind(void)
+{
+  enumerator_history *current_history = NULL;
+  int kind;
+  int i;
+
+  if (max_enum == NULL || enum_history == NULL)
+    return;
+
+  if (!gfc_option.fshort_enums)
+    return; 
+  
+  i = 0;
+  do
+    {
+      kind = gfc_integer_kinds[i++].kind;
+    }
+  while (kind < gfc_c_int_kind 
+        && gfc_check_integer_range (max_enum->initializer->value.integer,
+                                    kind) != ARITH_OK);
+
+  current_history = enum_history;
+  while (current_history != NULL)
+    {
+      current_history->sym->ts.kind = kind;
+      current_history = current_history->next;
+    }
+}
+
 /* Match any of the various end-block statements.  Returns the type of
    END to the caller.  The END INTERFACE, END IF, END DO and END
    SELECT statements cannot be replaced by a single END statement.  */
@@ -2731,6 +3044,15 @@ gfc_match_end (gfc_statement * st)
       eos_ok = 0;
       break;
 
+    case COMP_ENUM:
+      *st = ST_END_ENUM;
+      target = " enum";
+      eos_ok = 0;
+      last_initializer = NULL;
+      set_enum_kind ();
+      gfc_free_enum_history ();
+      break;
+
     default:
       gfc_error ("Unexpected END statement at %C");
       goto cleanup;
@@ -2875,6 +3197,20 @@ attr_decl1 (void)
       m = MATCH_ERROR;
       goto cleanup;
     }
+    
+  if (sym->attr.cray_pointee && sym->as != NULL)
+    {
+      /* Fix the array spec.  */
+      m = gfc_mod_pointee_as (sym->as);        
+      if (m == MATCH_ERROR)
+       goto cleanup;
+    }
+
+  if (gfc_add_attribute (&sym->attr, &var_locus, current_attr.intent) == FAILURE)
+    {
+      m = MATCH_ERROR;
+      goto cleanup;
+    }
 
   if ((current_attr.external || current_attr.intrinsic)
       && sym->attr.flavor != FL_PROCEDURE
@@ -2928,12 +3264,162 @@ attr_decl (void)
 }
 
 
+/* This routine matches Cray Pointer declarations of the form:
+   pointer ( <pointer>, <pointee> )
+   or
+   pointer ( <pointer1>, <pointee1> ), ( <pointer2>, <pointee2> ), ...   
+   The pointer, if already declared, should be an integer.  Otherwise, we 
+   set it as BT_INTEGER with kind gfc_index_integer_kind.  The pointee may
+   be either a scalar, or an array declaration.  No space is allocated for
+   the pointee.  For the statement 
+   pointer (ipt, ar(10))
+   any subsequent uses of ar will be translated (in C-notation) as
+   ar(i) => ((<type> *) ipt)(i)   
+   After gimplification, pointee variable will disappear in the code.  */
+
+static match
+cray_pointer_decl (void)
+{
+  match m;
+  gfc_array_spec *as;
+  gfc_symbol *cptr; /* Pointer symbol.  */
+  gfc_symbol *cpte; /* Pointee symbol.  */
+  locus var_locus;
+  bool done = false;
+
+  while (!done)
+    {
+      if (gfc_match_char ('(') != MATCH_YES)
+       {
+         gfc_error ("Expected '(' at %C");
+         return MATCH_ERROR;   
+       }
+      /* Match pointer.  */
+      var_locus = gfc_current_locus;
+      gfc_clear_attr (&current_attr);
+      gfc_add_cray_pointer (&current_attr, &var_locus);
+      current_ts.type = BT_INTEGER;
+      current_ts.kind = gfc_index_integer_kind;
+
+      m = gfc_match_symbol (&cptr, 0);  
+      if (m != MATCH_YES)
+       {
+         gfc_error ("Expected variable name at %C");
+         return m;
+       }
+  
+      if (gfc_add_cray_pointer (&cptr->attr, &var_locus) == FAILURE)
+       return MATCH_ERROR;
+
+      gfc_set_sym_referenced (cptr);      
+
+      if (cptr->ts.type == BT_UNKNOWN) /* Override the type, if necessary.  */
+       {
+         cptr->ts.type = BT_INTEGER;
+         cptr->ts.kind = gfc_index_integer_kind; 
+       }
+      else if (cptr->ts.type != BT_INTEGER)
+       {
+         gfc_error ("Cray pointer at %C must be an integer.");
+         return MATCH_ERROR;
+       }
+      else if (cptr->ts.kind < gfc_index_integer_kind)
+       gfc_warning ("Cray pointer at %C has %d bytes of precision;"
+                    " memory addresses require %d bytes.",
+                    cptr->ts.kind,
+                    gfc_index_integer_kind);
+
+      if (gfc_match_char (',') != MATCH_YES)
+       {
+         gfc_error ("Expected \",\" at %C");
+         return MATCH_ERROR;    
+       }
+
+      /* Match Pointee.  */  
+      var_locus = gfc_current_locus;
+      gfc_clear_attr (&current_attr);
+      gfc_add_cray_pointee (&current_attr, &var_locus);
+      current_ts.type = BT_UNKNOWN;
+      current_ts.kind = 0;
+
+      m = gfc_match_symbol (&cpte, 0);
+      if (m != MATCH_YES)
+       {
+         gfc_error ("Expected variable name at %C");
+         return m;
+       }
+       
+      /* Check for an optional array spec.  */
+      m = gfc_match_array_spec (&as);
+      if (m == MATCH_ERROR)
+       {
+         gfc_free_array_spec (as);
+         return m;
+       }
+      else if (m == MATCH_NO)
+       {
+         gfc_free_array_spec (as);
+         as = NULL;
+       }   
+
+      if (gfc_add_cray_pointee (&cpte->attr, &var_locus) == FAILURE)
+       return MATCH_ERROR;
+
+      gfc_set_sym_referenced (cpte);
+
+      if (cpte->as == NULL)
+       {
+         if (gfc_set_array_spec (cpte, as, &var_locus) == FAILURE)
+           gfc_internal_error ("Couldn't set Cray pointee array spec.");
+       }
+      else if (as != NULL)
+       {
+         gfc_error ("Duplicate array spec for Cray pointee at %C.");
+         gfc_free_array_spec (as);
+         return MATCH_ERROR;
+       }
+      
+      as = NULL;
+    
+      if (cpte->as != NULL)
+       {
+         /* Fix array spec.  */
+         m = gfc_mod_pointee_as (cpte->as);
+         if (m == MATCH_ERROR)
+           return m;
+       } 
+   
+      /* Point the Pointee at the Pointer.  */
+      cpte->cp_pointer = cptr;
+
+      if (gfc_match_char (')') != MATCH_YES)
+       {
+         gfc_error ("Expected \")\" at %C");
+         return MATCH_ERROR;    
+       }
+      m = gfc_match_char (',');
+      if (m != MATCH_YES)
+       done = true; /* Stop searching for more declarations.  */
+
+    }
+  
+  if (m == MATCH_ERROR /* Failed when trying to find ',' above.  */
+      || gfc_match_eos () != MATCH_YES)
+    {
+      gfc_error ("Expected \",\" or end of statement at %C");
+      return MATCH_ERROR;
+    }
+  return MATCH_YES;
+}
+
+
 match
 gfc_match_external (void)
 {
 
   gfc_clear_attr (&current_attr);
-  gfc_add_external (&current_attr, NULL);
+  current_attr.external = 1;
 
   return attr_decl ();
 }
@@ -2950,7 +3436,7 @@ gfc_match_intent (void)
     return MATCH_ERROR;
 
   gfc_clear_attr (&current_attr);
-  gfc_add_intent (&current_attr, intent, NULL);        /* Can't fail */
+  current_attr.intent = intent;
 
   return attr_decl ();
 }
@@ -2961,7 +3447,7 @@ gfc_match_intrinsic (void)
 {
 
   gfc_clear_attr (&current_attr);
-  gfc_add_intrinsic (&current_attr, NULL);
+  current_attr.intrinsic = 1;
 
   return attr_decl ();
 }
@@ -2972,7 +3458,7 @@ gfc_match_optional (void)
 {
 
   gfc_clear_attr (&current_attr);
-  gfc_add_optional (&current_attr, NULL);
+  current_attr.optional = 1;
 
   return attr_decl ();
 }
@@ -2981,11 +3467,24 @@ gfc_match_optional (void)
 match
 gfc_match_pointer (void)
 {
-
-  gfc_clear_attr (&current_attr);
-  gfc_add_pointer (&current_attr, NULL);
-
-  return attr_decl ();
+  gfc_gobble_whitespace ();
+  if (gfc_peek_char () == '(')
+    {
+      if (!gfc_option.flag_cray_pointer)
+       {
+         gfc_error ("Cray pointer declaration at %C requires -fcray-pointer"
+                    " flag.");
+         return MATCH_ERROR;
+       }
+      return cray_pointer_decl ();
+    }
+  else
+    {
+      gfc_clear_attr (&current_attr);
+      current_attr.pointer = 1;
+    
+      return attr_decl ();
+    }
 }
 
 
@@ -2994,7 +3493,7 @@ gfc_match_allocatable (void)
 {
 
   gfc_clear_attr (&current_attr);
-  gfc_add_allocatable (&current_attr, NULL);
+  current_attr.allocatable = 1;
 
   return attr_decl ();
 }
@@ -3005,7 +3504,7 @@ gfc_match_dimension (void)
 {
 
   gfc_clear_attr (&current_attr);
-  gfc_add_dimension (&current_attr, NULL, NULL);
+  current_attr.dimension = 1;
 
   return attr_decl ();
 }
@@ -3016,7 +3515,7 @@ gfc_match_target (void)
 {
 
   gfc_clear_attr (&current_attr);
-  gfc_add_target (&current_attr, NULL);
+  current_attr.target = 1;
 
   return attr_decl ();
 }
@@ -3493,3 +3992,113 @@ loop:
 
   return MATCH_YES;
 }
+
+
+/* Cray Pointees can be declared as: 
+      pointer (ipt, a (n,m,...,*)) 
+   By default, this is treated as an AS_ASSUMED_SIZE array.  We'll
+   cheat and set a constant bound of 1 for the last dimension, if this
+   is the case. Since there is no bounds-checking for Cray Pointees,
+   this will be okay.  */
+
+try
+gfc_mod_pointee_as (gfc_array_spec *as)
+{
+  as->cray_pointee = true; /* This will be useful to know later.  */
+  if (as->type == AS_ASSUMED_SIZE)
+    {
+      as->type = AS_EXPLICIT;
+      as->upper[as->rank - 1] = gfc_int_expr (1);
+      as->cp_was_assumed = true;
+    }
+  else if (as->type == AS_ASSUMED_SHAPE)
+    {
+      gfc_error ("Cray Pointee at %C cannot be assumed shape array");
+      return MATCH_ERROR;
+    }
+  return MATCH_YES;
+}
+
+
+/* Match the enum definition statement, here we are trying to match 
+   the first line of enum definition statement.  
+   Returns MATCH_YES if match is found.  */
+
+match
+gfc_match_enum (void)
+{
+  match m;
+  
+  m = gfc_match_eos ();
+  if (m != MATCH_YES)
+    return m;
+
+  if (gfc_notify_std (GFC_STD_F2003, 
+                     "New in Fortran 2003: ENUM AND ENUMERATOR at %C")
+      == FAILURE)
+    return MATCH_ERROR;
+
+  return MATCH_YES;
+}
+
+
+/* Match the enumerator definition statement. */
+
+match
+gfc_match_enumerator_def (void)
+{
+  match m;
+  int elem; 
+  
+  gfc_clear_ts (&current_ts);
+  
+  m = gfc_match (" enumerator");
+  if (m != MATCH_YES)
+    return m;
+  
+  if (gfc_current_state () != COMP_ENUM)
+    {
+      gfc_error ("ENUM definition statement expected before %C");
+      gfc_free_enum_history ();
+      return MATCH_ERROR;
+    }
+
+  (&current_ts)->type = BT_INTEGER;
+  (&current_ts)->kind = gfc_c_int_kind;
+  
+  m = match_attr_spec ();
+  if (m == MATCH_ERROR)
+    {
+      m = MATCH_NO;
+      goto cleanup;
+    }
+
+  elem = 1;
+  for (;;)
+    {
+      m = variable_decl (elem++);
+      if (m == MATCH_ERROR)
+       goto cleanup;
+      if (m == MATCH_NO)
+       break;
+
+      if (gfc_match_eos () == MATCH_YES)
+       goto cleanup;
+      if (gfc_match_char (',') != MATCH_YES)
+       break;
+    }
+
+  if (gfc_current_state () == COMP_ENUM)
+    {
+      gfc_free_enum_history ();
+      gfc_error ("Syntax error in ENUMERATOR definition at %C");
+      m = MATCH_ERROR;
+    }
+
+cleanup:
+  gfc_free_array_spec (current_as);
+  current_as = NULL;
+  return m;
+
+}
+