aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/decl.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fortran/decl.c')
-rw-r--r--gcc/fortran/decl.c568
1 files changed, 535 insertions, 33 deletions
diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c
index 80ec39c..0b8787a 100644
--- a/gcc/fortran/decl.c
+++ b/gcc/fortran/decl.c
@@ -391,13 +391,13 @@ match_data_constant (gfc_expr **result)
if (sym == NULL
|| (sym->attr.flavor != FL_PARAMETER
- && (!dt_sym || dt_sym->attr.flavor != FL_DERIVED)))
+ && (!dt_sym || !gfc_fl_struct (dt_sym->attr.flavor))))
{
gfc_error ("Symbol %qs must be a PARAMETER in DATA statement at %C",
name);
return MATCH_ERROR;
}
- else if (dt_sym && dt_sym->attr.flavor == FL_DERIVED)
+ 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. */
@@ -606,6 +606,161 @@ cleanup:
/************************ 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;
+ locus where;
+ mpz_t repeat, size;
+ bool scalar;
+ int cmp;
+
+ gcc_assert (ts);
+
+ mpz_init_set_ui (repeat, 0);
+ mpz_init (size);
+ scalar = !as || !as->rank;
+
+ /* 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");
+ goto cleanup;
+ }
+
+ where = gfc_current_locus;
+ 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)
+ 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;
+ }
+
+ /* 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;
+
+ expr->rank = as->rank;
+ expr->shape = gfc_get_shape (expr->rank);
+
+ /* Validate sizes. */
+ gcc_assert (gfc_array_size (expr, &size));
+ gcc_assert (spec_size (as, &repeat));
+ cmp = mpz_cmp (size, repeat);
+ 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");
+ if (cmp)
+ goto cleanup;
+ }
+
+ /* 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;
+ mpz_clear (size);
+ mpz_clear (repeat);
+ return MATCH_YES;
+
+syntax:
+ 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);
+ mpz_clear (size);
+ mpz_clear (repeat);
+ return MATCH_ERROR;
+}
+
+
/* Auxiliary function to merge DIMENSION and CODIMENSION array specs. */
static bool
@@ -1239,7 +1394,8 @@ build_sym (const char *name, gfc_charlen *cl, bool cl_deferred,
st = gfc_find_symtree (gfc_current_ns->sym_root, u_name);
- if (st != 0)
+ /* 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);
@@ -1469,7 +1625,7 @@ 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 derived type variables and procedure pointers. */
- if (sym->ts.type != BT_DERIVED && init->ts.type != BT_DERIVED
+ 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))
@@ -1608,7 +1764,7 @@ add_init_expr_to_sym (const char *name, gfc_expr **initp, locus *var_locus)
If we mark my_int as iso_c (since we can see it's value
is equal to one of the named constants), then my_int_2
will be considered C interoperable. */
- if (sym->ts.type != BT_CHARACTER && sym->ts.type != BT_DERIVED)
+ 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;
@@ -1666,6 +1822,7 @@ static bool
build_struct (const char *name, gfc_charlen *cl, gfc_expr **init,
gfc_array_spec **as)
{
+ gfc_state_data *s;
gfc_component *c;
bool t = true;
@@ -1689,6 +1846,35 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init,
}
}
+ /* 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 '%s' 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;
@@ -1868,7 +2054,7 @@ match_pointer_init (gfc_expr **init, int procptr)
{
match m;
- if (gfc_pure (NULL) && gfc_state_stack->state != COMP_DERIVED)
+ 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");
@@ -2062,7 +2248,7 @@ variable_decl (int elem)
/* 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_current_state () != COMP_DERIVED)
+ if (flag_cray_pointer && !gfc_comp_struct (gfc_current_state ()))
{
gfc_find_symbol (name, gfc_current_ns, 1, &sym);
if (sym != NULL && sym->attr.cray_pointee)
@@ -2127,7 +2313,7 @@ variable_decl (int elem)
For components of derived types, it is not true, so we don't
create a symbol for those yet. If we fail to create the symbol,
bail out. */
- if (gfc_current_state () != COMP_DERIVED
+ if (!gfc_comp_struct (gfc_current_state ())
&& !build_sym (name, cl, cl_deferred, &as, &var_locus))
{
m = MATCH_ERROR;
@@ -2154,6 +2340,9 @@ variable_decl (int elem)
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 "
@@ -2162,7 +2351,23 @@ variable_decl (int elem)
goto cleanup;
}
- return match_old_style_init (name);
+ /* 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, &current_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.
@@ -2200,7 +2405,7 @@ variable_decl (int elem)
}
if (current_attr.flavor != FL_PARAMETER && gfc_pure (NULL)
- && gfc_state_stack->state != COMP_DERIVED)
+ && !gfc_comp_struct (gfc_state_stack->state))
{
gfc_error ("Initialization of variable at %C is not allowed in "
"a PURE procedure");
@@ -2208,7 +2413,7 @@ variable_decl (int elem)
}
if (current_attr.flavor != FL_PARAMETER
- && gfc_state_stack->state != COMP_DERIVED)
+ && !gfc_comp_struct (gfc_state_stack->state))
gfc_unset_implicit_pure (gfc_current_ns->proc_name);
if (m != MATCH_YES)
@@ -2217,7 +2422,7 @@ variable_decl (int elem)
}
if (initializer != NULL && current_attr.allocatable
- && gfc_current_state () == COMP_DERIVED)
+ && gfc_comp_struct (gfc_current_state ()))
{
gfc_error ("Initialization of allocatable component at %C is not "
"allowed");
@@ -2228,7 +2433,7 @@ variable_decl (int elem)
/* Add the initializer. Note that it is fine if initializer is
NULL here, because we sometimes also need to check if a
declaration *must* have an initialization expression. */
- if (gfc_current_state () != COMP_DERIVED)
+ if (!gfc_comp_struct (gfc_current_state ()))
t = add_init_expr_to_sym (name, &initializer, &var_locus);
else
{
@@ -2236,6 +2441,12 @@ variable_decl (int elem)
&& !current_attr.pointer && !initializer)
initializer = gfc_default_initializer (&current_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;
@@ -2724,6 +2935,36 @@ done:
}
+/* Matches a RECORD declaration. */
+
+static match
+match_record_decl (const char *name)
+{
+ locus old_loc;
+ old_loc = gfc_current_locus;
+
+ if (gfc_match (" record") == MATCH_YES)
+ {
+ if (!gfc_option.flag_dec_structure)
+ {
+ gfc_current_locus = old_loc;
+ gfc_error ("RECORD at %C is an extension, enable it with "
+ "-fdec-structure");
+ return MATCH_ERROR;
+ }
+ if (gfc_match (" /%n/", name) != MATCH_YES)
+ {
+ gfc_error ("Structure name expected after RECORD at %C");
+ gfc_current_locus = old_loc;
+ return MATCH_ERROR;
+ }
+ return MATCH_YES;
+ }
+
+ gfc_current_locus = old_loc;
+ 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.
@@ -2781,7 +3022,7 @@ gfc_match_decl_type_spec (gfc_typespec *ts, int implicit_flag)
{
if ((m = gfc_match ("*)")) != MATCH_YES)
return m;
- if (gfc_current_state () == COMP_DERIVED)
+ if (gfc_comp_struct (gfc_current_state ()))
{
gfc_error ("Assumed type at %C is not allowed for components");
return MATCH_ERROR;
@@ -2892,10 +3133,51 @@ gfc_match_decl_type_spec (gfc_typespec *ts, int implicit_flag)
if (matched_type)
m = gfc_match_char (')');
- if (m == MATCH_YES)
- ts->type = BT_DERIVED;
+ 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 '%s' at %C is ambiguous", name);
+ return MATCH_ERROR;
+ }
+ 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. */
+ m = gfc_match (" structure");
+ if (m == MATCH_ERROR)
+ return MATCH_ERROR;
+ else if (m == MATCH_YES)
+ {
+ if ( gfc_current_state () != COMP_STRUCTURE
+ && gfc_current_state () != COMP_MAP)
+ return MATCH_ERROR;
+
+ 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;
+ }
+ return MATCH_ERROR;
+ }
+
/* Match CLASS declarations. */
m = gfc_match (" class ( * )");
if (m == MATCH_ERROR)
@@ -2964,9 +3246,7 @@ gfc_match_decl_type_spec (gfc_typespec *ts, int implicit_flag)
stored in a symtree with the first letter of the name capitalized; the
symtree with the all lower-case name contains the associated
generic function. */
- dt_name = gfc_get_string ("%c%s",
- (char) TOUPPER ((unsigned char) name[0]),
- (const char*)&name[1]);
+ dt_name = gfc_dt_upper_string (name);
sym = NULL;
dt_sym = NULL;
if (ts->kind != -1)
@@ -2998,7 +3278,7 @@ gfc_match_decl_type_spec (gfc_typespec *ts, int implicit_flag)
return MATCH_NO;
}
- if ((sym->attr.flavor != FL_UNKNOWN
+ if ((sym->attr.flavor != FL_UNKNOWN && sym->attr.flavor != FL_STRUCT
&& !(sym->attr.flavor == FL_PROCEDURE && sym->attr.generic))
|| sym->attr.subroutine)
{
@@ -3038,7 +3318,7 @@ gfc_match_decl_type_spec (gfc_typespec *ts, int implicit_flag)
gfc_set_sym_referenced (dt_sym);
- if (dt_sym->attr.flavor != FL_DERIVED
+ 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;
@@ -3480,9 +3760,7 @@ gfc_match_import (void)
letter of the name capitalized; the symtree with the all
lower-case name contains the associated generic function. */
st = gfc_new_symtree (&gfc_current_ns->sym_root,
- gfc_get_string ("%c%s",
- (char) TOUPPER ((unsigned char) name[0]),
- &name[1]));
+ gfc_dt_upper_string (name));
st->n.sym = sym;
sym->refs++;
sym->attr.imported = 1;
@@ -4497,7 +4775,7 @@ gfc_match_data_decl (void)
return m;
if ((current_ts.type == BT_DERIVED || current_ts.type == BT_CLASS)
- && gfc_current_state () != COMP_DERIVED)
+ && !gfc_comp_struct (gfc_current_state ()))
{
sym = gfc_use_derived (current_ts.u.derived);
@@ -4526,17 +4804,19 @@ gfc_match_data_decl (void)
&& !current_ts.u.derived->attr.zero_comp)
{
- if (current_attr.pointer && gfc_current_state () == COMP_DERIVED)
+ if (current_attr.pointer && gfc_comp_struct (gfc_current_state ()))
goto ok;
gfc_find_symbol (current_ts.u.derived->name,
current_ts.u.derived->ns, 1, &sym);
/* Any symbol that we find had better be a type definition
- which has its components defined. */
- if (sym != NULL && sym->attr.flavor == FL_DERIVED
+ 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->attr.zero_comp
+ || current_ts.u.derived == gfc_new_block))
goto ok;
gfc_error ("Derived type at %C has not been previously defined "
@@ -5791,6 +6071,10 @@ gfc_match_entry (void)
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");
@@ -6450,6 +6734,24 @@ gfc_match_end (gfc_statement *st)
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;
@@ -8020,6 +8322,208 @@ gfc_get_type_attr_spec (symbol_attribute *attr, char *name)
}
+/* 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 '%s' 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. */
+ int gfc_structure_id = 0;
+ char name[GFC_MAX_SYMBOL_LEN + 1];
+ gfc_symbol *sym;
+ match m;
+ locus where;
+
+ if(!gfc_option.flag_dec_structure)
+ {
+ gfc_error ("STRUCTURE at %C is a DEC extension, enable with "
+ "-fdec-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 '%s' 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). */
+
+ sprintf (name, gfc_dt_upper_string (name));
+ if (!get_struct_decl (name, FL_STRUCT, &where, &sym))
+ return MATCH_ERROR;
+
+ gfc_new_block = sym;
+ return MATCH_YES;
+}
+
/* Match the beginning of a derived type declaration. If a type name
was the result of a function, then it is possible to have a symbol
already to be known as a derived type yet have no components. */
@@ -8037,7 +8541,7 @@ gfc_match_derived_decl (void)
bool seen_attr = false;
gfc_interface *intr = NULL, *head;
- if (gfc_current_state () == COMP_DERIVED)
+ if (gfc_comp_struct (gfc_current_state ()))
return MATCH_NO;
name[0] = '\0';
@@ -8111,9 +8615,7 @@ gfc_match_derived_decl (void)
if (!sym)
{
/* Use upper case to save the actual derived-type symbol. */
- gfc_get_symbol (gfc_get_string ("%c%s",
- (char) TOUPPER ((unsigned char) gensym->name[0]),
- &gensym->name[1]), NULL, &sym);
+ gfc_get_symbol (gfc_dt_upper_string (gensym->name), NULL, &sym);
sym->name = gfc_get_string (gensym->name);
head = gensym->generic;
intr = gfc_get_interface ();