Index: gcc/gcc/fortran/decl.c |
diff --git a/gcc/gcc/fortran/decl.c b/gcc/gcc/fortran/decl.c |
index 36a6d6302da0f6e74161b7208059972240448b0b..692078a11d4f3f3f703c59d75e71fe3d50c10d2e 100644 |
--- a/gcc/gcc/fortran/decl.c |
+++ b/gcc/gcc/fortran/decl.c |
@@ -1,5 +1,5 @@ |
/* Declaration statement matcher |
- Copyright (C) 2002, 2004, 2005, 2006, 2007, 2008 |
+ Copyright (C) 2002, 2004, 2005, 2006, 2007, 2008, 2009, 2010 |
Free Software Foundation, Inc. |
Contributed by Andy Vaught |
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see |
#include "gfortran.h" |
#include "match.h" |
#include "parse.h" |
+#include "flags.h" |
/* Macros to access allocate memory for gfc_data_variable, |
@@ -621,8 +622,8 @@ char_len_param_value (gfc_expr **expr) |
if (e->symtree->n.sym->ts.type == BT_UNKNOWN) |
goto syntax; |
if (e->symtree->n.sym->ts.type == BT_CHARACTER |
- && e->symtree->n.sym->ts.cl |
- && e->symtree->n.sym->ts.cl->length->ts.type == BT_UNKNOWN) |
+ && e->symtree->n.sym->ts.u.cl |
+ && e->symtree->n.sym->ts.u.cl->length->ts.type == BT_UNKNOWN) |
goto syntax; |
} |
} |
@@ -654,6 +655,9 @@ match_char_length (gfc_expr **expr) |
if (m == MATCH_YES) |
{ |
+ if (gfc_notify_std (GFC_STD_F95_OBS, "Obsolescent feature: " |
+ "Old-style character length at %C") == FAILURE) |
+ return MATCH_ERROR; |
*expr = gfc_int_expr (length); |
return m; |
} |
@@ -695,14 +699,18 @@ syntax: |
(located in another namespace). */ |
static int |
-find_special (const char *name, gfc_symbol **result) |
+find_special (const char *name, gfc_symbol **result, bool allow_subroutine) |
{ |
gfc_state_data *s; |
+ gfc_symtree *st; |
int i; |
- i = gfc_get_symbol (name, NULL, result); |
+ i = gfc_get_sym_tree (name, NULL, &st, allow_subroutine); |
if (i == 0) |
- goto end; |
+ { |
+ *result = st ? st->n.sym : NULL; |
+ goto end; |
+ } |
if (gfc_current_state () != COMP_SUBROUTINE |
&& gfc_current_state () != COMP_FUNCTION) |
@@ -930,7 +938,7 @@ verify_c_interop_param (gfc_symbol *sym) |
"because derived type '%s' is not C interoperable", |
sym->name, &(sym->declared_at), |
sym->ns->proc_name->name, |
- sym->ts.derived->name); |
+ sym->ts.u.derived->name); |
else |
gfc_warning ("Variable '%s' at %L is a parameter to the " |
"BIND(C) procedure '%s' but may not be C " |
@@ -943,7 +951,7 @@ verify_c_interop_param (gfc_symbol *sym) |
length of 1. */ |
if (sym->ts.type == BT_CHARACTER) |
{ |
- gfc_charlen *cl = sym->ts.cl; |
+ gfc_charlen *cl = sym->ts.u.cl; |
if (!cl || !cl->length || cl->length->expr_type != EXPR_CONSTANT |
|| mpz_cmp_si (cl->length->value.integer, 1) != 0) |
{ |
@@ -1017,6 +1025,7 @@ verify_c_interop_param (gfc_symbol *sym) |
} |
+ |
/* Function called by variable_decl() that adds a name to the symbol table. */ |
static gfc_try |
@@ -1037,7 +1046,7 @@ build_sym (const char *name, gfc_charlen *cl, |
return FAILURE; |
if (sym->ts.type == BT_CHARACTER) |
- sym->ts.cl = cl; |
+ sym->ts.u.cl = cl; |
/* Add dimension attribute if present. */ |
if (gfc_set_array_spec (sym, *as, var_locus) == FAILURE) |
@@ -1089,6 +1098,14 @@ build_sym (const char *name, gfc_charlen *cl, |
sym->attr.implied_index = 0; |
+ if (sym->ts.type == BT_CLASS) |
+ { |
+ sym->attr.class_ok = (sym->attr.dummy |
+ || sym->attr.pointer |
+ || sym->attr.allocatable) ? 1 : 0; |
+ gfc_build_class_symbol (&sym->ts, &sym->attr, &sym->as); |
+ } |
+ |
return SUCCESS; |
} |
@@ -1203,7 +1220,7 @@ add_init_expr_to_sym (const char *name, gfc_expr **initp, locus *var_locus) |
gfc_expr *init; |
init = *initp; |
- if (find_special (name, &sym)) |
+ if (find_special (name, &sym, false)) |
return FAILURE; |
attr = sym->attr; |
@@ -1242,43 +1259,46 @@ add_init_expr_to_sym (const char *name, gfc_expr **initp, locus *var_locus) |
/* Check if the assignment can happen. This has to be put off |
until later for a derived type variable. */ |
if (sym->ts.type != BT_DERIVED && init->ts.type != BT_DERIVED |
+ && sym->ts.type != BT_CLASS && init->ts.type != BT_CLASS |
&& gfc_check_assign_symbol (sym, init) == FAILURE) |
return FAILURE; |
- if (sym->ts.type == BT_CHARACTER && sym->ts.cl) |
+ if (sym->ts.type == BT_CHARACTER && sym->ts.u.cl |
+ && init->ts.type == BT_CHARACTER) |
{ |
/* Update symbol character length according initializer. */ |
- if (sym->ts.cl->length == NULL) |
+ if (gfc_check_assign_symbol (sym, init) == FAILURE) |
+ return FAILURE; |
+ |
+ if (sym->ts.u.cl->length == NULL) |
{ |
int clen; |
/* If there are multiple CHARACTER variables declared on the |
same line, we don't want them to share the same length. */ |
- sym->ts.cl = gfc_get_charlen (); |
- sym->ts.cl->next = gfc_current_ns->cl_list; |
- gfc_current_ns->cl_list = sym->ts.cl; |
+ 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.cl->length = gfc_int_expr (clen); |
+ sym->ts.u.cl->length = gfc_int_expr (clen); |
} |
else if (init->expr_type == EXPR_ARRAY) |
{ |
gfc_expr *p = init->value.constructor->expr; |
clen = p->value.character.length; |
- sym->ts.cl->length = gfc_int_expr (clen); |
+ sym->ts.u.cl->length = gfc_int_expr (clen); |
} |
- else if (init->ts.cl && init->ts.cl->length) |
- sym->ts.cl->length = |
- gfc_copy_expr (sym->value->ts.cl->length); |
+ else if (init->ts.u.cl && init->ts.u.cl->length) |
+ sym->ts.u.cl->length = |
+ gfc_copy_expr (sym->value->ts.u.cl->length); |
} |
} |
/* Update initializer character length according symbol. */ |
- else if (sym->ts.cl->length->expr_type == EXPR_CONSTANT) |
+ else if (sym->ts.u.cl->length->expr_type == EXPR_CONSTANT) |
{ |
- int len = mpz_get_si (sym->ts.cl->length->value.integer); |
+ int len = mpz_get_si (sym->ts.u.cl->length->value.integer); |
gfc_constructor * p; |
if (init->expr_type == EXPR_CONSTANT) |
@@ -1287,10 +1307,8 @@ add_init_expr_to_sym (const char *name, gfc_expr **initp, locus *var_locus) |
{ |
/* Build a new charlen to prevent simplification from |
deleting the length before it is resolved. */ |
- init->ts.cl = gfc_get_charlen (); |
- init->ts.cl->next = gfc_current_ns->cl_list; |
- gfc_current_ns->cl_list = sym->ts.cl; |
- init->ts.cl->length = gfc_copy_expr (sym->ts.cl->length); |
+ 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 (p = init->value.constructor; p; p = p->next) |
gfc_set_constant_character_len (len, p->expr, -1); |
@@ -1377,11 +1395,12 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init, |
gfc_array_spec **as) |
{ |
gfc_component *c; |
+ gfc_try t = SUCCESS; |
- /* If the current symbol is of the same derived type that we're |
+ /* F03:C438/C439. If the current symbol is of the same derived type that we're |
constructing, it must have the pointer attribute. */ |
- if (current_ts.type == BT_DERIVED |
- && current_ts.derived == gfc_current_block () |
+ if ((current_ts.type == BT_DERIVED || current_ts.type == BT_CLASS) |
+ && current_ts.u.derived == gfc_current_block () |
&& current_attr.pointer == 0) |
{ |
gfc_error ("Component at %C must have the POINTER attribute"); |
@@ -1402,7 +1421,8 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init, |
return FAILURE; |
c->ts = current_ts; |
- c->ts.cl = cl; |
+ if (c->ts.type == BT_CHARACTER) |
+ c->ts.u.cl = cl; |
c->attr = current_attr; |
c->initializer = *init; |
@@ -1415,62 +1435,52 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init, |
/* Should this ever get more complicated, combine with similar section |
in add_init_expr_to_sym into a separate function. */ |
- if (c->ts.type == BT_CHARACTER && !c->attr.pointer && c->initializer && c->ts.cl |
- && c->ts.cl->length && c->ts.cl->length->expr_type == EXPR_CONSTANT) |
+ if (c->ts.type == BT_CHARACTER && !c->attr.pointer && c->initializer && c->ts.u.cl |
+ && c->ts.u.cl->length && c->ts.u.cl->length->expr_type == EXPR_CONSTANT) |
{ |
int len; |
- gcc_assert (c->ts.cl && c->ts.cl->length); |
- gcc_assert (c->ts.cl->length->expr_type == EXPR_CONSTANT); |
- gcc_assert (c->ts.cl->length->ts.type == BT_INTEGER); |
+ gcc_assert (c->ts.u.cl && c->ts.u.cl->length); |
+ gcc_assert (c->ts.u.cl->length->expr_type == EXPR_CONSTANT); |
+ gcc_assert (c->ts.u.cl->length->ts.type == BT_INTEGER); |
- len = mpz_get_si (c->ts.cl->length->value.integer); |
+ len = mpz_get_si (c->ts.u.cl->length->value.integer); |
if (c->initializer->expr_type == EXPR_CONSTANT) |
gfc_set_constant_character_len (len, c->initializer, -1); |
- else if (mpz_cmp (c->ts.cl->length->value.integer, |
- c->initializer->ts.cl->length->value.integer)) |
+ else if (mpz_cmp (c->ts.u.cl->length->value.integer, |
+ c->initializer->ts.u.cl->length->value.integer)) |
{ |
bool has_ts; |
gfc_constructor *ctor = c->initializer->value.constructor; |
- bool first = true; |
- int first_len; |
- |
- has_ts = (c->initializer->ts.cl |
- && c->initializer->ts.cl->length_from_typespec); |
+ has_ts = (c->initializer->ts.u.cl |
+ && c->initializer->ts.u.cl->length_from_typespec); |
- for (; ctor; ctor = ctor->next) |
+ if (ctor) |
{ |
- /* Remember the length of the first element for checking that |
- all elements *in the constructor* have the same length. This |
- need not be the length of the LHS! */ |
- if (first) |
+ int first_len; |
+ |
+ /* Remember the length of the first element for checking |
+ that all elements *in the constructor* have the same |
+ length. This need not be the length of the LHS! */ |
+ gcc_assert (ctor->expr->expr_type == EXPR_CONSTANT); |
+ gcc_assert (ctor->expr->ts.type == BT_CHARACTER); |
+ first_len = ctor->expr->value.character.length; |
+ |
+ for (; ctor; ctor = ctor->next) |
{ |
- gcc_assert (ctor->expr->expr_type == EXPR_CONSTANT); |
- gcc_assert (ctor->expr->ts.type == BT_CHARACTER); |
- first_len = ctor->expr->value.character.length; |
- first = false; |
+ if (ctor->expr->expr_type == EXPR_CONSTANT) |
+ gfc_set_constant_character_len (len, ctor->expr, |
+ has_ts ? -1 : first_len); |
} |
- |
- if (ctor->expr->expr_type == EXPR_CONSTANT) |
- gfc_set_constant_character_len (len, ctor->expr, |
- has_ts ? -1 : first_len); |
} |
} |
} |
/* Check array components. */ |
if (!c->attr.dimension) |
- { |
- if (c->attr.allocatable) |
- { |
- gfc_error ("Allocatable component at %C must be an array"); |
- return FAILURE; |
- } |
- else |
- return SUCCESS; |
- } |
+ goto scalar; |
if (c->attr.pointer) |
{ |
@@ -1478,7 +1488,7 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init, |
{ |
gfc_error ("Pointer array component of structure at %C must have a " |
"deferred shape"); |
- return FAILURE; |
+ t = FAILURE; |
} |
} |
else if (c->attr.allocatable) |
@@ -1487,7 +1497,7 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init, |
{ |
gfc_error ("Allocatable component of structure at %C must have a " |
"deferred shape"); |
- return FAILURE; |
+ t = FAILURE; |
} |
} |
else |
@@ -1496,11 +1506,15 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init, |
{ |
gfc_error ("Array component of structure at %C must have an " |
"explicit shape"); |
- return FAILURE; |
+ t = FAILURE; |
} |
} |
- return SUCCESS; |
+scalar: |
+ if (c->ts.type == BT_CLASS) |
+ gfc_build_class_symbol (&c->ts, &c->attr, &c->as); |
+ |
+ return t; |
} |
@@ -1560,12 +1574,10 @@ variable_decl (int elem) |
match m; |
gfc_try t; |
gfc_symbol *sym; |
- locus old_locus; |
initializer = NULL; |
as = NULL; |
cp_as = NULL; |
- old_locus = gfc_current_locus; |
/* When we get here, we've just matched a list of attributes and |
maybe a type and a double colon. The next thing we expect to see |
@@ -1594,9 +1606,7 @@ variable_decl (int elem) |
switch (match_char_length (&char_len)) |
{ |
case MATCH_YES: |
- cl = gfc_get_charlen (); |
- cl->next = gfc_current_ns->cl_list; |
- gfc_current_ns->cl_list = cl; |
+ cl = gfc_new_charlen (gfc_current_ns, NULL); |
cl->length = char_len; |
break; |
@@ -1605,16 +1615,14 @@ variable_decl (int elem) |
element. Also copy assumed lengths. */ |
case MATCH_NO: |
if (elem > 1 |
- && (current_ts.cl->length == NULL |
- || current_ts.cl->length->expr_type != EXPR_CONSTANT)) |
+ && (current_ts.u.cl->length == NULL |
+ || current_ts.u.cl->length->expr_type != EXPR_CONSTANT)) |
{ |
- cl = gfc_get_charlen (); |
- cl->next = gfc_current_ns->cl_list; |
- gfc_current_ns->cl_list = cl; |
- cl->length = gfc_copy_expr (current_ts.cl->length); |
+ cl = gfc_new_charlen (gfc_current_ns, NULL); |
+ cl->length = gfc_copy_expr (current_ts.u.cl->length); |
} |
else |
- cl = current_ts.cl; |
+ cl = current_ts.u.cl; |
break; |
@@ -1632,8 +1640,8 @@ variable_decl (int elem) |
{ |
sym->ts.type = current_ts.type; |
sym->ts.kind = current_ts.kind; |
- sym->ts.cl = cl; |
- sym->ts.derived = current_ts.derived; |
+ sym->ts.u.cl = cl; |
+ sym->ts.u.derived = current_ts.u.derived; |
sym->ts.is_c_interop = current_ts.is_c_interop; |
sym->ts.is_iso_c = current_ts.is_iso_c; |
m = MATCH_YES; |
@@ -1667,6 +1675,17 @@ variable_decl (int elem) |
} |
} |
+ /* 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 |
@@ -1694,13 +1713,13 @@ variable_decl (int elem) |
if (current_ts.type == BT_DERIVED |
&& gfc_current_ns->proc_name |
&& gfc_current_ns->proc_name->attr.if_source == IFSRC_IFBODY |
- && current_ts.derived->ns != gfc_current_ns) |
+ && current_ts.u.derived->ns != gfc_current_ns) |
{ |
gfc_symtree *st; |
- st = gfc_find_symtree (gfc_current_ns->sym_root, current_ts.derived->name); |
- if (!(current_ts.derived->attr.imported |
+ st = gfc_find_symtree (gfc_current_ns->sym_root, current_ts.u.derived->name); |
+ if (!(current_ts.u.derived->attr.imported |
&& st != NULL |
- && st->n.sym == current_ts.derived) |
+ && st->n.sym == current_ts.u.derived) |
&& !gfc_current_ns->has_import_set) |
{ |
gfc_error ("the type of '%s' at %C has not been declared within the " |
@@ -1762,7 +1781,7 @@ variable_decl (int elem) |
m = MATCH_ERROR; |
} |
- if (gfc_pure (NULL)) |
+ if (gfc_pure (NULL) && gfc_state_stack->state != COMP_DERIVED) |
{ |
gfc_error ("Initialization of pointer at %C is not allowed in " |
"a PURE procedure"); |
@@ -1790,7 +1809,8 @@ variable_decl (int elem) |
m = MATCH_ERROR; |
} |
- if (current_attr.flavor != FL_PARAMETER && gfc_pure (NULL)) |
+ if (current_attr.flavor != FL_PARAMETER && gfc_pure (NULL) |
+ && gfc_state_stack->state != COMP_DERIVED) |
{ |
gfc_error ("Initialization of variable at %C is not allowed in " |
"a PURE procedure"); |
@@ -1989,9 +2009,9 @@ kind_expr: |
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_error_now ("C kind type parameter is for type %s but type at %L " |
- "is %s", gfc_basic_typename (ts->f90_type), &where, |
- gfc_basic_typename (ts->type)); |
+ gfc_warning_now ("C kind type parameter is for type %s but type at %L " |
+ "is %s", gfc_basic_typename (ts->f90_type), &where, |
+ gfc_basic_typename (ts->type)); |
gfc_gobble_whitespace (); |
if ((c = gfc_next_ascii_char ()) != ')' |
@@ -2090,11 +2110,12 @@ no_match: |
return m; |
} |
+ |
/* Match the various kind/length specifications in a CHARACTER |
declaration. We don't return MATCH_NO. */ |
-static match |
-match_char_spec (gfc_typespec *ts) |
+match |
+gfc_match_char_spec (gfc_typespec *ts) |
{ |
int kind, seen_length, is_iso_c; |
gfc_charlen *cl; |
@@ -2221,16 +2242,14 @@ done: |
} |
/* Do some final massaging of the length values. */ |
- cl = gfc_get_charlen (); |
- cl->next = gfc_current_ns->cl_list; |
- gfc_current_ns->cl_list = cl; |
+ cl = gfc_new_charlen (gfc_current_ns, NULL); |
if (seen_length == 0) |
cl->length = gfc_int_expr (1); |
else |
cl->length = len; |
- ts->cl = cl; |
+ ts->u.cl = cl; |
ts->kind = kind == 0 ? gfc_default_character_kind : kind; |
/* We have to know if it was a c interoperable kind so we can |
@@ -2254,8 +2273,8 @@ done: |
} |
-/* Matches a type specification. If successful, sets the ts structure |
- to the matched specification. This is necessary for FUNCTION and |
+/* 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 |
@@ -2263,7 +2282,7 @@ done: |
statement correctly. */ |
match |
-gfc_match_type_spec (gfc_typespec *ts, int implicit_flag) |
+gfc_match_decl_type_spec (gfc_typespec *ts, int implicit_flag) |
{ |
char name[GFC_MAX_SYMBOL_LEN + 1]; |
gfc_symbol *sym; |
@@ -2285,7 +2304,7 @@ gfc_match_type_spec (gfc_typespec *ts, int implicit_flag) |
if (gfc_match (" byte") == MATCH_YES) |
{ |
- if (gfc_notify_std(GFC_STD_GNU, "Extension: BYTE type at %C") |
+ if (gfc_notify_std (GFC_STD_GNU, "Extension: BYTE type at %C") |
== FAILURE) |
return MATCH_ERROR; |
@@ -2312,7 +2331,7 @@ gfc_match_type_spec (gfc_typespec *ts, int implicit_flag) |
{ |
ts->type = BT_CHARACTER; |
if (implicit_flag == 0) |
- return match_char_spec (ts); |
+ return gfc_match_char_spec (ts); |
else |
return MATCH_YES; |
} |
@@ -2357,20 +2376,29 @@ gfc_match_type_spec (gfc_typespec *ts, int implicit_flag) |
} |
m = gfc_match (" type ( %n )", name); |
- if (m != MATCH_YES) |
- return m; |
+ if (m == MATCH_YES) |
+ ts->type = BT_DERIVED; |
+ else |
+ { |
+ m = gfc_match (" class ( %n )", name); |
+ if (m != MATCH_YES) |
+ return m; |
+ ts->type = BT_CLASS; |
- ts->type = BT_DERIVED; |
+ if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: CLASS statement at %C") |
+ == FAILURE) |
+ return MATCH_ERROR; |
+ } |
/* Defer association of the derived type until the end of the |
specification block. However, if the derived type can be |
found, add it to the typespec. */ |
if (gfc_matching_function) |
{ |
- ts->derived = NULL; |
+ ts->u.derived = NULL; |
if (gfc_current_state () != COMP_INTERFACE |
&& !gfc_find_symbol (name, NULL, 1, &sym) && sym) |
- ts->derived = sym; |
+ ts->u.derived = sym; |
return MATCH_YES; |
} |
@@ -2403,7 +2431,7 @@ gfc_match_type_spec (gfc_typespec *ts, int implicit_flag) |
return MATCH_ERROR; |
gfc_set_sym_referenced (sym); |
- ts->derived = sym; |
+ ts->u.derived = sym; |
return MATCH_YES; |
@@ -2415,8 +2443,8 @@ get_kind: |
if (gfc_current_form == FORM_FREE) |
{ |
- c = gfc_peek_ascii_char(); |
- if (!gfc_is_whitespace(c) && c != '*' && c != '(' |
+ c = gfc_peek_ascii_char (); |
+ if (!gfc_is_whitespace (c) && c != '*' && c != '(' |
&& c != ':' && c != ',') |
return MATCH_NO; |
} |
@@ -2577,7 +2605,7 @@ gfc_match_implicit (void) |
gfc_clear_new_implicit (); |
/* A basic type is mandatory here. */ |
- m = gfc_match_type_spec (&ts, 1); |
+ m = gfc_match_decl_type_spec (&ts, 1); |
if (m == MATCH_ERROR) |
goto error; |
if (m == MATCH_NO) |
@@ -2594,13 +2622,11 @@ gfc_match_implicit (void) |
if ((c == '\n') || (c == ',')) |
{ |
/* Check for CHARACTER with no length parameter. */ |
- if (ts.type == BT_CHARACTER && !ts.cl) |
+ if (ts.type == BT_CHARACTER && !ts.u.cl) |
{ |
ts.kind = gfc_default_character_kind; |
- ts.cl = gfc_get_charlen (); |
- ts.cl->next = gfc_current_ns->cl_list; |
- gfc_current_ns->cl_list = ts.cl; |
- ts.cl->length = gfc_int_expr (1); |
+ ts.u.cl = gfc_new_charlen (gfc_current_ns, NULL); |
+ ts.u.cl->length = gfc_int_expr (1); |
} |
/* Record the Successful match. */ |
@@ -2617,7 +2643,7 @@ gfc_match_implicit (void) |
/* Last chance -- check <TYPE> <SELECTOR> (<RANGE>). */ |
if (ts.type == BT_CHARACTER) |
- m = match_char_spec (&ts); |
+ m = gfc_match_char_spec (&ts); |
else |
{ |
m = gfc_match_kind_spec (&ts, false); |
@@ -2730,7 +2756,7 @@ gfc_match_import (void) |
goto next_item; |
} |
- st = gfc_new_symtree (&gfc_current_ns->sym_root, name); |
+ st = gfc_new_symtree (&gfc_current_ns->sym_root, sym->name); |
st->n.sym = sym; |
sym->refs++; |
sym->attr.imported = 1; |
@@ -2794,7 +2820,7 @@ match_attr_spec (void) |
DECL_IN, DECL_OUT, DECL_INOUT, DECL_INTRINSIC, DECL_OPTIONAL, |
DECL_PARAMETER, DECL_POINTER, DECL_PROTECTED, DECL_PRIVATE, |
DECL_PUBLIC, DECL_SAVE, DECL_TARGET, DECL_VALUE, DECL_VOLATILE, |
- DECL_IS_BIND_C, DECL_NONE, |
+ DECL_IS_BIND_C, DECL_ASYNCHRONOUS, DECL_NONE, |
GFC_DECL_END /* Sentinel */ |
} |
decl_types; |
@@ -2804,7 +2830,7 @@ match_attr_spec (void) |
locus start, seen_at[NUM_DECL]; |
int seen[NUM_DECL]; |
- decl_types d; |
+ unsigned int d; |
const char *attr; |
match m; |
gfc_try t; |
@@ -2839,9 +2865,25 @@ match_attr_spec (void) |
switch (gfc_peek_ascii_char ()) |
{ |
case 'a': |
- if (match_string_p ("allocatable")) |
- d = DECL_ALLOCATABLE; |
- break; |
+ 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 'b': |
/* Try and match the bind(c). */ |
@@ -3022,6 +3064,9 @@ match_attr_spec (void) |
case DECL_ALLOCATABLE: |
attr = "ALLOCATABLE"; |
break; |
+ case DECL_ASYNCHRONOUS: |
+ attr = "ASYNCHRONOUS"; |
+ break; |
case DECL_DIMENSION: |
attr = "DIMENSION"; |
break; |
@@ -3148,6 +3193,15 @@ match_attr_spec (void) |
t = gfc_add_allocatable (¤t_attr, &seen_at[d]); |
break; |
+ case DECL_ASYNCHRONOUS: |
+ if (gfc_notify_std (GFC_STD_F2003, |
+ "Fortran 2003: ASYNCHRONOUS attribute at %C") |
+ == FAILURE) |
+ t = FAILURE; |
+ else |
+ t = gfc_add_asynchronous (¤t_attr, NULL, &seen_at[d]); |
+ break; |
+ |
case DECL_DIMENSION: |
t = gfc_add_dimension (¤t_attr, NULL, &seen_at[d]); |
break; |
@@ -3312,8 +3366,8 @@ set_com_block_bind_c (gfc_common_head *com_block, int is_bind_c) |
gfc_try |
verify_c_interop (gfc_typespec *ts) |
{ |
- if (ts->type == BT_DERIVED && ts->derived != NULL) |
- return (ts->derived->ts.is_c_interop ? SUCCESS : FAILURE); |
+ if (ts->type == BT_DERIVED && ts->u.derived != NULL) |
+ return (ts->u.derived->ts.is_c_interop ? SUCCESS : FAILURE); |
else if (ts->is_c_interop != 1) |
return FAILURE; |
@@ -3455,9 +3509,9 @@ verify_bind_c_sym (gfc_symbol *tmp_sym, gfc_typespec *ts, |
/* BIND(C) functions can not return a character string. */ |
if (bind_c_function && tmp_sym->ts.type == BT_CHARACTER) |
- if (tmp_sym->ts.cl == NULL || tmp_sym->ts.cl->length == NULL |
- || tmp_sym->ts.cl->length->expr_type != EXPR_CONSTANT |
- || mpz_cmp_si (tmp_sym->ts.cl->length->value.integer, 1) != 0) |
+ if (tmp_sym->ts.u.cl == NULL || tmp_sym->ts.u.cl->length == NULL |
+ || tmp_sym->ts.u.cl->length->expr_type != EXPR_CONSTANT |
+ || mpz_cmp_si (tmp_sym->ts.u.cl->length->value.integer, 1) != 0) |
gfc_error ("Return type of BIND(C) function '%s' at %L cannot " |
"be a character string", tmp_sym->name, |
&(tmp_sym->declared_at)); |
@@ -3655,13 +3709,14 @@ gfc_match_data_decl (void) |
num_idents_on_line = 0; |
- m = gfc_match_type_spec (¤t_ts, 0); |
+ m = gfc_match_decl_type_spec (¤t_ts, 0); |
if (m != MATCH_YES) |
return m; |
- if (current_ts.type == BT_DERIVED && gfc_current_state () != COMP_DERIVED) |
+ if ((current_ts.type == BT_DERIVED || current_ts.type == BT_CLASS) |
+ && gfc_current_state () != COMP_DERIVED) |
{ |
- sym = gfc_use_derived (current_ts.derived); |
+ sym = gfc_use_derived (current_ts.u.derived); |
if (sym == NULL) |
{ |
@@ -3669,7 +3724,7 @@ gfc_match_data_decl (void) |
goto cleanup; |
} |
- current_ts.derived = sym; |
+ current_ts.u.derived = sym; |
} |
m = match_attr_spec (); |
@@ -3679,21 +3734,22 @@ gfc_match_data_decl (void) |
goto cleanup; |
} |
- if (current_ts.type == BT_DERIVED && current_ts.derived->components == NULL |
- && !current_ts.derived->attr.zero_comp) |
+ if ((current_ts.type == BT_DERIVED || current_ts.type == BT_CLASS) |
+ && current_ts.u.derived->components == NULL |
+ && !current_ts.u.derived->attr.zero_comp) |
{ |
if (current_attr.pointer && gfc_current_state () == COMP_DERIVED) |
goto ok; |
- gfc_find_symbol (current_ts.derived->name, |
- current_ts.derived->ns->parent, 1, &sym); |
+ gfc_find_symbol (current_ts.u.derived->name, |
+ current_ts.u.derived->ns->parent, 1, &sym); |
/* Any symbol that we find had better be a type definition |
which has its components defined. */ |
if (sym != NULL && sym->attr.flavor == FL_DERIVED |
- && (current_ts.derived->components != NULL |
- || current_ts.derived->attr.zero_comp)) |
+ && (current_ts.u.derived->components != NULL |
+ || current_ts.u.derived->attr.zero_comp)) |
goto ok; |
/* Now we have an error, which we signal, and then fix up |
@@ -3760,7 +3816,7 @@ gfc_match_prefix (gfc_typespec *ts) |
loop: |
if (!seen_type && ts != NULL |
- && gfc_match_type_spec (ts, 0) == MATCH_YES |
+ && gfc_match_decl_type_spec (ts, 0) == MATCH_YES |
&& gfc_match_space () == MATCH_YES) |
{ |
@@ -4069,19 +4125,85 @@ gfc_match_suffix (gfc_symbol *sym, gfc_symbol **result) |
} |
-/* Match a PROCEDURE declaration (R1211). */ |
+/* Procedure pointer return value without RESULT statement: |
+ Add "hidden" result variable named "ppr@". */ |
+ |
+static gfc_try |
+add_hidden_procptr_result (gfc_symbol *sym) |
+{ |
+ bool case1,case2; |
+ |
+ if (gfc_notification_std (GFC_STD_F2003) == ERROR) |
+ return FAILURE; |
+ |
+ /* First usage case: PROCEDURE and EXTERNAL statements. */ |
+ case1 = gfc_current_state () == COMP_FUNCTION && gfc_current_block () |
+ && strcmp (gfc_current_block ()->name, sym->name) == 0 |
+ && sym->attr.external; |
+ /* Second usage case: INTERFACE statements. */ |
+ case2 = gfc_current_state () == COMP_INTERFACE && gfc_state_stack->previous |
+ && gfc_state_stack->previous->state == COMP_FUNCTION |
+ && strcmp (gfc_state_stack->previous->sym->name, sym->name) == 0; |
+ |
+ if (case1 || case2) |
+ { |
+ gfc_symtree *stree; |
+ if (case1) |
+ gfc_get_sym_tree ("ppr@", gfc_current_ns, &stree, false); |
+ else if (case2) |
+ { |
+ gfc_symtree *st2; |
+ gfc_get_sym_tree ("ppr@", gfc_current_ns->parent, &stree, false); |
+ st2 = gfc_new_symtree (&gfc_current_ns->sym_root, "ppr@"); |
+ st2->n.sym = stree->n.sym; |
+ } |
+ sym->result = stree->n.sym; |
+ |
+ sym->result->attr.proc_pointer = sym->attr.proc_pointer; |
+ sym->result->attr.pointer = sym->attr.pointer; |
+ sym->result->attr.external = sym->attr.external; |
+ sym->result->attr.referenced = sym->attr.referenced; |
+ sym->result->ts = sym->ts; |
+ sym->attr.proc_pointer = 0; |
+ sym->attr.pointer = 0; |
+ sym->attr.external = 0; |
+ if (sym->result->attr.external && sym->result->attr.pointer) |
+ { |
+ sym->result->attr.pointer = 0; |
+ sym->result->attr.proc_pointer = 1; |
+ } |
+ |
+ return gfc_add_result (&sym->result->attr, sym->result->name, NULL); |
+ } |
+ /* POINTER after PROCEDURE/EXTERNAL/INTERFACE statement. */ |
+ else if (sym->attr.function && !sym->attr.external && sym->attr.pointer |
+ && sym->result && sym->result != sym && sym->result->attr.external |
+ && sym == gfc_current_ns->proc_name |
+ && sym == sym->result->ns->proc_name |
+ && strcmp ("ppr@", sym->result->name) == 0) |
+ { |
+ sym->result->attr.proc_pointer = 1; |
+ sym->attr.pointer = 0; |
+ return SUCCESS; |
+ } |
+ else |
+ return FAILURE; |
+} |
+ |
+ |
+/* Match the interface for a PROCEDURE declaration, |
+ including brackets (R1212). */ |
static match |
-match_procedure_decl (void) |
+match_procedure_interface (gfc_symbol **proc_if) |
{ |
match m; |
+ gfc_symtree *st; |
locus old_loc, entry_loc; |
- gfc_symbol *sym, *proc_if = NULL; |
- int num; |
- gfc_expr *initializer = NULL; |
+ 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) |
@@ -4092,7 +4214,7 @@ match_procedure_decl (void) |
/* Get the type spec. for the procedure interface. */ |
old_loc = gfc_current_locus; |
- m = gfc_match_type_spec (¤t_ts, 0); |
+ 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; |
@@ -4100,49 +4222,59 @@ match_procedure_decl (void) |
if (m == MATCH_ERROR) |
return m; |
+ /* Procedure interface is itself a procedure. */ |
gfc_current_locus = old_loc; |
+ m = gfc_match_name (name); |
- /* Get the name of the procedure or abstract interface |
- to inherit the interface from. */ |
- m = gfc_match_symbol (&proc_if, 1); |
+ /* 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 (m == MATCH_NO) |
- goto syntax; |
- else if (m == MATCH_ERROR) |
- return m; |
+ /* 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; |
/* Various interface checks. */ |
- if (proc_if) |
+ if (*proc_if) |
{ |
- proc_if->refs++; |
+ (*proc_if)->refs++; |
/* Resolve interface if possible. That way, attr.procedure is only set |
if it is declared by a later procedure-declaration-stmt, which is |
invalid per C1212. */ |
- while (proc_if->ts.interface) |
- proc_if = proc_if->ts.interface; |
+ while ((*proc_if)->ts.interface) |
+ *proc_if = (*proc_if)->ts.interface; |
- if (proc_if->generic) |
+ if ((*proc_if)->generic) |
{ |
- gfc_error ("Interface '%s' at %C may not be generic", proc_if->name); |
+ gfc_error ("Interface '%s' at %C may not be generic", |
+ (*proc_if)->name); |
return MATCH_ERROR; |
} |
- if (proc_if->attr.proc == PROC_ST_FUNCTION) |
+ if ((*proc_if)->attr.proc == PROC_ST_FUNCTION) |
{ |
gfc_error ("Interface '%s' at %C may not be a statement function", |
- proc_if->name); |
+ (*proc_if)->name); |
return MATCH_ERROR; |
} |
/* Handle intrinsic procedures. */ |
- if (!(proc_if->attr.external || proc_if->attr.use_assoc |
- || proc_if->attr.if_source == IFSRC_IFBODY) |
- && (gfc_is_intrinsic (proc_if, 0, gfc_current_locus) |
- || gfc_is_intrinsic (proc_if, 1, gfc_current_locus))) |
- proc_if->attr.intrinsic = 1; |
- if (proc_if->attr.intrinsic |
- && !gfc_intrinsic_actual_ok (proc_if->name, 0)) |
+ if (!((*proc_if)->attr.external || (*proc_if)->attr.use_assoc |
+ || (*proc_if)->attr.if_source == IFSRC_IFBODY) |
+ && (gfc_is_intrinsic ((*proc_if), 0, gfc_current_locus) |
+ || gfc_is_intrinsic ((*proc_if), 1, gfc_current_locus))) |
+ (*proc_if)->attr.intrinsic = 1; |
+ if ((*proc_if)->attr.intrinsic |
+ && !gfc_intrinsic_actual_ok ((*proc_if)->name, 0)) |
{ |
gfc_error ("Intrinsic procedure '%s' not allowed " |
- "in PROCEDURE statement at %C", proc_if->name); |
+ "in PROCEDURE statement at %C", (*proc_if)->name); |
return MATCH_ERROR; |
} |
} |
@@ -4154,7 +4286,26 @@ got_ts: |
return MATCH_NO; |
} |
- /* Parse attributes. */ |
+ 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; |
@@ -4201,22 +4352,36 @@ got_ts: |
if (gfc_add_external (&sym->attr, NULL) == FAILURE) |
return MATCH_ERROR; |
+ |
+ if (add_hidden_procptr_result (sym) == SUCCESS) |
+ sym = sym->result; |
+ |
if (gfc_add_proc (&sym->attr, sym->name, NULL) == FAILURE) |
return MATCH_ERROR; |
/* Set interface. */ |
if (proc_if != NULL) |
{ |
+ if (sym->ts.type != BT_UNKNOWN) |
+ { |
+ gfc_error ("Procedure '%s' at %L already has basic type of %s", |
+ sym->name, &gfc_current_locus, |
+ gfc_basic_typename (sym->ts.type)); |
+ return MATCH_ERROR; |
+ } |
sym->ts.interface = proc_if; |
sym->attr.untyped = 1; |
+ sym->attr.if_source = IFSRC_IFBODY; |
} |
else if (current_ts.type != BT_UNKNOWN) |
{ |
- sym->ts = current_ts; |
+ if (gfc_add_type (sym, ¤t_ts, &gfc_current_locus) == FAILURE) |
+ return MATCH_ERROR; |
sym->ts.interface = gfc_new_symbol ("", gfc_current_ns); |
sym->ts.interface->ts = current_ts; |
sym->ts.interface->attr.function = 1; |
sym->attr.function = sym->ts.interface->attr.function; |
+ sym->attr.if_source = IFSRC_UNKNOWN; |
} |
if (gfc_match (" =>") == MATCH_YES) |
@@ -4270,6 +4435,136 @@ cleanup: |
} |
+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, "Fortran 2003: Procedure pointer " |
+ "component at %C") == FAILURE) |
+ return MATCH_ERROR; |
+ |
+ /* Match PPC names. */ |
+ ts = current_ts; |
+ for(num=1;;num++) |
+ { |
+ m = gfc_match_name (name); |
+ if (m == MATCH_NO) |
+ goto syntax; |
+ else if (m == MATCH_ERROR) |
+ return m; |
+ |
+ if (gfc_add_component (gfc_current_block (), name, &c) == FAILURE) |
+ return MATCH_ERROR; |
+ |
+ /* Add current_attr to the symbol attributes. */ |
+ if (gfc_copy_attr (&c->attr, ¤t_attr, NULL) == FAILURE) |
+ return MATCH_ERROR; |
+ |
+ if (gfc_add_external (&c->attr, NULL) == FAILURE) |
+ return MATCH_ERROR; |
+ |
+ if (gfc_add_proc (&c->attr, name, NULL) == FAILURE) |
+ return MATCH_ERROR; |
+ |
+ c->tb = tb; |
+ |
+ /* Set interface. */ |
+ if (proc_if != NULL) |
+ { |
+ c->ts.interface = proc_if; |
+ c->attr.untyped = 1; |
+ c->attr.if_source = IFSRC_IFBODY; |
+ } |
+ else if (ts.type != BT_UNKNOWN) |
+ { |
+ c->ts = ts; |
+ c->ts.interface = gfc_new_symbol ("", gfc_current_ns); |
+ c->ts.interface->ts = ts; |
+ c->ts.interface->attr.function = 1; |
+ c->attr.function = c->ts.interface->attr.function; |
+ c->attr.if_source = IFSRC_UNKNOWN; |
+ } |
+ |
+ if (gfc_match (" =>") == MATCH_YES) |
+ { |
+ m = gfc_match_null (&initializer); |
+ if (m == MATCH_NO) |
+ { |
+ gfc_error ("Pointer initialization requires a NULL() at %C"); |
+ m = MATCH_ERROR; |
+ } |
+ if (gfc_pure (NULL)) |
+ { |
+ gfc_error ("Initialization of pointer at %C is not allowed in " |
+ "a PURE procedure"); |
+ m = MATCH_ERROR; |
+ } |
+ 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 |
@@ -4335,9 +4630,8 @@ gfc_match_procedure (void) |
m = match_procedure_in_interface (); |
break; |
case COMP_DERIVED: |
- gfc_error ("Fortran 2003: Procedure components at %C are not yet" |
- " implemented in gfortran"); |
- return MATCH_ERROR; |
+ m = match_ppc_decl (); |
+ break; |
case COMP_DERIVED_CONTAINS: |
m = match_procedure_in_type (); |
break; |
@@ -4407,6 +4701,10 @@ gfc_match_function_decl (void) |
} |
if (get_proc_name (name, &sym, false)) |
return MATCH_ERROR; |
+ |
+ if (add_hidden_procptr_result (sym) == SUCCESS) |
+ sym = sym->result; |
+ |
gfc_new_block = sym; |
m = gfc_match_formal_arglist (sym, 0, 0); |
@@ -4469,14 +4767,6 @@ gfc_match_function_decl (void) |
|| copy_prefix (&sym->attr, &sym->declared_at) == FAILURE) |
goto cleanup; |
- if (current_ts.type != BT_UNKNOWN && sym->ts.type != BT_UNKNOWN |
- && !sym->attr.implicit_type) |
- { |
- gfc_error ("Function '%s' at %C already has a type of %s", name, |
- gfc_basic_typename (sym->ts.type)); |
- goto cleanup; |
- } |
- |
/* Delay matching the function characteristics until after the |
specification block by signalling kind=-1. */ |
sym->declared_at = old_loc; |
@@ -4487,12 +4777,17 @@ gfc_match_function_decl (void) |
if (result == NULL) |
{ |
- sym->ts = current_ts; |
+ if (current_ts.type != BT_UNKNOWN |
+ && gfc_add_type (sym, ¤t_ts, &gfc_current_locus) == FAILURE) |
+ goto cleanup; |
sym->result = sym; |
} |
else |
{ |
- result->ts = current_ts; |
+ if (current_ts.type != BT_UNKNOWN |
+ && gfc_add_type (result, ¤t_ts, &gfc_current_locus) |
+ == FAILURE) |
+ goto cleanup; |
sym->result = result; |
} |
@@ -4516,7 +4811,7 @@ static bool |
add_global_entry (const char *name, int sub) |
{ |
gfc_gsymbol *s; |
- unsigned int type; |
+ enum gfc_symbol_type type; |
s = gfc_get_gsymbol(name); |
type = sub ? GSYM_SUBROUTINE : GSYM_FUNCTION; |
@@ -4530,6 +4825,7 @@ add_global_entry (const char *name, int sub) |
s->type = type; |
s->where = gfc_current_locus; |
s->defined = 1; |
+ s->ns = gfc_current_ns; |
return true; |
} |
return false; |
@@ -4803,6 +5099,14 @@ gfc_match_subroutine (void) |
if (get_proc_name (name, &sym, false)) |
return MATCH_ERROR; |
+ |
+ /* Set declared_at as it might point to, e.g., a PUBLIC statement, if |
+ the symbol existed before. */ |
+ sym->declared_at = gfc_current_locus; |
+ |
+ if (add_hidden_procptr_result (sym) == SUCCESS) |
+ sym = sym->result; |
+ |
gfc_new_block = sym; |
/* Check what next non-whitespace character is so we can tell if there |
@@ -5054,7 +5358,7 @@ set_enum_kind(void) |
if (max_enum == NULL || enum_history == NULL) |
return; |
- if (!gfc_option.fshort_enums) |
+ if (!flag_short_enums) |
return; |
i = 0; |
@@ -5076,8 +5380,8 @@ set_enum_kind(void) |
/* Match any of the various end-block statements. Returns the type of |
- END to the caller. The END INTERFACE, END IF, END DO and END |
- SELECT statements cannot be replaced by a single END statement. */ |
+ 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) |
@@ -5098,6 +5402,9 @@ gfc_match_end (gfc_statement *st) |
block_name = gfc_current_block () == NULL |
? NULL : gfc_current_block ()->name; |
+ if (state == COMP_BLOCK && !strcmp (block_name, "block@")) |
+ block_name = NULL; |
+ |
if (state == COMP_CONTAINS || state == COMP_DERIVED_CONTAINS) |
{ |
state = gfc_state_stack->previous->state; |
@@ -5151,6 +5458,12 @@ gfc_match_end (gfc_statement *st) |
eos_ok = 0; |
break; |
+ case COMP_BLOCK: |
+ *st = ST_END_BLOCK; |
+ target = " block"; |
+ eos_ok = 0; |
+ break; |
+ |
case COMP_IF: |
*st = ST_ENDIF; |
target = " if"; |
@@ -5164,6 +5477,7 @@ gfc_match_end (gfc_statement *st) |
break; |
case COMP_SELECT: |
+ case COMP_SELECT_TYPE: |
*st = ST_END_SELECT; |
target = " select"; |
eos_ok = 0; |
@@ -5220,10 +5534,10 @@ gfc_match_end (gfc_statement *st) |
{ |
if (*st != ST_ENDDO && *st != ST_ENDIF && *st != ST_END_SELECT |
- && *st != ST_END_FORALL && *st != ST_END_WHERE) |
+ && *st != ST_END_FORALL && *st != ST_END_WHERE && *st != ST_END_BLOCK) |
return MATCH_YES; |
- if (gfc_current_block () == NULL) |
+ if (!block_name) |
return MATCH_YES; |
gfc_error ("Expected block name of '%s' in %s statement at %C", |
@@ -5250,12 +5564,21 @@ gfc_match_end (gfc_statement *st) |
if (block_name == NULL) |
goto syntax; |
- if (strcmp (name, block_name) != 0) |
+ if (strcmp (name, block_name) != 0 && strcmp (block_name, "ppr@") != 0) |
{ |
gfc_error ("Expected label '%s' for %s statement at %C", block_name, |
gfc_ascii_statement (*st)); |
goto cleanup; |
} |
+ /* Procedure pointer as function result. */ |
+ else if (strcmp (block_name, "ppr@") == 0 |
+ && strcmp (name, gfc_current_block ()->ns->proc_name->name) != 0) |
+ { |
+ gfc_error ("Expected label '%s' for %s statement at %C", |
+ gfc_current_block ()->ns->proc_name->name, |
+ gfc_ascii_statement (*st)); |
+ goto cleanup; |
+ } |
if (gfc_match_eos () == MATCH_YES) |
return MATCH_YES; |
@@ -5289,7 +5612,7 @@ attr_decl1 (void) |
if (m != MATCH_YES) |
goto cleanup; |
- if (find_special (name, &sym)) |
+ if (find_special (name, &sym, false)) |
return MATCH_ERROR; |
var_locus = gfc_current_locus; |
@@ -5329,13 +5652,31 @@ attr_decl1 (void) |
} |
} |
- /* Update symbol table. DIMENSION attribute is set |
- in gfc_set_array_spec(). */ |
- if (current_attr.dimension == 0 |
- && gfc_copy_attr (&sym->attr, ¤t_attr, &var_locus) == FAILURE) |
+ /* 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) |
{ |
- m = MATCH_ERROR; |
- goto cleanup; |
+ gfc_component *comp; |
+ comp = gfc_find_component (sym->ts.u.derived, "$data", true, true); |
+ if (comp == NULL || gfc_copy_attr (&comp->attr, ¤t_attr, |
+ &var_locus) == FAILURE) |
+ { |
+ m = MATCH_ERROR; |
+ goto cleanup; |
+ } |
+ sym->attr.class_ok = (sym->attr.class_ok |
+ || current_attr.allocatable |
+ || current_attr.pointer); |
+ } |
+ else |
+ { |
+ if (current_attr.dimension == 0 |
+ && gfc_copy_attr (&sym->attr, ¤t_attr, &var_locus) == FAILURE) |
+ { |
+ m = MATCH_ERROR; |
+ goto cleanup; |
+ } |
} |
if (gfc_set_array_spec (sym, as, &var_locus) == FAILURE) |
@@ -5366,6 +5707,8 @@ attr_decl1 (void) |
goto cleanup; |
} |
+ add_hidden_procptr_result (sym); |
+ |
return MATCH_YES; |
cleanup: |
@@ -5575,6 +5918,13 @@ 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; |
@@ -5600,6 +5950,12 @@ gfc_match_intrinsic (void) |
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; |
@@ -6057,6 +6413,13 @@ 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, "Fortran 2003: VALUE statement at %C") |
== FAILURE) |
return MATCH_ERROR; |
@@ -6155,6 +6518,59 @@ syntax: |
} |
+match |
+gfc_match_asynchronous (void) |
+{ |
+ gfc_symbol *sym; |
+ match m; |
+ |
+ if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: ASYNCHRONOUS statement at %C") |
+ == FAILURE) |
+ return MATCH_ERROR; |
+ |
+ if (gfc_match (" ::") == MATCH_NO && gfc_match_space () == MATCH_NO) |
+ { |
+ return MATCH_ERROR; |
+ } |
+ |
+ if (gfc_match_eos () == MATCH_YES) |
+ goto syntax; |
+ |
+ for(;;) |
+ { |
+ /* ASYNCHRONOUS is special because it can be added to host-associated |
+ symbols locally. */ |
+ m = gfc_match_symbol (&sym, 1); |
+ switch (m) |
+ { |
+ case MATCH_YES: |
+ if (gfc_add_asynchronous (&sym->attr, sym->name, &gfc_current_locus) |
+ == FAILURE) |
+ return MATCH_ERROR; |
+ goto next_item; |
+ |
+ case MATCH_NO: |
+ break; |
+ |
+ case MATCH_ERROR: |
+ return MATCH_ERROR; |
+ } |
+ |
+ next_item: |
+ if (gfc_match_eos () == MATCH_YES) |
+ break; |
+ if (gfc_match_char (',') != MATCH_YES) |
+ goto syntax; |
+ } |
+ |
+ return MATCH_YES; |
+ |
+syntax: |
+ gfc_error ("Syntax error in ASYNCHRONOUS statement at %C"); |
+ return MATCH_ERROR; |
+} |
+ |
+ |
/* Match a module procedure statement. Note that we have to modify |
symbols in the parent's namespace because the current one was there |
to receive symbols that are in an interface's formal argument list. */ |
@@ -6180,7 +6596,10 @@ gfc_match_modproc (void) |
module_ns = gfc_current_ns->parent; |
for (; module_ns; module_ns = module_ns->parent) |
- if (module_ns->proc_name->attr.flavor == FL_MODULE) |
+ if (module_ns->proc_name->attr.flavor == FL_MODULE |
+ || module_ns->proc_name->attr.flavor == FL_PROGRAM |
+ || (module_ns->proc_name->attr.flavor == FL_PROCEDURE |
+ && !module_ns->proc_name->attr.contained)) |
break; |
if (module_ns == NULL) |
@@ -6192,6 +6611,7 @@ gfc_match_modproc (void) |
for (;;) |
{ |
+ locus old_locus = gfc_current_locus; |
bool last = false; |
m = gfc_match_name (name); |
@@ -6212,6 +6632,13 @@ gfc_match_modproc (void) |
if (gfc_get_symbol (name, module_ns, &sym)) |
return MATCH_ERROR; |
+ if (sym->attr.intrinsic) |
+ { |
+ gfc_error ("Intrinsic procedure at %L cannot be a MODULE " |
+ "PROCEDURE", &old_locus); |
+ return MATCH_ERROR; |
+ } |
+ |
if (sym->attr.proc != PROC_MODULE |
&& gfc_add_procedure (&sym->attr, PROC_MODULE, |
sym->name, NULL) == FAILURE) |
@@ -6221,6 +6648,7 @@ gfc_match_modproc (void) |
return MATCH_ERROR; |
sym->attr.mod_proc = 1; |
+ sym->declared_at = old_locus; |
if (last) |
break; |
@@ -6357,6 +6785,46 @@ gfc_get_type_attr_spec (symbol_attribute *attr, char *name) |
} |
+/* Assign a hash value for a derived type. The algorithm is that of |
+ SDBM. The hashed string is '[module_name #] derived_name'. */ |
+static unsigned int |
+hash_value (gfc_symbol *sym) |
+{ |
+ unsigned int hash = 0; |
+ const char *c; |
+ int i, len; |
+ |
+ /* Hash of the module or procedure name. */ |
+ if (sym->module != NULL) |
+ c = sym->module; |
+ else if (sym->ns && sym->ns->proc_name |
+ && sym->ns->proc_name->attr.flavor == FL_MODULE) |
+ c = sym->ns->proc_name->name; |
+ else |
+ c = NULL; |
+ |
+ if (c) |
+ { |
+ len = strlen (c); |
+ for (i = 0; i < len; i++, c++) |
+ hash = (hash << 6) + (hash << 16) - hash + (*c); |
+ |
+ /* Disambiguate between 'a' in 'aa' and 'aa' in 'a'. */ |
+ hash = (hash << 6) + (hash << 16) - hash + '#'; |
+ } |
+ |
+ /* Hash of the derived type name. */ |
+ len = strlen (sym->name); |
+ c = sym->name; |
+ for (i = 0; i < len; i++, c++) |
+ hash = (hash << 6) + (hash << 16) - hash + (*c); |
+ |
+ /* Return the hash but take the modulus for the sake of module read, |
+ even though this slightly increases the chance of collision. */ |
+ return (hash % 100000000); |
+} |
+ |
+ |
/* 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. */ |
@@ -6462,13 +6930,23 @@ gfc_match_derived_decl (void) |
/* Add the extended derived type as the first component. */ |
gfc_add_component (sym, parent, &p); |
- sym->attr.extension = attr.extension; |
extended->refs++; |
gfc_set_sym_referenced (extended); |
p->ts.type = BT_DERIVED; |
- p->ts.derived = extended; |
+ p->ts.u.derived = extended; |
p->initializer = gfc_default_initializer (&p->ts); |
+ |
+ /* Set extension level. */ |
+ if (extended->attr.extension == 255) |
+ { |
+ /* Since the extension field is 8 bit wide, we can only have |
+ up to 255 extension levels. */ |
+ gfc_error ("Maximum extension level reached with type '%s' at %L", |
+ extended->name, &extended->declared_at); |
+ return MATCH_ERROR; |
+ } |
+ sym->attr.extension = extended->attr.extension + 1; |
/* Provide the links between the extended type and its extension. */ |
if (!extended->f2k_derived) |
@@ -6477,6 +6955,10 @@ gfc_match_derived_decl (void) |
st->n.sym = sym; |
} |
+ if (!sym->hash_value) |
+ /* Set the hash for the compound name for this type. */ |
+ sym->hash_value = hash_value (sym); |
+ |
/* Take over the ABSTRACT attribute. */ |
sym->attr.abstract = attr.abstract; |
@@ -6487,22 +6969,14 @@ gfc_match_derived_decl (void) |
/* Cray Pointees can be declared as: |
- pointer (ipt, a (n,m,...,*)) |
- By default, this is treated as an AS_ASSUMED_SIZE array. We'll |
- cheat and set a constant bound of 1 for the last dimension, if this |
- is the case. Since there is no bounds-checking for Cray Pointees, |
- this will be okay. */ |
+ pointer (ipt, a (n,m,...,*)) */ |
-gfc_try |
+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->type = AS_EXPLICIT; |
- as->upper[as->rank - 1] = gfc_int_expr (1); |
- as->cp_was_assumed = true; |
- } |
+ as->cp_was_assumed = true; |
else if (as->type == AS_ASSUMED_SHAPE) |
{ |
gfc_error ("Cray Pointee at %C cannot be assumed shape array"); |
@@ -6533,6 +7007,51 @@ gfc_match_enum (void) |
} |
+/* 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_expr (); |
+ result->expr_type = EXPR_CONSTANT; |
+ result->ts.type = BT_INTEGER; |
+ result->ts.kind = gfc_c_int_kind; |
+ result->where = 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 |
@@ -6593,14 +7112,13 @@ enumerator_decl (void) |
previous enumerator (stored in last_initializer) is incremented |
by 1 and is used to initialize the current enumerator. */ |
if (initializer == NULL) |
- initializer = gfc_enum_initializer (last_initializer, old_locus); |
+ 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); |
+ gfc_error ("ENUMERATOR %L not initialized with integer expression", |
+ &var_locus); |
m = MATCH_ERROR; |
- gfc_free_enum_history (); |
goto cleanup; |
} |
@@ -6666,7 +7184,10 @@ gfc_match_enumerator_def (void) |
{ |
m = enumerator_decl (); |
if (m == MATCH_ERROR) |
- goto cleanup; |
+ { |
+ gfc_free_enum_history (); |
+ goto cleanup; |
+ } |
if (m == MATCH_NO) |
break; |
@@ -6694,10 +7215,11 @@ cleanup: |
/* Match binding attributes. */ |
static match |
-match_binding_attributes (gfc_typebound_proc* ba, bool generic) |
+match_binding_attributes (gfc_typebound_proc* ba, bool generic, bool ppc) |
{ |
bool found_passing = false; |
- match m; |
+ bool seen_ptr = false; |
+ match m = MATCH_YES; |
/* Intialize to defaults. Do so even before the MATCH_NO check so that in |
this case the defaults are in there. */ |
@@ -6706,13 +7228,13 @@ match_binding_attributes (gfc_typebound_proc* ba, bool generic) |
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. */ |
- if (gfc_match_char (',') == MATCH_NO) |
- { |
- ba->access = gfc_typebound_default_access; |
- return MATCH_NO; |
- } |
+ m = gfc_match_char (','); |
+ if (m == MATCH_NO) |
+ goto done; |
do |
{ |
@@ -6770,33 +7292,6 @@ match_binding_attributes (gfc_typebound_proc* ba, bool generic) |
continue; |
} |
- /* 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. */ |
- /* TODO: Handle really once implemented. */ |
- m = gfc_match (" deferred"); |
- if (m == MATCH_ERROR) |
- goto error; |
- if (m == MATCH_YES) |
- { |
- gfc_error ("DEFERRED not yet implemented at %C"); |
- goto error; |
- } |
- |
/* PASS possibly including argument. */ |
m = gfc_match (" pass"); |
if (m == MATCH_ERROR) |
@@ -6816,7 +7311,7 @@ match_binding_attributes (gfc_typebound_proc* ba, bool generic) |
if (m == MATCH_ERROR) |
goto error; |
if (m == MATCH_YES) |
- ba->pass_arg = xstrdup (arg); |
+ ba->pass_arg = gfc_get_string (arg); |
gcc_assert ((m == MATCH_YES) == (ba->pass_arg != NULL)); |
found_passing = true; |
@@ -6824,6 +7319,59 @@ match_binding_attributes (gfc_typebound_proc* ba, bool generic) |
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. */ |
@@ -6835,13 +7383,29 @@ match_binding_attributes (gfc_typebound_proc* ba, bool generic) |
} |
while (gfc_match_char (',') == MATCH_YES); |
+ /* NON_OVERRIDABLE and DEFERRED exclude themselves. */ |
+ if (ba->non_overridable && ba->deferred) |
+ { |
+ gfc_error ("NON_OVERRIDABLE and DEFERRED can't both appear at %C"); |
+ goto error; |
+ } |
+ |
+ m = MATCH_YES; |
+ |
+done: |
if (ba->access == ACCESS_UNKNOWN) |
ba->access = gfc_typebound_default_access; |
- return MATCH_YES; |
+ if (ppc && !seen_ptr) |
+ { |
+ gfc_error ("POINTER attribute is required for procedure pointer component" |
+ " at %C"); |
+ goto error; |
+ } |
+ |
+ return m; |
error: |
- gfc_free (ba->pass_arg); |
return MATCH_ERROR; |
} |
@@ -6853,7 +7417,7 @@ match_procedure_in_type (void) |
{ |
char name[GFC_MAX_SYMBOL_LEN + 1]; |
char target_buf[GFC_MAX_SYMBOL_LEN + 1]; |
- char* target; |
+ char* target = NULL; |
gfc_typebound_proc* tb; |
bool seen_colons; |
bool seen_attrs; |
@@ -6867,11 +7431,25 @@ match_procedure_in_type (void) |
block = gfc_state_stack->previous->sym; |
gcc_assert (block); |
- /* TODO: Really implement PROCEDURE(interface). */ |
+ /* Try to match PROCEDURE(interface). */ |
if (gfc_match (" (") == MATCH_YES) |
{ |
- gfc_error ("PROCEDURE(interface) at %C is not yet implemented"); |
- return MATCH_ERROR; |
+ 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; |
+ } |
+ |
+ target = target_buf; |
} |
/* Construct the data structure. */ |
@@ -6880,11 +7458,24 @@ match_procedure_in_type (void) |
tb->is_generic = 0; |
/* Match binding attributes. */ |
- m = match_binding_attributes (tb, false); |
+ m = match_binding_attributes (tb, false, false); |
if (m == MATCH_ERROR) |
return m; |
seen_attrs = (m == MATCH_YES); |
+ /* Check that attribute DEFERRED is given iff an interface is specified, which |
+ means target != NULL. */ |
+ if (tb->deferred && !target) |
+ { |
+ gfc_error ("Interface must be specified for DEFERRED binding at %C"); |
+ return MATCH_ERROR; |
+ } |
+ if (target && !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) |
@@ -6907,12 +7498,17 @@ match_procedure_in_type (void) |
} |
/* Try to match the '=> target', if it's there. */ |
- target = NULL; |
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" |
@@ -6949,11 +7545,19 @@ match_procedure_in_type (void) |
ns = block->f2k_derived; |
gcc_assert (ns); |
+ /* If the binding is DEFERRED, check that the containing type is ABSTRACT. */ |
+ if (tb->deferred && !block->attr.abstract) |
+ { |
+ gfc_error ("Type '%s' containing DEFERRED binding at %C is not ABSTRACT", |
+ block->name); |
+ return MATCH_ERROR; |
+ } |
+ |
/* See if we already have a binding with this name in the symtree which would |
be an error. If a GENERIC already targetted this binding, it may be |
already there but then typebound is still NULL. */ |
- stree = gfc_find_symtree (ns->sym_root, name); |
- if (stree && stree->typebound) |
+ stree = gfc_find_symtree (ns->tb_sym_root, name); |
+ if (stree && stree->n.tb) |
{ |
gfc_error ("There's already a procedure with binding name '%s' for the" |
" derived type '%s' at %C", name, block->name); |
@@ -6961,12 +7565,17 @@ match_procedure_in_type (void) |
} |
/* Insert it and set attributes. */ |
- if (gfc_get_sym_tree (name, ns, &stree)) |
- return MATCH_ERROR; |
- if (gfc_get_sym_tree (target, gfc_current_ns, &tb->u.specific)) |
+ |
+ if (!stree) |
+ { |
+ stree = gfc_new_symtree (&ns->tb_sym_root, name); |
+ gcc_assert (stree); |
+ } |
+ stree->n.tb = tb; |
+ |
+ if (gfc_get_sym_tree (target, gfc_current_ns, &tb->u.specific, false)) |
return MATCH_ERROR; |
gfc_set_sym_referenced (tb->u.specific->n.sym); |
- stree->typebound = tb; |
return MATCH_YES; |
} |
@@ -6978,11 +7587,13 @@ 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_symtree* st; |
gfc_namespace* ns; |
+ interface_type op_type; |
+ gfc_intrinsic_op op; |
match m; |
/* Check current state. */ |
@@ -6998,7 +7609,7 @@ gfc_match_generic (void) |
gcc_assert (block && ns); |
/* See if we get an access-specifier. */ |
- m = match_binding_attributes (&tbattr, true); |
+ m = match_binding_attributes (&tbattr, true, false); |
if (m == MATCH_ERROR) |
goto error; |
@@ -7009,47 +7620,126 @@ gfc_match_generic (void) |
goto error; |
} |
- /* The binding name and =>. */ |
- m = gfc_match (" %n =>", name); |
+ /* 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 at %C"); |
+ gfc_error ("Expected generic name or operator descriptor at %C"); |
goto error; |
} |
- /* If there's already something with this name, check that it is another |
- GENERIC and then extend that rather than build a new node. */ |
- st = gfc_find_symtree (ns->sym_root, name); |
- if (st) |
+ switch (op_type) |
{ |
- if (!st->typebound || !st->typebound->is_generic) |
+ case INTERFACE_GENERIC: |
+ snprintf (bind_name, sizeof (bind_name), "%s", name); |
+ break; |
+ |
+ case INTERFACE_USER_OP: |
+ snprintf (bind_name, sizeof (bind_name), "OPERATOR(.%s.)", name); |
+ break; |
+ |
+ case INTERFACE_INTRINSIC_OP: |
+ snprintf (bind_name, sizeof (bind_name), "OPERATOR(%s)", |
+ gfc_op2string (op)); |
+ break; |
+ |
+ default: |
+ gcc_unreachable (); |
+ } |
+ |
+ /* Match the required =>. */ |
+ if (gfc_match (" =>") != MATCH_YES) |
+ { |
+ gfc_error ("Expected '=>' at %C"); |
+ goto error; |
+ } |
+ |
+ /* Try to find existing GENERIC binding with this name / for this operator; |
+ if there is something, check that it is another GENERIC and then extend |
+ it rather than building a new node. Otherwise, create it and put it |
+ at the right position. */ |
+ |
+ switch (op_type) |
+ { |
+ case INTERFACE_USER_OP: |
+ case INTERFACE_GENERIC: |
+ { |
+ const bool is_op = (op_type == INTERFACE_USER_OP); |
+ gfc_symtree* st; |
+ |
+ st = gfc_find_symtree (is_op ? ns->tb_uop_root : ns->tb_sym_root, name); |
+ if (st) |
+ { |
+ tb = st->n.tb; |
+ gcc_assert (tb); |
+ } |
+ else |
+ tb = NULL; |
+ |
+ break; |
+ } |
+ |
+ case INTERFACE_INTRINSIC_OP: |
+ tb = ns->tb_op[op]; |
+ break; |
+ |
+ default: |
+ gcc_unreachable (); |
+ } |
+ |
+ if (tb) |
+ { |
+ if (!tb->is_generic) |
{ |
+ gcc_assert (op_type == INTERFACE_GENERIC); |
gfc_error ("There's already a non-generic procedure with binding name" |
" '%s' for the derived type '%s' at %C", |
- name, block->name); |
+ bind_name, block->name); |
goto error; |
} |
- tb = st->typebound; |
if (tb->access != tbattr.access) |
{ |
gfc_error ("Binding at %C must have the same access as already" |
- " defined binding '%s'", name); |
+ " defined binding '%s'", bind_name); |
goto error; |
} |
} |
else |
{ |
- if (gfc_get_sym_tree (name, ns, &st)) |
- return MATCH_ERROR; |
- |
- st->typebound = tb = gfc_get_typebound_proc (); |
+ tb = gfc_get_typebound_proc (); |
tb->where = gfc_current_locus; |
tb->access = tbattr.access; |
tb->is_generic = 1; |
tb->u.generic = NULL; |
+ |
+ switch (op_type) |
+ { |
+ case INTERFACE_GENERIC: |
+ case INTERFACE_USER_OP: |
+ { |
+ const bool is_op = (op_type == INTERFACE_USER_OP); |
+ gfc_symtree* st; |
+ |
+ st = gfc_new_symtree (is_op ? &ns->tb_uop_root : &ns->tb_sym_root, |
+ name); |
+ gcc_assert (st); |
+ st->n.tb = tb; |
+ |
+ break; |
+ } |
+ |
+ case INTERFACE_INTRINSIC_OP: |
+ ns->tb_op[op] = tb; |
+ break; |
+ |
+ default: |
+ gcc_unreachable (); |
+ } |
} |
/* Now, match all following names as specific targets. */ |
@@ -7067,20 +7757,17 @@ gfc_match_generic (void) |
goto error; |
} |
- if (gfc_get_sym_tree (name, ns, &target_st)) |
- goto error; |
+ target_st = gfc_get_tbp_symtree (&ns->tb_sym_root, name); |
/* See if this is a duplicate specification. */ |
for (target = tb->u.generic; target; target = target->next) |
if (target_st == target->specific_st) |
{ |
gfc_error ("'%s' already defined as specific binding for the" |
- " generic '%s' at %C", name, st->n.sym->name); |
+ " generic '%s' at %C", name, bind_name); |
goto error; |
} |
- gfc_set_sym_referenced (target_st->n.sym); |
- |
target = gfc_get_tbp_generic (); |
target->specific_st = target_st; |
target->specific = NULL; |
@@ -7115,8 +7802,18 @@ gfc_match_final_decl (void) |
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; |
@@ -7208,3 +7905,101 @@ gfc_match_final_decl (void) |
return MATCH_YES; |
} |
+ |
+ |
+const ext_attr_t ext_attr_list[] = { |
+ { "dllimport", EXT_ATTR_DLLIMPORT, "dllimport" }, |
+ { "dllexport", EXT_ATTR_DLLEXPORT, "dllexport" }, |
+ { "cdecl", EXT_ATTR_CDECL, "cdecl" }, |
+ { "stdcall", EXT_ATTR_STDCALL, "stdcall" }, |
+ { "fastcall", EXT_ATTR_FASTCALL, "fastcall" }, |
+ { NULL, EXT_ATTR_LAST, NULL } |
+}; |
+ |
+/* Match a !GCC$ ATTRIBUTES statement of the form: |
+ !GCC$ ATTRIBUTES attribute-list :: var-name [, var-name] ... |
+ When we come here, we have already matched the !GCC$ ATTRIBUTES string. |
+ |
+ TODO: We should support all GCC attributes using the same syntax for |
+ the attribute list, i.e. the list in C |
+ __attributes(( attribute-list )) |
+ matches then |
+ !GCC$ ATTRIBUTES attribute-list :: |
+ Cf. c-parser.c's c_parser_attributes; the data can then directly be |
+ saved into a TREE. |
+ |
+ As there is absolutely no risk of confusion, we should never return |
+ MATCH_NO. */ |
+match |
+gfc_match_gcc_attributes (void) |
+{ |
+ symbol_attribute attr; |
+ char name[GFC_MAX_SYMBOL_LEN + 1]; |
+ unsigned id; |
+ gfc_symbol *sym; |
+ match m; |
+ |
+ gfc_clear_attr (&attr); |
+ for(;;) |
+ { |
+ char ch; |
+ |
+ if (gfc_match_name (name) != MATCH_YES) |
+ return MATCH_ERROR; |
+ |
+ for (id = 0; id < EXT_ATTR_LAST; id++) |
+ if (strcmp (name, ext_attr_list[id].name) == 0) |
+ break; |
+ |
+ if (id == EXT_ATTR_LAST) |
+ { |
+ gfc_error ("Unknown attribute in !GCC$ ATTRIBUTES statement at %C"); |
+ return MATCH_ERROR; |
+ } |
+ |
+ if (gfc_add_ext_attribute (&attr, (ext_attr_id_t) id, &gfc_current_locus) |
+ == FAILURE) |
+ return MATCH_ERROR; |
+ |
+ gfc_gobble_whitespace (); |
+ ch = gfc_next_ascii_char (); |
+ if (ch == ':') |
+ { |
+ /* This is the successful exit condition for the loop. */ |
+ if (gfc_next_ascii_char () == ':') |
+ break; |
+ } |
+ |
+ if (ch == ',') |
+ continue; |
+ |
+ goto syntax; |
+ } |
+ |
+ if (gfc_match_eos () == MATCH_YES) |
+ goto syntax; |
+ |
+ for(;;) |
+ { |
+ m = gfc_match_name (name); |
+ if (m != MATCH_YES) |
+ return m; |
+ |
+ if (find_special (name, &sym, true)) |
+ return MATCH_ERROR; |
+ |
+ sym->attr.ext_attr |= attr.ext_attr; |
+ |
+ if (gfc_match_eos () == MATCH_YES) |
+ break; |
+ |
+ if (gfc_match_char (',') != MATCH_YES) |
+ goto syntax; |
+ } |
+ |
+ return MATCH_YES; |
+ |
+syntax: |
+ gfc_error ("Syntax error in !GCC$ ATTRIBUTES statement at %C"); |
+ return MATCH_ERROR; |
+} |