OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-stable/] [gcc-4.5.1/] [gcc/] [fortran/] [decl.c] - Diff between revs 816 and 826

Only display areas with differences | Details | Blame | View Log

Rev 816 Rev 826
/* Declaration statement matcher
/* Declaration statement matcher
   Copyright (C) 2002, 2004, 2005, 2006, 2007, 2008, 2009, 2010
   Copyright (C) 2002, 2004, 2005, 2006, 2007, 2008, 2009, 2010
   Free Software Foundation, Inc.
   Free Software Foundation, Inc.
   Contributed by Andy Vaught
   Contributed by Andy Vaught
 
 
This file is part of GCC.
This file is part of GCC.
 
 
GCC is free software; you can redistribute it and/or modify it under
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
Software Foundation; either version 3, or (at your option) any later
version.
version.
 
 
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.
for more details.
 
 
You should have received a copy of the GNU General Public License
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */
<http://www.gnu.org/licenses/>.  */
 
 
#include "config.h"
#include "config.h"
#include "system.h"
#include "system.h"
#include "gfortran.h"
#include "gfortran.h"
#include "match.h"
#include "match.h"
#include "parse.h"
#include "parse.h"
#include "flags.h"
#include "flags.h"
 
 
 
 
/* Macros to access allocate memory for gfc_data_variable,
/* Macros to access allocate memory for gfc_data_variable,
   gfc_data_value and gfc_data.  */
   gfc_data_value and gfc_data.  */
#define gfc_get_data_variable() XCNEW (gfc_data_variable)
#define gfc_get_data_variable() XCNEW (gfc_data_variable)
#define gfc_get_data_value() XCNEW (gfc_data_value)
#define gfc_get_data_value() XCNEW (gfc_data_value)
#define gfc_get_data() XCNEW (gfc_data)
#define gfc_get_data() XCNEW (gfc_data)
 
 
 
 
/* This flag is set if an old-style length selector is matched
/* This flag is set if an old-style length selector is matched
   during a type-declaration statement.  */
   during a type-declaration statement.  */
 
 
static int old_char_selector;
static int old_char_selector;
 
 
/* When variables acquire 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
   statement, they get them from the following static variables.  The
   first part of a declaration sets these variables and the second
   first part of a declaration sets these variables and the second
   part copies these into symbol structures.  */
   part copies these into symbol structures.  */
 
 
static gfc_typespec current_ts;
static gfc_typespec current_ts;
 
 
static symbol_attribute current_attr;
static symbol_attribute current_attr;
static gfc_array_spec *current_as;
static gfc_array_spec *current_as;
static int colon_seen;
static int colon_seen;
 
 
/* The current binding label (if any).  */
/* The current binding label (if any).  */
static char curr_binding_label[GFC_MAX_BINDING_LABEL_LEN + 1];
static char curr_binding_label[GFC_MAX_BINDING_LABEL_LEN + 1];
/* Need to know how many identifiers are on the current data declaration
/* Need to know how many identifiers are on the current data declaration
   line in case we're given the BIND(C) attribute with a NAME= specifier.  */
   line in case we're given the BIND(C) attribute with a NAME= specifier.  */
static int num_idents_on_line;
static int num_idents_on_line;
/* Need to know if a NAME= specifier was found during gfc_match_bind_c so we
/* Need to know if a NAME= specifier was found during gfc_match_bind_c so we
   can supply a name if the curr_binding_label is nil and NAME= was not.  */
   can supply a name if the curr_binding_label is nil and NAME= was not.  */
static int has_name_equals = 0;
static int has_name_equals = 0;
 
 
/* Initializer of the previous enumerator.  */
/* Initializer of the previous enumerator.  */
 
 
static gfc_expr *last_initializer;
static gfc_expr *last_initializer;
 
 
/* History of all the enumerators is maintained, so that
/* History of all the enumerators is maintained, so that
   kind values of all the enumerators could be updated depending
   kind values of all the enumerators could be updated depending
   upon the maximum initialized value.  */
   upon the maximum initialized value.  */
 
 
typedef struct enumerator_history
typedef struct enumerator_history
{
{
  gfc_symbol *sym;
  gfc_symbol *sym;
  gfc_expr *initializer;
  gfc_expr *initializer;
  struct enumerator_history *next;
  struct enumerator_history *next;
}
}
enumerator_history;
enumerator_history;
 
 
/* Header of enum history chain.  */
/* Header of enum history chain.  */
 
 
static enumerator_history *enum_history = NULL;
static enumerator_history *enum_history = NULL;
 
 
/* Pointer of enum history node containing largest initializer.  */
/* Pointer of enum history node containing largest initializer.  */
 
 
static enumerator_history *max_enum = NULL;
static enumerator_history *max_enum = NULL;
 
 
/* gfc_new_block points to the symbol of a newly matched block.  */
/* gfc_new_block points to the symbol of a newly matched block.  */
 
 
gfc_symbol *gfc_new_block;
gfc_symbol *gfc_new_block;
 
 
bool gfc_matching_function;
bool gfc_matching_function;
 
 
 
 
/********************* DATA statement subroutines *********************/
/********************* DATA statement subroutines *********************/
 
 
static bool in_match_data = false;
static bool in_match_data = false;
 
 
bool
bool
gfc_in_match_data (void)
gfc_in_match_data (void)
{
{
  return in_match_data;
  return in_match_data;
}
}
 
 
static void
static void
set_in_match_data (bool set_value)
set_in_match_data (bool set_value)
{
{
  in_match_data = set_value;
  in_match_data = set_value;
}
}
 
 
/* Free a gfc_data_variable structure and everything beneath it.  */
/* Free a gfc_data_variable structure and everything beneath it.  */
 
 
static void
static void
free_variable (gfc_data_variable *p)
free_variable (gfc_data_variable *p)
{
{
  gfc_data_variable *q;
  gfc_data_variable *q;
 
 
  for (; p; p = q)
  for (; p; p = q)
    {
    {
      q = p->next;
      q = p->next;
      gfc_free_expr (p->expr);
      gfc_free_expr (p->expr);
      gfc_free_iterator (&p->iter, 0);
      gfc_free_iterator (&p->iter, 0);
      free_variable (p->list);
      free_variable (p->list);
      gfc_free (p);
      gfc_free (p);
    }
    }
}
}
 
 
 
 
/* Free a gfc_data_value structure and everything beneath it.  */
/* Free a gfc_data_value structure and everything beneath it.  */
 
 
static void
static void
free_value (gfc_data_value *p)
free_value (gfc_data_value *p)
{
{
  gfc_data_value *q;
  gfc_data_value *q;
 
 
  for (; p; p = q)
  for (; p; p = q)
    {
    {
      q = p->next;
      q = p->next;
      gfc_free_expr (p->expr);
      gfc_free_expr (p->expr);
      gfc_free (p);
      gfc_free (p);
    }
    }
}
}
 
 
 
 
/* Free a list of gfc_data structures.  */
/* Free a list of gfc_data structures.  */
 
 
void
void
gfc_free_data (gfc_data *p)
gfc_free_data (gfc_data *p)
{
{
  gfc_data *q;
  gfc_data *q;
 
 
  for (; p; p = q)
  for (; p; p = q)
    {
    {
      q = p->next;
      q = p->next;
      free_variable (p->var);
      free_variable (p->var);
      free_value (p->value);
      free_value (p->value);
      gfc_free (p);
      gfc_free (p);
    }
    }
}
}
 
 
 
 
/* Free all data in a namespace.  */
/* Free all data in a namespace.  */
 
 
static void
static void
gfc_free_data_all (gfc_namespace *ns)
gfc_free_data_all (gfc_namespace *ns)
{
{
  gfc_data *d;
  gfc_data *d;
 
 
  for (;ns->data;)
  for (;ns->data;)
    {
    {
      d = ns->data->next;
      d = ns->data->next;
      gfc_free (ns->data);
      gfc_free (ns->data);
      ns->data = d;
      ns->data = d;
    }
    }
}
}
 
 
 
 
static match var_element (gfc_data_variable *);
static match var_element (gfc_data_variable *);
 
 
/* Match a list of variables terminated by an iterator and a right
/* Match a list of variables terminated by an iterator and a right
   parenthesis.  */
   parenthesis.  */
 
 
static match
static match
var_list (gfc_data_variable *parent)
var_list (gfc_data_variable *parent)
{
{
  gfc_data_variable *tail, var;
  gfc_data_variable *tail, var;
  match m;
  match m;
 
 
  m = var_element (&var);
  m = var_element (&var);
  if (m == MATCH_ERROR)
  if (m == MATCH_ERROR)
    return MATCH_ERROR;
    return MATCH_ERROR;
  if (m == MATCH_NO)
  if (m == MATCH_NO)
    goto syntax;
    goto syntax;
 
 
  tail = gfc_get_data_variable ();
  tail = gfc_get_data_variable ();
  *tail = var;
  *tail = var;
 
 
  parent->list = tail;
  parent->list = tail;
 
 
  for (;;)
  for (;;)
    {
    {
      if (gfc_match_char (',') != MATCH_YES)
      if (gfc_match_char (',') != MATCH_YES)
        goto syntax;
        goto syntax;
 
 
      m = gfc_match_iterator (&parent->iter, 1);
      m = gfc_match_iterator (&parent->iter, 1);
      if (m == MATCH_YES)
      if (m == MATCH_YES)
        break;
        break;
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      m = var_element (&var);
      m = var_element (&var);
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        return MATCH_ERROR;
        return MATCH_ERROR;
      if (m == MATCH_NO)
      if (m == MATCH_NO)
        goto syntax;
        goto syntax;
 
 
      tail->next = gfc_get_data_variable ();
      tail->next = gfc_get_data_variable ();
      tail = tail->next;
      tail = tail->next;
 
 
      *tail = var;
      *tail = var;
    }
    }
 
 
  if (gfc_match_char (')') != MATCH_YES)
  if (gfc_match_char (')') != MATCH_YES)
    goto syntax;
    goto syntax;
  return MATCH_YES;
  return MATCH_YES;
 
 
syntax:
syntax:
  gfc_syntax_error (ST_DATA);
  gfc_syntax_error (ST_DATA);
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
/* Match a single element in a data variable list, which can be a
/* Match a single element in a data variable list, which can be a
   variable-iterator list.  */
   variable-iterator list.  */
 
 
static match
static match
var_element (gfc_data_variable *new_var)
var_element (gfc_data_variable *new_var)
{
{
  match m;
  match m;
  gfc_symbol *sym;
  gfc_symbol *sym;
 
 
  memset (new_var, 0, sizeof (gfc_data_variable));
  memset (new_var, 0, sizeof (gfc_data_variable));
 
 
  if (gfc_match_char ('(') == MATCH_YES)
  if (gfc_match_char ('(') == MATCH_YES)
    return var_list (new_var);
    return var_list (new_var);
 
 
  m = gfc_match_variable (&new_var->expr, 0);
  m = gfc_match_variable (&new_var->expr, 0);
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    return m;
    return m;
 
 
  sym = new_var->expr->symtree->n.sym;
  sym = new_var->expr->symtree->n.sym;
 
 
  /* Symbol should already have an associated type.  */
  /* Symbol should already have an associated type.  */
  if (gfc_check_symbol_typed (sym, gfc_current_ns,
  if (gfc_check_symbol_typed (sym, gfc_current_ns,
                              false, gfc_current_locus) == FAILURE)
                              false, gfc_current_locus) == FAILURE)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  if (!sym->attr.function && gfc_current_ns->parent
  if (!sym->attr.function && gfc_current_ns->parent
      && gfc_current_ns->parent == sym->ns)
      && gfc_current_ns->parent == sym->ns)
    {
    {
      gfc_error ("Host associated variable '%s' may not be in the DATA "
      gfc_error ("Host associated variable '%s' may not be in the DATA "
                 "statement at %C", sym->name);
                 "statement at %C", sym->name);
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  if (gfc_current_state () != COMP_BLOCK_DATA
  if (gfc_current_state () != COMP_BLOCK_DATA
      && sym->attr.in_common
      && sym->attr.in_common
      && gfc_notify_std (GFC_STD_GNU, "Extension: initialization of "
      && gfc_notify_std (GFC_STD_GNU, "Extension: initialization of "
                         "common block variable '%s' in DATA statement at %C",
                         "common block variable '%s' in DATA statement at %C",
                         sym->name) == FAILURE)
                         sym->name) == FAILURE)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  if (gfc_add_data (&sym->attr, sym->name, &new_var->expr->where) == FAILURE)
  if (gfc_add_data (&sym->attr, sym->name, &new_var->expr->where) == FAILURE)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  return MATCH_YES;
  return MATCH_YES;
}
}
 
 
 
 
/* Match the top-level list of data variables.  */
/* Match the top-level list of data variables.  */
 
 
static match
static match
top_var_list (gfc_data *d)
top_var_list (gfc_data *d)
{
{
  gfc_data_variable var, *tail, *new_var;
  gfc_data_variable var, *tail, *new_var;
  match m;
  match m;
 
 
  tail = NULL;
  tail = NULL;
 
 
  for (;;)
  for (;;)
    {
    {
      m = var_element (&var);
      m = var_element (&var);
      if (m == MATCH_NO)
      if (m == MATCH_NO)
        goto syntax;
        goto syntax;
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      new_var = gfc_get_data_variable ();
      new_var = gfc_get_data_variable ();
      *new_var = var;
      *new_var = var;
 
 
      if (tail == NULL)
      if (tail == NULL)
        d->var = new_var;
        d->var = new_var;
      else
      else
        tail->next = new_var;
        tail->next = new_var;
 
 
      tail = new_var;
      tail = new_var;
 
 
      if (gfc_match_char ('/') == MATCH_YES)
      if (gfc_match_char ('/') == MATCH_YES)
        break;
        break;
      if (gfc_match_char (',') != MATCH_YES)
      if (gfc_match_char (',') != MATCH_YES)
        goto syntax;
        goto syntax;
    }
    }
 
 
  return MATCH_YES;
  return MATCH_YES;
 
 
syntax:
syntax:
  gfc_syntax_error (ST_DATA);
  gfc_syntax_error (ST_DATA);
  gfc_free_data_all (gfc_current_ns);
  gfc_free_data_all (gfc_current_ns);
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
static match
static match
match_data_constant (gfc_expr **result)
match_data_constant (gfc_expr **result)
{
{
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
  gfc_symbol *sym;
  gfc_symbol *sym;
  gfc_expr *expr;
  gfc_expr *expr;
  match m;
  match m;
  locus old_loc;
  locus old_loc;
 
 
  m = gfc_match_literal_constant (&expr, 1);
  m = gfc_match_literal_constant (&expr, 1);
  if (m == MATCH_YES)
  if (m == MATCH_YES)
    {
    {
      *result = expr;
      *result = expr;
      return MATCH_YES;
      return MATCH_YES;
    }
    }
 
 
  if (m == MATCH_ERROR)
  if (m == MATCH_ERROR)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  m = gfc_match_null (result);
  m = gfc_match_null (result);
  if (m != MATCH_NO)
  if (m != MATCH_NO)
    return m;
    return m;
 
 
  old_loc = gfc_current_locus;
  old_loc = gfc_current_locus;
 
 
  /* Should this be a structure component, try to match it
  /* Should this be a structure component, try to match it
     before matching a name.  */
     before matching a name.  */
  m = gfc_match_rvalue (result);
  m = gfc_match_rvalue (result);
  if (m == MATCH_ERROR)
  if (m == MATCH_ERROR)
    return m;
    return m;
 
 
  if (m == MATCH_YES && (*result)->expr_type == EXPR_STRUCTURE)
  if (m == MATCH_YES && (*result)->expr_type == EXPR_STRUCTURE)
    {
    {
      if (gfc_simplify_expr (*result, 0) == FAILURE)
      if (gfc_simplify_expr (*result, 0) == FAILURE)
        m = MATCH_ERROR;
        m = MATCH_ERROR;
      return m;
      return m;
    }
    }
 
 
  gfc_current_locus = old_loc;
  gfc_current_locus = old_loc;
 
 
  m = gfc_match_name (name);
  m = gfc_match_name (name);
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    return m;
    return m;
 
 
  if (gfc_find_symbol (name, NULL, 1, &sym))
  if (gfc_find_symbol (name, NULL, 1, &sym))
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  if (sym == NULL
  if (sym == NULL
      || (sym->attr.flavor != FL_PARAMETER && sym->attr.flavor != FL_DERIVED))
      || (sym->attr.flavor != FL_PARAMETER && sym->attr.flavor != FL_DERIVED))
    {
    {
      gfc_error ("Symbol '%s' must be a PARAMETER in DATA statement at %C",
      gfc_error ("Symbol '%s' must be a PARAMETER in DATA statement at %C",
                 name);
                 name);
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
  else if (sym->attr.flavor == FL_DERIVED)
  else if (sym->attr.flavor == FL_DERIVED)
    return gfc_match_structure_constructor (sym, result, false);
    return gfc_match_structure_constructor (sym, result, false);
 
 
  /* Check to see if the value is an initialization array expression.  */
  /* Check to see if the value is an initialization array expression.  */
  if (sym->value->expr_type == EXPR_ARRAY)
  if (sym->value->expr_type == EXPR_ARRAY)
    {
    {
      gfc_current_locus = old_loc;
      gfc_current_locus = old_loc;
 
 
      m = gfc_match_init_expr (result);
      m = gfc_match_init_expr (result);
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        return m;
        return m;
 
 
      if (m == MATCH_YES)
      if (m == MATCH_YES)
        {
        {
          if (gfc_simplify_expr (*result, 0) == FAILURE)
          if (gfc_simplify_expr (*result, 0) == FAILURE)
            m = MATCH_ERROR;
            m = MATCH_ERROR;
 
 
          if ((*result)->expr_type == EXPR_CONSTANT)
          if ((*result)->expr_type == EXPR_CONSTANT)
            return m;
            return m;
          else
          else
            {
            {
              gfc_error ("Invalid initializer %s in Data statement at %C", name);
              gfc_error ("Invalid initializer %s in Data statement at %C", name);
              return MATCH_ERROR;
              return MATCH_ERROR;
            }
            }
        }
        }
    }
    }
 
 
  *result = gfc_copy_expr (sym->value);
  *result = gfc_copy_expr (sym->value);
  return MATCH_YES;
  return MATCH_YES;
}
}
 
 
 
 
/* Match a list of values in a DATA statement.  The leading '/' has
/* Match a list of values in a DATA statement.  The leading '/' has
   already been seen at this point.  */
   already been seen at this point.  */
 
 
static match
static match
top_val_list (gfc_data *data)
top_val_list (gfc_data *data)
{
{
  gfc_data_value *new_val, *tail;
  gfc_data_value *new_val, *tail;
  gfc_expr *expr;
  gfc_expr *expr;
  match m;
  match m;
 
 
  tail = NULL;
  tail = NULL;
 
 
  for (;;)
  for (;;)
    {
    {
      m = match_data_constant (&expr);
      m = match_data_constant (&expr);
      if (m == MATCH_NO)
      if (m == MATCH_NO)
        goto syntax;
        goto syntax;
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      new_val = gfc_get_data_value ();
      new_val = gfc_get_data_value ();
      mpz_init (new_val->repeat);
      mpz_init (new_val->repeat);
 
 
      if (tail == NULL)
      if (tail == NULL)
        data->value = new_val;
        data->value = new_val;
      else
      else
        tail->next = new_val;
        tail->next = new_val;
 
 
      tail = new_val;
      tail = new_val;
 
 
      if (expr->ts.type != BT_INTEGER || gfc_match_char ('*') != MATCH_YES)
      if (expr->ts.type != BT_INTEGER || gfc_match_char ('*') != MATCH_YES)
        {
        {
          tail->expr = expr;
          tail->expr = expr;
          mpz_set_ui (tail->repeat, 1);
          mpz_set_ui (tail->repeat, 1);
        }
        }
      else
      else
        {
        {
          if (expr->ts.type == BT_INTEGER)
          if (expr->ts.type == BT_INTEGER)
            mpz_set (tail->repeat, expr->value.integer);
            mpz_set (tail->repeat, expr->value.integer);
          gfc_free_expr (expr);
          gfc_free_expr (expr);
 
 
          m = match_data_constant (&tail->expr);
          m = match_data_constant (&tail->expr);
          if (m == MATCH_NO)
          if (m == MATCH_NO)
            goto syntax;
            goto syntax;
          if (m == MATCH_ERROR)
          if (m == MATCH_ERROR)
            return MATCH_ERROR;
            return MATCH_ERROR;
        }
        }
 
 
      if (gfc_match_char ('/') == MATCH_YES)
      if (gfc_match_char ('/') == MATCH_YES)
        break;
        break;
      if (gfc_match_char (',') == MATCH_NO)
      if (gfc_match_char (',') == MATCH_NO)
        goto syntax;
        goto syntax;
    }
    }
 
 
  return MATCH_YES;
  return MATCH_YES;
 
 
syntax:
syntax:
  gfc_syntax_error (ST_DATA);
  gfc_syntax_error (ST_DATA);
  gfc_free_data_all (gfc_current_ns);
  gfc_free_data_all (gfc_current_ns);
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
/* Matches an old style initialization.  */
/* Matches an old style initialization.  */
 
 
static match
static match
match_old_style_init (const char *name)
match_old_style_init (const char *name)
{
{
  match m;
  match m;
  gfc_symtree *st;
  gfc_symtree *st;
  gfc_symbol *sym;
  gfc_symbol *sym;
  gfc_data *newdata;
  gfc_data *newdata;
 
 
  /* Set up data structure to hold initializers.  */
  /* Set up data structure to hold initializers.  */
  gfc_find_sym_tree (name, NULL, 0, &st);
  gfc_find_sym_tree (name, NULL, 0, &st);
  sym = st->n.sym;
  sym = st->n.sym;
 
 
  newdata = gfc_get_data ();
  newdata = gfc_get_data ();
  newdata->var = gfc_get_data_variable ();
  newdata->var = gfc_get_data_variable ();
  newdata->var->expr = gfc_get_variable_expr (st);
  newdata->var->expr = gfc_get_variable_expr (st);
  newdata->where = gfc_current_locus;
  newdata->where = gfc_current_locus;
 
 
  /* Match initial value list. This also eats the terminal '/'.  */
  /* Match initial value list. This also eats the terminal '/'.  */
  m = top_val_list (newdata);
  m = top_val_list (newdata);
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    {
    {
      gfc_free (newdata);
      gfc_free (newdata);
      return m;
      return m;
    }
    }
 
 
  if (gfc_pure (NULL))
  if (gfc_pure (NULL))
    {
    {
      gfc_error ("Initialization at %C is not allowed in a PURE procedure");
      gfc_error ("Initialization at %C is not allowed in a PURE procedure");
      gfc_free (newdata);
      gfc_free (newdata);
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  /* Mark the variable as having appeared in a data statement.  */
  /* Mark the variable as having appeared in a data statement.  */
  if (gfc_add_data (&sym->attr, sym->name, &sym->declared_at) == FAILURE)
  if (gfc_add_data (&sym->attr, sym->name, &sym->declared_at) == FAILURE)
    {
    {
      gfc_free (newdata);
      gfc_free (newdata);
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  /* Chain in namespace list of DATA initializers.  */
  /* Chain in namespace list of DATA initializers.  */
  newdata->next = gfc_current_ns->data;
  newdata->next = gfc_current_ns->data;
  gfc_current_ns->data = newdata;
  gfc_current_ns->data = newdata;
 
 
  return m;
  return m;
}
}
 
 
 
 
/* Match the stuff following a DATA statement. If ERROR_FLAG is set,
/* Match the stuff following a DATA statement. If ERROR_FLAG is set,
   we are matching a DATA statement and are therefore issuing an error
   we are matching a DATA statement and are therefore issuing an error
   if we encounter something unexpected, if not, we're trying to match
   if we encounter something unexpected, if not, we're trying to match
   an old-style initialization expression of the form INTEGER I /2/.  */
   an old-style initialization expression of the form INTEGER I /2/.  */
 
 
match
match
gfc_match_data (void)
gfc_match_data (void)
{
{
  gfc_data *new_data;
  gfc_data *new_data;
  match m;
  match m;
 
 
  set_in_match_data (true);
  set_in_match_data (true);
 
 
  for (;;)
  for (;;)
    {
    {
      new_data = gfc_get_data ();
      new_data = gfc_get_data ();
      new_data->where = gfc_current_locus;
      new_data->where = gfc_current_locus;
 
 
      m = top_var_list (new_data);
      m = top_var_list (new_data);
      if (m != MATCH_YES)
      if (m != MATCH_YES)
        goto cleanup;
        goto cleanup;
 
 
      m = top_val_list (new_data);
      m = top_val_list (new_data);
      if (m != MATCH_YES)
      if (m != MATCH_YES)
        goto cleanup;
        goto cleanup;
 
 
      new_data->next = gfc_current_ns->data;
      new_data->next = gfc_current_ns->data;
      gfc_current_ns->data = new_data;
      gfc_current_ns->data = new_data;
 
 
      if (gfc_match_eos () == MATCH_YES)
      if (gfc_match_eos () == MATCH_YES)
        break;
        break;
 
 
      gfc_match_char (',');     /* Optional comma */
      gfc_match_char (',');     /* Optional comma */
    }
    }
 
 
  set_in_match_data (false);
  set_in_match_data (false);
 
 
  if (gfc_pure (NULL))
  if (gfc_pure (NULL))
    {
    {
      gfc_error ("DATA statement at %C is not allowed in a PURE procedure");
      gfc_error ("DATA statement at %C is not allowed in a PURE procedure");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  return MATCH_YES;
  return MATCH_YES;
 
 
cleanup:
cleanup:
  set_in_match_data (false);
  set_in_match_data (false);
  gfc_free_data (new_data);
  gfc_free_data (new_data);
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
/************************ Declaration statements *********************/
/************************ Declaration statements *********************/
 
 
/* Match an intent specification.  Since this can only happen after an
/* Match an intent specification.  Since this can only happen after an
   INTENT word, a legal intent-spec must follow.  */
   INTENT word, a legal intent-spec must follow.  */
 
 
static sym_intent
static sym_intent
match_intent_spec (void)
match_intent_spec (void)
{
{
 
 
  if (gfc_match (" ( in out )") == MATCH_YES)
  if (gfc_match (" ( in out )") == MATCH_YES)
    return INTENT_INOUT;
    return INTENT_INOUT;
  if (gfc_match (" ( in )") == MATCH_YES)
  if (gfc_match (" ( in )") == MATCH_YES)
    return INTENT_IN;
    return INTENT_IN;
  if (gfc_match (" ( out )") == MATCH_YES)
  if (gfc_match (" ( out )") == MATCH_YES)
    return INTENT_OUT;
    return INTENT_OUT;
 
 
  gfc_error ("Bad INTENT specification at %C");
  gfc_error ("Bad INTENT specification at %C");
  return INTENT_UNKNOWN;
  return INTENT_UNKNOWN;
}
}
 
 
 
 
/* Matches a character length specification, which is either a
/* Matches a character length specification, which is either a
   specification expression or a '*'.  */
   specification expression or a '*'.  */
 
 
static match
static match
char_len_param_value (gfc_expr **expr)
char_len_param_value (gfc_expr **expr)
{
{
  match m;
  match m;
 
 
  if (gfc_match_char ('*') == MATCH_YES)
  if (gfc_match_char ('*') == MATCH_YES)
    {
    {
      *expr = NULL;
      *expr = NULL;
      return MATCH_YES;
      return MATCH_YES;
    }
    }
 
 
  m = gfc_match_expr (expr);
  m = gfc_match_expr (expr);
 
 
  if (m == MATCH_YES
  if (m == MATCH_YES
      && gfc_expr_check_typed (*expr, gfc_current_ns, false) == FAILURE)
      && gfc_expr_check_typed (*expr, gfc_current_ns, false) == FAILURE)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  if (m == MATCH_YES && (*expr)->expr_type == EXPR_FUNCTION)
  if (m == MATCH_YES && (*expr)->expr_type == EXPR_FUNCTION)
    {
    {
      if ((*expr)->value.function.actual
      if ((*expr)->value.function.actual
          && (*expr)->value.function.actual->expr->symtree)
          && (*expr)->value.function.actual->expr->symtree)
        {
        {
          gfc_expr *e;
          gfc_expr *e;
          e = (*expr)->value.function.actual->expr;
          e = (*expr)->value.function.actual->expr;
          if (e->symtree->n.sym->attr.flavor == FL_PROCEDURE
          if (e->symtree->n.sym->attr.flavor == FL_PROCEDURE
              && e->expr_type == EXPR_VARIABLE)
              && e->expr_type == EXPR_VARIABLE)
            {
            {
              if (e->symtree->n.sym->ts.type == BT_UNKNOWN)
              if (e->symtree->n.sym->ts.type == BT_UNKNOWN)
                goto syntax;
                goto syntax;
              if (e->symtree->n.sym->ts.type == BT_CHARACTER
              if (e->symtree->n.sym->ts.type == BT_CHARACTER
                  && e->symtree->n.sym->ts.u.cl
                  && e->symtree->n.sym->ts.u.cl
                  && e->symtree->n.sym->ts.u.cl->length->ts.type == BT_UNKNOWN)
                  && e->symtree->n.sym->ts.u.cl->length->ts.type == BT_UNKNOWN)
                goto syntax;
                goto syntax;
            }
            }
        }
        }
    }
    }
  return m;
  return m;
 
 
syntax:
syntax:
  gfc_error ("Conflict in attributes of function argument at %C");
  gfc_error ("Conflict in attributes of function argument at %C");
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
/* A character length is a '*' followed by a literal integer or a
/* A character length is a '*' followed by a literal integer or a
   char_len_param_value in parenthesis.  */
   char_len_param_value in parenthesis.  */
 
 
static match
static match
match_char_length (gfc_expr **expr)
match_char_length (gfc_expr **expr)
{
{
  int length;
  int length;
  match m;
  match m;
 
 
  m = gfc_match_char ('*');
  m = gfc_match_char ('*');
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    return m;
    return m;
 
 
  m = gfc_match_small_literal_int (&length, NULL);
  m = gfc_match_small_literal_int (&length, NULL);
  if (m == MATCH_ERROR)
  if (m == MATCH_ERROR)
    return m;
    return m;
 
 
  if (m == MATCH_YES)
  if (m == MATCH_YES)
    {
    {
      if (gfc_notify_std (GFC_STD_F95_OBS, "Obsolescent feature: "
      if (gfc_notify_std (GFC_STD_F95_OBS, "Obsolescent feature: "
                          "Old-style character length at %C") == FAILURE)
                          "Old-style character length at %C") == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
      *expr = gfc_int_expr (length);
      *expr = gfc_int_expr (length);
      return m;
      return m;
    }
    }
 
 
  if (gfc_match_char ('(') == MATCH_NO)
  if (gfc_match_char ('(') == MATCH_NO)
    goto syntax;
    goto syntax;
 
 
  m = char_len_param_value (expr);
  m = char_len_param_value (expr);
  if (m != MATCH_YES && gfc_matching_function)
  if (m != MATCH_YES && gfc_matching_function)
    {
    {
      gfc_undo_symbols ();
      gfc_undo_symbols ();
      m = MATCH_YES;
      m = MATCH_YES;
    }
    }
 
 
  if (m == MATCH_ERROR)
  if (m == MATCH_ERROR)
    return m;
    return m;
  if (m == MATCH_NO)
  if (m == MATCH_NO)
    goto syntax;
    goto syntax;
 
 
  if (gfc_match_char (')') == MATCH_NO)
  if (gfc_match_char (')') == MATCH_NO)
    {
    {
      gfc_free_expr (*expr);
      gfc_free_expr (*expr);
      *expr = NULL;
      *expr = NULL;
      goto syntax;
      goto syntax;
    }
    }
 
 
  return MATCH_YES;
  return MATCH_YES;
 
 
syntax:
syntax:
  gfc_error ("Syntax error in character length specification at %C");
  gfc_error ("Syntax error in character length specification at %C");
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
/* Special subroutine for finding a symbol.  Check if the name is found
/* 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
   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
   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
   to see if the name we've been given is the name of the interface
   (located in another namespace).  */
   (located in another namespace).  */
 
 
static int
static int
find_special (const char *name, gfc_symbol **result, bool allow_subroutine)
find_special (const char *name, gfc_symbol **result, bool allow_subroutine)
{
{
  gfc_state_data *s;
  gfc_state_data *s;
  gfc_symtree *st;
  gfc_symtree *st;
  int i;
  int i;
 
 
  i = gfc_get_sym_tree (name, NULL, &st, allow_subroutine);
  i = gfc_get_sym_tree (name, NULL, &st, allow_subroutine);
  if (i == 0)
  if (i == 0)
    {
    {
      *result = st ? st->n.sym : NULL;
      *result = st ? st->n.sym : NULL;
      goto end;
      goto end;
    }
    }
 
 
  if (gfc_current_state () != COMP_SUBROUTINE
  if (gfc_current_state () != COMP_SUBROUTINE
      && gfc_current_state () != COMP_FUNCTION)
      && gfc_current_state () != COMP_FUNCTION)
    goto end;
    goto end;
 
 
  s = gfc_state_stack->previous;
  s = gfc_state_stack->previous;
  if (s == NULL)
  if (s == NULL)
    goto end;
    goto end;
 
 
  if (s->state != COMP_INTERFACE)
  if (s->state != COMP_INTERFACE)
    goto end;
    goto end;
  if (s->sym == NULL)
  if (s->sym == NULL)
    goto end;             /* Nameless interface.  */
    goto end;             /* Nameless interface.  */
 
 
  if (strcmp (name, s->sym->name) == 0)
  if (strcmp (name, s->sym->name) == 0)
    {
    {
      *result = s->sym;
      *result = s->sym;
      return 0;
      return 0;
    }
    }
 
 
end:
end:
  return i;
  return i;
}
}
 
 
 
 
/* Special subroutine for getting a symbol node associated with a
/* Special subroutine for getting a symbol node associated with a
   procedure name, used in SUBROUTINE and FUNCTION statements.  The
   procedure name, used in SUBROUTINE and FUNCTION statements.  The
   symbol is created in the parent using with symtree node in the
   symbol is created in the parent using with symtree node in the
   child unit pointing to the symbol.  If the current namespace has no
   child unit pointing to the symbol.  If the current namespace has no
   parent, then the symbol is just created in the current unit.  */
   parent, then the symbol is just created in the current unit.  */
 
 
static int
static int
get_proc_name (const char *name, gfc_symbol **result, bool module_fcn_entry)
get_proc_name (const char *name, gfc_symbol **result, bool module_fcn_entry)
{
{
  gfc_symtree *st;
  gfc_symtree *st;
  gfc_symbol *sym;
  gfc_symbol *sym;
  int rc = 0;
  int rc = 0;
 
 
  /* Module functions have to be left in their own namespace because
  /* Module functions have to be left in their own namespace because
     they have potentially (almost certainly!) already been referenced.
     they have potentially (almost certainly!) already been referenced.
     In this sense, they are rather like external functions.  This is
     In this sense, they are rather like external functions.  This is
     fixed up in resolve.c(resolve_entries), where the symbol name-
     fixed up in resolve.c(resolve_entries), where the symbol name-
     space is set to point to the master function, so that the fake
     space is set to point to the master function, so that the fake
     result mechanism can work.  */
     result mechanism can work.  */
  if (module_fcn_entry)
  if (module_fcn_entry)
    {
    {
      /* Present if entry is declared to be a module procedure.  */
      /* Present if entry is declared to be a module procedure.  */
      rc = gfc_find_symbol (name, gfc_current_ns->parent, 0, result);
      rc = gfc_find_symbol (name, gfc_current_ns->parent, 0, result);
 
 
      if (*result == NULL)
      if (*result == NULL)
        rc = gfc_get_symbol (name, NULL, result);
        rc = gfc_get_symbol (name, NULL, result);
      else if (!gfc_get_symbol (name, NULL, &sym) && sym
      else if (!gfc_get_symbol (name, NULL, &sym) && sym
                 && (*result)->ts.type == BT_UNKNOWN
                 && (*result)->ts.type == BT_UNKNOWN
                 && sym->attr.flavor == FL_UNKNOWN)
                 && sym->attr.flavor == FL_UNKNOWN)
        /* Pick up the typespec for the entry, if declared in the function
        /* Pick up the typespec for the entry, if declared in the function
           body.  Note that this symbol is FL_UNKNOWN because it will
           body.  Note that this symbol is FL_UNKNOWN because it will
           only have appeared in a type declaration.  The local symtree
           only have appeared in a type declaration.  The local symtree
           is set to point to the module symbol and a unique symtree
           is set to point to the module symbol and a unique symtree
           to the local version.  This latter ensures a correct clearing
           to the local version.  This latter ensures a correct clearing
           of the symbols.  */
           of the symbols.  */
        {
        {
          /* If the ENTRY proceeds its specification, we need to ensure
          /* If the ENTRY proceeds its specification, we need to ensure
             that this does not raise a "has no IMPLICIT type" error.  */
             that this does not raise a "has no IMPLICIT type" error.  */
          if (sym->ts.type == BT_UNKNOWN)
          if (sym->ts.type == BT_UNKNOWN)
            sym->attr.untyped = 1;
            sym->attr.untyped = 1;
 
 
          (*result)->ts = sym->ts;
          (*result)->ts = sym->ts;
 
 
          /* Put the symbol in the procedure namespace so that, should
          /* Put the symbol in the procedure namespace so that, should
             the ENTRY precede its specification, the specification
             the ENTRY precede its specification, the specification
             can be applied.  */
             can be applied.  */
          (*result)->ns = gfc_current_ns;
          (*result)->ns = gfc_current_ns;
 
 
          gfc_find_sym_tree (name, gfc_current_ns, 0, &st);
          gfc_find_sym_tree (name, gfc_current_ns, 0, &st);
          st->n.sym = *result;
          st->n.sym = *result;
          st = gfc_get_unique_symtree (gfc_current_ns);
          st = gfc_get_unique_symtree (gfc_current_ns);
          st->n.sym = sym;
          st->n.sym = sym;
        }
        }
    }
    }
  else
  else
    rc = gfc_get_symbol (name, gfc_current_ns->parent, result);
    rc = gfc_get_symbol (name, gfc_current_ns->parent, result);
 
 
  if (rc)
  if (rc)
    return rc;
    return rc;
 
 
  sym = *result;
  sym = *result;
  gfc_current_ns->refs++;
  gfc_current_ns->refs++;
 
 
  if (sym && !sym->gfc_new && gfc_current_state () != COMP_INTERFACE)
  if (sym && !sym->gfc_new && gfc_current_state () != COMP_INTERFACE)
    {
    {
      /* Trap another encompassed procedure with the same name.  All
      /* Trap another encompassed procedure with the same name.  All
         these conditions are necessary to avoid picking up an entry
         these conditions are necessary to avoid picking up an entry
         whose name clashes with that of the encompassing procedure;
         whose name clashes with that of the encompassing procedure;
         this is handled using gsymbols to register unique,globally
         this is handled using gsymbols to register unique,globally
         accessible names.  */
         accessible names.  */
      if (sym->attr.flavor != 0
      if (sym->attr.flavor != 0
          && sym->attr.proc != 0
          && sym->attr.proc != 0
          && (sym->attr.subroutine || sym->attr.function)
          && (sym->attr.subroutine || sym->attr.function)
          && sym->attr.if_source != IFSRC_UNKNOWN)
          && sym->attr.if_source != IFSRC_UNKNOWN)
        gfc_error_now ("Procedure '%s' at %C is already defined at %L",
        gfc_error_now ("Procedure '%s' at %C is already defined at %L",
                       name, &sym->declared_at);
                       name, &sym->declared_at);
 
 
      /* Trap a procedure with a name the same as interface in the
      /* Trap a procedure with a name the same as interface in the
         encompassing scope.  */
         encompassing scope.  */
      if (sym->attr.generic != 0
      if (sym->attr.generic != 0
          && (sym->attr.subroutine || sym->attr.function)
          && (sym->attr.subroutine || sym->attr.function)
          && !sym->attr.mod_proc)
          && !sym->attr.mod_proc)
        gfc_error_now ("Name '%s' at %C is already defined"
        gfc_error_now ("Name '%s' at %C is already defined"
                       " as a generic interface at %L",
                       " as a generic interface at %L",
                       name, &sym->declared_at);
                       name, &sym->declared_at);
 
 
      /* Trap declarations of attributes in encompassing scope.  The
      /* Trap declarations of attributes in encompassing scope.  The
         signature for this is that ts.kind is set.  Legitimate
         signature for this is that ts.kind is set.  Legitimate
         references only set ts.type.  */
         references only set ts.type.  */
      if (sym->ts.kind != 0
      if (sym->ts.kind != 0
          && !sym->attr.implicit_type
          && !sym->attr.implicit_type
          && sym->attr.proc == 0
          && sym->attr.proc == 0
          && gfc_current_ns->parent != NULL
          && gfc_current_ns->parent != NULL
          && sym->attr.access == 0
          && sym->attr.access == 0
          && !module_fcn_entry)
          && !module_fcn_entry)
        gfc_error_now ("Procedure '%s' at %C has an explicit interface "
        gfc_error_now ("Procedure '%s' at %C has an explicit interface "
                       "and must not have attributes declared at %L",
                       "and must not have attributes declared at %L",
                       name, &sym->declared_at);
                       name, &sym->declared_at);
    }
    }
 
 
  if (gfc_current_ns->parent == NULL || *result == NULL)
  if (gfc_current_ns->parent == NULL || *result == NULL)
    return rc;
    return rc;
 
 
  /* Module function entries will already have a symtree in
  /* Module function entries will already have a symtree in
     the current namespace but will need one at module level.  */
     the current namespace but will need one at module level.  */
  if (module_fcn_entry)
  if (module_fcn_entry)
    {
    {
      /* Present if entry is declared to be a module procedure.  */
      /* Present if entry is declared to be a module procedure.  */
      rc = gfc_find_sym_tree (name, gfc_current_ns->parent, 0, &st);
      rc = gfc_find_sym_tree (name, gfc_current_ns->parent, 0, &st);
      if (st == NULL)
      if (st == NULL)
        st = gfc_new_symtree (&gfc_current_ns->parent->sym_root, name);
        st = gfc_new_symtree (&gfc_current_ns->parent->sym_root, name);
    }
    }
  else
  else
    st = gfc_new_symtree (&gfc_current_ns->sym_root, name);
    st = gfc_new_symtree (&gfc_current_ns->sym_root, name);
 
 
  st->n.sym = sym;
  st->n.sym = sym;
  sym->refs++;
  sym->refs++;
 
 
  /* See if the procedure should be a module procedure.  */
  /* See if the procedure should be a module procedure.  */
 
 
  if (((sym->ns->proc_name != NULL
  if (((sym->ns->proc_name != NULL
                && sym->ns->proc_name->attr.flavor == FL_MODULE
                && sym->ns->proc_name->attr.flavor == FL_MODULE
                && sym->attr.proc != PROC_MODULE)
                && sym->attr.proc != PROC_MODULE)
            || (module_fcn_entry && sym->attr.proc != PROC_MODULE))
            || (module_fcn_entry && sym->attr.proc != PROC_MODULE))
        && gfc_add_procedure (&sym->attr, PROC_MODULE,
        && gfc_add_procedure (&sym->attr, PROC_MODULE,
                              sym->name, NULL) == FAILURE)
                              sym->name, NULL) == FAILURE)
    rc = 2;
    rc = 2;
 
 
  return rc;
  return rc;
}
}
 
 
 
 
/* Verify that the given symbol representing a parameter is C
/* Verify that the given symbol representing a parameter is C
   interoperable, by checking to see if it was marked as such after
   interoperable, by checking to see if it was marked as such after
   its declaration.  If the given symbol is not interoperable, a
   its declaration.  If the given symbol is not interoperable, a
   warning is reported, thus removing the need to return the status to
   warning is reported, thus removing the need to return the status to
   the calling function.  The standard does not require the user use
   the calling function.  The standard does not require the user use
   one of the iso_c_binding named constants to declare an
   one of the iso_c_binding named constants to declare an
   interoperable parameter, but we can't be sure if the param is C
   interoperable parameter, but we can't be sure if the param is C
   interop or not if the user doesn't.  For example, integer(4) may be
   interop or not if the user doesn't.  For example, integer(4) may be
   legal Fortran, but doesn't have meaning in C.  It may interop with
   legal Fortran, but doesn't have meaning in C.  It may interop with
   a number of the C types, which causes a problem because the
   a number of the C types, which causes a problem because the
   compiler can't know which one.  This code is almost certainly not
   compiler can't know which one.  This code is almost certainly not
   portable, and the user will get what they deserve if the C type
   portable, and the user will get what they deserve if the C type
   across platforms isn't always interoperable with integer(4).  If
   across platforms isn't always interoperable with integer(4).  If
   the user had used something like integer(c_int) or integer(c_long),
   the user had used something like integer(c_int) or integer(c_long),
   the compiler could have automatically handled the varying sizes
   the compiler could have automatically handled the varying sizes
   across platforms.  */
   across platforms.  */
 
 
gfc_try
gfc_try
verify_c_interop_param (gfc_symbol *sym)
verify_c_interop_param (gfc_symbol *sym)
{
{
  int is_c_interop = 0;
  int is_c_interop = 0;
  gfc_try retval = SUCCESS;
  gfc_try retval = SUCCESS;
 
 
  /* We check implicitly typed variables in symbol.c:gfc_set_default_type().
  /* We check implicitly typed variables in symbol.c:gfc_set_default_type().
     Don't repeat the checks here.  */
     Don't repeat the checks here.  */
  if (sym->attr.implicit_type)
  if (sym->attr.implicit_type)
    return SUCCESS;
    return SUCCESS;
 
 
  /* For subroutines or functions that are passed to a BIND(C) procedure,
  /* For subroutines or functions that are passed to a BIND(C) procedure,
     they're interoperable if they're BIND(C) and their params are all
     they're interoperable if they're BIND(C) and their params are all
     interoperable.  */
     interoperable.  */
  if (sym->attr.flavor == FL_PROCEDURE)
  if (sym->attr.flavor == FL_PROCEDURE)
    {
    {
      if (sym->attr.is_bind_c == 0)
      if (sym->attr.is_bind_c == 0)
        {
        {
          gfc_error_now ("Procedure '%s' at %L must have the BIND(C) "
          gfc_error_now ("Procedure '%s' at %L must have the BIND(C) "
                         "attribute to be C interoperable", sym->name,
                         "attribute to be C interoperable", sym->name,
                         &(sym->declared_at));
                         &(sym->declared_at));
 
 
          return FAILURE;
          return FAILURE;
        }
        }
      else
      else
        {
        {
          if (sym->attr.is_c_interop == 1)
          if (sym->attr.is_c_interop == 1)
            /* We've already checked this procedure; don't check it again.  */
            /* We've already checked this procedure; don't check it again.  */
            return SUCCESS;
            return SUCCESS;
          else
          else
            return verify_bind_c_sym (sym, &(sym->ts), sym->attr.in_common,
            return verify_bind_c_sym (sym, &(sym->ts), sym->attr.in_common,
                                      sym->common_block);
                                      sym->common_block);
        }
        }
    }
    }
 
 
  /* See if we've stored a reference to a procedure that owns sym.  */
  /* See if we've stored a reference to a procedure that owns sym.  */
  if (sym->ns != NULL && sym->ns->proc_name != NULL)
  if (sym->ns != NULL && sym->ns->proc_name != NULL)
    {
    {
      if (sym->ns->proc_name->attr.is_bind_c == 1)
      if (sym->ns->proc_name->attr.is_bind_c == 1)
        {
        {
          is_c_interop =
          is_c_interop =
            (verify_c_interop (&(sym->ts))
            (verify_c_interop (&(sym->ts))
             == SUCCESS ? 1 : 0);
             == SUCCESS ? 1 : 0);
 
 
          if (is_c_interop != 1)
          if (is_c_interop != 1)
            {
            {
              /* Make personalized messages to give better feedback.  */
              /* Make personalized messages to give better feedback.  */
              if (sym->ts.type == BT_DERIVED)
              if (sym->ts.type == BT_DERIVED)
                gfc_error ("Type '%s' at %L is a parameter to the BIND(C) "
                gfc_error ("Type '%s' at %L is a parameter to the BIND(C) "
                           " procedure '%s' but is not C interoperable "
                           " procedure '%s' but is not C interoperable "
                           "because derived type '%s' is not C interoperable",
                           "because derived type '%s' is not C interoperable",
                           sym->name, &(sym->declared_at),
                           sym->name, &(sym->declared_at),
                           sym->ns->proc_name->name,
                           sym->ns->proc_name->name,
                           sym->ts.u.derived->name);
                           sym->ts.u.derived->name);
              else
              else
                gfc_warning ("Variable '%s' at %L is a parameter to the "
                gfc_warning ("Variable '%s' at %L is a parameter to the "
                             "BIND(C) procedure '%s' but may not be C "
                             "BIND(C) procedure '%s' but may not be C "
                             "interoperable",
                             "interoperable",
                             sym->name, &(sym->declared_at),
                             sym->name, &(sym->declared_at),
                             sym->ns->proc_name->name);
                             sym->ns->proc_name->name);
            }
            }
 
 
          /* Character strings are only C interoperable if they have a
          /* Character strings are only C interoperable if they have a
             length of 1.  */
             length of 1.  */
          if (sym->ts.type == BT_CHARACTER)
          if (sym->ts.type == BT_CHARACTER)
            {
            {
              gfc_charlen *cl = sym->ts.u.cl;
              gfc_charlen *cl = sym->ts.u.cl;
              if (!cl || !cl->length || cl->length->expr_type != EXPR_CONSTANT
              if (!cl || !cl->length || cl->length->expr_type != EXPR_CONSTANT
                  || mpz_cmp_si (cl->length->value.integer, 1) != 0)
                  || mpz_cmp_si (cl->length->value.integer, 1) != 0)
                {
                {
                  gfc_error ("Character argument '%s' at %L "
                  gfc_error ("Character argument '%s' at %L "
                             "must be length 1 because "
                             "must be length 1 because "
                             "procedure '%s' is BIND(C)",
                             "procedure '%s' is BIND(C)",
                             sym->name, &sym->declared_at,
                             sym->name, &sym->declared_at,
                             sym->ns->proc_name->name);
                             sym->ns->proc_name->name);
                  retval = FAILURE;
                  retval = FAILURE;
                }
                }
            }
            }
 
 
          /* We have to make sure that any param to a bind(c) routine does
          /* We have to make sure that any param to a bind(c) routine does
             not have the allocatable, pointer, or optional attributes,
             not have the allocatable, pointer, or optional attributes,
             according to J3/04-007, section 5.1.  */
             according to J3/04-007, section 5.1.  */
          if (sym->attr.allocatable == 1)
          if (sym->attr.allocatable == 1)
            {
            {
              gfc_error ("Variable '%s' at %L cannot have the "
              gfc_error ("Variable '%s' at %L cannot have the "
                         "ALLOCATABLE attribute because procedure '%s'"
                         "ALLOCATABLE attribute because procedure '%s'"
                         " is BIND(C)", sym->name, &(sym->declared_at),
                         " is BIND(C)", sym->name, &(sym->declared_at),
                         sym->ns->proc_name->name);
                         sym->ns->proc_name->name);
              retval = FAILURE;
              retval = FAILURE;
            }
            }
 
 
          if (sym->attr.pointer == 1)
          if (sym->attr.pointer == 1)
            {
            {
              gfc_error ("Variable '%s' at %L cannot have the "
              gfc_error ("Variable '%s' at %L cannot have the "
                         "POINTER attribute because procedure '%s'"
                         "POINTER attribute because procedure '%s'"
                         " is BIND(C)", sym->name, &(sym->declared_at),
                         " is BIND(C)", sym->name, &(sym->declared_at),
                         sym->ns->proc_name->name);
                         sym->ns->proc_name->name);
              retval = FAILURE;
              retval = FAILURE;
            }
            }
 
 
          if (sym->attr.optional == 1)
          if (sym->attr.optional == 1)
            {
            {
              gfc_error ("Variable '%s' at %L cannot have the "
              gfc_error ("Variable '%s' at %L cannot have the "
                         "OPTIONAL attribute because procedure '%s'"
                         "OPTIONAL attribute because procedure '%s'"
                         " is BIND(C)", sym->name, &(sym->declared_at),
                         " is BIND(C)", sym->name, &(sym->declared_at),
                         sym->ns->proc_name->name);
                         sym->ns->proc_name->name);
              retval = FAILURE;
              retval = FAILURE;
            }
            }
 
 
          /* Make sure that if it has the dimension attribute, that it is
          /* Make sure that if it has the dimension attribute, that it is
             either assumed size or explicit shape.  */
             either assumed size or explicit shape.  */
          if (sym->as != NULL)
          if (sym->as != NULL)
            {
            {
              if (sym->as->type == AS_ASSUMED_SHAPE)
              if (sym->as->type == AS_ASSUMED_SHAPE)
                {
                {
                  gfc_error ("Assumed-shape array '%s' at %L cannot be an "
                  gfc_error ("Assumed-shape array '%s' at %L cannot be an "
                             "argument to the procedure '%s' at %L because "
                             "argument to the procedure '%s' at %L because "
                             "the procedure is BIND(C)", sym->name,
                             "the procedure is BIND(C)", sym->name,
                             &(sym->declared_at), sym->ns->proc_name->name,
                             &(sym->declared_at), sym->ns->proc_name->name,
                             &(sym->ns->proc_name->declared_at));
                             &(sym->ns->proc_name->declared_at));
                  retval = FAILURE;
                  retval = FAILURE;
                }
                }
 
 
              if (sym->as->type == AS_DEFERRED)
              if (sym->as->type == AS_DEFERRED)
                {
                {
                  gfc_error ("Deferred-shape array '%s' at %L cannot be an "
                  gfc_error ("Deferred-shape array '%s' at %L cannot be an "
                             "argument to the procedure '%s' at %L because "
                             "argument to the procedure '%s' at %L because "
                             "the procedure is BIND(C)", sym->name,
                             "the procedure is BIND(C)", sym->name,
                             &(sym->declared_at), sym->ns->proc_name->name,
                             &(sym->declared_at), sym->ns->proc_name->name,
                             &(sym->ns->proc_name->declared_at));
                             &(sym->ns->proc_name->declared_at));
                  retval = FAILURE;
                  retval = FAILURE;
                }
                }
          }
          }
        }
        }
    }
    }
 
 
  return retval;
  return retval;
}
}
 
 
 
 
 
 
/* Function called by variable_decl() that adds a name to the symbol table.  */
/* Function called by variable_decl() that adds a name to the symbol table.  */
 
 
static gfc_try
static gfc_try
build_sym (const char *name, gfc_charlen *cl,
build_sym (const char *name, gfc_charlen *cl,
           gfc_array_spec **as, locus *var_locus)
           gfc_array_spec **as, locus *var_locus)
{
{
  symbol_attribute attr;
  symbol_attribute attr;
  gfc_symbol *sym;
  gfc_symbol *sym;
 
 
  if (gfc_get_symbol (name, NULL, &sym))
  if (gfc_get_symbol (name, NULL, &sym))
    return FAILURE;
    return FAILURE;
 
 
  /* Start updating the symbol table.  Add basic type attribute if present.  */
  /* Start updating the symbol table.  Add basic type attribute if present.  */
  if (current_ts.type != BT_UNKNOWN
  if (current_ts.type != BT_UNKNOWN
      && (sym->attr.implicit_type == 0
      && (sym->attr.implicit_type == 0
          || !gfc_compare_types (&sym->ts, &current_ts))
          || !gfc_compare_types (&sym->ts, &current_ts))
      && gfc_add_type (sym, &current_ts, var_locus) == FAILURE)
      && gfc_add_type (sym, &current_ts, var_locus) == FAILURE)
    return FAILURE;
    return FAILURE;
 
 
  if (sym->ts.type == BT_CHARACTER)
  if (sym->ts.type == BT_CHARACTER)
    sym->ts.u.cl = cl;
    sym->ts.u.cl = cl;
 
 
  /* Add dimension attribute if present.  */
  /* Add dimension attribute if present.  */
  if (gfc_set_array_spec (sym, *as, var_locus) == FAILURE)
  if (gfc_set_array_spec (sym, *as, var_locus) == FAILURE)
    return FAILURE;
    return FAILURE;
  *as = NULL;
  *as = NULL;
 
 
  /* Add attribute to symbol.  The copy is so that we can reset the
  /* Add attribute to symbol.  The copy is so that we can reset the
     dimension attribute.  */
     dimension attribute.  */
  attr = current_attr;
  attr = current_attr;
  attr.dimension = 0;
  attr.dimension = 0;
 
 
  if (gfc_copy_attr (&sym->attr, &attr, var_locus) == FAILURE)
  if (gfc_copy_attr (&sym->attr, &attr, var_locus) == FAILURE)
    return FAILURE;
    return FAILURE;
 
 
  /* Finish any work that may need to be done for the binding label,
  /* Finish any work that may need to be done for the binding label,
     if it's a bind(c).  The bind(c) attr is found before the symbol
     if it's a bind(c).  The bind(c) attr is found before the symbol
     is made, and before the symbol name (for data decls), so the
     is made, and before the symbol name (for data decls), so the
     current_ts is holding the binding label, or nothing if the
     current_ts is holding the binding label, or nothing if the
     name= attr wasn't given.  Therefore, test here if we're dealing
     name= attr wasn't given.  Therefore, test here if we're dealing
     with a bind(c) and make sure the binding label is set correctly.  */
     with a bind(c) and make sure the binding label is set correctly.  */
  if (sym->attr.is_bind_c == 1)
  if (sym->attr.is_bind_c == 1)
    {
    {
      if (sym->binding_label[0] == '\0')
      if (sym->binding_label[0] == '\0')
        {
        {
          /* Set the binding label and verify that if a NAME= was specified
          /* Set the binding label and verify that if a NAME= was specified
             then only one identifier was in the entity-decl-list.  */
             then only one identifier was in the entity-decl-list.  */
          if (set_binding_label (sym->binding_label, sym->name,
          if (set_binding_label (sym->binding_label, sym->name,
                                 num_idents_on_line) == FAILURE)
                                 num_idents_on_line) == FAILURE)
            return FAILURE;
            return FAILURE;
        }
        }
    }
    }
 
 
  /* See if we know we're in a common block, and if it's a bind(c)
  /* See if we know we're in a common block, and if it's a bind(c)
     common then we need to make sure we're an interoperable type.  */
     common then we need to make sure we're an interoperable type.  */
  if (sym->attr.in_common == 1)
  if (sym->attr.in_common == 1)
    {
    {
      /* Test the common block object.  */
      /* Test the common block object.  */
      if (sym->common_block != NULL && sym->common_block->is_bind_c == 1
      if (sym->common_block != NULL && sym->common_block->is_bind_c == 1
          && sym->ts.is_c_interop != 1)
          && sym->ts.is_c_interop != 1)
        {
        {
          gfc_error_now ("Variable '%s' in common block '%s' at %C "
          gfc_error_now ("Variable '%s' in common block '%s' at %C "
                         "must be declared with a C interoperable "
                         "must be declared with a C interoperable "
                         "kind since common block '%s' is BIND(C)",
                         "kind since common block '%s' is BIND(C)",
                         sym->name, sym->common_block->name,
                         sym->name, sym->common_block->name,
                         sym->common_block->name);
                         sym->common_block->name);
          gfc_clear_error ();
          gfc_clear_error ();
        }
        }
    }
    }
 
 
  sym->attr.implied_index = 0;
  sym->attr.implied_index = 0;
 
 
  if (sym->ts.type == BT_CLASS)
  if (sym->ts.type == BT_CLASS)
    {
    {
      sym->attr.class_ok = (sym->attr.dummy
      sym->attr.class_ok = (sym->attr.dummy
                              || sym->attr.pointer
                              || sym->attr.pointer
                              || sym->attr.allocatable) ? 1 : 0;
                              || sym->attr.allocatable) ? 1 : 0;
      gfc_build_class_symbol (&sym->ts, &sym->attr, &sym->as);
      gfc_build_class_symbol (&sym->ts, &sym->attr, &sym->as);
    }
    }
 
 
  return SUCCESS;
  return SUCCESS;
}
}
 
 
 
 
/* Set character constant to the given length. The constant will be padded or
/* Set character constant to the given length. The constant will be padded or
   truncated.  If we're inside an array constructor without a typespec, we
   truncated.  If we're inside an array constructor without a typespec, we
   additionally check that all elements have the same length; check_len -1
   additionally check that all elements have the same length; check_len -1
   means no checking.  */
   means no checking.  */
 
 
void
void
gfc_set_constant_character_len (int len, gfc_expr *expr, int check_len)
gfc_set_constant_character_len (int len, gfc_expr *expr, int check_len)
{
{
  gfc_char_t *s;
  gfc_char_t *s;
  int slen;
  int slen;
 
 
  gcc_assert (expr->expr_type == EXPR_CONSTANT);
  gcc_assert (expr->expr_type == EXPR_CONSTANT);
  gcc_assert (expr->ts.type == BT_CHARACTER);
  gcc_assert (expr->ts.type == BT_CHARACTER);
 
 
  slen = expr->value.character.length;
  slen = expr->value.character.length;
  if (len != slen)
  if (len != slen)
    {
    {
      s = gfc_get_wide_string (len + 1);
      s = gfc_get_wide_string (len + 1);
      memcpy (s, expr->value.character.string,
      memcpy (s, expr->value.character.string,
              MIN (len, slen) * sizeof (gfc_char_t));
              MIN (len, slen) * sizeof (gfc_char_t));
      if (len > slen)
      if (len > slen)
        gfc_wide_memset (&s[slen], ' ', len - slen);
        gfc_wide_memset (&s[slen], ' ', len - slen);
 
 
      if (gfc_option.warn_character_truncation && slen > len)
      if (gfc_option.warn_character_truncation && slen > len)
        gfc_warning_now ("CHARACTER expression at %L is being truncated "
        gfc_warning_now ("CHARACTER expression at %L is being truncated "
                         "(%d/%d)", &expr->where, slen, len);
                         "(%d/%d)", &expr->where, slen, len);
 
 
      /* Apply the standard by 'hand' otherwise it gets cleared for
      /* Apply the standard by 'hand' otherwise it gets cleared for
         initializers.  */
         initializers.  */
      if (check_len != -1 && slen != check_len
      if (check_len != -1 && slen != check_len
          && !(gfc_option.allow_std & GFC_STD_GNU))
          && !(gfc_option.allow_std & GFC_STD_GNU))
        gfc_error_now ("The CHARACTER elements of the array constructor "
        gfc_error_now ("The CHARACTER elements of the array constructor "
                       "at %L must have the same length (%d/%d)",
                       "at %L must have the same length (%d/%d)",
                        &expr->where, slen, check_len);
                        &expr->where, slen, check_len);
 
 
      s[len] = '\0';
      s[len] = '\0';
      gfc_free (expr->value.character.string);
      gfc_free (expr->value.character.string);
      expr->value.character.string = s;
      expr->value.character.string = s;
      expr->value.character.length = len;
      expr->value.character.length = len;
    }
    }
}
}
 
 
 
 
/* Function to create and update the enumerator history
/* Function to create and update the enumerator history
   using the information passed as arguments.
   using the information passed as arguments.
   Pointer "max_enum" is also updated, to point to
   Pointer "max_enum" is also updated, to point to
   enum history node containing largest initializer.
   enum history node containing largest initializer.
 
 
   SYM points to the symbol node of enumerator.
   SYM points to the symbol node of enumerator.
   INIT points to its enumerator value.  */
   INIT points to its enumerator value.  */
 
 
static void
static void
create_enum_history (gfc_symbol *sym, gfc_expr *init)
create_enum_history (gfc_symbol *sym, gfc_expr *init)
{
{
  enumerator_history *new_enum_history;
  enumerator_history *new_enum_history;
  gcc_assert (sym != NULL && init != NULL);
  gcc_assert (sym != NULL && init != NULL);
 
 
  new_enum_history = XCNEW (enumerator_history);
  new_enum_history = XCNEW (enumerator_history);
 
 
  new_enum_history->sym = sym;
  new_enum_history->sym = sym;
  new_enum_history->initializer = init;
  new_enum_history->initializer = init;
  new_enum_history->next = NULL;
  new_enum_history->next = NULL;
 
 
  if (enum_history == NULL)
  if (enum_history == NULL)
    {
    {
      enum_history = new_enum_history;
      enum_history = new_enum_history;
      max_enum = enum_history;
      max_enum = enum_history;
    }
    }
  else
  else
    {
    {
      new_enum_history->next = enum_history;
      new_enum_history->next = enum_history;
      enum_history = new_enum_history;
      enum_history = new_enum_history;
 
 
      if (mpz_cmp (max_enum->initializer->value.integer,
      if (mpz_cmp (max_enum->initializer->value.integer,
                   new_enum_history->initializer->value.integer) < 0)
                   new_enum_history->initializer->value.integer) < 0)
        max_enum = new_enum_history;
        max_enum = new_enum_history;
    }
    }
}
}
 
 
 
 
/* Function to free enum kind history.  */
/* Function to free enum kind history.  */
 
 
void
void
gfc_free_enum_history (void)
gfc_free_enum_history (void)
{
{
  enumerator_history *current = enum_history;
  enumerator_history *current = enum_history;
  enumerator_history *next;
  enumerator_history *next;
 
 
  while (current != NULL)
  while (current != NULL)
    {
    {
      next = current->next;
      next = current->next;
      gfc_free (current);
      gfc_free (current);
      current = next;
      current = next;
    }
    }
  max_enum = NULL;
  max_enum = NULL;
  enum_history = NULL;
  enum_history = NULL;
}
}
 
 
 
 
/* Function called by variable_decl() that adds an initialization
/* Function called by variable_decl() that adds an initialization
   expression to a symbol.  */
   expression to a symbol.  */
 
 
static gfc_try
static gfc_try
add_init_expr_to_sym (const char *name, gfc_expr **initp, locus *var_locus)
add_init_expr_to_sym (const char *name, gfc_expr **initp, locus *var_locus)
{
{
  symbol_attribute attr;
  symbol_attribute attr;
  gfc_symbol *sym;
  gfc_symbol *sym;
  gfc_expr *init;
  gfc_expr *init;
 
 
  init = *initp;
  init = *initp;
  if (find_special (name, &sym, false))
  if (find_special (name, &sym, false))
    return FAILURE;
    return FAILURE;
 
 
  attr = sym->attr;
  attr = sym->attr;
 
 
  /* If this symbol is confirming an implicit parameter type,
  /* If this symbol is confirming an implicit parameter type,
     then an initialization expression is not allowed.  */
     then an initialization expression is not allowed.  */
  if (attr.flavor == FL_PARAMETER
  if (attr.flavor == FL_PARAMETER
      && sym->value != NULL
      && sym->value != NULL
      && *initp != NULL)
      && *initp != NULL)
    {
    {
      gfc_error ("Initializer not allowed for PARAMETER '%s' at %C",
      gfc_error ("Initializer not allowed for PARAMETER '%s' at %C",
                 sym->name);
                 sym->name);
      return FAILURE;
      return FAILURE;
    }
    }
 
 
  if (init == NULL)
  if (init == NULL)
    {
    {
      /* An initializer is required for PARAMETER declarations.  */
      /* An initializer is required for PARAMETER declarations.  */
      if (attr.flavor == FL_PARAMETER)
      if (attr.flavor == FL_PARAMETER)
        {
        {
          gfc_error ("PARAMETER at %L is missing an initializer", var_locus);
          gfc_error ("PARAMETER at %L is missing an initializer", var_locus);
          return FAILURE;
          return FAILURE;
        }
        }
    }
    }
  else
  else
    {
    {
      /* If a variable appears in a DATA block, it cannot have an
      /* If a variable appears in a DATA block, it cannot have an
         initializer.  */
         initializer.  */
      if (sym->attr.data)
      if (sym->attr.data)
        {
        {
          gfc_error ("Variable '%s' at %C with an initializer already "
          gfc_error ("Variable '%s' at %C with an initializer already "
                     "appears in a DATA statement", sym->name);
                     "appears in a DATA statement", sym->name);
          return FAILURE;
          return FAILURE;
        }
        }
 
 
      /* Check if the assignment can happen. This has to be put off
      /* Check if the assignment can happen. This has to be put off
         until later for a derived type variable.  */
         until later for a derived type variable.  */
      if (sym->ts.type != BT_DERIVED && init->ts.type != BT_DERIVED
      if (sym->ts.type != BT_DERIVED && init->ts.type != BT_DERIVED
          && sym->ts.type != BT_CLASS && init->ts.type != BT_CLASS
          && sym->ts.type != BT_CLASS && init->ts.type != BT_CLASS
          && gfc_check_assign_symbol (sym, init) == FAILURE)
          && gfc_check_assign_symbol (sym, init) == FAILURE)
        return FAILURE;
        return FAILURE;
 
 
      if (sym->ts.type == BT_CHARACTER && sym->ts.u.cl
      if (sym->ts.type == BT_CHARACTER && sym->ts.u.cl
            && init->ts.type == BT_CHARACTER)
            && init->ts.type == BT_CHARACTER)
        {
        {
          /* Update symbol character length according initializer.  */
          /* Update symbol character length according initializer.  */
          if (gfc_check_assign_symbol (sym, init) == FAILURE)
          if (gfc_check_assign_symbol (sym, init) == FAILURE)
            return FAILURE;
            return FAILURE;
 
 
          if (sym->ts.u.cl->length == NULL)
          if (sym->ts.u.cl->length == NULL)
            {
            {
              int clen;
              int clen;
              /* If there are multiple CHARACTER variables declared on the
              /* If there are multiple CHARACTER variables declared on the
                 same line, we don't want them to share the same length.  */
                 same line, we don't want them to share the same length.  */
              sym->ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL);
              sym->ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL);
 
 
              if (sym->attr.flavor == FL_PARAMETER)
              if (sym->attr.flavor == FL_PARAMETER)
                {
                {
                  if (init->expr_type == EXPR_CONSTANT)
                  if (init->expr_type == EXPR_CONSTANT)
                    {
                    {
                      clen = init->value.character.length;
                      clen = init->value.character.length;
                      sym->ts.u.cl->length = gfc_int_expr (clen);
                      sym->ts.u.cl->length = gfc_int_expr (clen);
                    }
                    }
                  else if (init->expr_type == EXPR_ARRAY)
                  else if (init->expr_type == EXPR_ARRAY)
                    {
                    {
                      gfc_expr *p = init->value.constructor->expr;
                      gfc_expr *p = init->value.constructor->expr;
                      clen = p->value.character.length;
                      clen = p->value.character.length;
                      sym->ts.u.cl->length = gfc_int_expr (clen);
                      sym->ts.u.cl->length = gfc_int_expr (clen);
                    }
                    }
                  else if (init->ts.u.cl && init->ts.u.cl->length)
                  else if (init->ts.u.cl && init->ts.u.cl->length)
                    sym->ts.u.cl->length =
                    sym->ts.u.cl->length =
                                gfc_copy_expr (sym->value->ts.u.cl->length);
                                gfc_copy_expr (sym->value->ts.u.cl->length);
                }
                }
            }
            }
          /* Update initializer character length according symbol.  */
          /* Update initializer character length according symbol.  */
          else if (sym->ts.u.cl->length->expr_type == EXPR_CONSTANT)
          else if (sym->ts.u.cl->length->expr_type == EXPR_CONSTANT)
            {
            {
              int len = mpz_get_si (sym->ts.u.cl->length->value.integer);
              int len = mpz_get_si (sym->ts.u.cl->length->value.integer);
              gfc_constructor * p;
              gfc_constructor * p;
 
 
              if (init->expr_type == EXPR_CONSTANT)
              if (init->expr_type == EXPR_CONSTANT)
                gfc_set_constant_character_len (len, init, -1);
                gfc_set_constant_character_len (len, init, -1);
              else if (init->expr_type == EXPR_ARRAY)
              else if (init->expr_type == EXPR_ARRAY)
                {
                {
                  /* Build a new charlen to prevent simplification from
                  /* Build a new charlen to prevent simplification from
                     deleting the length before it is resolved.  */
                     deleting the length before it is resolved.  */
                  init->ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL);
                  init->ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL);
                  init->ts.u.cl->length = gfc_copy_expr (sym->ts.u.cl->length);
                  init->ts.u.cl->length = gfc_copy_expr (sym->ts.u.cl->length);
 
 
                  for (p = init->value.constructor; p; p = p->next)
                  for (p = init->value.constructor; p; p = p->next)
                    gfc_set_constant_character_len (len, p->expr, -1);
                    gfc_set_constant_character_len (len, p->expr, -1);
                }
                }
            }
            }
        }
        }
 
 
      /* Need to check if the expression we initialized this
      /* Need to check if the expression we initialized this
         to was one of the iso_c_binding named constants.  If so,
         to was one of the iso_c_binding named constants.  If so,
         and we're a parameter (constant), let it be iso_c.
         and we're a parameter (constant), let it be iso_c.
         For example:
         For example:
         integer(c_int), parameter :: my_int = c_int
         integer(c_int), parameter :: my_int = c_int
         integer(my_int) :: my_int_2
         integer(my_int) :: my_int_2
         If we mark my_int as iso_c (since we can see it's value
         If we mark my_int as iso_c (since we can see it's value
         is equal to one of the named constants), then my_int_2
         is equal to one of the named constants), then my_int_2
         will be considered C interoperable.  */
         will be considered C interoperable.  */
      if (sym->ts.type != BT_CHARACTER && sym->ts.type != BT_DERIVED)
      if (sym->ts.type != BT_CHARACTER && sym->ts.type != BT_DERIVED)
        {
        {
          sym->ts.is_iso_c |= init->ts.is_iso_c;
          sym->ts.is_iso_c |= init->ts.is_iso_c;
          sym->ts.is_c_interop |= init->ts.is_c_interop;
          sym->ts.is_c_interop |= init->ts.is_c_interop;
          /* attr bits needed for module files.  */
          /* attr bits needed for module files.  */
          sym->attr.is_iso_c |= init->ts.is_iso_c;
          sym->attr.is_iso_c |= init->ts.is_iso_c;
          sym->attr.is_c_interop |= init->ts.is_c_interop;
          sym->attr.is_c_interop |= init->ts.is_c_interop;
          if (init->ts.is_iso_c)
          if (init->ts.is_iso_c)
            sym->ts.f90_type = init->ts.f90_type;
            sym->ts.f90_type = init->ts.f90_type;
        }
        }
 
 
      /* Add initializer.  Make sure we keep the ranks sane.  */
      /* Add initializer.  Make sure we keep the ranks sane.  */
      if (sym->attr.dimension && init->rank == 0)
      if (sym->attr.dimension && init->rank == 0)
        {
        {
          mpz_t size;
          mpz_t size;
          gfc_expr *array;
          gfc_expr *array;
          gfc_constructor *c;
          gfc_constructor *c;
          int n;
          int n;
          if (sym->attr.flavor == FL_PARAMETER
          if (sym->attr.flavor == FL_PARAMETER
                && init->expr_type == EXPR_CONSTANT
                && init->expr_type == EXPR_CONSTANT
                && spec_size (sym->as, &size) == SUCCESS
                && spec_size (sym->as, &size) == SUCCESS
                && mpz_cmp_si (size, 0) > 0)
                && mpz_cmp_si (size, 0) > 0)
            {
            {
              array = gfc_start_constructor (init->ts.type, init->ts.kind,
              array = gfc_start_constructor (init->ts.type, init->ts.kind,
                                             &init->where);
                                             &init->where);
 
 
              array->value.constructor = c = NULL;
              array->value.constructor = c = NULL;
              for (n = 0; n < (int)mpz_get_si (size); n++)
              for (n = 0; n < (int)mpz_get_si (size); n++)
                {
                {
                  if (array->value.constructor == NULL)
                  if (array->value.constructor == NULL)
                    {
                    {
                      array->value.constructor = c = gfc_get_constructor ();
                      array->value.constructor = c = gfc_get_constructor ();
                      c->expr = init;
                      c->expr = init;
                    }
                    }
                  else
                  else
                    {
                    {
                      c->next = gfc_get_constructor ();
                      c->next = gfc_get_constructor ();
                      c = c->next;
                      c = c->next;
                      c->expr = gfc_copy_expr (init);
                      c->expr = gfc_copy_expr (init);
                    }
                    }
                }
                }
 
 
              array->shape = gfc_get_shape (sym->as->rank);
              array->shape = gfc_get_shape (sym->as->rank);
              for (n = 0; n < sym->as->rank; n++)
              for (n = 0; n < sym->as->rank; n++)
                spec_dimen_size (sym->as, n, &array->shape[n]);
                spec_dimen_size (sym->as, n, &array->shape[n]);
 
 
              init = array;
              init = array;
              mpz_clear (size);
              mpz_clear (size);
            }
            }
          init->rank = sym->as->rank;
          init->rank = sym->as->rank;
        }
        }
 
 
      sym->value = init;
      sym->value = init;
      if (sym->attr.save == SAVE_NONE)
      if (sym->attr.save == SAVE_NONE)
        sym->attr.save = SAVE_IMPLICIT;
        sym->attr.save = SAVE_IMPLICIT;
      *initp = NULL;
      *initp = NULL;
    }
    }
 
 
  return SUCCESS;
  return SUCCESS;
}
}
 
 
 
 
/* Function called by variable_decl() that adds a name to a structure
/* Function called by variable_decl() that adds a name to a structure
   being built.  */
   being built.  */
 
 
static gfc_try
static gfc_try
build_struct (const char *name, gfc_charlen *cl, gfc_expr **init,
build_struct (const char *name, gfc_charlen *cl, gfc_expr **init,
              gfc_array_spec **as)
              gfc_array_spec **as)
{
{
  gfc_component *c;
  gfc_component *c;
  gfc_try t = SUCCESS;
  gfc_try t = SUCCESS;
 
 
  /* F03:C438/C439. If the current symbol is of the same derived type that we're
  /* F03:C438/C439. If the current symbol is of the same derived type that we're
     constructing, it must have the pointer attribute.  */
     constructing, it must have the pointer attribute.  */
  if ((current_ts.type == BT_DERIVED || current_ts.type == BT_CLASS)
  if ((current_ts.type == BT_DERIVED || current_ts.type == BT_CLASS)
      && current_ts.u.derived == gfc_current_block ()
      && current_ts.u.derived == gfc_current_block ()
      && current_attr.pointer == 0)
      && current_attr.pointer == 0)
    {
    {
      gfc_error ("Component at %C must have the POINTER attribute");
      gfc_error ("Component at %C must have the POINTER attribute");
      return FAILURE;
      return FAILURE;
    }
    }
 
 
  if (gfc_current_block ()->attr.pointer && (*as)->rank != 0)
  if (gfc_current_block ()->attr.pointer && (*as)->rank != 0)
    {
    {
      if ((*as)->type != AS_DEFERRED && (*as)->type != AS_EXPLICIT)
      if ((*as)->type != AS_DEFERRED && (*as)->type != AS_EXPLICIT)
        {
        {
          gfc_error ("Array component of structure at %C must have explicit "
          gfc_error ("Array component of structure at %C must have explicit "
                     "or deferred shape");
                     "or deferred shape");
          return FAILURE;
          return FAILURE;
        }
        }
    }
    }
 
 
  if (gfc_add_component (gfc_current_block (), name, &c) == FAILURE)
  if (gfc_add_component (gfc_current_block (), name, &c) == FAILURE)
    return FAILURE;
    return FAILURE;
 
 
  c->ts = current_ts;
  c->ts = current_ts;
  if (c->ts.type == BT_CHARACTER)
  if (c->ts.type == BT_CHARACTER)
    c->ts.u.cl = cl;
    c->ts.u.cl = cl;
  c->attr = current_attr;
  c->attr = current_attr;
 
 
  c->initializer = *init;
  c->initializer = *init;
  *init = NULL;
  *init = NULL;
 
 
  c->as = *as;
  c->as = *as;
  if (c->as != NULL)
  if (c->as != NULL)
    c->attr.dimension = 1;
    c->attr.dimension = 1;
  *as = NULL;
  *as = NULL;
 
 
  /* Should this ever get more complicated, combine with similar section
  /* Should this ever get more complicated, combine with similar section
     in add_init_expr_to_sym into a separate function.  */
     in add_init_expr_to_sym into a separate function.  */
  if (c->ts.type == BT_CHARACTER && !c->attr.pointer && c->initializer && c->ts.u.cl
  if (c->ts.type == BT_CHARACTER && !c->attr.pointer && c->initializer && c->ts.u.cl
      && c->ts.u.cl->length && c->ts.u.cl->length->expr_type == EXPR_CONSTANT)
      && c->ts.u.cl->length && c->ts.u.cl->length->expr_type == EXPR_CONSTANT)
    {
    {
      int len;
      int len;
 
 
      gcc_assert (c->ts.u.cl && c->ts.u.cl->length);
      gcc_assert (c->ts.u.cl && c->ts.u.cl->length);
      gcc_assert (c->ts.u.cl->length->expr_type == EXPR_CONSTANT);
      gcc_assert (c->ts.u.cl->length->expr_type == EXPR_CONSTANT);
      gcc_assert (c->ts.u.cl->length->ts.type == BT_INTEGER);
      gcc_assert (c->ts.u.cl->length->ts.type == BT_INTEGER);
 
 
      len = mpz_get_si (c->ts.u.cl->length->value.integer);
      len = mpz_get_si (c->ts.u.cl->length->value.integer);
 
 
      if (c->initializer->expr_type == EXPR_CONSTANT)
      if (c->initializer->expr_type == EXPR_CONSTANT)
        gfc_set_constant_character_len (len, c->initializer, -1);
        gfc_set_constant_character_len (len, c->initializer, -1);
      else if (mpz_cmp (c->ts.u.cl->length->value.integer,
      else if (mpz_cmp (c->ts.u.cl->length->value.integer,
                        c->initializer->ts.u.cl->length->value.integer))
                        c->initializer->ts.u.cl->length->value.integer))
        {
        {
          bool has_ts;
          bool has_ts;
          gfc_constructor *ctor = c->initializer->value.constructor;
          gfc_constructor *ctor = c->initializer->value.constructor;
 
 
          has_ts = (c->initializer->ts.u.cl
          has_ts = (c->initializer->ts.u.cl
                    && c->initializer->ts.u.cl->length_from_typespec);
                    && c->initializer->ts.u.cl->length_from_typespec);
 
 
          if (ctor)
          if (ctor)
            {
            {
              int first_len;
              int first_len;
 
 
              /* Remember the length of the first element for checking
              /* Remember the length of the first element for checking
                 that all elements *in the constructor* have the same
                 that all elements *in the constructor* have the same
                 length.  This need not be the length of the LHS!  */
                 length.  This need not be the length of the LHS!  */
              gcc_assert (ctor->expr->expr_type == EXPR_CONSTANT);
              gcc_assert (ctor->expr->expr_type == EXPR_CONSTANT);
              gcc_assert (ctor->expr->ts.type == BT_CHARACTER);
              gcc_assert (ctor->expr->ts.type == BT_CHARACTER);
              first_len = ctor->expr->value.character.length;
              first_len = ctor->expr->value.character.length;
 
 
              for (; ctor; ctor = ctor->next)
              for (; ctor; ctor = ctor->next)
                {
                {
                  if (ctor->expr->expr_type == EXPR_CONSTANT)
                  if (ctor->expr->expr_type == EXPR_CONSTANT)
                    gfc_set_constant_character_len (len, ctor->expr,
                    gfc_set_constant_character_len (len, ctor->expr,
                                                    has_ts ? -1 : first_len);
                                                    has_ts ? -1 : first_len);
                }
                }
            }
            }
        }
        }
    }
    }
 
 
  /* Check array components.  */
  /* Check array components.  */
  if (!c->attr.dimension)
  if (!c->attr.dimension)
    goto scalar;
    goto scalar;
 
 
  if (c->attr.pointer)
  if (c->attr.pointer)
    {
    {
      if (c->as->type != AS_DEFERRED)
      if (c->as->type != AS_DEFERRED)
        {
        {
          gfc_error ("Pointer array component of structure at %C must have a "
          gfc_error ("Pointer array component of structure at %C must have a "
                     "deferred shape");
                     "deferred shape");
          t = FAILURE;
          t = FAILURE;
        }
        }
    }
    }
  else if (c->attr.allocatable)
  else if (c->attr.allocatable)
    {
    {
      if (c->as->type != AS_DEFERRED)
      if (c->as->type != AS_DEFERRED)
        {
        {
          gfc_error ("Allocatable component of structure at %C must have a "
          gfc_error ("Allocatable component of structure at %C must have a "
                     "deferred shape");
                     "deferred shape");
          t = FAILURE;
          t = FAILURE;
        }
        }
    }
    }
  else
  else
    {
    {
      if (c->as->type != AS_EXPLICIT)
      if (c->as->type != AS_EXPLICIT)
        {
        {
          gfc_error ("Array component of structure at %C must have an "
          gfc_error ("Array component of structure at %C must have an "
                     "explicit shape");
                     "explicit shape");
          t = FAILURE;
          t = FAILURE;
        }
        }
    }
    }
 
 
scalar:
scalar:
  if (c->ts.type == BT_CLASS)
  if (c->ts.type == BT_CLASS)
    gfc_build_class_symbol (&c->ts, &c->attr, &c->as);
    gfc_build_class_symbol (&c->ts, &c->attr, &c->as);
 
 
  return t;
  return t;
}
}
 
 
 
 
/* Match a 'NULL()', and possibly take care of some side effects.  */
/* Match a 'NULL()', and possibly take care of some side effects.  */
 
 
match
match
gfc_match_null (gfc_expr **result)
gfc_match_null (gfc_expr **result)
{
{
  gfc_symbol *sym;
  gfc_symbol *sym;
  gfc_expr *e;
  gfc_expr *e;
  match m;
  match m;
 
 
  m = gfc_match (" null ( )");
  m = gfc_match (" null ( )");
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    return m;
    return m;
 
 
  /* The NULL symbol now has to be/become an intrinsic function.  */
  /* The NULL symbol now has to be/become an intrinsic function.  */
  if (gfc_get_symbol ("null", NULL, &sym))
  if (gfc_get_symbol ("null", NULL, &sym))
    {
    {
      gfc_error ("NULL() initialization at %C is ambiguous");
      gfc_error ("NULL() initialization at %C is ambiguous");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  gfc_intrinsic_symbol (sym);
  gfc_intrinsic_symbol (sym);
 
 
  if (sym->attr.proc != PROC_INTRINSIC
  if (sym->attr.proc != PROC_INTRINSIC
      && (gfc_add_procedure (&sym->attr, PROC_INTRINSIC,
      && (gfc_add_procedure (&sym->attr, PROC_INTRINSIC,
                             sym->name, NULL) == FAILURE
                             sym->name, NULL) == FAILURE
          || gfc_add_function (&sym->attr, sym->name, NULL) == FAILURE))
          || gfc_add_function (&sym->attr, sym->name, NULL) == FAILURE))
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  e = gfc_get_expr ();
  e = gfc_get_expr ();
  e->where = gfc_current_locus;
  e->where = gfc_current_locus;
  e->expr_type = EXPR_NULL;
  e->expr_type = EXPR_NULL;
  e->ts.type = BT_UNKNOWN;
  e->ts.type = BT_UNKNOWN;
 
 
  *result = e;
  *result = e;
 
 
  return MATCH_YES;
  return MATCH_YES;
}
}
 
 
 
 
/* Match a variable name with an optional initializer.  When this
/* Match a variable name with an optional initializer.  When this
   subroutine is called, a variable is expected to be parsed next.
   subroutine is called, a variable is expected to be parsed next.
   Depending on what is happening at the moment, updates either the
   Depending on what is happening at the moment, updates either the
   symbol table or the current interface.  */
   symbol table or the current interface.  */
 
 
static match
static match
variable_decl (int elem)
variable_decl (int elem)
{
{
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
  gfc_expr *initializer, *char_len;
  gfc_expr *initializer, *char_len;
  gfc_array_spec *as;
  gfc_array_spec *as;
  gfc_array_spec *cp_as; /* Extra copy for Cray Pointees.  */
  gfc_array_spec *cp_as; /* Extra copy for Cray Pointees.  */
  gfc_charlen *cl;
  gfc_charlen *cl;
  locus var_locus;
  locus var_locus;
  match m;
  match m;
  gfc_try t;
  gfc_try t;
  gfc_symbol *sym;
  gfc_symbol *sym;
 
 
  initializer = NULL;
  initializer = NULL;
  as = NULL;
  as = NULL;
  cp_as = NULL;
  cp_as = NULL;
 
 
  /* When we get here, we've just matched a list of attributes and
  /* 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
     maybe a type and a double colon.  The next thing we expect to see
     is the name of the symbol.  */
     is the name of the symbol.  */
  m = gfc_match_name (name);
  m = gfc_match_name (name);
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    goto cleanup;
    goto cleanup;
 
 
  var_locus = gfc_current_locus;
  var_locus = gfc_current_locus;
 
 
  /* Now we could see the optional array spec. or character length.  */
  /* Now we could see the optional array spec. or character length.  */
  m = gfc_match_array_spec (&as);
  m = gfc_match_array_spec (&as);
  if (gfc_option.flag_cray_pointer && m == MATCH_YES)
  if (gfc_option.flag_cray_pointer && m == MATCH_YES)
    cp_as = gfc_copy_array_spec (as);
    cp_as = gfc_copy_array_spec (as);
  else if (m == MATCH_ERROR)
  else if (m == MATCH_ERROR)
    goto cleanup;
    goto cleanup;
 
 
  if (m == MATCH_NO)
  if (m == MATCH_NO)
    as = gfc_copy_array_spec (current_as);
    as = gfc_copy_array_spec (current_as);
 
 
  char_len = NULL;
  char_len = NULL;
  cl = NULL;
  cl = NULL;
 
 
  if (current_ts.type == BT_CHARACTER)
  if (current_ts.type == BT_CHARACTER)
    {
    {
      switch (match_char_length (&char_len))
      switch (match_char_length (&char_len))
        {
        {
        case MATCH_YES:
        case MATCH_YES:
          cl = gfc_new_charlen (gfc_current_ns, NULL);
          cl = gfc_new_charlen (gfc_current_ns, NULL);
 
 
          cl->length = char_len;
          cl->length = char_len;
          break;
          break;
 
 
        /* Non-constant lengths need to be copied after the first
        /* Non-constant lengths need to be copied after the first
           element.  Also copy assumed lengths.  */
           element.  Also copy assumed lengths.  */
        case MATCH_NO:
        case MATCH_NO:
          if (elem > 1
          if (elem > 1
              && (current_ts.u.cl->length == NULL
              && (current_ts.u.cl->length == NULL
                  || current_ts.u.cl->length->expr_type != EXPR_CONSTANT))
                  || current_ts.u.cl->length->expr_type != EXPR_CONSTANT))
            {
            {
              cl = gfc_new_charlen (gfc_current_ns, NULL);
              cl = gfc_new_charlen (gfc_current_ns, NULL);
              cl->length = gfc_copy_expr (current_ts.u.cl->length);
              cl->length = gfc_copy_expr (current_ts.u.cl->length);
            }
            }
          else
          else
            cl = current_ts.u.cl;
            cl = current_ts.u.cl;
 
 
          break;
          break;
 
 
        case MATCH_ERROR:
        case MATCH_ERROR:
          goto cleanup;
          goto cleanup;
        }
        }
    }
    }
 
 
  /*  If this symbol has already shown up in a Cray Pointer declaration,
  /*  If this symbol has already shown up in a Cray Pointer declaration,
      then we want to set the type & bail out.  */
      then we want to set the type & bail out.  */
  if (gfc_option.flag_cray_pointer)
  if (gfc_option.flag_cray_pointer)
    {
    {
      gfc_find_symbol (name, gfc_current_ns, 1, &sym);
      gfc_find_symbol (name, gfc_current_ns, 1, &sym);
      if (sym != NULL && sym->attr.cray_pointee)
      if (sym != NULL && sym->attr.cray_pointee)
        {
        {
          sym->ts.type = current_ts.type;
          sym->ts.type = current_ts.type;
          sym->ts.kind = current_ts.kind;
          sym->ts.kind = current_ts.kind;
          sym->ts.u.cl = cl;
          sym->ts.u.cl = cl;
          sym->ts.u.derived = current_ts.u.derived;
          sym->ts.u.derived = current_ts.u.derived;
          sym->ts.is_c_interop = current_ts.is_c_interop;
          sym->ts.is_c_interop = current_ts.is_c_interop;
          sym->ts.is_iso_c = current_ts.is_iso_c;
          sym->ts.is_iso_c = current_ts.is_iso_c;
          m = MATCH_YES;
          m = MATCH_YES;
 
 
          /* Check to see if we have an array specification.  */
          /* Check to see if we have an array specification.  */
          if (cp_as != NULL)
          if (cp_as != NULL)
            {
            {
              if (sym->as != NULL)
              if (sym->as != NULL)
                {
                {
                  gfc_error ("Duplicate array spec for Cray pointee at %C");
                  gfc_error ("Duplicate array spec for Cray pointee at %C");
                  gfc_free_array_spec (cp_as);
                  gfc_free_array_spec (cp_as);
                  m = MATCH_ERROR;
                  m = MATCH_ERROR;
                  goto cleanup;
                  goto cleanup;
                }
                }
              else
              else
                {
                {
                  if (gfc_set_array_spec (sym, cp_as, &var_locus) == FAILURE)
                  if (gfc_set_array_spec (sym, cp_as, &var_locus) == FAILURE)
                    gfc_internal_error ("Couldn't set pointee array spec.");
                    gfc_internal_error ("Couldn't set pointee array spec.");
 
 
                  /* Fix the array spec.  */
                  /* Fix the array spec.  */
                  m = gfc_mod_pointee_as (sym->as);
                  m = gfc_mod_pointee_as (sym->as);
                  if (m == MATCH_ERROR)
                  if (m == MATCH_ERROR)
                    goto cleanup;
                    goto cleanup;
                }
                }
            }
            }
          goto cleanup;
          goto cleanup;
        }
        }
      else
      else
        {
        {
          gfc_free_array_spec (cp_as);
          gfc_free_array_spec (cp_as);
        }
        }
    }
    }
 
 
  /* Procedure pointer as function result.  */
  /* Procedure pointer as function result.  */
  if (gfc_current_state () == COMP_FUNCTION
  if (gfc_current_state () == COMP_FUNCTION
      && strcmp ("ppr@", gfc_current_block ()->name) == 0
      && strcmp ("ppr@", gfc_current_block ()->name) == 0
      && strcmp (name, gfc_current_block ()->ns->proc_name->name) == 0)
      && strcmp (name, gfc_current_block ()->ns->proc_name->name) == 0)
    strcpy (name, "ppr@");
    strcpy (name, "ppr@");
 
 
  if (gfc_current_state () == COMP_FUNCTION
  if (gfc_current_state () == COMP_FUNCTION
      && strcmp (name, gfc_current_block ()->name) == 0
      && strcmp (name, gfc_current_block ()->name) == 0
      && gfc_current_block ()->result
      && gfc_current_block ()->result
      && strcmp ("ppr@", gfc_current_block ()->result->name) == 0)
      && strcmp ("ppr@", gfc_current_block ()->result->name) == 0)
    strcpy (name, "ppr@");
    strcpy (name, "ppr@");
 
 
  /* OK, we've successfully matched the declaration.  Now put the
  /* OK, we've successfully matched the declaration.  Now put the
     symbol in the current namespace, because it might be used in the
     symbol in the current namespace, because it might be used in the
     optional initialization expression for this symbol, e.g. this is
     optional initialization expression for this symbol, e.g. this is
     perfectly legal:
     perfectly legal:
 
 
     integer, parameter :: i = huge(i)
     integer, parameter :: i = huge(i)
 
 
     This is only true for parameters or variables of a basic type.
     This is only true for parameters or variables of a basic type.
     For components of derived types, it is not true, so we don't
     For components of derived types, it is not true, so we don't
     create a symbol for those yet.  If we fail to create the symbol,
     create a symbol for those yet.  If we fail to create the symbol,
     bail out.  */
     bail out.  */
  if (gfc_current_state () != COMP_DERIVED
  if (gfc_current_state () != COMP_DERIVED
      && build_sym (name, cl, &as, &var_locus) == FAILURE)
      && build_sym (name, cl, &as, &var_locus) == FAILURE)
    {
    {
      m = MATCH_ERROR;
      m = MATCH_ERROR;
      goto cleanup;
      goto cleanup;
    }
    }
 
 
  /* An interface body specifies all of the procedure's
  /* An interface body specifies all of the procedure's
     characteristics and these shall be consistent with those
     characteristics and these shall be consistent with those
     specified in the procedure definition, except that the interface
     specified in the procedure definition, except that the interface
     may specify a procedure that is not pure if the procedure is
     may specify a procedure that is not pure if the procedure is
     defined to be pure(12.3.2).  */
     defined to be pure(12.3.2).  */
  if (current_ts.type == BT_DERIVED
  if (current_ts.type == BT_DERIVED
      && gfc_current_ns->proc_name
      && gfc_current_ns->proc_name
      && gfc_current_ns->proc_name->attr.if_source == IFSRC_IFBODY
      && gfc_current_ns->proc_name->attr.if_source == IFSRC_IFBODY
      && current_ts.u.derived->ns != gfc_current_ns)
      && current_ts.u.derived->ns != gfc_current_ns)
    {
    {
      gfc_symtree *st;
      gfc_symtree *st;
      st = gfc_find_symtree (gfc_current_ns->sym_root, current_ts.u.derived->name);
      st = gfc_find_symtree (gfc_current_ns->sym_root, current_ts.u.derived->name);
      if (!(current_ts.u.derived->attr.imported
      if (!(current_ts.u.derived->attr.imported
                && st != NULL
                && st != NULL
                && st->n.sym == current_ts.u.derived)
                && st->n.sym == current_ts.u.derived)
            && !gfc_current_ns->has_import_set)
            && !gfc_current_ns->has_import_set)
        {
        {
            gfc_error ("the type of '%s' at %C has not been declared within the "
            gfc_error ("the type of '%s' at %C has not been declared within the "
                       "interface", name);
                       "interface", name);
            m = MATCH_ERROR;
            m = MATCH_ERROR;
            goto cleanup;
            goto cleanup;
        }
        }
    }
    }
 
 
  /* In functions that have a RESULT variable defined, the function
  /* In functions that have a RESULT variable defined, the function
     name always refers to function calls.  Therefore, the name is
     name always refers to function calls.  Therefore, the name is
     not allowed to appear in specification statements.  */
     not allowed to appear in specification statements.  */
  if (gfc_current_state () == COMP_FUNCTION
  if (gfc_current_state () == COMP_FUNCTION
      && gfc_current_block () != NULL
      && gfc_current_block () != NULL
      && gfc_current_block ()->result != NULL
      && gfc_current_block ()->result != NULL
      && gfc_current_block ()->result != gfc_current_block ()
      && gfc_current_block ()->result != gfc_current_block ()
      && strcmp (gfc_current_block ()->name, name) == 0)
      && strcmp (gfc_current_block ()->name, name) == 0)
    {
    {
      gfc_error ("Function name '%s' not allowed at %C", name);
      gfc_error ("Function name '%s' not allowed at %C", name);
      m = MATCH_ERROR;
      m = MATCH_ERROR;
      goto cleanup;
      goto cleanup;
    }
    }
 
 
  /* We allow old-style initializations of the form
  /* We allow old-style initializations of the form
       integer i /2/, j(4) /3*3, 1/
       integer i /2/, j(4) /3*3, 1/
     (if no colon has been seen). These are different from data
     (if no colon has been seen). These are different from data
     statements in that initializers are only allowed to apply to the
     statements in that initializers are only allowed to apply to the
     variable immediately preceding, i.e.
     variable immediately preceding, i.e.
       integer i, j /1, 2/
       integer i, j /1, 2/
     is not allowed. Therefore we have to do some work manually, that
     is not allowed. Therefore we have to do some work manually, that
     could otherwise be left to the matchers for DATA statements.  */
     could otherwise be left to the matchers for DATA statements.  */
 
 
  if (!colon_seen && gfc_match (" /") == MATCH_YES)
  if (!colon_seen && gfc_match (" /") == MATCH_YES)
    {
    {
      if (gfc_notify_std (GFC_STD_GNU, "Extension: Old-style "
      if (gfc_notify_std (GFC_STD_GNU, "Extension: Old-style "
                          "initialization at %C") == FAILURE)
                          "initialization at %C") == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      return match_old_style_init (name);
      return match_old_style_init (name);
    }
    }
 
 
  /* The double colon must be present in order to have initializers.
  /* The double colon must be present in order to have initializers.
     Otherwise the statement is ambiguous with an assignment statement.  */
     Otherwise the statement is ambiguous with an assignment statement.  */
  if (colon_seen)
  if (colon_seen)
    {
    {
      if (gfc_match (" =>") == MATCH_YES)
      if (gfc_match (" =>") == MATCH_YES)
        {
        {
          if (!current_attr.pointer)
          if (!current_attr.pointer)
            {
            {
              gfc_error ("Initialization at %C isn't for a pointer variable");
              gfc_error ("Initialization at %C isn't for a pointer variable");
              m = MATCH_ERROR;
              m = MATCH_ERROR;
              goto cleanup;
              goto cleanup;
            }
            }
 
 
          m = gfc_match_null (&initializer);
          m = gfc_match_null (&initializer);
          if (m == MATCH_NO)
          if (m == MATCH_NO)
            {
            {
              gfc_error ("Pointer initialization requires a NULL() at %C");
              gfc_error ("Pointer initialization requires a NULL() at %C");
              m = MATCH_ERROR;
              m = MATCH_ERROR;
            }
            }
 
 
          if (gfc_pure (NULL) && gfc_state_stack->state != COMP_DERIVED)
          if (gfc_pure (NULL) && gfc_state_stack->state != COMP_DERIVED)
            {
            {
              gfc_error ("Initialization of pointer at %C is not allowed in "
              gfc_error ("Initialization of pointer at %C is not allowed in "
                         "a PURE procedure");
                         "a PURE procedure");
              m = MATCH_ERROR;
              m = MATCH_ERROR;
            }
            }
 
 
          if (m != MATCH_YES)
          if (m != MATCH_YES)
            goto cleanup;
            goto cleanup;
 
 
        }
        }
      else if (gfc_match_char ('=') == MATCH_YES)
      else if (gfc_match_char ('=') == MATCH_YES)
        {
        {
          if (current_attr.pointer)
          if (current_attr.pointer)
            {
            {
              gfc_error ("Pointer initialization at %C requires '=>', "
              gfc_error ("Pointer initialization at %C requires '=>', "
                         "not '='");
                         "not '='");
              m = MATCH_ERROR;
              m = MATCH_ERROR;
              goto cleanup;
              goto cleanup;
            }
            }
 
 
          m = gfc_match_init_expr (&initializer);
          m = gfc_match_init_expr (&initializer);
          if (m == MATCH_NO)
          if (m == MATCH_NO)
            {
            {
              gfc_error ("Expected an initialization expression at %C");
              gfc_error ("Expected an initialization expression at %C");
              m = MATCH_ERROR;
              m = MATCH_ERROR;
            }
            }
 
 
          if (current_attr.flavor != FL_PARAMETER && gfc_pure (NULL)
          if (current_attr.flavor != FL_PARAMETER && gfc_pure (NULL)
              && gfc_state_stack->state != COMP_DERIVED)
              && gfc_state_stack->state != COMP_DERIVED)
            {
            {
              gfc_error ("Initialization of variable at %C is not allowed in "
              gfc_error ("Initialization of variable at %C is not allowed in "
                         "a PURE procedure");
                         "a PURE procedure");
              m = MATCH_ERROR;
              m = MATCH_ERROR;
            }
            }
 
 
          if (m != MATCH_YES)
          if (m != MATCH_YES)
            goto cleanup;
            goto cleanup;
        }
        }
    }
    }
 
 
  if (initializer != NULL && current_attr.allocatable
  if (initializer != NULL && current_attr.allocatable
        && gfc_current_state () == COMP_DERIVED)
        && gfc_current_state () == COMP_DERIVED)
    {
    {
      gfc_error ("Initialization of allocatable component at %C is not "
      gfc_error ("Initialization of allocatable component at %C is not "
                 "allowed");
                 "allowed");
      m = MATCH_ERROR;
      m = MATCH_ERROR;
      goto cleanup;
      goto cleanup;
    }
    }
 
 
  /* Add the initializer.  Note that it is fine if initializer is
  /* Add the initializer.  Note that it is fine if initializer is
     NULL here, because we sometimes also need to check if a
     NULL here, because we sometimes also need to check if a
     declaration *must* have an initialization expression.  */
     declaration *must* have an initialization expression.  */
  if (gfc_current_state () != COMP_DERIVED)
  if (gfc_current_state () != COMP_DERIVED)
    t = add_init_expr_to_sym (name, &initializer, &var_locus);
    t = add_init_expr_to_sym (name, &initializer, &var_locus);
  else
  else
    {
    {
      if (current_ts.type == BT_DERIVED
      if (current_ts.type == BT_DERIVED
          && !current_attr.pointer && !initializer)
          && !current_attr.pointer && !initializer)
        initializer = gfc_default_initializer (&current_ts);
        initializer = gfc_default_initializer (&current_ts);
      t = build_struct (name, cl, &initializer, &as);
      t = build_struct (name, cl, &initializer, &as);
    }
    }
 
 
  m = (t == SUCCESS) ? MATCH_YES : MATCH_ERROR;
  m = (t == SUCCESS) ? MATCH_YES : MATCH_ERROR;
 
 
cleanup:
cleanup:
  /* Free stuff up and return.  */
  /* Free stuff up and return.  */
  gfc_free_expr (initializer);
  gfc_free_expr (initializer);
  gfc_free_array_spec (as);
  gfc_free_array_spec (as);
 
 
  return m;
  return m;
}
}
 
 
 
 
/* Match an extended-f77 "TYPESPEC*bytesize"-style kind specification.
/* Match an extended-f77 "TYPESPEC*bytesize"-style kind specification.
   This assumes that the byte size is equal to the kind number for
   This assumes that the byte size is equal to the kind number for
   non-COMPLEX types, and equal to twice the kind number for COMPLEX.  */
   non-COMPLEX types, and equal to twice the kind number for COMPLEX.  */
 
 
match
match
gfc_match_old_kind_spec (gfc_typespec *ts)
gfc_match_old_kind_spec (gfc_typespec *ts)
{
{
  match m;
  match m;
  int original_kind;
  int original_kind;
 
 
  if (gfc_match_char ('*') != MATCH_YES)
  if (gfc_match_char ('*') != MATCH_YES)
    return MATCH_NO;
    return MATCH_NO;
 
 
  m = gfc_match_small_literal_int (&ts->kind, NULL);
  m = gfc_match_small_literal_int (&ts->kind, NULL);
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  original_kind = ts->kind;
  original_kind = ts->kind;
 
 
  /* Massage the kind numbers for complex types.  */
  /* Massage the kind numbers for complex types.  */
  if (ts->type == BT_COMPLEX)
  if (ts->type == BT_COMPLEX)
    {
    {
      if (ts->kind % 2)
      if (ts->kind % 2)
        {
        {
          gfc_error ("Old-style type declaration %s*%d not supported at %C",
          gfc_error ("Old-style type declaration %s*%d not supported at %C",
                     gfc_basic_typename (ts->type), original_kind);
                     gfc_basic_typename (ts->type), original_kind);
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
      ts->kind /= 2;
      ts->kind /= 2;
    }
    }
 
 
  if (gfc_validate_kind (ts->type, ts->kind, true) < 0)
  if (gfc_validate_kind (ts->type, ts->kind, true) < 0)
    {
    {
      gfc_error ("Old-style type declaration %s*%d not supported at %C",
      gfc_error ("Old-style type declaration %s*%d not supported at %C",
                 gfc_basic_typename (ts->type), original_kind);
                 gfc_basic_typename (ts->type), original_kind);
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  if (gfc_notify_std (GFC_STD_GNU, "Nonstandard type declaration %s*%d at %C",
  if (gfc_notify_std (GFC_STD_GNU, "Nonstandard type declaration %s*%d at %C",
                      gfc_basic_typename (ts->type), original_kind) == FAILURE)
                      gfc_basic_typename (ts->type), original_kind) == FAILURE)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  return MATCH_YES;
  return MATCH_YES;
}
}
 
 
 
 
/* Match a kind specification.  Since kinds are generally optional, we
/* Match a kind specification.  Since kinds are generally optional, we
   usually return MATCH_NO if something goes wrong.  If a "kind="
   usually return MATCH_NO if something goes wrong.  If a "kind="
   string is found, then we know we have an error.  */
   string is found, then we know we have an error.  */
 
 
match
match
gfc_match_kind_spec (gfc_typespec *ts, bool kind_expr_only)
gfc_match_kind_spec (gfc_typespec *ts, bool kind_expr_only)
{
{
  locus where, loc;
  locus where, loc;
  gfc_expr *e;
  gfc_expr *e;
  match m, n;
  match m, n;
  char c;
  char c;
  const char *msg;
  const char *msg;
 
 
  m = MATCH_NO;
  m = MATCH_NO;
  n = MATCH_YES;
  n = MATCH_YES;
  e = NULL;
  e = NULL;
 
 
  where = loc = gfc_current_locus;
  where = loc = gfc_current_locus;
 
 
  if (kind_expr_only)
  if (kind_expr_only)
    goto kind_expr;
    goto kind_expr;
 
 
  if (gfc_match_char ('(') == MATCH_NO)
  if (gfc_match_char ('(') == MATCH_NO)
    return MATCH_NO;
    return MATCH_NO;
 
 
  /* Also gobbles optional text.  */
  /* Also gobbles optional text.  */
  if (gfc_match (" kind = ") == MATCH_YES)
  if (gfc_match (" kind = ") == MATCH_YES)
    m = MATCH_ERROR;
    m = MATCH_ERROR;
 
 
  loc = gfc_current_locus;
  loc = gfc_current_locus;
 
 
kind_expr:
kind_expr:
  n = gfc_match_init_expr (&e);
  n = gfc_match_init_expr (&e);
 
 
  if (n != MATCH_YES)
  if (n != MATCH_YES)
    {
    {
      if (gfc_matching_function)
      if (gfc_matching_function)
        {
        {
          /* The function kind expression might include use associated or
          /* The function kind expression might include use associated or
             imported parameters and try again after the specification
             imported parameters and try again after the specification
             expressions.....  */
             expressions.....  */
          if (gfc_match_char (')') != MATCH_YES)
          if (gfc_match_char (')') != MATCH_YES)
            {
            {
              gfc_error ("Missing right parenthesis at %C");
              gfc_error ("Missing right parenthesis at %C");
              m = MATCH_ERROR;
              m = MATCH_ERROR;
              goto no_match;
              goto no_match;
            }
            }
 
 
          gfc_free_expr (e);
          gfc_free_expr (e);
          gfc_undo_symbols ();
          gfc_undo_symbols ();
          return MATCH_YES;
          return MATCH_YES;
        }
        }
      else
      else
        {
        {
          /* ....or else, the match is real.  */
          /* ....or else, the match is real.  */
          if (n == MATCH_NO)
          if (n == MATCH_NO)
            gfc_error ("Expected initialization expression at %C");
            gfc_error ("Expected initialization expression at %C");
          if (n != MATCH_YES)
          if (n != MATCH_YES)
            return MATCH_ERROR;
            return MATCH_ERROR;
        }
        }
    }
    }
 
 
  if (e->rank != 0)
  if (e->rank != 0)
    {
    {
      gfc_error ("Expected scalar initialization expression at %C");
      gfc_error ("Expected scalar initialization expression at %C");
      m = MATCH_ERROR;
      m = MATCH_ERROR;
      goto no_match;
      goto no_match;
    }
    }
 
 
  msg = gfc_extract_int (e, &ts->kind);
  msg = gfc_extract_int (e, &ts->kind);
 
 
  if (msg != NULL)
  if (msg != NULL)
    {
    {
      gfc_error (msg);
      gfc_error (msg);
      m = MATCH_ERROR;
      m = MATCH_ERROR;
      goto no_match;
      goto no_match;
    }
    }
 
 
  /* Before throwing away the expression, let's see if we had a
  /* Before throwing away the expression, let's see if we had a
     C interoperable kind (and store the fact).  */
     C interoperable kind (and store the fact).  */
  if (e->ts.is_c_interop == 1)
  if (e->ts.is_c_interop == 1)
    {
    {
      /* Mark this as c interoperable if being declared with one
      /* Mark this as c interoperable if being declared with one
         of the named constants from iso_c_binding.  */
         of the named constants from iso_c_binding.  */
      ts->is_c_interop = e->ts.is_iso_c;
      ts->is_c_interop = e->ts.is_iso_c;
      ts->f90_type = e->ts.f90_type;
      ts->f90_type = e->ts.f90_type;
    }
    }
 
 
  gfc_free_expr (e);
  gfc_free_expr (e);
  e = NULL;
  e = NULL;
 
 
  /* Ignore errors to this point, if we've gotten here.  This means
  /* Ignore errors to this point, if we've gotten here.  This means
     we ignore the m=MATCH_ERROR from above.  */
     we ignore the m=MATCH_ERROR from above.  */
  if (gfc_validate_kind (ts->type, ts->kind, true) < 0)
  if (gfc_validate_kind (ts->type, ts->kind, true) < 0)
    {
    {
      gfc_error ("Kind %d not supported for type %s at %C", ts->kind,
      gfc_error ("Kind %d not supported for type %s at %C", ts->kind,
                 gfc_basic_typename (ts->type));
                 gfc_basic_typename (ts->type));
      gfc_current_locus = where;
      gfc_current_locus = where;
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  /* Warn if, e.g., c_int is used for a REAL variable, but not
  /* Warn if, e.g., c_int is used for a REAL variable, but not
     if, e.g., c_double is used for COMPLEX as the standard
     if, e.g., c_double is used for COMPLEX as the standard
     explicitly says that the kind type parameter for complex and real
     explicitly says that the kind type parameter for complex and real
     variable is the same, i.e. c_float == c_float_complex.  */
     variable is the same, i.e. c_float == c_float_complex.  */
  if (ts->f90_type != BT_UNKNOWN && ts->f90_type != ts->type
  if (ts->f90_type != BT_UNKNOWN && ts->f90_type != ts->type
      && !((ts->f90_type == BT_REAL && ts->type == BT_COMPLEX)
      && !((ts->f90_type == BT_REAL && ts->type == BT_COMPLEX)
           || (ts->f90_type == BT_COMPLEX && ts->type == BT_REAL)))
           || (ts->f90_type == BT_COMPLEX && ts->type == BT_REAL)))
    gfc_warning_now ("C kind type parameter is for type %s but type at %L "
    gfc_warning_now ("C kind type parameter is for type %s but type at %L "
                     "is %s", gfc_basic_typename (ts->f90_type), &where,
                     "is %s", gfc_basic_typename (ts->f90_type), &where,
                     gfc_basic_typename (ts->type));
                     gfc_basic_typename (ts->type));
 
 
  gfc_gobble_whitespace ();
  gfc_gobble_whitespace ();
  if ((c = gfc_next_ascii_char ()) != ')'
  if ((c = gfc_next_ascii_char ()) != ')'
      && (ts->type != BT_CHARACTER || c != ','))
      && (ts->type != BT_CHARACTER || c != ','))
    {
    {
      if (ts->type == BT_CHARACTER)
      if (ts->type == BT_CHARACTER)
        gfc_error ("Missing right parenthesis or comma at %C");
        gfc_error ("Missing right parenthesis or comma at %C");
      else
      else
        gfc_error ("Missing right parenthesis at %C");
        gfc_error ("Missing right parenthesis at %C");
      m = MATCH_ERROR;
      m = MATCH_ERROR;
    }
    }
  else
  else
     /* All tests passed.  */
     /* All tests passed.  */
     m = MATCH_YES;
     m = MATCH_YES;
 
 
  if(m == MATCH_ERROR)
  if(m == MATCH_ERROR)
     gfc_current_locus = where;
     gfc_current_locus = where;
 
 
  /* Return what we know from the test(s).  */
  /* Return what we know from the test(s).  */
  return m;
  return m;
 
 
no_match:
no_match:
  gfc_free_expr (e);
  gfc_free_expr (e);
  gfc_current_locus = where;
  gfc_current_locus = where;
  return m;
  return m;
}
}
 
 
 
 
static match
static match
match_char_kind (int * kind, int * is_iso_c)
match_char_kind (int * kind, int * is_iso_c)
{
{
  locus where;
  locus where;
  gfc_expr *e;
  gfc_expr *e;
  match m, n;
  match m, n;
  const char *msg;
  const char *msg;
 
 
  m = MATCH_NO;
  m = MATCH_NO;
  e = NULL;
  e = NULL;
  where = gfc_current_locus;
  where = gfc_current_locus;
 
 
  n = gfc_match_init_expr (&e);
  n = gfc_match_init_expr (&e);
 
 
  if (n != MATCH_YES && gfc_matching_function)
  if (n != MATCH_YES && gfc_matching_function)
    {
    {
      /* The expression might include use-associated or imported
      /* The expression might include use-associated or imported
         parameters and try again after the specification
         parameters and try again after the specification
         expressions.  */
         expressions.  */
      gfc_free_expr (e);
      gfc_free_expr (e);
      gfc_undo_symbols ();
      gfc_undo_symbols ();
      return MATCH_YES;
      return MATCH_YES;
    }
    }
 
 
  if (n == MATCH_NO)
  if (n == MATCH_NO)
    gfc_error ("Expected initialization expression at %C");
    gfc_error ("Expected initialization expression at %C");
  if (n != MATCH_YES)
  if (n != MATCH_YES)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  if (e->rank != 0)
  if (e->rank != 0)
    {
    {
      gfc_error ("Expected scalar initialization expression at %C");
      gfc_error ("Expected scalar initialization expression at %C");
      m = MATCH_ERROR;
      m = MATCH_ERROR;
      goto no_match;
      goto no_match;
    }
    }
 
 
  msg = gfc_extract_int (e, kind);
  msg = gfc_extract_int (e, kind);
  *is_iso_c = e->ts.is_iso_c;
  *is_iso_c = e->ts.is_iso_c;
  if (msg != NULL)
  if (msg != NULL)
    {
    {
      gfc_error (msg);
      gfc_error (msg);
      m = MATCH_ERROR;
      m = MATCH_ERROR;
      goto no_match;
      goto no_match;
    }
    }
 
 
  gfc_free_expr (e);
  gfc_free_expr (e);
 
 
  /* Ignore errors to this point, if we've gotten here.  This means
  /* Ignore errors to this point, if we've gotten here.  This means
     we ignore the m=MATCH_ERROR from above.  */
     we ignore the m=MATCH_ERROR from above.  */
  if (gfc_validate_kind (BT_CHARACTER, *kind, true) < 0)
  if (gfc_validate_kind (BT_CHARACTER, *kind, true) < 0)
    {
    {
      gfc_error ("Kind %d is not supported for CHARACTER at %C", *kind);
      gfc_error ("Kind %d is not supported for CHARACTER at %C", *kind);
      m = MATCH_ERROR;
      m = MATCH_ERROR;
    }
    }
  else
  else
     /* All tests passed.  */
     /* All tests passed.  */
     m = MATCH_YES;
     m = MATCH_YES;
 
 
  if (m == MATCH_ERROR)
  if (m == MATCH_ERROR)
     gfc_current_locus = where;
     gfc_current_locus = where;
 
 
  /* Return what we know from the test(s).  */
  /* Return what we know from the test(s).  */
  return m;
  return m;
 
 
no_match:
no_match:
  gfc_free_expr (e);
  gfc_free_expr (e);
  gfc_current_locus = where;
  gfc_current_locus = where;
  return m;
  return m;
}
}
 
 
 
 
/* Match the various kind/length specifications in a CHARACTER
/* Match the various kind/length specifications in a CHARACTER
   declaration.  We don't return MATCH_NO.  */
   declaration.  We don't return MATCH_NO.  */
 
 
match
match
gfc_match_char_spec (gfc_typespec *ts)
gfc_match_char_spec (gfc_typespec *ts)
{
{
  int kind, seen_length, is_iso_c;
  int kind, seen_length, is_iso_c;
  gfc_charlen *cl;
  gfc_charlen *cl;
  gfc_expr *len;
  gfc_expr *len;
  match m;
  match m;
 
 
  len = NULL;
  len = NULL;
  seen_length = 0;
  seen_length = 0;
  kind = 0;
  kind = 0;
  is_iso_c = 0;
  is_iso_c = 0;
 
 
  /* Try the old-style specification first.  */
  /* Try the old-style specification first.  */
  old_char_selector = 0;
  old_char_selector = 0;
 
 
  m = match_char_length (&len);
  m = match_char_length (&len);
  if (m != MATCH_NO)
  if (m != MATCH_NO)
    {
    {
      if (m == MATCH_YES)
      if (m == MATCH_YES)
        old_char_selector = 1;
        old_char_selector = 1;
      seen_length = 1;
      seen_length = 1;
      goto done;
      goto done;
    }
    }
 
 
  m = gfc_match_char ('(');
  m = gfc_match_char ('(');
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    {
    {
      m = MATCH_YES;    /* Character without length is a single char.  */
      m = MATCH_YES;    /* Character without length is a single char.  */
      goto done;
      goto done;
    }
    }
 
 
  /* Try the weird case:  ( KIND = <int> [ , LEN = <len-param> ] ).  */
  /* Try the weird case:  ( KIND = <int> [ , LEN = <len-param> ] ).  */
  if (gfc_match (" kind =") == MATCH_YES)
  if (gfc_match (" kind =") == MATCH_YES)
    {
    {
      m = match_char_kind (&kind, &is_iso_c);
      m = match_char_kind (&kind, &is_iso_c);
 
 
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        goto done;
        goto done;
      if (m == MATCH_NO)
      if (m == MATCH_NO)
        goto syntax;
        goto syntax;
 
 
      if (gfc_match (" , len =") == MATCH_NO)
      if (gfc_match (" , len =") == MATCH_NO)
        goto rparen;
        goto rparen;
 
 
      m = char_len_param_value (&len);
      m = char_len_param_value (&len);
      if (m == MATCH_NO)
      if (m == MATCH_NO)
        goto syntax;
        goto syntax;
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        goto done;
        goto done;
      seen_length = 1;
      seen_length = 1;
 
 
      goto rparen;
      goto rparen;
    }
    }
 
 
  /* Try to match "LEN = <len-param>" or "LEN = <len-param>, KIND = <int>".  */
  /* Try to match "LEN = <len-param>" or "LEN = <len-param>, KIND = <int>".  */
  if (gfc_match (" len =") == MATCH_YES)
  if (gfc_match (" len =") == MATCH_YES)
    {
    {
      m = char_len_param_value (&len);
      m = char_len_param_value (&len);
      if (m == MATCH_NO)
      if (m == MATCH_NO)
        goto syntax;
        goto syntax;
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        goto done;
        goto done;
      seen_length = 1;
      seen_length = 1;
 
 
      if (gfc_match_char (')') == MATCH_YES)
      if (gfc_match_char (')') == MATCH_YES)
        goto done;
        goto done;
 
 
      if (gfc_match (" , kind =") != MATCH_YES)
      if (gfc_match (" , kind =") != MATCH_YES)
        goto syntax;
        goto syntax;
 
 
      if (match_char_kind (&kind, &is_iso_c) == MATCH_ERROR)
      if (match_char_kind (&kind, &is_iso_c) == MATCH_ERROR)
        goto done;
        goto done;
 
 
      goto rparen;
      goto rparen;
    }
    }
 
 
  /* Try to match ( <len-param> ) or ( <len-param> , [ KIND = ] <int> ).  */
  /* Try to match ( <len-param> ) or ( <len-param> , [ KIND = ] <int> ).  */
  m = char_len_param_value (&len);
  m = char_len_param_value (&len);
  if (m == MATCH_NO)
  if (m == MATCH_NO)
    goto syntax;
    goto syntax;
  if (m == MATCH_ERROR)
  if (m == MATCH_ERROR)
    goto done;
    goto done;
  seen_length = 1;
  seen_length = 1;
 
 
  m = gfc_match_char (')');
  m = gfc_match_char (')');
  if (m == MATCH_YES)
  if (m == MATCH_YES)
    goto done;
    goto done;
 
 
  if (gfc_match_char (',') != MATCH_YES)
  if (gfc_match_char (',') != MATCH_YES)
    goto syntax;
    goto syntax;
 
 
  gfc_match (" kind =");        /* Gobble optional text.  */
  gfc_match (" kind =");        /* Gobble optional text.  */
 
 
  m = match_char_kind (&kind, &is_iso_c);
  m = match_char_kind (&kind, &is_iso_c);
  if (m == MATCH_ERROR)
  if (m == MATCH_ERROR)
    goto done;
    goto done;
  if (m == MATCH_NO)
  if (m == MATCH_NO)
    goto syntax;
    goto syntax;
 
 
rparen:
rparen:
  /* Require a right-paren at this point.  */
  /* Require a right-paren at this point.  */
  m = gfc_match_char (')');
  m = gfc_match_char (')');
  if (m == MATCH_YES)
  if (m == MATCH_YES)
    goto done;
    goto done;
 
 
syntax:
syntax:
  gfc_error ("Syntax error in CHARACTER declaration at %C");
  gfc_error ("Syntax error in CHARACTER declaration at %C");
  m = MATCH_ERROR;
  m = MATCH_ERROR;
  gfc_free_expr (len);
  gfc_free_expr (len);
  return m;
  return m;
 
 
done:
done:
  /* Deal with character functions after USE and IMPORT statements.  */
  /* Deal with character functions after USE and IMPORT statements.  */
  if (gfc_matching_function)
  if (gfc_matching_function)
    {
    {
      gfc_free_expr (len);
      gfc_free_expr (len);
      gfc_undo_symbols ();
      gfc_undo_symbols ();
      return MATCH_YES;
      return MATCH_YES;
    }
    }
 
 
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    {
    {
      gfc_free_expr (len);
      gfc_free_expr (len);
      return m;
      return m;
    }
    }
 
 
  /* Do some final massaging of the length values.  */
  /* Do some final massaging of the length values.  */
  cl = gfc_new_charlen (gfc_current_ns, NULL);
  cl = gfc_new_charlen (gfc_current_ns, NULL);
 
 
  if (seen_length == 0)
  if (seen_length == 0)
    cl->length = gfc_int_expr (1);
    cl->length = gfc_int_expr (1);
  else
  else
    cl->length = len;
    cl->length = len;
 
 
  ts->u.cl = cl;
  ts->u.cl = cl;
  ts->kind = kind == 0 ? gfc_default_character_kind : kind;
  ts->kind = kind == 0 ? gfc_default_character_kind : kind;
 
 
  /* We have to know if it was a c interoperable kind so we can
  /* We have to know if it was a c interoperable kind so we can
     do accurate type checking of bind(c) procs, etc.  */
     do accurate type checking of bind(c) procs, etc.  */
  if (kind != 0)
  if (kind != 0)
    /* Mark this as c interoperable if being declared with one
    /* Mark this as c interoperable if being declared with one
       of the named constants from iso_c_binding.  */
       of the named constants from iso_c_binding.  */
    ts->is_c_interop = is_iso_c;
    ts->is_c_interop = is_iso_c;
  else if (len != NULL)
  else if (len != NULL)
    /* Here, we might have parsed something such as: character(c_char)
    /* Here, we might have parsed something such as: character(c_char)
       In this case, the parsing code above grabs the c_char when
       In this case, the parsing code above grabs the c_char when
       looking for the length (line 1690, roughly).  it's the last
       looking for the length (line 1690, roughly).  it's the last
       testcase for parsing the kind params of a character variable.
       testcase for parsing the kind params of a character variable.
       However, it's not actually the length.    this seems like it
       However, it's not actually the length.    this seems like it
       could be an error.
       could be an error.
       To see if the user used a C interop kind, test the expr
       To see if the user used a C interop kind, test the expr
       of the so called length, and see if it's C interoperable.  */
       of the so called length, and see if it's C interoperable.  */
    ts->is_c_interop = len->ts.is_iso_c;
    ts->is_c_interop = len->ts.is_iso_c;
 
 
  return MATCH_YES;
  return MATCH_YES;
}
}
 
 
 
 
/* Matches a declaration-type-spec (F03:R502).  If successful, sets the ts
/* Matches a declaration-type-spec (F03:R502).  If successful, sets the ts
   structure to the matched specification.  This is necessary for FUNCTION and
   structure to the matched specification.  This is necessary for FUNCTION and
   IMPLICIT statements.
   IMPLICIT statements.
 
 
   If implicit_flag is nonzero, then we don't check for the optional
   If implicit_flag is nonzero, then we don't check for the optional
   kind specification.  Not doing so is needed for matching an IMPLICIT
   kind specification.  Not doing so is needed for matching an IMPLICIT
   statement correctly.  */
   statement correctly.  */
 
 
match
match
gfc_match_decl_type_spec (gfc_typespec *ts, int implicit_flag)
gfc_match_decl_type_spec (gfc_typespec *ts, int implicit_flag)
{
{
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
  gfc_symbol *sym;
  gfc_symbol *sym;
  match m;
  match m;
  char c;
  char c;
  bool seen_deferred_kind;
  bool seen_deferred_kind;
 
 
  /* A belt and braces check that the typespec is correctly being treated
  /* A belt and braces check that the typespec is correctly being treated
     as a deferred characteristic association.  */
     as a deferred characteristic association.  */
  seen_deferred_kind = (gfc_current_state () == COMP_FUNCTION)
  seen_deferred_kind = (gfc_current_state () == COMP_FUNCTION)
                          && (gfc_current_block ()->result->ts.kind == -1)
                          && (gfc_current_block ()->result->ts.kind == -1)
                          && (ts->kind == -1);
                          && (ts->kind == -1);
  gfc_clear_ts (ts);
  gfc_clear_ts (ts);
  if (seen_deferred_kind)
  if (seen_deferred_kind)
    ts->kind = -1;
    ts->kind = -1;
 
 
  /* Clear the current binding label, in case one is given.  */
  /* Clear the current binding label, in case one is given.  */
  curr_binding_label[0] = '\0';
  curr_binding_label[0] = '\0';
 
 
  if (gfc_match (" byte") == MATCH_YES)
  if (gfc_match (" byte") == MATCH_YES)
    {
    {
      if (gfc_notify_std (GFC_STD_GNU, "Extension: BYTE type at %C")
      if (gfc_notify_std (GFC_STD_GNU, "Extension: BYTE type at %C")
          == FAILURE)
          == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      if (gfc_validate_kind (BT_INTEGER, 1, true) < 0)
      if (gfc_validate_kind (BT_INTEGER, 1, true) < 0)
        {
        {
          gfc_error ("BYTE type used at %C "
          gfc_error ("BYTE type used at %C "
                     "is not available on the target machine");
                     "is not available on the target machine");
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
      ts->type = BT_INTEGER;
      ts->type = BT_INTEGER;
      ts->kind = 1;
      ts->kind = 1;
      return MATCH_YES;
      return MATCH_YES;
    }
    }
 
 
  if (gfc_match (" integer") == MATCH_YES)
  if (gfc_match (" integer") == MATCH_YES)
    {
    {
      ts->type = BT_INTEGER;
      ts->type = BT_INTEGER;
      ts->kind = gfc_default_integer_kind;
      ts->kind = gfc_default_integer_kind;
      goto get_kind;
      goto get_kind;
    }
    }
 
 
  if (gfc_match (" character") == MATCH_YES)
  if (gfc_match (" character") == MATCH_YES)
    {
    {
      ts->type = BT_CHARACTER;
      ts->type = BT_CHARACTER;
      if (implicit_flag == 0)
      if (implicit_flag == 0)
        return gfc_match_char_spec (ts);
        return gfc_match_char_spec (ts);
      else
      else
        return MATCH_YES;
        return MATCH_YES;
    }
    }
 
 
  if (gfc_match (" real") == MATCH_YES)
  if (gfc_match (" real") == MATCH_YES)
    {
    {
      ts->type = BT_REAL;
      ts->type = BT_REAL;
      ts->kind = gfc_default_real_kind;
      ts->kind = gfc_default_real_kind;
      goto get_kind;
      goto get_kind;
    }
    }
 
 
  if (gfc_match (" double precision") == MATCH_YES)
  if (gfc_match (" double precision") == MATCH_YES)
    {
    {
      ts->type = BT_REAL;
      ts->type = BT_REAL;
      ts->kind = gfc_default_double_kind;
      ts->kind = gfc_default_double_kind;
      return MATCH_YES;
      return MATCH_YES;
    }
    }
 
 
  if (gfc_match (" complex") == MATCH_YES)
  if (gfc_match (" complex") == MATCH_YES)
    {
    {
      ts->type = BT_COMPLEX;
      ts->type = BT_COMPLEX;
      ts->kind = gfc_default_complex_kind;
      ts->kind = gfc_default_complex_kind;
      goto get_kind;
      goto get_kind;
    }
    }
 
 
  if (gfc_match (" double complex") == MATCH_YES)
  if (gfc_match (" double complex") == MATCH_YES)
    {
    {
      if (gfc_notify_std (GFC_STD_GNU, "DOUBLE COMPLEX at %C does not "
      if (gfc_notify_std (GFC_STD_GNU, "DOUBLE COMPLEX at %C does not "
                          "conform to the Fortran 95 standard") == FAILURE)
                          "conform to the Fortran 95 standard") == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      ts->type = BT_COMPLEX;
      ts->type = BT_COMPLEX;
      ts->kind = gfc_default_double_kind;
      ts->kind = gfc_default_double_kind;
      return MATCH_YES;
      return MATCH_YES;
    }
    }
 
 
  if (gfc_match (" logical") == MATCH_YES)
  if (gfc_match (" logical") == MATCH_YES)
    {
    {
      ts->type = BT_LOGICAL;
      ts->type = BT_LOGICAL;
      ts->kind = gfc_default_logical_kind;
      ts->kind = gfc_default_logical_kind;
      goto get_kind;
      goto get_kind;
    }
    }
 
 
  m = gfc_match (" type ( %n )", name);
  m = gfc_match (" type ( %n )", name);
  if (m == MATCH_YES)
  if (m == MATCH_YES)
    ts->type = BT_DERIVED;
    ts->type = BT_DERIVED;
  else
  else
    {
    {
      m = gfc_match (" class ( %n )", name);
      m = gfc_match (" class ( %n )", name);
      if (m != MATCH_YES)
      if (m != MATCH_YES)
        return m;
        return m;
      ts->type = BT_CLASS;
      ts->type = BT_CLASS;
 
 
      if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: CLASS statement at %C")
      if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: CLASS statement at %C")
                          == FAILURE)
                          == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
    }
    }
 
 
  /* Defer association of the derived type until the end of the
  /* Defer association of the derived type until the end of the
     specification block.  However, if the derived type can be
     specification block.  However, if the derived type can be
     found, add it to the typespec.  */
     found, add it to the typespec.  */
  if (gfc_matching_function)
  if (gfc_matching_function)
    {
    {
      ts->u.derived = NULL;
      ts->u.derived = NULL;
      if (gfc_current_state () != COMP_INTERFACE
      if (gfc_current_state () != COMP_INTERFACE
            && !gfc_find_symbol (name, NULL, 1, &sym) && sym)
            && !gfc_find_symbol (name, NULL, 1, &sym) && sym)
        ts->u.derived = sym;
        ts->u.derived = sym;
      return MATCH_YES;
      return MATCH_YES;
    }
    }
 
 
  /* Search for the name but allow the components to be defined later.  If
  /* Search for the name but allow the components to be defined later.  If
     type = -1, this typespec has been seen in a function declaration but
     type = -1, this typespec has been seen in a function declaration but
     the type could not be accessed at that point.  */
     the type could not be accessed at that point.  */
  sym = NULL;
  sym = NULL;
  if (ts->kind != -1 && gfc_get_ha_symbol (name, &sym))
  if (ts->kind != -1 && gfc_get_ha_symbol (name, &sym))
    {
    {
      gfc_error ("Type name '%s' at %C is ambiguous", name);
      gfc_error ("Type name '%s' at %C is ambiguous", name);
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
  else if (ts->kind == -1)
  else if (ts->kind == -1)
    {
    {
      int iface = gfc_state_stack->previous->state != COMP_INTERFACE
      int iface = gfc_state_stack->previous->state != COMP_INTERFACE
                    || gfc_current_ns->has_import_set;
                    || gfc_current_ns->has_import_set;
      if (gfc_find_symbol (name, NULL, iface, &sym))
      if (gfc_find_symbol (name, NULL, iface, &sym))
        {
        {
          gfc_error ("Type name '%s' at %C is ambiguous", name);
          gfc_error ("Type name '%s' at %C is ambiguous", name);
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
      ts->kind = 0;
      ts->kind = 0;
      if (sym == NULL)
      if (sym == NULL)
        return MATCH_NO;
        return MATCH_NO;
    }
    }
 
 
  if (sym->attr.flavor != FL_DERIVED
  if (sym->attr.flavor != FL_DERIVED
      && gfc_add_flavor (&sym->attr, FL_DERIVED, sym->name, NULL) == FAILURE)
      && gfc_add_flavor (&sym->attr, FL_DERIVED, sym->name, NULL) == FAILURE)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  gfc_set_sym_referenced (sym);
  gfc_set_sym_referenced (sym);
  ts->u.derived = sym;
  ts->u.derived = sym;
 
 
  return MATCH_YES;
  return MATCH_YES;
 
 
get_kind:
get_kind:
  /* For all types except double, derived and character, look for an
  /* For all types except double, derived and character, look for an
     optional kind specifier.  MATCH_NO is actually OK at this point.  */
     optional kind specifier.  MATCH_NO is actually OK at this point.  */
  if (implicit_flag == 1)
  if (implicit_flag == 1)
    return MATCH_YES;
    return MATCH_YES;
 
 
  if (gfc_current_form == FORM_FREE)
  if (gfc_current_form == FORM_FREE)
    {
    {
      c = gfc_peek_ascii_char ();
      c = gfc_peek_ascii_char ();
      if (!gfc_is_whitespace (c) && c != '*' && c != '('
      if (!gfc_is_whitespace (c) && c != '*' && c != '('
          && c != ':' && c != ',')
          && c != ':' && c != ',')
       return MATCH_NO;
       return MATCH_NO;
    }
    }
 
 
  m = gfc_match_kind_spec (ts, false);
  m = gfc_match_kind_spec (ts, false);
  if (m == MATCH_NO && ts->type != BT_CHARACTER)
  if (m == MATCH_NO && ts->type != BT_CHARACTER)
    m = gfc_match_old_kind_spec (ts);
    m = gfc_match_old_kind_spec (ts);
 
 
  /* Defer association of the KIND expression of function results
  /* Defer association of the KIND expression of function results
     until after USE and IMPORT statements.  */
     until after USE and IMPORT statements.  */
  if ((gfc_current_state () == COMP_NONE && gfc_error_flag_test ())
  if ((gfc_current_state () == COMP_NONE && gfc_error_flag_test ())
         || gfc_matching_function)
         || gfc_matching_function)
    return MATCH_YES;
    return MATCH_YES;
 
 
  if (m == MATCH_NO)
  if (m == MATCH_NO)
    m = MATCH_YES;              /* No kind specifier found.  */
    m = MATCH_YES;              /* No kind specifier found.  */
 
 
  return m;
  return m;
}
}
 
 
 
 
/* Match an IMPLICIT NONE statement.  Actually, this statement is
/* Match an IMPLICIT NONE statement.  Actually, this statement is
   already matched in parse.c, or we would not end up here in the
   already matched in parse.c, or we would not end up here in the
   first place.  So the only thing we need to check, is if there is
   first place.  So the only thing we need to check, is if there is
   trailing garbage.  If not, the match is successful.  */
   trailing garbage.  If not, the match is successful.  */
 
 
match
match
gfc_match_implicit_none (void)
gfc_match_implicit_none (void)
{
{
  return (gfc_match_eos () == MATCH_YES) ? MATCH_YES : MATCH_NO;
  return (gfc_match_eos () == MATCH_YES) ? MATCH_YES : MATCH_NO;
}
}
 
 
 
 
/* Match the letter range(s) of an IMPLICIT statement.  */
/* Match the letter range(s) of an IMPLICIT statement.  */
 
 
static match
static match
match_implicit_range (void)
match_implicit_range (void)
{
{
  char c, c1, c2;
  char c, c1, c2;
  int inner;
  int inner;
  locus cur_loc;
  locus cur_loc;
 
 
  cur_loc = gfc_current_locus;
  cur_loc = gfc_current_locus;
 
 
  gfc_gobble_whitespace ();
  gfc_gobble_whitespace ();
  c = gfc_next_ascii_char ();
  c = gfc_next_ascii_char ();
  if (c != '(')
  if (c != '(')
    {
    {
      gfc_error ("Missing character range in IMPLICIT at %C");
      gfc_error ("Missing character range in IMPLICIT at %C");
      goto bad;
      goto bad;
    }
    }
 
 
  inner = 1;
  inner = 1;
  while (inner)
  while (inner)
    {
    {
      gfc_gobble_whitespace ();
      gfc_gobble_whitespace ();
      c1 = gfc_next_ascii_char ();
      c1 = gfc_next_ascii_char ();
      if (!ISALPHA (c1))
      if (!ISALPHA (c1))
        goto bad;
        goto bad;
 
 
      gfc_gobble_whitespace ();
      gfc_gobble_whitespace ();
      c = gfc_next_ascii_char ();
      c = gfc_next_ascii_char ();
 
 
      switch (c)
      switch (c)
        {
        {
        case ')':
        case ')':
          inner = 0;             /* Fall through.  */
          inner = 0;             /* Fall through.  */
 
 
        case ',':
        case ',':
          c2 = c1;
          c2 = c1;
          break;
          break;
 
 
        case '-':
        case '-':
          gfc_gobble_whitespace ();
          gfc_gobble_whitespace ();
          c2 = gfc_next_ascii_char ();
          c2 = gfc_next_ascii_char ();
          if (!ISALPHA (c2))
          if (!ISALPHA (c2))
            goto bad;
            goto bad;
 
 
          gfc_gobble_whitespace ();
          gfc_gobble_whitespace ();
          c = gfc_next_ascii_char ();
          c = gfc_next_ascii_char ();
 
 
          if ((c != ',') && (c != ')'))
          if ((c != ',') && (c != ')'))
            goto bad;
            goto bad;
          if (c == ')')
          if (c == ')')
            inner = 0;
            inner = 0;
 
 
          break;
          break;
 
 
        default:
        default:
          goto bad;
          goto bad;
        }
        }
 
 
      if (c1 > c2)
      if (c1 > c2)
        {
        {
          gfc_error ("Letters must be in alphabetic order in "
          gfc_error ("Letters must be in alphabetic order in "
                     "IMPLICIT statement at %C");
                     "IMPLICIT statement at %C");
          goto bad;
          goto bad;
        }
        }
 
 
      /* See if we can add the newly matched range to the pending
      /* See if we can add the newly matched range to the pending
         implicits from this IMPLICIT statement.  We do not check for
         implicits from this IMPLICIT statement.  We do not check for
         conflicts with whatever earlier IMPLICIT statements may have
         conflicts with whatever earlier IMPLICIT statements may have
         set.  This is done when we've successfully finished matching
         set.  This is done when we've successfully finished matching
         the current one.  */
         the current one.  */
      if (gfc_add_new_implicit_range (c1, c2) != SUCCESS)
      if (gfc_add_new_implicit_range (c1, c2) != SUCCESS)
        goto bad;
        goto bad;
    }
    }
 
 
  return MATCH_YES;
  return MATCH_YES;
 
 
bad:
bad:
  gfc_syntax_error (ST_IMPLICIT);
  gfc_syntax_error (ST_IMPLICIT);
 
 
  gfc_current_locus = cur_loc;
  gfc_current_locus = cur_loc;
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
/* Match an IMPLICIT statement, storing the types for
/* Match an IMPLICIT statement, storing the types for
   gfc_set_implicit() if the statement is accepted by the parser.
   gfc_set_implicit() if the statement is accepted by the parser.
   There is a strange looking, but legal syntactic construction
   There is a strange looking, but legal syntactic construction
   possible.  It looks like:
   possible.  It looks like:
 
 
     IMPLICIT INTEGER (a-b) (c-d)
     IMPLICIT INTEGER (a-b) (c-d)
 
 
   This is legal if "a-b" is a constant expression that happens to
   This is legal if "a-b" is a constant expression that happens to
   equal one of the legal kinds for integers.  The real problem
   equal one of the legal kinds for integers.  The real problem
   happens with an implicit specification that looks like:
   happens with an implicit specification that looks like:
 
 
     IMPLICIT INTEGER (a-b)
     IMPLICIT INTEGER (a-b)
 
 
   In this case, a typespec matcher that is "greedy" (as most of the
   In this case, a typespec matcher that is "greedy" (as most of the
   matchers are) gobbles the character range as a kindspec, leaving
   matchers are) gobbles the character range as a kindspec, leaving
   nothing left.  We therefore have to go a bit more slowly in the
   nothing left.  We therefore have to go a bit more slowly in the
   matching process by inhibiting the kindspec checking during
   matching process by inhibiting the kindspec checking during
   typespec matching and checking for a kind later.  */
   typespec matching and checking for a kind later.  */
 
 
match
match
gfc_match_implicit (void)
gfc_match_implicit (void)
{
{
  gfc_typespec ts;
  gfc_typespec ts;
  locus cur_loc;
  locus cur_loc;
  char c;
  char c;
  match m;
  match m;
 
 
  gfc_clear_ts (&ts);
  gfc_clear_ts (&ts);
 
 
  /* We don't allow empty implicit statements.  */
  /* We don't allow empty implicit statements.  */
  if (gfc_match_eos () == MATCH_YES)
  if (gfc_match_eos () == MATCH_YES)
    {
    {
      gfc_error ("Empty IMPLICIT statement at %C");
      gfc_error ("Empty IMPLICIT statement at %C");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  do
  do
    {
    {
      /* First cleanup.  */
      /* First cleanup.  */
      gfc_clear_new_implicit ();
      gfc_clear_new_implicit ();
 
 
      /* A basic type is mandatory here.  */
      /* A basic type is mandatory here.  */
      m = gfc_match_decl_type_spec (&ts, 1);
      m = gfc_match_decl_type_spec (&ts, 1);
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        goto error;
        goto error;
      if (m == MATCH_NO)
      if (m == MATCH_NO)
        goto syntax;
        goto syntax;
 
 
      cur_loc = gfc_current_locus;
      cur_loc = gfc_current_locus;
      m = match_implicit_range ();
      m = match_implicit_range ();
 
 
      if (m == MATCH_YES)
      if (m == MATCH_YES)
        {
        {
          /* We may have <TYPE> (<RANGE>).  */
          /* We may have <TYPE> (<RANGE>).  */
          gfc_gobble_whitespace ();
          gfc_gobble_whitespace ();
          c = gfc_next_ascii_char ();
          c = gfc_next_ascii_char ();
          if ((c == '\n') || (c == ','))
          if ((c == '\n') || (c == ','))
            {
            {
              /* Check for CHARACTER with no length parameter.  */
              /* Check for CHARACTER with no length parameter.  */
              if (ts.type == BT_CHARACTER && !ts.u.cl)
              if (ts.type == BT_CHARACTER && !ts.u.cl)
                {
                {
                  ts.kind = gfc_default_character_kind;
                  ts.kind = gfc_default_character_kind;
                  ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL);
                  ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL);
                  ts.u.cl->length = gfc_int_expr (1);
                  ts.u.cl->length = gfc_int_expr (1);
                }
                }
 
 
              /* Record the Successful match.  */
              /* Record the Successful match.  */
              if (gfc_merge_new_implicit (&ts) != SUCCESS)
              if (gfc_merge_new_implicit (&ts) != SUCCESS)
                return MATCH_ERROR;
                return MATCH_ERROR;
              continue;
              continue;
            }
            }
 
 
          gfc_current_locus = cur_loc;
          gfc_current_locus = cur_loc;
        }
        }
 
 
      /* Discard the (incorrectly) matched range.  */
      /* Discard the (incorrectly) matched range.  */
      gfc_clear_new_implicit ();
      gfc_clear_new_implicit ();
 
 
      /* Last chance -- check <TYPE> <SELECTOR> (<RANGE>).  */
      /* Last chance -- check <TYPE> <SELECTOR> (<RANGE>).  */
      if (ts.type == BT_CHARACTER)
      if (ts.type == BT_CHARACTER)
        m = gfc_match_char_spec (&ts);
        m = gfc_match_char_spec (&ts);
      else
      else
        {
        {
          m = gfc_match_kind_spec (&ts, false);
          m = gfc_match_kind_spec (&ts, false);
          if (m == MATCH_NO)
          if (m == MATCH_NO)
            {
            {
              m = gfc_match_old_kind_spec (&ts);
              m = gfc_match_old_kind_spec (&ts);
              if (m == MATCH_ERROR)
              if (m == MATCH_ERROR)
                goto error;
                goto error;
              if (m == MATCH_NO)
              if (m == MATCH_NO)
                goto syntax;
                goto syntax;
            }
            }
        }
        }
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        goto error;
        goto error;
 
 
      m = match_implicit_range ();
      m = match_implicit_range ();
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        goto error;
        goto error;
      if (m == MATCH_NO)
      if (m == MATCH_NO)
        goto syntax;
        goto syntax;
 
 
      gfc_gobble_whitespace ();
      gfc_gobble_whitespace ();
      c = gfc_next_ascii_char ();
      c = gfc_next_ascii_char ();
      if ((c != '\n') && (c != ','))
      if ((c != '\n') && (c != ','))
        goto syntax;
        goto syntax;
 
 
      if (gfc_merge_new_implicit (&ts) != SUCCESS)
      if (gfc_merge_new_implicit (&ts) != SUCCESS)
        return MATCH_ERROR;
        return MATCH_ERROR;
    }
    }
  while (c == ',');
  while (c == ',');
 
 
  return MATCH_YES;
  return MATCH_YES;
 
 
syntax:
syntax:
  gfc_syntax_error (ST_IMPLICIT);
  gfc_syntax_error (ST_IMPLICIT);
 
 
error:
error:
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
match
match
gfc_match_import (void)
gfc_match_import (void)
{
{
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
  match m;
  match m;
  gfc_symbol *sym;
  gfc_symbol *sym;
  gfc_symtree *st;
  gfc_symtree *st;
 
 
  if (gfc_current_ns->proc_name == NULL
  if (gfc_current_ns->proc_name == NULL
      || gfc_current_ns->proc_name->attr.if_source != IFSRC_IFBODY)
      || gfc_current_ns->proc_name->attr.if_source != IFSRC_IFBODY)
    {
    {
      gfc_error ("IMPORT statement at %C only permitted in "
      gfc_error ("IMPORT statement at %C only permitted in "
                 "an INTERFACE body");
                 "an INTERFACE body");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: IMPORT statement at %C")
  if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: IMPORT statement at %C")
      == FAILURE)
      == FAILURE)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  if (gfc_match_eos () == MATCH_YES)
  if (gfc_match_eos () == MATCH_YES)
    {
    {
      /* All host variables should be imported.  */
      /* All host variables should be imported.  */
      gfc_current_ns->has_import_set = 1;
      gfc_current_ns->has_import_set = 1;
      return MATCH_YES;
      return MATCH_YES;
    }
    }
 
 
  if (gfc_match (" ::") == MATCH_YES)
  if (gfc_match (" ::") == MATCH_YES)
    {
    {
      if (gfc_match_eos () == MATCH_YES)
      if (gfc_match_eos () == MATCH_YES)
        {
        {
           gfc_error ("Expecting list of named entities at %C");
           gfc_error ("Expecting list of named entities at %C");
           return MATCH_ERROR;
           return MATCH_ERROR;
        }
        }
    }
    }
 
 
  for(;;)
  for(;;)
    {
    {
      m = gfc_match (" %n", name);
      m = gfc_match (" %n", name);
      switch (m)
      switch (m)
        {
        {
        case MATCH_YES:
        case MATCH_YES:
          if (gfc_current_ns->parent !=  NULL
          if (gfc_current_ns->parent !=  NULL
              && gfc_find_symbol (name, gfc_current_ns->parent, 1, &sym))
              && gfc_find_symbol (name, gfc_current_ns->parent, 1, &sym))
            {
            {
               gfc_error ("Type name '%s' at %C is ambiguous", name);
               gfc_error ("Type name '%s' at %C is ambiguous", name);
               return MATCH_ERROR;
               return MATCH_ERROR;
            }
            }
          else if (gfc_current_ns->proc_name->ns->parent !=  NULL
          else if (gfc_current_ns->proc_name->ns->parent !=  NULL
                   && gfc_find_symbol (name,
                   && gfc_find_symbol (name,
                                       gfc_current_ns->proc_name->ns->parent,
                                       gfc_current_ns->proc_name->ns->parent,
                                       1, &sym))
                                       1, &sym))
            {
            {
               gfc_error ("Type name '%s' at %C is ambiguous", name);
               gfc_error ("Type name '%s' at %C is ambiguous", name);
               return MATCH_ERROR;
               return MATCH_ERROR;
            }
            }
 
 
          if (sym == NULL)
          if (sym == NULL)
            {
            {
              gfc_error ("Cannot IMPORT '%s' from host scoping unit "
              gfc_error ("Cannot IMPORT '%s' from host scoping unit "
                         "at %C - does not exist.", name);
                         "at %C - does not exist.", name);
              return MATCH_ERROR;
              return MATCH_ERROR;
            }
            }
 
 
          if (gfc_find_symtree (gfc_current_ns->sym_root,name))
          if (gfc_find_symtree (gfc_current_ns->sym_root,name))
            {
            {
              gfc_warning ("'%s' is already IMPORTed from host scoping unit "
              gfc_warning ("'%s' is already IMPORTed from host scoping unit "
                           "at %C.", name);
                           "at %C.", name);
              goto next_item;
              goto next_item;
            }
            }
 
 
          st = gfc_new_symtree (&gfc_current_ns->sym_root, sym->name);
          st = gfc_new_symtree (&gfc_current_ns->sym_root, sym->name);
          st->n.sym = sym;
          st->n.sym = sym;
          sym->refs++;
          sym->refs++;
          sym->attr.imported = 1;
          sym->attr.imported = 1;
 
 
          goto next_item;
          goto next_item;
 
 
        case MATCH_NO:
        case MATCH_NO:
          break;
          break;
 
 
        case MATCH_ERROR:
        case MATCH_ERROR:
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
    next_item:
    next_item:
      if (gfc_match_eos () == MATCH_YES)
      if (gfc_match_eos () == MATCH_YES)
        break;
        break;
      if (gfc_match_char (',') != MATCH_YES)
      if (gfc_match_char (',') != MATCH_YES)
        goto syntax;
        goto syntax;
    }
    }
 
 
  return MATCH_YES;
  return MATCH_YES;
 
 
syntax:
syntax:
  gfc_error ("Syntax error in IMPORT statement at %C");
  gfc_error ("Syntax error in IMPORT statement at %C");
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
/* A minimal implementation of gfc_match without whitespace, escape
/* A minimal implementation of gfc_match without whitespace, escape
   characters or variable arguments.  Returns true if the next
   characters or variable arguments.  Returns true if the next
   characters match the TARGET template exactly.  */
   characters match the TARGET template exactly.  */
 
 
static bool
static bool
match_string_p (const char *target)
match_string_p (const char *target)
{
{
  const char *p;
  const char *p;
 
 
  for (p = target; *p; p++)
  for (p = target; *p; p++)
    if ((char) gfc_next_ascii_char () != *p)
    if ((char) gfc_next_ascii_char () != *p)
      return false;
      return false;
  return true;
  return true;
}
}
 
 
/* Matches an attribute specification including array specs.  If
/* Matches an attribute specification including array specs.  If
   successful, leaves the variables current_attr and current_as
   successful, leaves the variables current_attr and current_as
   holding the specification.  Also sets the colon_seen variable for
   holding the specification.  Also sets the colon_seen variable for
   later use by matchers associated with initializations.
   later use by matchers associated with initializations.
 
 
   This subroutine is a little tricky in the sense that we don't know
   This subroutine is a little tricky in the sense that we don't know
   if we really have an attr-spec until we hit the double colon.
   if we really have an attr-spec until we hit the double colon.
   Until that time, we can only return MATCH_NO.  This forces us to
   Until that time, we can only return MATCH_NO.  This forces us to
   check for duplicate specification at this level.  */
   check for duplicate specification at this level.  */
 
 
static match
static match
match_attr_spec (void)
match_attr_spec (void)
{
{
  /* Modifiers that can exist in a type statement.  */
  /* Modifiers that can exist in a type statement.  */
  typedef enum
  typedef enum
  { GFC_DECL_BEGIN = 0,
  { GFC_DECL_BEGIN = 0,
    DECL_ALLOCATABLE = GFC_DECL_BEGIN, DECL_DIMENSION, DECL_EXTERNAL,
    DECL_ALLOCATABLE = GFC_DECL_BEGIN, DECL_DIMENSION, DECL_EXTERNAL,
    DECL_IN, DECL_OUT, DECL_INOUT, DECL_INTRINSIC, DECL_OPTIONAL,
    DECL_IN, DECL_OUT, DECL_INOUT, DECL_INTRINSIC, DECL_OPTIONAL,
    DECL_PARAMETER, DECL_POINTER, DECL_PROTECTED, DECL_PRIVATE,
    DECL_PARAMETER, DECL_POINTER, DECL_PROTECTED, DECL_PRIVATE,
    DECL_PUBLIC, DECL_SAVE, DECL_TARGET, DECL_VALUE, DECL_VOLATILE,
    DECL_PUBLIC, DECL_SAVE, DECL_TARGET, DECL_VALUE, DECL_VOLATILE,
    DECL_IS_BIND_C, DECL_ASYNCHRONOUS, DECL_NONE,
    DECL_IS_BIND_C, DECL_ASYNCHRONOUS, DECL_NONE,
    GFC_DECL_END /* Sentinel */
    GFC_DECL_END /* Sentinel */
  }
  }
  decl_types;
  decl_types;
 
 
/* GFC_DECL_END is the sentinel, index starts at 0.  */
/* GFC_DECL_END is the sentinel, index starts at 0.  */
#define NUM_DECL GFC_DECL_END
#define NUM_DECL GFC_DECL_END
 
 
  locus start, seen_at[NUM_DECL];
  locus start, seen_at[NUM_DECL];
  int seen[NUM_DECL];
  int seen[NUM_DECL];
  unsigned int d;
  unsigned int d;
  const char *attr;
  const char *attr;
  match m;
  match m;
  gfc_try t;
  gfc_try t;
 
 
  gfc_clear_attr (&current_attr);
  gfc_clear_attr (&current_attr);
  start = gfc_current_locus;
  start = gfc_current_locus;
 
 
  current_as = NULL;
  current_as = NULL;
  colon_seen = 0;
  colon_seen = 0;
 
 
  /* See if we get all of the keywords up to the final double colon.  */
  /* See if we get all of the keywords up to the final double colon.  */
  for (d = GFC_DECL_BEGIN; d != GFC_DECL_END; d++)
  for (d = GFC_DECL_BEGIN; d != GFC_DECL_END; d++)
    seen[d] = 0;
    seen[d] = 0;
 
 
  for (;;)
  for (;;)
    {
    {
      char ch;
      char ch;
 
 
      d = DECL_NONE;
      d = DECL_NONE;
      gfc_gobble_whitespace ();
      gfc_gobble_whitespace ();
 
 
      ch = gfc_next_ascii_char ();
      ch = gfc_next_ascii_char ();
      if (ch == ':')
      if (ch == ':')
        {
        {
          /* This is the successful exit condition for the loop.  */
          /* This is the successful exit condition for the loop.  */
          if (gfc_next_ascii_char () == ':')
          if (gfc_next_ascii_char () == ':')
            break;
            break;
        }
        }
      else if (ch == ',')
      else if (ch == ',')
        {
        {
          gfc_gobble_whitespace ();
          gfc_gobble_whitespace ();
          switch (gfc_peek_ascii_char ())
          switch (gfc_peek_ascii_char ())
            {
            {
            case 'a':
            case 'a':
              gfc_next_ascii_char ();
              gfc_next_ascii_char ();
              switch (gfc_next_ascii_char ())
              switch (gfc_next_ascii_char ())
                {
                {
                case 'l':
                case 'l':
                  if (match_string_p ("locatable"))
                  if (match_string_p ("locatable"))
                    {
                    {
                      /* Matched "allocatable".  */
                      /* Matched "allocatable".  */
                      d = DECL_ALLOCATABLE;
                      d = DECL_ALLOCATABLE;
                    }
                    }
                  break;
                  break;
 
 
                case 's':
                case 's':
                  if (match_string_p ("ynchronous"))
                  if (match_string_p ("ynchronous"))
                    {
                    {
                      /* Matched "asynchronous".  */
                      /* Matched "asynchronous".  */
                      d = DECL_ASYNCHRONOUS;
                      d = DECL_ASYNCHRONOUS;
                    }
                    }
                  break;
                  break;
                }
                }
 
 
            case 'b':
            case 'b':
              /* Try and match the bind(c).  */
              /* Try and match the bind(c).  */
              m = gfc_match_bind_c (NULL, true);
              m = gfc_match_bind_c (NULL, true);
              if (m == MATCH_YES)
              if (m == MATCH_YES)
                d = DECL_IS_BIND_C;
                d = DECL_IS_BIND_C;
              else if (m == MATCH_ERROR)
              else if (m == MATCH_ERROR)
                goto cleanup;
                goto cleanup;
              break;
              break;
 
 
            case 'd':
            case 'd':
              if (match_string_p ("dimension"))
              if (match_string_p ("dimension"))
                d = DECL_DIMENSION;
                d = DECL_DIMENSION;
              break;
              break;
 
 
            case 'e':
            case 'e':
              if (match_string_p ("external"))
              if (match_string_p ("external"))
                d = DECL_EXTERNAL;
                d = DECL_EXTERNAL;
              break;
              break;
 
 
            case 'i':
            case 'i':
              if (match_string_p ("int"))
              if (match_string_p ("int"))
                {
                {
                  ch = gfc_next_ascii_char ();
                  ch = gfc_next_ascii_char ();
                  if (ch == 'e')
                  if (ch == 'e')
                    {
                    {
                      if (match_string_p ("nt"))
                      if (match_string_p ("nt"))
                        {
                        {
                          /* Matched "intent".  */
                          /* Matched "intent".  */
                          /* TODO: Call match_intent_spec from here.  */
                          /* TODO: Call match_intent_spec from here.  */
                          if (gfc_match (" ( in out )") == MATCH_YES)
                          if (gfc_match (" ( in out )") == MATCH_YES)
                            d = DECL_INOUT;
                            d = DECL_INOUT;
                          else if (gfc_match (" ( in )") == MATCH_YES)
                          else if (gfc_match (" ( in )") == MATCH_YES)
                            d = DECL_IN;
                            d = DECL_IN;
                          else if (gfc_match (" ( out )") == MATCH_YES)
                          else if (gfc_match (" ( out )") == MATCH_YES)
                            d = DECL_OUT;
                            d = DECL_OUT;
                        }
                        }
                    }
                    }
                  else if (ch == 'r')
                  else if (ch == 'r')
                    {
                    {
                      if (match_string_p ("insic"))
                      if (match_string_p ("insic"))
                        {
                        {
                          /* Matched "intrinsic".  */
                          /* Matched "intrinsic".  */
                          d = DECL_INTRINSIC;
                          d = DECL_INTRINSIC;
                        }
                        }
                    }
                    }
                }
                }
              break;
              break;
 
 
            case 'o':
            case 'o':
              if (match_string_p ("optional"))
              if (match_string_p ("optional"))
                d = DECL_OPTIONAL;
                d = DECL_OPTIONAL;
              break;
              break;
 
 
            case 'p':
            case 'p':
              gfc_next_ascii_char ();
              gfc_next_ascii_char ();
              switch (gfc_next_ascii_char ())
              switch (gfc_next_ascii_char ())
                {
                {
                case 'a':
                case 'a':
                  if (match_string_p ("rameter"))
                  if (match_string_p ("rameter"))
                    {
                    {
                      /* Matched "parameter".  */
                      /* Matched "parameter".  */
                      d = DECL_PARAMETER;
                      d = DECL_PARAMETER;
                    }
                    }
                  break;
                  break;
 
 
                case 'o':
                case 'o':
                  if (match_string_p ("inter"))
                  if (match_string_p ("inter"))
                    {
                    {
                      /* Matched "pointer".  */
                      /* Matched "pointer".  */
                      d = DECL_POINTER;
                      d = DECL_POINTER;
                    }
                    }
                  break;
                  break;
 
 
                case 'r':
                case 'r':
                  ch = gfc_next_ascii_char ();
                  ch = gfc_next_ascii_char ();
                  if (ch == 'i')
                  if (ch == 'i')
                    {
                    {
                      if (match_string_p ("vate"))
                      if (match_string_p ("vate"))
                        {
                        {
                          /* Matched "private".  */
                          /* Matched "private".  */
                          d = DECL_PRIVATE;
                          d = DECL_PRIVATE;
                        }
                        }
                    }
                    }
                  else if (ch == 'o')
                  else if (ch == 'o')
                    {
                    {
                      if (match_string_p ("tected"))
                      if (match_string_p ("tected"))
                        {
                        {
                          /* Matched "protected".  */
                          /* Matched "protected".  */
                          d = DECL_PROTECTED;
                          d = DECL_PROTECTED;
                        }
                        }
                    }
                    }
                  break;
                  break;
 
 
                case 'u':
                case 'u':
                  if (match_string_p ("blic"))
                  if (match_string_p ("blic"))
                    {
                    {
                      /* Matched "public".  */
                      /* Matched "public".  */
                      d = DECL_PUBLIC;
                      d = DECL_PUBLIC;
                    }
                    }
                  break;
                  break;
                }
                }
              break;
              break;
 
 
            case 's':
            case 's':
              if (match_string_p ("save"))
              if (match_string_p ("save"))
                d = DECL_SAVE;
                d = DECL_SAVE;
              break;
              break;
 
 
            case 't':
            case 't':
              if (match_string_p ("target"))
              if (match_string_p ("target"))
                d = DECL_TARGET;
                d = DECL_TARGET;
              break;
              break;
 
 
            case 'v':
            case 'v':
              gfc_next_ascii_char ();
              gfc_next_ascii_char ();
              ch = gfc_next_ascii_char ();
              ch = gfc_next_ascii_char ();
              if (ch == 'a')
              if (ch == 'a')
                {
                {
                  if (match_string_p ("lue"))
                  if (match_string_p ("lue"))
                    {
                    {
                      /* Matched "value".  */
                      /* Matched "value".  */
                      d = DECL_VALUE;
                      d = DECL_VALUE;
                    }
                    }
                }
                }
              else if (ch == 'o')
              else if (ch == 'o')
                {
                {
                  if (match_string_p ("latile"))
                  if (match_string_p ("latile"))
                    {
                    {
                      /* Matched "volatile".  */
                      /* Matched "volatile".  */
                      d = DECL_VOLATILE;
                      d = DECL_VOLATILE;
                    }
                    }
                }
                }
              break;
              break;
            }
            }
        }
        }
 
 
      /* No double colon and no recognizable decl_type, so assume that
      /* No double colon and no recognizable decl_type, so assume that
         we've been looking at something else the whole time.  */
         we've been looking at something else the whole time.  */
      if (d == DECL_NONE)
      if (d == DECL_NONE)
        {
        {
          m = MATCH_NO;
          m = MATCH_NO;
          goto cleanup;
          goto cleanup;
        }
        }
 
 
      /* Check to make sure any parens are paired up correctly.  */
      /* Check to make sure any parens are paired up correctly.  */
      if (gfc_match_parens () == MATCH_ERROR)
      if (gfc_match_parens () == MATCH_ERROR)
        {
        {
          m = MATCH_ERROR;
          m = MATCH_ERROR;
          goto cleanup;
          goto cleanup;
        }
        }
 
 
      seen[d]++;
      seen[d]++;
      seen_at[d] = gfc_current_locus;
      seen_at[d] = gfc_current_locus;
 
 
      if (d == DECL_DIMENSION)
      if (d == DECL_DIMENSION)
        {
        {
          m = gfc_match_array_spec (&current_as);
          m = gfc_match_array_spec (&current_as);
 
 
          if (m == MATCH_NO)
          if (m == MATCH_NO)
            {
            {
              gfc_error ("Missing dimension specification at %C");
              gfc_error ("Missing dimension specification at %C");
              m = MATCH_ERROR;
              m = MATCH_ERROR;
            }
            }
 
 
          if (m == MATCH_ERROR)
          if (m == MATCH_ERROR)
            goto cleanup;
            goto cleanup;
        }
        }
    }
    }
 
 
  /* Since we've seen a double colon, we have to be looking at an
  /* Since we've seen a double colon, we have to be looking at an
     attr-spec.  This means that we can now issue errors.  */
     attr-spec.  This means that we can now issue errors.  */
  for (d = GFC_DECL_BEGIN; d != GFC_DECL_END; d++)
  for (d = GFC_DECL_BEGIN; d != GFC_DECL_END; d++)
    if (seen[d] > 1)
    if (seen[d] > 1)
      {
      {
        switch (d)
        switch (d)
          {
          {
          case DECL_ALLOCATABLE:
          case DECL_ALLOCATABLE:
            attr = "ALLOCATABLE";
            attr = "ALLOCATABLE";
            break;
            break;
          case DECL_ASYNCHRONOUS:
          case DECL_ASYNCHRONOUS:
            attr = "ASYNCHRONOUS";
            attr = "ASYNCHRONOUS";
            break;
            break;
          case DECL_DIMENSION:
          case DECL_DIMENSION:
            attr = "DIMENSION";
            attr = "DIMENSION";
            break;
            break;
          case DECL_EXTERNAL:
          case DECL_EXTERNAL:
            attr = "EXTERNAL";
            attr = "EXTERNAL";
            break;
            break;
          case DECL_IN:
          case DECL_IN:
            attr = "INTENT (IN)";
            attr = "INTENT (IN)";
            break;
            break;
          case DECL_OUT:
          case DECL_OUT:
            attr = "INTENT (OUT)";
            attr = "INTENT (OUT)";
            break;
            break;
          case DECL_INOUT:
          case DECL_INOUT:
            attr = "INTENT (IN OUT)";
            attr = "INTENT (IN OUT)";
            break;
            break;
          case DECL_INTRINSIC:
          case DECL_INTRINSIC:
            attr = "INTRINSIC";
            attr = "INTRINSIC";
            break;
            break;
          case DECL_OPTIONAL:
          case DECL_OPTIONAL:
            attr = "OPTIONAL";
            attr = "OPTIONAL";
            break;
            break;
          case DECL_PARAMETER:
          case DECL_PARAMETER:
            attr = "PARAMETER";
            attr = "PARAMETER";
            break;
            break;
          case DECL_POINTER:
          case DECL_POINTER:
            attr = "POINTER";
            attr = "POINTER";
            break;
            break;
          case DECL_PROTECTED:
          case DECL_PROTECTED:
            attr = "PROTECTED";
            attr = "PROTECTED";
            break;
            break;
          case DECL_PRIVATE:
          case DECL_PRIVATE:
            attr = "PRIVATE";
            attr = "PRIVATE";
            break;
            break;
          case DECL_PUBLIC:
          case DECL_PUBLIC:
            attr = "PUBLIC";
            attr = "PUBLIC";
            break;
            break;
          case DECL_SAVE:
          case DECL_SAVE:
            attr = "SAVE";
            attr = "SAVE";
            break;
            break;
          case DECL_TARGET:
          case DECL_TARGET:
            attr = "TARGET";
            attr = "TARGET";
            break;
            break;
          case DECL_IS_BIND_C:
          case DECL_IS_BIND_C:
            attr = "IS_BIND_C";
            attr = "IS_BIND_C";
            break;
            break;
          case DECL_VALUE:
          case DECL_VALUE:
            attr = "VALUE";
            attr = "VALUE";
            break;
            break;
          case DECL_VOLATILE:
          case DECL_VOLATILE:
            attr = "VOLATILE";
            attr = "VOLATILE";
            break;
            break;
          default:
          default:
            attr = NULL;        /* This shouldn't happen.  */
            attr = NULL;        /* This shouldn't happen.  */
          }
          }
 
 
        gfc_error ("Duplicate %s attribute at %L", attr, &seen_at[d]);
        gfc_error ("Duplicate %s attribute at %L", attr, &seen_at[d]);
        m = MATCH_ERROR;
        m = MATCH_ERROR;
        goto cleanup;
        goto cleanup;
      }
      }
 
 
  /* Now that we've dealt with duplicate attributes, add the attributes
  /* Now that we've dealt with duplicate attributes, add the attributes
     to the current attribute.  */
     to the current attribute.  */
  for (d = GFC_DECL_BEGIN; d != GFC_DECL_END; d++)
  for (d = GFC_DECL_BEGIN; d != GFC_DECL_END; d++)
    {
    {
      if (seen[d] == 0)
      if (seen[d] == 0)
        continue;
        continue;
 
 
      if (gfc_current_state () == COMP_DERIVED
      if (gfc_current_state () == COMP_DERIVED
          && d != DECL_DIMENSION && d != DECL_POINTER
          && d != DECL_DIMENSION && d != DECL_POINTER
          && d != DECL_PRIVATE   && d != DECL_PUBLIC
          && d != DECL_PRIVATE   && d != DECL_PUBLIC
          && d != DECL_NONE)
          && d != DECL_NONE)
        {
        {
          if (d == DECL_ALLOCATABLE)
          if (d == DECL_ALLOCATABLE)
            {
            {
              if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: ALLOCATABLE "
              if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: ALLOCATABLE "
                                  "attribute at %C in a TYPE definition")
                                  "attribute at %C in a TYPE definition")
                  == FAILURE)
                  == FAILURE)
                {
                {
                  m = MATCH_ERROR;
                  m = MATCH_ERROR;
                  goto cleanup;
                  goto cleanup;
                }
                }
            }
            }
          else
          else
            {
            {
              gfc_error ("Attribute at %L is not allowed in a TYPE definition",
              gfc_error ("Attribute at %L is not allowed in a TYPE definition",
                         &seen_at[d]);
                         &seen_at[d]);
              m = MATCH_ERROR;
              m = MATCH_ERROR;
              goto cleanup;
              goto cleanup;
            }
            }
        }
        }
 
 
      if ((d == DECL_PRIVATE || d == DECL_PUBLIC)
      if ((d == DECL_PRIVATE || d == DECL_PUBLIC)
          && gfc_current_state () != COMP_MODULE)
          && gfc_current_state () != COMP_MODULE)
        {
        {
          if (d == DECL_PRIVATE)
          if (d == DECL_PRIVATE)
            attr = "PRIVATE";
            attr = "PRIVATE";
          else
          else
            attr = "PUBLIC";
            attr = "PUBLIC";
          if (gfc_current_state () == COMP_DERIVED
          if (gfc_current_state () == COMP_DERIVED
              && gfc_state_stack->previous
              && gfc_state_stack->previous
              && gfc_state_stack->previous->state == COMP_MODULE)
              && gfc_state_stack->previous->state == COMP_MODULE)
            {
            {
              if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: Attribute %s "
              if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: Attribute %s "
                                  "at %L in a TYPE definition", attr,
                                  "at %L in a TYPE definition", attr,
                                  &seen_at[d])
                                  &seen_at[d])
                  == FAILURE)
                  == FAILURE)
                {
                {
                  m = MATCH_ERROR;
                  m = MATCH_ERROR;
                  goto cleanup;
                  goto cleanup;
                }
                }
            }
            }
          else
          else
            {
            {
              gfc_error ("%s attribute at %L is not allowed outside of the "
              gfc_error ("%s attribute at %L is not allowed outside of the "
                         "specification part of a module", attr, &seen_at[d]);
                         "specification part of a module", attr, &seen_at[d]);
              m = MATCH_ERROR;
              m = MATCH_ERROR;
              goto cleanup;
              goto cleanup;
            }
            }
        }
        }
 
 
      switch (d)
      switch (d)
        {
        {
        case DECL_ALLOCATABLE:
        case DECL_ALLOCATABLE:
          t = gfc_add_allocatable (&current_attr, &seen_at[d]);
          t = gfc_add_allocatable (&current_attr, &seen_at[d]);
          break;
          break;
 
 
        case DECL_ASYNCHRONOUS:
        case DECL_ASYNCHRONOUS:
          if (gfc_notify_std (GFC_STD_F2003,
          if (gfc_notify_std (GFC_STD_F2003,
                              "Fortran 2003: ASYNCHRONOUS attribute at %C")
                              "Fortran 2003: ASYNCHRONOUS attribute at %C")
              == FAILURE)
              == FAILURE)
            t = FAILURE;
            t = FAILURE;
          else
          else
            t = gfc_add_asynchronous (&current_attr, NULL, &seen_at[d]);
            t = gfc_add_asynchronous (&current_attr, NULL, &seen_at[d]);
          break;
          break;
 
 
        case DECL_DIMENSION:
        case DECL_DIMENSION:
          t = gfc_add_dimension (&current_attr, NULL, &seen_at[d]);
          t = gfc_add_dimension (&current_attr, NULL, &seen_at[d]);
          break;
          break;
 
 
        case DECL_EXTERNAL:
        case DECL_EXTERNAL:
          t = gfc_add_external (&current_attr, &seen_at[d]);
          t = gfc_add_external (&current_attr, &seen_at[d]);
          break;
          break;
 
 
        case DECL_IN:
        case DECL_IN:
          t = gfc_add_intent (&current_attr, INTENT_IN, &seen_at[d]);
          t = gfc_add_intent (&current_attr, INTENT_IN, &seen_at[d]);
          break;
          break;
 
 
        case DECL_OUT:
        case DECL_OUT:
          t = gfc_add_intent (&current_attr, INTENT_OUT, &seen_at[d]);
          t = gfc_add_intent (&current_attr, INTENT_OUT, &seen_at[d]);
          break;
          break;
 
 
        case DECL_INOUT:
        case DECL_INOUT:
          t = gfc_add_intent (&current_attr, INTENT_INOUT, &seen_at[d]);
          t = gfc_add_intent (&current_attr, INTENT_INOUT, &seen_at[d]);
          break;
          break;
 
 
        case DECL_INTRINSIC:
        case DECL_INTRINSIC:
          t = gfc_add_intrinsic (&current_attr, &seen_at[d]);
          t = gfc_add_intrinsic (&current_attr, &seen_at[d]);
          break;
          break;
 
 
        case DECL_OPTIONAL:
        case DECL_OPTIONAL:
          t = gfc_add_optional (&current_attr, &seen_at[d]);
          t = gfc_add_optional (&current_attr, &seen_at[d]);
          break;
          break;
 
 
        case DECL_PARAMETER:
        case DECL_PARAMETER:
          t = gfc_add_flavor (&current_attr, FL_PARAMETER, NULL, &seen_at[d]);
          t = gfc_add_flavor (&current_attr, FL_PARAMETER, NULL, &seen_at[d]);
          break;
          break;
 
 
        case DECL_POINTER:
        case DECL_POINTER:
          t = gfc_add_pointer (&current_attr, &seen_at[d]);
          t = gfc_add_pointer (&current_attr, &seen_at[d]);
          break;
          break;
 
 
        case DECL_PROTECTED:
        case DECL_PROTECTED:
          if (gfc_current_ns->proc_name->attr.flavor != FL_MODULE)
          if (gfc_current_ns->proc_name->attr.flavor != FL_MODULE)
            {
            {
               gfc_error ("PROTECTED at %C only allowed in specification "
               gfc_error ("PROTECTED at %C only allowed in specification "
                          "part of a module");
                          "part of a module");
               t = FAILURE;
               t = FAILURE;
               break;
               break;
            }
            }
 
 
          if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: PROTECTED "
          if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: PROTECTED "
                              "attribute at %C")
                              "attribute at %C")
              == FAILURE)
              == FAILURE)
            t = FAILURE;
            t = FAILURE;
          else
          else
            t = gfc_add_protected (&current_attr, NULL, &seen_at[d]);
            t = gfc_add_protected (&current_attr, NULL, &seen_at[d]);
          break;
          break;
 
 
        case DECL_PRIVATE:
        case DECL_PRIVATE:
          t = gfc_add_access (&current_attr, ACCESS_PRIVATE, NULL,
          t = gfc_add_access (&current_attr, ACCESS_PRIVATE, NULL,
                              &seen_at[d]);
                              &seen_at[d]);
          break;
          break;
 
 
        case DECL_PUBLIC:
        case DECL_PUBLIC:
          t = gfc_add_access (&current_attr, ACCESS_PUBLIC, NULL,
          t = gfc_add_access (&current_attr, ACCESS_PUBLIC, NULL,
                              &seen_at[d]);
                              &seen_at[d]);
          break;
          break;
 
 
        case DECL_SAVE:
        case DECL_SAVE:
          t = gfc_add_save (&current_attr, NULL, &seen_at[d]);
          t = gfc_add_save (&current_attr, NULL, &seen_at[d]);
          break;
          break;
 
 
        case DECL_TARGET:
        case DECL_TARGET:
          t = gfc_add_target (&current_attr, &seen_at[d]);
          t = gfc_add_target (&current_attr, &seen_at[d]);
          break;
          break;
 
 
        case DECL_IS_BIND_C:
        case DECL_IS_BIND_C:
           t = gfc_add_is_bind_c(&current_attr, NULL, &seen_at[d], 0);
           t = gfc_add_is_bind_c(&current_attr, NULL, &seen_at[d], 0);
           break;
           break;
 
 
        case DECL_VALUE:
        case DECL_VALUE:
          if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: VALUE attribute "
          if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: VALUE attribute "
                              "at %C")
                              "at %C")
              == FAILURE)
              == FAILURE)
            t = FAILURE;
            t = FAILURE;
          else
          else
            t = gfc_add_value (&current_attr, NULL, &seen_at[d]);
            t = gfc_add_value (&current_attr, NULL, &seen_at[d]);
          break;
          break;
 
 
        case DECL_VOLATILE:
        case DECL_VOLATILE:
          if (gfc_notify_std (GFC_STD_F2003,
          if (gfc_notify_std (GFC_STD_F2003,
                              "Fortran 2003: VOLATILE attribute at %C")
                              "Fortran 2003: VOLATILE attribute at %C")
              == FAILURE)
              == FAILURE)
            t = FAILURE;
            t = FAILURE;
          else
          else
            t = gfc_add_volatile (&current_attr, NULL, &seen_at[d]);
            t = gfc_add_volatile (&current_attr, NULL, &seen_at[d]);
          break;
          break;
 
 
        default:
        default:
          gfc_internal_error ("match_attr_spec(): Bad attribute");
          gfc_internal_error ("match_attr_spec(): Bad attribute");
        }
        }
 
 
      if (t == FAILURE)
      if (t == FAILURE)
        {
        {
          m = MATCH_ERROR;
          m = MATCH_ERROR;
          goto cleanup;
          goto cleanup;
        }
        }
    }
    }
 
 
  colon_seen = 1;
  colon_seen = 1;
  return MATCH_YES;
  return MATCH_YES;
 
 
cleanup:
cleanup:
  gfc_current_locus = start;
  gfc_current_locus = start;
  gfc_free_array_spec (current_as);
  gfc_free_array_spec (current_as);
  current_as = NULL;
  current_as = NULL;
  return m;
  return m;
}
}
 
 
 
 
/* Set the binding label, dest_label, either with the binding label
/* Set the binding label, dest_label, either with the binding label
   stored in the given gfc_typespec, ts, or if none was provided, it
   stored in the given gfc_typespec, ts, or if none was provided, it
   will be the symbol name in all lower case, as required by the draft
   will be the symbol name in all lower case, as required by the draft
   (J3/04-007, section 15.4.1).  If a binding label was given and
   (J3/04-007, section 15.4.1).  If a binding label was given and
   there is more than one argument (num_idents), it is an error.  */
   there is more than one argument (num_idents), it is an error.  */
 
 
gfc_try
gfc_try
set_binding_label (char *dest_label, const char *sym_name, int num_idents)
set_binding_label (char *dest_label, const char *sym_name, int num_idents)
{
{
  if (num_idents > 1 && has_name_equals)
  if (num_idents > 1 && has_name_equals)
    {
    {
      gfc_error ("Multiple identifiers provided with "
      gfc_error ("Multiple identifiers provided with "
                 "single NAME= specifier at %C");
                 "single NAME= specifier at %C");
      return FAILURE;
      return FAILURE;
    }
    }
 
 
  if (curr_binding_label[0] != '\0')
  if (curr_binding_label[0] != '\0')
    {
    {
      /* Binding label given; store in temp holder til have sym.  */
      /* Binding label given; store in temp holder til have sym.  */
      strcpy (dest_label, curr_binding_label);
      strcpy (dest_label, curr_binding_label);
    }
    }
  else
  else
    {
    {
      /* No binding label given, and the NAME= specifier did not exist,
      /* No binding label given, and the NAME= specifier did not exist,
         which means there was no NAME="".  */
         which means there was no NAME="".  */
      if (sym_name != NULL && has_name_equals == 0)
      if (sym_name != NULL && has_name_equals == 0)
        strcpy (dest_label, sym_name);
        strcpy (dest_label, sym_name);
    }
    }
 
 
  return SUCCESS;
  return SUCCESS;
}
}
 
 
 
 
/* Set the status of the given common block as being BIND(C) or not,
/* Set the status of the given common block as being BIND(C) or not,
   depending on the given parameter, is_bind_c.  */
   depending on the given parameter, is_bind_c.  */
 
 
void
void
set_com_block_bind_c (gfc_common_head *com_block, int is_bind_c)
set_com_block_bind_c (gfc_common_head *com_block, int is_bind_c)
{
{
  com_block->is_bind_c = is_bind_c;
  com_block->is_bind_c = is_bind_c;
  return;
  return;
}
}
 
 
 
 
/* Verify that the given gfc_typespec is for a C interoperable type.  */
/* Verify that the given gfc_typespec is for a C interoperable type.  */
 
 
gfc_try
gfc_try
verify_c_interop (gfc_typespec *ts)
verify_c_interop (gfc_typespec *ts)
{
{
  if (ts->type == BT_DERIVED && ts->u.derived != NULL)
  if (ts->type == BT_DERIVED && ts->u.derived != NULL)
    return (ts->u.derived->ts.is_c_interop ? SUCCESS : FAILURE);
    return (ts->u.derived->ts.is_c_interop ? SUCCESS : FAILURE);
  else if (ts->is_c_interop != 1)
  else if (ts->is_c_interop != 1)
    return FAILURE;
    return FAILURE;
 
 
  return SUCCESS;
  return SUCCESS;
}
}
 
 
 
 
/* Verify that the variables of a given common block, which has been
/* Verify that the variables of a given common block, which has been
   defined with the attribute specifier bind(c), to be of a C
   defined with the attribute specifier bind(c), to be of a C
   interoperable type.  Errors will be reported here, if
   interoperable type.  Errors will be reported here, if
   encountered.  */
   encountered.  */
 
 
gfc_try
gfc_try
verify_com_block_vars_c_interop (gfc_common_head *com_block)
verify_com_block_vars_c_interop (gfc_common_head *com_block)
{
{
  gfc_symbol *curr_sym = NULL;
  gfc_symbol *curr_sym = NULL;
  gfc_try retval = SUCCESS;
  gfc_try retval = SUCCESS;
 
 
  curr_sym = com_block->head;
  curr_sym = com_block->head;
 
 
  /* Make sure we have at least one symbol.  */
  /* Make sure we have at least one symbol.  */
  if (curr_sym == NULL)
  if (curr_sym == NULL)
    return retval;
    return retval;
 
 
  /* Here we know we have a symbol, so we'll execute this loop
  /* Here we know we have a symbol, so we'll execute this loop
     at least once.  */
     at least once.  */
  do
  do
    {
    {
      /* The second to last param, 1, says this is in a common block.  */
      /* The second to last param, 1, says this is in a common block.  */
      retval = verify_bind_c_sym (curr_sym, &(curr_sym->ts), 1, com_block);
      retval = verify_bind_c_sym (curr_sym, &(curr_sym->ts), 1, com_block);
      curr_sym = curr_sym->common_next;
      curr_sym = curr_sym->common_next;
    } while (curr_sym != NULL);
    } while (curr_sym != NULL);
 
 
  return retval;
  return retval;
}
}
 
 
 
 
/* Verify that a given BIND(C) symbol is C interoperable.  If it is not,
/* Verify that a given BIND(C) symbol is C interoperable.  If it is not,
   an appropriate error message is reported.  */
   an appropriate error message is reported.  */
 
 
gfc_try
gfc_try
verify_bind_c_sym (gfc_symbol *tmp_sym, gfc_typespec *ts,
verify_bind_c_sym (gfc_symbol *tmp_sym, gfc_typespec *ts,
                   int is_in_common, gfc_common_head *com_block)
                   int is_in_common, gfc_common_head *com_block)
{
{
  bool bind_c_function = false;
  bool bind_c_function = false;
  gfc_try retval = SUCCESS;
  gfc_try retval = SUCCESS;
 
 
  if (tmp_sym->attr.function && tmp_sym->attr.is_bind_c)
  if (tmp_sym->attr.function && tmp_sym->attr.is_bind_c)
    bind_c_function = true;
    bind_c_function = true;
 
 
  if (tmp_sym->attr.function && tmp_sym->result != NULL)
  if (tmp_sym->attr.function && tmp_sym->result != NULL)
    {
    {
      tmp_sym = tmp_sym->result;
      tmp_sym = tmp_sym->result;
      /* Make sure it wasn't an implicitly typed result.  */
      /* Make sure it wasn't an implicitly typed result.  */
      if (tmp_sym->attr.implicit_type)
      if (tmp_sym->attr.implicit_type)
        {
        {
          gfc_warning ("Implicitly declared BIND(C) function '%s' at "
          gfc_warning ("Implicitly declared BIND(C) function '%s' at "
                       "%L may not be C interoperable", tmp_sym->name,
                       "%L may not be C interoperable", tmp_sym->name,
                       &tmp_sym->declared_at);
                       &tmp_sym->declared_at);
          tmp_sym->ts.f90_type = tmp_sym->ts.type;
          tmp_sym->ts.f90_type = tmp_sym->ts.type;
          /* Mark it as C interoperable to prevent duplicate warnings.  */
          /* Mark it as C interoperable to prevent duplicate warnings.  */
          tmp_sym->ts.is_c_interop = 1;
          tmp_sym->ts.is_c_interop = 1;
          tmp_sym->attr.is_c_interop = 1;
          tmp_sym->attr.is_c_interop = 1;
        }
        }
    }
    }
 
 
  /* Here, we know we have the bind(c) attribute, so if we have
  /* Here, we know we have the bind(c) attribute, so if we have
     enough type info, then verify that it's a C interop kind.
     enough type info, then verify that it's a C interop kind.
     The info could be in the symbol already, or possibly still in
     The info could be in the symbol already, or possibly still in
     the given ts (current_ts), so look in both.  */
     the given ts (current_ts), so look in both.  */
  if (tmp_sym->ts.type != BT_UNKNOWN || ts->type != BT_UNKNOWN)
  if (tmp_sym->ts.type != BT_UNKNOWN || ts->type != BT_UNKNOWN)
    {
    {
      if (verify_c_interop (&(tmp_sym->ts)) != SUCCESS)
      if (verify_c_interop (&(tmp_sym->ts)) != SUCCESS)
        {
        {
          /* See if we're dealing with a sym in a common block or not.  */
          /* See if we're dealing with a sym in a common block or not.  */
          if (is_in_common == 1)
          if (is_in_common == 1)
            {
            {
              gfc_warning ("Variable '%s' in common block '%s' at %L "
              gfc_warning ("Variable '%s' in common block '%s' at %L "
                           "may not be a C interoperable "
                           "may not be a C interoperable "
                           "kind though common block '%s' is BIND(C)",
                           "kind though common block '%s' is BIND(C)",
                           tmp_sym->name, com_block->name,
                           tmp_sym->name, com_block->name,
                           &(tmp_sym->declared_at), com_block->name);
                           &(tmp_sym->declared_at), com_block->name);
            }
            }
          else
          else
            {
            {
              if (tmp_sym->ts.type == BT_DERIVED || ts->type == BT_DERIVED)
              if (tmp_sym->ts.type == BT_DERIVED || ts->type == BT_DERIVED)
                gfc_error ("Type declaration '%s' at %L is not C "
                gfc_error ("Type declaration '%s' at %L is not C "
                           "interoperable but it is BIND(C)",
                           "interoperable but it is BIND(C)",
                           tmp_sym->name, &(tmp_sym->declared_at));
                           tmp_sym->name, &(tmp_sym->declared_at));
              else
              else
                gfc_warning ("Variable '%s' at %L "
                gfc_warning ("Variable '%s' at %L "
                             "may not be a C interoperable "
                             "may not be a C interoperable "
                             "kind but it is bind(c)",
                             "kind but it is bind(c)",
                             tmp_sym->name, &(tmp_sym->declared_at));
                             tmp_sym->name, &(tmp_sym->declared_at));
            }
            }
        }
        }
 
 
      /* Variables declared w/in a common block can't be bind(c)
      /* Variables declared w/in a common block can't be bind(c)
         since there's no way for C to see these variables, so there's
         since there's no way for C to see these variables, so there's
         semantically no reason for the attribute.  */
         semantically no reason for the attribute.  */
      if (is_in_common == 1 && tmp_sym->attr.is_bind_c == 1)
      if (is_in_common == 1 && tmp_sym->attr.is_bind_c == 1)
        {
        {
          gfc_error ("Variable '%s' in common block '%s' at "
          gfc_error ("Variable '%s' in common block '%s' at "
                     "%L cannot be declared with BIND(C) "
                     "%L cannot be declared with BIND(C) "
                     "since it is not a global",
                     "since it is not a global",
                     tmp_sym->name, com_block->name,
                     tmp_sym->name, com_block->name,
                     &(tmp_sym->declared_at));
                     &(tmp_sym->declared_at));
          retval = FAILURE;
          retval = FAILURE;
        }
        }
 
 
      /* Scalar variables that are bind(c) can not have the pointer
      /* Scalar variables that are bind(c) can not have the pointer
         or allocatable attributes.  */
         or allocatable attributes.  */
      if (tmp_sym->attr.is_bind_c == 1)
      if (tmp_sym->attr.is_bind_c == 1)
        {
        {
          if (tmp_sym->attr.pointer == 1)
          if (tmp_sym->attr.pointer == 1)
            {
            {
              gfc_error ("Variable '%s' at %L cannot have both the "
              gfc_error ("Variable '%s' at %L cannot have both the "
                         "POINTER and BIND(C) attributes",
                         "POINTER and BIND(C) attributes",
                         tmp_sym->name, &(tmp_sym->declared_at));
                         tmp_sym->name, &(tmp_sym->declared_at));
              retval = FAILURE;
              retval = FAILURE;
            }
            }
 
 
          if (tmp_sym->attr.allocatable == 1)
          if (tmp_sym->attr.allocatable == 1)
            {
            {
              gfc_error ("Variable '%s' at %L cannot have both the "
              gfc_error ("Variable '%s' at %L cannot have both the "
                         "ALLOCATABLE and BIND(C) attributes",
                         "ALLOCATABLE and BIND(C) attributes",
                         tmp_sym->name, &(tmp_sym->declared_at));
                         tmp_sym->name, &(tmp_sym->declared_at));
              retval = FAILURE;
              retval = FAILURE;
            }
            }
 
 
        }
        }
 
 
      /* If it is a BIND(C) function, make sure the return value is a
      /* If it is a BIND(C) function, make sure the return value is a
         scalar value.  The previous tests in this function made sure
         scalar value.  The previous tests in this function made sure
         the type is interoperable.  */
         the type is interoperable.  */
      if (bind_c_function && tmp_sym->as != NULL)
      if (bind_c_function && tmp_sym->as != NULL)
        gfc_error ("Return type of BIND(C) function '%s' at %L cannot "
        gfc_error ("Return type of BIND(C) function '%s' at %L cannot "
                   "be an array", tmp_sym->name, &(tmp_sym->declared_at));
                   "be an array", tmp_sym->name, &(tmp_sym->declared_at));
 
 
      /* BIND(C) functions can not return a character string.  */
      /* BIND(C) functions can not return a character string.  */
      if (bind_c_function && tmp_sym->ts.type == BT_CHARACTER)
      if (bind_c_function && tmp_sym->ts.type == BT_CHARACTER)
        if (tmp_sym->ts.u.cl == NULL || tmp_sym->ts.u.cl->length == NULL
        if (tmp_sym->ts.u.cl == NULL || tmp_sym->ts.u.cl->length == NULL
            || tmp_sym->ts.u.cl->length->expr_type != EXPR_CONSTANT
            || tmp_sym->ts.u.cl->length->expr_type != EXPR_CONSTANT
            || mpz_cmp_si (tmp_sym->ts.u.cl->length->value.integer, 1) != 0)
            || mpz_cmp_si (tmp_sym->ts.u.cl->length->value.integer, 1) != 0)
          gfc_error ("Return type of BIND(C) function '%s' at %L cannot "
          gfc_error ("Return type of BIND(C) function '%s' at %L cannot "
                         "be a character string", tmp_sym->name,
                         "be a character string", tmp_sym->name,
                         &(tmp_sym->declared_at));
                         &(tmp_sym->declared_at));
    }
    }
 
 
  /* See if the symbol has been marked as private.  If it has, make sure
  /* See if the symbol has been marked as private.  If it has, make sure
     there is no binding label and warn the user if there is one.  */
     there is no binding label and warn the user if there is one.  */
  if (tmp_sym->attr.access == ACCESS_PRIVATE
  if (tmp_sym->attr.access == ACCESS_PRIVATE
      && tmp_sym->binding_label[0] != '\0')
      && tmp_sym->binding_label[0] != '\0')
      /* Use gfc_warning_now because we won't say that the symbol fails
      /* Use gfc_warning_now because we won't say that the symbol fails
         just because of this.  */
         just because of this.  */
      gfc_warning_now ("Symbol '%s' at %L is marked PRIVATE but has been "
      gfc_warning_now ("Symbol '%s' at %L is marked PRIVATE but has been "
                       "given the binding label '%s'", tmp_sym->name,
                       "given the binding label '%s'", tmp_sym->name,
                       &(tmp_sym->declared_at), tmp_sym->binding_label);
                       &(tmp_sym->declared_at), tmp_sym->binding_label);
 
 
  return retval;
  return retval;
}
}
 
 
 
 
/* Set the appropriate fields for a symbol that's been declared as
/* Set the appropriate fields for a symbol that's been declared as
   BIND(C) (the is_bind_c flag and the binding label), and verify that
   BIND(C) (the is_bind_c flag and the binding label), and verify that
   the type is C interoperable.  Errors are reported by the functions
   the type is C interoperable.  Errors are reported by the functions
   used to set/test these fields.  */
   used to set/test these fields.  */
 
 
gfc_try
gfc_try
set_verify_bind_c_sym (gfc_symbol *tmp_sym, int num_idents)
set_verify_bind_c_sym (gfc_symbol *tmp_sym, int num_idents)
{
{
  gfc_try retval = SUCCESS;
  gfc_try retval = SUCCESS;
 
 
  /* TODO: Do we need to make sure the vars aren't marked private?  */
  /* TODO: Do we need to make sure the vars aren't marked private?  */
 
 
  /* Set the is_bind_c bit in symbol_attribute.  */
  /* Set the is_bind_c bit in symbol_attribute.  */
  gfc_add_is_bind_c (&(tmp_sym->attr), tmp_sym->name, &gfc_current_locus, 0);
  gfc_add_is_bind_c (&(tmp_sym->attr), tmp_sym->name, &gfc_current_locus, 0);
 
 
  if (set_binding_label (tmp_sym->binding_label, tmp_sym->name,
  if (set_binding_label (tmp_sym->binding_label, tmp_sym->name,
                         num_idents) != SUCCESS)
                         num_idents) != SUCCESS)
    return FAILURE;
    return FAILURE;
 
 
  return retval;
  return retval;
}
}
 
 
 
 
/* Set the fields marking the given common block as BIND(C), including
/* Set the fields marking the given common block as BIND(C), including
   a binding label, and report any errors encountered.  */
   a binding label, and report any errors encountered.  */
 
 
gfc_try
gfc_try
set_verify_bind_c_com_block (gfc_common_head *com_block, int num_idents)
set_verify_bind_c_com_block (gfc_common_head *com_block, int num_idents)
{
{
  gfc_try retval = SUCCESS;
  gfc_try retval = SUCCESS;
 
 
  /* destLabel, common name, typespec (which may have binding label).  */
  /* destLabel, common name, typespec (which may have binding label).  */
  if (set_binding_label (com_block->binding_label, com_block->name, num_idents)
  if (set_binding_label (com_block->binding_label, com_block->name, num_idents)
      != SUCCESS)
      != SUCCESS)
    return FAILURE;
    return FAILURE;
 
 
  /* Set the given common block (com_block) to being bind(c) (1).  */
  /* Set the given common block (com_block) to being bind(c) (1).  */
  set_com_block_bind_c (com_block, 1);
  set_com_block_bind_c (com_block, 1);
 
 
  return retval;
  return retval;
}
}
 
 
 
 
/* Retrieve the list of one or more identifiers that the given bind(c)
/* Retrieve the list of one or more identifiers that the given bind(c)
   attribute applies to.  */
   attribute applies to.  */
 
 
gfc_try
gfc_try
get_bind_c_idents (void)
get_bind_c_idents (void)
{
{
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
  int num_idents = 0;
  int num_idents = 0;
  gfc_symbol *tmp_sym = NULL;
  gfc_symbol *tmp_sym = NULL;
  match found_id;
  match found_id;
  gfc_common_head *com_block = NULL;
  gfc_common_head *com_block = NULL;
 
 
  if (gfc_match_name (name) == MATCH_YES)
  if (gfc_match_name (name) == MATCH_YES)
    {
    {
      found_id = MATCH_YES;
      found_id = MATCH_YES;
      gfc_get_ha_symbol (name, &tmp_sym);
      gfc_get_ha_symbol (name, &tmp_sym);
    }
    }
  else if (match_common_name (name) == MATCH_YES)
  else if (match_common_name (name) == MATCH_YES)
    {
    {
      found_id = MATCH_YES;
      found_id = MATCH_YES;
      com_block = gfc_get_common (name, 0);
      com_block = gfc_get_common (name, 0);
    }
    }
  else
  else
    {
    {
      gfc_error ("Need either entity or common block name for "
      gfc_error ("Need either entity or common block name for "
                 "attribute specification statement at %C");
                 "attribute specification statement at %C");
      return FAILURE;
      return FAILURE;
    }
    }
 
 
  /* Save the current identifier and look for more.  */
  /* Save the current identifier and look for more.  */
  do
  do
    {
    {
      /* Increment the number of identifiers found for this spec stmt.  */
      /* Increment the number of identifiers found for this spec stmt.  */
      num_idents++;
      num_idents++;
 
 
      /* Make sure we have a sym or com block, and verify that it can
      /* Make sure we have a sym or com block, and verify that it can
         be bind(c).  Set the appropriate field(s) and look for more
         be bind(c).  Set the appropriate field(s) and look for more
         identifiers.  */
         identifiers.  */
      if (tmp_sym != NULL || com_block != NULL)
      if (tmp_sym != NULL || com_block != NULL)
        {
        {
          if (tmp_sym != NULL)
          if (tmp_sym != NULL)
            {
            {
              if (set_verify_bind_c_sym (tmp_sym, num_idents)
              if (set_verify_bind_c_sym (tmp_sym, num_idents)
                  != SUCCESS)
                  != SUCCESS)
                return FAILURE;
                return FAILURE;
            }
            }
          else
          else
            {
            {
              if (set_verify_bind_c_com_block(com_block, num_idents)
              if (set_verify_bind_c_com_block(com_block, num_idents)
                  != SUCCESS)
                  != SUCCESS)
                return FAILURE;
                return FAILURE;
            }
            }
 
 
          /* Look to see if we have another identifier.  */
          /* Look to see if we have another identifier.  */
          tmp_sym = NULL;
          tmp_sym = NULL;
          if (gfc_match_eos () == MATCH_YES)
          if (gfc_match_eos () == MATCH_YES)
            found_id = MATCH_NO;
            found_id = MATCH_NO;
          else if (gfc_match_char (',') != MATCH_YES)
          else if (gfc_match_char (',') != MATCH_YES)
            found_id = MATCH_NO;
            found_id = MATCH_NO;
          else if (gfc_match_name (name) == MATCH_YES)
          else if (gfc_match_name (name) == MATCH_YES)
            {
            {
              found_id = MATCH_YES;
              found_id = MATCH_YES;
              gfc_get_ha_symbol (name, &tmp_sym);
              gfc_get_ha_symbol (name, &tmp_sym);
            }
            }
          else if (match_common_name (name) == MATCH_YES)
          else if (match_common_name (name) == MATCH_YES)
            {
            {
              found_id = MATCH_YES;
              found_id = MATCH_YES;
              com_block = gfc_get_common (name, 0);
              com_block = gfc_get_common (name, 0);
            }
            }
          else
          else
            {
            {
              gfc_error ("Missing entity or common block name for "
              gfc_error ("Missing entity or common block name for "
                         "attribute specification statement at %C");
                         "attribute specification statement at %C");
              return FAILURE;
              return FAILURE;
            }
            }
        }
        }
      else
      else
        {
        {
          gfc_internal_error ("Missing symbol");
          gfc_internal_error ("Missing symbol");
        }
        }
    } while (found_id == MATCH_YES);
    } while (found_id == MATCH_YES);
 
 
  /* if we get here we were successful */
  /* if we get here we were successful */
  return SUCCESS;
  return SUCCESS;
}
}
 
 
 
 
/* Try and match a BIND(C) attribute specification statement.  */
/* Try and match a BIND(C) attribute specification statement.  */
 
 
match
match
gfc_match_bind_c_stmt (void)
gfc_match_bind_c_stmt (void)
{
{
  match found_match = MATCH_NO;
  match found_match = MATCH_NO;
  gfc_typespec *ts;
  gfc_typespec *ts;
 
 
  ts = &current_ts;
  ts = &current_ts;
 
 
  /* This may not be necessary.  */
  /* This may not be necessary.  */
  gfc_clear_ts (ts);
  gfc_clear_ts (ts);
  /* Clear the temporary binding label holder.  */
  /* Clear the temporary binding label holder.  */
  curr_binding_label[0] = '\0';
  curr_binding_label[0] = '\0';
 
 
  /* Look for the bind(c).  */
  /* Look for the bind(c).  */
  found_match = gfc_match_bind_c (NULL, true);
  found_match = gfc_match_bind_c (NULL, true);
 
 
  if (found_match == MATCH_YES)
  if (found_match == MATCH_YES)
    {
    {
      /* Look for the :: now, but it is not required.  */
      /* Look for the :: now, but it is not required.  */
      gfc_match (" :: ");
      gfc_match (" :: ");
 
 
      /* Get the identifier(s) that needs to be updated.  This may need to
      /* Get the identifier(s) that needs to be updated.  This may need to
         change to hand the flag(s) for the attr specified so all identifiers
         change to hand the flag(s) for the attr specified so all identifiers
         found can have all appropriate parts updated (assuming that the same
         found can have all appropriate parts updated (assuming that the same
         spec stmt can have multiple attrs, such as both bind(c) and
         spec stmt can have multiple attrs, such as both bind(c) and
         allocatable...).  */
         allocatable...).  */
      if (get_bind_c_idents () != SUCCESS)
      if (get_bind_c_idents () != SUCCESS)
        /* Error message should have printed already.  */
        /* Error message should have printed already.  */
        return MATCH_ERROR;
        return MATCH_ERROR;
    }
    }
 
 
  return found_match;
  return found_match;
}
}
 
 
 
 
/* Match a data declaration statement.  */
/* Match a data declaration statement.  */
 
 
match
match
gfc_match_data_decl (void)
gfc_match_data_decl (void)
{
{
  gfc_symbol *sym;
  gfc_symbol *sym;
  match m;
  match m;
  int elem;
  int elem;
 
 
  num_idents_on_line = 0;
  num_idents_on_line = 0;
 
 
  m = gfc_match_decl_type_spec (&current_ts, 0);
  m = gfc_match_decl_type_spec (&current_ts, 0);
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    return m;
    return m;
 
 
  if ((current_ts.type == BT_DERIVED || current_ts.type == BT_CLASS)
  if ((current_ts.type == BT_DERIVED || current_ts.type == BT_CLASS)
        && gfc_current_state () != COMP_DERIVED)
        && gfc_current_state () != COMP_DERIVED)
    {
    {
      sym = gfc_use_derived (current_ts.u.derived);
      sym = gfc_use_derived (current_ts.u.derived);
 
 
      if (sym == NULL)
      if (sym == NULL)
        {
        {
          m = MATCH_ERROR;
          m = MATCH_ERROR;
          goto cleanup;
          goto cleanup;
        }
        }
 
 
      current_ts.u.derived = sym;
      current_ts.u.derived = sym;
    }
    }
 
 
  m = match_attr_spec ();
  m = match_attr_spec ();
  if (m == MATCH_ERROR)
  if (m == MATCH_ERROR)
    {
    {
      m = MATCH_NO;
      m = MATCH_NO;
      goto cleanup;
      goto cleanup;
    }
    }
 
 
  if ((current_ts.type == BT_DERIVED || current_ts.type == BT_CLASS)
  if ((current_ts.type == BT_DERIVED || current_ts.type == BT_CLASS)
      && current_ts.u.derived->components == NULL
      && current_ts.u.derived->components == NULL
      && !current_ts.u.derived->attr.zero_comp)
      && !current_ts.u.derived->attr.zero_comp)
    {
    {
 
 
      if (current_attr.pointer && gfc_current_state () == COMP_DERIVED)
      if (current_attr.pointer && gfc_current_state () == COMP_DERIVED)
        goto ok;
        goto ok;
 
 
      gfc_find_symbol (current_ts.u.derived->name,
      gfc_find_symbol (current_ts.u.derived->name,
                       current_ts.u.derived->ns->parent, 1, &sym);
                       current_ts.u.derived->ns->parent, 1, &sym);
 
 
      /* Any symbol that we find had better be a type definition
      /* Any symbol that we find had better be a type definition
         which has its components defined.  */
         which has its components defined.  */
      if (sym != NULL && sym->attr.flavor == FL_DERIVED
      if (sym != NULL && sym->attr.flavor == FL_DERIVED
          && (current_ts.u.derived->components != NULL
          && (current_ts.u.derived->components != NULL
              || current_ts.u.derived->attr.zero_comp))
              || current_ts.u.derived->attr.zero_comp))
        goto ok;
        goto ok;
 
 
      /* Now we have an error, which we signal, and then fix up
      /* Now we have an error, which we signal, and then fix up
         because the knock-on is plain and simple confusing.  */
         because the knock-on is plain and simple confusing.  */
      gfc_error_now ("Derived type at %C has not been previously defined "
      gfc_error_now ("Derived type at %C has not been previously defined "
                     "and so cannot appear in a derived type definition");
                     "and so cannot appear in a derived type definition");
      current_attr.pointer = 1;
      current_attr.pointer = 1;
      goto ok;
      goto ok;
    }
    }
 
 
ok:
ok:
  /* If we have an old-style character declaration, and no new-style
  /* If we have an old-style character declaration, and no new-style
     attribute specifications, then there a comma is optional between
     attribute specifications, then there a comma is optional between
     the type specification and the variable list.  */
     the type specification and the variable list.  */
  if (m == MATCH_NO && current_ts.type == BT_CHARACTER && old_char_selector)
  if (m == MATCH_NO && current_ts.type == BT_CHARACTER && old_char_selector)
    gfc_match_char (',');
    gfc_match_char (',');
 
 
  /* Give the types/attributes to symbols that follow. Give the element
  /* Give the types/attributes to symbols that follow. Give the element
     a number so that repeat character length expressions can be copied.  */
     a number so that repeat character length expressions can be copied.  */
  elem = 1;
  elem = 1;
  for (;;)
  for (;;)
    {
    {
      num_idents_on_line++;
      num_idents_on_line++;
      m = variable_decl (elem++);
      m = variable_decl (elem++);
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        goto cleanup;
        goto cleanup;
      if (m == MATCH_NO)
      if (m == MATCH_NO)
        break;
        break;
 
 
      if (gfc_match_eos () == MATCH_YES)
      if (gfc_match_eos () == MATCH_YES)
        goto cleanup;
        goto cleanup;
      if (gfc_match_char (',') != MATCH_YES)
      if (gfc_match_char (',') != MATCH_YES)
        break;
        break;
    }
    }
 
 
  if (gfc_error_flag_test () == 0)
  if (gfc_error_flag_test () == 0)
    gfc_error ("Syntax error in data declaration at %C");
    gfc_error ("Syntax error in data declaration at %C");
  m = MATCH_ERROR;
  m = MATCH_ERROR;
 
 
  gfc_free_data_all (gfc_current_ns);
  gfc_free_data_all (gfc_current_ns);
 
 
cleanup:
cleanup:
  gfc_free_array_spec (current_as);
  gfc_free_array_spec (current_as);
  current_as = NULL;
  current_as = NULL;
  return m;
  return m;
}
}
 
 
 
 
/* Match a prefix associated with a function or subroutine
/* Match a prefix associated with a function or subroutine
   declaration.  If the typespec pointer is nonnull, then a typespec
   declaration.  If the typespec pointer is nonnull, then a typespec
   can be matched.  Note that if nothing matches, MATCH_YES is
   can be matched.  Note that if nothing matches, MATCH_YES is
   returned (the null string was matched).  */
   returned (the null string was matched).  */
 
 
match
match
gfc_match_prefix (gfc_typespec *ts)
gfc_match_prefix (gfc_typespec *ts)
{
{
  bool seen_type;
  bool seen_type;
 
 
  gfc_clear_attr (&current_attr);
  gfc_clear_attr (&current_attr);
  seen_type = 0;
  seen_type = 0;
 
 
  gcc_assert (!gfc_matching_prefix);
  gcc_assert (!gfc_matching_prefix);
  gfc_matching_prefix = true;
  gfc_matching_prefix = true;
 
 
loop:
loop:
  if (!seen_type && ts != NULL
  if (!seen_type && ts != NULL
      && gfc_match_decl_type_spec (ts, 0) == MATCH_YES
      && gfc_match_decl_type_spec (ts, 0) == MATCH_YES
      && gfc_match_space () == MATCH_YES)
      && gfc_match_space () == MATCH_YES)
    {
    {
 
 
      seen_type = 1;
      seen_type = 1;
      goto loop;
      goto loop;
    }
    }
 
 
  if (gfc_match ("elemental% ") == MATCH_YES)
  if (gfc_match ("elemental% ") == MATCH_YES)
    {
    {
      if (gfc_add_elemental (&current_attr, NULL) == FAILURE)
      if (gfc_add_elemental (&current_attr, NULL) == FAILURE)
        goto error;
        goto error;
 
 
      goto loop;
      goto loop;
    }
    }
 
 
  if (gfc_match ("pure% ") == MATCH_YES)
  if (gfc_match ("pure% ") == MATCH_YES)
    {
    {
      if (gfc_add_pure (&current_attr, NULL) == FAILURE)
      if (gfc_add_pure (&current_attr, NULL) == FAILURE)
        goto error;
        goto error;
 
 
      goto loop;
      goto loop;
    }
    }
 
 
  if (gfc_match ("recursive% ") == MATCH_YES)
  if (gfc_match ("recursive% ") == MATCH_YES)
    {
    {
      if (gfc_add_recursive (&current_attr, NULL) == FAILURE)
      if (gfc_add_recursive (&current_attr, NULL) == FAILURE)
        goto error;
        goto error;
 
 
      goto loop;
      goto loop;
    }
    }
 
 
  /* At this point, the next item is not a prefix.  */
  /* At this point, the next item is not a prefix.  */
  gcc_assert (gfc_matching_prefix);
  gcc_assert (gfc_matching_prefix);
  gfc_matching_prefix = false;
  gfc_matching_prefix = false;
  return MATCH_YES;
  return MATCH_YES;
 
 
error:
error:
  gcc_assert (gfc_matching_prefix);
  gcc_assert (gfc_matching_prefix);
  gfc_matching_prefix = false;
  gfc_matching_prefix = false;
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
/* Copy attributes matched by gfc_match_prefix() to attributes on a symbol.  */
/* Copy attributes matched by gfc_match_prefix() to attributes on a symbol.  */
 
 
static gfc_try
static gfc_try
copy_prefix (symbol_attribute *dest, locus *where)
copy_prefix (symbol_attribute *dest, locus *where)
{
{
  if (current_attr.pure && gfc_add_pure (dest, where) == FAILURE)
  if (current_attr.pure && gfc_add_pure (dest, where) == FAILURE)
    return FAILURE;
    return FAILURE;
 
 
  if (current_attr.elemental && gfc_add_elemental (dest, where) == FAILURE)
  if (current_attr.elemental && gfc_add_elemental (dest, where) == FAILURE)
    return FAILURE;
    return FAILURE;
 
 
  if (current_attr.recursive && gfc_add_recursive (dest, where) == FAILURE)
  if (current_attr.recursive && gfc_add_recursive (dest, where) == FAILURE)
    return FAILURE;
    return FAILURE;
 
 
  return SUCCESS;
  return SUCCESS;
}
}
 
 
 
 
/* Match a formal argument list.  */
/* Match a formal argument list.  */
 
 
match
match
gfc_match_formal_arglist (gfc_symbol *progname, int st_flag, int null_flag)
gfc_match_formal_arglist (gfc_symbol *progname, int st_flag, int null_flag)
{
{
  gfc_formal_arglist *head, *tail, *p, *q;
  gfc_formal_arglist *head, *tail, *p, *q;
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
  gfc_symbol *sym;
  gfc_symbol *sym;
  match m;
  match m;
 
 
  head = tail = NULL;
  head = tail = NULL;
 
 
  if (gfc_match_char ('(') != MATCH_YES)
  if (gfc_match_char ('(') != MATCH_YES)
    {
    {
      if (null_flag)
      if (null_flag)
        goto ok;
        goto ok;
      return MATCH_NO;
      return MATCH_NO;
    }
    }
 
 
  if (gfc_match_char (')') == MATCH_YES)
  if (gfc_match_char (')') == MATCH_YES)
    goto ok;
    goto ok;
 
 
  for (;;)
  for (;;)
    {
    {
      if (gfc_match_char ('*') == MATCH_YES)
      if (gfc_match_char ('*') == MATCH_YES)
        sym = NULL;
        sym = NULL;
      else
      else
        {
        {
          m = gfc_match_name (name);
          m = gfc_match_name (name);
          if (m != MATCH_YES)
          if (m != MATCH_YES)
            goto cleanup;
            goto cleanup;
 
 
          if (gfc_get_symbol (name, NULL, &sym))
          if (gfc_get_symbol (name, NULL, &sym))
            goto cleanup;
            goto cleanup;
        }
        }
 
 
      p = gfc_get_formal_arglist ();
      p = gfc_get_formal_arglist ();
 
 
      if (head == NULL)
      if (head == NULL)
        head = tail = p;
        head = tail = p;
      else
      else
        {
        {
          tail->next = p;
          tail->next = p;
          tail = p;
          tail = p;
        }
        }
 
 
      tail->sym = sym;
      tail->sym = sym;
 
 
      /* We don't add the VARIABLE flavor because the name could be a
      /* We don't add the VARIABLE flavor because the name could be a
         dummy procedure.  We don't apply these attributes to formal
         dummy procedure.  We don't apply these attributes to formal
         arguments of statement functions.  */
         arguments of statement functions.  */
      if (sym != NULL && !st_flag
      if (sym != NULL && !st_flag
          && (gfc_add_dummy (&sym->attr, sym->name, NULL) == FAILURE
          && (gfc_add_dummy (&sym->attr, sym->name, NULL) == FAILURE
              || gfc_missing_attr (&sym->attr, NULL) == FAILURE))
              || gfc_missing_attr (&sym->attr, NULL) == FAILURE))
        {
        {
          m = MATCH_ERROR;
          m = MATCH_ERROR;
          goto cleanup;
          goto cleanup;
        }
        }
 
 
      /* The name of a program unit can be in a different namespace,
      /* The name of a program unit can be in a different namespace,
         so check for it explicitly.  After the statement is accepted,
         so check for it explicitly.  After the statement is accepted,
         the name is checked for especially in gfc_get_symbol().  */
         the name is checked for especially in gfc_get_symbol().  */
      if (gfc_new_block != NULL && sym != NULL
      if (gfc_new_block != NULL && sym != NULL
          && strcmp (sym->name, gfc_new_block->name) == 0)
          && strcmp (sym->name, gfc_new_block->name) == 0)
        {
        {
          gfc_error ("Name '%s' at %C is the name of the procedure",
          gfc_error ("Name '%s' at %C is the name of the procedure",
                     sym->name);
                     sym->name);
          m = MATCH_ERROR;
          m = MATCH_ERROR;
          goto cleanup;
          goto cleanup;
        }
        }
 
 
      if (gfc_match_char (')') == MATCH_YES)
      if (gfc_match_char (')') == MATCH_YES)
        goto ok;
        goto ok;
 
 
      m = gfc_match_char (',');
      m = gfc_match_char (',');
      if (m != MATCH_YES)
      if (m != MATCH_YES)
        {
        {
          gfc_error ("Unexpected junk in formal argument list at %C");
          gfc_error ("Unexpected junk in formal argument list at %C");
          goto cleanup;
          goto cleanup;
        }
        }
    }
    }
 
 
ok:
ok:
  /* Check for duplicate symbols in the formal argument list.  */
  /* Check for duplicate symbols in the formal argument list.  */
  if (head != NULL)
  if (head != NULL)
    {
    {
      for (p = head; p->next; p = p->next)
      for (p = head; p->next; p = p->next)
        {
        {
          if (p->sym == NULL)
          if (p->sym == NULL)
            continue;
            continue;
 
 
          for (q = p->next; q; q = q->next)
          for (q = p->next; q; q = q->next)
            if (p->sym == q->sym)
            if (p->sym == q->sym)
              {
              {
                gfc_error ("Duplicate symbol '%s' in formal argument list "
                gfc_error ("Duplicate symbol '%s' in formal argument list "
                           "at %C", p->sym->name);
                           "at %C", p->sym->name);
 
 
                m = MATCH_ERROR;
                m = MATCH_ERROR;
                goto cleanup;
                goto cleanup;
              }
              }
        }
        }
    }
    }
 
 
  if (gfc_add_explicit_interface (progname, IFSRC_DECL, head, NULL)
  if (gfc_add_explicit_interface (progname, IFSRC_DECL, head, NULL)
      == FAILURE)
      == FAILURE)
    {
    {
      m = MATCH_ERROR;
      m = MATCH_ERROR;
      goto cleanup;
      goto cleanup;
    }
    }
 
 
  return MATCH_YES;
  return MATCH_YES;
 
 
cleanup:
cleanup:
  gfc_free_formal_arglist (head);
  gfc_free_formal_arglist (head);
  return m;
  return m;
}
}
 
 
 
 
/* Match a RESULT specification following a function declaration or
/* Match a RESULT specification following a function declaration or
   ENTRY statement.  Also matches the end-of-statement.  */
   ENTRY statement.  Also matches the end-of-statement.  */
 
 
static match
static match
match_result (gfc_symbol *function, gfc_symbol **result)
match_result (gfc_symbol *function, gfc_symbol **result)
{
{
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
  gfc_symbol *r;
  gfc_symbol *r;
  match m;
  match m;
 
 
  if (gfc_match (" result (") != MATCH_YES)
  if (gfc_match (" result (") != MATCH_YES)
    return MATCH_NO;
    return MATCH_NO;
 
 
  m = gfc_match_name (name);
  m = gfc_match_name (name);
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    return m;
    return m;
 
 
  /* Get the right paren, and that's it because there could be the
  /* Get the right paren, and that's it because there could be the
     bind(c) attribute after the result clause.  */
     bind(c) attribute after the result clause.  */
  if (gfc_match_char(')') != MATCH_YES)
  if (gfc_match_char(')') != MATCH_YES)
    {
    {
     /* TODO: should report the missing right paren here.  */
     /* TODO: should report the missing right paren here.  */
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  if (strcmp (function->name, name) == 0)
  if (strcmp (function->name, name) == 0)
    {
    {
      gfc_error ("RESULT variable at %C must be different than function name");
      gfc_error ("RESULT variable at %C must be different than function name");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  if (gfc_get_symbol (name, NULL, &r))
  if (gfc_get_symbol (name, NULL, &r))
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  if (gfc_add_result (&r->attr, r->name, NULL) == FAILURE)
  if (gfc_add_result (&r->attr, r->name, NULL) == FAILURE)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  *result = r;
  *result = r;
 
 
  return MATCH_YES;
  return MATCH_YES;
}
}
 
 
 
 
/* Match a function suffix, which could be a combination of a result
/* Match a function suffix, which could be a combination of a result
   clause and BIND(C), either one, or neither.  The draft does not
   clause and BIND(C), either one, or neither.  The draft does not
   require them to come in a specific order.  */
   require them to come in a specific order.  */
 
 
match
match
gfc_match_suffix (gfc_symbol *sym, gfc_symbol **result)
gfc_match_suffix (gfc_symbol *sym, gfc_symbol **result)
{
{
  match is_bind_c;   /* Found bind(c).  */
  match is_bind_c;   /* Found bind(c).  */
  match is_result;   /* Found result clause.  */
  match is_result;   /* Found result clause.  */
  match found_match; /* Status of whether we've found a good match.  */
  match found_match; /* Status of whether we've found a good match.  */
  char peek_char;    /* Character we're going to peek at.  */
  char peek_char;    /* Character we're going to peek at.  */
  bool allow_binding_name;
  bool allow_binding_name;
 
 
  /* Initialize to having found nothing.  */
  /* Initialize to having found nothing.  */
  found_match = MATCH_NO;
  found_match = MATCH_NO;
  is_bind_c = MATCH_NO;
  is_bind_c = MATCH_NO;
  is_result = MATCH_NO;
  is_result = MATCH_NO;
 
 
  /* Get the next char to narrow between result and bind(c).  */
  /* Get the next char to narrow between result and bind(c).  */
  gfc_gobble_whitespace ();
  gfc_gobble_whitespace ();
  peek_char = gfc_peek_ascii_char ();
  peek_char = gfc_peek_ascii_char ();
 
 
  /* C binding names are not allowed for internal procedures.  */
  /* C binding names are not allowed for internal procedures.  */
  if (gfc_current_state () == COMP_CONTAINS
  if (gfc_current_state () == COMP_CONTAINS
      && sym->ns->proc_name->attr.flavor != FL_MODULE)
      && sym->ns->proc_name->attr.flavor != FL_MODULE)
    allow_binding_name = false;
    allow_binding_name = false;
  else
  else
    allow_binding_name = true;
    allow_binding_name = true;
 
 
  switch (peek_char)
  switch (peek_char)
    {
    {
    case 'r':
    case 'r':
      /* Look for result clause.  */
      /* Look for result clause.  */
      is_result = match_result (sym, result);
      is_result = match_result (sym, result);
      if (is_result == MATCH_YES)
      if (is_result == MATCH_YES)
        {
        {
          /* Now see if there is a bind(c) after it.  */
          /* Now see if there is a bind(c) after it.  */
          is_bind_c = gfc_match_bind_c (sym, allow_binding_name);
          is_bind_c = gfc_match_bind_c (sym, allow_binding_name);
          /* We've found the result clause and possibly bind(c).  */
          /* We've found the result clause and possibly bind(c).  */
          found_match = MATCH_YES;
          found_match = MATCH_YES;
        }
        }
      else
      else
        /* This should only be MATCH_ERROR.  */
        /* This should only be MATCH_ERROR.  */
        found_match = is_result;
        found_match = is_result;
      break;
      break;
    case 'b':
    case 'b':
      /* Look for bind(c) first.  */
      /* Look for bind(c) first.  */
      is_bind_c = gfc_match_bind_c (sym, allow_binding_name);
      is_bind_c = gfc_match_bind_c (sym, allow_binding_name);
      if (is_bind_c == MATCH_YES)
      if (is_bind_c == MATCH_YES)
        {
        {
          /* Now see if a result clause followed it.  */
          /* Now see if a result clause followed it.  */
          is_result = match_result (sym, result);
          is_result = match_result (sym, result);
          found_match = MATCH_YES;
          found_match = MATCH_YES;
        }
        }
      else
      else
        {
        {
          /* Should only be a MATCH_ERROR if we get here after seeing 'b'.  */
          /* Should only be a MATCH_ERROR if we get here after seeing 'b'.  */
          found_match = MATCH_ERROR;
          found_match = MATCH_ERROR;
        }
        }
      break;
      break;
    default:
    default:
      gfc_error ("Unexpected junk after function declaration at %C");
      gfc_error ("Unexpected junk after function declaration at %C");
      found_match = MATCH_ERROR;
      found_match = MATCH_ERROR;
      break;
      break;
    }
    }
 
 
  if (is_bind_c == MATCH_YES)
  if (is_bind_c == MATCH_YES)
    {
    {
      /* Fortran 2008 draft allows BIND(C) for internal procedures.  */
      /* Fortran 2008 draft allows BIND(C) for internal procedures.  */
      if (gfc_current_state () == COMP_CONTAINS
      if (gfc_current_state () == COMP_CONTAINS
          && sym->ns->proc_name->attr.flavor != FL_MODULE
          && sym->ns->proc_name->attr.flavor != FL_MODULE
          && gfc_notify_std (GFC_STD_F2008, "Fortran 2008: BIND(C) attribute "
          && gfc_notify_std (GFC_STD_F2008, "Fortran 2008: BIND(C) attribute "
                             "at %L may not be specified for an internal "
                             "at %L may not be specified for an internal "
                             "procedure", &gfc_current_locus)
                             "procedure", &gfc_current_locus)
             == FAILURE)
             == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      if (gfc_add_is_bind_c (&(sym->attr), sym->name, &gfc_current_locus, 1)
      if (gfc_add_is_bind_c (&(sym->attr), sym->name, &gfc_current_locus, 1)
          == FAILURE)
          == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
    }
    }
 
 
  return found_match;
  return found_match;
}
}
 
 
 
 
/* Procedure pointer return value without RESULT statement:
/* Procedure pointer return value without RESULT statement:
   Add "hidden" result variable named "ppr@".  */
   Add "hidden" result variable named "ppr@".  */
 
 
static gfc_try
static gfc_try
add_hidden_procptr_result (gfc_symbol *sym)
add_hidden_procptr_result (gfc_symbol *sym)
{
{
  bool case1,case2;
  bool case1,case2;
 
 
  if (gfc_notification_std (GFC_STD_F2003) == ERROR)
  if (gfc_notification_std (GFC_STD_F2003) == ERROR)
    return FAILURE;
    return FAILURE;
 
 
  /* First usage case: PROCEDURE and EXTERNAL statements.  */
  /* First usage case: PROCEDURE and EXTERNAL statements.  */
  case1 = gfc_current_state () == COMP_FUNCTION && gfc_current_block ()
  case1 = gfc_current_state () == COMP_FUNCTION && gfc_current_block ()
          && strcmp (gfc_current_block ()->name, sym->name) == 0
          && strcmp (gfc_current_block ()->name, sym->name) == 0
          && sym->attr.external;
          && sym->attr.external;
  /* Second usage case: INTERFACE statements.  */
  /* Second usage case: INTERFACE statements.  */
  case2 = gfc_current_state () == COMP_INTERFACE && gfc_state_stack->previous
  case2 = gfc_current_state () == COMP_INTERFACE && gfc_state_stack->previous
          && gfc_state_stack->previous->state == COMP_FUNCTION
          && gfc_state_stack->previous->state == COMP_FUNCTION
          && strcmp (gfc_state_stack->previous->sym->name, sym->name) == 0;
          && strcmp (gfc_state_stack->previous->sym->name, sym->name) == 0;
 
 
  if (case1 || case2)
  if (case1 || case2)
    {
    {
      gfc_symtree *stree;
      gfc_symtree *stree;
      if (case1)
      if (case1)
        gfc_get_sym_tree ("ppr@", gfc_current_ns, &stree, false);
        gfc_get_sym_tree ("ppr@", gfc_current_ns, &stree, false);
      else if (case2)
      else if (case2)
        {
        {
          gfc_symtree *st2;
          gfc_symtree *st2;
          gfc_get_sym_tree ("ppr@", gfc_current_ns->parent, &stree, false);
          gfc_get_sym_tree ("ppr@", gfc_current_ns->parent, &stree, false);
          st2 = gfc_new_symtree (&gfc_current_ns->sym_root, "ppr@");
          st2 = gfc_new_symtree (&gfc_current_ns->sym_root, "ppr@");
          st2->n.sym = stree->n.sym;
          st2->n.sym = stree->n.sym;
        }
        }
      sym->result = stree->n.sym;
      sym->result = stree->n.sym;
 
 
      sym->result->attr.proc_pointer = sym->attr.proc_pointer;
      sym->result->attr.proc_pointer = sym->attr.proc_pointer;
      sym->result->attr.pointer = sym->attr.pointer;
      sym->result->attr.pointer = sym->attr.pointer;
      sym->result->attr.external = sym->attr.external;
      sym->result->attr.external = sym->attr.external;
      sym->result->attr.referenced = sym->attr.referenced;
      sym->result->attr.referenced = sym->attr.referenced;
      sym->result->ts = sym->ts;
      sym->result->ts = sym->ts;
      sym->attr.proc_pointer = 0;
      sym->attr.proc_pointer = 0;
      sym->attr.pointer = 0;
      sym->attr.pointer = 0;
      sym->attr.external = 0;
      sym->attr.external = 0;
      if (sym->result->attr.external && sym->result->attr.pointer)
      if (sym->result->attr.external && sym->result->attr.pointer)
        {
        {
          sym->result->attr.pointer = 0;
          sym->result->attr.pointer = 0;
          sym->result->attr.proc_pointer = 1;
          sym->result->attr.proc_pointer = 1;
        }
        }
 
 
      return gfc_add_result (&sym->result->attr, sym->result->name, NULL);
      return gfc_add_result (&sym->result->attr, sym->result->name, NULL);
    }
    }
  /* POINTER after PROCEDURE/EXTERNAL/INTERFACE statement.  */
  /* POINTER after PROCEDURE/EXTERNAL/INTERFACE statement.  */
  else if (sym->attr.function && !sym->attr.external && sym->attr.pointer
  else if (sym->attr.function && !sym->attr.external && sym->attr.pointer
           && sym->result && sym->result != sym && sym->result->attr.external
           && sym->result && sym->result != sym && sym->result->attr.external
           && sym == gfc_current_ns->proc_name
           && sym == gfc_current_ns->proc_name
           && sym == sym->result->ns->proc_name
           && sym == sym->result->ns->proc_name
           && strcmp ("ppr@", sym->result->name) == 0)
           && strcmp ("ppr@", sym->result->name) == 0)
    {
    {
      sym->result->attr.proc_pointer = 1;
      sym->result->attr.proc_pointer = 1;
      sym->attr.pointer = 0;
      sym->attr.pointer = 0;
      return SUCCESS;
      return SUCCESS;
    }
    }
  else
  else
    return FAILURE;
    return FAILURE;
}
}
 
 
 
 
/* Match the interface for a PROCEDURE declaration,
/* Match the interface for a PROCEDURE declaration,
   including brackets (R1212).  */
   including brackets (R1212).  */
 
 
static match
static match
match_procedure_interface (gfc_symbol **proc_if)
match_procedure_interface (gfc_symbol **proc_if)
{
{
  match m;
  match m;
  gfc_symtree *st;
  gfc_symtree *st;
  locus old_loc, entry_loc;
  locus old_loc, entry_loc;
  gfc_namespace *old_ns = gfc_current_ns;
  gfc_namespace *old_ns = gfc_current_ns;
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
 
 
  old_loc = entry_loc = gfc_current_locus;
  old_loc = entry_loc = gfc_current_locus;
  gfc_clear_ts (&current_ts);
  gfc_clear_ts (&current_ts);
 
 
  if (gfc_match (" (") != MATCH_YES)
  if (gfc_match (" (") != MATCH_YES)
    {
    {
      gfc_current_locus = entry_loc;
      gfc_current_locus = entry_loc;
      return MATCH_NO;
      return MATCH_NO;
    }
    }
 
 
  /* Get the type spec. for the procedure interface.  */
  /* Get the type spec. for the procedure interface.  */
  old_loc = gfc_current_locus;
  old_loc = gfc_current_locus;
  m = gfc_match_decl_type_spec (&current_ts, 0);
  m = gfc_match_decl_type_spec (&current_ts, 0);
  gfc_gobble_whitespace ();
  gfc_gobble_whitespace ();
  if (m == MATCH_YES || (m == MATCH_NO && gfc_peek_ascii_char () == ')'))
  if (m == MATCH_YES || (m == MATCH_NO && gfc_peek_ascii_char () == ')'))
    goto got_ts;
    goto got_ts;
 
 
  if (m == MATCH_ERROR)
  if (m == MATCH_ERROR)
    return m;
    return m;
 
 
  /* Procedure interface is itself a procedure.  */
  /* Procedure interface is itself a procedure.  */
  gfc_current_locus = old_loc;
  gfc_current_locus = old_loc;
  m = gfc_match_name (name);
  m = gfc_match_name (name);
 
 
  /* First look to see if it is already accessible in the current
  /* First look to see if it is already accessible in the current
     namespace because it is use associated or contained.  */
     namespace because it is use associated or contained.  */
  st = NULL;
  st = NULL;
  if (gfc_find_sym_tree (name, NULL, 0, &st))
  if (gfc_find_sym_tree (name, NULL, 0, &st))
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  /* If it is still not found, then try the parent namespace, if it
  /* If it is still not found, then try the parent namespace, if it
     exists and create the symbol there if it is still not found.  */
     exists and create the symbol there if it is still not found.  */
  if (gfc_current_ns->parent)
  if (gfc_current_ns->parent)
    gfc_current_ns = gfc_current_ns->parent;
    gfc_current_ns = gfc_current_ns->parent;
  if (st == NULL && gfc_get_ha_sym_tree (name, &st))
  if (st == NULL && gfc_get_ha_sym_tree (name, &st))
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  gfc_current_ns = old_ns;
  gfc_current_ns = old_ns;
  *proc_if = st->n.sym;
  *proc_if = st->n.sym;
 
 
  /* Various interface checks.  */
  /* Various interface checks.  */
  if (*proc_if)
  if (*proc_if)
    {
    {
      (*proc_if)->refs++;
      (*proc_if)->refs++;
      /* Resolve interface if possible. That way, attr.procedure is only set
      /* Resolve interface if possible. That way, attr.procedure is only set
         if it is declared by a later procedure-declaration-stmt, which is
         if it is declared by a later procedure-declaration-stmt, which is
         invalid per C1212.  */
         invalid per C1212.  */
      while ((*proc_if)->ts.interface)
      while ((*proc_if)->ts.interface)
        *proc_if = (*proc_if)->ts.interface;
        *proc_if = (*proc_if)->ts.interface;
 
 
      if ((*proc_if)->generic)
      if ((*proc_if)->generic)
        {
        {
          gfc_error ("Interface '%s' at %C may not be generic",
          gfc_error ("Interface '%s' at %C may not be generic",
                     (*proc_if)->name);
                     (*proc_if)->name);
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
      if ((*proc_if)->attr.proc == PROC_ST_FUNCTION)
      if ((*proc_if)->attr.proc == PROC_ST_FUNCTION)
        {
        {
          gfc_error ("Interface '%s' at %C may not be a statement function",
          gfc_error ("Interface '%s' at %C may not be a statement function",
                     (*proc_if)->name);
                     (*proc_if)->name);
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
      /* Handle intrinsic procedures.  */
      /* Handle intrinsic procedures.  */
      if (!((*proc_if)->attr.external || (*proc_if)->attr.use_assoc
      if (!((*proc_if)->attr.external || (*proc_if)->attr.use_assoc
            || (*proc_if)->attr.if_source == IFSRC_IFBODY)
            || (*proc_if)->attr.if_source == IFSRC_IFBODY)
          && (gfc_is_intrinsic ((*proc_if), 0, gfc_current_locus)
          && (gfc_is_intrinsic ((*proc_if), 0, gfc_current_locus)
              || gfc_is_intrinsic ((*proc_if), 1, gfc_current_locus)))
              || gfc_is_intrinsic ((*proc_if), 1, gfc_current_locus)))
        (*proc_if)->attr.intrinsic = 1;
        (*proc_if)->attr.intrinsic = 1;
      if ((*proc_if)->attr.intrinsic
      if ((*proc_if)->attr.intrinsic
          && !gfc_intrinsic_actual_ok ((*proc_if)->name, 0))
          && !gfc_intrinsic_actual_ok ((*proc_if)->name, 0))
        {
        {
          gfc_error ("Intrinsic procedure '%s' not allowed "
          gfc_error ("Intrinsic procedure '%s' not allowed "
                    "in PROCEDURE statement at %C", (*proc_if)->name);
                    "in PROCEDURE statement at %C", (*proc_if)->name);
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
    }
    }
 
 
got_ts:
got_ts:
  if (gfc_match (" )") != MATCH_YES)
  if (gfc_match (" )") != MATCH_YES)
    {
    {
      gfc_current_locus = entry_loc;
      gfc_current_locus = entry_loc;
      return MATCH_NO;
      return MATCH_NO;
    }
    }
 
 
  return MATCH_YES;
  return MATCH_YES;
}
}
 
 
 
 
/* Match a PROCEDURE declaration (R1211).  */
/* Match a PROCEDURE declaration (R1211).  */
 
 
static match
static match
match_procedure_decl (void)
match_procedure_decl (void)
{
{
  match m;
  match m;
  gfc_symbol *sym, *proc_if = NULL;
  gfc_symbol *sym, *proc_if = NULL;
  int num;
  int num;
  gfc_expr *initializer = NULL;
  gfc_expr *initializer = NULL;
 
 
  /* Parse interface (with brackets). */
  /* Parse interface (with brackets). */
  m = match_procedure_interface (&proc_if);
  m = match_procedure_interface (&proc_if);
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    return m;
    return m;
 
 
  /* Parse attributes (with colons).  */
  /* Parse attributes (with colons).  */
  m = match_attr_spec();
  m = match_attr_spec();
  if (m == MATCH_ERROR)
  if (m == MATCH_ERROR)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  /* Get procedure symbols.  */
  /* Get procedure symbols.  */
  for(num=1;;num++)
  for(num=1;;num++)
    {
    {
      m = gfc_match_symbol (&sym, 0);
      m = gfc_match_symbol (&sym, 0);
      if (m == MATCH_NO)
      if (m == MATCH_NO)
        goto syntax;
        goto syntax;
      else if (m == MATCH_ERROR)
      else if (m == MATCH_ERROR)
        return m;
        return m;
 
 
      /* Add current_attr to the symbol attributes.  */
      /* Add current_attr to the symbol attributes.  */
      if (gfc_copy_attr (&sym->attr, &current_attr, NULL) == FAILURE)
      if (gfc_copy_attr (&sym->attr, &current_attr, NULL) == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      if (sym->attr.is_bind_c)
      if (sym->attr.is_bind_c)
        {
        {
          /* Check for C1218.  */
          /* Check for C1218.  */
          if (!proc_if || !proc_if->attr.is_bind_c)
          if (!proc_if || !proc_if->attr.is_bind_c)
            {
            {
              gfc_error ("BIND(C) attribute at %C requires "
              gfc_error ("BIND(C) attribute at %C requires "
                        "an interface with BIND(C)");
                        "an interface with BIND(C)");
              return MATCH_ERROR;
              return MATCH_ERROR;
            }
            }
          /* Check for C1217.  */
          /* Check for C1217.  */
          if (has_name_equals && sym->attr.pointer)
          if (has_name_equals && sym->attr.pointer)
            {
            {
              gfc_error ("BIND(C) procedure with NAME may not have "
              gfc_error ("BIND(C) procedure with NAME may not have "
                        "POINTER attribute at %C");
                        "POINTER attribute at %C");
              return MATCH_ERROR;
              return MATCH_ERROR;
            }
            }
          if (has_name_equals && sym->attr.dummy)
          if (has_name_equals && sym->attr.dummy)
            {
            {
              gfc_error ("Dummy procedure at %C may not have "
              gfc_error ("Dummy procedure at %C may not have "
                        "BIND(C) attribute with NAME");
                        "BIND(C) attribute with NAME");
              return MATCH_ERROR;
              return MATCH_ERROR;
            }
            }
          /* Set binding label for BIND(C).  */
          /* Set binding label for BIND(C).  */
          if (set_binding_label (sym->binding_label, sym->name, num) != SUCCESS)
          if (set_binding_label (sym->binding_label, sym->name, num) != SUCCESS)
            return MATCH_ERROR;
            return MATCH_ERROR;
        }
        }
 
 
      if (gfc_add_external (&sym->attr, NULL) == FAILURE)
      if (gfc_add_external (&sym->attr, NULL) == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      if (add_hidden_procptr_result (sym) == SUCCESS)
      if (add_hidden_procptr_result (sym) == SUCCESS)
        sym = sym->result;
        sym = sym->result;
 
 
      if (gfc_add_proc (&sym->attr, sym->name, NULL) == FAILURE)
      if (gfc_add_proc (&sym->attr, sym->name, NULL) == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      /* Set interface.  */
      /* Set interface.  */
      if (proc_if != NULL)
      if (proc_if != NULL)
        {
        {
          if (sym->ts.type != BT_UNKNOWN)
          if (sym->ts.type != BT_UNKNOWN)
            {
            {
              gfc_error ("Procedure '%s' at %L already has basic type of %s",
              gfc_error ("Procedure '%s' at %L already has basic type of %s",
                         sym->name, &gfc_current_locus,
                         sym->name, &gfc_current_locus,
                         gfc_basic_typename (sym->ts.type));
                         gfc_basic_typename (sym->ts.type));
              return MATCH_ERROR;
              return MATCH_ERROR;
            }
            }
          sym->ts.interface = proc_if;
          sym->ts.interface = proc_if;
          sym->attr.untyped = 1;
          sym->attr.untyped = 1;
          sym->attr.if_source = IFSRC_IFBODY;
          sym->attr.if_source = IFSRC_IFBODY;
        }
        }
      else if (current_ts.type != BT_UNKNOWN)
      else if (current_ts.type != BT_UNKNOWN)
        {
        {
          if (gfc_add_type (sym, &current_ts, &gfc_current_locus) == FAILURE)
          if (gfc_add_type (sym, &current_ts, &gfc_current_locus) == FAILURE)
            return MATCH_ERROR;
            return MATCH_ERROR;
          sym->ts.interface = gfc_new_symbol ("", gfc_current_ns);
          sym->ts.interface = gfc_new_symbol ("", gfc_current_ns);
          sym->ts.interface->ts = current_ts;
          sym->ts.interface->ts = current_ts;
          sym->ts.interface->attr.function = 1;
          sym->ts.interface->attr.function = 1;
          sym->attr.function = sym->ts.interface->attr.function;
          sym->attr.function = sym->ts.interface->attr.function;
          sym->attr.if_source = IFSRC_UNKNOWN;
          sym->attr.if_source = IFSRC_UNKNOWN;
        }
        }
 
 
      if (gfc_match (" =>") == MATCH_YES)
      if (gfc_match (" =>") == MATCH_YES)
        {
        {
          if (!current_attr.pointer)
          if (!current_attr.pointer)
            {
            {
              gfc_error ("Initialization at %C isn't for a pointer variable");
              gfc_error ("Initialization at %C isn't for a pointer variable");
              m = MATCH_ERROR;
              m = MATCH_ERROR;
              goto cleanup;
              goto cleanup;
            }
            }
 
 
          m = gfc_match_null (&initializer);
          m = gfc_match_null (&initializer);
          if (m == MATCH_NO)
          if (m == MATCH_NO)
            {
            {
              gfc_error ("Pointer initialization requires a NULL() at %C");
              gfc_error ("Pointer initialization requires a NULL() at %C");
              m = MATCH_ERROR;
              m = MATCH_ERROR;
            }
            }
 
 
          if (gfc_pure (NULL))
          if (gfc_pure (NULL))
            {
            {
              gfc_error ("Initialization of pointer at %C is not allowed in "
              gfc_error ("Initialization of pointer at %C is not allowed in "
                         "a PURE procedure");
                         "a PURE procedure");
              m = MATCH_ERROR;
              m = MATCH_ERROR;
            }
            }
 
 
          if (m != MATCH_YES)
          if (m != MATCH_YES)
            goto cleanup;
            goto cleanup;
 
 
          if (add_init_expr_to_sym (sym->name, &initializer, &gfc_current_locus)
          if (add_init_expr_to_sym (sym->name, &initializer, &gfc_current_locus)
              != SUCCESS)
              != SUCCESS)
            goto cleanup;
            goto cleanup;
 
 
        }
        }
 
 
      gfc_set_sym_referenced (sym);
      gfc_set_sym_referenced (sym);
 
 
      if (gfc_match_eos () == MATCH_YES)
      if (gfc_match_eos () == MATCH_YES)
        return MATCH_YES;
        return MATCH_YES;
      if (gfc_match_char (',') != MATCH_YES)
      if (gfc_match_char (',') != MATCH_YES)
        goto syntax;
        goto syntax;
    }
    }
 
 
syntax:
syntax:
  gfc_error ("Syntax error in PROCEDURE statement at %C");
  gfc_error ("Syntax error in PROCEDURE statement at %C");
  return MATCH_ERROR;
  return MATCH_ERROR;
 
 
cleanup:
cleanup:
  /* Free stuff up and return.  */
  /* Free stuff up and return.  */
  gfc_free_expr (initializer);
  gfc_free_expr (initializer);
  return m;
  return m;
}
}
 
 
 
 
static match
static match
match_binding_attributes (gfc_typebound_proc* ba, bool generic, bool ppc);
match_binding_attributes (gfc_typebound_proc* ba, bool generic, bool ppc);
 
 
 
 
/* Match a procedure pointer component declaration (R445).  */
/* Match a procedure pointer component declaration (R445).  */
 
 
static match
static match
match_ppc_decl (void)
match_ppc_decl (void)
{
{
  match m;
  match m;
  gfc_symbol *proc_if = NULL;
  gfc_symbol *proc_if = NULL;
  gfc_typespec ts;
  gfc_typespec ts;
  int num;
  int num;
  gfc_component *c;
  gfc_component *c;
  gfc_expr *initializer = NULL;
  gfc_expr *initializer = NULL;
  gfc_typebound_proc* tb;
  gfc_typebound_proc* tb;
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
 
 
  /* Parse interface (with brackets).  */
  /* Parse interface (with brackets).  */
  m = match_procedure_interface (&proc_if);
  m = match_procedure_interface (&proc_if);
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    goto syntax;
    goto syntax;
 
 
  /* Parse attributes.  */
  /* Parse attributes.  */
  tb = XCNEW (gfc_typebound_proc);
  tb = XCNEW (gfc_typebound_proc);
  tb->where = gfc_current_locus;
  tb->where = gfc_current_locus;
  m = match_binding_attributes (tb, false, true);
  m = match_binding_attributes (tb, false, true);
  if (m == MATCH_ERROR)
  if (m == MATCH_ERROR)
    return m;
    return m;
 
 
  gfc_clear_attr (&current_attr);
  gfc_clear_attr (&current_attr);
  current_attr.procedure = 1;
  current_attr.procedure = 1;
  current_attr.proc_pointer = 1;
  current_attr.proc_pointer = 1;
  current_attr.access = tb->access;
  current_attr.access = tb->access;
  current_attr.flavor = FL_PROCEDURE;
  current_attr.flavor = FL_PROCEDURE;
 
 
  /* Match the colons (required).  */
  /* Match the colons (required).  */
  if (gfc_match (" ::") != MATCH_YES)
  if (gfc_match (" ::") != MATCH_YES)
    {
    {
      gfc_error ("Expected '::' after binding-attributes at %C");
      gfc_error ("Expected '::' after binding-attributes at %C");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  /* Check for C450.  */
  /* Check for C450.  */
  if (!tb->nopass && proc_if == NULL)
  if (!tb->nopass && proc_if == NULL)
    {
    {
      gfc_error("NOPASS or explicit interface required at %C");
      gfc_error("NOPASS or explicit interface required at %C");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: Procedure pointer "
  if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: Procedure pointer "
                     "component at %C") == FAILURE)
                     "component at %C") == FAILURE)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  /* Match PPC names.  */
  /* Match PPC names.  */
  ts = current_ts;
  ts = current_ts;
  for(num=1;;num++)
  for(num=1;;num++)
    {
    {
      m = gfc_match_name (name);
      m = gfc_match_name (name);
      if (m == MATCH_NO)
      if (m == MATCH_NO)
        goto syntax;
        goto syntax;
      else if (m == MATCH_ERROR)
      else if (m == MATCH_ERROR)
        return m;
        return m;
 
 
      if (gfc_add_component (gfc_current_block (), name, &c) == FAILURE)
      if (gfc_add_component (gfc_current_block (), name, &c) == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      /* Add current_attr to the symbol attributes.  */
      /* Add current_attr to the symbol attributes.  */
      if (gfc_copy_attr (&c->attr, &current_attr, NULL) == FAILURE)
      if (gfc_copy_attr (&c->attr, &current_attr, NULL) == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      if (gfc_add_external (&c->attr, NULL) == FAILURE)
      if (gfc_add_external (&c->attr, NULL) == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      if (gfc_add_proc (&c->attr, name, NULL) == FAILURE)
      if (gfc_add_proc (&c->attr, name, NULL) == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      c->tb = tb;
      c->tb = tb;
 
 
      /* Set interface.  */
      /* Set interface.  */
      if (proc_if != NULL)
      if (proc_if != NULL)
        {
        {
          c->ts.interface = proc_if;
          c->ts.interface = proc_if;
          c->attr.untyped = 1;
          c->attr.untyped = 1;
          c->attr.if_source = IFSRC_IFBODY;
          c->attr.if_source = IFSRC_IFBODY;
        }
        }
      else if (ts.type != BT_UNKNOWN)
      else if (ts.type != BT_UNKNOWN)
        {
        {
          c->ts = ts;
          c->ts = ts;
          c->ts.interface = gfc_new_symbol ("", gfc_current_ns);
          c->ts.interface = gfc_new_symbol ("", gfc_current_ns);
          c->ts.interface->ts = ts;
          c->ts.interface->ts = ts;
          c->ts.interface->attr.function = 1;
          c->ts.interface->attr.function = 1;
          c->attr.function = c->ts.interface->attr.function;
          c->attr.function = c->ts.interface->attr.function;
          c->attr.if_source = IFSRC_UNKNOWN;
          c->attr.if_source = IFSRC_UNKNOWN;
        }
        }
 
 
      if (gfc_match (" =>") == MATCH_YES)
      if (gfc_match (" =>") == MATCH_YES)
        {
        {
          m = gfc_match_null (&initializer);
          m = gfc_match_null (&initializer);
          if (m == MATCH_NO)
          if (m == MATCH_NO)
            {
            {
              gfc_error ("Pointer initialization requires a NULL() at %C");
              gfc_error ("Pointer initialization requires a NULL() at %C");
              m = MATCH_ERROR;
              m = MATCH_ERROR;
            }
            }
          if (gfc_pure (NULL))
          if (gfc_pure (NULL))
            {
            {
              gfc_error ("Initialization of pointer at %C is not allowed in "
              gfc_error ("Initialization of pointer at %C is not allowed in "
                         "a PURE procedure");
                         "a PURE procedure");
              m = MATCH_ERROR;
              m = MATCH_ERROR;
            }
            }
          if (m != MATCH_YES)
          if (m != MATCH_YES)
            {
            {
              gfc_free_expr (initializer);
              gfc_free_expr (initializer);
              return m;
              return m;
            }
            }
          c->initializer = initializer;
          c->initializer = initializer;
        }
        }
 
 
      if (gfc_match_eos () == MATCH_YES)
      if (gfc_match_eos () == MATCH_YES)
        return MATCH_YES;
        return MATCH_YES;
      if (gfc_match_char (',') != MATCH_YES)
      if (gfc_match_char (',') != MATCH_YES)
        goto syntax;
        goto syntax;
    }
    }
 
 
syntax:
syntax:
  gfc_error ("Syntax error in procedure pointer component at %C");
  gfc_error ("Syntax error in procedure pointer component at %C");
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
/* Match a PROCEDURE declaration inside an interface (R1206).  */
/* Match a PROCEDURE declaration inside an interface (R1206).  */
 
 
static match
static match
match_procedure_in_interface (void)
match_procedure_in_interface (void)
{
{
  match m;
  match m;
  gfc_symbol *sym;
  gfc_symbol *sym;
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
 
 
  if (current_interface.type == INTERFACE_NAMELESS
  if (current_interface.type == INTERFACE_NAMELESS
      || current_interface.type == INTERFACE_ABSTRACT)
      || current_interface.type == INTERFACE_ABSTRACT)
    {
    {
      gfc_error ("PROCEDURE at %C must be in a generic interface");
      gfc_error ("PROCEDURE at %C must be in a generic interface");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  for(;;)
  for(;;)
    {
    {
      m = gfc_match_name (name);
      m = gfc_match_name (name);
      if (m == MATCH_NO)
      if (m == MATCH_NO)
        goto syntax;
        goto syntax;
      else if (m == MATCH_ERROR)
      else if (m == MATCH_ERROR)
        return m;
        return m;
      if (gfc_get_symbol (name, gfc_current_ns->parent, &sym))
      if (gfc_get_symbol (name, gfc_current_ns->parent, &sym))
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      if (gfc_add_interface (sym) == FAILURE)
      if (gfc_add_interface (sym) == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      if (gfc_match_eos () == MATCH_YES)
      if (gfc_match_eos () == MATCH_YES)
        break;
        break;
      if (gfc_match_char (',') != MATCH_YES)
      if (gfc_match_char (',') != MATCH_YES)
        goto syntax;
        goto syntax;
    }
    }
 
 
  return MATCH_YES;
  return MATCH_YES;
 
 
syntax:
syntax:
  gfc_error ("Syntax error in PROCEDURE statement at %C");
  gfc_error ("Syntax error in PROCEDURE statement at %C");
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
/* General matcher for PROCEDURE declarations.  */
/* General matcher for PROCEDURE declarations.  */
 
 
static match match_procedure_in_type (void);
static match match_procedure_in_type (void);
 
 
match
match
gfc_match_procedure (void)
gfc_match_procedure (void)
{
{
  match m;
  match m;
 
 
  switch (gfc_current_state ())
  switch (gfc_current_state ())
    {
    {
    case COMP_NONE:
    case COMP_NONE:
    case COMP_PROGRAM:
    case COMP_PROGRAM:
    case COMP_MODULE:
    case COMP_MODULE:
    case COMP_SUBROUTINE:
    case COMP_SUBROUTINE:
    case COMP_FUNCTION:
    case COMP_FUNCTION:
      m = match_procedure_decl ();
      m = match_procedure_decl ();
      break;
      break;
    case COMP_INTERFACE:
    case COMP_INTERFACE:
      m = match_procedure_in_interface ();
      m = match_procedure_in_interface ();
      break;
      break;
    case COMP_DERIVED:
    case COMP_DERIVED:
      m = match_ppc_decl ();
      m = match_ppc_decl ();
      break;
      break;
    case COMP_DERIVED_CONTAINS:
    case COMP_DERIVED_CONTAINS:
      m = match_procedure_in_type ();
      m = match_procedure_in_type ();
      break;
      break;
    default:
    default:
      return MATCH_NO;
      return MATCH_NO;
    }
    }
 
 
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    return m;
    return m;
 
 
  if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: PROCEDURE statement at %C")
  if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: PROCEDURE statement at %C")
      == FAILURE)
      == FAILURE)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  return m;
  return m;
}
}
 
 
 
 
/* Warn if a matched procedure has the same name as an intrinsic; this is
/* Warn if a matched procedure has the same name as an intrinsic; this is
   simply a wrapper around gfc_warn_intrinsic_shadow that interprets the current
   simply a wrapper around gfc_warn_intrinsic_shadow that interprets the current
   parser-state-stack to find out whether we're in a module.  */
   parser-state-stack to find out whether we're in a module.  */
 
 
static void
static void
warn_intrinsic_shadow (const gfc_symbol* sym, bool func)
warn_intrinsic_shadow (const gfc_symbol* sym, bool func)
{
{
  bool in_module;
  bool in_module;
 
 
  in_module = (gfc_state_stack->previous
  in_module = (gfc_state_stack->previous
               && gfc_state_stack->previous->state == COMP_MODULE);
               && gfc_state_stack->previous->state == COMP_MODULE);
 
 
  gfc_warn_intrinsic_shadow (sym, in_module, func);
  gfc_warn_intrinsic_shadow (sym, in_module, func);
}
}
 
 
 
 
/* Match a function declaration.  */
/* Match a function declaration.  */
 
 
match
match
gfc_match_function_decl (void)
gfc_match_function_decl (void)
{
{
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
  gfc_symbol *sym, *result;
  gfc_symbol *sym, *result;
  locus old_loc;
  locus old_loc;
  match m;
  match m;
  match suffix_match;
  match suffix_match;
  match found_match; /* Status returned by match func.  */
  match found_match; /* Status returned by match func.  */
 
 
  if (gfc_current_state () != COMP_NONE
  if (gfc_current_state () != COMP_NONE
      && gfc_current_state () != COMP_INTERFACE
      && gfc_current_state () != COMP_INTERFACE
      && gfc_current_state () != COMP_CONTAINS)
      && gfc_current_state () != COMP_CONTAINS)
    return MATCH_NO;
    return MATCH_NO;
 
 
  gfc_clear_ts (&current_ts);
  gfc_clear_ts (&current_ts);
 
 
  old_loc = gfc_current_locus;
  old_loc = gfc_current_locus;
 
 
  m = gfc_match_prefix (&current_ts);
  m = gfc_match_prefix (&current_ts);
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    {
    {
      gfc_current_locus = old_loc;
      gfc_current_locus = old_loc;
      return m;
      return m;
    }
    }
 
 
  if (gfc_match ("function% %n", name) != MATCH_YES)
  if (gfc_match ("function% %n", name) != MATCH_YES)
    {
    {
      gfc_current_locus = old_loc;
      gfc_current_locus = old_loc;
      return MATCH_NO;
      return MATCH_NO;
    }
    }
  if (get_proc_name (name, &sym, false))
  if (get_proc_name (name, &sym, false))
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  if (add_hidden_procptr_result (sym) == SUCCESS)
  if (add_hidden_procptr_result (sym) == SUCCESS)
    sym = sym->result;
    sym = sym->result;
 
 
  gfc_new_block = sym;
  gfc_new_block = sym;
 
 
  m = gfc_match_formal_arglist (sym, 0, 0);
  m = gfc_match_formal_arglist (sym, 0, 0);
  if (m == MATCH_NO)
  if (m == MATCH_NO)
    {
    {
      gfc_error ("Expected formal argument list in function "
      gfc_error ("Expected formal argument list in function "
                 "definition at %C");
                 "definition at %C");
      m = MATCH_ERROR;
      m = MATCH_ERROR;
      goto cleanup;
      goto cleanup;
    }
    }
  else if (m == MATCH_ERROR)
  else if (m == MATCH_ERROR)
    goto cleanup;
    goto cleanup;
 
 
  result = NULL;
  result = NULL;
 
 
  /* According to the draft, the bind(c) and result clause can
  /* According to the draft, the bind(c) and result clause can
     come in either order after the formal_arg_list (i.e., either
     come in either order after the formal_arg_list (i.e., either
     can be first, both can exist together or by themselves or neither
     can be first, both can exist together or by themselves or neither
     one).  Therefore, the match_result can't match the end of the
     one).  Therefore, the match_result can't match the end of the
     string, and check for the bind(c) or result clause in either order.  */
     string, and check for the bind(c) or result clause in either order.  */
  found_match = gfc_match_eos ();
  found_match = gfc_match_eos ();
 
 
  /* Make sure that it isn't already declared as BIND(C).  If it is, it
  /* Make sure that it isn't already declared as BIND(C).  If it is, it
     must have been marked BIND(C) with a BIND(C) attribute and that is
     must have been marked BIND(C) with a BIND(C) attribute and that is
     not allowed for procedures.  */
     not allowed for procedures.  */
  if (sym->attr.is_bind_c == 1)
  if (sym->attr.is_bind_c == 1)
    {
    {
      sym->attr.is_bind_c = 0;
      sym->attr.is_bind_c = 0;
      if (sym->old_symbol != NULL)
      if (sym->old_symbol != NULL)
        gfc_error_now ("BIND(C) attribute at %L can only be used for "
        gfc_error_now ("BIND(C) attribute at %L can only be used for "
                       "variables or common blocks",
                       "variables or common blocks",
                       &(sym->old_symbol->declared_at));
                       &(sym->old_symbol->declared_at));
      else
      else
        gfc_error_now ("BIND(C) attribute at %L can only be used for "
        gfc_error_now ("BIND(C) attribute at %L can only be used for "
                       "variables or common blocks", &gfc_current_locus);
                       "variables or common blocks", &gfc_current_locus);
    }
    }
 
 
  if (found_match != MATCH_YES)
  if (found_match != MATCH_YES)
    {
    {
      /* If we haven't found the end-of-statement, look for a suffix.  */
      /* If we haven't found the end-of-statement, look for a suffix.  */
      suffix_match = gfc_match_suffix (sym, &result);
      suffix_match = gfc_match_suffix (sym, &result);
      if (suffix_match == MATCH_YES)
      if (suffix_match == MATCH_YES)
        /* Need to get the eos now.  */
        /* Need to get the eos now.  */
        found_match = gfc_match_eos ();
        found_match = gfc_match_eos ();
      else
      else
        found_match = suffix_match;
        found_match = suffix_match;
    }
    }
 
 
  if(found_match != MATCH_YES)
  if(found_match != MATCH_YES)
    m = MATCH_ERROR;
    m = MATCH_ERROR;
  else
  else
    {
    {
      /* Make changes to the symbol.  */
      /* Make changes to the symbol.  */
      m = MATCH_ERROR;
      m = MATCH_ERROR;
 
 
      if (gfc_add_function (&sym->attr, sym->name, NULL) == FAILURE)
      if (gfc_add_function (&sym->attr, sym->name, NULL) == FAILURE)
        goto cleanup;
        goto cleanup;
 
 
      if (gfc_missing_attr (&sym->attr, NULL) == FAILURE
      if (gfc_missing_attr (&sym->attr, NULL) == FAILURE
          || copy_prefix (&sym->attr, &sym->declared_at) == FAILURE)
          || copy_prefix (&sym->attr, &sym->declared_at) == FAILURE)
        goto cleanup;
        goto cleanup;
 
 
      /* Delay matching the function characteristics until after the
      /* Delay matching the function characteristics until after the
         specification block by signalling kind=-1.  */
         specification block by signalling kind=-1.  */
      sym->declared_at = old_loc;
      sym->declared_at = old_loc;
      if (current_ts.type != BT_UNKNOWN)
      if (current_ts.type != BT_UNKNOWN)
        current_ts.kind = -1;
        current_ts.kind = -1;
      else
      else
        current_ts.kind = 0;
        current_ts.kind = 0;
 
 
      if (result == NULL)
      if (result == NULL)
        {
        {
          if (current_ts.type != BT_UNKNOWN
          if (current_ts.type != BT_UNKNOWN
              && gfc_add_type (sym, &current_ts, &gfc_current_locus) == FAILURE)
              && gfc_add_type (sym, &current_ts, &gfc_current_locus) == FAILURE)
            goto cleanup;
            goto cleanup;
          sym->result = sym;
          sym->result = sym;
        }
        }
      else
      else
        {
        {
          if (current_ts.type != BT_UNKNOWN
          if (current_ts.type != BT_UNKNOWN
              && gfc_add_type (result, &current_ts, &gfc_current_locus)
              && gfc_add_type (result, &current_ts, &gfc_current_locus)
                 == FAILURE)
                 == FAILURE)
            goto cleanup;
            goto cleanup;
          sym->result = result;
          sym->result = result;
        }
        }
 
 
      /* Warn if this procedure has the same name as an intrinsic.  */
      /* Warn if this procedure has the same name as an intrinsic.  */
      warn_intrinsic_shadow (sym, true);
      warn_intrinsic_shadow (sym, true);
 
 
      return MATCH_YES;
      return MATCH_YES;
    }
    }
 
 
cleanup:
cleanup:
  gfc_current_locus = old_loc;
  gfc_current_locus = old_loc;
  return m;
  return m;
}
}
 
 
 
 
/* This is mostly a copy of parse.c(add_global_procedure) but modified to
/* 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
   pass the name of the entry, rather than the gfc_current_block name, and
   to return false upon finding an existing global entry.  */
   to return false upon finding an existing global entry.  */
 
 
static bool
static bool
add_global_entry (const char *name, int sub)
add_global_entry (const char *name, int sub)
{
{
  gfc_gsymbol *s;
  gfc_gsymbol *s;
  enum gfc_symbol_type type;
  enum gfc_symbol_type type;
 
 
  s = gfc_get_gsymbol(name);
  s = gfc_get_gsymbol(name);
  type = sub ? GSYM_SUBROUTINE : GSYM_FUNCTION;
  type = sub ? GSYM_SUBROUTINE : GSYM_FUNCTION;
 
 
  if (s->defined
  if (s->defined
      || (s->type != GSYM_UNKNOWN
      || (s->type != GSYM_UNKNOWN
          && s->type != type))
          && s->type != type))
    gfc_global_used(s, NULL);
    gfc_global_used(s, NULL);
  else
  else
    {
    {
      s->type = type;
      s->type = type;
      s->where = gfc_current_locus;
      s->where = gfc_current_locus;
      s->defined = 1;
      s->defined = 1;
      s->ns = gfc_current_ns;
      s->ns = gfc_current_ns;
      return true;
      return true;
    }
    }
  return false;
  return false;
}
}
 
 
 
 
/* Match an ENTRY statement.  */
/* Match an ENTRY statement.  */
 
 
match
match
gfc_match_entry (void)
gfc_match_entry (void)
{
{
  gfc_symbol *proc;
  gfc_symbol *proc;
  gfc_symbol *result;
  gfc_symbol *result;
  gfc_symbol *entry;
  gfc_symbol *entry;
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
  gfc_compile_state state;
  gfc_compile_state state;
  match m;
  match m;
  gfc_entry_list *el;
  gfc_entry_list *el;
  locus old_loc;
  locus old_loc;
  bool module_procedure;
  bool module_procedure;
  char peek_char;
  char peek_char;
  match is_bind_c;
  match is_bind_c;
 
 
  m = gfc_match_name (name);
  m = gfc_match_name (name);
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    return m;
    return m;
 
 
  state = gfc_current_state ();
  state = gfc_current_state ();
  if (state != COMP_SUBROUTINE && state != COMP_FUNCTION)
  if (state != COMP_SUBROUTINE && state != COMP_FUNCTION)
    {
    {
      switch (state)
      switch (state)
        {
        {
          case COMP_PROGRAM:
          case COMP_PROGRAM:
            gfc_error ("ENTRY statement at %C cannot appear within a PROGRAM");
            gfc_error ("ENTRY statement at %C cannot appear within a PROGRAM");
            break;
            break;
          case COMP_MODULE:
          case COMP_MODULE:
            gfc_error ("ENTRY statement at %C cannot appear within a MODULE");
            gfc_error ("ENTRY statement at %C cannot appear within a MODULE");
            break;
            break;
          case COMP_BLOCK_DATA:
          case COMP_BLOCK_DATA:
            gfc_error ("ENTRY statement at %C cannot appear within "
            gfc_error ("ENTRY statement at %C cannot appear within "
                       "a BLOCK DATA");
                       "a BLOCK DATA");
            break;
            break;
          case COMP_INTERFACE:
          case COMP_INTERFACE:
            gfc_error ("ENTRY statement at %C cannot appear within "
            gfc_error ("ENTRY statement at %C cannot appear within "
                       "an INTERFACE");
                       "an INTERFACE");
            break;
            break;
          case COMP_DERIVED:
          case COMP_DERIVED:
            gfc_error ("ENTRY statement at %C cannot appear within "
            gfc_error ("ENTRY statement at %C cannot appear within "
                       "a DERIVED TYPE block");
                       "a DERIVED TYPE block");
            break;
            break;
          case COMP_IF:
          case COMP_IF:
            gfc_error ("ENTRY statement at %C cannot appear within "
            gfc_error ("ENTRY statement at %C cannot appear within "
                       "an IF-THEN block");
                       "an IF-THEN block");
            break;
            break;
          case COMP_DO:
          case COMP_DO:
            gfc_error ("ENTRY statement at %C cannot appear within "
            gfc_error ("ENTRY statement at %C cannot appear within "
                       "a DO block");
                       "a DO block");
            break;
            break;
          case COMP_SELECT:
          case COMP_SELECT:
            gfc_error ("ENTRY statement at %C cannot appear within "
            gfc_error ("ENTRY statement at %C cannot appear within "
                       "a SELECT block");
                       "a SELECT block");
            break;
            break;
          case COMP_FORALL:
          case COMP_FORALL:
            gfc_error ("ENTRY statement at %C cannot appear within "
            gfc_error ("ENTRY statement at %C cannot appear within "
                       "a FORALL block");
                       "a FORALL block");
            break;
            break;
          case COMP_WHERE:
          case COMP_WHERE:
            gfc_error ("ENTRY statement at %C cannot appear within "
            gfc_error ("ENTRY statement at %C cannot appear within "
                       "a WHERE block");
                       "a WHERE block");
            break;
            break;
          case COMP_CONTAINS:
          case COMP_CONTAINS:
            gfc_error ("ENTRY statement at %C cannot appear within "
            gfc_error ("ENTRY statement at %C cannot appear within "
                       "a contained subprogram");
                       "a contained subprogram");
            break;
            break;
          default:
          default:
            gfc_internal_error ("gfc_match_entry(): Bad state");
            gfc_internal_error ("gfc_match_entry(): Bad state");
        }
        }
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  module_procedure = gfc_current_ns->parent != NULL
  module_procedure = gfc_current_ns->parent != NULL
                   && gfc_current_ns->parent->proc_name
                   && gfc_current_ns->parent->proc_name
                   && gfc_current_ns->parent->proc_name->attr.flavor
                   && gfc_current_ns->parent->proc_name->attr.flavor
                      == FL_MODULE;
                      == FL_MODULE;
 
 
  if (gfc_current_ns->parent != NULL
  if (gfc_current_ns->parent != NULL
      && gfc_current_ns->parent->proc_name
      && gfc_current_ns->parent->proc_name
      && !module_procedure)
      && !module_procedure)
    {
    {
      gfc_error("ENTRY statement at %C cannot appear in a "
      gfc_error("ENTRY statement at %C cannot appear in a "
                "contained procedure");
                "contained procedure");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  /* Module function entries need special care in get_proc_name
  /* Module function entries need special care in get_proc_name
     because previous references within the function will have
     because previous references within the function will have
     created symbols attached to the current namespace.  */
     created symbols attached to the current namespace.  */
  if (get_proc_name (name, &entry,
  if (get_proc_name (name, &entry,
                     gfc_current_ns->parent != NULL
                     gfc_current_ns->parent != NULL
                     && module_procedure))
                     && module_procedure))
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  proc = gfc_current_block ();
  proc = gfc_current_block ();
 
 
  /* Make sure that it isn't already declared as BIND(C).  If it is, it
  /* Make sure that it isn't already declared as BIND(C).  If it is, it
     must have been marked BIND(C) with a BIND(C) attribute and that is
     must have been marked BIND(C) with a BIND(C) attribute and that is
     not allowed for procedures.  */
     not allowed for procedures.  */
  if (entry->attr.is_bind_c == 1)
  if (entry->attr.is_bind_c == 1)
    {
    {
      entry->attr.is_bind_c = 0;
      entry->attr.is_bind_c = 0;
      if (entry->old_symbol != NULL)
      if (entry->old_symbol != NULL)
        gfc_error_now ("BIND(C) attribute at %L can only be used for "
        gfc_error_now ("BIND(C) attribute at %L can only be used for "
                       "variables or common blocks",
                       "variables or common blocks",
                       &(entry->old_symbol->declared_at));
                       &(entry->old_symbol->declared_at));
      else
      else
        gfc_error_now ("BIND(C) attribute at %L can only be used for "
        gfc_error_now ("BIND(C) attribute at %L can only be used for "
                       "variables or common blocks", &gfc_current_locus);
                       "variables or common blocks", &gfc_current_locus);
    }
    }
 
 
  /* Check what next non-whitespace character is so we can tell if there
  /* Check what next non-whitespace character is so we can tell if there
     is the required parens if we have a BIND(C).  */
     is the required parens if we have a BIND(C).  */
  gfc_gobble_whitespace ();
  gfc_gobble_whitespace ();
  peek_char = gfc_peek_ascii_char ();
  peek_char = gfc_peek_ascii_char ();
 
 
  if (state == COMP_SUBROUTINE)
  if (state == COMP_SUBROUTINE)
    {
    {
      /* An entry in a subroutine.  */
      /* An entry in a subroutine.  */
      if (!gfc_current_ns->parent && !add_global_entry (name, 1))
      if (!gfc_current_ns->parent && !add_global_entry (name, 1))
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      m = gfc_match_formal_arglist (entry, 0, 1);
      m = gfc_match_formal_arglist (entry, 0, 1);
      if (m != MATCH_YES)
      if (m != MATCH_YES)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      /* Call gfc_match_bind_c with allow_binding_name = true as ENTRY can
      /* Call gfc_match_bind_c with allow_binding_name = true as ENTRY can
         never be an internal procedure.  */
         never be an internal procedure.  */
      is_bind_c = gfc_match_bind_c (entry, true);
      is_bind_c = gfc_match_bind_c (entry, true);
      if (is_bind_c == MATCH_ERROR)
      if (is_bind_c == MATCH_ERROR)
        return MATCH_ERROR;
        return MATCH_ERROR;
      if (is_bind_c == MATCH_YES)
      if (is_bind_c == MATCH_YES)
        {
        {
          if (peek_char != '(')
          if (peek_char != '(')
            {
            {
              gfc_error ("Missing required parentheses before BIND(C) at %C");
              gfc_error ("Missing required parentheses before BIND(C) at %C");
              return MATCH_ERROR;
              return MATCH_ERROR;
            }
            }
            if (gfc_add_is_bind_c (&(entry->attr), entry->name, &(entry->declared_at), 1)
            if (gfc_add_is_bind_c (&(entry->attr), entry->name, &(entry->declared_at), 1)
                == FAILURE)
                == FAILURE)
              return MATCH_ERROR;
              return MATCH_ERROR;
        }
        }
 
 
      if (gfc_add_entry (&entry->attr, entry->name, NULL) == FAILURE
      if (gfc_add_entry (&entry->attr, entry->name, NULL) == FAILURE
          || gfc_add_subroutine (&entry->attr, entry->name, NULL) == FAILURE)
          || gfc_add_subroutine (&entry->attr, entry->name, NULL) == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
    }
    }
  else
  else
    {
    {
      /* An entry in a function.
      /* An entry in a function.
         We need to take special care because writing
         We need to take special care because writing
            ENTRY f()
            ENTRY f()
         as
         as
            ENTRY f
            ENTRY f
         is allowed, whereas
         is allowed, whereas
            ENTRY f() RESULT (r)
            ENTRY f() RESULT (r)
         can't be written as
         can't be written as
            ENTRY f RESULT (r).  */
            ENTRY f RESULT (r).  */
      if (!gfc_current_ns->parent && !add_global_entry (name, 0))
      if (!gfc_current_ns->parent && !add_global_entry (name, 0))
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      old_loc = gfc_current_locus;
      old_loc = gfc_current_locus;
      if (gfc_match_eos () == MATCH_YES)
      if (gfc_match_eos () == MATCH_YES)
        {
        {
          gfc_current_locus = old_loc;
          gfc_current_locus = old_loc;
          /* Match the empty argument list, and add the interface to
          /* Match the empty argument list, and add the interface to
             the symbol.  */
             the symbol.  */
          m = gfc_match_formal_arglist (entry, 0, 1);
          m = gfc_match_formal_arglist (entry, 0, 1);
        }
        }
      else
      else
        m = gfc_match_formal_arglist (entry, 0, 0);
        m = gfc_match_formal_arglist (entry, 0, 0);
 
 
      if (m != MATCH_YES)
      if (m != MATCH_YES)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      result = NULL;
      result = NULL;
 
 
      if (gfc_match_eos () == MATCH_YES)
      if (gfc_match_eos () == MATCH_YES)
        {
        {
          if (gfc_add_entry (&entry->attr, entry->name, NULL) == FAILURE
          if (gfc_add_entry (&entry->attr, entry->name, NULL) == FAILURE
              || gfc_add_function (&entry->attr, entry->name, NULL) == FAILURE)
              || gfc_add_function (&entry->attr, entry->name, NULL) == FAILURE)
            return MATCH_ERROR;
            return MATCH_ERROR;
 
 
          entry->result = entry;
          entry->result = entry;
        }
        }
      else
      else
        {
        {
          m = gfc_match_suffix (entry, &result);
          m = gfc_match_suffix (entry, &result);
          if (m == MATCH_NO)
          if (m == MATCH_NO)
            gfc_syntax_error (ST_ENTRY);
            gfc_syntax_error (ST_ENTRY);
          if (m != MATCH_YES)
          if (m != MATCH_YES)
            return MATCH_ERROR;
            return MATCH_ERROR;
 
 
          if (result)
          if (result)
            {
            {
              if (gfc_add_result (&result->attr, result->name, NULL) == FAILURE
              if (gfc_add_result (&result->attr, result->name, NULL) == FAILURE
                  || gfc_add_entry (&entry->attr, result->name, NULL) == FAILURE
                  || gfc_add_entry (&entry->attr, result->name, NULL) == FAILURE
                  || gfc_add_function (&entry->attr, result->name, NULL)
                  || gfc_add_function (&entry->attr, result->name, NULL)
                  == FAILURE)
                  == FAILURE)
                return MATCH_ERROR;
                return MATCH_ERROR;
              entry->result = result;
              entry->result = result;
            }
            }
          else
          else
            {
            {
              if (gfc_add_entry (&entry->attr, entry->name, NULL) == FAILURE
              if (gfc_add_entry (&entry->attr, entry->name, NULL) == FAILURE
                  || gfc_add_function (&entry->attr, entry->name, NULL) == FAILURE)
                  || gfc_add_function (&entry->attr, entry->name, NULL) == FAILURE)
                return MATCH_ERROR;
                return MATCH_ERROR;
              entry->result = entry;
              entry->result = entry;
            }
            }
        }
        }
    }
    }
 
 
  if (gfc_match_eos () != MATCH_YES)
  if (gfc_match_eos () != MATCH_YES)
    {
    {
      gfc_syntax_error (ST_ENTRY);
      gfc_syntax_error (ST_ENTRY);
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  entry->attr.recursive = proc->attr.recursive;
  entry->attr.recursive = proc->attr.recursive;
  entry->attr.elemental = proc->attr.elemental;
  entry->attr.elemental = proc->attr.elemental;
  entry->attr.pure = proc->attr.pure;
  entry->attr.pure = proc->attr.pure;
 
 
  el = gfc_get_entry_list ();
  el = gfc_get_entry_list ();
  el->sym = entry;
  el->sym = entry;
  el->next = gfc_current_ns->entries;
  el->next = gfc_current_ns->entries;
  gfc_current_ns->entries = el;
  gfc_current_ns->entries = el;
  if (el->next)
  if (el->next)
    el->id = el->next->id + 1;
    el->id = el->next->id + 1;
  else
  else
    el->id = 1;
    el->id = 1;
 
 
  new_st.op = EXEC_ENTRY;
  new_st.op = EXEC_ENTRY;
  new_st.ext.entry = el;
  new_st.ext.entry = el;
 
 
  return MATCH_YES;
  return MATCH_YES;
}
}
 
 
 
 
/* Match a subroutine statement, including optional prefixes.  */
/* Match a subroutine statement, including optional prefixes.  */
 
 
match
match
gfc_match_subroutine (void)
gfc_match_subroutine (void)
{
{
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
  gfc_symbol *sym;
  gfc_symbol *sym;
  match m;
  match m;
  match is_bind_c;
  match is_bind_c;
  char peek_char;
  char peek_char;
  bool allow_binding_name;
  bool allow_binding_name;
 
 
  if (gfc_current_state () != COMP_NONE
  if (gfc_current_state () != COMP_NONE
      && gfc_current_state () != COMP_INTERFACE
      && gfc_current_state () != COMP_INTERFACE
      && gfc_current_state () != COMP_CONTAINS)
      && gfc_current_state () != COMP_CONTAINS)
    return MATCH_NO;
    return MATCH_NO;
 
 
  m = gfc_match_prefix (NULL);
  m = gfc_match_prefix (NULL);
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    return m;
    return m;
 
 
  m = gfc_match ("subroutine% %n", name);
  m = gfc_match ("subroutine% %n", name);
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    return m;
    return m;
 
 
  if (get_proc_name (name, &sym, false))
  if (get_proc_name (name, &sym, false))
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  /* Set declared_at as it might point to, e.g., a PUBLIC statement, if
  /* Set declared_at as it might point to, e.g., a PUBLIC statement, if
     the symbol existed before. */
     the symbol existed before. */
  sym->declared_at = gfc_current_locus;
  sym->declared_at = gfc_current_locus;
 
 
  if (add_hidden_procptr_result (sym) == SUCCESS)
  if (add_hidden_procptr_result (sym) == SUCCESS)
    sym = sym->result;
    sym = sym->result;
 
 
  gfc_new_block = sym;
  gfc_new_block = sym;
 
 
  /* Check what next non-whitespace character is so we can tell if there
  /* Check what next non-whitespace character is so we can tell if there
     is the required parens if we have a BIND(C).  */
     is the required parens if we have a BIND(C).  */
  gfc_gobble_whitespace ();
  gfc_gobble_whitespace ();
  peek_char = gfc_peek_ascii_char ();
  peek_char = gfc_peek_ascii_char ();
 
 
  if (gfc_add_subroutine (&sym->attr, sym->name, NULL) == FAILURE)
  if (gfc_add_subroutine (&sym->attr, sym->name, NULL) == FAILURE)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  if (gfc_match_formal_arglist (sym, 0, 1) != MATCH_YES)
  if (gfc_match_formal_arglist (sym, 0, 1) != MATCH_YES)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  /* Make sure that it isn't already declared as BIND(C).  If it is, it
  /* Make sure that it isn't already declared as BIND(C).  If it is, it
     must have been marked BIND(C) with a BIND(C) attribute and that is
     must have been marked BIND(C) with a BIND(C) attribute and that is
     not allowed for procedures.  */
     not allowed for procedures.  */
  if (sym->attr.is_bind_c == 1)
  if (sym->attr.is_bind_c == 1)
    {
    {
      sym->attr.is_bind_c = 0;
      sym->attr.is_bind_c = 0;
      if (sym->old_symbol != NULL)
      if (sym->old_symbol != NULL)
        gfc_error_now ("BIND(C) attribute at %L can only be used for "
        gfc_error_now ("BIND(C) attribute at %L can only be used for "
                       "variables or common blocks",
                       "variables or common blocks",
                       &(sym->old_symbol->declared_at));
                       &(sym->old_symbol->declared_at));
      else
      else
        gfc_error_now ("BIND(C) attribute at %L can only be used for "
        gfc_error_now ("BIND(C) attribute at %L can only be used for "
                       "variables or common blocks", &gfc_current_locus);
                       "variables or common blocks", &gfc_current_locus);
    }
    }
 
 
  /* C binding names are not allowed for internal procedures.  */
  /* C binding names are not allowed for internal procedures.  */
  if (gfc_current_state () == COMP_CONTAINS
  if (gfc_current_state () == COMP_CONTAINS
      && sym->ns->proc_name->attr.flavor != FL_MODULE)
      && sym->ns->proc_name->attr.flavor != FL_MODULE)
    allow_binding_name = false;
    allow_binding_name = false;
  else
  else
    allow_binding_name = true;
    allow_binding_name = true;
 
 
  /* Here, we are just checking if it has the bind(c) attribute, and if
  /* Here, we are just checking if it has the bind(c) attribute, and if
     so, then we need to make sure it's all correct.  If it doesn't,
     so, then we need to make sure it's all correct.  If it doesn't,
     we still need to continue matching the rest of the subroutine line.  */
     we still need to continue matching the rest of the subroutine line.  */
  is_bind_c = gfc_match_bind_c (sym, allow_binding_name);
  is_bind_c = gfc_match_bind_c (sym, allow_binding_name);
  if (is_bind_c == MATCH_ERROR)
  if (is_bind_c == MATCH_ERROR)
    {
    {
      /* There was an attempt at the bind(c), but it was wrong.  An
      /* There was an attempt at the bind(c), but it was wrong.  An
         error message should have been printed w/in the gfc_match_bind_c
         error message should have been printed w/in the gfc_match_bind_c
         so here we'll just return the MATCH_ERROR.  */
         so here we'll just return the MATCH_ERROR.  */
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  if (is_bind_c == MATCH_YES)
  if (is_bind_c == MATCH_YES)
    {
    {
      /* The following is allowed in the Fortran 2008 draft.  */
      /* The following is allowed in the Fortran 2008 draft.  */
      if (gfc_current_state () == COMP_CONTAINS
      if (gfc_current_state () == COMP_CONTAINS
          && sym->ns->proc_name->attr.flavor != FL_MODULE
          && sym->ns->proc_name->attr.flavor != FL_MODULE
          && gfc_notify_std (GFC_STD_F2008, "Fortran 2008: BIND(C) attribute "
          && gfc_notify_std (GFC_STD_F2008, "Fortran 2008: BIND(C) attribute "
                             "at %L may not be specified for an internal "
                             "at %L may not be specified for an internal "
                             "procedure", &gfc_current_locus)
                             "procedure", &gfc_current_locus)
             == FAILURE)
             == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      if (peek_char != '(')
      if (peek_char != '(')
        {
        {
          gfc_error ("Missing required parentheses before BIND(C) at %C");
          gfc_error ("Missing required parentheses before BIND(C) at %C");
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
      if (gfc_add_is_bind_c (&(sym->attr), sym->name, &(sym->declared_at), 1)
      if (gfc_add_is_bind_c (&(sym->attr), sym->name, &(sym->declared_at), 1)
          == FAILURE)
          == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
    }
    }
 
 
  if (gfc_match_eos () != MATCH_YES)
  if (gfc_match_eos () != MATCH_YES)
    {
    {
      gfc_syntax_error (ST_SUBROUTINE);
      gfc_syntax_error (ST_SUBROUTINE);
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  if (copy_prefix (&sym->attr, &sym->declared_at) == FAILURE)
  if (copy_prefix (&sym->attr, &sym->declared_at) == FAILURE)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  /* Warn if it has the same name as an intrinsic.  */
  /* Warn if it has the same name as an intrinsic.  */
  warn_intrinsic_shadow (sym, false);
  warn_intrinsic_shadow (sym, false);
 
 
  return MATCH_YES;
  return MATCH_YES;
}
}
 
 
 
 
/* Match a BIND(C) specifier, with the optional 'name=' specifier if
/* Match a BIND(C) specifier, with the optional 'name=' specifier if
   given, and set the binding label in either the given symbol (if not
   given, and set the binding label in either the given symbol (if not
   NULL), or in the current_ts.  The symbol may be NULL because we may
   NULL), or in the current_ts.  The symbol may be NULL because we may
   encounter the BIND(C) before the declaration itself.  Return
   encounter the BIND(C) before the declaration itself.  Return
   MATCH_NO if what we're looking at isn't a BIND(C) specifier,
   MATCH_NO if what we're looking at isn't a BIND(C) specifier,
   MATCH_ERROR if it is a BIND(C) clause but an error was encountered,
   MATCH_ERROR if it is a BIND(C) clause but an error was encountered,
   or MATCH_YES if the specifier was correct and the binding label and
   or MATCH_YES if the specifier was correct and the binding label and
   bind(c) fields were set correctly for the given symbol or the
   bind(c) fields were set correctly for the given symbol or the
   current_ts. If allow_binding_name is false, no binding name may be
   current_ts. If allow_binding_name is false, no binding name may be
   given.  */
   given.  */
 
 
match
match
gfc_match_bind_c (gfc_symbol *sym, bool allow_binding_name)
gfc_match_bind_c (gfc_symbol *sym, bool allow_binding_name)
{
{
  /* binding label, if exists */
  /* binding label, if exists */
  char binding_label[GFC_MAX_SYMBOL_LEN + 1];
  char binding_label[GFC_MAX_SYMBOL_LEN + 1];
  match double_quote;
  match double_quote;
  match single_quote;
  match single_quote;
 
 
  /* Initialize the flag that specifies whether we encountered a NAME=
  /* Initialize the flag that specifies whether we encountered a NAME=
     specifier or not.  */
     specifier or not.  */
  has_name_equals = 0;
  has_name_equals = 0;
 
 
  /* Init the first char to nil so we can catch if we don't have
  /* Init the first char to nil so we can catch if we don't have
     the label (name attr) or the symbol name yet.  */
     the label (name attr) or the symbol name yet.  */
  binding_label[0] = '\0';
  binding_label[0] = '\0';
 
 
  /* This much we have to be able to match, in this order, if
  /* This much we have to be able to match, in this order, if
     there is a bind(c) label.  */
     there is a bind(c) label.  */
  if (gfc_match (" bind ( c ") != MATCH_YES)
  if (gfc_match (" bind ( c ") != MATCH_YES)
    return MATCH_NO;
    return MATCH_NO;
 
 
  /* Now see if there is a binding label, or if we've reached the
  /* Now see if there is a binding label, or if we've reached the
     end of the bind(c) attribute without one.  */
     end of the bind(c) attribute without one.  */
  if (gfc_match_char (',') == MATCH_YES)
  if (gfc_match_char (',') == MATCH_YES)
    {
    {
      if (gfc_match (" name = ") != MATCH_YES)
      if (gfc_match (" name = ") != MATCH_YES)
        {
        {
          gfc_error ("Syntax error in NAME= specifier for binding label "
          gfc_error ("Syntax error in NAME= specifier for binding label "
                     "at %C");
                     "at %C");
          /* should give an error message here */
          /* should give an error message here */
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
      has_name_equals = 1;
      has_name_equals = 1;
 
 
      /* Get the opening quote.  */
      /* Get the opening quote.  */
      double_quote = MATCH_YES;
      double_quote = MATCH_YES;
      single_quote = MATCH_YES;
      single_quote = MATCH_YES;
      double_quote = gfc_match_char ('"');
      double_quote = gfc_match_char ('"');
      if (double_quote != MATCH_YES)
      if (double_quote != MATCH_YES)
        single_quote = gfc_match_char ('\'');
        single_quote = gfc_match_char ('\'');
      if (double_quote != MATCH_YES && single_quote != MATCH_YES)
      if (double_quote != MATCH_YES && single_quote != MATCH_YES)
        {
        {
          gfc_error ("Syntax error in NAME= specifier for binding label "
          gfc_error ("Syntax error in NAME= specifier for binding label "
                     "at %C");
                     "at %C");
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
      /* Grab the binding label, using functions that will not lower
      /* Grab the binding label, using functions that will not lower
         case the names automatically.  */
         case the names automatically.  */
      if (gfc_match_name_C (binding_label) != MATCH_YES)
      if (gfc_match_name_C (binding_label) != MATCH_YES)
         return MATCH_ERROR;
         return MATCH_ERROR;
 
 
      /* Get the closing quotation.  */
      /* Get the closing quotation.  */
      if (double_quote == MATCH_YES)
      if (double_quote == MATCH_YES)
        {
        {
          if (gfc_match_char ('"') != MATCH_YES)
          if (gfc_match_char ('"') != MATCH_YES)
            {
            {
              gfc_error ("Missing closing quote '\"' for binding label at %C");
              gfc_error ("Missing closing quote '\"' for binding label at %C");
              /* User started string with '"' so looked to match it.  */
              /* User started string with '"' so looked to match it.  */
              return MATCH_ERROR;
              return MATCH_ERROR;
            }
            }
        }
        }
      else
      else
        {
        {
          if (gfc_match_char ('\'') != MATCH_YES)
          if (gfc_match_char ('\'') != MATCH_YES)
            {
            {
              gfc_error ("Missing closing quote '\'' for binding label at %C");
              gfc_error ("Missing closing quote '\'' for binding label at %C");
              /* User started string with "'" char.  */
              /* User started string with "'" char.  */
              return MATCH_ERROR;
              return MATCH_ERROR;
            }
            }
        }
        }
   }
   }
 
 
  /* Get the required right paren.  */
  /* Get the required right paren.  */
  if (gfc_match_char (')') != MATCH_YES)
  if (gfc_match_char (')') != MATCH_YES)
    {
    {
      gfc_error ("Missing closing paren for binding label at %C");
      gfc_error ("Missing closing paren for binding label at %C");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  if (has_name_equals && !allow_binding_name)
  if (has_name_equals && !allow_binding_name)
    {
    {
      gfc_error ("No binding name is allowed in BIND(C) at %C");
      gfc_error ("No binding name is allowed in BIND(C) at %C");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  if (has_name_equals && sym != NULL && sym->attr.dummy)
  if (has_name_equals && sym != NULL && sym->attr.dummy)
    {
    {
      gfc_error ("For dummy procedure %s, no binding name is "
      gfc_error ("For dummy procedure %s, no binding name is "
                 "allowed in BIND(C) at %C", sym->name);
                 "allowed in BIND(C) at %C", sym->name);
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
 
 
  /* Save the binding label to the symbol.  If sym is null, we're
  /* Save the binding label to the symbol.  If sym is null, we're
     probably matching the typespec attributes of a declaration and
     probably matching the typespec attributes of a declaration and
     haven't gotten the name yet, and therefore, no symbol yet.  */
     haven't gotten the name yet, and therefore, no symbol yet.  */
  if (binding_label[0] != '\0')
  if (binding_label[0] != '\0')
    {
    {
      if (sym != NULL)
      if (sym != NULL)
      {
      {
        strcpy (sym->binding_label, binding_label);
        strcpy (sym->binding_label, binding_label);
      }
      }
      else
      else
        strcpy (curr_binding_label, binding_label);
        strcpy (curr_binding_label, binding_label);
    }
    }
  else if (allow_binding_name)
  else if (allow_binding_name)
    {
    {
      /* No binding label, but if symbol isn't null, we
      /* No binding label, but if symbol isn't null, we
         can set the label for it here.
         can set the label for it here.
         If name="" or allow_binding_name is false, no C binding name is
         If name="" or allow_binding_name is false, no C binding name is
         created. */
         created. */
      if (sym != NULL && sym->name != NULL && has_name_equals == 0)
      if (sym != NULL && sym->name != NULL && has_name_equals == 0)
        strncpy (sym->binding_label, sym->name, strlen (sym->name) + 1);
        strncpy (sym->binding_label, sym->name, strlen (sym->name) + 1);
    }
    }
 
 
  if (has_name_equals && gfc_current_state () == COMP_INTERFACE
  if (has_name_equals && gfc_current_state () == COMP_INTERFACE
      && current_interface.type == INTERFACE_ABSTRACT)
      && current_interface.type == INTERFACE_ABSTRACT)
    {
    {
      gfc_error ("NAME not allowed on BIND(C) for ABSTRACT INTERFACE at %C");
      gfc_error ("NAME not allowed on BIND(C) for ABSTRACT INTERFACE at %C");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  return MATCH_YES;
  return MATCH_YES;
}
}
 
 
 
 
/* Return nonzero if we're currently compiling a contained procedure.  */
/* Return nonzero if we're currently compiling a contained procedure.  */
 
 
static int
static int
contained_procedure (void)
contained_procedure (void)
{
{
  gfc_state_data *s = gfc_state_stack;
  gfc_state_data *s = gfc_state_stack;
 
 
  if ((s->state == COMP_SUBROUTINE || s->state == COMP_FUNCTION)
  if ((s->state == COMP_SUBROUTINE || s->state == COMP_FUNCTION)
      && s->previous != NULL && s->previous->state == COMP_CONTAINS)
      && s->previous != NULL && s->previous->state == COMP_CONTAINS)
    return 1;
    return 1;
 
 
  return 0;
  return 0;
}
}
 
 
/* Set the kind of each enumerator.  The kind is selected such that it is
/* Set the kind of each enumerator.  The kind is selected such that it is
   interoperable with the corresponding C enumeration type, making
   interoperable with the corresponding C enumeration type, making
   sure that -fshort-enums is honored.  */
   sure that -fshort-enums is honored.  */
 
 
static void
static void
set_enum_kind(void)
set_enum_kind(void)
{
{
  enumerator_history *current_history = NULL;
  enumerator_history *current_history = NULL;
  int kind;
  int kind;
  int i;
  int i;
 
 
  if (max_enum == NULL || enum_history == NULL)
  if (max_enum == NULL || enum_history == NULL)
    return;
    return;
 
 
  if (!flag_short_enums)
  if (!flag_short_enums)
    return;
    return;
 
 
  i = 0;
  i = 0;
  do
  do
    {
    {
      kind = gfc_integer_kinds[i++].kind;
      kind = gfc_integer_kinds[i++].kind;
    }
    }
  while (kind < gfc_c_int_kind
  while (kind < gfc_c_int_kind
         && gfc_check_integer_range (max_enum->initializer->value.integer,
         && gfc_check_integer_range (max_enum->initializer->value.integer,
                                     kind) != ARITH_OK);
                                     kind) != ARITH_OK);
 
 
  current_history = enum_history;
  current_history = enum_history;
  while (current_history != NULL)
  while (current_history != NULL)
    {
    {
      current_history->sym->ts.kind = kind;
      current_history->sym->ts.kind = kind;
      current_history = current_history->next;
      current_history = current_history->next;
    }
    }
}
}
 
 
 
 
/* Match any of the various end-block statements.  Returns the type of
/* Match any of the various end-block statements.  Returns the type of
   END to the caller.  The END INTERFACE, END IF, END DO, END SELECT
   END to the caller.  The END INTERFACE, END IF, END DO, END SELECT
   and END BLOCK statements cannot be replaced by a single END statement.  */
   and END BLOCK statements cannot be replaced by a single END statement.  */
 
 
match
match
gfc_match_end (gfc_statement *st)
gfc_match_end (gfc_statement *st)
{
{
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
  gfc_compile_state state;
  gfc_compile_state state;
  locus old_loc;
  locus old_loc;
  const char *block_name;
  const char *block_name;
  const char *target;
  const char *target;
  int eos_ok;
  int eos_ok;
  match m;
  match m;
 
 
  old_loc = gfc_current_locus;
  old_loc = gfc_current_locus;
  if (gfc_match ("end") != MATCH_YES)
  if (gfc_match ("end") != MATCH_YES)
    return MATCH_NO;
    return MATCH_NO;
 
 
  state = gfc_current_state ();
  state = gfc_current_state ();
  block_name = gfc_current_block () == NULL
  block_name = gfc_current_block () == NULL
             ? NULL : gfc_current_block ()->name;
             ? NULL : gfc_current_block ()->name;
 
 
  if (state == COMP_BLOCK && !strcmp (block_name, "block@"))
  if (state == COMP_BLOCK && !strcmp (block_name, "block@"))
    block_name = NULL;
    block_name = NULL;
 
 
  if (state == COMP_CONTAINS || state == COMP_DERIVED_CONTAINS)
  if (state == COMP_CONTAINS || state == COMP_DERIVED_CONTAINS)
    {
    {
      state = gfc_state_stack->previous->state;
      state = gfc_state_stack->previous->state;
      block_name = gfc_state_stack->previous->sym == NULL
      block_name = gfc_state_stack->previous->sym == NULL
                 ? NULL : gfc_state_stack->previous->sym->name;
                 ? NULL : gfc_state_stack->previous->sym->name;
    }
    }
 
 
  switch (state)
  switch (state)
    {
    {
    case COMP_NONE:
    case COMP_NONE:
    case COMP_PROGRAM:
    case COMP_PROGRAM:
      *st = ST_END_PROGRAM;
      *st = ST_END_PROGRAM;
      target = " program";
      target = " program";
      eos_ok = 1;
      eos_ok = 1;
      break;
      break;
 
 
    case COMP_SUBROUTINE:
    case COMP_SUBROUTINE:
      *st = ST_END_SUBROUTINE;
      *st = ST_END_SUBROUTINE;
      target = " subroutine";
      target = " subroutine";
      eos_ok = !contained_procedure ();
      eos_ok = !contained_procedure ();
      break;
      break;
 
 
    case COMP_FUNCTION:
    case COMP_FUNCTION:
      *st = ST_END_FUNCTION;
      *st = ST_END_FUNCTION;
      target = " function";
      target = " function";
      eos_ok = !contained_procedure ();
      eos_ok = !contained_procedure ();
      break;
      break;
 
 
    case COMP_BLOCK_DATA:
    case COMP_BLOCK_DATA:
      *st = ST_END_BLOCK_DATA;
      *st = ST_END_BLOCK_DATA;
      target = " block data";
      target = " block data";
      eos_ok = 1;
      eos_ok = 1;
      break;
      break;
 
 
    case COMP_MODULE:
    case COMP_MODULE:
      *st = ST_END_MODULE;
      *st = ST_END_MODULE;
      target = " module";
      target = " module";
      eos_ok = 1;
      eos_ok = 1;
      break;
      break;
 
 
    case COMP_INTERFACE:
    case COMP_INTERFACE:
      *st = ST_END_INTERFACE;
      *st = ST_END_INTERFACE;
      target = " interface";
      target = " interface";
      eos_ok = 0;
      eos_ok = 0;
      break;
      break;
 
 
    case COMP_DERIVED:
    case COMP_DERIVED:
    case COMP_DERIVED_CONTAINS:
    case COMP_DERIVED_CONTAINS:
      *st = ST_END_TYPE;
      *st = ST_END_TYPE;
      target = " type";
      target = " type";
      eos_ok = 0;
      eos_ok = 0;
      break;
      break;
 
 
    case COMP_BLOCK:
    case COMP_BLOCK:
      *st = ST_END_BLOCK;
      *st = ST_END_BLOCK;
      target = " block";
      target = " block";
      eos_ok = 0;
      eos_ok = 0;
      break;
      break;
 
 
    case COMP_IF:
    case COMP_IF:
      *st = ST_ENDIF;
      *st = ST_ENDIF;
      target = " if";
      target = " if";
      eos_ok = 0;
      eos_ok = 0;
      break;
      break;
 
 
    case COMP_DO:
    case COMP_DO:
      *st = ST_ENDDO;
      *st = ST_ENDDO;
      target = " do";
      target = " do";
      eos_ok = 0;
      eos_ok = 0;
      break;
      break;
 
 
    case COMP_SELECT:
    case COMP_SELECT:
    case COMP_SELECT_TYPE:
    case COMP_SELECT_TYPE:
      *st = ST_END_SELECT;
      *st = ST_END_SELECT;
      target = " select";
      target = " select";
      eos_ok = 0;
      eos_ok = 0;
      break;
      break;
 
 
    case COMP_FORALL:
    case COMP_FORALL:
      *st = ST_END_FORALL;
      *st = ST_END_FORALL;
      target = " forall";
      target = " forall";
      eos_ok = 0;
      eos_ok = 0;
      break;
      break;
 
 
    case COMP_WHERE:
    case COMP_WHERE:
      *st = ST_END_WHERE;
      *st = ST_END_WHERE;
      target = " where";
      target = " where";
      eos_ok = 0;
      eos_ok = 0;
      break;
      break;
 
 
    case COMP_ENUM:
    case COMP_ENUM:
      *st = ST_END_ENUM;
      *st = ST_END_ENUM;
      target = " enum";
      target = " enum";
      eos_ok = 0;
      eos_ok = 0;
      last_initializer = NULL;
      last_initializer = NULL;
      set_enum_kind ();
      set_enum_kind ();
      gfc_free_enum_history ();
      gfc_free_enum_history ();
      break;
      break;
 
 
    default:
    default:
      gfc_error ("Unexpected END statement at %C");
      gfc_error ("Unexpected END statement at %C");
      goto cleanup;
      goto cleanup;
    }
    }
 
 
  if (gfc_match_eos () == MATCH_YES)
  if (gfc_match_eos () == MATCH_YES)
    {
    {
      if (!eos_ok)
      if (!eos_ok)
        {
        {
          /* We would have required END [something].  */
          /* We would have required END [something].  */
          gfc_error ("%s statement expected at %L",
          gfc_error ("%s statement expected at %L",
                     gfc_ascii_statement (*st), &old_loc);
                     gfc_ascii_statement (*st), &old_loc);
          goto cleanup;
          goto cleanup;
        }
        }
 
 
      return MATCH_YES;
      return MATCH_YES;
    }
    }
 
 
  /* Verify that we've got the sort of end-block that we're expecting.  */
  /* Verify that we've got the sort of end-block that we're expecting.  */
  if (gfc_match (target) != MATCH_YES)
  if (gfc_match (target) != MATCH_YES)
    {
    {
      gfc_error ("Expecting %s statement at %C", gfc_ascii_statement (*st));
      gfc_error ("Expecting %s statement at %C", gfc_ascii_statement (*st));
      goto cleanup;
      goto cleanup;
    }
    }
 
 
  /* If we're at the end, make sure a block name wasn't required.  */
  /* If we're at the end, make sure a block name wasn't required.  */
  if (gfc_match_eos () == MATCH_YES)
  if (gfc_match_eos () == MATCH_YES)
    {
    {
 
 
      if (*st != ST_ENDDO && *st != ST_ENDIF && *st != ST_END_SELECT
      if (*st != ST_ENDDO && *st != ST_ENDIF && *st != ST_END_SELECT
          && *st != ST_END_FORALL && *st != ST_END_WHERE && *st != ST_END_BLOCK)
          && *st != ST_END_FORALL && *st != ST_END_WHERE && *st != ST_END_BLOCK)
        return MATCH_YES;
        return MATCH_YES;
 
 
      if (!block_name)
      if (!block_name)
        return MATCH_YES;
        return MATCH_YES;
 
 
      gfc_error ("Expected block name of '%s' in %s statement at %C",
      gfc_error ("Expected block name of '%s' in %s statement at %C",
                 block_name, gfc_ascii_statement (*st));
                 block_name, gfc_ascii_statement (*st));
 
 
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  /* END INTERFACE has a special handler for its several possible endings.  */
  /* END INTERFACE has a special handler for its several possible endings.  */
  if (*st == ST_END_INTERFACE)
  if (*st == ST_END_INTERFACE)
    return gfc_match_end_interface ();
    return gfc_match_end_interface ();
 
 
  /* We haven't hit the end of statement, so what is left must be an
  /* We haven't hit the end of statement, so what is left must be an
     end-name.  */
     end-name.  */
  m = gfc_match_space ();
  m = gfc_match_space ();
  if (m == MATCH_YES)
  if (m == MATCH_YES)
    m = gfc_match_name (name);
    m = gfc_match_name (name);
 
 
  if (m == MATCH_NO)
  if (m == MATCH_NO)
    gfc_error ("Expected terminating name at %C");
    gfc_error ("Expected terminating name at %C");
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    goto cleanup;
    goto cleanup;
 
 
  if (block_name == NULL)
  if (block_name == NULL)
    goto syntax;
    goto syntax;
 
 
  if (strcmp (name, block_name) != 0 && strcmp (block_name, "ppr@") != 0)
  if (strcmp (name, block_name) != 0 && strcmp (block_name, "ppr@") != 0)
    {
    {
      gfc_error ("Expected label '%s' for %s statement at %C", block_name,
      gfc_error ("Expected label '%s' for %s statement at %C", block_name,
                 gfc_ascii_statement (*st));
                 gfc_ascii_statement (*st));
      goto cleanup;
      goto cleanup;
    }
    }
  /* Procedure pointer as function result.  */
  /* Procedure pointer as function result.  */
  else if (strcmp (block_name, "ppr@") == 0
  else if (strcmp (block_name, "ppr@") == 0
           && strcmp (name, gfc_current_block ()->ns->proc_name->name) != 0)
           && strcmp (name, gfc_current_block ()->ns->proc_name->name) != 0)
    {
    {
      gfc_error ("Expected label '%s' for %s statement at %C",
      gfc_error ("Expected label '%s' for %s statement at %C",
                 gfc_current_block ()->ns->proc_name->name,
                 gfc_current_block ()->ns->proc_name->name,
                 gfc_ascii_statement (*st));
                 gfc_ascii_statement (*st));
      goto cleanup;
      goto cleanup;
    }
    }
 
 
  if (gfc_match_eos () == MATCH_YES)
  if (gfc_match_eos () == MATCH_YES)
    return MATCH_YES;
    return MATCH_YES;
 
 
syntax:
syntax:
  gfc_syntax_error (*st);
  gfc_syntax_error (*st);
 
 
cleanup:
cleanup:
  gfc_current_locus = old_loc;
  gfc_current_locus = old_loc;
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
 
 
/***************** Attribute declaration statements ****************/
/***************** Attribute declaration statements ****************/
 
 
/* Set the attribute of a single variable.  */
/* Set the attribute of a single variable.  */
 
 
static match
static match
attr_decl1 (void)
attr_decl1 (void)
{
{
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
  gfc_array_spec *as;
  gfc_array_spec *as;
  gfc_symbol *sym;
  gfc_symbol *sym;
  locus var_locus;
  locus var_locus;
  match m;
  match m;
 
 
  as = NULL;
  as = NULL;
 
 
  m = gfc_match_name (name);
  m = gfc_match_name (name);
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    goto cleanup;
    goto cleanup;
 
 
  if (find_special (name, &sym, false))
  if (find_special (name, &sym, false))
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  var_locus = gfc_current_locus;
  var_locus = gfc_current_locus;
 
 
  /* Deal with possible array specification for certain attributes.  */
  /* Deal with possible array specification for certain attributes.  */
  if (current_attr.dimension
  if (current_attr.dimension
      || current_attr.allocatable
      || current_attr.allocatable
      || current_attr.pointer
      || current_attr.pointer
      || current_attr.target)
      || current_attr.target)
    {
    {
      m = gfc_match_array_spec (&as);
      m = gfc_match_array_spec (&as);
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        goto cleanup;
        goto cleanup;
 
 
      if (current_attr.dimension && m == MATCH_NO)
      if (current_attr.dimension && m == MATCH_NO)
        {
        {
          gfc_error ("Missing array specification at %L in DIMENSION "
          gfc_error ("Missing array specification at %L in DIMENSION "
                     "statement", &var_locus);
                     "statement", &var_locus);
          m = MATCH_ERROR;
          m = MATCH_ERROR;
          goto cleanup;
          goto cleanup;
        }
        }
 
 
      if (current_attr.dimension && sym->value)
      if (current_attr.dimension && sym->value)
        {
        {
          gfc_error ("Dimensions specified for %s at %L after its "
          gfc_error ("Dimensions specified for %s at %L after its "
                     "initialisation", sym->name, &var_locus);
                     "initialisation", sym->name, &var_locus);
          m = MATCH_ERROR;
          m = MATCH_ERROR;
          goto cleanup;
          goto cleanup;
        }
        }
 
 
      if ((current_attr.allocatable || current_attr.pointer)
      if ((current_attr.allocatable || current_attr.pointer)
          && (m == MATCH_YES) && (as->type != AS_DEFERRED))
          && (m == MATCH_YES) && (as->type != AS_DEFERRED))
        {
        {
          gfc_error ("Array specification must be deferred at %L", &var_locus);
          gfc_error ("Array specification must be deferred at %L", &var_locus);
          m = MATCH_ERROR;
          m = MATCH_ERROR;
          goto cleanup;
          goto cleanup;
        }
        }
    }
    }
 
 
  /* Update symbol table.  DIMENSION attribute is set in
  /* Update symbol table.  DIMENSION attribute is set in
     gfc_set_array_spec().  For CLASS variables, this must be applied
     gfc_set_array_spec().  For CLASS variables, this must be applied
     to the first component, or '$data' field.  */
     to the first component, or '$data' field.  */
  if (sym->ts.type == BT_CLASS && sym->ts.u.derived)
  if (sym->ts.type == BT_CLASS && sym->ts.u.derived)
    {
    {
      gfc_component *comp;
      gfc_component *comp;
      comp = gfc_find_component (sym->ts.u.derived, "$data", true, true);
      comp = gfc_find_component (sym->ts.u.derived, "$data", true, true);
      if (comp == NULL || gfc_copy_attr (&comp->attr, &current_attr,
      if (comp == NULL || gfc_copy_attr (&comp->attr, &current_attr,
                                         &var_locus) == FAILURE)
                                         &var_locus) == FAILURE)
        {
        {
          m = MATCH_ERROR;
          m = MATCH_ERROR;
          goto cleanup;
          goto cleanup;
        }
        }
      sym->attr.class_ok = (sym->attr.class_ok
      sym->attr.class_ok = (sym->attr.class_ok
                              || current_attr.allocatable
                              || current_attr.allocatable
                              || current_attr.pointer);
                              || current_attr.pointer);
    }
    }
  else
  else
    {
    {
      if (current_attr.dimension == 0
      if (current_attr.dimension == 0
            && gfc_copy_attr (&sym->attr, &current_attr, &var_locus) == FAILURE)
            && gfc_copy_attr (&sym->attr, &current_attr, &var_locus) == FAILURE)
        {
        {
          m = MATCH_ERROR;
          m = MATCH_ERROR;
          goto cleanup;
          goto cleanup;
        }
        }
    }
    }
 
 
  if (gfc_set_array_spec (sym, as, &var_locus) == FAILURE)
  if (gfc_set_array_spec (sym, as, &var_locus) == FAILURE)
    {
    {
      m = MATCH_ERROR;
      m = MATCH_ERROR;
      goto cleanup;
      goto cleanup;
    }
    }
 
 
  if (sym->attr.cray_pointee && sym->as != NULL)
  if (sym->attr.cray_pointee && sym->as != NULL)
    {
    {
      /* Fix the array spec.  */
      /* Fix the array spec.  */
      m = gfc_mod_pointee_as (sym->as);
      m = gfc_mod_pointee_as (sym->as);
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        goto cleanup;
        goto cleanup;
    }
    }
 
 
  if (gfc_add_attribute (&sym->attr, &var_locus) == FAILURE)
  if (gfc_add_attribute (&sym->attr, &var_locus) == FAILURE)
    {
    {
      m = MATCH_ERROR;
      m = MATCH_ERROR;
      goto cleanup;
      goto cleanup;
    }
    }
 
 
  if ((current_attr.external || current_attr.intrinsic)
  if ((current_attr.external || current_attr.intrinsic)
      && sym->attr.flavor != FL_PROCEDURE
      && sym->attr.flavor != FL_PROCEDURE
      && gfc_add_flavor (&sym->attr, FL_PROCEDURE, sym->name, NULL) == FAILURE)
      && gfc_add_flavor (&sym->attr, FL_PROCEDURE, sym->name, NULL) == FAILURE)
    {
    {
      m = MATCH_ERROR;
      m = MATCH_ERROR;
      goto cleanup;
      goto cleanup;
    }
    }
 
 
  add_hidden_procptr_result (sym);
  add_hidden_procptr_result (sym);
 
 
  return MATCH_YES;
  return MATCH_YES;
 
 
cleanup:
cleanup:
  gfc_free_array_spec (as);
  gfc_free_array_spec (as);
  return m;
  return m;
}
}
 
 
 
 
/* Generic attribute declaration subroutine.  Used for attributes that
/* Generic attribute declaration subroutine.  Used for attributes that
   just have a list of names.  */
   just have a list of names.  */
 
 
static match
static match
attr_decl (void)
attr_decl (void)
{
{
  match m;
  match m;
 
 
  /* Gobble the optional double colon, by simply ignoring the result
  /* Gobble the optional double colon, by simply ignoring the result
     of gfc_match().  */
     of gfc_match().  */
  gfc_match (" ::");
  gfc_match (" ::");
 
 
  for (;;)
  for (;;)
    {
    {
      m = attr_decl1 ();
      m = attr_decl1 ();
      if (m != MATCH_YES)
      if (m != MATCH_YES)
        break;
        break;
 
 
      if (gfc_match_eos () == MATCH_YES)
      if (gfc_match_eos () == MATCH_YES)
        {
        {
          m = MATCH_YES;
          m = MATCH_YES;
          break;
          break;
        }
        }
 
 
      if (gfc_match_char (',') != MATCH_YES)
      if (gfc_match_char (',') != MATCH_YES)
        {
        {
          gfc_error ("Unexpected character in variable list at %C");
          gfc_error ("Unexpected character in variable list at %C");
          m = MATCH_ERROR;
          m = MATCH_ERROR;
          break;
          break;
        }
        }
    }
    }
 
 
  return m;
  return m;
}
}
 
 
 
 
/* This routine matches Cray Pointer declarations of the form:
/* This routine matches Cray Pointer declarations of the form:
   pointer ( <pointer>, <pointee> )
   pointer ( <pointer>, <pointee> )
   or
   or
   pointer ( <pointer1>, <pointee1> ), ( <pointer2>, <pointee2> ), ...
   pointer ( <pointer1>, <pointee1> ), ( <pointer2>, <pointee2> ), ...
   The pointer, if already declared, should be an integer.  Otherwise, we
   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
   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
   be either a scalar, or an array declaration.  No space is allocated for
   the pointee.  For the statement
   the pointee.  For the statement
   pointer (ipt, ar(10))
   pointer (ipt, ar(10))
   any subsequent uses of ar will be translated (in C-notation) as
   any subsequent uses of ar will be translated (in C-notation) as
   ar(i) => ((<type> *) ipt)(i)
   ar(i) => ((<type> *) ipt)(i)
   After gimplification, pointee variable will disappear in the code.  */
   After gimplification, pointee variable will disappear in the code.  */
 
 
static match
static match
cray_pointer_decl (void)
cray_pointer_decl (void)
{
{
  match m;
  match m;
  gfc_array_spec *as;
  gfc_array_spec *as;
  gfc_symbol *cptr; /* Pointer symbol.  */
  gfc_symbol *cptr; /* Pointer symbol.  */
  gfc_symbol *cpte; /* Pointee symbol.  */
  gfc_symbol *cpte; /* Pointee symbol.  */
  locus var_locus;
  locus var_locus;
  bool done = false;
  bool done = false;
 
 
  while (!done)
  while (!done)
    {
    {
      if (gfc_match_char ('(') != MATCH_YES)
      if (gfc_match_char ('(') != MATCH_YES)
        {
        {
          gfc_error ("Expected '(' at %C");
          gfc_error ("Expected '(' at %C");
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
      /* Match pointer.  */
      /* Match pointer.  */
      var_locus = gfc_current_locus;
      var_locus = gfc_current_locus;
      gfc_clear_attr (&current_attr);
      gfc_clear_attr (&current_attr);
      gfc_add_cray_pointer (&current_attr, &var_locus);
      gfc_add_cray_pointer (&current_attr, &var_locus);
      current_ts.type = BT_INTEGER;
      current_ts.type = BT_INTEGER;
      current_ts.kind = gfc_index_integer_kind;
      current_ts.kind = gfc_index_integer_kind;
 
 
      m = gfc_match_symbol (&cptr, 0);
      m = gfc_match_symbol (&cptr, 0);
      if (m != MATCH_YES)
      if (m != MATCH_YES)
        {
        {
          gfc_error ("Expected variable name at %C");
          gfc_error ("Expected variable name at %C");
          return m;
          return m;
        }
        }
 
 
      if (gfc_add_cray_pointer (&cptr->attr, &var_locus) == FAILURE)
      if (gfc_add_cray_pointer (&cptr->attr, &var_locus) == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      gfc_set_sym_referenced (cptr);
      gfc_set_sym_referenced (cptr);
 
 
      if (cptr->ts.type == BT_UNKNOWN) /* Override the type, if necessary.  */
      if (cptr->ts.type == BT_UNKNOWN) /* Override the type, if necessary.  */
        {
        {
          cptr->ts.type = BT_INTEGER;
          cptr->ts.type = BT_INTEGER;
          cptr->ts.kind = gfc_index_integer_kind;
          cptr->ts.kind = gfc_index_integer_kind;
        }
        }
      else if (cptr->ts.type != BT_INTEGER)
      else if (cptr->ts.type != BT_INTEGER)
        {
        {
          gfc_error ("Cray pointer at %C must be an integer");
          gfc_error ("Cray pointer at %C must be an integer");
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
      else if (cptr->ts.kind < gfc_index_integer_kind)
      else if (cptr->ts.kind < gfc_index_integer_kind)
        gfc_warning ("Cray pointer at %C has %d bytes of precision;"
        gfc_warning ("Cray pointer at %C has %d bytes of precision;"
                     " memory addresses require %d bytes",
                     " memory addresses require %d bytes",
                     cptr->ts.kind, gfc_index_integer_kind);
                     cptr->ts.kind, gfc_index_integer_kind);
 
 
      if (gfc_match_char (',') != MATCH_YES)
      if (gfc_match_char (',') != MATCH_YES)
        {
        {
          gfc_error ("Expected \",\" at %C");
          gfc_error ("Expected \",\" at %C");
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
      /* Match Pointee.  */
      /* Match Pointee.  */
      var_locus = gfc_current_locus;
      var_locus = gfc_current_locus;
      gfc_clear_attr (&current_attr);
      gfc_clear_attr (&current_attr);
      gfc_add_cray_pointee (&current_attr, &var_locus);
      gfc_add_cray_pointee (&current_attr, &var_locus);
      current_ts.type = BT_UNKNOWN;
      current_ts.type = BT_UNKNOWN;
      current_ts.kind = 0;
      current_ts.kind = 0;
 
 
      m = gfc_match_symbol (&cpte, 0);
      m = gfc_match_symbol (&cpte, 0);
      if (m != MATCH_YES)
      if (m != MATCH_YES)
        {
        {
          gfc_error ("Expected variable name at %C");
          gfc_error ("Expected variable name at %C");
          return m;
          return m;
        }
        }
 
 
      /* Check for an optional array spec.  */
      /* Check for an optional array spec.  */
      m = gfc_match_array_spec (&as);
      m = gfc_match_array_spec (&as);
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        {
        {
          gfc_free_array_spec (as);
          gfc_free_array_spec (as);
          return m;
          return m;
        }
        }
      else if (m == MATCH_NO)
      else if (m == MATCH_NO)
        {
        {
          gfc_free_array_spec (as);
          gfc_free_array_spec (as);
          as = NULL;
          as = NULL;
        }
        }
 
 
      if (gfc_add_cray_pointee (&cpte->attr, &var_locus) == FAILURE)
      if (gfc_add_cray_pointee (&cpte->attr, &var_locus) == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      gfc_set_sym_referenced (cpte);
      gfc_set_sym_referenced (cpte);
 
 
      if (cpte->as == NULL)
      if (cpte->as == NULL)
        {
        {
          if (gfc_set_array_spec (cpte, as, &var_locus) == FAILURE)
          if (gfc_set_array_spec (cpte, as, &var_locus) == FAILURE)
            gfc_internal_error ("Couldn't set Cray pointee array spec.");
            gfc_internal_error ("Couldn't set Cray pointee array spec.");
        }
        }
      else if (as != NULL)
      else if (as != NULL)
        {
        {
          gfc_error ("Duplicate array spec for Cray pointee at %C");
          gfc_error ("Duplicate array spec for Cray pointee at %C");
          gfc_free_array_spec (as);
          gfc_free_array_spec (as);
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
      as = NULL;
      as = NULL;
 
 
      if (cpte->as != NULL)
      if (cpte->as != NULL)
        {
        {
          /* Fix array spec.  */
          /* Fix array spec.  */
          m = gfc_mod_pointee_as (cpte->as);
          m = gfc_mod_pointee_as (cpte->as);
          if (m == MATCH_ERROR)
          if (m == MATCH_ERROR)
            return m;
            return m;
        }
        }
 
 
      /* Point the Pointee at the Pointer.  */
      /* Point the Pointee at the Pointer.  */
      cpte->cp_pointer = cptr;
      cpte->cp_pointer = cptr;
 
 
      if (gfc_match_char (')') != MATCH_YES)
      if (gfc_match_char (')') != MATCH_YES)
        {
        {
          gfc_error ("Expected \")\" at %C");
          gfc_error ("Expected \")\" at %C");
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
      m = gfc_match_char (',');
      m = gfc_match_char (',');
      if (m != MATCH_YES)
      if (m != MATCH_YES)
        done = true; /* Stop searching for more declarations.  */
        done = true; /* Stop searching for more declarations.  */
 
 
    }
    }
 
 
  if (m == MATCH_ERROR /* Failed when trying to find ',' above.  */
  if (m == MATCH_ERROR /* Failed when trying to find ',' above.  */
      || gfc_match_eos () != MATCH_YES)
      || gfc_match_eos () != MATCH_YES)
    {
    {
      gfc_error ("Expected \",\" or end of statement at %C");
      gfc_error ("Expected \",\" or end of statement at %C");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
  return MATCH_YES;
  return MATCH_YES;
}
}
 
 
 
 
match
match
gfc_match_external (void)
gfc_match_external (void)
{
{
 
 
  gfc_clear_attr (&current_attr);
  gfc_clear_attr (&current_attr);
  current_attr.external = 1;
  current_attr.external = 1;
 
 
  return attr_decl ();
  return attr_decl ();
}
}
 
 
 
 
match
match
gfc_match_intent (void)
gfc_match_intent (void)
{
{
  sym_intent intent;
  sym_intent intent;
 
 
  /* This is not allowed within a BLOCK construct!  */
  /* This is not allowed within a BLOCK construct!  */
  if (gfc_current_state () == COMP_BLOCK)
  if (gfc_current_state () == COMP_BLOCK)
    {
    {
      gfc_error ("INTENT is not allowed inside of BLOCK at %C");
      gfc_error ("INTENT is not allowed inside of BLOCK at %C");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  intent = match_intent_spec ();
  intent = match_intent_spec ();
  if (intent == INTENT_UNKNOWN)
  if (intent == INTENT_UNKNOWN)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  gfc_clear_attr (&current_attr);
  gfc_clear_attr (&current_attr);
  current_attr.intent = intent;
  current_attr.intent = intent;
 
 
  return attr_decl ();
  return attr_decl ();
}
}
 
 
 
 
match
match
gfc_match_intrinsic (void)
gfc_match_intrinsic (void)
{
{
 
 
  gfc_clear_attr (&current_attr);
  gfc_clear_attr (&current_attr);
  current_attr.intrinsic = 1;
  current_attr.intrinsic = 1;
 
 
  return attr_decl ();
  return attr_decl ();
}
}
 
 
 
 
match
match
gfc_match_optional (void)
gfc_match_optional (void)
{
{
  /* This is not allowed within a BLOCK construct!  */
  /* This is not allowed within a BLOCK construct!  */
  if (gfc_current_state () == COMP_BLOCK)
  if (gfc_current_state () == COMP_BLOCK)
    {
    {
      gfc_error ("OPTIONAL is not allowed inside of BLOCK at %C");
      gfc_error ("OPTIONAL is not allowed inside of BLOCK at %C");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  gfc_clear_attr (&current_attr);
  gfc_clear_attr (&current_attr);
  current_attr.optional = 1;
  current_attr.optional = 1;
 
 
  return attr_decl ();
  return attr_decl ();
}
}
 
 
 
 
match
match
gfc_match_pointer (void)
gfc_match_pointer (void)
{
{
  gfc_gobble_whitespace ();
  gfc_gobble_whitespace ();
  if (gfc_peek_ascii_char () == '(')
  if (gfc_peek_ascii_char () == '(')
    {
    {
      if (!gfc_option.flag_cray_pointer)
      if (!gfc_option.flag_cray_pointer)
        {
        {
          gfc_error ("Cray pointer declaration at %C requires -fcray-pointer "
          gfc_error ("Cray pointer declaration at %C requires -fcray-pointer "
                     "flag");
                     "flag");
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
      return cray_pointer_decl ();
      return cray_pointer_decl ();
    }
    }
  else
  else
    {
    {
      gfc_clear_attr (&current_attr);
      gfc_clear_attr (&current_attr);
      current_attr.pointer = 1;
      current_attr.pointer = 1;
 
 
      return attr_decl ();
      return attr_decl ();
    }
    }
}
}
 
 
 
 
match
match
gfc_match_allocatable (void)
gfc_match_allocatable (void)
{
{
  gfc_clear_attr (&current_attr);
  gfc_clear_attr (&current_attr);
  current_attr.allocatable = 1;
  current_attr.allocatable = 1;
 
 
  return attr_decl ();
  return attr_decl ();
}
}
 
 
 
 
match
match
gfc_match_dimension (void)
gfc_match_dimension (void)
{
{
  gfc_clear_attr (&current_attr);
  gfc_clear_attr (&current_attr);
  current_attr.dimension = 1;
  current_attr.dimension = 1;
 
 
  return attr_decl ();
  return attr_decl ();
}
}
 
 
 
 
match
match
gfc_match_target (void)
gfc_match_target (void)
{
{
  gfc_clear_attr (&current_attr);
  gfc_clear_attr (&current_attr);
  current_attr.target = 1;
  current_attr.target = 1;
 
 
  return attr_decl ();
  return attr_decl ();
}
}
 
 
 
 
/* Match the list of entities being specified in a PUBLIC or PRIVATE
/* Match the list of entities being specified in a PUBLIC or PRIVATE
   statement.  */
   statement.  */
 
 
static match
static match
access_attr_decl (gfc_statement st)
access_attr_decl (gfc_statement st)
{
{
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
  interface_type type;
  interface_type type;
  gfc_user_op *uop;
  gfc_user_op *uop;
  gfc_symbol *sym;
  gfc_symbol *sym;
  gfc_intrinsic_op op;
  gfc_intrinsic_op op;
  match m;
  match m;
 
 
  if (gfc_match (" ::") == MATCH_NO && gfc_match_space () == MATCH_NO)
  if (gfc_match (" ::") == MATCH_NO && gfc_match_space () == MATCH_NO)
    goto done;
    goto done;
 
 
  for (;;)
  for (;;)
    {
    {
      m = gfc_match_generic_spec (&type, name, &op);
      m = gfc_match_generic_spec (&type, name, &op);
      if (m == MATCH_NO)
      if (m == MATCH_NO)
        goto syntax;
        goto syntax;
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      switch (type)
      switch (type)
        {
        {
        case INTERFACE_NAMELESS:
        case INTERFACE_NAMELESS:
        case INTERFACE_ABSTRACT:
        case INTERFACE_ABSTRACT:
          goto syntax;
          goto syntax;
 
 
        case INTERFACE_GENERIC:
        case INTERFACE_GENERIC:
          if (gfc_get_symbol (name, NULL, &sym))
          if (gfc_get_symbol (name, NULL, &sym))
            goto done;
            goto done;
 
 
          if (gfc_add_access (&sym->attr, (st == ST_PUBLIC)
          if (gfc_add_access (&sym->attr, (st == ST_PUBLIC)
                                          ? ACCESS_PUBLIC : ACCESS_PRIVATE,
                                          ? ACCESS_PUBLIC : ACCESS_PRIVATE,
                              sym->name, NULL) == FAILURE)
                              sym->name, NULL) == FAILURE)
            return MATCH_ERROR;
            return MATCH_ERROR;
 
 
          break;
          break;
 
 
        case INTERFACE_INTRINSIC_OP:
        case INTERFACE_INTRINSIC_OP:
          if (gfc_current_ns->operator_access[op] == ACCESS_UNKNOWN)
          if (gfc_current_ns->operator_access[op] == ACCESS_UNKNOWN)
            {
            {
              gfc_current_ns->operator_access[op] =
              gfc_current_ns->operator_access[op] =
                (st == ST_PUBLIC) ? ACCESS_PUBLIC : ACCESS_PRIVATE;
                (st == ST_PUBLIC) ? ACCESS_PUBLIC : ACCESS_PRIVATE;
            }
            }
          else
          else
            {
            {
              gfc_error ("Access specification of the %s operator at %C has "
              gfc_error ("Access specification of the %s operator at %C has "
                         "already been specified", gfc_op2string (op));
                         "already been specified", gfc_op2string (op));
              goto done;
              goto done;
            }
            }
 
 
          break;
          break;
 
 
        case INTERFACE_USER_OP:
        case INTERFACE_USER_OP:
          uop = gfc_get_uop (name);
          uop = gfc_get_uop (name);
 
 
          if (uop->access == ACCESS_UNKNOWN)
          if (uop->access == ACCESS_UNKNOWN)
            {
            {
              uop->access = (st == ST_PUBLIC)
              uop->access = (st == ST_PUBLIC)
                          ? ACCESS_PUBLIC : ACCESS_PRIVATE;
                          ? ACCESS_PUBLIC : ACCESS_PRIVATE;
            }
            }
          else
          else
            {
            {
              gfc_error ("Access specification of the .%s. operator at %C "
              gfc_error ("Access specification of the .%s. operator at %C "
                         "has already been specified", sym->name);
                         "has already been specified", sym->name);
              goto done;
              goto done;
            }
            }
 
 
          break;
          break;
        }
        }
 
 
      if (gfc_match_char (',') == MATCH_NO)
      if (gfc_match_char (',') == MATCH_NO)
        break;
        break;
    }
    }
 
 
  if (gfc_match_eos () != MATCH_YES)
  if (gfc_match_eos () != MATCH_YES)
    goto syntax;
    goto syntax;
  return MATCH_YES;
  return MATCH_YES;
 
 
syntax:
syntax:
  gfc_syntax_error (st);
  gfc_syntax_error (st);
 
 
done:
done:
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
match
match
gfc_match_protected (void)
gfc_match_protected (void)
{
{
  gfc_symbol *sym;
  gfc_symbol *sym;
  match m;
  match m;
 
 
  if (gfc_current_ns->proc_name->attr.flavor != FL_MODULE)
  if (gfc_current_ns->proc_name->attr.flavor != FL_MODULE)
    {
    {
       gfc_error ("PROTECTED at %C only allowed in specification "
       gfc_error ("PROTECTED at %C only allowed in specification "
                  "part of a module");
                  "part of a module");
       return MATCH_ERROR;
       return MATCH_ERROR;
 
 
    }
    }
 
 
  if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: PROTECTED statement at %C")
  if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: PROTECTED statement at %C")
      == FAILURE)
      == FAILURE)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  if (gfc_match (" ::") == MATCH_NO && gfc_match_space () == MATCH_NO)
  if (gfc_match (" ::") == MATCH_NO && gfc_match_space () == MATCH_NO)
    {
    {
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  if (gfc_match_eos () == MATCH_YES)
  if (gfc_match_eos () == MATCH_YES)
    goto syntax;
    goto syntax;
 
 
  for(;;)
  for(;;)
    {
    {
      m = gfc_match_symbol (&sym, 0);
      m = gfc_match_symbol (&sym, 0);
      switch (m)
      switch (m)
        {
        {
        case MATCH_YES:
        case MATCH_YES:
          if (gfc_add_protected (&sym->attr, sym->name, &gfc_current_locus)
          if (gfc_add_protected (&sym->attr, sym->name, &gfc_current_locus)
              == FAILURE)
              == FAILURE)
            return MATCH_ERROR;
            return MATCH_ERROR;
          goto next_item;
          goto next_item;
 
 
        case MATCH_NO:
        case MATCH_NO:
          break;
          break;
 
 
        case MATCH_ERROR:
        case MATCH_ERROR:
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
    next_item:
    next_item:
      if (gfc_match_eos () == MATCH_YES)
      if (gfc_match_eos () == MATCH_YES)
        break;
        break;
      if (gfc_match_char (',') != MATCH_YES)
      if (gfc_match_char (',') != MATCH_YES)
        goto syntax;
        goto syntax;
    }
    }
 
 
  return MATCH_YES;
  return MATCH_YES;
 
 
syntax:
syntax:
  gfc_error ("Syntax error in PROTECTED statement at %C");
  gfc_error ("Syntax error in PROTECTED statement at %C");
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
/* The PRIVATE statement is a bit weird in that it can be an attribute
/* The PRIVATE statement is a bit weird in that it can be an attribute
   declaration, but also works as a standalone statement inside of a
   declaration, but also works as a standalone statement inside of a
   type declaration or a module.  */
   type declaration or a module.  */
 
 
match
match
gfc_match_private (gfc_statement *st)
gfc_match_private (gfc_statement *st)
{
{
 
 
  if (gfc_match ("private") != MATCH_YES)
  if (gfc_match ("private") != MATCH_YES)
    return MATCH_NO;
    return MATCH_NO;
 
 
  if (gfc_current_state () != COMP_MODULE
  if (gfc_current_state () != COMP_MODULE
      && !(gfc_current_state () == COMP_DERIVED
      && !(gfc_current_state () == COMP_DERIVED
           && gfc_state_stack->previous
           && gfc_state_stack->previous
           && gfc_state_stack->previous->state == COMP_MODULE)
           && gfc_state_stack->previous->state == COMP_MODULE)
      && !(gfc_current_state () == COMP_DERIVED_CONTAINS
      && !(gfc_current_state () == COMP_DERIVED_CONTAINS
           && gfc_state_stack->previous && gfc_state_stack->previous->previous
           && gfc_state_stack->previous && gfc_state_stack->previous->previous
           && gfc_state_stack->previous->previous->state == COMP_MODULE))
           && gfc_state_stack->previous->previous->state == COMP_MODULE))
    {
    {
      gfc_error ("PRIVATE statement at %C is only allowed in the "
      gfc_error ("PRIVATE statement at %C is only allowed in the "
                 "specification part of a module");
                 "specification part of a module");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  if (gfc_current_state () == COMP_DERIVED)
  if (gfc_current_state () == COMP_DERIVED)
    {
    {
      if (gfc_match_eos () == MATCH_YES)
      if (gfc_match_eos () == MATCH_YES)
        {
        {
          *st = ST_PRIVATE;
          *st = ST_PRIVATE;
          return MATCH_YES;
          return MATCH_YES;
        }
        }
 
 
      gfc_syntax_error (ST_PRIVATE);
      gfc_syntax_error (ST_PRIVATE);
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  if (gfc_match_eos () == MATCH_YES)
  if (gfc_match_eos () == MATCH_YES)
    {
    {
      *st = ST_PRIVATE;
      *st = ST_PRIVATE;
      return MATCH_YES;
      return MATCH_YES;
    }
    }
 
 
  *st = ST_ATTR_DECL;
  *st = ST_ATTR_DECL;
  return access_attr_decl (ST_PRIVATE);
  return access_attr_decl (ST_PRIVATE);
}
}
 
 
 
 
match
match
gfc_match_public (gfc_statement *st)
gfc_match_public (gfc_statement *st)
{
{
 
 
  if (gfc_match ("public") != MATCH_YES)
  if (gfc_match ("public") != MATCH_YES)
    return MATCH_NO;
    return MATCH_NO;
 
 
  if (gfc_current_state () != COMP_MODULE)
  if (gfc_current_state () != COMP_MODULE)
    {
    {
      gfc_error ("PUBLIC statement at %C is only allowed in the "
      gfc_error ("PUBLIC statement at %C is only allowed in the "
                 "specification part of a module");
                 "specification part of a module");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  if (gfc_match_eos () == MATCH_YES)
  if (gfc_match_eos () == MATCH_YES)
    {
    {
      *st = ST_PUBLIC;
      *st = ST_PUBLIC;
      return MATCH_YES;
      return MATCH_YES;
    }
    }
 
 
  *st = ST_ATTR_DECL;
  *st = ST_ATTR_DECL;
  return access_attr_decl (ST_PUBLIC);
  return access_attr_decl (ST_PUBLIC);
}
}
 
 
 
 
/* Workhorse for gfc_match_parameter.  */
/* Workhorse for gfc_match_parameter.  */
 
 
static match
static match
do_parm (void)
do_parm (void)
{
{
  gfc_symbol *sym;
  gfc_symbol *sym;
  gfc_expr *init;
  gfc_expr *init;
  match m;
  match m;
  gfc_try t;
  gfc_try t;
 
 
  m = gfc_match_symbol (&sym, 0);
  m = gfc_match_symbol (&sym, 0);
  if (m == MATCH_NO)
  if (m == MATCH_NO)
    gfc_error ("Expected variable name at %C in PARAMETER statement");
    gfc_error ("Expected variable name at %C in PARAMETER statement");
 
 
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    return m;
    return m;
 
 
  if (gfc_match_char ('=') == MATCH_NO)
  if (gfc_match_char ('=') == MATCH_NO)
    {
    {
      gfc_error ("Expected = sign in PARAMETER statement at %C");
      gfc_error ("Expected = sign in PARAMETER statement at %C");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  m = gfc_match_init_expr (&init);
  m = gfc_match_init_expr (&init);
  if (m == MATCH_NO)
  if (m == MATCH_NO)
    gfc_error ("Expected expression at %C in PARAMETER statement");
    gfc_error ("Expected expression at %C in PARAMETER statement");
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    return m;
    return m;
 
 
  if (sym->ts.type == BT_UNKNOWN
  if (sym->ts.type == BT_UNKNOWN
      && gfc_set_default_type (sym, 1, NULL) == FAILURE)
      && gfc_set_default_type (sym, 1, NULL) == FAILURE)
    {
    {
      m = MATCH_ERROR;
      m = MATCH_ERROR;
      goto cleanup;
      goto cleanup;
    }
    }
 
 
  if (gfc_check_assign_symbol (sym, init) == FAILURE
  if (gfc_check_assign_symbol (sym, init) == FAILURE
      || gfc_add_flavor (&sym->attr, FL_PARAMETER, sym->name, NULL) == FAILURE)
      || gfc_add_flavor (&sym->attr, FL_PARAMETER, sym->name, NULL) == FAILURE)
    {
    {
      m = MATCH_ERROR;
      m = MATCH_ERROR;
      goto cleanup;
      goto cleanup;
    }
    }
 
 
  if (sym->value)
  if (sym->value)
    {
    {
      gfc_error ("Initializing already initialized variable at %C");
      gfc_error ("Initializing already initialized variable at %C");
      m = MATCH_ERROR;
      m = MATCH_ERROR;
      goto cleanup;
      goto cleanup;
    }
    }
 
 
  t = add_init_expr_to_sym (sym->name, &init, &gfc_current_locus);
  t = add_init_expr_to_sym (sym->name, &init, &gfc_current_locus);
  return (t == SUCCESS) ? MATCH_YES : MATCH_ERROR;
  return (t == SUCCESS) ? MATCH_YES : MATCH_ERROR;
 
 
cleanup:
cleanup:
  gfc_free_expr (init);
  gfc_free_expr (init);
  return m;
  return m;
}
}
 
 
 
 
/* Match a parameter statement, with the weird syntax that these have.  */
/* Match a parameter statement, with the weird syntax that these have.  */
 
 
match
match
gfc_match_parameter (void)
gfc_match_parameter (void)
{
{
  match m;
  match m;
 
 
  if (gfc_match_char ('(') == MATCH_NO)
  if (gfc_match_char ('(') == MATCH_NO)
    return MATCH_NO;
    return MATCH_NO;
 
 
  for (;;)
  for (;;)
    {
    {
      m = do_parm ();
      m = do_parm ();
      if (m != MATCH_YES)
      if (m != MATCH_YES)
        break;
        break;
 
 
      if (gfc_match (" )%t") == MATCH_YES)
      if (gfc_match (" )%t") == MATCH_YES)
        break;
        break;
 
 
      if (gfc_match_char (',') != MATCH_YES)
      if (gfc_match_char (',') != MATCH_YES)
        {
        {
          gfc_error ("Unexpected characters in PARAMETER statement at %C");
          gfc_error ("Unexpected characters in PARAMETER statement at %C");
          m = MATCH_ERROR;
          m = MATCH_ERROR;
          break;
          break;
        }
        }
    }
    }
 
 
  return m;
  return m;
}
}
 
 
 
 
/* Save statements have a special syntax.  */
/* Save statements have a special syntax.  */
 
 
match
match
gfc_match_save (void)
gfc_match_save (void)
{
{
  char n[GFC_MAX_SYMBOL_LEN+1];
  char n[GFC_MAX_SYMBOL_LEN+1];
  gfc_common_head *c;
  gfc_common_head *c;
  gfc_symbol *sym;
  gfc_symbol *sym;
  match m;
  match m;
 
 
  if (gfc_match_eos () == MATCH_YES)
  if (gfc_match_eos () == MATCH_YES)
    {
    {
      if (gfc_current_ns->seen_save)
      if (gfc_current_ns->seen_save)
        {
        {
          if (gfc_notify_std (GFC_STD_LEGACY, "Blanket SAVE statement at %C "
          if (gfc_notify_std (GFC_STD_LEGACY, "Blanket SAVE statement at %C "
                              "follows previous SAVE statement")
                              "follows previous SAVE statement")
              == FAILURE)
              == FAILURE)
            return MATCH_ERROR;
            return MATCH_ERROR;
        }
        }
 
 
      gfc_current_ns->save_all = gfc_current_ns->seen_save = 1;
      gfc_current_ns->save_all = gfc_current_ns->seen_save = 1;
      return MATCH_YES;
      return MATCH_YES;
    }
    }
 
 
  if (gfc_current_ns->save_all)
  if (gfc_current_ns->save_all)
    {
    {
      if (gfc_notify_std (GFC_STD_LEGACY, "SAVE statement at %C follows "
      if (gfc_notify_std (GFC_STD_LEGACY, "SAVE statement at %C follows "
                          "blanket SAVE statement")
                          "blanket SAVE statement")
          == FAILURE)
          == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
    }
    }
 
 
  gfc_match (" ::");
  gfc_match (" ::");
 
 
  for (;;)
  for (;;)
    {
    {
      m = gfc_match_symbol (&sym, 0);
      m = gfc_match_symbol (&sym, 0);
      switch (m)
      switch (m)
        {
        {
        case MATCH_YES:
        case MATCH_YES:
          if (gfc_add_save (&sym->attr, sym->name, &gfc_current_locus)
          if (gfc_add_save (&sym->attr, sym->name, &gfc_current_locus)
              == FAILURE)
              == FAILURE)
            return MATCH_ERROR;
            return MATCH_ERROR;
          goto next_item;
          goto next_item;
 
 
        case MATCH_NO:
        case MATCH_NO:
          break;
          break;
 
 
        case MATCH_ERROR:
        case MATCH_ERROR:
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
      m = gfc_match (" / %n /", &n);
      m = gfc_match (" / %n /", &n);
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        return MATCH_ERROR;
        return MATCH_ERROR;
      if (m == MATCH_NO)
      if (m == MATCH_NO)
        goto syntax;
        goto syntax;
 
 
      c = gfc_get_common (n, 0);
      c = gfc_get_common (n, 0);
      c->saved = 1;
      c->saved = 1;
 
 
      gfc_current_ns->seen_save = 1;
      gfc_current_ns->seen_save = 1;
 
 
    next_item:
    next_item:
      if (gfc_match_eos () == MATCH_YES)
      if (gfc_match_eos () == MATCH_YES)
        break;
        break;
      if (gfc_match_char (',') != MATCH_YES)
      if (gfc_match_char (',') != MATCH_YES)
        goto syntax;
        goto syntax;
    }
    }
 
 
  return MATCH_YES;
  return MATCH_YES;
 
 
syntax:
syntax:
  gfc_error ("Syntax error in SAVE statement at %C");
  gfc_error ("Syntax error in SAVE statement at %C");
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
match
match
gfc_match_value (void)
gfc_match_value (void)
{
{
  gfc_symbol *sym;
  gfc_symbol *sym;
  match m;
  match m;
 
 
  /* This is not allowed within a BLOCK construct!  */
  /* This is not allowed within a BLOCK construct!  */
  if (gfc_current_state () == COMP_BLOCK)
  if (gfc_current_state () == COMP_BLOCK)
    {
    {
      gfc_error ("VALUE is not allowed inside of BLOCK at %C");
      gfc_error ("VALUE is not allowed inside of BLOCK at %C");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: VALUE statement at %C")
  if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: VALUE statement at %C")
      == FAILURE)
      == FAILURE)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  if (gfc_match (" ::") == MATCH_NO && gfc_match_space () == MATCH_NO)
  if (gfc_match (" ::") == MATCH_NO && gfc_match_space () == MATCH_NO)
    {
    {
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  if (gfc_match_eos () == MATCH_YES)
  if (gfc_match_eos () == MATCH_YES)
    goto syntax;
    goto syntax;
 
 
  for(;;)
  for(;;)
    {
    {
      m = gfc_match_symbol (&sym, 0);
      m = gfc_match_symbol (&sym, 0);
      switch (m)
      switch (m)
        {
        {
        case MATCH_YES:
        case MATCH_YES:
          if (gfc_add_value (&sym->attr, sym->name, &gfc_current_locus)
          if (gfc_add_value (&sym->attr, sym->name, &gfc_current_locus)
              == FAILURE)
              == FAILURE)
            return MATCH_ERROR;
            return MATCH_ERROR;
          goto next_item;
          goto next_item;
 
 
        case MATCH_NO:
        case MATCH_NO:
          break;
          break;
 
 
        case MATCH_ERROR:
        case MATCH_ERROR:
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
    next_item:
    next_item:
      if (gfc_match_eos () == MATCH_YES)
      if (gfc_match_eos () == MATCH_YES)
        break;
        break;
      if (gfc_match_char (',') != MATCH_YES)
      if (gfc_match_char (',') != MATCH_YES)
        goto syntax;
        goto syntax;
    }
    }
 
 
  return MATCH_YES;
  return MATCH_YES;
 
 
syntax:
syntax:
  gfc_error ("Syntax error in VALUE statement at %C");
  gfc_error ("Syntax error in VALUE statement at %C");
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
match
match
gfc_match_volatile (void)
gfc_match_volatile (void)
{
{
  gfc_symbol *sym;
  gfc_symbol *sym;
  match m;
  match m;
 
 
  if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: VOLATILE statement at %C")
  if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: VOLATILE statement at %C")
      == FAILURE)
      == FAILURE)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  if (gfc_match (" ::") == MATCH_NO && gfc_match_space () == MATCH_NO)
  if (gfc_match (" ::") == MATCH_NO && gfc_match_space () == MATCH_NO)
    {
    {
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  if (gfc_match_eos () == MATCH_YES)
  if (gfc_match_eos () == MATCH_YES)
    goto syntax;
    goto syntax;
 
 
  for(;;)
  for(;;)
    {
    {
      /* VOLATILE is special because it can be added to host-associated
      /* VOLATILE is special because it can be added to host-associated
         symbols locally.  */
         symbols locally.  */
      m = gfc_match_symbol (&sym, 1);
      m = gfc_match_symbol (&sym, 1);
      switch (m)
      switch (m)
        {
        {
        case MATCH_YES:
        case MATCH_YES:
          if (gfc_add_volatile (&sym->attr, sym->name, &gfc_current_locus)
          if (gfc_add_volatile (&sym->attr, sym->name, &gfc_current_locus)
              == FAILURE)
              == FAILURE)
            return MATCH_ERROR;
            return MATCH_ERROR;
          goto next_item;
          goto next_item;
 
 
        case MATCH_NO:
        case MATCH_NO:
          break;
          break;
 
 
        case MATCH_ERROR:
        case MATCH_ERROR:
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
    next_item:
    next_item:
      if (gfc_match_eos () == MATCH_YES)
      if (gfc_match_eos () == MATCH_YES)
        break;
        break;
      if (gfc_match_char (',') != MATCH_YES)
      if (gfc_match_char (',') != MATCH_YES)
        goto syntax;
        goto syntax;
    }
    }
 
 
  return MATCH_YES;
  return MATCH_YES;
 
 
syntax:
syntax:
  gfc_error ("Syntax error in VOLATILE statement at %C");
  gfc_error ("Syntax error in VOLATILE statement at %C");
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
match
match
gfc_match_asynchronous (void)
gfc_match_asynchronous (void)
{
{
  gfc_symbol *sym;
  gfc_symbol *sym;
  match m;
  match m;
 
 
  if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: ASYNCHRONOUS statement at %C")
  if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: ASYNCHRONOUS statement at %C")
      == FAILURE)
      == FAILURE)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  if (gfc_match (" ::") == MATCH_NO && gfc_match_space () == MATCH_NO)
  if (gfc_match (" ::") == MATCH_NO && gfc_match_space () == MATCH_NO)
    {
    {
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  if (gfc_match_eos () == MATCH_YES)
  if (gfc_match_eos () == MATCH_YES)
    goto syntax;
    goto syntax;
 
 
  for(;;)
  for(;;)
    {
    {
      /* ASYNCHRONOUS is special because it can be added to host-associated
      /* ASYNCHRONOUS is special because it can be added to host-associated
         symbols locally.  */
         symbols locally.  */
      m = gfc_match_symbol (&sym, 1);
      m = gfc_match_symbol (&sym, 1);
      switch (m)
      switch (m)
        {
        {
        case MATCH_YES:
        case MATCH_YES:
          if (gfc_add_asynchronous (&sym->attr, sym->name, &gfc_current_locus)
          if (gfc_add_asynchronous (&sym->attr, sym->name, &gfc_current_locus)
              == FAILURE)
              == FAILURE)
            return MATCH_ERROR;
            return MATCH_ERROR;
          goto next_item;
          goto next_item;
 
 
        case MATCH_NO:
        case MATCH_NO:
          break;
          break;
 
 
        case MATCH_ERROR:
        case MATCH_ERROR:
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
    next_item:
    next_item:
      if (gfc_match_eos () == MATCH_YES)
      if (gfc_match_eos () == MATCH_YES)
        break;
        break;
      if (gfc_match_char (',') != MATCH_YES)
      if (gfc_match_char (',') != MATCH_YES)
        goto syntax;
        goto syntax;
    }
    }
 
 
  return MATCH_YES;
  return MATCH_YES;
 
 
syntax:
syntax:
  gfc_error ("Syntax error in ASYNCHRONOUS statement at %C");
  gfc_error ("Syntax error in ASYNCHRONOUS statement at %C");
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
/* Match a module procedure statement.  Note that we have to modify
/* Match a module procedure statement.  Note that we have to modify
   symbols in the parent's namespace because the current one was there
   symbols in the parent's namespace because the current one was there
   to receive symbols that are in an interface's formal argument list.  */
   to receive symbols that are in an interface's formal argument list.  */
 
 
match
match
gfc_match_modproc (void)
gfc_match_modproc (void)
{
{
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
  gfc_symbol *sym;
  gfc_symbol *sym;
  match m;
  match m;
  gfc_namespace *module_ns;
  gfc_namespace *module_ns;
  gfc_interface *old_interface_head, *interface;
  gfc_interface *old_interface_head, *interface;
 
 
  if (gfc_state_stack->state != COMP_INTERFACE
  if (gfc_state_stack->state != COMP_INTERFACE
      || gfc_state_stack->previous == NULL
      || gfc_state_stack->previous == NULL
      || current_interface.type == INTERFACE_NAMELESS
      || current_interface.type == INTERFACE_NAMELESS
      || current_interface.type == INTERFACE_ABSTRACT)
      || current_interface.type == INTERFACE_ABSTRACT)
    {
    {
      gfc_error ("MODULE PROCEDURE at %C must be in a generic module "
      gfc_error ("MODULE PROCEDURE at %C must be in a generic module "
                 "interface");
                 "interface");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  module_ns = gfc_current_ns->parent;
  module_ns = gfc_current_ns->parent;
  for (; module_ns; module_ns = module_ns->parent)
  for (; module_ns; module_ns = module_ns->parent)
    if (module_ns->proc_name->attr.flavor == FL_MODULE
    if (module_ns->proc_name->attr.flavor == FL_MODULE
        || module_ns->proc_name->attr.flavor == FL_PROGRAM
        || module_ns->proc_name->attr.flavor == FL_PROGRAM
        || (module_ns->proc_name->attr.flavor == FL_PROCEDURE
        || (module_ns->proc_name->attr.flavor == FL_PROCEDURE
            && !module_ns->proc_name->attr.contained))
            && !module_ns->proc_name->attr.contained))
      break;
      break;
 
 
  if (module_ns == NULL)
  if (module_ns == NULL)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  /* Store the current state of the interface. We will need it if we
  /* Store the current state of the interface. We will need it if we
     end up with a syntax error and need to recover.  */
     end up with a syntax error and need to recover.  */
  old_interface_head = gfc_current_interface_head ();
  old_interface_head = gfc_current_interface_head ();
 
 
  for (;;)
  for (;;)
    {
    {
      locus old_locus = gfc_current_locus;
      locus old_locus = gfc_current_locus;
      bool last = false;
      bool last = false;
 
 
      m = gfc_match_name (name);
      m = gfc_match_name (name);
      if (m == MATCH_NO)
      if (m == MATCH_NO)
        goto syntax;
        goto syntax;
      if (m != MATCH_YES)
      if (m != MATCH_YES)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      /* Check for syntax error before starting to add symbols to the
      /* Check for syntax error before starting to add symbols to the
         current namespace.  */
         current namespace.  */
      if (gfc_match_eos () == MATCH_YES)
      if (gfc_match_eos () == MATCH_YES)
        last = true;
        last = true;
      if (!last && gfc_match_char (',') != MATCH_YES)
      if (!last && gfc_match_char (',') != MATCH_YES)
        goto syntax;
        goto syntax;
 
 
      /* Now we're sure the syntax is valid, we process this item
      /* Now we're sure the syntax is valid, we process this item
         further.  */
         further.  */
      if (gfc_get_symbol (name, module_ns, &sym))
      if (gfc_get_symbol (name, module_ns, &sym))
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      if (sym->attr.intrinsic)
      if (sym->attr.intrinsic)
        {
        {
          gfc_error ("Intrinsic procedure at %L cannot be a MODULE "
          gfc_error ("Intrinsic procedure at %L cannot be a MODULE "
                     "PROCEDURE", &old_locus);
                     "PROCEDURE", &old_locus);
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
      if (sym->attr.proc != PROC_MODULE
      if (sym->attr.proc != PROC_MODULE
          && gfc_add_procedure (&sym->attr, PROC_MODULE,
          && gfc_add_procedure (&sym->attr, PROC_MODULE,
                                sym->name, NULL) == FAILURE)
                                sym->name, NULL) == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      if (gfc_add_interface (sym) == FAILURE)
      if (gfc_add_interface (sym) == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      sym->attr.mod_proc = 1;
      sym->attr.mod_proc = 1;
      sym->declared_at = old_locus;
      sym->declared_at = old_locus;
 
 
      if (last)
      if (last)
        break;
        break;
    }
    }
 
 
  return MATCH_YES;
  return MATCH_YES;
 
 
syntax:
syntax:
  /* Restore the previous state of the interface.  */
  /* Restore the previous state of the interface.  */
  interface = gfc_current_interface_head ();
  interface = gfc_current_interface_head ();
  gfc_set_current_interface_head (old_interface_head);
  gfc_set_current_interface_head (old_interface_head);
 
 
  /* Free the new interfaces.  */
  /* Free the new interfaces.  */
  while (interface != old_interface_head)
  while (interface != old_interface_head)
  {
  {
    gfc_interface *i = interface->next;
    gfc_interface *i = interface->next;
    gfc_free (interface);
    gfc_free (interface);
    interface = i;
    interface = i;
  }
  }
 
 
  /* And issue a syntax error.  */
  /* And issue a syntax error.  */
  gfc_syntax_error (ST_MODULE_PROC);
  gfc_syntax_error (ST_MODULE_PROC);
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
/* Check a derived type that is being extended.  */
/* Check a derived type that is being extended.  */
static gfc_symbol*
static gfc_symbol*
check_extended_derived_type (char *name)
check_extended_derived_type (char *name)
{
{
  gfc_symbol *extended;
  gfc_symbol *extended;
 
 
  if (gfc_find_symbol (name, gfc_current_ns, 1, &extended))
  if (gfc_find_symbol (name, gfc_current_ns, 1, &extended))
    {
    {
      gfc_error ("Ambiguous symbol in TYPE definition at %C");
      gfc_error ("Ambiguous symbol in TYPE definition at %C");
      return NULL;
      return NULL;
    }
    }
 
 
  if (!extended)
  if (!extended)
    {
    {
      gfc_error ("No such symbol in TYPE definition at %C");
      gfc_error ("No such symbol in TYPE definition at %C");
      return NULL;
      return NULL;
    }
    }
 
 
  if (extended->attr.flavor != FL_DERIVED)
  if (extended->attr.flavor != FL_DERIVED)
    {
    {
      gfc_error ("'%s' in EXTENDS expression at %C is not a "
      gfc_error ("'%s' in EXTENDS expression at %C is not a "
                 "derived type", name);
                 "derived type", name);
      return NULL;
      return NULL;
    }
    }
 
 
  if (extended->attr.is_bind_c)
  if (extended->attr.is_bind_c)
    {
    {
      gfc_error ("'%s' cannot be extended at %C because it "
      gfc_error ("'%s' cannot be extended at %C because it "
                 "is BIND(C)", extended->name);
                 "is BIND(C)", extended->name);
      return NULL;
      return NULL;
    }
    }
 
 
  if (extended->attr.sequence)
  if (extended->attr.sequence)
    {
    {
      gfc_error ("'%s' cannot be extended at %C because it "
      gfc_error ("'%s' cannot be extended at %C because it "
                 "is a SEQUENCE type", extended->name);
                 "is a SEQUENCE type", extended->name);
      return NULL;
      return NULL;
    }
    }
 
 
  return extended;
  return extended;
}
}
 
 
 
 
/* Match the optional attribute specifiers for a type declaration.
/* Match the optional attribute specifiers for a type declaration.
   Return MATCH_ERROR if an error is encountered in one of the handled
   Return MATCH_ERROR if an error is encountered in one of the handled
   attributes (public, private, bind(c)), MATCH_NO if what's found is
   attributes (public, private, bind(c)), MATCH_NO if what's found is
   not a handled attribute, and MATCH_YES otherwise.  TODO: More error
   not a handled attribute, and MATCH_YES otherwise.  TODO: More error
   checking on attribute conflicts needs to be done.  */
   checking on attribute conflicts needs to be done.  */
 
 
match
match
gfc_get_type_attr_spec (symbol_attribute *attr, char *name)
gfc_get_type_attr_spec (symbol_attribute *attr, char *name)
{
{
  /* See if the derived type is marked as private.  */
  /* See if the derived type is marked as private.  */
  if (gfc_match (" , private") == MATCH_YES)
  if (gfc_match (" , private") == MATCH_YES)
    {
    {
      if (gfc_current_state () != COMP_MODULE)
      if (gfc_current_state () != COMP_MODULE)
        {
        {
          gfc_error ("Derived type at %C can only be PRIVATE in the "
          gfc_error ("Derived type at %C can only be PRIVATE in the "
                     "specification part of a module");
                     "specification part of a module");
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
      if (gfc_add_access (attr, ACCESS_PRIVATE, NULL, NULL) == FAILURE)
      if (gfc_add_access (attr, ACCESS_PRIVATE, NULL, NULL) == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
    }
    }
  else if (gfc_match (" , public") == MATCH_YES)
  else if (gfc_match (" , public") == MATCH_YES)
    {
    {
      if (gfc_current_state () != COMP_MODULE)
      if (gfc_current_state () != COMP_MODULE)
        {
        {
          gfc_error ("Derived type at %C can only be PUBLIC in the "
          gfc_error ("Derived type at %C can only be PUBLIC in the "
                     "specification part of a module");
                     "specification part of a module");
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
      if (gfc_add_access (attr, ACCESS_PUBLIC, NULL, NULL) == FAILURE)
      if (gfc_add_access (attr, ACCESS_PUBLIC, NULL, NULL) == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
    }
    }
  else if (gfc_match (" , bind ( c )") == MATCH_YES)
  else if (gfc_match (" , bind ( c )") == MATCH_YES)
    {
    {
      /* If the type is defined to be bind(c) it then needs to make
      /* If the type is defined to be bind(c) it then needs to make
         sure that all fields are interoperable.  This will
         sure that all fields are interoperable.  This will
         need to be a semantic check on the finished derived type.
         need to be a semantic check on the finished derived type.
         See 15.2.3 (lines 9-12) of F2003 draft.  */
         See 15.2.3 (lines 9-12) of F2003 draft.  */
      if (gfc_add_is_bind_c (attr, NULL, &gfc_current_locus, 0) != SUCCESS)
      if (gfc_add_is_bind_c (attr, NULL, &gfc_current_locus, 0) != SUCCESS)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      /* TODO: attr conflicts need to be checked, probably in symbol.c.  */
      /* TODO: attr conflicts need to be checked, probably in symbol.c.  */
    }
    }
  else if (gfc_match (" , abstract") == MATCH_YES)
  else if (gfc_match (" , abstract") == MATCH_YES)
    {
    {
      if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: ABSTRACT type at %C")
      if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: ABSTRACT type at %C")
            == FAILURE)
            == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      if (gfc_add_abstract (attr, &gfc_current_locus) == FAILURE)
      if (gfc_add_abstract (attr, &gfc_current_locus) == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
    }
    }
  else if (name && gfc_match(" , extends ( %n )", name) == MATCH_YES)
  else if (name && gfc_match(" , extends ( %n )", name) == MATCH_YES)
    {
    {
      if (gfc_add_extension (attr, &gfc_current_locus) == FAILURE)
      if (gfc_add_extension (attr, &gfc_current_locus) == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
    }
    }
  else
  else
    return MATCH_NO;
    return MATCH_NO;
 
 
  /* If we get here, something matched.  */
  /* If we get here, something matched.  */
  return MATCH_YES;
  return MATCH_YES;
}
}
 
 
 
 
/* Assign a hash value for a derived type. The algorithm is that of
/* Assign a hash value for a derived type. The algorithm is that of
   SDBM. The hashed string is '[module_name #] derived_name'.  */
   SDBM. The hashed string is '[module_name #] derived_name'.  */
static unsigned int
static unsigned int
hash_value (gfc_symbol *sym)
hash_value (gfc_symbol *sym)
{
{
  unsigned int hash = 0;
  unsigned int hash = 0;
  const char *c;
  const char *c;
  int i, len;
  int i, len;
 
 
  /* Hash of the module or procedure name.  */
  /* Hash of the module or procedure name.  */
  if (sym->module != NULL)
  if (sym->module != NULL)
    c = sym->module;
    c = sym->module;
  else if (sym->ns && sym->ns->proc_name
  else if (sym->ns && sym->ns->proc_name
             && sym->ns->proc_name->attr.flavor == FL_MODULE)
             && sym->ns->proc_name->attr.flavor == FL_MODULE)
    c = sym->ns->proc_name->name;
    c = sym->ns->proc_name->name;
  else
  else
    c = NULL;
    c = NULL;
 
 
  if (c)
  if (c)
    {
    {
      len = strlen (c);
      len = strlen (c);
      for (i = 0; i < len; i++, c++)
      for (i = 0; i < len; i++, c++)
        hash =  (hash << 6) + (hash << 16) - hash + (*c);
        hash =  (hash << 6) + (hash << 16) - hash + (*c);
 
 
      /* Disambiguate between 'a' in 'aa' and 'aa' in 'a'.  */
      /* Disambiguate between 'a' in 'aa' and 'aa' in 'a'.  */
      hash =  (hash << 6) + (hash << 16) - hash + '#';
      hash =  (hash << 6) + (hash << 16) - hash + '#';
    }
    }
 
 
  /* Hash of the derived type name.  */
  /* Hash of the derived type name.  */
  len = strlen (sym->name);
  len = strlen (sym->name);
  c = sym->name;
  c = sym->name;
  for (i = 0; i < len; i++, c++)
  for (i = 0; i < len; i++, c++)
    hash = (hash << 6) + (hash << 16) - hash + (*c);
    hash = (hash << 6) + (hash << 16) - hash + (*c);
 
 
  /* Return the hash but take the modulus for the sake of module read,
  /* Return the hash but take the modulus for the sake of module read,
     even though this slightly increases the chance of collision.  */
     even though this slightly increases the chance of collision.  */
  return (hash % 100000000);
  return (hash % 100000000);
}
}
 
 
 
 
/* Match the beginning of a derived type declaration.  If a type name
/* Match the beginning of a derived type declaration.  If a type name
   was the result of a function, then it is possible to have a symbol
   was the result of a function, then it is possible to have a symbol
   already to be known as a derived type yet have no components.  */
   already to be known as a derived type yet have no components.  */
 
 
match
match
gfc_match_derived_decl (void)
gfc_match_derived_decl (void)
{
{
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char parent[GFC_MAX_SYMBOL_LEN + 1];
  char parent[GFC_MAX_SYMBOL_LEN + 1];
  symbol_attribute attr;
  symbol_attribute attr;
  gfc_symbol *sym;
  gfc_symbol *sym;
  gfc_symbol *extended;
  gfc_symbol *extended;
  match m;
  match m;
  match is_type_attr_spec = MATCH_NO;
  match is_type_attr_spec = MATCH_NO;
  bool seen_attr = false;
  bool seen_attr = false;
 
 
  if (gfc_current_state () == COMP_DERIVED)
  if (gfc_current_state () == COMP_DERIVED)
    return MATCH_NO;
    return MATCH_NO;
 
 
  name[0] = '\0';
  name[0] = '\0';
  parent[0] = '\0';
  parent[0] = '\0';
  gfc_clear_attr (&attr);
  gfc_clear_attr (&attr);
  extended = NULL;
  extended = NULL;
 
 
  do
  do
    {
    {
      is_type_attr_spec = gfc_get_type_attr_spec (&attr, parent);
      is_type_attr_spec = gfc_get_type_attr_spec (&attr, parent);
      if (is_type_attr_spec == MATCH_ERROR)
      if (is_type_attr_spec == MATCH_ERROR)
        return MATCH_ERROR;
        return MATCH_ERROR;
      if (is_type_attr_spec == MATCH_YES)
      if (is_type_attr_spec == MATCH_YES)
        seen_attr = true;
        seen_attr = true;
    } while (is_type_attr_spec == MATCH_YES);
    } while (is_type_attr_spec == MATCH_YES);
 
 
  /* Deal with derived type extensions.  The extension attribute has
  /* Deal with derived type extensions.  The extension attribute has
     been added to 'attr' but now the parent type must be found and
     been added to 'attr' but now the parent type must be found and
     checked.  */
     checked.  */
  if (parent[0])
  if (parent[0])
    extended = check_extended_derived_type (parent);
    extended = check_extended_derived_type (parent);
 
 
  if (parent[0] && !extended)
  if (parent[0] && !extended)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  if (gfc_match (" ::") != MATCH_YES && seen_attr)
  if (gfc_match (" ::") != MATCH_YES && seen_attr)
    {
    {
      gfc_error ("Expected :: in TYPE definition at %C");
      gfc_error ("Expected :: in TYPE definition at %C");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  m = gfc_match (" %n%t", name);
  m = gfc_match (" %n%t", name);
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    return m;
    return m;
 
 
  /* Make sure the name is not the name of an intrinsic type.  */
  /* Make sure the name is not the name of an intrinsic type.  */
  if (gfc_is_intrinsic_typename (name))
  if (gfc_is_intrinsic_typename (name))
    {
    {
      gfc_error ("Type name '%s' at %C cannot be the same as an intrinsic "
      gfc_error ("Type name '%s' at %C cannot be the same as an intrinsic "
                 "type", name);
                 "type", name);
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  if (gfc_get_symbol (name, NULL, &sym))
  if (gfc_get_symbol (name, NULL, &sym))
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  if (sym->ts.type != BT_UNKNOWN)
  if (sym->ts.type != BT_UNKNOWN)
    {
    {
      gfc_error ("Derived type name '%s' at %C already has a basic type "
      gfc_error ("Derived type name '%s' at %C already has a basic type "
                 "of %s", sym->name, gfc_typename (&sym->ts));
                 "of %s", sym->name, gfc_typename (&sym->ts));
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  /* The symbol may already have the derived attribute without the
  /* The symbol may already have the derived attribute without the
     components.  The ways this can happen is via a function
     components.  The ways this can happen is via a function
     definition, an INTRINSIC statement or a subtype in another
     definition, an INTRINSIC statement or a subtype in another
     derived type that is a pointer.  The first part of the AND clause
     derived type that is a pointer.  The first part of the AND clause
     is true if the symbol is not the return value of a function.  */
     is true if the symbol is not the return value of a function.  */
  if (sym->attr.flavor != FL_DERIVED
  if (sym->attr.flavor != FL_DERIVED
      && gfc_add_flavor (&sym->attr, FL_DERIVED, sym->name, NULL) == FAILURE)
      && gfc_add_flavor (&sym->attr, FL_DERIVED, sym->name, NULL) == FAILURE)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  if (sym->components != NULL || sym->attr.zero_comp)
  if (sym->components != NULL || sym->attr.zero_comp)
    {
    {
      gfc_error ("Derived type definition of '%s' at %C has already been "
      gfc_error ("Derived type definition of '%s' at %C has already been "
                 "defined", sym->name);
                 "defined", sym->name);
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  if (attr.access != ACCESS_UNKNOWN
  if (attr.access != ACCESS_UNKNOWN
      && gfc_add_access (&sym->attr, attr.access, sym->name, NULL) == FAILURE)
      && gfc_add_access (&sym->attr, attr.access, sym->name, NULL) == FAILURE)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  /* See if the derived type was labeled as bind(c).  */
  /* See if the derived type was labeled as bind(c).  */
  if (attr.is_bind_c != 0)
  if (attr.is_bind_c != 0)
    sym->attr.is_bind_c = attr.is_bind_c;
    sym->attr.is_bind_c = attr.is_bind_c;
 
 
  /* Construct the f2k_derived namespace if it is not yet there.  */
  /* Construct the f2k_derived namespace if it is not yet there.  */
  if (!sym->f2k_derived)
  if (!sym->f2k_derived)
    sym->f2k_derived = gfc_get_namespace (NULL, 0);
    sym->f2k_derived = gfc_get_namespace (NULL, 0);
 
 
  if (extended && !sym->components)
  if (extended && !sym->components)
    {
    {
      gfc_component *p;
      gfc_component *p;
      gfc_symtree *st;
      gfc_symtree *st;
 
 
      /* Add the extended derived type as the first component.  */
      /* Add the extended derived type as the first component.  */
      gfc_add_component (sym, parent, &p);
      gfc_add_component (sym, parent, &p);
      extended->refs++;
      extended->refs++;
      gfc_set_sym_referenced (extended);
      gfc_set_sym_referenced (extended);
 
 
      p->ts.type = BT_DERIVED;
      p->ts.type = BT_DERIVED;
      p->ts.u.derived = extended;
      p->ts.u.derived = extended;
      p->initializer = gfc_default_initializer (&p->ts);
      p->initializer = gfc_default_initializer (&p->ts);
 
 
      /* Set extension level.  */
      /* Set extension level.  */
      if (extended->attr.extension == 255)
      if (extended->attr.extension == 255)
        {
        {
          /* Since the extension field is 8 bit wide, we can only have
          /* Since the extension field is 8 bit wide, we can only have
             up to 255 extension levels.  */
             up to 255 extension levels.  */
          gfc_error ("Maximum extension level reached with type '%s' at %L",
          gfc_error ("Maximum extension level reached with type '%s' at %L",
                     extended->name, &extended->declared_at);
                     extended->name, &extended->declared_at);
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
      sym->attr.extension = extended->attr.extension + 1;
      sym->attr.extension = extended->attr.extension + 1;
 
 
      /* Provide the links between the extended type and its extension.  */
      /* Provide the links between the extended type and its extension.  */
      if (!extended->f2k_derived)
      if (!extended->f2k_derived)
        extended->f2k_derived = gfc_get_namespace (NULL, 0);
        extended->f2k_derived = gfc_get_namespace (NULL, 0);
      st = gfc_new_symtree (&extended->f2k_derived->sym_root, sym->name);
      st = gfc_new_symtree (&extended->f2k_derived->sym_root, sym->name);
      st->n.sym = sym;
      st->n.sym = sym;
    }
    }
 
 
  if (!sym->hash_value)
  if (!sym->hash_value)
    /* Set the hash for the compound name for this type.  */
    /* Set the hash for the compound name for this type.  */
    sym->hash_value = hash_value (sym);
    sym->hash_value = hash_value (sym);
 
 
  /* Take over the ABSTRACT attribute.  */
  /* Take over the ABSTRACT attribute.  */
  sym->attr.abstract = attr.abstract;
  sym->attr.abstract = attr.abstract;
 
 
  gfc_new_block = sym;
  gfc_new_block = sym;
 
 
  return MATCH_YES;
  return MATCH_YES;
}
}
 
 
 
 
/* Cray Pointees can be declared as:
/* Cray Pointees can be declared as:
      pointer (ipt, a (n,m,...,*))  */
      pointer (ipt, a (n,m,...,*))  */
 
 
match
match
gfc_mod_pointee_as (gfc_array_spec *as)
gfc_mod_pointee_as (gfc_array_spec *as)
{
{
  as->cray_pointee = true; /* This will be useful to know later.  */
  as->cray_pointee = true; /* This will be useful to know later.  */
  if (as->type == AS_ASSUMED_SIZE)
  if (as->type == AS_ASSUMED_SIZE)
    as->cp_was_assumed = true;
    as->cp_was_assumed = true;
  else if (as->type == AS_ASSUMED_SHAPE)
  else if (as->type == AS_ASSUMED_SHAPE)
    {
    {
      gfc_error ("Cray Pointee at %C cannot be assumed shape array");
      gfc_error ("Cray Pointee at %C cannot be assumed shape array");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
  return MATCH_YES;
  return MATCH_YES;
}
}
 
 
 
 
/* Match the enum definition statement, here we are trying to match
/* Match the enum definition statement, here we are trying to match
   the first line of enum definition statement.
   the first line of enum definition statement.
   Returns MATCH_YES if match is found.  */
   Returns MATCH_YES if match is found.  */
 
 
match
match
gfc_match_enum (void)
gfc_match_enum (void)
{
{
  match m;
  match m;
 
 
  m = gfc_match_eos ();
  m = gfc_match_eos ();
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    return m;
    return m;
 
 
  if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: ENUM and ENUMERATOR at %C")
  if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: ENUM and ENUMERATOR at %C")
      == FAILURE)
      == FAILURE)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  return MATCH_YES;
  return MATCH_YES;
}
}
 
 
 
 
/* Returns an initializer whose value is one higher than the value of the
/* Returns an initializer whose value is one higher than the value of the
   LAST_INITIALIZER argument.  If the argument is NULL, the
   LAST_INITIALIZER argument.  If the argument is NULL, the
   initializers value will be set to zero.  The initializer's kind
   initializers value will be set to zero.  The initializer's kind
   will be set to gfc_c_int_kind.
   will be set to gfc_c_int_kind.
 
 
   If -fshort-enums is given, the appropriate kind will be selected
   If -fshort-enums is given, the appropriate kind will be selected
   later after all enumerators have been parsed.  A warning is issued
   later after all enumerators have been parsed.  A warning is issued
   here if an initializer exceeds gfc_c_int_kind.  */
   here if an initializer exceeds gfc_c_int_kind.  */
 
 
static gfc_expr *
static gfc_expr *
enum_initializer (gfc_expr *last_initializer, locus where)
enum_initializer (gfc_expr *last_initializer, locus where)
{
{
  gfc_expr *result;
  gfc_expr *result;
 
 
  result = gfc_get_expr ();
  result = gfc_get_expr ();
  result->expr_type = EXPR_CONSTANT;
  result->expr_type = EXPR_CONSTANT;
  result->ts.type = BT_INTEGER;
  result->ts.type = BT_INTEGER;
  result->ts.kind = gfc_c_int_kind;
  result->ts.kind = gfc_c_int_kind;
  result->where = where;
  result->where = where;
 
 
  mpz_init (result->value.integer);
  mpz_init (result->value.integer);
 
 
  if (last_initializer != NULL)
  if (last_initializer != NULL)
    {
    {
      mpz_add_ui (result->value.integer, last_initializer->value.integer, 1);
      mpz_add_ui (result->value.integer, last_initializer->value.integer, 1);
      result->where = last_initializer->where;
      result->where = last_initializer->where;
 
 
      if (gfc_check_integer_range (result->value.integer,
      if (gfc_check_integer_range (result->value.integer,
             gfc_c_int_kind) != ARITH_OK)
             gfc_c_int_kind) != ARITH_OK)
        {
        {
          gfc_error ("Enumerator exceeds the C integer type at %C");
          gfc_error ("Enumerator exceeds the C integer type at %C");
          return NULL;
          return NULL;
        }
        }
    }
    }
  else
  else
    {
    {
      /* Control comes here, if it's the very first enumerator and no
      /* Control comes here, if it's the very first enumerator and no
         initializer has been given.  It will be initialized to zero.  */
         initializer has been given.  It will be initialized to zero.  */
      mpz_set_si (result->value.integer, 0);
      mpz_set_si (result->value.integer, 0);
    }
    }
 
 
  return result;
  return result;
}
}
 
 
 
 
/* Match a variable name with an optional initializer.  When this
/* Match a variable name with an optional initializer.  When this
   subroutine is called, a variable is expected to be parsed next.
   subroutine is called, a variable is expected to be parsed next.
   Depending on what is happening at the moment, updates either the
   Depending on what is happening at the moment, updates either the
   symbol table or the current interface.  */
   symbol table or the current interface.  */
 
 
static match
static match
enumerator_decl (void)
enumerator_decl (void)
{
{
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
  gfc_expr *initializer;
  gfc_expr *initializer;
  gfc_array_spec *as = NULL;
  gfc_array_spec *as = NULL;
  gfc_symbol *sym;
  gfc_symbol *sym;
  locus var_locus;
  locus var_locus;
  match m;
  match m;
  gfc_try t;
  gfc_try t;
  locus old_locus;
  locus old_locus;
 
 
  initializer = NULL;
  initializer = NULL;
  old_locus = gfc_current_locus;
  old_locus = gfc_current_locus;
 
 
  /* When we get here, we've just matched a list of attributes and
  /* 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
     maybe a type and a double colon.  The next thing we expect to see
     is the name of the symbol.  */
     is the name of the symbol.  */
  m = gfc_match_name (name);
  m = gfc_match_name (name);
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    goto cleanup;
    goto cleanup;
 
 
  var_locus = gfc_current_locus;
  var_locus = gfc_current_locus;
 
 
  /* OK, we've successfully matched the declaration.  Now put the
  /* OK, we've successfully matched the declaration.  Now put the
     symbol in the current namespace. If we fail to create the symbol,
     symbol in the current namespace. If we fail to create the symbol,
     bail out.  */
     bail out.  */
  if (build_sym (name, NULL, &as, &var_locus) == FAILURE)
  if (build_sym (name, NULL, &as, &var_locus) == FAILURE)
    {
    {
      m = MATCH_ERROR;
      m = MATCH_ERROR;
      goto cleanup;
      goto cleanup;
    }
    }
 
 
  /* The double colon must be present in order to have initializers.
  /* The double colon must be present in order to have initializers.
     Otherwise the statement is ambiguous with an assignment statement.  */
     Otherwise the statement is ambiguous with an assignment statement.  */
  if (colon_seen)
  if (colon_seen)
    {
    {
      if (gfc_match_char ('=') == MATCH_YES)
      if (gfc_match_char ('=') == MATCH_YES)
        {
        {
          m = gfc_match_init_expr (&initializer);
          m = gfc_match_init_expr (&initializer);
          if (m == MATCH_NO)
          if (m == MATCH_NO)
            {
            {
              gfc_error ("Expected an initialization expression at %C");
              gfc_error ("Expected an initialization expression at %C");
              m = MATCH_ERROR;
              m = MATCH_ERROR;
            }
            }
 
 
          if (m != MATCH_YES)
          if (m != MATCH_YES)
            goto cleanup;
            goto cleanup;
        }
        }
    }
    }
 
 
  /* If we do not have an initializer, the initialization value of the
  /* If we do not have an initializer, the initialization value of the
     previous enumerator (stored in last_initializer) is incremented
     previous enumerator (stored in last_initializer) is incremented
     by 1 and is used to initialize the current enumerator.  */
     by 1 and is used to initialize the current enumerator.  */
  if (initializer == NULL)
  if (initializer == NULL)
    initializer = enum_initializer (last_initializer, old_locus);
    initializer = enum_initializer (last_initializer, old_locus);
 
 
  if (initializer == NULL || initializer->ts.type != BT_INTEGER)
  if (initializer == NULL || initializer->ts.type != BT_INTEGER)
    {
    {
      gfc_error ("ENUMERATOR %L not initialized with integer expression",
      gfc_error ("ENUMERATOR %L not initialized with integer expression",
                 &var_locus);
                 &var_locus);
      m = MATCH_ERROR;
      m = MATCH_ERROR;
      goto cleanup;
      goto cleanup;
    }
    }
 
 
  /* Store this current initializer, for the next enumerator variable
  /* Store this current initializer, for the next enumerator variable
     to be parsed.  add_init_expr_to_sym() zeros initializer, so we
     to be parsed.  add_init_expr_to_sym() zeros initializer, so we
     use last_initializer below.  */
     use last_initializer below.  */
  last_initializer = initializer;
  last_initializer = initializer;
  t = add_init_expr_to_sym (name, &initializer, &var_locus);
  t = add_init_expr_to_sym (name, &initializer, &var_locus);
 
 
  /* Maintain enumerator history.  */
  /* Maintain enumerator history.  */
  gfc_find_symbol (name, NULL, 0, &sym);
  gfc_find_symbol (name, NULL, 0, &sym);
  create_enum_history (sym, last_initializer);
  create_enum_history (sym, last_initializer);
 
 
  return (t == SUCCESS) ? MATCH_YES : MATCH_ERROR;
  return (t == SUCCESS) ? MATCH_YES : MATCH_ERROR;
 
 
cleanup:
cleanup:
  /* Free stuff up and return.  */
  /* Free stuff up and return.  */
  gfc_free_expr (initializer);
  gfc_free_expr (initializer);
 
 
  return m;
  return m;
}
}
 
 
 
 
/* Match the enumerator definition statement.  */
/* Match the enumerator definition statement.  */
 
 
match
match
gfc_match_enumerator_def (void)
gfc_match_enumerator_def (void)
{
{
  match m;
  match m;
  gfc_try t;
  gfc_try t;
 
 
  gfc_clear_ts (&current_ts);
  gfc_clear_ts (&current_ts);
 
 
  m = gfc_match (" enumerator");
  m = gfc_match (" enumerator");
  if (m != MATCH_YES)
  if (m != MATCH_YES)
    return m;
    return m;
 
 
  m = gfc_match (" :: ");
  m = gfc_match (" :: ");
  if (m == MATCH_ERROR)
  if (m == MATCH_ERROR)
    return m;
    return m;
 
 
  colon_seen = (m == MATCH_YES);
  colon_seen = (m == MATCH_YES);
 
 
  if (gfc_current_state () != COMP_ENUM)
  if (gfc_current_state () != COMP_ENUM)
    {
    {
      gfc_error ("ENUM definition statement expected before %C");
      gfc_error ("ENUM definition statement expected before %C");
      gfc_free_enum_history ();
      gfc_free_enum_history ();
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  (&current_ts)->type = BT_INTEGER;
  (&current_ts)->type = BT_INTEGER;
  (&current_ts)->kind = gfc_c_int_kind;
  (&current_ts)->kind = gfc_c_int_kind;
 
 
  gfc_clear_attr (&current_attr);
  gfc_clear_attr (&current_attr);
  t = gfc_add_flavor (&current_attr, FL_PARAMETER, NULL, NULL);
  t = gfc_add_flavor (&current_attr, FL_PARAMETER, NULL, NULL);
  if (t == FAILURE)
  if (t == FAILURE)
    {
    {
      m = MATCH_ERROR;
      m = MATCH_ERROR;
      goto cleanup;
      goto cleanup;
    }
    }
 
 
  for (;;)
  for (;;)
    {
    {
      m = enumerator_decl ();
      m = enumerator_decl ();
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        {
        {
          gfc_free_enum_history ();
          gfc_free_enum_history ();
          goto cleanup;
          goto cleanup;
        }
        }
      if (m == MATCH_NO)
      if (m == MATCH_NO)
        break;
        break;
 
 
      if (gfc_match_eos () == MATCH_YES)
      if (gfc_match_eos () == MATCH_YES)
        goto cleanup;
        goto cleanup;
      if (gfc_match_char (',') != MATCH_YES)
      if (gfc_match_char (',') != MATCH_YES)
        break;
        break;
    }
    }
 
 
  if (gfc_current_state () == COMP_ENUM)
  if (gfc_current_state () == COMP_ENUM)
    {
    {
      gfc_free_enum_history ();
      gfc_free_enum_history ();
      gfc_error ("Syntax error in ENUMERATOR definition at %C");
      gfc_error ("Syntax error in ENUMERATOR definition at %C");
      m = MATCH_ERROR;
      m = MATCH_ERROR;
    }
    }
 
 
cleanup:
cleanup:
  gfc_free_array_spec (current_as);
  gfc_free_array_spec (current_as);
  current_as = NULL;
  current_as = NULL;
  return m;
  return m;
 
 
}
}
 
 
 
 
/* Match binding attributes.  */
/* Match binding attributes.  */
 
 
static match
static match
match_binding_attributes (gfc_typebound_proc* ba, bool generic, bool ppc)
match_binding_attributes (gfc_typebound_proc* ba, bool generic, bool ppc)
{
{
  bool found_passing = false;
  bool found_passing = false;
  bool seen_ptr = false;
  bool seen_ptr = false;
  match m = MATCH_YES;
  match m = MATCH_YES;
 
 
  /* Intialize to defaults.  Do so even before the MATCH_NO check so that in
  /* Intialize to defaults.  Do so even before the MATCH_NO check so that in
     this case the defaults are in there.  */
     this case the defaults are in there.  */
  ba->access = ACCESS_UNKNOWN;
  ba->access = ACCESS_UNKNOWN;
  ba->pass_arg = NULL;
  ba->pass_arg = NULL;
  ba->pass_arg_num = 0;
  ba->pass_arg_num = 0;
  ba->nopass = 0;
  ba->nopass = 0;
  ba->non_overridable = 0;
  ba->non_overridable = 0;
  ba->deferred = 0;
  ba->deferred = 0;
  ba->ppc = ppc;
  ba->ppc = ppc;
 
 
  /* If we find a comma, we believe there are binding attributes.  */
  /* If we find a comma, we believe there are binding attributes.  */
  m = gfc_match_char (',');
  m = gfc_match_char (',');
  if (m == MATCH_NO)
  if (m == MATCH_NO)
    goto done;
    goto done;
 
 
  do
  do
    {
    {
      /* Access specifier.  */
      /* Access specifier.  */
 
 
      m = gfc_match (" public");
      m = gfc_match (" public");
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        goto error;
        goto error;
      if (m == MATCH_YES)
      if (m == MATCH_YES)
        {
        {
          if (ba->access != ACCESS_UNKNOWN)
          if (ba->access != ACCESS_UNKNOWN)
            {
            {
              gfc_error ("Duplicate access-specifier at %C");
              gfc_error ("Duplicate access-specifier at %C");
              goto error;
              goto error;
            }
            }
 
 
          ba->access = ACCESS_PUBLIC;
          ba->access = ACCESS_PUBLIC;
          continue;
          continue;
        }
        }
 
 
      m = gfc_match (" private");
      m = gfc_match (" private");
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        goto error;
        goto error;
      if (m == MATCH_YES)
      if (m == MATCH_YES)
        {
        {
          if (ba->access != ACCESS_UNKNOWN)
          if (ba->access != ACCESS_UNKNOWN)
            {
            {
              gfc_error ("Duplicate access-specifier at %C");
              gfc_error ("Duplicate access-specifier at %C");
              goto error;
              goto error;
            }
            }
 
 
          ba->access = ACCESS_PRIVATE;
          ba->access = ACCESS_PRIVATE;
          continue;
          continue;
        }
        }
 
 
      /* If inside GENERIC, the following is not allowed.  */
      /* If inside GENERIC, the following is not allowed.  */
      if (!generic)
      if (!generic)
        {
        {
 
 
          /* NOPASS flag.  */
          /* NOPASS flag.  */
          m = gfc_match (" nopass");
          m = gfc_match (" nopass");
          if (m == MATCH_ERROR)
          if (m == MATCH_ERROR)
            goto error;
            goto error;
          if (m == MATCH_YES)
          if (m == MATCH_YES)
            {
            {
              if (found_passing)
              if (found_passing)
                {
                {
                  gfc_error ("Binding attributes already specify passing,"
                  gfc_error ("Binding attributes already specify passing,"
                             " illegal NOPASS at %C");
                             " illegal NOPASS at %C");
                  goto error;
                  goto error;
                }
                }
 
 
              found_passing = true;
              found_passing = true;
              ba->nopass = 1;
              ba->nopass = 1;
              continue;
              continue;
            }
            }
 
 
          /* PASS possibly including argument.  */
          /* PASS possibly including argument.  */
          m = gfc_match (" pass");
          m = gfc_match (" pass");
          if (m == MATCH_ERROR)
          if (m == MATCH_ERROR)
            goto error;
            goto error;
          if (m == MATCH_YES)
          if (m == MATCH_YES)
            {
            {
              char arg[GFC_MAX_SYMBOL_LEN + 1];
              char arg[GFC_MAX_SYMBOL_LEN + 1];
 
 
              if (found_passing)
              if (found_passing)
                {
                {
                  gfc_error ("Binding attributes already specify passing,"
                  gfc_error ("Binding attributes already specify passing,"
                             " illegal PASS at %C");
                             " illegal PASS at %C");
                  goto error;
                  goto error;
                }
                }
 
 
              m = gfc_match (" ( %n )", arg);
              m = gfc_match (" ( %n )", arg);
              if (m == MATCH_ERROR)
              if (m == MATCH_ERROR)
                goto error;
                goto error;
              if (m == MATCH_YES)
              if (m == MATCH_YES)
                ba->pass_arg = gfc_get_string (arg);
                ba->pass_arg = gfc_get_string (arg);
              gcc_assert ((m == MATCH_YES) == (ba->pass_arg != NULL));
              gcc_assert ((m == MATCH_YES) == (ba->pass_arg != NULL));
 
 
              found_passing = true;
              found_passing = true;
              ba->nopass = 0;
              ba->nopass = 0;
              continue;
              continue;
            }
            }
 
 
          if (ppc)
          if (ppc)
            {
            {
              /* POINTER flag.  */
              /* POINTER flag.  */
              m = gfc_match (" pointer");
              m = gfc_match (" pointer");
              if (m == MATCH_ERROR)
              if (m == MATCH_ERROR)
                goto error;
                goto error;
              if (m == MATCH_YES)
              if (m == MATCH_YES)
                {
                {
                  if (seen_ptr)
                  if (seen_ptr)
                    {
                    {
                      gfc_error ("Duplicate POINTER attribute at %C");
                      gfc_error ("Duplicate POINTER attribute at %C");
                      goto error;
                      goto error;
                    }
                    }
 
 
                  seen_ptr = true;
                  seen_ptr = true;
                  continue;
                  continue;
                }
                }
            }
            }
          else
          else
            {
            {
              /* NON_OVERRIDABLE flag.  */
              /* NON_OVERRIDABLE flag.  */
              m = gfc_match (" non_overridable");
              m = gfc_match (" non_overridable");
              if (m == MATCH_ERROR)
              if (m == MATCH_ERROR)
                goto error;
                goto error;
              if (m == MATCH_YES)
              if (m == MATCH_YES)
                {
                {
                  if (ba->non_overridable)
                  if (ba->non_overridable)
                    {
                    {
                      gfc_error ("Duplicate NON_OVERRIDABLE at %C");
                      gfc_error ("Duplicate NON_OVERRIDABLE at %C");
                      goto error;
                      goto error;
                    }
                    }
 
 
                  ba->non_overridable = 1;
                  ba->non_overridable = 1;
                  continue;
                  continue;
                }
                }
 
 
              /* DEFERRED flag.  */
              /* DEFERRED flag.  */
              m = gfc_match (" deferred");
              m = gfc_match (" deferred");
              if (m == MATCH_ERROR)
              if (m == MATCH_ERROR)
                goto error;
                goto error;
              if (m == MATCH_YES)
              if (m == MATCH_YES)
                {
                {
                  if (ba->deferred)
                  if (ba->deferred)
                    {
                    {
                      gfc_error ("Duplicate DEFERRED at %C");
                      gfc_error ("Duplicate DEFERRED at %C");
                      goto error;
                      goto error;
                    }
                    }
 
 
                  ba->deferred = 1;
                  ba->deferred = 1;
                  continue;
                  continue;
                }
                }
            }
            }
 
 
        }
        }
 
 
      /* Nothing matching found.  */
      /* Nothing matching found.  */
      if (generic)
      if (generic)
        gfc_error ("Expected access-specifier at %C");
        gfc_error ("Expected access-specifier at %C");
      else
      else
        gfc_error ("Expected binding attribute at %C");
        gfc_error ("Expected binding attribute at %C");
      goto error;
      goto error;
    }
    }
  while (gfc_match_char (',') == MATCH_YES);
  while (gfc_match_char (',') == MATCH_YES);
 
 
  /* NON_OVERRIDABLE and DEFERRED exclude themselves.  */
  /* NON_OVERRIDABLE and DEFERRED exclude themselves.  */
  if (ba->non_overridable && ba->deferred)
  if (ba->non_overridable && ba->deferred)
    {
    {
      gfc_error ("NON_OVERRIDABLE and DEFERRED can't both appear at %C");
      gfc_error ("NON_OVERRIDABLE and DEFERRED can't both appear at %C");
      goto error;
      goto error;
    }
    }
 
 
  m = MATCH_YES;
  m = MATCH_YES;
 
 
done:
done:
  if (ba->access == ACCESS_UNKNOWN)
  if (ba->access == ACCESS_UNKNOWN)
    ba->access = gfc_typebound_default_access;
    ba->access = gfc_typebound_default_access;
 
 
  if (ppc && !seen_ptr)
  if (ppc && !seen_ptr)
    {
    {
      gfc_error ("POINTER attribute is required for procedure pointer component"
      gfc_error ("POINTER attribute is required for procedure pointer component"
                 " at %C");
                 " at %C");
      goto error;
      goto error;
    }
    }
 
 
  return m;
  return m;
 
 
error:
error:
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
/* Match a PROCEDURE specific binding inside a derived type.  */
/* Match a PROCEDURE specific binding inside a derived type.  */
 
 
static match
static match
match_procedure_in_type (void)
match_procedure_in_type (void)
{
{
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char target_buf[GFC_MAX_SYMBOL_LEN + 1];
  char target_buf[GFC_MAX_SYMBOL_LEN + 1];
  char* target = NULL;
  char* target = NULL;
  gfc_typebound_proc* tb;
  gfc_typebound_proc* tb;
  bool seen_colons;
  bool seen_colons;
  bool seen_attrs;
  bool seen_attrs;
  match m;
  match m;
  gfc_symtree* stree;
  gfc_symtree* stree;
  gfc_namespace* ns;
  gfc_namespace* ns;
  gfc_symbol* block;
  gfc_symbol* block;
 
 
  /* Check current state.  */
  /* Check current state.  */
  gcc_assert (gfc_state_stack->state == COMP_DERIVED_CONTAINS);
  gcc_assert (gfc_state_stack->state == COMP_DERIVED_CONTAINS);
  block = gfc_state_stack->previous->sym;
  block = gfc_state_stack->previous->sym;
  gcc_assert (block);
  gcc_assert (block);
 
 
  /* Try to match PROCEDURE(interface).  */
  /* Try to match PROCEDURE(interface).  */
  if (gfc_match (" (") == MATCH_YES)
  if (gfc_match (" (") == MATCH_YES)
    {
    {
      m = gfc_match_name (target_buf);
      m = gfc_match_name (target_buf);
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        return m;
        return m;
      if (m != MATCH_YES)
      if (m != MATCH_YES)
        {
        {
          gfc_error ("Interface-name expected after '(' at %C");
          gfc_error ("Interface-name expected after '(' at %C");
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
      if (gfc_match (" )") != MATCH_YES)
      if (gfc_match (" )") != MATCH_YES)
        {
        {
          gfc_error ("')' expected at %C");
          gfc_error ("')' expected at %C");
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
      target = target_buf;
      target = target_buf;
    }
    }
 
 
  /* Construct the data structure.  */
  /* Construct the data structure.  */
  tb = gfc_get_typebound_proc ();
  tb = gfc_get_typebound_proc ();
  tb->where = gfc_current_locus;
  tb->where = gfc_current_locus;
  tb->is_generic = 0;
  tb->is_generic = 0;
 
 
  /* Match binding attributes.  */
  /* Match binding attributes.  */
  m = match_binding_attributes (tb, false, false);
  m = match_binding_attributes (tb, false, false);
  if (m == MATCH_ERROR)
  if (m == MATCH_ERROR)
    return m;
    return m;
  seen_attrs = (m == MATCH_YES);
  seen_attrs = (m == MATCH_YES);
 
 
  /* Check that attribute DEFERRED is given iff an interface is specified, which
  /* Check that attribute DEFERRED is given iff an interface is specified, which
     means target != NULL.  */
     means target != NULL.  */
  if (tb->deferred && !target)
  if (tb->deferred && !target)
    {
    {
      gfc_error ("Interface must be specified for DEFERRED binding at %C");
      gfc_error ("Interface must be specified for DEFERRED binding at %C");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
  if (target && !tb->deferred)
  if (target && !tb->deferred)
    {
    {
      gfc_error ("PROCEDURE(interface) at %C should be declared DEFERRED");
      gfc_error ("PROCEDURE(interface) at %C should be declared DEFERRED");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  /* Match the colons.  */
  /* Match the colons.  */
  m = gfc_match (" ::");
  m = gfc_match (" ::");
  if (m == MATCH_ERROR)
  if (m == MATCH_ERROR)
    return m;
    return m;
  seen_colons = (m == MATCH_YES);
  seen_colons = (m == MATCH_YES);
  if (seen_attrs && !seen_colons)
  if (seen_attrs && !seen_colons)
    {
    {
      gfc_error ("Expected '::' after binding-attributes at %C");
      gfc_error ("Expected '::' after binding-attributes at %C");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  /* Match the binding name.  */
  /* Match the binding name.  */
  m = gfc_match_name (name);
  m = gfc_match_name (name);
  if (m == MATCH_ERROR)
  if (m == MATCH_ERROR)
    return m;
    return m;
  if (m == MATCH_NO)
  if (m == MATCH_NO)
    {
    {
      gfc_error ("Expected binding name at %C");
      gfc_error ("Expected binding name at %C");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  /* Try to match the '=> target', if it's there.  */
  /* Try to match the '=> target', if it's there.  */
  m = gfc_match (" =>");
  m = gfc_match (" =>");
  if (m == MATCH_ERROR)
  if (m == MATCH_ERROR)
    return m;
    return m;
  if (m == MATCH_YES)
  if (m == MATCH_YES)
    {
    {
      if (tb->deferred)
      if (tb->deferred)
        {
        {
          gfc_error ("'=> target' is invalid for DEFERRED binding at %C");
          gfc_error ("'=> target' is invalid for DEFERRED binding at %C");
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
      if (!seen_colons)
      if (!seen_colons)
        {
        {
          gfc_error ("'::' needed in PROCEDURE binding with explicit target"
          gfc_error ("'::' needed in PROCEDURE binding with explicit target"
                     " at %C");
                     " at %C");
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
      m = gfc_match_name (target_buf);
      m = gfc_match_name (target_buf);
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        return m;
        return m;
      if (m == MATCH_NO)
      if (m == MATCH_NO)
        {
        {
          gfc_error ("Expected binding target after '=>' at %C");
          gfc_error ("Expected binding target after '=>' at %C");
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
      target = target_buf;
      target = target_buf;
    }
    }
 
 
  /* Now we should have the end.  */
  /* Now we should have the end.  */
  m = gfc_match_eos ();
  m = gfc_match_eos ();
  if (m == MATCH_ERROR)
  if (m == MATCH_ERROR)
    return m;
    return m;
  if (m == MATCH_NO)
  if (m == MATCH_NO)
    {
    {
      gfc_error ("Junk after PROCEDURE declaration at %C");
      gfc_error ("Junk after PROCEDURE declaration at %C");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  /* If no target was found, it has the same name as the binding.  */
  /* If no target was found, it has the same name as the binding.  */
  if (!target)
  if (!target)
    target = name;
    target = name;
 
 
  /* Get the namespace to insert the symbols into.  */
  /* Get the namespace to insert the symbols into.  */
  ns = block->f2k_derived;
  ns = block->f2k_derived;
  gcc_assert (ns);
  gcc_assert (ns);
 
 
  /* If the binding is DEFERRED, check that the containing type is ABSTRACT.  */
  /* If the binding is DEFERRED, check that the containing type is ABSTRACT.  */
  if (tb->deferred && !block->attr.abstract)
  if (tb->deferred && !block->attr.abstract)
    {
    {
      gfc_error ("Type '%s' containing DEFERRED binding at %C is not ABSTRACT",
      gfc_error ("Type '%s' containing DEFERRED binding at %C is not ABSTRACT",
                 block->name);
                 block->name);
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  /* See if we already have a binding with this name in the symtree which would
  /* See if we already have a binding with this name in the symtree which would
     be an error.  If a GENERIC already targetted this binding, it may be
     be an error.  If a GENERIC already targetted this binding, it may be
     already there but then typebound is still NULL.  */
     already there but then typebound is still NULL.  */
  stree = gfc_find_symtree (ns->tb_sym_root, name);
  stree = gfc_find_symtree (ns->tb_sym_root, name);
  if (stree && stree->n.tb)
  if (stree && stree->n.tb)
    {
    {
      gfc_error ("There's already a procedure with binding name '%s' for the"
      gfc_error ("There's already a procedure with binding name '%s' for the"
                 " derived type '%s' at %C", name, block->name);
                 " derived type '%s' at %C", name, block->name);
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  /* Insert it and set attributes.  */
  /* Insert it and set attributes.  */
 
 
  if (!stree)
  if (!stree)
    {
    {
      stree = gfc_new_symtree (&ns->tb_sym_root, name);
      stree = gfc_new_symtree (&ns->tb_sym_root, name);
      gcc_assert (stree);
      gcc_assert (stree);
    }
    }
  stree->n.tb = tb;
  stree->n.tb = tb;
 
 
  if (gfc_get_sym_tree (target, gfc_current_ns, &tb->u.specific, false))
  if (gfc_get_sym_tree (target, gfc_current_ns, &tb->u.specific, false))
    return MATCH_ERROR;
    return MATCH_ERROR;
  gfc_set_sym_referenced (tb->u.specific->n.sym);
  gfc_set_sym_referenced (tb->u.specific->n.sym);
 
 
  return MATCH_YES;
  return MATCH_YES;
}
}
 
 
 
 
/* Match a GENERIC procedure binding inside a derived type.  */
/* Match a GENERIC procedure binding inside a derived type.  */
 
 
match
match
gfc_match_generic (void)
gfc_match_generic (void)
{
{
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char bind_name[GFC_MAX_SYMBOL_LEN + 16]; /* Allow space for OPERATOR(...).  */
  char bind_name[GFC_MAX_SYMBOL_LEN + 16]; /* Allow space for OPERATOR(...).  */
  gfc_symbol* block;
  gfc_symbol* block;
  gfc_typebound_proc tbattr; /* Used for match_binding_attributes.  */
  gfc_typebound_proc tbattr; /* Used for match_binding_attributes.  */
  gfc_typebound_proc* tb;
  gfc_typebound_proc* tb;
  gfc_namespace* ns;
  gfc_namespace* ns;
  interface_type op_type;
  interface_type op_type;
  gfc_intrinsic_op op;
  gfc_intrinsic_op op;
  match m;
  match m;
 
 
  /* Check current state.  */
  /* Check current state.  */
  if (gfc_current_state () == COMP_DERIVED)
  if (gfc_current_state () == COMP_DERIVED)
    {
    {
      gfc_error ("GENERIC at %C must be inside a derived-type CONTAINS");
      gfc_error ("GENERIC at %C must be inside a derived-type CONTAINS");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
  if (gfc_current_state () != COMP_DERIVED_CONTAINS)
  if (gfc_current_state () != COMP_DERIVED_CONTAINS)
    return MATCH_NO;
    return MATCH_NO;
  block = gfc_state_stack->previous->sym;
  block = gfc_state_stack->previous->sym;
  ns = block->f2k_derived;
  ns = block->f2k_derived;
  gcc_assert (block && ns);
  gcc_assert (block && ns);
 
 
  /* See if we get an access-specifier.  */
  /* See if we get an access-specifier.  */
  m = match_binding_attributes (&tbattr, true, false);
  m = match_binding_attributes (&tbattr, true, false);
  if (m == MATCH_ERROR)
  if (m == MATCH_ERROR)
    goto error;
    goto error;
 
 
  /* Now the colons, those are required.  */
  /* Now the colons, those are required.  */
  if (gfc_match (" ::") != MATCH_YES)
  if (gfc_match (" ::") != MATCH_YES)
    {
    {
      gfc_error ("Expected '::' at %C");
      gfc_error ("Expected '::' at %C");
      goto error;
      goto error;
    }
    }
 
 
  /* Match the binding name; depending on type (operator / generic) format
  /* Match the binding name; depending on type (operator / generic) format
     it for future error messages into bind_name.  */
     it for future error messages into bind_name.  */
 
 
  m = gfc_match_generic_spec (&op_type, name, &op);
  m = gfc_match_generic_spec (&op_type, name, &op);
  if (m == MATCH_ERROR)
  if (m == MATCH_ERROR)
    return MATCH_ERROR;
    return MATCH_ERROR;
  if (m == MATCH_NO)
  if (m == MATCH_NO)
    {
    {
      gfc_error ("Expected generic name or operator descriptor at %C");
      gfc_error ("Expected generic name or operator descriptor at %C");
      goto error;
      goto error;
    }
    }
 
 
  switch (op_type)
  switch (op_type)
    {
    {
    case INTERFACE_GENERIC:
    case INTERFACE_GENERIC:
      snprintf (bind_name, sizeof (bind_name), "%s", name);
      snprintf (bind_name, sizeof (bind_name), "%s", name);
      break;
      break;
 
 
    case INTERFACE_USER_OP:
    case INTERFACE_USER_OP:
      snprintf (bind_name, sizeof (bind_name), "OPERATOR(.%s.)", name);
      snprintf (bind_name, sizeof (bind_name), "OPERATOR(.%s.)", name);
      break;
      break;
 
 
    case INTERFACE_INTRINSIC_OP:
    case INTERFACE_INTRINSIC_OP:
      snprintf (bind_name, sizeof (bind_name), "OPERATOR(%s)",
      snprintf (bind_name, sizeof (bind_name), "OPERATOR(%s)",
                gfc_op2string (op));
                gfc_op2string (op));
      break;
      break;
 
 
    default:
    default:
      gcc_unreachable ();
      gcc_unreachable ();
    }
    }
 
 
  /* Match the required =>.  */
  /* Match the required =>.  */
  if (gfc_match (" =>") != MATCH_YES)
  if (gfc_match (" =>") != MATCH_YES)
    {
    {
      gfc_error ("Expected '=>' at %C");
      gfc_error ("Expected '=>' at %C");
      goto error;
      goto error;
    }
    }
 
 
  /* Try to find existing GENERIC binding with this name / for this operator;
  /* Try to find existing GENERIC binding with this name / for this operator;
     if there is something, check that it is another GENERIC and then extend
     if there is something, check that it is another GENERIC and then extend
     it rather than building a new node.  Otherwise, create it and put it
     it rather than building a new node.  Otherwise, create it and put it
     at the right position.  */
     at the right position.  */
 
 
  switch (op_type)
  switch (op_type)
    {
    {
    case INTERFACE_USER_OP:
    case INTERFACE_USER_OP:
    case INTERFACE_GENERIC:
    case INTERFACE_GENERIC:
      {
      {
        const bool is_op = (op_type == INTERFACE_USER_OP);
        const bool is_op = (op_type == INTERFACE_USER_OP);
        gfc_symtree* st;
        gfc_symtree* st;
 
 
        st = gfc_find_symtree (is_op ? ns->tb_uop_root : ns->tb_sym_root, name);
        st = gfc_find_symtree (is_op ? ns->tb_uop_root : ns->tb_sym_root, name);
        if (st)
        if (st)
          {
          {
            tb = st->n.tb;
            tb = st->n.tb;
            gcc_assert (tb);
            gcc_assert (tb);
          }
          }
        else
        else
          tb = NULL;
          tb = NULL;
 
 
        break;
        break;
      }
      }
 
 
    case INTERFACE_INTRINSIC_OP:
    case INTERFACE_INTRINSIC_OP:
      tb = ns->tb_op[op];
      tb = ns->tb_op[op];
      break;
      break;
 
 
    default:
    default:
      gcc_unreachable ();
      gcc_unreachable ();
    }
    }
 
 
  if (tb)
  if (tb)
    {
    {
      if (!tb->is_generic)
      if (!tb->is_generic)
        {
        {
          gcc_assert (op_type == INTERFACE_GENERIC);
          gcc_assert (op_type == INTERFACE_GENERIC);
          gfc_error ("There's already a non-generic procedure with binding name"
          gfc_error ("There's already a non-generic procedure with binding name"
                     " '%s' for the derived type '%s' at %C",
                     " '%s' for the derived type '%s' at %C",
                     bind_name, block->name);
                     bind_name, block->name);
          goto error;
          goto error;
        }
        }
 
 
      if (tb->access != tbattr.access)
      if (tb->access != tbattr.access)
        {
        {
          gfc_error ("Binding at %C must have the same access as already"
          gfc_error ("Binding at %C must have the same access as already"
                     " defined binding '%s'", bind_name);
                     " defined binding '%s'", bind_name);
          goto error;
          goto error;
        }
        }
    }
    }
  else
  else
    {
    {
      tb = gfc_get_typebound_proc ();
      tb = gfc_get_typebound_proc ();
      tb->where = gfc_current_locus;
      tb->where = gfc_current_locus;
      tb->access = tbattr.access;
      tb->access = tbattr.access;
      tb->is_generic = 1;
      tb->is_generic = 1;
      tb->u.generic = NULL;
      tb->u.generic = NULL;
 
 
      switch (op_type)
      switch (op_type)
        {
        {
        case INTERFACE_GENERIC:
        case INTERFACE_GENERIC:
        case INTERFACE_USER_OP:
        case INTERFACE_USER_OP:
          {
          {
            const bool is_op = (op_type == INTERFACE_USER_OP);
            const bool is_op = (op_type == INTERFACE_USER_OP);
            gfc_symtree* st;
            gfc_symtree* st;
 
 
            st = gfc_new_symtree (is_op ? &ns->tb_uop_root : &ns->tb_sym_root,
            st = gfc_new_symtree (is_op ? &ns->tb_uop_root : &ns->tb_sym_root,
                                  name);
                                  name);
            gcc_assert (st);
            gcc_assert (st);
            st->n.tb = tb;
            st->n.tb = tb;
 
 
            break;
            break;
          }
          }
 
 
        case INTERFACE_INTRINSIC_OP:
        case INTERFACE_INTRINSIC_OP:
          ns->tb_op[op] = tb;
          ns->tb_op[op] = tb;
          break;
          break;
 
 
        default:
        default:
          gcc_unreachable ();
          gcc_unreachable ();
        }
        }
    }
    }
 
 
  /* Now, match all following names as specific targets.  */
  /* Now, match all following names as specific targets.  */
  do
  do
    {
    {
      gfc_symtree* target_st;
      gfc_symtree* target_st;
      gfc_tbp_generic* target;
      gfc_tbp_generic* target;
 
 
      m = gfc_match_name (name);
      m = gfc_match_name (name);
      if (m == MATCH_ERROR)
      if (m == MATCH_ERROR)
        goto error;
        goto error;
      if (m == MATCH_NO)
      if (m == MATCH_NO)
        {
        {
          gfc_error ("Expected specific binding name at %C");
          gfc_error ("Expected specific binding name at %C");
          goto error;
          goto error;
        }
        }
 
 
      target_st = gfc_get_tbp_symtree (&ns->tb_sym_root, name);
      target_st = gfc_get_tbp_symtree (&ns->tb_sym_root, name);
 
 
      /* See if this is a duplicate specification.  */
      /* See if this is a duplicate specification.  */
      for (target = tb->u.generic; target; target = target->next)
      for (target = tb->u.generic; target; target = target->next)
        if (target_st == target->specific_st)
        if (target_st == target->specific_st)
          {
          {
            gfc_error ("'%s' already defined as specific binding for the"
            gfc_error ("'%s' already defined as specific binding for the"
                       " generic '%s' at %C", name, bind_name);
                       " generic '%s' at %C", name, bind_name);
            goto error;
            goto error;
          }
          }
 
 
      target = gfc_get_tbp_generic ();
      target = gfc_get_tbp_generic ();
      target->specific_st = target_st;
      target->specific_st = target_st;
      target->specific = NULL;
      target->specific = NULL;
      target->next = tb->u.generic;
      target->next = tb->u.generic;
      tb->u.generic = target;
      tb->u.generic = target;
    }
    }
  while (gfc_match (" ,") == MATCH_YES);
  while (gfc_match (" ,") == MATCH_YES);
 
 
  /* Here should be the end.  */
  /* Here should be the end.  */
  if (gfc_match_eos () != MATCH_YES)
  if (gfc_match_eos () != MATCH_YES)
    {
    {
      gfc_error ("Junk after GENERIC binding at %C");
      gfc_error ("Junk after GENERIC binding at %C");
      goto error;
      goto error;
    }
    }
 
 
  return MATCH_YES;
  return MATCH_YES;
 
 
error:
error:
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 
 
 
/* Match a FINAL declaration inside a derived type.  */
/* Match a FINAL declaration inside a derived type.  */
 
 
match
match
gfc_match_final_decl (void)
gfc_match_final_decl (void)
{
{
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
  gfc_symbol* sym;
  gfc_symbol* sym;
  match m;
  match m;
  gfc_namespace* module_ns;
  gfc_namespace* module_ns;
  bool first, last;
  bool first, last;
  gfc_symbol* block;
  gfc_symbol* block;
 
 
  if (gfc_current_form == FORM_FREE)
  if (gfc_current_form == FORM_FREE)
    {
    {
      char c = gfc_peek_ascii_char ();
      char c = gfc_peek_ascii_char ();
      if (!gfc_is_whitespace (c) && c != ':')
      if (!gfc_is_whitespace (c) && c != ':')
        return MATCH_NO;
        return MATCH_NO;
    }
    }
 
 
  if (gfc_state_stack->state != COMP_DERIVED_CONTAINS)
  if (gfc_state_stack->state != COMP_DERIVED_CONTAINS)
    {
    {
      if (gfc_current_form == FORM_FIXED)
      if (gfc_current_form == FORM_FIXED)
        return MATCH_NO;
        return MATCH_NO;
 
 
      gfc_error ("FINAL declaration at %C must be inside a derived type "
      gfc_error ("FINAL declaration at %C must be inside a derived type "
                 "CONTAINS section");
                 "CONTAINS section");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  block = gfc_state_stack->previous->sym;
  block = gfc_state_stack->previous->sym;
  gcc_assert (block);
  gcc_assert (block);
 
 
  if (!gfc_state_stack->previous || !gfc_state_stack->previous->previous
  if (!gfc_state_stack->previous || !gfc_state_stack->previous->previous
      || gfc_state_stack->previous->previous->state != COMP_MODULE)
      || gfc_state_stack->previous->previous->state != COMP_MODULE)
    {
    {
      gfc_error ("Derived type declaration with FINAL at %C must be in the"
      gfc_error ("Derived type declaration with FINAL at %C must be in the"
                 " specification part of a MODULE");
                 " specification part of a MODULE");
      return MATCH_ERROR;
      return MATCH_ERROR;
    }
    }
 
 
  module_ns = gfc_current_ns;
  module_ns = gfc_current_ns;
  gcc_assert (module_ns);
  gcc_assert (module_ns);
  gcc_assert (module_ns->proc_name->attr.flavor == FL_MODULE);
  gcc_assert (module_ns->proc_name->attr.flavor == FL_MODULE);
 
 
  /* Match optional ::, don't care about MATCH_YES or MATCH_NO.  */
  /* Match optional ::, don't care about MATCH_YES or MATCH_NO.  */
  if (gfc_match (" ::") == MATCH_ERROR)
  if (gfc_match (" ::") == MATCH_ERROR)
    return MATCH_ERROR;
    return MATCH_ERROR;
 
 
  /* Match the sequence of procedure names.  */
  /* Match the sequence of procedure names.  */
  first = true;
  first = true;
  last = false;
  last = false;
  do
  do
    {
    {
      gfc_finalizer* f;
      gfc_finalizer* f;
 
 
      if (first && gfc_match_eos () == MATCH_YES)
      if (first && gfc_match_eos () == MATCH_YES)
        {
        {
          gfc_error ("Empty FINAL at %C");
          gfc_error ("Empty FINAL at %C");
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
      m = gfc_match_name (name);
      m = gfc_match_name (name);
      if (m == MATCH_NO)
      if (m == MATCH_NO)
        {
        {
          gfc_error ("Expected module procedure name at %C");
          gfc_error ("Expected module procedure name at %C");
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
      else if (m != MATCH_YES)
      else if (m != MATCH_YES)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      if (gfc_match_eos () == MATCH_YES)
      if (gfc_match_eos () == MATCH_YES)
        last = true;
        last = true;
      if (!last && gfc_match_char (',') != MATCH_YES)
      if (!last && gfc_match_char (',') != MATCH_YES)
        {
        {
          gfc_error ("Expected ',' at %C");
          gfc_error ("Expected ',' at %C");
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
      if (gfc_get_symbol (name, module_ns, &sym))
      if (gfc_get_symbol (name, module_ns, &sym))
        {
        {
          gfc_error ("Unknown procedure name \"%s\" at %C", name);
          gfc_error ("Unknown procedure name \"%s\" at %C", name);
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
      /* Mark the symbol as module procedure.  */
      /* Mark the symbol as module procedure.  */
      if (sym->attr.proc != PROC_MODULE
      if (sym->attr.proc != PROC_MODULE
          && gfc_add_procedure (&sym->attr, PROC_MODULE,
          && gfc_add_procedure (&sym->attr, PROC_MODULE,
                                sym->name, NULL) == FAILURE)
                                sym->name, NULL) == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      /* Check if we already have this symbol in the list, this is an error.  */
      /* Check if we already have this symbol in the list, this is an error.  */
      for (f = block->f2k_derived->finalizers; f; f = f->next)
      for (f = block->f2k_derived->finalizers; f; f = f->next)
        if (f->proc_sym == sym)
        if (f->proc_sym == sym)
          {
          {
            gfc_error ("'%s' at %C is already defined as FINAL procedure!",
            gfc_error ("'%s' at %C is already defined as FINAL procedure!",
                       name);
                       name);
            return MATCH_ERROR;
            return MATCH_ERROR;
          }
          }
 
 
      /* Add this symbol to the list of finalizers.  */
      /* Add this symbol to the list of finalizers.  */
      gcc_assert (block->f2k_derived);
      gcc_assert (block->f2k_derived);
      ++sym->refs;
      ++sym->refs;
      f = XCNEW (gfc_finalizer);
      f = XCNEW (gfc_finalizer);
      f->proc_sym = sym;
      f->proc_sym = sym;
      f->proc_tree = NULL;
      f->proc_tree = NULL;
      f->where = gfc_current_locus;
      f->where = gfc_current_locus;
      f->next = block->f2k_derived->finalizers;
      f->next = block->f2k_derived->finalizers;
      block->f2k_derived->finalizers = f;
      block->f2k_derived->finalizers = f;
 
 
      first = false;
      first = false;
    }
    }
  while (!last);
  while (!last);
 
 
  return MATCH_YES;
  return MATCH_YES;
}
}
 
 
 
 
const ext_attr_t ext_attr_list[] = {
const ext_attr_t ext_attr_list[] = {
  { "dllimport", EXT_ATTR_DLLIMPORT, "dllimport" },
  { "dllimport", EXT_ATTR_DLLIMPORT, "dllimport" },
  { "dllexport", EXT_ATTR_DLLEXPORT, "dllexport" },
  { "dllexport", EXT_ATTR_DLLEXPORT, "dllexport" },
  { "cdecl",     EXT_ATTR_CDECL,     "cdecl"     },
  { "cdecl",     EXT_ATTR_CDECL,     "cdecl"     },
  { "stdcall",   EXT_ATTR_STDCALL,   "stdcall"   },
  { "stdcall",   EXT_ATTR_STDCALL,   "stdcall"   },
  { "fastcall",  EXT_ATTR_FASTCALL,  "fastcall"  },
  { "fastcall",  EXT_ATTR_FASTCALL,  "fastcall"  },
  { NULL,        EXT_ATTR_LAST,      NULL        }
  { NULL,        EXT_ATTR_LAST,      NULL        }
};
};
 
 
/* Match a !GCC$ ATTRIBUTES statement of the form:
/* Match a !GCC$ ATTRIBUTES statement of the form:
      !GCC$ ATTRIBUTES attribute-list :: var-name [, var-name] ...
      !GCC$ ATTRIBUTES attribute-list :: var-name [, var-name] ...
   When we come here, we have already matched the !GCC$ ATTRIBUTES string.
   When we come here, we have already matched the !GCC$ ATTRIBUTES string.
 
 
   TODO: We should support all GCC attributes using the same syntax for
   TODO: We should support all GCC attributes using the same syntax for
   the attribute list, i.e. the list in C
   the attribute list, i.e. the list in C
      __attributes(( attribute-list ))
      __attributes(( attribute-list ))
   matches then
   matches then
      !GCC$ ATTRIBUTES attribute-list ::
      !GCC$ ATTRIBUTES attribute-list ::
   Cf. c-parser.c's c_parser_attributes; the data can then directly be
   Cf. c-parser.c's c_parser_attributes; the data can then directly be
   saved into a TREE.
   saved into a TREE.
 
 
   As there is absolutely no risk of confusion, we should never return
   As there is absolutely no risk of confusion, we should never return
   MATCH_NO.  */
   MATCH_NO.  */
match
match
gfc_match_gcc_attributes (void)
gfc_match_gcc_attributes (void)
{
{
  symbol_attribute attr;
  symbol_attribute attr;
  char name[GFC_MAX_SYMBOL_LEN + 1];
  char name[GFC_MAX_SYMBOL_LEN + 1];
  unsigned id;
  unsigned id;
  gfc_symbol *sym;
  gfc_symbol *sym;
  match m;
  match m;
 
 
  gfc_clear_attr (&attr);
  gfc_clear_attr (&attr);
  for(;;)
  for(;;)
    {
    {
      char ch;
      char ch;
 
 
      if (gfc_match_name (name) != MATCH_YES)
      if (gfc_match_name (name) != MATCH_YES)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      for (id = 0; id < EXT_ATTR_LAST; id++)
      for (id = 0; id < EXT_ATTR_LAST; id++)
        if (strcmp (name, ext_attr_list[id].name) == 0)
        if (strcmp (name, ext_attr_list[id].name) == 0)
          break;
          break;
 
 
      if (id == EXT_ATTR_LAST)
      if (id == EXT_ATTR_LAST)
        {
        {
          gfc_error ("Unknown attribute in !GCC$ ATTRIBUTES statement at %C");
          gfc_error ("Unknown attribute in !GCC$ ATTRIBUTES statement at %C");
          return MATCH_ERROR;
          return MATCH_ERROR;
        }
        }
 
 
      if (gfc_add_ext_attribute (&attr, (ext_attr_id_t) id, &gfc_current_locus)
      if (gfc_add_ext_attribute (&attr, (ext_attr_id_t) id, &gfc_current_locus)
          == FAILURE)
          == FAILURE)
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      gfc_gobble_whitespace ();
      gfc_gobble_whitespace ();
      ch = gfc_next_ascii_char ();
      ch = gfc_next_ascii_char ();
      if (ch == ':')
      if (ch == ':')
        {
        {
          /* This is the successful exit condition for the loop.  */
          /* This is the successful exit condition for the loop.  */
          if (gfc_next_ascii_char () == ':')
          if (gfc_next_ascii_char () == ':')
            break;
            break;
        }
        }
 
 
      if (ch == ',')
      if (ch == ',')
        continue;
        continue;
 
 
      goto syntax;
      goto syntax;
    }
    }
 
 
  if (gfc_match_eos () == MATCH_YES)
  if (gfc_match_eos () == MATCH_YES)
    goto syntax;
    goto syntax;
 
 
  for(;;)
  for(;;)
    {
    {
      m = gfc_match_name (name);
      m = gfc_match_name (name);
      if (m != MATCH_YES)
      if (m != MATCH_YES)
        return m;
        return m;
 
 
      if (find_special (name, &sym, true))
      if (find_special (name, &sym, true))
        return MATCH_ERROR;
        return MATCH_ERROR;
 
 
      sym->attr.ext_attr |= attr.ext_attr;
      sym->attr.ext_attr |= attr.ext_attr;
 
 
      if (gfc_match_eos () == MATCH_YES)
      if (gfc_match_eos () == MATCH_YES)
        break;
        break;
 
 
      if (gfc_match_char (',') != MATCH_YES)
      if (gfc_match_char (',') != MATCH_YES)
        goto syntax;
        goto syntax;
    }
    }
 
 
  return MATCH_YES;
  return MATCH_YES;
 
 
syntax:
syntax:
  gfc_error ("Syntax error in !GCC$ ATTRIBUTES statement at %C");
  gfc_error ("Syntax error in !GCC$ ATTRIBUTES statement at %C");
  return MATCH_ERROR;
  return MATCH_ERROR;
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.