/* Declaration statement matcher
Copyright (C) 2002-2022 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
. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "options.h"
#include "tree.h"
#include "gfortran.h"
#include "stringpool.h"
#include "match.h"
#include "parse.h"
#include "constructor.h"
#include "target.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 bool 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;
static int attr_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;
/* Set upon parsing a !GCC$ unroll n directive for use in the next loop. */
int directive_unroll = -1;
/* Set upon parsing supported !GCC$ pragmas for use in the next loop. */
bool directive_ivdep = false;
bool directive_vector = false;
bool directive_novector = false;
/* Map of middle-end built-ins that should be vectorized. */
hash_map *gfc_vectorized_builtins;
/* If a kind expression of a component of a parameterized derived type is
parameterized, temporarily store the expression here. */
static gfc_expr *saved_kind_expr = NULL;
/* Used to store the parameter list arising in a PDT declaration and
in the typespec of a PDT variable or component. */
static gfc_actual_arglist *decl_type_param_list;
static gfc_actual_arglist *type_param_spec_list;
/********************* 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;
}
}
/* Reject data parsed since the last restore point was marked. */
void
gfc_reject_data (gfc_namespace *ns)
{
gfc_data *d;
while (ns->data && ns->data != ns->old_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;
if (new_var->expr->expr_type == EXPR_CONSTANT
&& new_var->expr->symtree == NULL)
{
gfc_error ("Inquiry parameter cannot appear in a "
"data-stmt-object-list at %C");
return MATCH_ERROR;
}
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))
return MATCH_ERROR;
if (!sym->attr.function && gfc_current_ns->parent
&& gfc_current_ns->parent == sym->ns)
{
gfc_error ("Host associated variable %qs 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 %qs in DATA statement at %C",
sym->name))
return MATCH_ERROR;
if (!gfc_add_data (&sym->attr, sym->name, &new_var->expr->where))
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 (new_var->expr)
new_var->expr->where = gfc_current_locus;
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))
m = MATCH_ERROR;
return m;
}
else if (m == MATCH_YES)
{
/* If a parameter inquiry ends up here, symtree is NULL but **result
contains the right constant expression. Check here. */
if ((*result)->symtree == NULL
&& (*result)->expr_type == EXPR_CONSTANT
&& ((*result)->ts.type == BT_INTEGER
|| (*result)->ts.type == BT_REAL))
return m;
/* F2018:R845 data-stmt-constant is initial-data-target.
A data-stmt-constant shall be ... initial-data-target if and
only if the corresponding data-stmt-object has the POINTER
attribute. ... If data-stmt-constant is initial-data-target
the corresponding data statement object shall be
data-pointer-initialization compatible (7.5.4.6) with the initial
data target; the data statement object is initially associated
with the target. */
if ((*result)->symtree->n.sym->attr.save
&& (*result)->symtree->n.sym->attr.target)
return m;
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 || !gfc_fl_struct (dt_sym->attr.flavor))))
{
gfc_error ("Symbol %qs must be a PARAMETER in DATA statement at %C",
name);
*result = NULL;
return MATCH_ERROR;
}
else if (dt_sym && gfc_fl_struct (dt_sym->attr.flavor))
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))
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, *nd;
/* 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->var->expr->where = sym->declared_at;
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;
}
/* Check that a BOZ did not creep into an old-style initialization. */
for (nd = newdata; nd; nd = nd->next)
{
if (nd->value->expr->ts.type == BT_BOZ
&& gfc_invalid_boz (G_("BOZ at %L cannot appear in an old-style "
"initialization"), &nd->value->expr->where))
return MATCH_ERROR;
if (nd->var->expr->ts.type != BT_INTEGER
&& nd->var->expr->ts.type != BT_REAL
&& nd->value->expr->ts.type == BT_BOZ)
{
gfc_error (G_("BOZ literal constant near %L cannot be assigned to "
"a %qs variable in an old-style initialization"),
&nd->value->expr->where,
gfc_typename (&nd->value->expr->ts));
return MATCH_ERROR;
}
}
if (gfc_pure (NULL))
{
gfc_error ("Initialization at %C is not allowed in a PURE procedure");
free (newdata);
return MATCH_ERROR;
}
gfc_unset_implicit_pure (gfc_current_ns->proc_name);
/* Mark the variable as having appeared in a data statement. */
if (!gfc_add_data (&sym->attr, sym->name, &sym->declared_at))
{
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;
gfc_expr *e;
gfc_ref *ref;
match m;
char c;
/* DATA has been matched. In free form source code, the next character
needs to be whitespace or '(' from an implied do-loop. Check that
here. */
c = gfc_peek_ascii_char ();
if (gfc_current_form == FORM_FREE && !gfc_is_whitespace (c) && c != '(')
return MATCH_NO;
/* Before parsing the rest of a DATA statement, check F2008:c1206. */
if ((gfc_current_state () == COMP_FUNCTION
|| gfc_current_state () == COMP_SUBROUTINE)
&& gfc_state_stack->previous->state == COMP_INTERFACE)
{
gfc_error ("DATA statement at %C cannot appear within an INTERFACE");
return MATCH_ERROR;
}
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;
if (new_data->var->iter.var
&& new_data->var->iter.var->ts.type == BT_INTEGER
&& new_data->var->iter.var->symtree->n.sym->attr.implied_index == 1
&& new_data->var->list
&& new_data->var->list->expr
&& new_data->var->list->expr->ts.type == BT_CHARACTER
&& new_data->var->list->expr->ref
&& new_data->var->list->expr->ref->type == REF_SUBSTRING)
{
gfc_error ("Invalid substring in data-implied-do at %L in DATA "
"statement", &new_data->var->list->expr->where);
goto cleanup;
}
/* Check for an entity with an allocatable component, which is not
allowed. */
e = new_data->var->expr;
if (e)
{
bool invalid;
invalid = false;
for (ref = e->ref; ref; ref = ref->next)
if ((ref->type == REF_COMPONENT
&& ref->u.c.component->attr.allocatable)
|| (ref->type == REF_ARRAY
&& e->symtree->n.sym->attr.pointer != 1
&& ref->u.ar.as && ref->u.ar.as->type == AS_DEFERRED))
invalid = true;
if (invalid)
{
gfc_error ("Allocatable component or deferred-shaped array "
"near %C in DATA statement");
goto cleanup;
}
/* F2008:C567 (R536) A data-i-do-object or a variable that appears
as a data-stmt-object shall not be an object designator in which
a pointer appears other than as the entire rightmost part-ref. */
if (!e->ref && e->ts.type == BT_DERIVED
&& e->symtree->n.sym->attr.pointer)
goto partref;
ref = e->ref;
if (e->symtree->n.sym->ts.type == BT_DERIVED
&& e->symtree->n.sym->attr.pointer
&& ref->type == REF_COMPONENT)
goto partref;
for (; ref; ref = ref->next)
if (ref->type == REF_COMPONENT
&& ref->u.c.component->attr.pointer
&& ref->next)
goto partref;
}
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;
/* A BOZ literal constant cannot appear in a structure constructor.
Check for that here for a data statement value. */
if (new_data->value->expr->ts.type == BT_DERIVED
&& new_data->value->expr->value.constructor)
{
gfc_constructor *c;
c = gfc_constructor_first (new_data->value->expr->value.constructor);
for (; c; c = gfc_constructor_next (c))
if (c->expr && c->expr->ts.type == BT_BOZ)
{
gfc_error ("BOZ literal constant at %L cannot appear in a "
"structure constructor", &c->expr->where);
return MATCH_ERROR;
}
}
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;
}
gfc_unset_implicit_pure (gfc_current_ns->proc_name);
return MATCH_YES;
partref:
gfc_error ("part-ref with pointer attribute near %L is not "
"rightmost part-ref of data-stmt-object",
&e->where);
cleanup:
set_in_match_data (false);
gfc_free_data (new_data);
return MATCH_ERROR;
}
/************************ Declaration statements *********************/
/* Like gfc_match_init_expr, but matches a 'clist' (old-style initialization
list). The difference here is the expression is a list of constants
and is surrounded by '/'.
The typespec ts must match the typespec of the variable which the
clist is initializing.
The arrayspec tells whether this should match a list of constants
corresponding to array elements or a scalar (as == NULL). */
static match
match_clist_expr (gfc_expr **result, gfc_typespec *ts, gfc_array_spec *as)
{
gfc_constructor_base array_head = NULL;
gfc_expr *expr = NULL;
match m = MATCH_ERROR;
locus where;
mpz_t repeat, cons_size, as_size;
bool scalar;
int cmp;
gcc_assert (ts);
/* We have already matched '/' - now look for a constant list, as with
top_val_list from decl.c, but append the result to an array. */
if (gfc_match ("/") == MATCH_YES)
{
gfc_error ("Empty old style initializer list at %C");
return MATCH_ERROR;
}
where = gfc_current_locus;
scalar = !as || !as->rank;
if (!scalar && !spec_size (as, &as_size))
{
gfc_error ("Array in initializer list at %L must have an explicit shape",
as->type == AS_EXPLICIT ? &as->upper[0]->where : &where);
/* Nothing to cleanup yet. */
return MATCH_ERROR;
}
mpz_init_set_ui (repeat, 0);
for (;;)
{
m = match_data_constant (&expr);
if (m != MATCH_YES)
expr = NULL; /* match_data_constant may set expr to garbage */
if (m == MATCH_NO)
goto syntax;
if (m == MATCH_ERROR)
goto cleanup;
/* Found r in repeat spec r*c; look for the constant to repeat. */
if ( gfc_match_char ('*') == MATCH_YES)
{
if (scalar)
{
gfc_error ("Repeat spec invalid in scalar initializer at %C");
goto cleanup;
}
if (expr->ts.type != BT_INTEGER)
{
gfc_error ("Repeat spec must be an integer at %C");
goto cleanup;
}
mpz_set (repeat, expr->value.integer);
gfc_free_expr (expr);
expr = NULL;
m = match_data_constant (&expr);
if (m == MATCH_NO)
{
m = MATCH_ERROR;
gfc_error ("Expected data constant after repeat spec at %C");
}
if (m != MATCH_YES)
goto cleanup;
}
/* No repeat spec, we matched the data constant itself. */
else
mpz_set_ui (repeat, 1);
if (!scalar)
{
/* Add the constant initializer as many times as repeated. */
for (; mpz_cmp_ui (repeat, 0) > 0; mpz_sub_ui (repeat, repeat, 1))
{
/* Make sure types of elements match */
if(ts && !gfc_compare_types (&expr->ts, ts)
&& !gfc_convert_type (expr, ts, 1))
goto cleanup;
gfc_constructor_append_expr (&array_head,
gfc_copy_expr (expr), &gfc_current_locus);
}
gfc_free_expr (expr);
expr = NULL;
}
/* For scalar initializers quit after one element. */
else
{
if(gfc_match_char ('/') != MATCH_YES)
{
gfc_error ("End of scalar initializer expected at %C");
goto cleanup;
}
break;
}
if (gfc_match_char ('/') == MATCH_YES)
break;
if (gfc_match_char (',') == MATCH_NO)
goto syntax;
}
/* If we break early from here out, we encountered an error. */
m = MATCH_ERROR;
/* Set up expr as an array constructor. */
if (!scalar)
{
expr = gfc_get_array_expr (ts->type, ts->kind, &where);
expr->ts = *ts;
expr->value.constructor = array_head;
/* Validate sizes. We built expr ourselves, so cons_size will be
constant (we fail above for non-constant expressions).
We still need to verify that the sizes match. */
gcc_assert (gfc_array_size (expr, &cons_size));
cmp = mpz_cmp (cons_size, as_size);
if (cmp < 0)
gfc_error ("Not enough elements in array initializer at %C");
else if (cmp > 0)
gfc_error ("Too many elements in array initializer at %C");
mpz_clear (cons_size);
if (cmp)
goto cleanup;
/* Set the rank/shape to match the LHS as auto-reshape is implied. */
expr->rank = as->rank;
expr->shape = gfc_get_shape (as->rank);
for (int i = 0; i < as->rank; ++i)
spec_dimen_size (as, i, &expr->shape[i]);
}
/* Make sure scalar types match. */
else if (!gfc_compare_types (&expr->ts, ts)
&& !gfc_convert_type (expr, ts, 1))
goto cleanup;
if (expr->ts.u.cl)
expr->ts.u.cl->length_from_typespec = 1;
*result = expr;
m = MATCH_YES;
goto done;
syntax:
m = MATCH_ERROR;
gfc_error ("Syntax error in old style initializer list at %C");
cleanup:
if (expr)
expr->value.constructor = NULL;
gfc_free_expr (expr);
gfc_constructor_free (array_head);
done:
mpz_clear (repeat);
if (!scalar)
mpz_clear (as_size);
return m;
}
/* Auxiliary function to merge DIMENSION and CODIMENSION array specs. */
static bool
merge_array_spec (gfc_array_spec *from, gfc_array_spec *to, bool copy)
{
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 false;
}
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 (int i = to->corank - 1; i >= 0; i--)
{
/* Do not exceed the limits on lower[] and upper[]. gfortran
cleans up elsewhere. */
int j = from->rank + i;
if (j >= GFC_MAX_DIMENSIONS)
break;
to->lower[j] = to->lower[i];
to->upper[j] = to->upper[i];
}
for (int 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 (int i = 0; i < from->corank; i++)
{
/* Do not exceed the limits on lower[] and upper[]. gfortran
cleans up elsewhere. */
int k = from->rank + i;
int j = to->rank + i;
if (j >= GFC_MAX_DIMENSIONS)
break;
if (copy)
{
to->lower[j] = gfc_copy_expr (from->lower[k]);
to->upper[j] = gfc_copy_expr (from->upper[k]);
}
else
{
to->lower[j] = from->lower[k];
to->upper[j] = from->upper[k];
}
}
}
if (to->rank + to->corank > GFC_MAX_DIMENSIONS)
{
gfc_error ("Sum of array rank %d and corank %d at %C exceeds maximum "
"allowed dimensions of %d",
to->rank, to->corank, GFC_MAX_DIMENSIONS);
to->corank = GFC_MAX_DIMENSIONS - to->rank;
return false;
}
return true;
}
/* 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"))
return MATCH_ERROR;
*deferred = true;
return MATCH_YES;
}
m = gfc_match_expr (expr);
if (m == MATCH_NO || m == MATCH_ERROR)
return m;
if (!gfc_expr_check_typed (*expr, gfc_current_ns, false))
return MATCH_ERROR;
/* If gfortran gets an EXPR_OP, try to simplifiy it. This catches things
like CHARACTER(([1])). */
if ((*expr)->expr_type == EXPR_OP)
gfc_simplify_expr (*expr, 1);
if ((*expr)->expr_type == EXPR_FUNCTION)
{
if ((*expr)->ts.type == BT_INTEGER
|| ((*expr)->ts.type == BT_UNKNOWN
&& strcmp((*expr)->symtree->name, "null") != 0))
return MATCH_YES;
goto syntax;
}
else if ((*expr)->expr_type == EXPR_CONSTANT)
{
/* F2008, 4.4.3.1: The length is a type parameter; its kind is
processor dependent and its value is greater than or equal to zero.
F2008, 4.4.3.2: If the character length parameter value evaluates
to a negative value, the length of character entities declared
is zero. */
if ((*expr)->ts.type == BT_INTEGER)
{
if (mpz_cmp_si ((*expr)->value.integer, 0) < 0)
mpz_set_si ((*expr)->value.integer, 0);
}
else
goto syntax;
}
else if ((*expr)->expr_type == EXPR_ARRAY)
goto syntax;
else if ((*expr)->expr_type == EXPR_VARIABLE)
{
bool t;
gfc_expr *e;
e = gfc_copy_expr (*expr);
/* This catches the invalid code "[character(m(2:3)) :: 'x', 'y']",
which causes an ICE if gfc_reduce_init_expr() is called. */
if (e->ref && e->ref->type == REF_ARRAY
&& e->ref->u.ar.type == AR_UNKNOWN
&& e->ref->u.ar.dimen_type[0] == DIMEN_RANGE)
goto syntax;
t = gfc_reduce_init_expr (e);
if (!t && e->ts.type == BT_UNKNOWN
&& e->symtree->n.sym->attr.untyped == 1
&& (flag_implicit_none
|| e->symtree->n.sym->ns->seen_implicit_none == 1
|| e->symtree->n.sym->ns->parent->seen_implicit_none == 1))
{
gfc_free_expr (e);
goto syntax;
}
if ((e->ref && e->ref->type == REF_ARRAY
&& e->ref->u.ar.type != AR_ELEMENT)
|| (!e->ref && e->expr_type == EXPR_ARRAY))
{
gfc_free_expr (e);
goto syntax;
}
gfc_free_expr (e);
}
if (gfc_seen_div0)
m = MATCH_ERROR;
return m;
syntax:
gfc_error ("Scalar INTEGER expression expected at %L", &(*expr)->where);
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"))
return MATCH_ERROR;
*expr = gfc_get_int_expr (gfc_charlen_int_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);
sym->refs++;
st->n.sym = sym;
}
}
else
rc = gfc_get_symbol (name, gfc_current_ns->parent, result);
if (rc)
return rc;
sym = *result;
if (sym->attr.proc == PROC_ST_FUNCTION)
return rc;
if (sym->attr.module_procedure && sym->attr.if_source == IFSRC_IFBODY)
{
/* Create a partially populated interface symbol to carry the
characteristics of the procedure and the result. */
sym->tlink = gfc_new_symbol (name, sym->ns);
gfc_add_type (sym->tlink, &(sym->ts), &gfc_current_locus);
gfc_copy_attr (&sym->tlink->attr, &sym->attr, NULL);
if (sym->attr.dimension)
sym->tlink->as = gfc_copy_array_spec (sym->as);
/* Ideally, at this point, a copy would be made of the formal
arguments and their namespace. However, this does not appear
to be necessary, albeit at the expense of not being able to
use gfc_compare_interfaces directly. */
if (sym->result && sym->result != sym)
{
sym->tlink->result = sym->result;
sym->result = NULL;
}
else if (sym->result)
{
sym->tlink->result = sym->tlink;
}
}
else 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.entry)
&& sym->attr.if_source != IFSRC_UNKNOWN)
{
gfc_error_now ("Procedure %qs at %C is already defined at %L",
name, &sym->declared_at);
return true;
}
if (sym->attr.flavor != 0
&& sym->attr.entry && sym->attr.if_source != IFSRC_UNKNOWN)
{
gfc_error_now ("Procedure %qs at %C is already defined at %L",
name, &sym->declared_at);
return true;
}
if (sym->attr.external && sym->attr.procedure
&& gfc_current_state () == COMP_CONTAINS)
{
gfc_error_now ("Contained procedure %qs at %C clashes with "
"procedure defined at %L",
name, &sym->declared_at);
return true;
}
/* 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 %qs at %C is already defined"
" as a generic interface at %L",
name, &sym->declared_at);
return true;
}
/* Trap declarations of attributes in encompassing scope. The
signature for this is that ts.kind is nonzero for no-CLASS
entity. For a CLASS entity, ts.kind is zero. */
if ((sym->ts.kind != 0 || sym->ts.type == BT_CLASS)
&& !sym->attr.implicit_type
&& sym->attr.proc == 0
&& gfc_current_ns->parent != NULL
&& sym->attr.access == 0
&& !module_fcn_entry)
{
gfc_error_now ("Procedure %qs at %C has an explicit interface "
"from a previous declaration", name);
return true;
}
}
/* C1246 (R1225) MODULE shall appear only in the function-stmt or
subroutine-stmt of a module subprogram or of a nonabstract interface
body that is declared in the scoping unit of a module or submodule. */
if (sym->attr.external
&& (sym->attr.subroutine || sym->attr.function)
&& sym->attr.if_source == IFSRC_IFBODY
&& !current_attr.module_procedure
&& sym->attr.proc == PROC_MODULE
&& gfc_state_stack->state == COMP_CONTAINS)
{
gfc_error_now ("Procedure %qs defined in interface body at %L "
"clashes with internal procedure defined at %C",
name, &sym->declared_at);
return true;
}
if (sym && !sym->gfc_new
&& sym->attr.flavor != FL_UNKNOWN
&& sym->attr.referenced == 0 && sym->attr.subroutine == 1
&& gfc_state_stack->state == COMP_CONTAINS
&& gfc_state_stack->previous->state == COMP_SUBROUTINE)
{
gfc_error_now ("Procedure %qs at %C is already defined at %L",
name, &sym->declared_at);
return true;
}
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))
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. */
bool
gfc_verify_c_interop_param (gfc_symbol *sym)
{
int is_c_interop = 0;
bool retval = true;
/* We check implicitly typed variables in symbol.c:gfc_set_default_type().
Don't repeat the checks here. */
if (sym->attr.implicit_type)
return true;
/* 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 %qs at %L must have the BIND(C) "
"attribute to be C interoperable", sym->name,
&(sym->declared_at));
return false;
}
else
{
if (sym->attr.is_c_interop == 1)
/* We've already checked this procedure; don't check it again. */
return true;
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)) ? 1 : 0);
if (is_c_interop != 1)
{
/* Make personalized messages to give better feedback. */
if (sym->ts.type == BT_DERIVED)
gfc_error ("Variable %qs at %L is a dummy argument to the "
"BIND(C) procedure %qs but is not C interoperable "
"because derived type %qs 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 %qs at %L is a dummy argument to the "
"BIND(C) procedure %qs but is not C interoperable "
"because it is polymorphic",
sym->name, &(sym->declared_at),
sym->ns->proc_name->name);
else if (warn_c_binding_type)
gfc_warning (OPT_Wc_binding_type,
"Variable %qs at %L is a dummy argument of the "
"BIND(C) procedure %qs but may not be C "
"interoperable",
sym->name, &(sym->declared_at),
sym->ns->proc_name->name);
}
/* Per F2018, 18.3.6 (5), pointer + contiguous is not permitted. */
if (sym->attr.pointer && sym->attr.contiguous)
gfc_error ("Dummy argument %qs at %L may not be a pointer with "
"CONTIGUOUS attribute as procedure %qs is BIND(C)",
sym->name, &sym->declared_at, sym->ns->proc_name->name);
/* Per F2018, C1557, pointer/allocatable dummies to a bind(c)
procedure that are default-initialized are not permitted. */
if ((sym->attr.pointer || sym->attr.allocatable)
&& sym->ts.type == BT_DERIVED
&& gfc_has_default_initializer (sym->ts.u.derived))
{
gfc_error ("Default-initialized %s dummy argument %qs "
"at %L is not permitted in BIND(C) procedure %qs",
(sym->attr.pointer ? "pointer" : "allocatable"),
sym->name, &sym->declared_at,
sym->ns->proc_name->name);
retval = false;
}
/* Character strings are only C interoperable if they have a
length of 1. However, as an argument they are also iteroperable
when passed as descriptor (which requires len=: or len=*). */
if (sym->ts.type == BT_CHARACTER)
{
gfc_charlen *cl = sym->ts.u.cl;
if (sym->attr.allocatable || sym->attr.pointer)
{
/* F2018, 18.3.6 (6). */
if (!sym->ts.deferred)
{
if (sym->attr.allocatable)
gfc_error ("Allocatable character dummy argument %qs "
"at %L must have deferred length as "
"procedure %qs is BIND(C)", sym->name,
&sym->declared_at, sym->ns->proc_name->name);
else
gfc_error ("Pointer character dummy argument %qs at %L "
"must have deferred length as procedure %qs "
"is BIND(C)", sym->name, &sym->declared_at,
sym->ns->proc_name->name);
retval = false;
}
else if (!gfc_notify_std (GFC_STD_F2018,
"Deferred-length character dummy "
"argument %qs at %L of procedure "
"%qs with BIND(C) attribute",
sym->name, &sym->declared_at,
sym->ns->proc_name->name))
retval = false;
}
else if (sym->attr.value
&& (!cl || !cl->length
|| cl->length->expr_type != EXPR_CONSTANT
|| mpz_cmp_si (cl->length->value.integer, 1) != 0))
{
gfc_error ("Character dummy argument %qs at %L must be "
"of length 1 as it has the VALUE attribute",
sym->name, &sym->declared_at);
retval = false;
}
else if (!cl || !cl->length)
{
/* Assumed length; F2018, 18.3.6 (5)(2).
Uses the CFI array descriptor - also for scalars and
explicit-size/assumed-size arrays. */
if (!gfc_notify_std (GFC_STD_F2018,
"Assumed-length character dummy argument "
"%qs at %L of procedure %qs with BIND(C) "
"attribute", sym->name, &sym->declared_at,
sym->ns->proc_name->name))
retval = false;
}
else if (cl->length->expr_type != EXPR_CONSTANT
|| mpz_cmp_si (cl->length->value.integer, 1) != 0)
{
/* F2018, 18.3.6, (5), item 4. */
if (!sym->attr.dimension
|| sym->as->type == AS_ASSUMED_SIZE
|| sym->as->type == AS_EXPLICIT)
{
gfc_error ("Character dummy argument %qs at %L must be "
"of constant length of one or assumed length, "
"unless it has assumed shape or assumed rank, "
"as procedure %qs has the BIND(C) attribute",
sym->name, &sym->declared_at,
sym->ns->proc_name->name);
retval = false;
}
/* else: valid only since F2018 - and an assumed-shape/rank
array; however, gfc_notify_std is already called when
those array types are used. Thus, silently accept F200x. */
}
}
/* 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_notify_std (GFC_STD_F2018, "Variable %qs at %L with "
"ALLOCATABLE attribute in procedure %qs "
"with BIND(C)", sym->name,
&(sym->declared_at),
sym->ns->proc_name->name))
retval = false;
if (sym->attr.pointer == 1
&& !gfc_notify_std (GFC_STD_F2018, "Variable %qs at %L with "
"POINTER attribute in procedure %qs "
"with BIND(C)", sym->name,
&(sym->declared_at),
sym->ns->proc_name->name))
retval = false;
if (sym->attr.optional == 1 && sym->attr.value)
{
gfc_error ("Variable %qs at %L cannot have both the OPTIONAL "
"and the VALUE attribute because procedure %qs "
"is BIND(C)", sym->name, &(sym->declared_at),
sym->ns->proc_name->name);
retval = false;
}
else if (sym->attr.optional == 1
&& !gfc_notify_std (GFC_STD_F2018, "Variable %qs "
"at %L with OPTIONAL attribute in "
"procedure %qs which is BIND(C)",
sym->name, &(sym->declared_at),
sym->ns->proc_name->name))
retval = false;
/* 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_F2018, "Assumed-shape array %qs "
"at %L as dummy argument to the BIND(C) "
"procedure %qs at %L", sym->name,
&(sym->declared_at),
sym->ns->proc_name->name,
&(sym->ns->proc_name->declared_at)))
retval = false;
}
}
return retval;
}
/* Function called by variable_decl() that adds a name to the symbol table. */
static bool
build_sym (const char *name, gfc_charlen *cl, bool cl_deferred,
gfc_array_spec **as, locus *var_locus)
{
symbol_attribute attr;
gfc_symbol *sym;
int upper;
gfc_symtree *st;
/* Symbols in a submodule are host associated from the parent module or
submodules. Therefore, they can be overridden by declarations in the
submodule scope. Deal with this by attaching the existing symbol to
a new symtree and recycling the old symtree with a new symbol... */
st = gfc_find_symtree (gfc_current_ns->sym_root, name);
if (st != NULL && gfc_state_stack->state == COMP_SUBMODULE
&& st->n.sym != NULL
&& st->n.sym->attr.host_assoc && st->n.sym->attr.used_in_submodule)
{
gfc_symtree *s = gfc_get_unique_symtree (gfc_current_ns);
s->n.sym = st->n.sym;
sym = gfc_new_symbol (name, gfc_current_ns);
st->n.sym = sym;
sym->refs++;
gfc_set_sym_referenced (sym);
}
/* ...Otherwise generate a new symtree and new symbol. */
else if (gfc_get_symbol (name, NULL, &sym))
return false;
/* Check if the name has already been defined as a type. The
first letter of the symtree will be in upper case then. Of
course, this is only necessary if the upper case letter is
actually different. */
upper = TOUPPER(name[0]);
if (upper != name[0])
{
char u_name[GFC_MAX_SYMBOL_LEN + 1];
gfc_symtree *st;
gcc_assert (strlen(name) <= GFC_MAX_SYMBOL_LEN);
strcpy (u_name, name);
u_name[0] = upper;
st = gfc_find_symtree (gfc_current_ns->sym_root, u_name);
/* STRUCTURE types can alias symbol names */
if (st != 0 && st->n.sym->attr.flavor != FL_STRUCT)
{
gfc_error ("Symbol %qs at %C also declared as a type at %L", name,
&st->n.sym->declared_at);
return false;
}
}
/* 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, ¤t_ts))
&& !gfc_add_type (sym, ¤t_ts, var_locus))
return false;
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))
return false;
*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))
return false;
/* 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))
return false;
}
}
/* 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 %qs in common block %qs at %C "
"must be declared with a C interoperable "
"kind since common block %qs is BIND(C)",
sym->name, sym->common_block->name,
sym->common_block->name);
gfc_clear_error ();
}
}
sym->attr.implied_index = 0;
/* Use the parameter expressions for a parameterized derived type. */
if ((sym->ts.type == BT_DERIVED || sym->ts.type == BT_CLASS)
&& sym->ts.u.derived->attr.pdt_type && type_param_spec_list)
sym->param_list = gfc_copy_actual_arglist (type_param_spec_list);
if (sym->ts.type == BT_CLASS)
return gfc_build_class_symbol (&sym->ts, &sym->attr, &sym->as);
return true;
}
/* 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 (gfc_charlen_t len, gfc_expr *expr,
gfc_charlen_t check_len)
{
gfc_char_t *s;
gfc_charlen_t slen;
if (expr->ts.type != BT_CHARACTER)
return;
if (expr->expr_type != EXPR_CONSTANT)
{
gfc_error_now ("CHARACTER length must be a constant at %L", &expr->where);
return;
}
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 (warn_character_truncation && slen > len)
gfc_warning_now (OPT_Wcharacter_truncation,
"CHARACTER expression at %L is being truncated "
"(%ld/%ld)", &expr->where,
(long) slen, (long) 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 (%ld/%ld)",
&expr->where, (long) slen,
(long) check_len);
s[len] = '\0';
free (expr->value.character.string);
expr->value.character.string = s;
expr->value.character.length = len;
/* If explicit representation was given, clear it
as it is no longer needed after padding. */
if (expr->representation.length)
{
expr->representation.length = 0;
free (expr->representation.string);
expr->representation.string = NULL;
}
}
}
/* 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 bool
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 false;
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)
{
if (*initp != NULL)
{
gfc_error ("Initializer not allowed for PARAMETER %qs at %C",
sym->name);
return false;
}
else
return true;
}
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 false;
}
}
else
{
/* If a variable appears in a DATA block, it cannot have an
initializer. */
if (sym->attr.data)
{
gfc_error ("Variable %qs at %C with an initializer already "
"appears in a DATA statement", sym->name);
return false;
}
/* Check if the assignment can happen. This has to be put off
until later for derived type variables and procedure pointers. */
if (!gfc_bt_struct (sym->ts.type) && !gfc_bt_struct (init->ts.type)
&& sym->ts.type != BT_CLASS && init->ts.type != BT_CLASS
&& !sym->attr.proc_pointer
&& !gfc_check_assign_symbol (sym, NULL, init))
return false;
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))
return false;
if (sym->ts.u.cl->length == NULL)
{
gfc_charlen_t 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_charlen_int_kind,
NULL, clen);
}
else if (init->expr_type == EXPR_ARRAY)
{
if (init->ts.u.cl && init->ts.u.cl->length)
{
const gfc_expr *length = init->ts.u.cl->length;
if (length->expr_type != EXPR_CONSTANT)
{
gfc_error ("Cannot initialize parameter array "
"at %L "
"with variable length elements",
&sym->declared_at);
return false;
}
clen = mpz_get_si (length->value.integer);
}
else if (init->value.constructor)
{
gfc_constructor *c;
c = gfc_constructor_first (init->value.constructor);
clen = c->expr->value.character.length;
}
else
gcc_unreachable ();
sym->ts.u.cl->length
= gfc_get_int_expr (gfc_charlen_int_kind,
NULL, clen);
}
else if (init->ts.u.cl && init->ts.u.cl->length)
sym->ts.u.cl->length =
gfc_copy_expr (init->ts.u.cl->length);
}
}
/* Update initializer character length according symbol. */
else if (sym->ts.u.cl->length->expr_type == EXPR_CONSTANT)
{
if (!gfc_specification_expr (sym->ts.u.cl->length))
return false;
int k = gfc_validate_kind (BT_INTEGER, gfc_charlen_int_kind,
false);
/* resolve_charlen will complain later on if the length
is too large. Just skeep the initialization in that case. */
if (mpz_cmp (sym->ts.u.cl->length->value.integer,
gfc_integer_kinds[k].huge) <= 0)
{
HOST_WIDE_INT len
= gfc_mpz_get_hwi (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->attr.flavor == FL_PARAMETER && sym->attr.dimension && sym->as
&& sym->as->rank && init->rank && init->rank != sym->as->rank)
{
gfc_error ("Rank mismatch of array at %L and its initializer "
"(%d/%d)", &sym->declared_at, sym->as->rank, init->rank);
return false;
}
/* 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 ("Cannot initialize implied-shape array at %L"
" with scalar", &sym->declared_at);
return false;
}
/* The shape may be NULL for EXPR_ARRAY, set it. */
if (init->shape == NULL)
{
gcc_assert (init->expr_type == EXPR_ARRAY);
init->shape = gfc_get_shape (1);
if (!gfc_array_size (init, &init->shape[0]))
gfc_internal_error ("gfc_array_size failed");
}
for (dim = 0; dim < sym->as->rank; ++dim)
{
int k;
gfc_expr *e, *lower;
lower = sym->as->lower[dim];
/* If the lower bound is an array element from another
parameterized array, then it is marked with EXPR_VARIABLE and
is an initialization expression. Try to reduce it. */
if (lower->expr_type == EXPR_VARIABLE)
gfc_reduce_init_expr (lower);
if (lower->expr_type == EXPR_CONSTANT)
{
/* 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;
}
else
{
gfc_error ("Non-constant lower bound in implied-shape"
" declaration at %L", &lower->where);
return false;
}
}
sym->as->type = AS_EXPLICIT;
}
/* Ensure that explicit bounds are simplified. */
if (sym->attr.flavor == FL_PARAMETER && sym->attr.dimension
&& sym->as->type == AS_EXPLICIT)
{
for (int dim = 0; dim < sym->as->rank; ++dim)
{
gfc_expr *e;
e = sym->as->lower[dim];
if (e->expr_type != EXPR_CONSTANT)
gfc_reduce_init_expr (e);
e = sym->as->upper[dim];
if (e->expr_type != EXPR_CONSTANT)
gfc_reduce_init_expr (e);
}
}
/* 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 && !gfc_bt_struct (sym->ts.type))
{
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
&& gfc_is_constant_expr (init)
&& (init->expr_type == EXPR_CONSTANT
|| init->expr_type == EXPR_STRUCTURE)
&& spec_size (sym->as, &size)
&& mpz_cmp_si (size, 0) > 0)
{
array = gfc_get_array_expr (init->ts.type, init->ts.kind,
&init->where);
if (init->ts.type == BT_DERIVED)
array->ts.u.derived = init->ts.u.derived;
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 true;
}
/* Function called by variable_decl() that adds a name to a structure
being built. */
static bool
build_struct (const char *name, gfc_charlen *cl, gfc_expr **init,
gfc_array_spec **as)
{
gfc_state_data *s;
gfc_component *c;
/* 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)
{
if (current_attr.allocatable
&& !gfc_notify_std(GFC_STD_F2008, "Component at %C "
"must have the POINTER attribute"))
{
return false;
}
else if (current_attr.allocatable == 0)
{
gfc_error ("Component at %C must have the POINTER attribute");
return false;
}
}
/* F03:C437. */
if (current_ts.type == BT_CLASS
&& !(current_attr.pointer || current_attr.allocatable))
{
gfc_error ("Component %qs with CLASS at %C must be allocatable "
"or pointer", name);
return false;
}
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 false;
}
}
/* If we are in a nested union/map definition, gfc_add_component will not
properly find repeated components because:
(i) gfc_add_component does a flat search, where components of unions
and maps are implicity chained so nested components may conflict.
(ii) Unions and maps are not linked as components of their parent
structures until after they are parsed.
For (i) we use gfc_find_component which searches recursively, and for (ii)
we search each block directly from the parse stack until we find the top
level structure. */
s = gfc_state_stack;
if (s->state == COMP_UNION || s->state == COMP_MAP)
{
while (s->state == COMP_UNION || gfc_comp_struct (s->state))
{
c = gfc_find_component (s->sym, name, true, true, NULL);
if (c != NULL)
{
gfc_error_now ("Component %qs at %C already declared at %L",
name, &c->loc);
return false;
}
/* Break after we've searched the entire chain. */
if (s->state == COMP_DERIVED || s->state == COMP_STRUCTURE)
break;
s = s->previous;
}
}
if (!gfc_add_component (gfc_current_block(), name, &c))
return false;
c->ts = current_ts;
if (c->ts.type == BT_CHARACTER)
c->ts.u.cl = cl;
if (c->ts.type != BT_CLASS && c->ts.type != BT_DERIVED
&& (c->ts.kind == 0 || c->ts.type == BT_CHARACTER)
&& saved_kind_expr != NULL)
c->kind_expr = gfc_copy_expr (saved_kind_expr);
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;
gfc_apply_init (&c->ts, &c->attr, c->initializer);
/* 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");
return false;
}
}
else if (c->attr.allocatable)
{
if (c->as->type != AS_DEFERRED)
{
gfc_error ("Allocatable component of structure at %C must have a "
"deferred shape");
return false;
}
}
else
{
if (c->as->type != AS_EXPLICIT)
{
gfc_error ("Array component of structure at %C must have an "
"explicit shape");
return false;
}
}
scalar:
if (c->ts.type == BT_CLASS)
return gfc_build_class_symbol (&c->ts, &c->attr, &c->as);
if (c->attr.pdt_kind || c->attr.pdt_len)
{
gfc_symbol *sym;
gfc_find_symbol (c->name, gfc_current_block ()->f2k_derived,
0, &sym);
if (sym == NULL)
{
gfc_error ("Type parameter %qs at %C has no corresponding entry "
"in the type parameter name list at %L",
c->name, &gfc_current_block ()->declared_at);
return false;
}
sym->ts = c->ts;
sym->attr.pdt_kind = c->attr.pdt_kind;
sym->attr.pdt_len = c->attr.pdt_len;
if (c->initializer)
sym->value = gfc_copy_expr (c->initializer);
sym->attr.flavor = FL_VARIABLE;
}
if ((c->ts.type == BT_DERIVED || c->ts.type == BT_CLASS)
&& c->ts.u.derived && c->ts.u.derived->attr.pdt_template
&& decl_type_param_list)
c->param_list = gfc_copy_actual_arglist (decl_type_param_list);
return true;
}
/* 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
&& !(sym->attr.use_assoc && sym->attr.intrinsic)
&& (!gfc_add_procedure(&sym->attr, PROC_INTRINSIC, sym->name, NULL)
|| !gfc_add_function (&sym->attr, sym->name, NULL)))
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_comp_struct (gfc_state_stack->state))
{
gfc_error ("Initialization of pointer at %C is not allowed in "
"a PURE procedure");
return MATCH_ERROR;
}
gfc_unset_implicit_pure (gfc_current_ns->proc_name);
/* 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))
return MATCH_ERROR;
if (!gfc_notify_std (GFC_STD_F2008, "non-NULL pointer "
"initialization at %C"))
return MATCH_ERROR;
return MATCH_YES;
}
static bool
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 ("RESULT variable %qs at %L prohibits FUNCTION name %qs at %C "
"from appearing in a specification statement",
block->result->name, &block->result->declared_at, name);
return false;
}
}
return true;
}
/* 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];
static unsigned int fill_id = 0;
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;
bool t;
gfc_symbol *sym;
char c;
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. */
/* If we are parsing a structure with legacy support, we allow the symbol
name to be '%FILL' which gives it an anonymous (inaccessible) name. */
m = MATCH_NO;
gfc_gobble_whitespace ();
c = gfc_peek_ascii_char ();
if (c == '%')
{
gfc_next_ascii_char (); /* Burn % character. */
m = gfc_match ("fill");
if (m == MATCH_YES)
{
if (gfc_current_state () != COMP_STRUCTURE)
{
if (flag_dec_structure)
gfc_error ("%qs not allowed outside STRUCTURE at %C", "%FILL");
else
gfc_error ("%qs at %C is a DEC extension, enable with "
"%<-fdec-structure%>", "%FILL");
m = MATCH_ERROR;
goto cleanup;
}
if (attr_seen)
{
gfc_error ("%qs entity cannot have attributes at %C", "%FILL");
m = MATCH_ERROR;
goto cleanup;
}
/* %FILL components are given invalid fortran names. */
snprintf (name, GFC_MAX_SYMBOL_LEN + 1, "%%FILL%u", fill_id++);
}
else
{
gfc_error ("Invalid character %qc in variable name at %C", c);
return MATCH_ERROR;
}
}
else
{
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))
{
m = MATCH_ERROR;
goto cleanup;
}
if (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 cannot
be assumed-size.
An explicit-shape-array cannot appear under several conditions.
That check is done here as well. */
if (as)
{
if (as->type == AS_IMPLIED_SHAPE && current_attr.flavor != FL_PARAMETER)
{
m = MATCH_ERROR;
gfc_error ("Non-PARAMETER symbol %qs at %L cannot 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))
{
m = MATCH_ERROR;
goto cleanup;
}
gfc_seen_div0 = false;
/* F2018:C830 (R816) An explicit-shape-spec whose bounds are not
constant expressions shall appear only in a subprogram, derived
type definition, BLOCK construct, or interface body. */
if (as->type == AS_EXPLICIT
&& gfc_current_state () != COMP_BLOCK
&& gfc_current_state () != COMP_DERIVED
&& gfc_current_state () != COMP_FUNCTION
&& gfc_current_state () != COMP_INTERFACE
&& gfc_current_state () != COMP_SUBROUTINE)
{
gfc_expr *e;
bool not_constant = false;
for (int i = 0; i < as->rank; i++)
{
e = gfc_copy_expr (as->lower[i]);
if (!gfc_resolve_expr (e) && gfc_seen_div0)
{
m = MATCH_ERROR;
goto cleanup;
}
gfc_simplify_expr (e, 0);
if (e && (e->expr_type != EXPR_CONSTANT))
{
not_constant = true;
break;
}
gfc_free_expr (e);
e = gfc_copy_expr (as->upper[i]);
if (!gfc_resolve_expr (e) && gfc_seen_div0)
{
m = MATCH_ERROR;
goto cleanup;
}
gfc_simplify_expr (e, 0);
if (e && (e->expr_type != EXPR_CONSTANT))
{
not_constant = true;
break;
}
gfc_free_expr (e);
}
if (not_constant && e->ts.type != BT_INTEGER)
{
gfc_error ("Explicit array shape at %C must be constant of "
"INTEGER type and not %s type",
gfc_basic_typename (e->ts.type));
m = MATCH_ERROR;
goto cleanup;
}
if (not_constant)
{
gfc_error ("Explicit shaped array with nonconstant bounds at %C");
m = MATCH_ERROR;
goto cleanup;
}
}
if (as->type == AS_EXPLICIT)
{
for (int i = 0; i < as->rank; i++)
{
gfc_expr *e, *n;
e = as->lower[i];
if (e->expr_type != EXPR_CONSTANT)
{
n = gfc_copy_expr (e);
if (!gfc_simplify_expr (n, 1) && gfc_seen_div0)
{
m = MATCH_ERROR;
goto cleanup;
}
if (n->expr_type == EXPR_CONSTANT)
gfc_replace_expr (e, n);
else
gfc_free_expr (n);
}
e = as->upper[i];
if (e->expr_type != EXPR_CONSTANT)
{
n = gfc_copy_expr (e);
if (!gfc_simplify_expr (n, 1) && gfc_seen_div0)
{
m = MATCH_ERROR;
goto cleanup;
}
if (n->expr_type == EXPR_CONSTANT)
gfc_replace_expr (e, n);
else
gfc_free_expr (n);
}
}
}
}
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;
}
}
/* The dummy arguments and result of the abreviated form of MODULE
PROCEDUREs, used in SUBMODULES should not be redefined. */
if (gfc_current_ns->proc_name
&& gfc_current_ns->proc_name->abr_modproc_decl)
{
gfc_find_symbol (name, gfc_current_ns, 1, &sym);
if (sym != NULL && (sym->attr.dummy || sym->attr.result))
{
m = MATCH_ERROR;
gfc_error ("%qs at %C is a redefinition of the declaration "
"in the corresponding interface for MODULE "
"PROCEDURE %qs", sym->name,
gfc_current_ns->proc_name->name);
goto cleanup;
}
}
/* %FILL components may not have initializers. */
if (startswith (name, "%FILL") && gfc_match_eos () != MATCH_YES)
{
gfc_error ("%qs entity cannot have an initializer at %C", "%FILL");
m = MATCH_ERROR;
goto cleanup;
}
/* If this symbol has already shown up in a Cray Pointer declaration,
and this is not a component declaration,
then we want to set the type & bail out. */
if (flag_cray_pointer && !gfc_comp_struct (gfc_current_state ()))
{
gfc_find_symbol (name, gfc_current_ns, 0, &sym);
if (sym != NULL && sym->attr.cray_pointee)
{
m = MATCH_YES;
if (!gfc_add_type (sym, ¤t_ts, &gfc_current_locus))
{
m = MATCH_ERROR;
goto cleanup;
}
/* 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))
gfc_internal_error ("Cannot 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_comp_struct (gfc_current_state ())
&& !build_sym (name, cl, cl_deferred, &as, &var_locus))
{
m = MATCH_ERROR;
goto cleanup;
}
if (!check_function_name (name))
{
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"))
return MATCH_ERROR;
/* Allow old style initializations for components of STRUCTUREs and MAPs
but not components of derived types. */
else if (gfc_current_state () == COMP_DERIVED)
{
gfc_error ("Invalid old style initialization for derived type "
"component at %C");
m = MATCH_ERROR;
goto cleanup;
}
/* For structure components, read the initializer as a special
expression and let the rest of this function apply the initializer
as usual. */
else if (gfc_comp_struct (gfc_current_state ()))
{
m = match_clist_expr (&initializer, ¤t_ts, as);
if (m == MATCH_NO)
gfc_error ("Syntax error in old style initialization of %s at %C",
name);
if (m != MATCH_YES)
goto cleanup;
}
/* Otherwise we treat the old style initialization just like a
DATA declaration for the current variable. */
else
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;
/* The target of a pointer initialization must have the SAVE
attribute. A variable in PROGRAM, MODULE, or SUBMODULE scope
is implicit SAVEd. Explicitly, set the SAVE_IMPLICIT value. */
if (initializer->expr_type == EXPR_VARIABLE
&& initializer->symtree->n.sym->attr.save == SAVE_NONE
&& (gfc_current_state () == COMP_PROGRAM
|| gfc_current_state () == COMP_MODULE
|| gfc_current_state () == COMP_SUBMODULE))
initializer->symtree->n.sym->attr.save = SAVE_IMPLICIT;
}
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_comp_struct (gfc_state_stack->state))
{
gfc_error ("Initialization of variable at %C is not allowed in "
"a PURE procedure");
m = MATCH_ERROR;
}
if (current_attr.flavor != FL_PARAMETER
&& !gfc_comp_struct (gfc_state_stack->state))
gfc_unset_implicit_pure (gfc_current_ns->proc_name);
if (m != MATCH_YES)
goto cleanup;
}
}
if (initializer != NULL && current_attr.allocatable
&& gfc_comp_struct (gfc_current_state ()))
{
gfc_error ("Initialization of allocatable component at %C is not "
"allowed");
m = MATCH_ERROR;
goto cleanup;
}
if (gfc_current_state () == COMP_DERIVED
&& initializer && initializer->ts.type == BT_HOLLERITH)
{
gfc_error ("Initialization of structure component with a HOLLERITH "
"constant at %L is not allowed", &initializer->where);
m = MATCH_ERROR;
goto cleanup;
}
if (gfc_current_state () == COMP_DERIVED
&& gfc_current_block ()->attr.pdt_template)
{
gfc_symbol *param;
gfc_find_symbol (name, gfc_current_block ()->f2k_derived,
0, ¶m);
if (!param && (current_attr.pdt_kind || current_attr.pdt_len))
{
gfc_error ("The component with KIND or LEN attribute at %C does not "
"not appear in the type parameter list at %L",
&gfc_current_block ()->declared_at);
m = MATCH_ERROR;
goto cleanup;
}
else if (param && !(current_attr.pdt_kind || current_attr.pdt_len))
{
gfc_error ("The component at %C that appears in the type parameter "
"list at %L has neither the KIND nor LEN attribute",
&gfc_current_block ()->declared_at);
m = MATCH_ERROR;
goto cleanup;
}
else if (as && (current_attr.pdt_kind || current_attr.pdt_len))
{
gfc_error ("The component at %C which is a type parameter must be "
"a scalar");
m = MATCH_ERROR;
goto cleanup;
}
else if (param && initializer)
{
if (initializer->ts.type == BT_BOZ)
{
gfc_error ("BOZ literal constant at %L cannot appear as an "
"initializer", &initializer->where);
m = MATCH_ERROR;
goto cleanup;
}
param->value = gfc_copy_expr (initializer);
}
}
/* Before adding a possible initilizer, do a simple check for compatibility
of lhs and rhs types. Assigning a REAL value to a derived type is not a
good thing. */
if (current_ts.type == BT_DERIVED && initializer
&& (gfc_numeric_ts (&initializer->ts)
|| initializer->ts.type == BT_LOGICAL
|| initializer->ts.type == BT_CHARACTER))
{
gfc_error ("Incompatible initialization between a derived type "
"entity and an entity with %qs type at %C",
gfc_typename (initializer));
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_comp_struct (gfc_current_state ()))
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 (¤t_ts);
t = build_struct (name, cl, &initializer, &as);
/* If we match a nested structure definition we expect to see the
* body even if the variable declarations blow up, so we need to keep
* the structure declaration around. */
if (gfc_new_block && gfc_new_block->attr.flavor == FL_STRUCT)
gfc_commit_symbol (gfc_new_block);
}
m = (t) ? MATCH_YES : MATCH_ERROR;
cleanup:
/* Free stuff up and return. */
gfc_seen_div0 = false;
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. */
static 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 && flag_integer4_kind == 8)
ts->kind = 8;
if (ts->type == BT_REAL || ts->type == BT_COMPLEX)
{
if (ts->kind == 4)
{
if (flag_real4_kind == 8)
ts->kind = 8;
if (flag_real4_kind == 10)
ts->kind = 10;
if (flag_real4_kind == 16)
ts->kind = 16;
}
else if (ts->kind == 8)
{
if (flag_real8_kind == 4)
ts->kind = 4;
if (flag_real8_kind == 10)
ts->kind = 10;
if (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))
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;
m = MATCH_NO;
n = MATCH_YES;
e = NULL;
saved_kind_expr = 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 (gfc_derived_parameter_expr (e))
{
ts->kind = 0;
saved_kind_expr = gfc_copy_expr (e);
goto close_brackets;
}
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;
}
if (gfc_extract_int (e, &ts->kind, 1))
{
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;
if (e->symtree)
ts->interop_kind = e->symtree->n.sym;
}
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 (0, "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));
close_brackets:
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 && flag_integer4_kind == 8)
ts->kind = 8;
if (ts->type == BT_REAL || ts->type == BT_COMPLEX)
{
if (ts->kind == 4)
{
if (flag_real4_kind == 8)
ts->kind = 8;
if (flag_real4_kind == 10)
ts->kind = 10;
if (flag_real4_kind == 16)
ts->kind = 16;
}
else if (ts->kind == 8)
{
if (flag_real8_kind == 4)
ts->kind = 4;
if (flag_real8_kind == 10)
ts->kind = 10;
if (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;
bool fail;
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;
}
if (gfc_derived_parameter_expr (e))
{
saved_kind_expr = e;
*kind = 0;
return MATCH_YES;
}
fail = gfc_extract_int (e, kind, 1);
*is_iso_c = e->ts.is_iso_c;
if (fail)
{
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 = [ , LEN = ] ). */
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 = " or "LEN = , KIND = ". */
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 ( ) or ( , [ KIND = ] ). */
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_charlen_int_kind, NULL, 1);
else
{
/* If gfortran ends up here, then len may be reducible to a constant.
Try to do that here. If it does not reduce, simply assign len to
charlen. A complication occurs with user-defined generic functions,
which are not resolved. Use a private namespace to deal with
generic functions. */
if (len && len->expr_type != EXPR_CONSTANT)
{
gfc_namespace *old_ns;
gfc_expr *e;
old_ns = gfc_current_ns;
gfc_current_ns = gfc_get_namespace (NULL, 0);
e = gfc_copy_expr (len);
gfc_reduce_init_expr (e);
if (e->expr_type == EXPR_CONSTANT)
{
gfc_replace_expr (len, e);
if (mpz_cmp_si (len->value.integer, 0) < 0)
mpz_set_ui (len->value.integer, 0);
}
else
gfc_free_expr (e);
gfc_free_namespace (gfc_current_ns);
gfc_current_ns = old_ns;
}
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 RECORD declaration. */
static match
match_record_decl (char *name)
{
locus old_loc;
old_loc = gfc_current_locus;
match m;
m = gfc_match (" record /");
if (m == MATCH_YES)
{
if (!flag_dec_structure)
{
gfc_current_locus = old_loc;
gfc_error ("RECORD at %C is an extension, enable it with "
"%<-fdec-structure%>");
return MATCH_ERROR;
}
m = gfc_match (" %n/", name);
if (m == MATCH_YES)
return MATCH_YES;
}
gfc_current_locus = old_loc;
if (flag_dec_structure
&& (gfc_match (" record% ") == MATCH_YES
|| gfc_match (" record%t") == MATCH_YES))
gfc_error ("Structure name expected after RECORD at %C");
if (m == MATCH_NO)
return MATCH_NO;
return MATCH_ERROR;
}
/* This function uses the gfc_actual_arglist 'type_param_spec_list' as a source
of expressions to substitute into the possibly parameterized expression
'e'. Using a list is inefficient but should not be too bad since the
number of type parameters is not likely to be large. */
static bool
insert_parameter_exprs (gfc_expr* e, gfc_symbol* sym ATTRIBUTE_UNUSED,
int* f)
{
gfc_actual_arglist *param;
gfc_expr *copy;
if (e->expr_type != EXPR_VARIABLE)
return false;
gcc_assert (e->symtree);
if (e->symtree->n.sym->attr.pdt_kind
|| (*f != 0 && e->symtree->n.sym->attr.pdt_len))
{
for (param = type_param_spec_list; param; param = param->next)
if (strcmp (e->symtree->n.sym->name, param->name) == 0)
break;
if (param)
{
copy = gfc_copy_expr (param->expr);
*e = *copy;
free (copy);
}
}
return false;
}
static bool
gfc_insert_kind_parameter_exprs (gfc_expr *e)
{
return gfc_traverse_expr (e, NULL, &insert_parameter_exprs, 0);
}
bool
gfc_insert_parameter_exprs (gfc_expr *e, gfc_actual_arglist *param_list)
{
gfc_actual_arglist *old_param_spec_list = type_param_spec_list;
type_param_spec_list = param_list;
bool res = gfc_traverse_expr (e, NULL, &insert_parameter_exprs, 1);
type_param_spec_list = old_param_spec_list;
return res;
}
/* Determines the instance of a parameterized derived type to be used by
matching determining the values of the kind parameters and using them
in the name of the instance. If the instance exists, it is used, otherwise
a new derived type is created. */
match
gfc_get_pdt_instance (gfc_actual_arglist *param_list, gfc_symbol **sym,
gfc_actual_arglist **ext_param_list)
{
/* The PDT template symbol. */
gfc_symbol *pdt = *sym;
/* The symbol for the parameter in the template f2k_namespace. */
gfc_symbol *param;
/* The hoped for instance of the PDT. */
gfc_symbol *instance;
/* The list of parameters appearing in the PDT declaration. */
gfc_formal_arglist *type_param_name_list;
/* Used to store the parameter specification list during recursive calls. */
gfc_actual_arglist *old_param_spec_list;
/* Pointers to the parameter specification being used. */
gfc_actual_arglist *actual_param;
gfc_actual_arglist *tail = NULL;
/* Used to build up the name of the PDT instance. The prefix uses 4
characters and each KIND parameter 2 more. Allow 8 of the latter. */
char name[GFC_MAX_SYMBOL_LEN + 21];
bool name_seen = (param_list == NULL);
bool assumed_seen = false;
bool deferred_seen = false;
bool spec_error = false;
int kind_value, i;
gfc_expr *kind_expr;
gfc_component *c1, *c2;
match m;
type_param_spec_list = NULL;
type_param_name_list = pdt->formal;
actual_param = param_list;
sprintf (name, "Pdt%s", pdt->name);
/* Run through the parameter name list and pick up the actual
parameter values or use the default values in the PDT declaration. */
for (; type_param_name_list;
type_param_name_list = type_param_name_list->next)
{
if (actual_param && actual_param->spec_type != SPEC_EXPLICIT)
{
if (actual_param->spec_type == SPEC_ASSUMED)
spec_error = deferred_seen;
else
spec_error = assumed_seen;
if (spec_error)
{
gfc_error ("The type parameter spec list at %C cannot contain "
"both ASSUMED and DEFERRED parameters");
goto error_return;
}
}
if (actual_param && actual_param->name)
name_seen = true;
param = type_param_name_list->sym;
if (!param || !param->name)
continue;
c1 = gfc_find_component (pdt, param->name, false, true, NULL);
/* An error should already have been thrown in resolve.c
(resolve_fl_derived0). */
if (!pdt->attr.use_assoc && !c1)
goto error_return;
kind_expr = NULL;
if (!name_seen)
{
if (!actual_param && !(c1 && c1->initializer))
{
gfc_error ("The type parameter spec list at %C does not contain "
"enough parameter expressions");
goto error_return;
}
else if (!actual_param && c1 && c1->initializer)
kind_expr = gfc_copy_expr (c1->initializer);
else if (actual_param && actual_param->spec_type == SPEC_EXPLICIT)
kind_expr = gfc_copy_expr (actual_param->expr);
}
else
{
actual_param = param_list;
for (;actual_param; actual_param = actual_param->next)
if (actual_param->name
&& strcmp (actual_param->name, param->name) == 0)
break;
if (actual_param && actual_param->spec_type == SPEC_EXPLICIT)
kind_expr = gfc_copy_expr (actual_param->expr);
else
{
if (c1->initializer)
kind_expr = gfc_copy_expr (c1->initializer);
else if (!(actual_param && param->attr.pdt_len))
{
gfc_error ("The derived parameter %qs at %C does not "
"have a default value", param->name);
goto error_return;
}
}
}
/* Store the current parameter expressions in a temporary actual
arglist 'list' so that they can be substituted in the corresponding
expressions in the PDT instance. */
if (type_param_spec_list == NULL)
{
type_param_spec_list = gfc_get_actual_arglist ();
tail = type_param_spec_list;
}
else
{
tail->next = gfc_get_actual_arglist ();
tail = tail->next;
}
tail->name = param->name;
if (kind_expr)
{
/* Try simplification even for LEN expressions. */
bool ok;
gfc_resolve_expr (kind_expr);
ok = gfc_simplify_expr (kind_expr, 1);
/* Variable expressions seem to default to BT_PROCEDURE.
TODO find out why this is and fix it. */
if (kind_expr->ts.type != BT_INTEGER
&& kind_expr->ts.type != BT_PROCEDURE)
{
gfc_error ("The parameter expression at %C must be of "
"INTEGER type and not %s type",
gfc_basic_typename (kind_expr->ts.type));
goto error_return;
}
if (kind_expr->ts.type == BT_INTEGER && !ok)
{
gfc_error ("The parameter expression at %C does not "
"simplify to an INTEGER constant");
goto error_return;
}
tail->expr = gfc_copy_expr (kind_expr);
}
if (actual_param)
tail->spec_type = actual_param->spec_type;
if (!param->attr.pdt_kind)
{
if (!name_seen && actual_param)
actual_param = actual_param->next;
if (kind_expr)
{
gfc_free_expr (kind_expr);
kind_expr = NULL;
}
continue;
}
if (actual_param
&& (actual_param->spec_type == SPEC_ASSUMED
|| actual_param->spec_type == SPEC_DEFERRED))
{
gfc_error ("The KIND parameter %qs at %C cannot either be "
"ASSUMED or DEFERRED", param->name);
goto error_return;
}
if (!kind_expr || !gfc_is_constant_expr (kind_expr))
{
gfc_error ("The value for the KIND parameter %qs at %C does not "
"reduce to a constant expression", param->name);
goto error_return;
}
gfc_extract_int (kind_expr, &kind_value);
sprintf (name + strlen (name), "_%d", kind_value);
if (!name_seen && actual_param)
actual_param = actual_param->next;
gfc_free_expr (kind_expr);
}
if (!name_seen && actual_param)
{
gfc_error ("The type parameter spec list at %C contains too many "
"parameter expressions");
goto error_return;
}
/* Now we search for the PDT instance 'name'. If it doesn't exist, we
build it, using 'pdt' as a template. */
if (gfc_get_symbol (name, pdt->ns, &instance))
{
gfc_error ("Parameterized derived type at %C is ambiguous");
goto error_return;
}
m = MATCH_YES;
if (instance->attr.flavor == FL_DERIVED
&& instance->attr.pdt_type)
{
instance->refs++;
if (ext_param_list)
*ext_param_list = type_param_spec_list;
*sym = instance;
gfc_commit_symbols ();
return m;
}
/* Start building the new instance of the parameterized type. */
gfc_copy_attr (&instance->attr, &pdt->attr, &pdt->declared_at);
instance->attr.pdt_template = 0;
instance->attr.pdt_type = 1;
instance->declared_at = gfc_current_locus;
/* Add the components, replacing the parameters in all expressions
with the expressions for their values in 'type_param_spec_list'. */
c1 = pdt->components;
tail = type_param_spec_list;
for (; c1; c1 = c1->next)
{
gfc_add_component (instance, c1->name, &c2);
c2->ts = c1->ts;
c2->attr = c1->attr;
/* The order of declaration of the type_specs might not be the
same as that of the components. */
if (c1->attr.pdt_kind || c1->attr.pdt_len)
{
for (tail = type_param_spec_list; tail; tail = tail->next)
if (strcmp (c1->name, tail->name) == 0)
break;
}
/* Deal with type extension by recursively calling this function
to obtain the instance of the extended type. */
if (gfc_current_state () != COMP_DERIVED
&& c1 == pdt->components
&& (c1->ts.type == BT_DERIVED || c1->ts.type == BT_CLASS)
&& c1->ts.u.derived && c1->ts.u.derived->attr.pdt_template
&& gfc_get_derived_super_type (*sym) == c2->ts.u.derived)
{
gfc_formal_arglist *f;
old_param_spec_list = type_param_spec_list;
/* Obtain a spec list appropriate to the extended type..*/
actual_param = gfc_copy_actual_arglist (type_param_spec_list);
type_param_spec_list = actual_param;
for (f = c1->ts.u.derived->formal; f && f->next; f = f->next)
actual_param = actual_param->next;
if (actual_param)
{
gfc_free_actual_arglist (actual_param->next);
actual_param->next = NULL;
}
/* Now obtain the PDT instance for the extended type. */
c2->param_list = type_param_spec_list;
m = gfc_get_pdt_instance (type_param_spec_list, &c2->ts.u.derived,
NULL);
type_param_spec_list = old_param_spec_list;
c2->ts.u.derived->refs++;
gfc_set_sym_referenced (c2->ts.u.derived);
/* Set extension level. */
if (c2->ts.u.derived->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 %qs at %L",
c2->ts.u.derived->name,
&c2->ts.u.derived->declared_at);
goto error_return;
}
instance->attr.extension = c2->ts.u.derived->attr.extension + 1;
continue;
}
/* Set the component kind using the parameterized expression. */
if ((c1->ts.kind == 0 || c1->ts.type == BT_CHARACTER)
&& c1->kind_expr != NULL)
{
gfc_expr *e = gfc_copy_expr (c1->kind_expr);
gfc_insert_kind_parameter_exprs (e);
gfc_simplify_expr (e, 1);
gfc_extract_int (e, &c2->ts.kind);
gfc_free_expr (e);
if (gfc_validate_kind (c2->ts.type, c2->ts.kind, true) < 0)
{
gfc_error ("Kind %d not supported for type %s at %C",
c2->ts.kind, gfc_basic_typename (c2->ts.type));
goto error_return;
}
}
/* Similarly, set the string length if parameterized. */
if (c1->ts.type == BT_CHARACTER
&& c1->ts.u.cl->length
&& gfc_derived_parameter_expr (c1->ts.u.cl->length))
{
gfc_expr *e;
e = gfc_copy_expr (c1->ts.u.cl->length);
gfc_insert_kind_parameter_exprs (e);
gfc_simplify_expr (e, 1);
c2->ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL);
c2->ts.u.cl->length = e;
c2->attr.pdt_string = 1;
}
/* Set up either the KIND/LEN initializer, if constant,
or the parameterized expression. Use the template
initializer if one is not already set in this instance. */
if (c2->attr.pdt_kind || c2->attr.pdt_len)
{
if (tail && tail->expr && gfc_is_constant_expr (tail->expr))
c2->initializer = gfc_copy_expr (tail->expr);
else if (tail && tail->expr)
{
c2->param_list = gfc_get_actual_arglist ();
c2->param_list->name = tail->name;
c2->param_list->expr = gfc_copy_expr (tail->expr);
c2->param_list->next = NULL;
}
if (!c2->initializer && c1->initializer)
c2->initializer = gfc_copy_expr (c1->initializer);
}
/* Copy the array spec. */
c2->as = gfc_copy_array_spec (c1->as);
if (c1->ts.type == BT_CLASS)
CLASS_DATA (c2)->as = gfc_copy_array_spec (CLASS_DATA (c1)->as);
/* Determine if an array spec is parameterized. If so, substitute
in the parameter expressions for the bounds and set the pdt_array
attribute. Notice that this attribute must be unconditionally set
if this is an array of parameterized character length. */
if (c1->as && c1->as->type == AS_EXPLICIT)
{
bool pdt_array = false;
/* Are the bounds of the array parameterized? */
for (i = 0; i < c1->as->rank; i++)
{
if (gfc_derived_parameter_expr (c1->as->lower[i]))
pdt_array = true;
if (gfc_derived_parameter_expr (c1->as->upper[i]))
pdt_array = true;
}
/* If they are, free the expressions for the bounds and
replace them with the template expressions with substitute
values. */
for (i = 0; pdt_array && i < c1->as->rank; i++)
{
gfc_expr *e;
e = gfc_copy_expr (c1->as->lower[i]);
gfc_insert_kind_parameter_exprs (e);
gfc_simplify_expr (e, 1);
gfc_free_expr (c2->as->lower[i]);
c2->as->lower[i] = e;
e = gfc_copy_expr (c1->as->upper[i]);
gfc_insert_kind_parameter_exprs (e);
gfc_simplify_expr (e, 1);
gfc_free_expr (c2->as->upper[i]);
c2->as->upper[i] = e;
}
c2->attr.pdt_array = pdt_array ? 1 : c2->attr.pdt_string;
if (c1->initializer)
{
c2->initializer = gfc_copy_expr (c1->initializer);
gfc_insert_kind_parameter_exprs (c2->initializer);
gfc_simplify_expr (c2->initializer, 1);
}
}
/* Recurse into this function for PDT components. */
if ((c1->ts.type == BT_DERIVED || c1->ts.type == BT_CLASS)
&& c1->ts.u.derived && c1->ts.u.derived->attr.pdt_template)
{
gfc_actual_arglist *params;
/* The component in the template has a list of specification
expressions derived from its declaration. */
params = gfc_copy_actual_arglist (c1->param_list);
actual_param = params;
/* Substitute the template parameters with the expressions
from the specification list. */
for (;actual_param; actual_param = actual_param->next)
gfc_insert_parameter_exprs (actual_param->expr,
type_param_spec_list);
/* Now obtain the PDT instance for the component. */
old_param_spec_list = type_param_spec_list;
m = gfc_get_pdt_instance (params, &c2->ts.u.derived, NULL);
type_param_spec_list = old_param_spec_list;
c2->param_list = params;
if (!(c2->attr.pointer || c2->attr.allocatable))
c2->initializer = gfc_default_initializer (&c2->ts);
if (c2->attr.allocatable)
instance->attr.alloc_comp = 1;
}
}
gfc_commit_symbol (instance);
if (ext_param_list)
*ext_param_list = type_param_spec_list;
*sym = instance;
return m;
error_return:
gfc_free_actual_arglist (type_param_spec_list);
return MATCH_ERROR;
}
/* Match a legacy nonstandard BYTE type-spec. */
static match
match_byte_typespec (gfc_typespec *ts)
{
if (gfc_match (" byte") == MATCH_YES)
{
if (!gfc_notify_std (GFC_STD_GNU, "BYTE type at %C"))
return MATCH_ERROR;
if (gfc_current_form == FORM_FREE)
{
char c = gfc_peek_ascii_char ();
if (!gfc_is_whitespace (c) && c != ',')
return MATCH_NO;
}
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;
}
return MATCH_NO;
}
/* 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)
{
/* Provide sufficient space to hold "pdtsymbol". */
char *name = XALLOCAVEC (char, GFC_MAX_SYMBOL_LEN + 1);
gfc_symbol *sym, *dt_sym;
match m;
char c;
bool seen_deferred_kind, matched_type;
const char *dt_name;
decl_type_param_list = NULL;
/* 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;
/* Match BYTE type-spec. */
m = match_byte_typespec (ts);
if (m != MATCH_NO)
return m;
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_comp_struct (gfc_current_state ()))
{
gfc_error ("Assumed type at %C is not allowed for components");
return MATCH_ERROR;
}
if (!gfc_notify_std (GFC_STD_F2018, "Assumed type at %C"))
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"))
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)
{
gfc_error ("Malformed type-spec at %C");
return 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"))
return MATCH_ERROR;
if (matched_type && gfc_match_char (')') != MATCH_YES)
{
gfc_error ("Malformed type-spec at %C");
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"))
return MATCH_ERROR;
if (matched_type
&& !gfc_notify_std (GFC_STD_F2008, "TYPE with "
"intrinsic-type-spec at %C"))
return MATCH_ERROR;
if (matched_type && gfc_match_char (')') != MATCH_YES)
{
gfc_error ("Malformed type-spec at %C");
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_actual_arglist (1, &decl_type_param_list, true);
if (m == MATCH_ERROR)
return m;
gfc_gobble_whitespace ();
if (gfc_peek_ascii_char () != ')')
{
gfc_error ("Malformed type-spec at %C");
return MATCH_ERROR;
}
m = gfc_match_char (')'); /* Burn closing ')'. */
}
if (m != MATCH_YES)
m = match_record_decl (name);
if (matched_type || m == MATCH_YES)
{
ts->type = BT_DERIVED;
/* We accept record/s/ or type(s) where s is a structure, but we
* don't need all the extra derived-type stuff for structures. */
if (gfc_find_symbol (gfc_dt_upper_string (name), NULL, 1, &sym))
{
gfc_error ("Type name %qs at %C is ambiguous", name);
return MATCH_ERROR;
}
if (sym && sym->attr.flavor == FL_DERIVED
&& sym->attr.pdt_template
&& gfc_current_state () != COMP_DERIVED)
{
m = gfc_get_pdt_instance (decl_type_param_list, &sym, NULL);
if (m != MATCH_YES)
return m;
gcc_assert (!sym->attr.pdt_template && sym->attr.pdt_type);
ts->u.derived = sym;
const char* lower = gfc_dt_lower_string (sym->name);
size_t len = strlen (lower);
/* Reallocate with sufficient size. */
if (len > GFC_MAX_SYMBOL_LEN)
name = XALLOCAVEC (char, len + 1);
memcpy (name, lower, len);
name[len] = '\0';
}
if (sym && sym->attr.flavor == FL_STRUCT)
{
ts->u.derived = sym;
return MATCH_YES;
}
/* Actually a derived type. */
}
else
{
/* Match nested STRUCTURE declarations; only valid within another
structure declaration. */
if (flag_dec_structure
&& (gfc_current_state () == COMP_STRUCTURE
|| gfc_current_state () == COMP_MAP))
{
m = gfc_match (" structure");
if (m == MATCH_YES)
{
m = gfc_match_structure_decl ();
if (m == MATCH_YES)
{
/* gfc_new_block is updated by match_structure_decl. */
ts->type = BT_DERIVED;
ts->u.derived = gfc_new_block;
return MATCH_YES;
}
}
if (m == MATCH_ERROR)
return MATCH_ERROR;
}
/* 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))
return MATCH_ERROR;
}
else
{
st = gfc_get_tbp_symtree (&gfc_current_ns->sym_root, "STAR");
st->n.sym = upe;
upe->refs++;
}
ts->u.derived = upe;
return m;
}
m = gfc_match (" class (");
if (m == MATCH_YES)
m = gfc_match ("%n", name);
else
return m;
if (m != MATCH_YES)
return m;
ts->type = BT_CLASS;
if (!gfc_notify_std (GFC_STD_F2003, "CLASS statement at %C"))
return MATCH_ERROR;
m = gfc_match_actual_arglist (1, &decl_type_param_list, true);
if (m == MATCH_ERROR)
return m;
m = gfc_match_char (')');
if (m != MATCH_YES)
return m;
}
/* 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_dt_upper_string (name);
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 %qs at %C is ambiguous", name);
return MATCH_ERROR;
}
if (sym->generic && !dt_sym)
dt_sym = gfc_find_dt_in_generic (sym);
/* Host associated PDTs can get confused with their constructors
because they ar instantiated in the template's namespace. */
if (!dt_sym)
{
if (gfc_find_symbol (dt_name, NULL, 1, &dt_sym))
{
gfc_error ("Type name %qs at %C is ambiguous", name);
return MATCH_ERROR;
}
if (dt_sym && !dt_sym->attr.pdt_type)
dt_sym = NULL;
}
}
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 %qs 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_STRUCT
&& !(sym->attr.flavor == FL_PROCEDURE && sym->attr.generic))
|| sym->attr.subroutine)
{
gfc_error ("Type name %qs at %C conflicts with previously declared "
"entity at %L, which has the same name", name,
&sym->declared_at);
return MATCH_ERROR;
}
if (sym && sym->attr.flavor == FL_DERIVED
&& sym->attr.pdt_template
&& gfc_current_state () != COMP_DERIVED)
{
m = gfc_get_pdt_instance (decl_type_param_list, &sym, NULL);
if (m != MATCH_YES)
return m;
gcc_assert (!sym->attr.pdt_template && sym->attr.pdt_type);
ts->u.derived = sym;
strcpy (name, gfc_dt_lower_string (sym->name));
}
gfc_save_symbol_data (sym);
gfc_set_sym_referenced (sym);
if (!sym->attr.generic
&& !gfc_add_generic (&sym->attr, sym->name, NULL))
return MATCH_ERROR;
if (!sym->attr.function
&& !gfc_add_function (&sym->attr, sym->name, NULL))
return MATCH_ERROR;
if (dt_sym && dt_sym->attr.flavor == FL_DERIVED
&& dt_sym->attr.pdt_template
&& gfc_current_state () != COMP_DERIVED)
{
m = gfc_get_pdt_instance (decl_type_param_list, &dt_sym, NULL);
if (m != MATCH_YES)
return m;
gcc_assert (!dt_sym->attr.pdt_template && dt_sym->attr.pdt_type);
}
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 ("%s", 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;
}
else
gfc_save_symbol_data (dt_sym);
gfc_set_sym_referenced (dt_sym);
if (dt_sym->attr.flavor != FL_DERIVED && dt_sym->attr.flavor != FL_STRUCT
&& !gfc_add_flavor (&dt_sym->attr, FL_DERIVED, sym->name, NULL))
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"))
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;
}
gfc_error ("Malformed type-spec at %C");
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 (gfc_validate_kind (ts->type, ts->kind, true) == -1)
return MATCH_ERROR;
}
if (matched_type && gfc_match_char (')') != MATCH_YES)
{
gfc_error ("Malformed type-spec at %C");
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)
{
char c;
match m;
char name[GFC_MAX_SYMBOL_LEN + 1];
bool type = false;
bool external = false;
locus cur_loc = gfc_current_locus;
if (gfc_current_ns->seen_implicit_none
|| gfc_current_ns->has_implicit_none_export)
{
gfc_error ("Duplicate IMPLICIT NONE statement at %C");
return MATCH_ERROR;
}
gfc_gobble_whitespace ();
c = gfc_peek_ascii_char ();
if (c == '(')
{
(void) gfc_next_ascii_char ();
if (!gfc_notify_std (GFC_STD_F2018, "IMPLICIT NONE with spec list at %C"))
return MATCH_ERROR;
gfc_gobble_whitespace ();
if (gfc_peek_ascii_char () == ')')
{
(void) gfc_next_ascii_char ();
type = true;
}
else
for(;;)
{
m = gfc_match (" %n", name);
if (m != MATCH_YES)
return MATCH_ERROR;
if (strcmp (name, "type") == 0)
type = true;
else if (strcmp (name, "external") == 0)
external = true;
else
return MATCH_ERROR;
gfc_gobble_whitespace ();
c = gfc_next_ascii_char ();
if (c == ',')
continue;
if (c == ')')
break;
return MATCH_ERROR;
}
}
else
type = true;
if (gfc_match_eos () != MATCH_YES)
return MATCH_ERROR;
gfc_set_implicit_none (type, external, &cur_loc);
return MATCH_YES;
}
/* 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))
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;
if (gfc_current_ns->seen_implicit_none)
{
gfc_error ("IMPLICIT statement at %C following an IMPLICIT NONE (type) "
"statement");
return MATCH_ERROR;
}
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 (). */
gfc_gobble_whitespace ();
c = gfc_peek_ascii_char ();
if (c == ',' || c == '\n' || c == ';' || 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_charlen_int_kind,
NULL, 1);
}
/* Record the Successful match. */
if (!gfc_merge_new_implicit (&ts))
return MATCH_ERROR;
if (c == ',')
c = gfc_next_ascii_char ();
else if (gfc_match_eos () == MATCH_ERROR)
goto error;
continue;
}
gfc_current_locus = cur_loc;
}
/* Discard the (incorrectly) matched range. */
gfc_clear_new_implicit ();
/* Last chance -- check (). */
if (ts.type == BT_CHARACTER)
m = gfc_match_char_spec (&ts);
else if (gfc_numeric_ts(&ts) || ts.type == BT_LOGICAL)
{
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 != ',' && gfc_match_eos () != MATCH_YES)
goto syntax;
if (!gfc_merge_new_implicit (&ts))
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_current_ns->proc_name->attr.module_procedure)
{
gfc_error ("F2008: C1210 IMPORT statement at %C is not permitted "
"in a module procedure interface body");
return MATCH_ERROR;
}
if (!gfc_notify_std (GFC_STD_F2003, "IMPORT statement at %C"))
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 %qs 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 %qs at %C is ambiguous", name);
return MATCH_ERROR;
}
if (sym == NULL)
{
gfc_error ("Cannot IMPORT %qs 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 (0, "%qs 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_dt_upper_string (name));
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_IN = INTENT_IN, DECL_OUT = INTENT_OUT, DECL_INOUT = INTENT_INOUT,
DECL_DIMENSION, DECL_EXTERNAL,
DECL_INTRINSIC, DECL_OPTIONAL,
DECL_PARAMETER, DECL_POINTER, DECL_PROTECTED, DECL_PRIVATE,
DECL_STATIC, DECL_AUTOMATIC,
DECL_PUBLIC, DECL_SAVE, DECL_TARGET, DECL_VALUE, DECL_VOLATILE,
DECL_IS_BIND_C, DECL_CODIMENSION, DECL_ASYNCHRONOUS, DECL_CONTIGUOUS,
DECL_LEN, DECL_KIND, DECL_NONE, GFC_DECL_END /* Sentinel */
};
/* GFC_DECL_END is the sentinel, index starts at 0. */
#define NUM_DECL GFC_DECL_END
/* Make sure that values from sym_intent are safe to be used here. */
gcc_assert (INTENT_IN > 0);
locus start, seen_at[NUM_DECL];
int seen[NUM_DECL];
unsigned int d;
const char *attr;
match m;
bool t;
gfc_clear_attr (¤t_attr);
start = gfc_current_locus;
current_as = NULL;
colon_seen = 0;
attr_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;
case 'u':
if (match_string_p ("tomatic"))
{
/* Matched "automatic". */
d = DECL_AUTOMATIC;
}
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;
}
/* FALLTHRU */
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". */
d = match_intent_spec ();
if (d == INTENT_UNKNOWN)
{
m = MATCH_ERROR;
goto cleanup;
}
}
}
else if (ch == 'r')
{
if (match_string_p ("insic"))
{
/* Matched "intrinsic". */
d = DECL_INTRINSIC;
}
}
}
break;
case 'k':
if (match_string_p ("kind"))
d = DECL_KIND;
break;
case 'l':
if (match_string_p ("len"))
d = DECL_LEN;
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':
gfc_next_ascii_char ();
switch (gfc_next_ascii_char ())
{
case 'a':
if (match_string_p ("ve"))
{
/* Matched "save". */
d = DECL_SAVE;
}
break;
case 't':
if (match_string_p ("atic"))
{
/* Matched "static". */
d = DECL_STATIC;
}
break;
}
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))
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_KIND:
attr = "KIND";
break;
case DECL_LEN:
attr = "LEN";
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_STATIC:
attr = "STATIC";
break;
case DECL_AUTOMATIC:
attr = "AUTOMATIC";
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;
else
attr_seen = 1;
if ((d == DECL_STATIC || d == DECL_AUTOMATIC)
&& !flag_dec_static)
{
gfc_error ("%s at %L is a DEC extension, enable with "
"%<-fdec-static%>",
d == DECL_STATIC ? "STATIC" : "AUTOMATIC", &seen_at[d]);
m = MATCH_ERROR;
goto cleanup;
}
/* Allow SAVE with STATIC, but don't complain. */
if (d == DECL_STATIC && seen[DECL_SAVE])
continue;
if (gfc_comp_struct (gfc_current_state ())
&& d != DECL_DIMENSION && d != DECL_CODIMENSION
&& d != DECL_POINTER && d != DECL_PRIVATE
&& d != DECL_PUBLIC && d != DECL_CONTIGUOUS && d != DECL_NONE)
{
bool is_derived = gfc_current_state () == COMP_DERIVED;
if (d == DECL_ALLOCATABLE)
{
if (!gfc_notify_std (GFC_STD_F2003, is_derived
? G_("ALLOCATABLE attribute at %C in a "
"TYPE definition")
: G_("ALLOCATABLE attribute at %C in a "
"STRUCTURE definition")))
{
m = MATCH_ERROR;
goto cleanup;
}
}
else if (d == DECL_KIND)
{
if (!gfc_notify_std (GFC_STD_F2003, is_derived
? G_("KIND attribute at %C in a "
"TYPE definition")
: G_("KIND attribute at %C in a "
"STRUCTURE definition")))
{
m = MATCH_ERROR;
goto cleanup;
}
if (current_ts.type != BT_INTEGER)
{
gfc_error ("Component with KIND attribute at %C must be "
"INTEGER");
m = MATCH_ERROR;
goto cleanup;
}
}
else if (d == DECL_LEN)
{
if (!gfc_notify_std (GFC_STD_F2003, is_derived
? G_("LEN attribute at %C in a "
"TYPE definition")
: G_("LEN attribute at %C in a "
"STRUCTURE definition")))
{
m = MATCH_ERROR;
goto cleanup;
}
if (current_ts.type != BT_INTEGER)
{
gfc_error ("Component with LEN attribute at %C must be "
"INTEGER");
m = MATCH_ERROR;
goto cleanup;
}
}
else
{
gfc_error (is_derived ? G_("Attribute at %L is not allowed in a "
"TYPE definition")
: G_("Attribute at %L is not allowed in a "
"STRUCTURE 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]))
{
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;
}
}
if (gfc_current_state () != COMP_DERIVED
&& (d == DECL_KIND || d == DECL_LEN))
{
gfc_error ("Attribute at %L is not allowed outside a TYPE "
"definition", &seen_at[d]);
m = MATCH_ERROR;
goto cleanup;
}
switch (d)
{
case DECL_ALLOCATABLE:
t = gfc_add_allocatable (¤t_attr, &seen_at[d]);
break;
case DECL_ASYNCHRONOUS:
if (!gfc_notify_std (GFC_STD_F2003, "ASYNCHRONOUS attribute at %C"))
t = false;
else
t = gfc_add_asynchronous (¤t_attr, NULL, &seen_at[d]);
break;
case DECL_CODIMENSION:
t = gfc_add_codimension (¤t_attr, NULL, &seen_at[d]);
break;
case DECL_CONTIGUOUS:
if (!gfc_notify_std (GFC_STD_F2008, "CONTIGUOUS attribute at %C"))
t = false;
else
t = gfc_add_contiguous (¤t_attr, NULL, &seen_at[d]);
break;
case DECL_DIMENSION:
t = gfc_add_dimension (¤t_attr, NULL, &seen_at[d]);
break;
case DECL_EXTERNAL:
t = gfc_add_external (¤t_attr, &seen_at[d]);
break;
case DECL_IN:
t = gfc_add_intent (¤t_attr, INTENT_IN, &seen_at[d]);
break;
case DECL_OUT:
t = gfc_add_intent (¤t_attr, INTENT_OUT, &seen_at[d]);
break;
case DECL_INOUT:
t = gfc_add_intent (¤t_attr, INTENT_INOUT, &seen_at[d]);
break;
case DECL_INTRINSIC:
t = gfc_add_intrinsic (¤t_attr, &seen_at[d]);
break;
case DECL_OPTIONAL:
t = gfc_add_optional (¤t_attr, &seen_at[d]);
break;
case DECL_KIND:
t = gfc_add_kind (¤t_attr, &seen_at[d]);
break;
case DECL_LEN:
t = gfc_add_len (¤t_attr, &seen_at[d]);
break;
case DECL_PARAMETER:
t = gfc_add_flavor (¤t_attr, FL_PARAMETER, NULL, &seen_at[d]);
break;
case DECL_POINTER:
t = gfc_add_pointer (¤t_attr, &seen_at[d]);
break;
case DECL_PROTECTED:
if (gfc_current_state () != COMP_MODULE
|| (gfc_current_ns->proc_name
&& gfc_current_ns->proc_name->attr.flavor != FL_MODULE))
{
gfc_error ("PROTECTED at %C only allowed in specification "
"part of a module");
t = false;
break;
}
if (!gfc_notify_std (GFC_STD_F2003, "PROTECTED attribute at %C"))
t = false;
else
t = gfc_add_protected (¤t_attr, NULL, &seen_at[d]);
break;
case DECL_PRIVATE:
t = gfc_add_access (¤t_attr, ACCESS_PRIVATE, NULL,
&seen_at[d]);
break;
case DECL_PUBLIC:
t = gfc_add_access (¤t_attr, ACCESS_PUBLIC, NULL,
&seen_at[d]);
break;
case DECL_STATIC:
case DECL_SAVE:
t = gfc_add_save (¤t_attr, SAVE_EXPLICIT, NULL, &seen_at[d]);
break;
case DECL_AUTOMATIC:
t = gfc_add_automatic (¤t_attr, NULL, &seen_at[d]);
break;
case DECL_TARGET:
t = gfc_add_target (¤t_attr, &seen_at[d]);
break;
case DECL_IS_BIND_C:
t = gfc_add_is_bind_c(¤t_attr, NULL, &seen_at[d], 0);
break;
case DECL_VALUE:
if (!gfc_notify_std (GFC_STD_F2003, "VALUE attribute at %C"))
t = false;
else
t = gfc_add_value (¤t_attr, NULL, &seen_at[d]);
break;
case DECL_VOLATILE:
if (!gfc_notify_std (GFC_STD_F2003, "VOLATILE attribute at %C"))
t = false;
else
t = gfc_add_volatile (¤t_attr, NULL, &seen_at[d]);
break;
default:
gfc_internal_error ("match_attr_spec(): Bad attribute");
}
if (!t)
{
m = MATCH_ERROR;
goto cleanup;
}
}
/* Since Fortran 2008 module variables implicitly have the SAVE attribute. */
if ((gfc_current_state () == COMP_MODULE
|| gfc_current_state () == COMP_SUBMODULE)
&& !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;
attr_seen = 0;
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 bool
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 false;
}
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 true;
}
/* Set the status of the given common block as being BIND(C) or not,
depending on the given parameter, is_bind_c. */
static 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. */
bool
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)
? true : false;
else if (ts->type == BT_CLASS)
return false;
else if (ts->is_c_interop != 1 && ts->type != BT_ASSUMED)
return false;
return true;
}
/* 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. */
bool
verify_com_block_vars_c_interop (gfc_common_head *com_block)
{
gfc_symbol *curr_sym = NULL;
bool retval = true;
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. */
bool
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;
bool retval = true;
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 && warn_c_binding_type)
{
gfc_warning (OPT_Wc_binding_type,
"Implicitly declared BIND(C) function %qs 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)))
{
/* See if we're dealing with a sym in a common block or not. */
if (is_in_common == 1 && warn_c_binding_type)
{
gfc_warning (OPT_Wc_binding_type,
"Variable %qs in common block %qs at %L "
"may not be a C interoperable "
"kind though common block %qs 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 %qs at %L is not C "
"interoperable but it is BIND(C)",
tmp_sym->name, &(tmp_sym->declared_at));
else if (warn_c_binding_type)
gfc_warning (OPT_Wc_binding_type, "Variable %qs 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 %qs in common block %qs 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 = false;
}
/* Scalar variables that are bind(c) cannot have the pointer
or allocatable attributes. */
if (tmp_sym->attr.is_bind_c == 1)
{
if (tmp_sym->attr.pointer == 1)
{
gfc_error ("Variable %qs at %L cannot have both the "
"POINTER and BIND(C) attributes",
tmp_sym->name, &(tmp_sym->declared_at));
retval = false;
}
if (tmp_sym->attr.allocatable == 1)
{
gfc_error ("Variable %qs at %L cannot have both the "
"ALLOCATABLE and BIND(C) attributes",
tmp_sym->name, &(tmp_sym->declared_at));
retval = false;
}
}
/* 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 %qs at %L cannot "
"be an array", tmp_sym->name, &(tmp_sym->declared_at));
/* BIND(C) functions cannot 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 %qs of character "
"type at %L must have length 1", 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 (0, "Symbol %qs at %L is marked PRIVATE but has been "
"given the binding label %qs", 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. */
static bool
set_verify_bind_c_sym (gfc_symbol *tmp_sym, int num_idents)
{
bool retval = true;
/* 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))
return false;
return retval;
}
/* Set the fields marking the given common block as BIND(C), including
a binding label, and report any errors encountered. */
static bool
set_verify_bind_c_com_block (gfc_common_head *com_block, int num_idents)
{
bool retval = true;
/* destLabel, common name, typespec (which may have binding label). */
if (!set_binding_label (&com_block->binding_label, com_block->name,
num_idents))
return false;
/* 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. */
static bool
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 (gfc_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 false;
}
/* 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))
return false;
}
else
{
if (!set_verify_bind_c_com_block (com_block, num_idents))
return false;
}
/* 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 (gfc_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 false;
}
}
else
{
gfc_internal_error ("Missing symbol");
}
} while (found_id == MATCH_YES);
/* if we get here we were successful */
return true;
}
/* 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 = ¤t_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)
{
if (!gfc_notify_std (GFC_STD_F2003, "BIND(C) statement at %C"))
return MATCH_ERROR;
/* 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 ())
/* 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;
type_param_spec_list = NULL;
decl_type_param_list = NULL;
num_idents_on_line = 0;
m = gfc_match_decl_type_spec (¤t_ts, 0);
if (m != MATCH_YES)
return m;
if ((current_ts.type == BT_DERIVED || current_ts.type == BT_CLASS)
&& !gfc_comp_struct (gfc_current_state ()))
{
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_comp_struct (gfc_current_state ()))
goto ok;
if (current_attr.allocatable && 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, or be a structure definition
actively being parsed. */
if (sym != NULL && gfc_fl_struct (sym->attr.flavor)
&& (current_ts.u.derived->components != NULL
|| current_ts.u.derived->attr.zero_comp
|| current_ts.u.derived == gfc_new_block))
goto ok;
gfc_error ("Derived type at %C has not been previously defined "
"and so cannot appear in a derived type definition");
m = MATCH_ERROR;
goto cleanup;
}
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 ())
{
/* An anonymous structure declaration is unambiguous; if we matched one
according to gfc_match_structure_decl, we need to return MATCH_YES
here to avoid confusing the remaining matchers, even if there was an
error during variable_decl. We must flush any such errors. Note this
causes the parser to gracefully continue parsing the remaining input
as a structure body, which likely follows. */
if (current_ts.type == BT_DERIVED && current_ts.u.derived
&& gfc_fl_struct (current_ts.u.derived->attr.flavor))
{
gfc_error_now ("Syntax error in anonymous structure declaration"
" at %C");
/* Skip the bad variable_decl and line up for the start of the
structure body. */
gfc_error_recovery ();
m = MATCH_YES;
goto cleanup;
}
gfc_error ("Syntax error in data declaration at %C");
}
m = MATCH_ERROR;
gfc_free_data_all (gfc_current_ns);
cleanup:
if (saved_kind_expr)
gfc_free_expr (saved_kind_expr);
if (type_param_spec_list)
gfc_free_actual_arglist (type_param_spec_list);
if (decl_type_param_list)
gfc_free_actual_arglist (decl_type_param_list);
saved_kind_expr = NULL;
gfc_free_array_spec (current_as);
current_as = NULL;
return m;
}
static bool
in_module_or_interface(void)
{
if (gfc_current_state () == COMP_MODULE
|| gfc_current_state () == COMP_SUBMODULE
|| gfc_current_state () == COMP_INTERFACE)
return true;
if (gfc_state_stack->state == COMP_CONTAINS
|| gfc_state_stack->state == COMP_FUNCTION
|| gfc_state_stack->state == COMP_SUBROUTINE)
{
gfc_state_data *p;
for (p = gfc_state_stack->previous; p ; p = p->previous)
{
if (p->state == COMP_MODULE || p->state == COMP_SUBMODULE
|| p->state == COMP_INTERFACE)
return true;
}
}
return false;
}
/* 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 (¤t_attr);
seen_type = false;
seen_impure = false;
gcc_assert (!gfc_matching_prefix);
gfc_matching_prefix = true;
do
{
found_prefix = false;
/* MODULE is a prefix like PURE, ELEMENTAL, etc., having a
corresponding attribute seems natural and distinguishes these
procedures from procedure types of PROC_MODULE, which these are
as well. */
if (gfc_match ("module% ") == MATCH_YES)
{
if (!gfc_notify_std (GFC_STD_F2008, "MODULE prefix at %C"))
goto error;
if (!in_module_or_interface ())
{
gfc_error ("MODULE prefix at %C found outside of a module, "
"submodule, or interface");
goto error;
}
current_attr.module_procedure = 1;
found_prefix = true;
}
if (!seen_type && ts != NULL)
{
match m;
m = gfc_match_decl_type_spec (ts, 0);
if (m == MATCH_ERROR)
goto error;
if (m == MATCH_YES && gfc_match_space () == MATCH_YES)
{
seen_type = true;
found_prefix = true;
}
}
if (gfc_match ("elemental% ") == MATCH_YES)
{
if (!gfc_add_elemental (¤t_attr, NULL))
goto error;
found_prefix = true;
}
if (gfc_match ("pure% ") == MATCH_YES)
{
if (!gfc_add_pure (¤t_attr, NULL))
goto error;
found_prefix = true;
}
if (gfc_match ("recursive% ") == MATCH_YES)
{
if (!gfc_add_recursive (¤t_attr, NULL))
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"))
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 (¤t_attr, NULL))
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 bool
copy_prefix (symbol_attribute *dest, locus *where)
{
if (dest->module_procedure)
{
if (current_attr.elemental)
dest->elemental = 1;
if (current_attr.pure)
dest->pure = 1;
if (current_attr.recursive)
dest->recursive = 1;
/* Module procedures are unusual in that the 'dest' is copied from
the interface declaration. However, this is an oportunity to
check that the submodule declaration is compliant with the
interface. */
if (dest->elemental && !current_attr.elemental)
{
gfc_error ("ELEMENTAL prefix in MODULE PROCEDURE interface is "
"missing at %L", where);
return false;
}
if (dest->pure && !current_attr.pure)
{
gfc_error ("PURE prefix in MODULE PROCEDURE interface is "
"missing at %L", where);
return false;
}
if (dest->recursive && !current_attr.recursive)
{
gfc_error ("RECURSIVE prefix in MODULE PROCEDURE interface is "
"missing at %L", where);
return false;
}
return true;
}
if (current_attr.elemental && !gfc_add_elemental (dest, where))
return false;
if (current_attr.pure && !gfc_add_pure (dest, where))
return false;
if (current_attr.recursive && !gfc_add_recursive (dest, where))
return false;
return true;
}
/* Match a formal argument list or, if typeparam is true, a
type_param_name_list. */
match
gfc_match_formal_arglist (gfc_symbol *progname, int st_flag,
int null_flag, bool typeparam)
{
gfc_formal_arglist *head, *tail, *p, *q;
char name[GFC_MAX_SYMBOL_LEN + 1];
gfc_symbol *sym;
match m;
gfc_formal_arglist *formal = NULL;
head = tail = NULL;
/* Keep the interface formal argument list and null it so that the
matching for the new declaration can be done. The numbers and
names of the arguments are checked here. The interface formal
arguments are retained in formal_arglist and the characteristics
are compared in resolve.c(resolve_fl_procedure). See the remark
in get_proc_name about the eventual need to copy the formal_arglist
and populate the formal namespace of the interface symbol. */
if (progname->attr.module_procedure
&& progname->attr.host_assoc)
{
formal = progname->formal;
progname->formal = NULL;
}
if (gfc_match_char ('(') != MATCH_YES)
{
if (null_flag)
goto ok;
return MATCH_NO;
}
if (gfc_match_char (')') == MATCH_YES)
{
if (typeparam)
{
gfc_error_now ("A type parameter list is required at %C");
m = MATCH_ERROR;
goto cleanup;
}
else
goto ok;
}
for (;;)
{
if (gfc_match_char ('*') == MATCH_YES)
{
sym = NULL;
if (!typeparam && !gfc_notify_std (GFC_STD_F95_OBS,
"Alternate-return argument at %C"))
{
m = MATCH_ERROR;
goto cleanup;
}
else if (typeparam)
gfc_error_now ("A parameter name is required at %C");
}
else
{
m = gfc_match_name (name);
if (m != MATCH_YES)
{
if(typeparam)
gfc_error_now ("A parameter name is required at %C");
goto cleanup;
}
if (!typeparam && gfc_get_symbol (name, NULL, &sym))
goto cleanup;
else if (typeparam
&& gfc_get_symbol (name, progname->f2k_derived, &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)
|| !gfc_missing_attr (&sym->attr, NULL)))
{
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 && !typeparam
&& strcmp (sym->name, gfc_new_block->name) == 0)
{
gfc_error ("Name %qs 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)
{
if (typeparam)
gfc_error_now ("Expected parameter list in type declaration "
"at %C");
else
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)
{
if (typeparam)
gfc_error_now ("Duplicate name %qs in parameter "
"list at %C", p->sym->name);
else
gfc_error ("Duplicate symbol %qs in formal argument "
"list at %C", p->sym->name);
m = MATCH_ERROR;
goto cleanup;
}
}
}
if (!gfc_add_explicit_interface (progname, IFSRC_DECL, head, NULL))
{
m = MATCH_ERROR;
goto cleanup;
}
/* gfc_error_now used in following and return with MATCH_YES because
doing otherwise results in a cascade of extraneous errors and in
some cases an ICE in symbol.c(gfc_release_symbol). */
if (progname->attr.module_procedure && progname->attr.host_assoc)
{
bool arg_count_mismatch = false;
if (!formal && head)
arg_count_mismatch = true;
/* Abbreviated module procedure declaration is not meant to have any
formal arguments! */
if (!progname->abr_modproc_decl && formal && !head)
arg_count_mismatch = true;
for (p = formal, q = head; p && q; p = p->next, q = q->next)
{
if ((p->next != NULL && q->next == NULL)
|| (p->next == NULL && q->next != NULL))
arg_count_mismatch = true;
else if ((p->sym == NULL && q->sym == NULL)
|| strcmp (p->sym->name, q->sym->name) == 0)
continue;
else
gfc_error_now ("Mismatch in MODULE PROCEDURE formal "
"argument names (%s/%s) at %C",
p->sym->name, q->sym->name);
}
if (arg_count_mismatch)
gfc_error_now ("Mismatch in number of MODULE PROCEDURE "
"formal arguments at %C");
}
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))
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. */
static 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))
return MATCH_ERROR;
if (!gfc_add_is_bind_c (&(sym->attr), sym->name, &gfc_current_locus, 1))
return MATCH_ERROR;
}
return found_match;
}
/* Procedure pointer return value without RESULT statement:
Add "hidden" result variable named "ppr@". */
static bool
add_hidden_procptr_result (gfc_symbol *sym)
{
bool case1,case2;
if (gfc_notification_std (GFC_STD_F2003) == ERROR)
return false;
/* 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
{
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;
stree->n.sym->refs++;
}
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 true;
}
else
return false;
}
/* 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 (¤t_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 (¤t_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)
*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))
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, ¤t_attr, NULL))
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))
return MATCH_ERROR;
}
if (!gfc_add_external (&sym->attr, NULL))
return MATCH_ERROR;
if (add_hidden_procptr_result (sym))
sym = sym->result;
if (!gfc_add_proc (&sym->attr, sym->name, NULL))
return MATCH_ERROR;
/* Set interface. */
if (proc_if != NULL)
{
if (sym->ts.type != BT_UNKNOWN)
{
gfc_error ("Procedure %qs 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, ¤t_ts, &gfc_current_locus))
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))
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 (¤t_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"))
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))
return MATCH_ERROR;
/* Add current_attr to the symbol attributes. */
if (!gfc_copy_attr (&c->attr, ¤t_attr, NULL))
return MATCH_ERROR;
if (!gfc_add_external (&c->attr, NULL))
return MATCH_ERROR;
if (!gfc_add_proc (&c->attr, name, NULL))
return MATCH_ERROR;
if (num == 1)
c->tb = tb;
else
{
c->tb = XCNEW (gfc_typebound_proc);
c->tb->where = gfc_current_locus;
*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))
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))
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_SUBMODULE:
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"))
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
do_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_state_stack->previous->state == COMP_SUBMODULE));
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 (¤t_ts);
old_loc = gfc_current_locus;
m = gfc_match_prefix (¤t_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))
sym = sym->result;
if (current_attr.module_procedure)
sym->attr.module_procedure = 1;
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 (gfc_state_stack->previous
&& gfc_state_stack->previous->state != COMP_SUBMODULE)
{
locus loc;
loc = sym->old_symbol != NULL
? sym->old_symbol->declared_at : gfc_current_locus;
gfc_error_now ("BIND(C) attribute at %L can only be used for "
"variables or common blocks", &loc);
}
}
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;
}
/* F2018 C1550 (R1526) If MODULE appears in the prefix of a module
subprogram and a binding label is specified, it shall be the
same as the binding label specified in the corresponding module
procedure interface body. */
if (sym->attr.is_bind_c && sym->attr.module_procedure && sym->old_symbol
&& strcmp (sym->name, sym->old_symbol->name) == 0
&& sym->binding_label && sym->old_symbol->binding_label
&& strcmp (sym->binding_label, sym->old_symbol->binding_label) != 0)
{
const char *null = "NULL", *s1, *s2;
s1 = sym->binding_label;
if (!s1) s1 = null;
s2 = sym->old_symbol->binding_label;
if (!s2) s2 = null;
gfc_error ("Mismatch in BIND(C) names (%qs/%qs) at %C", s1, s2);
sym->refs++; /* Needed to avoid an ICE in gfc_release_symbol */
return MATCH_ERROR;
}
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))
goto cleanup;
if (!gfc_missing_attr (&sym->attr, NULL))
goto cleanup;
if (!copy_prefix (&sym->attr, &sym->declared_at))
{
if(!sym->attr.module_procedure)
goto cleanup;
else
gfc_error_check ();
}
/* 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, ¤t_ts, &gfc_current_locus))
goto cleanup;
sym->result = sym;
}
else
{
if (current_ts.type != BT_UNKNOWN
&& !gfc_add_type (result, ¤t_ts, &gfc_current_locus))
goto cleanup;
sym->result = result;
}
/* Warn if this procedure has the same name as an intrinsic. */
do_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, const char *binding_label, bool sub,
locus *where)
{
gfc_gsymbol *s;
enum gfc_symbol_type type;
type = sub ? GSYM_SUBROUTINE : GSYM_FUNCTION;
/* Only in Fortran 2003: For procedures with a binding label also the Fortran
name is a global identifier. */
if (!binding_label || gfc_notification_std (GFC_STD_F2008))
{
s = gfc_get_gsymbol (name, false);
if (s->defined || (s->type != GSYM_UNKNOWN && s->type != type))
{
gfc_global_used (s, where);
return false;
}
else
{
s->type = type;
s->sym_name = name;
s->where = *where;
s->defined = 1;
s->ns = gfc_current_ns;
}
}
/* Don't add the symbol multiple times. */
if (binding_label
&& (!gfc_notification_std (GFC_STD_F2008)
|| strcmp (name, binding_label) != 0))
{
s = gfc_get_gsymbol (binding_label, true);
if (s->defined || (s->type != GSYM_UNKNOWN && s->type != type))
{
gfc_global_used (s, where);
return false;
}
else
{
s->type = type;
s->sym_name = name;
s->binding_label = binding_label;
s->where = *where;
s->defined = 1;
s->ns = gfc_current_ns;
}
}
return true;
}
/* 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"))
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_SUBMODULE:
gfc_error ("ENTRY statement at %C cannot appear within a SUBMODULE");
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_STRUCTURE:
gfc_error ("ENTRY statement at %C cannot appear within "
"a STRUCTURE block");
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_error ("Unexpected ENTRY statement at %C");
}
return MATCH_ERROR;
}
if ((state == COMP_SUBROUTINE || state == COMP_FUNCTION)
&& gfc_state_stack->previous->state == COMP_INTERFACE)
{
gfc_error ("ENTRY statement at %C cannot appear within an INTERFACE");
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)
{
locus loc;
entry->attr.is_bind_c = 0;
loc = entry->old_symbol != NULL
? entry->old_symbol->declared_at : gfc_current_locus;
gfc_error_now ("BIND(C) attribute at %L can only be used for "
"variables or common blocks", &loc);
}
/* Check what next non-whitespace character is so we can tell if there
is the required parens if we have a BIND(C). */
old_loc = gfc_current_locus;
gfc_gobble_whitespace ();
peek_char = gfc_peek_ascii_char ();
if (state == COMP_SUBROUTINE)
{
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))
return MATCH_ERROR;
}
if (!gfc_current_ns->parent
&& !add_global_entry (name, entry->binding_label, true,
&old_loc))
return MATCH_ERROR;
/* An entry in a subroutine. */
if (!gfc_add_entry (&entry->attr, entry->name, NULL)
|| !gfc_add_subroutine (&entry->attr, entry->name, NULL))
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_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)
|| !gfc_add_function (&entry->attr, entry->name, NULL))
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)
|| !gfc_add_entry (&entry->attr, result->name, NULL)
|| !gfc_add_function (&entry->attr, result->name, NULL))
return MATCH_ERROR;
entry->result = result;
}
else
{
if (!gfc_add_entry (&entry->attr, entry->name, NULL)
|| !gfc_add_function (&entry->attr, entry->name, NULL))
return MATCH_ERROR;
entry->result = entry;
}
}
if (!gfc_current_ns->parent
&& !add_global_entry (name, entry->binding_label, false,
&old_loc))
return MATCH_ERROR;
}
if (gfc_match_eos () != MATCH_YES)
{
gfc_syntax_error (ST_ENTRY);
return MATCH_ERROR;
}
/* F2018:C1546 An elemental procedure shall not have the BIND attribute. */
if (proc->attr.elemental && entry->attr.is_bind_c)
{
gfc_error ("ENTRY statement at %L with BIND(C) prohibited in an "
"elemental procedure", &entry->declared_at);
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;
locus loc;
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 (current_attr.module_procedure)
sym->attr.module_procedure = 1;
if (add_hidden_procptr_result (sym))
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))
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 (gfc_state_stack->previous
&& gfc_state_stack->previous->state != COMP_SUBMODULE)
{
locus loc;
loc = sym->old_symbol != NULL
? sym->old_symbol->declared_at : gfc_current_locus;
gfc_error_now ("BIND(C) attribute at %L can only be used for "
"variables or common blocks", &loc);
}
}
/* 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. */
gfc_gobble_whitespace ();
loc = gfc_current_locus;
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)
{
gfc_formal_arglist *arg;
/* 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))
return MATCH_ERROR;
if (peek_char != '(')
{
gfc_error ("Missing required parentheses before BIND(C) at %C");
return MATCH_ERROR;
}
/* F2018 C1550 (R1526) If MODULE appears in the prefix of a module
subprogram and a binding label is specified, it shall be the
same as the binding label specified in the corresponding module
procedure interface body. */
if (sym->attr.module_procedure && sym->old_symbol
&& strcmp (sym->name, sym->old_symbol->name) == 0
&& sym->binding_label && sym->old_symbol->binding_label
&& strcmp (sym->binding_label, sym->old_symbol->binding_label) != 0)
{
const char *null = "NULL", *s1, *s2;
s1 = sym->binding_label;
if (!s1) s1 = null;
s2 = sym->old_symbol->binding_label;
if (!s2) s2 = null;
gfc_error ("Mismatch in BIND(C) names (%qs/%qs) at %C", s1, s2);
sym->refs++; /* Needed to avoid an ICE in gfc_release_symbol */
return MATCH_ERROR;
}
/* Scan the dummy arguments for an alternate return. */
for (arg = sym->formal; arg; arg = arg->next)
if (!arg->sym)
{
gfc_error ("Alternate return dummy argument cannot appear in a "
"SUBROUTINE with the BIND(C) attribute at %L", &loc);
return MATCH_ERROR;
}
if (!gfc_add_is_bind_c (&(sym->attr), sym->name, &(sym->declared_at), 1))
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))
{
if(!sym->attr.module_procedure)
return MATCH_ERROR;
else
gfc_error_check ();
}
/* Warn if it has the same name as an intrinsic. */
do_warn_intrinsic_shadow (sym, false);
return MATCH_YES;
}
/* Check that the NAME identifier in a BIND attribute or statement
is conform to C identifier rules. */
match
check_bind_name_identifier (char **name)
{
char *n = *name, *p;
/* Remove leading spaces. */
while (*n == ' ')
n++;
/* On an empty string, free memory and set name to NULL. */
if (*n == '\0')
{
free (*name);
*name = NULL;
return MATCH_YES;
}
/* Remove trailing spaces. */
p = n + strlen(n) - 1;
while (*p == ' ')
*(p--) = '\0';
/* Insert the identifier into the symbol table. */
p = xstrdup (n);
free (*name);
*name = p;
/* Now check that identifier is valid under C rules. */
if (ISDIGIT (*p))
{
gfc_error ("Invalid C identifier in NAME= specifier at %C");
return MATCH_ERROR;
}
for (; *p; p++)
if (!(ISALNUM (*p) || *p == '_' || *p == '$'))
{
gfc_error ("Invalid C identifier in NAME= specifier at %C");
return MATCH_ERROR;
}
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)
{
char *binding_label = NULL;
gfc_expr *e = NULL;
/* 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;
if (gfc_match_init_expr (&e) != MATCH_YES)
{
gfc_free_expr (e);
return MATCH_ERROR;
}
if (!gfc_simplify_expr(e, 0))
{
gfc_error ("NAME= specifier at %C should be a constant expression");
gfc_free_expr (e);
return MATCH_ERROR;
}
if (e->expr_type != EXPR_CONSTANT || e->ts.type != BT_CHARACTER
|| e->ts.kind != gfc_default_character_kind || e->rank != 0)
{
gfc_error ("NAME= specifier at %C should be a scalar of "
"default character kind");
gfc_free_expr(e);
return MATCH_ERROR;
}
// Get a C string from the Fortran string constant
binding_label = gfc_widechar_to_char (e->value.character.string,
e->value.character.length);
gfc_free_expr(e);
// Check that it is valid (old gfc_match_name_C)
if (check_bind_name_identifier (&binding_label) != MATCH_YES)
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;
bool abreviated_modproc_decl = false;
bool got_matching_end = false;
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 (startswith (block_name, "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;
abreviated_modproc_decl = gfc_state_stack->previous->sym
&& gfc_state_stack->previous->sym->abr_modproc_decl;
break;
default:
break;
}
if (!abreviated_modproc_decl)
abreviated_modproc_decl = gfc_current_block ()
&& gfc_current_block ()->abr_modproc_decl;
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;
if (!abreviated_modproc_decl)
target = " subroutine";
else
target = " procedure";
eos_ok = !contained_procedure ();
break;
case COMP_FUNCTION:
*st = ST_END_FUNCTION;
if (!abreviated_modproc_decl)
target = " function";
else
target = " procedure";
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_SUBMODULE:
*st = ST_END_SUBMODULE;
target = " submodule";
eos_ok = 1;
break;
case COMP_INTERFACE:
*st = ST_END_INTERFACE;
target = " interface";
eos_ok = 0;
break;
case COMP_MAP:
*st = ST_END_MAP;
target = " map";
eos_ok = 0;
break;
case COMP_UNION:
*st = ST_END_UNION;
target = " union";
eos_ok = 0;
break;
case COMP_STRUCTURE:
*st = ST_END_STRUCTURE;
target = " structure";
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:
case COMP_OMP_STRICTLY_STRUCTURED_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:
case COMP_SELECT_RANK:
*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;
}
old_loc = gfc_current_locus;
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",
abreviated_modproc_decl ? "END PROCEDURE"
: gfc_ascii_statement(*st), &old_loc))
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 %L", abreviated_modproc_decl
? "END PROCEDURE" : gfc_ascii_statement(*st), &old_loc);
goto cleanup;
}
else
got_matching_end = true;
old_loc = gfc_current_locus;
/* 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 %qs in %s statement at %L",
block_name, gfc_ascii_statement (*st), &old_loc);
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;
/* We have to pick out the declared submodule name from the composite
required by F2008:11.2.3 para 2, which ends in the declared name. */
if (state == COMP_SUBMODULE)
block_name = strchr (block_name, '.') + 1;
if (strcmp (name, block_name) != 0 && strcmp (block_name, "ppr@") != 0)
{
gfc_error ("Expected label %qs 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 %qs 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. */
while (state == COMP_BLOCK && !got_matching_end)
{
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;
gfc_state_stack = gfc_state_stack->previous;
state = gfc_current_state ();
}
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;
/* Workaround -Wmaybe-uninitialized false positive during
profiledbootstrap by initializing them. */
gfc_symbol *sym = NULL;
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))
{
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 "
"initialization", 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)
{
/* gfc_set_array_spec sets sym->attr not CLASS_DATA(sym)->attr. Check
for duplicate attribute here. */
if (CLASS_DATA(sym)->attr.dimension == 1 && as)
{
gfc_error ("Duplicate DIMENSION attribute at %C");
m = MATCH_ERROR;
goto cleanup;
}
if (!gfc_copy_attr (&CLASS_DATA(sym)->attr, ¤t_attr, &var_locus))
{
m = MATCH_ERROR;
goto cleanup;
}
}
else
{
if (current_attr.dimension == 0 && current_attr.codimension == 0
&& !gfc_copy_attr (&sym->attr, ¤t_attr, &var_locus))
{
m = MATCH_ERROR;
goto cleanup;
}
}
if (sym->ts.type == BT_CLASS
&& !gfc_build_class_symbol (&sym->ts, &sym->attr, &sym->as))
{
m = MATCH_ERROR;
goto cleanup;
}
if (!gfc_set_array_spec (sym, as, &var_locus))
{
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))
{
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))
{
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 ( , )
or
pointer ( , ), ( , ), ...
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) => (( *) 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 (¤t_attr);
gfc_add_cray_pointer (¤t_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))
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 (0, "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 (¤t_attr);
gfc_add_cray_pointee (¤t_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))
return MATCH_ERROR;
gfc_set_sym_referenced (cpte);
if (cpte->as == NULL)
{
if (!gfc_set_array_spec (cpte, as, &var_locus))
gfc_internal_error ("Cannot 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 (¤t_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 (¤t_attr);
current_attr.intent = intent;
return attr_decl ();
}
match
gfc_match_intrinsic (void)
{
gfc_clear_attr (¤t_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 (¤t_attr);
current_attr.optional = 1;
return attr_decl ();
}
match
gfc_match_pointer (void)
{
gfc_gobble_whitespace ();
if (gfc_peek_ascii_char () == '(')
{
if (!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 (¤t_attr);
current_attr.pointer = 1;
return attr_decl ();
}
}
match
gfc_match_allocatable (void)
{
gfc_clear_attr (¤t_attr);
current_attr.allocatable = 1;
return attr_decl ();
}
match
gfc_match_codimension (void)
{
gfc_clear_attr (¤t_attr);
current_attr.codimension = 1;
return attr_decl ();
}
match
gfc_match_contiguous (void)
{
if (!gfc_notify_std (GFC_STD_F2008, "CONTIGUOUS statement at %C"))
return MATCH_ERROR;
gfc_clear_attr (¤t_attr);
current_attr.contiguous = 1;
return attr_decl ();
}
match
gfc_match_dimension (void)
{
gfc_clear_attr (¤t_attr);
current_attr.dimension = 1;
return attr_decl ();
}
match
gfc_match_target (void)
{
gfc_clear_attr (¤t_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;
gfc_access access = (st == ST_PUBLIC) ? ACCESS_PUBLIC : ACCESS_PRIVATE;
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)
goto done;
switch (type)
{
case INTERFACE_NAMELESS:
case INTERFACE_ABSTRACT:
goto syntax;
case INTERFACE_GENERIC:
case INTERFACE_DTIO:
if (gfc_get_symbol (name, NULL, &sym))
goto done;
if (type == INTERFACE_DTIO
&& gfc_current_ns->proc_name
&& gfc_current_ns->proc_name->attr.flavor == FL_MODULE
&& sym->attr.flavor == FL_UNKNOWN)
sym->attr.flavor = FL_PROCEDURE;
if (!gfc_add_access (&sym->attr, access, sym->name, NULL))
goto done;
if (sym->attr.generic && (dt_sym = gfc_find_dt_in_generic (sym))
&& !gfc_add_access (&dt_sym->attr, access, sym->name, NULL))
goto done;
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] = access;
/* 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] = access;
}
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 = access;
}
else
{
gfc_error ("Access specification of the .%s. operator at %C "
"has already been specified", uop->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;
char c;
/* PROTECTED has already been seen, but must be followed by whitespace
or ::. */
c = gfc_peek_ascii_char ();
if (!gfc_is_whitespace (c) && c != ':')
return MATCH_NO;
if (!gfc_current_ns->proc_name
|| 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;
}
gfc_match (" ::");
if (!gfc_notify_std (GFC_STD_F2003, "PROTECTED statement at %C"))
return MATCH_ERROR;
/* PROTECTED has an entity-list. */
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))
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)
{
gfc_state_data *prev;
if (gfc_match ("private") != MATCH_YES)
return MATCH_NO;
/* Try matching PRIVATE without an access-list. */
if (gfc_match_eos () == MATCH_YES)
{
prev = gfc_state_stack->previous;
if (gfc_current_state () != COMP_MODULE
&& !(gfc_current_state () == COMP_DERIVED
&& prev && prev->state == COMP_MODULE)
&& !(gfc_current_state () == COMP_DERIVED_CONTAINS
&& prev->previous && prev->previous->state == COMP_MODULE))
{
gfc_error ("PRIVATE statement at %C is only allowed in the "
"specification part of a module");
return MATCH_ERROR;
}
*st = ST_PRIVATE;
return MATCH_YES;
}
/* At this point in free-form source code, PRIVATE must be followed
by whitespace or ::. */
if (gfc_current_form == FORM_FREE)
{
char c = gfc_peek_ascii_char ();
if (!gfc_is_whitespace (c) && c != ':')
return MATCH_NO;
}
prev = gfc_state_stack->previous;
if (gfc_current_state () != COMP_MODULE
&& !(gfc_current_state () == COMP_DERIVED
&& prev && prev->state == COMP_MODULE)
&& !(gfc_current_state () == COMP_DERIVED_CONTAINS
&& prev->previous && prev->previous->state == COMP_MODULE))
{
gfc_error ("PRIVATE statement at %C is only allowed in the "
"specification part of a module");
return MATCH_ERROR;
}
*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;
/* Try matching PUBLIC without an access-list. */
if (gfc_match_eos () == MATCH_YES)
{
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;
}
*st = ST_PUBLIC;
return MATCH_YES;
}
/* At this point in free-form source code, PUBLIC must be followed
by whitespace or ::. */
if (gfc_current_form == FORM_FREE)
{
char c = gfc_peek_ascii_char ();
if (!gfc_is_whitespace (c) && c != ':')
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;
}
*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;
bool 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))
{
m = MATCH_ERROR;
goto cleanup;
}
if (!gfc_check_assign_symbol (sym, NULL, init)
|| !gfc_add_flavor (&sym->attr, FL_PARAMETER, sym->name, NULL))
{
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) ? 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)
{
const char *term = " )%t";
match m;
if (gfc_match_char ('(') == MATCH_NO)
{
/* With legacy PARAMETER statements, don't expect a terminating ')'. */
if (!gfc_notify_std (GFC_STD_LEGACY, "PARAMETER without '()' at %C"))
return MATCH_NO;
term = " %t";
}
for (;;)
{
m = do_parm ();
if (m != MATCH_YES)
break;
if (gfc_match (term) == MATCH_YES)
break;
if (gfc_match_char (',') != MATCH_YES)
{
gfc_error ("Unexpected characters in PARAMETER statement at %C");
m = MATCH_ERROR;
break;
}
}
return m;
}
match
gfc_match_automatic (void)
{
gfc_symbol *sym;
match m;
bool seen_symbol = false;
if (!flag_dec_static)
{
gfc_error ("%s at %C is a DEC extension, enable with "
"%<-fdec-static%>",
"AUTOMATIC"
);
return MATCH_ERROR;
}
gfc_match (" ::");
for (;;)
{
m = gfc_match_symbol (&sym, 0);
switch (m)
{
case MATCH_NO:
break;
case MATCH_ERROR:
return MATCH_ERROR;
case MATCH_YES:
if (!gfc_add_automatic (&sym->attr, sym->name, &gfc_current_locus))
return MATCH_ERROR;
seen_symbol = true;
break;
}
if (gfc_match_eos () == MATCH_YES)
break;
if (gfc_match_char (',') != MATCH_YES)
goto syntax;
}
if (!seen_symbol)
{
gfc_error ("Expected entity-list in AUTOMATIC statement at %C");
return MATCH_ERROR;
}
return MATCH_YES;
syntax:
gfc_error ("Syntax error in AUTOMATIC statement at %C");
return MATCH_ERROR;
}
match
gfc_match_static (void)
{
gfc_symbol *sym;
match m;
bool seen_symbol = false;
if (!flag_dec_static)
{
gfc_error ("%s at %C is a DEC extension, enable with "
"%<-fdec-static%>",
"STATIC");
return MATCH_ERROR;
}
gfc_match (" ::");
for (;;)
{
m = gfc_match_symbol (&sym, 0);
switch (m)
{
case MATCH_NO:
break;
case MATCH_ERROR:
return MATCH_ERROR;
case MATCH_YES:
if (!gfc_add_save (&sym->attr, SAVE_EXPLICIT, sym->name,
&gfc_current_locus))
return MATCH_ERROR;
seen_symbol = true;
break;
}
if (gfc_match_eos () == MATCH_YES)
break;
if (gfc_match_char (',') != MATCH_YES)
goto syntax;
}
if (!seen_symbol)
{
gfc_error ("Expected entity-list in STATIC statement at %C");
return MATCH_ERROR;
}
return MATCH_YES;
syntax:
gfc_error ("Syntax error in STATIC statement at %C");
return MATCH_ERROR;
}
/* 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"))
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"))
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))
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:
if (gfc_current_ns->seen_save)
{
gfc_error ("Syntax error in SAVE statement at %C");
return MATCH_ERROR;
}
else
return MATCH_NO;
}
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"))
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))
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;
char *name;
match m;
if (!gfc_notify_std (GFC_STD_F2003, "VOLATILE statement at %C"))
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:
name = XCNEWVAR (char, strlen (sym->name) + 1);
strcpy (name, sym->name);
if (!check_function_name (name))
return MATCH_ERROR;
/* 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 %qs at "
"%C, which is use-/host-associated", sym->name);
return MATCH_ERROR;
}
if (!gfc_add_volatile (&sym->attr, sym->name, &gfc_current_locus))
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;
char *name;
match m;
if (!gfc_notify_std (GFC_STD_F2003, "ASYNCHRONOUS statement at %C"))
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:
name = XCNEWVAR (char, strlen (sym->name) + 1);
strcpy (name, sym->name);
if (!check_function_name (name))
return MATCH_ERROR;
if (!gfc_add_asynchronous (&sym->attr, sym->name, &gfc_current_locus))
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 in a submodule. */
match
gfc_match_submod_proc (void)
{
char name[GFC_MAX_SYMBOL_LEN + 1];
gfc_symbol *sym, *fsym;
match m;
gfc_formal_arglist *formal, *head, *tail;
if (gfc_current_state () != COMP_CONTAINS
|| !(gfc_state_stack->previous
&& (gfc_state_stack->previous->state == COMP_SUBMODULE
|| gfc_state_stack->previous->state == COMP_MODULE)))
return MATCH_NO;
m = gfc_match (" module% procedure% %n", name);
if (m != MATCH_YES)
return m;
if (!gfc_notify_std (GFC_STD_F2008, "MODULE PROCEDURE declaration "
"at %C"))
return MATCH_ERROR;
if (get_proc_name (name, &sym, false))
return MATCH_ERROR;
/* Make sure that the result field is appropriately filled. */
if (sym->tlink && sym->tlink->attr.function)
{
if (sym->tlink->result && sym->tlink->result != sym->tlink)
{
sym->result = sym->tlink->result;
if (!sym->result->attr.use_assoc)
{
gfc_symtree *st = gfc_new_symtree (&gfc_current_ns->sym_root,
sym->result->name);
st->n.sym = sym->result;
sym->result->refs++;
}
}
else
sym->result = sym;
}
/* 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 (!sym->attr.module_procedure)
return MATCH_ERROR;
/* Signal match_end to expect "end procedure". */
sym->abr_modproc_decl = 1;
/* Change from IFSRC_IFBODY coming from the interface declaration. */
sym->attr.if_source = IFSRC_DECL;
gfc_new_block = sym;
/* Make a new formal arglist with the symbols in the procedure
namespace. */
head = tail = NULL;
for (formal = sym->formal; formal && formal->sym; formal = formal->next)
{
if (formal == sym->formal)
head = tail = gfc_get_formal_arglist ();
else
{
tail->next = gfc_get_formal_arglist ();
tail = tail->next;
}
if (gfc_copy_dummy_sym (&fsym, formal->sym, 0))
goto cleanup;
tail->sym = fsym;
gfc_set_sym_referenced (fsym);
}
/* The dummy symbols get cleaned up, when the formal_namespace of the
interface declaration is cleared. This allows us to add the
explicit interface as is done for other type of procedure. */
if (!gfc_add_explicit_interface (sym, IFSRC_DECL, head,
&gfc_current_locus))
return MATCH_ERROR;
if (gfc_match_eos () != MATCH_YES)
{
/* Unset st->n.sym. Note: in reject_statement (), the symbol changes are
undone, such that the st->n.sym->formal points to the original symbol;
if now this namespace is finalized, the formal namespace is freed,
but it might be still needed in the parent namespace. */
gfc_symtree *st = gfc_find_symtree (gfc_current_ns->sym_root, sym->name);
st->n.sym = NULL;
gfc_free_symbol (sym->tlink);
sym->tlink = NULL;
sym->refs--;
gfc_syntax_error (ST_MODULE_PROC);
return MATCH_ERROR;
}
return MATCH_YES;
cleanup:
gfc_free_formal_arglist (head);
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->state != COMP_CONTAINS)
|| 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))
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))
return MATCH_ERROR;
if (!gfc_add_interface (sym))
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;
}
extended = gfc_find_dt_in_generic (extended);
/* F08:C428. */
if (!extended)
{
gfc_error ("Symbol %qs at %C has not been previously defined", name);
return NULL;
}
if (extended->attr.flavor != FL_DERIVED)
{
gfc_error ("%qs in EXTENDS expression at %C is not a "
"derived type", name);
return NULL;
}
if (extended->attr.is_bind_c)
{
gfc_error ("%qs cannot be extended at %C because it "
"is BIND(C)", extended->name);
return NULL;
}
if (extended->attr.sequence)
{
gfc_error ("%qs 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. */
static 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))
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))
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))
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"))
return MATCH_ERROR;
if (!gfc_add_abstract (attr, &gfc_current_locus))
return MATCH_ERROR;
}
else if (name && gfc_match (" , extends ( %n )", name) == MATCH_YES)
{
if (!gfc_add_extension (attr, &gfc_current_locus))
return MATCH_ERROR;
}
else
return MATCH_NO;
/* If we get here, something matched. */
return MATCH_YES;
}
/* Common function for type declaration blocks similar to derived types, such
as STRUCTURES and MAPs. Unlike derived types, a structure type
does NOT have a generic symbol matching the name given by the user.
STRUCTUREs can share names with variables and PARAMETERs so we must allow
for the creation of an independent symbol.
Other parameters are a message to prefix errors with, the name of the new
type to be created, and the flavor to add to the resulting symbol. */
static bool
get_struct_decl (const char *name, sym_flavor fl, locus *decl,
gfc_symbol **result)
{
gfc_symbol *sym;
locus where;
gcc_assert (name[0] == (char) TOUPPER (name[0]));
if (decl)
where = *decl;
else
where = gfc_current_locus;
if (gfc_get_symbol (name, NULL, &sym))
return false;
if (!sym)
{
gfc_internal_error ("Failed to create structure type '%s' at %C", name);
return false;
}
if (sym->components != NULL || sym->attr.zero_comp)
{
gfc_error ("Type definition of %qs at %C was already defined at %L",
sym->name, &sym->declared_at);
return false;
}
sym->declared_at = where;
if (sym->attr.flavor != fl
&& !gfc_add_flavor (&sym->attr, fl, sym->name, NULL))
return false;
if (!sym->hash_value)
/* Set the hash for the compound name for this type. */
sym->hash_value = gfc_hash_value (sym);
/* Normally the type is expected to have been completely parsed by the time
a field declaration with this type is seen. For unions, maps, and nested
structure declarations, we need to indicate that it is okay that we
haven't seen any components yet. This will be updated after the structure
is fully parsed. */
sym->attr.zero_comp = 0;
/* Structures always act like derived-types with the SEQUENCE attribute */
gfc_add_sequence (&sym->attr, sym->name, NULL);
if (result) *result = sym;
return true;
}
/* Match the opening of a MAP block. Like a struct within a union in C;
behaves identical to STRUCTURE blocks. */
match
gfc_match_map (void)
{
/* Counter used to give unique internal names to map structures. */
static unsigned int gfc_map_id = 0;
char name[GFC_MAX_SYMBOL_LEN + 1];
gfc_symbol *sym;
locus old_loc;
old_loc = gfc_current_locus;
if (gfc_match_eos () != MATCH_YES)
{
gfc_error ("Junk after MAP statement at %C");
gfc_current_locus = old_loc;
return MATCH_ERROR;
}
/* Map blocks are anonymous so we make up unique names for the symbol table
which are invalid Fortran identifiers. */
snprintf (name, GFC_MAX_SYMBOL_LEN + 1, "MM$%u", gfc_map_id++);
if (!get_struct_decl (name, FL_STRUCT, &old_loc, &sym))
return MATCH_ERROR;
gfc_new_block = sym;
return MATCH_YES;
}
/* Match the opening of a UNION block. */
match
gfc_match_union (void)
{
/* Counter used to give unique internal names to union types. */
static unsigned int gfc_union_id = 0;
char name[GFC_MAX_SYMBOL_LEN + 1];
gfc_symbol *sym;
locus old_loc;
old_loc = gfc_current_locus;
if (gfc_match_eos () != MATCH_YES)
{
gfc_error ("Junk after UNION statement at %C");
gfc_current_locus = old_loc;
return MATCH_ERROR;
}
/* Unions are anonymous so we make up unique names for the symbol table
which are invalid Fortran identifiers. */
snprintf (name, GFC_MAX_SYMBOL_LEN + 1, "UU$%u", gfc_union_id++);
if (!get_struct_decl (name, FL_UNION, &old_loc, &sym))
return MATCH_ERROR;
gfc_new_block = sym;
return MATCH_YES;
}
/* Match the beginning of a STRUCTURE declaration. This is similar to
matching the beginning of a derived type declaration with a few
twists. The resulting type symbol has no access control or other
interesting attributes. */
match
gfc_match_structure_decl (void)
{
/* Counter used to give unique internal names to anonymous structures. */
static unsigned int gfc_structure_id = 0;
char name[GFC_MAX_SYMBOL_LEN + 1];
gfc_symbol *sym;
match m;
locus where;
if (!flag_dec_structure)
{
gfc_error ("%s at %C is a DEC extension, enable with "
"%<-fdec-structure%>",
"STRUCTURE");
return MATCH_ERROR;
}
name[0] = '\0';
m = gfc_match (" /%n/", name);
if (m != MATCH_YES)
{
/* Non-nested structure declarations require a structure name. */
if (!gfc_comp_struct (gfc_current_state ()))
{
gfc_error ("Structure name expected in non-nested structure "
"declaration at %C");
return MATCH_ERROR;
}
/* This is an anonymous structure; make up a unique name for it
(upper-case letters never make it to symbol names from the source).
The important thing is initializing the type variable
and setting gfc_new_symbol, which is immediately used by
parse_structure () and variable_decl () to add components of
this type. */
snprintf (name, GFC_MAX_SYMBOL_LEN + 1, "SS$%u", gfc_structure_id++);
}
where = gfc_current_locus;
/* No field list allowed after non-nested structure declaration. */
if (!gfc_comp_struct (gfc_current_state ())
&& gfc_match_eos () != MATCH_YES)
{
gfc_error ("Junk after non-nested STRUCTURE statement at %C");
return MATCH_ERROR;
}
/* Make sure the name is not the name of an intrinsic type. */
if (gfc_is_intrinsic_typename (name))
{
gfc_error ("Structure name %qs at %C cannot be the same as an"
" intrinsic type", name);
return MATCH_ERROR;
}
/* Store the actual type symbol for the structure with an upper-case first
letter (an invalid Fortran identifier). */
if (!get_struct_decl (gfc_dt_upper_string (name), FL_STRUCT, &where, &sym))
return MATCH_ERROR;
gfc_new_block = sym;
return MATCH_YES;
}
/* This function does some work to determine which matcher should be used to
* match a statement beginning with "TYPE". This is used to disambiguate TYPE
* as an alias for PRINT from derived type declarations, TYPE IS statements,
* and [parameterized] derived type declarations. */
match
gfc_match_type (gfc_statement *st)
{
char name[GFC_MAX_SYMBOL_LEN + 1];
match m;
locus old_loc;
/* Requires -fdec. */
if (!flag_dec)
return MATCH_NO;
m = gfc_match ("type");
if (m != MATCH_YES)
return m;
/* If we already have an error in the buffer, it is probably from failing to
* match a derived type data declaration. Let it happen. */
else if (gfc_error_flag_test ())
return MATCH_NO;
old_loc = gfc_current_locus;
*st = ST_NONE;
/* If we see an attribute list before anything else it's definitely a derived
* type declaration. */
if (gfc_match (" ,") == MATCH_YES || gfc_match (" ::") == MATCH_YES)
goto derived;
/* By now "TYPE" has already been matched. If we do not see a name, this may
* be something like "TYPE *" or "TYPE ". */
m = gfc_match_name (name);
if (m != MATCH_YES)
{
/* Let print match if it can, otherwise throw an error from
* gfc_match_derived_decl. */
gfc_current_locus = old_loc;
if (gfc_match_print () == MATCH_YES)
{
*st = ST_WRITE;
return MATCH_YES;
}
goto derived;
}
/* Check for EOS. */
if (gfc_match_eos () == MATCH_YES)
{
/* By now we have "TYPE ". Check first if the name is an
* intrinsic typename - if so let gfc_match_derived_decl dump an error.
* Otherwise if gfc_match_derived_decl fails it's probably an existing
* symbol which can be printed. */
gfc_current_locus = old_loc;
m = gfc_match_derived_decl ();
if (gfc_is_intrinsic_typename (name) || m == MATCH_YES)
{
*st = ST_DERIVED_DECL;
return m;
}
}
else
{
/* Here we have "TYPE ". Check for or a PDT declaration
like . */
gfc_gobble_whitespace ();
bool paren = gfc_peek_ascii_char () == '(';
if (paren)
{
if (strcmp ("is", name) == 0)
goto typeis;
else
goto derived;
}
}
/* Treat TYPE... like PRINT... */
gfc_current_locus = old_loc;
*st = ST_WRITE;
return gfc_match_print ();
derived:
gfc_current_locus = old_loc;
*st = ST_DERIVED_DECL;
return gfc_match_derived_decl ();
typeis:
gfc_current_locus = old_loc;
*st = ST_TYPE_IS;
return gfc_match_type_is ();
}
/* 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;
bool parameterized_type = false;
bool seen_colons = false;
if (gfc_comp_struct (gfc_current_state ()))
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;
m = gfc_match (" ::");
if (m == MATCH_YES)
{
seen_colons = true;
}
else if (seen_attr)
{
gfc_error ("Expected :: in TYPE definition at %C");
return MATCH_ERROR;
}
/* In free source form, need to check for TYPE XXX as oppose to TYPEXXX.
But, we need to simply return for TYPE(. */
if (m == MATCH_NO && gfc_current_form == FORM_FREE)
{
char c = gfc_peek_ascii_char ();
if (c == '(')
return m;
if (!gfc_is_whitespace (c))
{
gfc_error ("Mangled derived type definition at %C");
return MATCH_NO;
}
}
m = gfc_match (" %n ", name);
if (m != MATCH_YES)
return m;
/* Make sure that we don't identify TYPE IS (...) as a parameterized
derived type named 'is'.
TODO Expand the check, when 'name' = "is" by matching " (tname) "
and checking if this is a(n intrinsic) typename. This picks up
misplaced TYPE IS statements such as in select_type_1.f03. */
if (gfc_peek_ascii_char () == '(')
{
if (gfc_current_state () == COMP_SELECT_TYPE
|| (!seen_colons && !strcmp (name, "is")))
return MATCH_NO;
parameterized_type = true;
}
m = gfc_match_eos ();
if (m != MATCH_YES && !parameterized_type)
return m;
/* Make sure the name is not the name of an intrinsic type. */
if (gfc_is_intrinsic_typename (name))
{
gfc_error ("Type name %qs 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)
{
if (gensym->ts.u.derived)
gfc_error ("Derived type name %qs at %C already has a basic type "
"of %s", gensym->name, gfc_typename (&gensym->ts));
else
gfc_error ("Derived type name %qs at %C already has a basic type",
gensym->name);
return MATCH_ERROR;
}
if (!gensym->attr.generic
&& !gfc_add_generic (&gensym->attr, gensym->name, NULL))
return MATCH_ERROR;
if (!gensym->attr.function
&& !gfc_add_function (&gensym->attr, gensym->name, NULL))
return MATCH_ERROR;
if (gensym->attr.dummy)
{
gfc_error ("Dummy argument %qs at %L cannot be a derived type at %C",
name, &gensym->declared_at);
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 %qs 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_dt_upper_string (gensym->name), NULL, &sym);
sym->name = gfc_get_string ("%s", 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))
return MATCH_ERROR;
if (attr.access != ACCESS_UNKNOWN
&& !gfc_add_access (&sym->attr, attr.access, sym->name, NULL))
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))
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 (parameterized_type)
{
/* Ignore error or mismatches by going to the end of the statement
in order to avoid the component declarations causing problems. */
m = gfc_match_formal_arglist (sym, 0, 0, true);
if (m != MATCH_YES)
gfc_error_recovery ();
else
sym->attr.pdt_template = 1;
m = gfc_match_eos ();
if (m != MATCH_YES)
{
gfc_error_recovery ();
gfc_error_now ("Garbage after PARAMETERIZED TYPE declaration at %C");
}
}
if (extended && !sym->components)
{
gfc_component *p;
gfc_formal_arglist *f, *g, *h;
/* 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 %qs 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);
/* Copy the extended type-param-name-list from the extended type,
append those of the extension and add the whole lot to the
extension. */
if (extended->attr.pdt_template)
{
g = h = NULL;
sym->attr.pdt_template = 1;
for (f = extended->formal; f; f = f->next)
{
if (f == extended->formal)
{
g = gfc_get_formal_arglist ();
h = g;
}
else
{
g->next = gfc_get_formal_arglist ();
g = g->next;
}
g->sym = f->sym;
}
g->next = sym->formal;
sym->formal = h;
}
}
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"))
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;
bool 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))
{
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) ? 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;
bool t;
gfc_clear_ts (¤t_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;
}
(¤t_ts)->type = BT_INTEGER;
(¤t_ts)->kind = gfc_c_int_kind;
gfc_clear_attr (¤t_attr);
t = gfc_add_flavor (¤t_attr, FL_PARAMETER, NULL, NULL);
if (!t)
{
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 ("%s", 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 cannot both appear at %C");
goto error;
}
m = MATCH_YES;
done:
if (ba->access == ACCESS_UNKNOWN)
ba->access = ppc ? gfc_current_block()->component_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"))
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 %qs 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 targeted 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 %qs for "
"the derived type %qs 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);
gfc_add_flavor(&stree->n.tb->u.specific->n.sym->attr, FL_PROCEDURE,
target, &stree->n.tb->u.specific->n.sym->declared_at);
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:
case INTERFACE_DTIO:
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;
case INTERFACE_NAMELESS:
gfc_error ("Malformed GENERIC statement at %C");
goto error;
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_DTIO:
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);
tb = st ? st->n.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"
" %qs for the derived type %qs 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 %qs", 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_DTIO:
case INTERFACE_GENERIC:
case INTERFACE_USER_OP:
{
const bool is_op = (op_type == INTERFACE_USER_OP);
gfc_symtree* st = gfc_get_tbp_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 ("%qs already defined as specific binding for the"
" generic %qs 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 %qs 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))
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 ("%qs 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" },
{ "no_arg_check", EXT_ATTR_NO_ARG_CHECK, NULL },
{ "deprecated", EXT_ATTR_DEPRECATED, NULL },
{ 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))
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;
}
/* Match a !GCC$ UNROLL statement of the form:
!GCC$ UNROLL n
The parameter n is the number of times we are supposed to unroll.
When we come here, we have already matched the !GCC$ UNROLL string. */
match
gfc_match_gcc_unroll (void)
{
int value;
/* FIXME: use gfc_match_small_literal_int instead, delete small_int */
if (gfc_match_small_int (&value) == MATCH_YES)
{
if (value < 0 || value > USHRT_MAX)
{
gfc_error ("% directive requires a"
" non-negative integral constant"
" less than or equal to %u at %C",
USHRT_MAX
);
return MATCH_ERROR;
}
if (gfc_match_eos () == MATCH_YES)
{
directive_unroll = value == 0 ? 1 : value;
return MATCH_YES;
}
}
gfc_error ("Syntax error in !GCC$ UNROLL directive at %C");
return MATCH_ERROR;
}
/* Match a !GCC$ builtin (b) attributes simd flags if('target') form:
The parameter b is name of a middle-end built-in.
FLAGS is optional and must be one of:
- (inbranch)
- (notinbranch)
IF('target') is optional and TARGET is a name of a multilib ABI.
When we come here, we have already matched the !GCC$ builtin string. */
match
gfc_match_gcc_builtin (void)
{
char builtin[GFC_MAX_SYMBOL_LEN + 1];
char target[GFC_MAX_SYMBOL_LEN + 1];
if (gfc_match (" ( %n ) attributes simd", builtin) != MATCH_YES)
return MATCH_ERROR;
gfc_simd_clause clause = SIMD_NONE;
if (gfc_match (" ( notinbranch ) ") == MATCH_YES)
clause = SIMD_NOTINBRANCH;
else if (gfc_match (" ( inbranch ) ") == MATCH_YES)
clause = SIMD_INBRANCH;
if (gfc_match (" if ( '%n' ) ", target) == MATCH_YES)
{
const char *abi = targetm.get_multilib_abi_name ();
if (abi == NULL || strcmp (abi, target) != 0)
return MATCH_YES;
}
if (gfc_vectorized_builtins == NULL)
gfc_vectorized_builtins = new hash_map ();
char *r = XNEWVEC (char, strlen (builtin) + 32);
sprintf (r, "__builtin_%s", builtin);
bool existed;
int &value = gfc_vectorized_builtins->get_or_insert (r, &existed);
value |= clause;
if (existed)
free (r);
return MATCH_YES;
}
/* Match an !GCC$ IVDEP statement.
When we come here, we have already matched the !GCC$ IVDEP string. */
match
gfc_match_gcc_ivdep (void)
{
if (gfc_match_eos () == MATCH_YES)
{
directive_ivdep = true;
return MATCH_YES;
}
gfc_error ("Syntax error in !GCC$ IVDEP directive at %C");
return MATCH_ERROR;
}
/* Match an !GCC$ VECTOR statement.
When we come here, we have already matched the !GCC$ VECTOR string. */
match
gfc_match_gcc_vector (void)
{
if (gfc_match_eos () == MATCH_YES)
{
directive_vector = true;
directive_novector = false;
return MATCH_YES;
}
gfc_error ("Syntax error in !GCC$ VECTOR directive at %C");
return MATCH_ERROR;
}
/* Match an !GCC$ NOVECTOR statement.
When we come here, we have already matched the !GCC$ NOVECTOR string. */
match
gfc_match_gcc_novector (void)
{
if (gfc_match_eos () == MATCH_YES)
{
directive_novector = true;
directive_vector = false;
return MATCH_YES;
}
gfc_error ("Syntax error in !GCC$ NOVECTOR directive at %C");
return MATCH_ERROR;
}