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