diff options
Diffstat (limited to 'gcc/fortran')
-rw-r--r-- | gcc/fortran/ChangeLog | 19 | ||||
-rw-r--r-- | gcc/fortran/decl.c | 180 | ||||
-rw-r--r-- | gcc/fortran/primary.c | 5 |
3 files changed, 135 insertions, 69 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index ea90d12b116..ef28e189c8d 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,22 @@ +2007-02-15 Steven G. Kargl <kargl@gcc.gnu.org> + + PR fortran/30799 + * primary.c (match_logical_constant): Return MATCH_ERROR on invalid + kind. + +2007-02-15 Tobias Schlueter <tobi@gcc.gnu.org> + + PR fortran/30478 + * decl.c (create_enum_history, gfc_free_enum_history): Formatting + fixes. + (add_init_expr_to_sym): Remove ENUM-specific code-path. + (variable_decl): Likewise. Formatting fix. + (match_attr_spec): Remove ENUM-specific codepath. + (gfc_match_enum): Fix typo in error message. + (enumerator_decl): New. + (gfc_match_enumerator_def): Strip down to code necessary for + ENUMs, use enumerator_decl. + 2007-02-13 Release Manager * GCC 4.1.2 released. diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c index e69ae3cbe28..df362014668 100644 --- a/gcc/fortran/decl.c +++ b/gcc/fortran/decl.c @@ -758,7 +758,7 @@ gfc_set_constant_character_len (int len, gfc_expr * expr) INIT points to its enumerator value. */ static void -create_enum_history(gfc_symbol *sym, gfc_expr *init) +create_enum_history (gfc_symbol *sym, gfc_expr *init) { enumerator_history *new_enum_history; gcc_assert (sym != NULL && init != NULL); @@ -789,7 +789,7 @@ create_enum_history(gfc_symbol *sym, gfc_expr *init) /* Function to free enum kind history. */ void -gfc_free_enum_history(void) +gfc_free_enum_history (void) { enumerator_history *current = enum_history; enumerator_history *next; @@ -805,7 +805,7 @@ gfc_free_enum_history(void) } -/* Function called by variable_decl() that adds an initialization +/* Function called by variabl_decl() that adds an initialization expression to a symbol. */ static try @@ -911,10 +911,6 @@ add_init_expr_to_sym (const char *name, gfc_expr ** initp, *initp = NULL; } - /* Maintain enumerator history. */ - if (gfc_current_state () == COMP_ENUM) - create_enum_history (sym, init); - return SUCCESS; } @@ -1073,14 +1069,6 @@ variable_decl (int elem) if (m == MATCH_NO) as = gfc_copy_array_spec (current_as); - else if (gfc_current_state () == COMP_ENUM) - { - gfc_error ("Enumerator cannot be array at %C"); - gfc_free_enum_history (); - m = MATCH_ERROR; - goto cleanup; - } - char_len = NULL; cl = NULL; @@ -1179,10 +1167,11 @@ variable_decl (int elem) goto cleanup; } - /* An interface body specifies all of the procedure's characteristics and these - shall be consistent with those specified in the procedure definition, except - that the interface may specify a procedure that is not pure if the procedure - is defined to be pure(12.3.2). */ + /* An interface body specifies all of the procedure's + characteristics and these shall be consistent with those + specified in the procedure definition, except that the interface + may specify a procedure that is not pure if the procedure is + defined to be pure(12.3.2). */ if (current_ts.type == BT_DERIVED && gfc_current_ns->proc_name->attr.if_source == IFSRC_IFBODY && current_ts.derived->ns != gfc_current_ns) @@ -1288,30 +1277,6 @@ variable_decl (int elem) } } - /* Check if we are parsing an enumeration and if the current enumerator - variable has an initializer or not. If it does 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 (gfc_current_state () == COMP_ENUM) - { - if (initializer == NULL) - initializer = gfc_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; - gfc_free_enum_history (); - goto cleanup; - } - - /* Store this current initializer, for the next enumerator - variable to be parsed. */ - last_initializer = initializer; - } - /* 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. */ @@ -2033,12 +1998,6 @@ match_attr_spec (void) if (d == DECL_NONE || d == DECL_COLON) break; - if (gfc_current_state () == COMP_ENUM) - { - gfc_error ("Enumerator cannot have attributes %C"); - return MATCH_ERROR; - } - seen[d]++; seen_at[d] = gfc_current_locus; @@ -2057,18 +2016,6 @@ match_attr_spec (void) } } - /* If we are parsing an enumeration and have ensured that no other - attributes are present we can now set the parameter attribute. */ - if (gfc_current_state () == COMP_ENUM) - { - t = gfc_add_flavor (¤t_attr, FL_PARAMETER, NULL, NULL); - if (t == FAILURE) - { - m = MATCH_ERROR; - goto cleanup; - } - } - /* No double colon, so assume that we've been looking at something else the whole time. */ if (d == DECL_NONE) @@ -4081,7 +4028,7 @@ gfc_match_enum (void) return m; if (gfc_notify_std (GFC_STD_F2003, - "New in Fortran 2003: ENUM AND ENUMERATOR at %C") + "New in Fortran 2003: ENUM and ENUMERATOR at %C") == FAILURE) return MATCH_ERROR; @@ -4089,19 +4036,116 @@ gfc_match_enum (void) } +/* 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; + try t; + locus old_locus; + + initializer = NULL; + old_locus = gfc_current_locus; + + /* When we get here, we've just matched a list of attributes and + maybe a type and a double colon. The next thing we expect to see + is the name of the symbol. */ + m = gfc_match_name (name); + if (m != MATCH_YES) + goto cleanup; + + var_locus = gfc_current_locus; + + /* OK, we've successfully matched the declaration. Now put the + symbol in the current namespace. If we fail to create the symbol, + bail out. */ + if (build_sym (name, NULL, &as, &var_locus) == FAILURE) + { + m = MATCH_ERROR; + goto cleanup; + } + + /* The double colon must be present in order to have initializers. + Otherwise the statement is ambiguous with an assignment statement. */ + if (colon_seen) + { + if (gfc_match_char ('=') == MATCH_YES) + { + m = gfc_match_init_expr (&initializer); + if (m == MATCH_NO) + { + gfc_error ("Expected an initialization expression at %C"); + m = MATCH_ERROR; + } + + if (m != MATCH_YES) + goto cleanup; + } + } + + /* If we do not have an initializer, the initialization value of the + previous enumerator (stored in last_initializer) is incremented + by 1 and is used to initialize the current enumerator. */ + if (initializer == NULL) + initializer = gfc_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; + gfc_free_enum_history (); + goto cleanup; + } + + /* Store this current initializer, for the next enumerator variable + to be parsed. add_init_expr_to_sym() zeros initializer, so we + use last_initializer below. */ + last_initializer = initializer; + t = add_init_expr_to_sym (name, &initializer, &var_locus); + + /* Maintain enumerator history. */ + gfc_find_symbol (name, NULL, 0, &sym); + create_enum_history (sym, last_initializer); + + return (t == SUCCESS) ? MATCH_YES : MATCH_ERROR; + +cleanup: + /* Free stuff up and return. */ + gfc_free_expr (initializer); + + return m; +} + + /* Match the enumerator definition statement. */ match gfc_match_enumerator_def (void) { match m; - int elem; + try 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) { @@ -4113,17 +4157,17 @@ gfc_match_enumerator_def (void) (¤t_ts)->type = BT_INTEGER; (¤t_ts)->kind = gfc_c_int_kind; - m = match_attr_spec (); - if (m == MATCH_ERROR) + gfc_clear_attr (¤t_attr); + t = gfc_add_flavor (¤t_attr, FL_PARAMETER, NULL, NULL); + if (t == FAILURE) { - m = MATCH_NO; + m = MATCH_ERROR; goto cleanup; } - elem = 1; for (;;) { - m = variable_decl (elem++); + m = enumerator_decl (); if (m == MATCH_ERROR) goto cleanup; if (m == MATCH_NO) diff --git a/gcc/fortran/primary.c b/gcc/fortran/primary.c index 182cb4c47e8..e5bdd79c74e 100644 --- a/gcc/fortran/primary.c +++ b/gcc/fortran/primary.c @@ -1039,7 +1039,10 @@ match_logical_constant (gfc_expr ** result) kind = gfc_default_logical_kind; if (gfc_validate_kind (BT_LOGICAL, kind, true) < 0) - gfc_error ("Bad kind for logical constant at %C"); + { + gfc_error ("Bad kind for logical constant at %C"); + return MATCH_ERROR; + } e = gfc_get_expr (); |