| Index: gcc/gcc/fortran/parse.c
|
| diff --git a/gcc/gcc/fortran/parse.c b/gcc/gcc/fortran/parse.c
|
| index 64272e2a51eec6da41af4dd437202d8f130d8ee4..63814dadc80278cc02d77435375b1ba6c7a53d28 100644
|
| --- a/gcc/gcc/fortran/parse.c
|
| +++ b/gcc/gcc/fortran/parse.c
|
| @@ -1,5 +1,6 @@
|
| /* Main parser.
|
| - Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
| + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
|
| + 2009, 2010
|
| Free Software Foundation, Inc.
|
| Contributed by Andy Vaught
|
|
|
| @@ -110,7 +111,7 @@ decode_specification_statement (void)
|
| match ("import", gfc_match_import, ST_IMPORT);
|
| match ("use", gfc_match_use, ST_USE);
|
|
|
| - if (gfc_current_block ()->ts.type != BT_DERIVED)
|
| + if (gfc_current_block ()->result->ts.type != BT_DERIVED)
|
| goto end_of_block;
|
|
|
| match (NULL, gfc_match_st_function, ST_STATEMENT_FUNCTION);
|
| @@ -128,6 +129,8 @@ decode_specification_statement (void)
|
| case 'a':
|
| match ("abstract% interface", gfc_match_abstract_interface,
|
| ST_INTERFACE);
|
| + match ("allocatable", gfc_match_asynchronous, ST_ATTR_DECL);
|
| + match ("asynchronous", gfc_match_asynchronous, ST_ATTR_DECL);
|
| break;
|
|
|
| case 'b':
|
| @@ -288,7 +291,7 @@ decode_statement (void)
|
| gfc_undo_symbols ();
|
| gfc_current_locus = old_locus;
|
|
|
| - /* Check for the IF, DO, SELECT, WHERE and FORALL statements, which
|
| + /* Check for the IF, DO, SELECT, WHERE, FORALL and BLOCK statements, which
|
| might begin with a block label. The match functions for these
|
| statements are unusual in that their keyword is not seen before
|
| the matcher is called. */
|
| @@ -308,8 +311,10 @@ decode_statement (void)
|
| gfc_undo_symbols ();
|
| gfc_current_locus = old_locus;
|
|
|
| + match (NULL, gfc_match_block, ST_BLOCK);
|
| match (NULL, gfc_match_do, ST_DO);
|
| match (NULL, gfc_match_select, ST_SELECT_CASE);
|
| + match (NULL, gfc_match_select_type, ST_SELECT_TYPE);
|
|
|
| /* General statement matching: Instead of testing every possible
|
| statement, we eliminate most possibilities by peeking at the
|
| @@ -325,6 +330,7 @@ decode_statement (void)
|
| match ("allocate", gfc_match_allocate, ST_ALLOCATE);
|
| match ("allocatable", gfc_match_allocatable, ST_ATTR_DECL);
|
| match ("assign", gfc_match_assign, ST_LABEL_ASSIGNMENT);
|
| + match ("asynchronous", gfc_match_asynchronous, ST_ATTR_DECL);
|
| break;
|
|
|
| case 'b':
|
| @@ -341,6 +347,7 @@ decode_statement (void)
|
| match ("case", gfc_match_case, ST_CASE);
|
| match ("common", gfc_match_common, ST_COMMON);
|
| match ("contains", gfc_match_eos, ST_CONTAINS);
|
| + match ("class", gfc_match_class_is, ST_CLASS_IS);
|
| break;
|
|
|
| case 'd':
|
| @@ -430,6 +437,7 @@ decode_statement (void)
|
| case 't':
|
| match ("target", gfc_match_target, ST_ATTR_DECL);
|
| match ("type", gfc_match_derived_decl, ST_DERIVED_DECL);
|
| + match ("type is", gfc_match_type_is, ST_TYPE_IS);
|
| break;
|
|
|
| case 'u':
|
| @@ -565,6 +573,34 @@ decode_omp_directive (void)
|
| return ST_NONE;
|
| }
|
|
|
| +static gfc_statement
|
| +decode_gcc_attribute (void)
|
| +{
|
| + locus old_locus;
|
| +
|
| +#ifdef GFC_DEBUG
|
| + gfc_symbol_state ();
|
| +#endif
|
| +
|
| + gfc_clear_error (); /* Clear any pending errors. */
|
| + gfc_clear_warning (); /* Clear any pending warnings. */
|
| + old_locus = gfc_current_locus;
|
| +
|
| + match ("attributes", gfc_match_gcc_attributes, ST_ATTR_DECL);
|
| +
|
| + /* All else has failed, so give up. See if any of the matchers has
|
| + stored an error message of some sort. */
|
| +
|
| + if (gfc_error_check () == 0)
|
| + gfc_error_now ("Unclassifiable GCC directive at %C");
|
| +
|
| + reject_statement ();
|
| +
|
| + gfc_error_recovery ();
|
| +
|
| + return ST_NONE;
|
| +}
|
| +
|
| #undef match
|
|
|
|
|
| @@ -626,7 +662,7 @@ next_free (void)
|
| if (gfc_match_eos () == MATCH_YES)
|
| {
|
| gfc_warning_now ("Ignoring statement label in empty statement "
|
| - "at %C");
|
| + "at %L", &label_locus);
|
| gfc_free_st_label (gfc_statement_label);
|
| gfc_statement_label = NULL;
|
| return ST_NONE;
|
| @@ -636,21 +672,39 @@ next_free (void)
|
| else if (c == '!')
|
| {
|
| /* Comments have already been skipped by the time we get here,
|
| - except for OpenMP directives. */
|
| - if (gfc_option.flag_openmp)
|
| + except for GCC attributes and OpenMP directives. */
|
| +
|
| + gfc_next_ascii_char (); /* Eat up the exclamation sign. */
|
| + c = gfc_peek_ascii_char ();
|
| +
|
| + if (c == 'g')
|
| + {
|
| + int i;
|
| +
|
| + c = gfc_next_ascii_char ();
|
| + for (i = 0; i < 4; i++, c = gfc_next_ascii_char ())
|
| + gcc_assert (c == "gcc$"[i]);
|
| +
|
| + gfc_gobble_whitespace ();
|
| + return decode_gcc_attribute ();
|
| +
|
| + }
|
| + else if (c == '$' && gfc_option.flag_openmp)
|
| {
|
| int i;
|
|
|
| c = gfc_next_ascii_char ();
|
| - for (i = 0; i < 5; i++, c = gfc_next_ascii_char ())
|
| - gcc_assert (c == "!$omp"[i]);
|
| + for (i = 0; i < 4; i++, c = gfc_next_ascii_char ())
|
| + gcc_assert (c == "$omp"[i]);
|
|
|
| gcc_assert (c == ' ' || c == '\t');
|
| gfc_gobble_whitespace ();
|
| return decode_omp_directive ();
|
| }
|
| - }
|
|
|
| + gcc_unreachable ();
|
| + }
|
| +
|
| if (at_bol && c == ';')
|
| {
|
| gfc_error_now ("Semicolon at %C needs to be preceded by statement");
|
| @@ -708,12 +762,22 @@ next_fixed (void)
|
| break;
|
|
|
| /* Comments have already been skipped by the time we get
|
| - here, except for OpenMP directives. */
|
| + here, except for GCC attributes and OpenMP directives. */
|
| +
|
| case '*':
|
| - if (gfc_option.flag_openmp)
|
| + c = gfc_next_char_literal (0);
|
| +
|
| + if (TOLOWER (c) == 'g')
|
| {
|
| - for (i = 0; i < 5; i++, c = gfc_next_char_literal (0))
|
| - gcc_assert ((char) gfc_wide_tolower (c) == "*$omp"[i]);
|
| + for (i = 0; i < 4; i++, c = gfc_next_char_literal (0))
|
| + gcc_assert (TOLOWER (c) == "gcc$"[i]);
|
| +
|
| + return decode_gcc_attribute ();
|
| + }
|
| + else if (c == '$' && gfc_option.flag_openmp)
|
| + {
|
| + for (i = 0; i < 4; i++, c = gfc_next_char_literal (0))
|
| + gcc_assert ((char) gfc_wide_tolower (c) == "$omp"[i]);
|
|
|
| if (c != ' ' && c != '0')
|
| {
|
| @@ -791,7 +855,10 @@ next_fixed (void)
|
|
|
| blank_line:
|
| if (digit_flag)
|
| - gfc_warning ("Ignoring statement label in empty statement at %C");
|
| + gfc_warning_now ("Ignoring statement label in empty statement at %L",
|
| + &label_locus);
|
| +
|
| + gfc_current_locus.lb->truncated = 0;
|
| gfc_advance_line ();
|
| return ST_NONE;
|
| }
|
| @@ -805,6 +872,7 @@ next_statement (void)
|
| {
|
| gfc_statement st;
|
| locus old_locus;
|
| +
|
| gfc_new_block = NULL;
|
|
|
| gfc_current_ns->old_cl_list = gfc_current_ns->cl_list;
|
| @@ -814,14 +882,7 @@ next_statement (void)
|
| gfc_buffer_error (1);
|
|
|
| if (gfc_at_eol ())
|
| - {
|
| - if ((gfc_option.warn_line_truncation || gfc_current_form == FORM_FREE)
|
| - && gfc_current_locus.lb
|
| - && gfc_current_locus.lb->truncated)
|
| - gfc_warning_now ("Line truncated at %C");
|
| -
|
| - gfc_advance_line ();
|
| - }
|
| + gfc_advance_line ();
|
|
|
| gfc_skip_comments ();
|
|
|
| @@ -879,8 +940,10 @@ next_statement (void)
|
|
|
| /* Statements that mark other executable statements. */
|
|
|
| -#define case_exec_markers case ST_DO: case ST_FORALL_BLOCK: case ST_IF_BLOCK: \
|
| - case ST_WHERE_BLOCK: case ST_SELECT_CASE: case ST_OMP_PARALLEL: \
|
| +#define case_exec_markers case ST_DO: case ST_FORALL_BLOCK: \
|
| + case ST_IF_BLOCK: case ST_BLOCK: \
|
| + case ST_WHERE_BLOCK: case ST_SELECT_CASE: case ST_SELECT_TYPE: \
|
| + case ST_OMP_PARALLEL: \
|
| case ST_OMP_PARALLEL_SECTIONS: case ST_OMP_SECTIONS: case ST_OMP_ORDERED: \
|
| case ST_OMP_CRITICAL: case ST_OMP_MASTER: case ST_OMP_SINGLE: \
|
| case ST_OMP_DO: case ST_OMP_PARALLEL_DO: case ST_OMP_ATOMIC: \
|
| @@ -898,7 +961,8 @@ next_statement (void)
|
| are detected in gfc_match_end(). */
|
|
|
| #define case_end case ST_END_BLOCK_DATA: case ST_END_FUNCTION: \
|
| - case ST_END_PROGRAM: case ST_END_SUBROUTINE
|
| + case ST_END_PROGRAM: case ST_END_SUBROUTINE: \
|
| + case ST_END_BLOCK
|
|
|
|
|
| /* Push a new state onto the stack. */
|
| @@ -1088,6 +1152,9 @@ gfc_ascii_statement (gfc_statement st)
|
| case ST_BACKSPACE:
|
| p = "BACKSPACE";
|
| break;
|
| + case ST_BLOCK:
|
| + p = "BLOCK";
|
| + break;
|
| case ST_BLOCK_DATA:
|
| p = "BLOCK DATA";
|
| break;
|
| @@ -1136,6 +1203,9 @@ gfc_ascii_statement (gfc_statement st)
|
| case ST_ELSEWHERE:
|
| p = "ELSEWHERE";
|
| break;
|
| + case ST_END_BLOCK:
|
| + p = "END BLOCK";
|
| + break;
|
| case ST_END_BLOCK_DATA:
|
| p = "END BLOCK DATA";
|
| break;
|
| @@ -1297,6 +1367,15 @@ gfc_ascii_statement (gfc_statement st)
|
| case ST_SELECT_CASE:
|
| p = "SELECT CASE";
|
| break;
|
| + case ST_SELECT_TYPE:
|
| + p = "SELECT TYPE";
|
| + break;
|
| + case ST_TYPE_IS:
|
| + p = "TYPE IS";
|
| + break;
|
| + case ST_CLASS_IS:
|
| + p = "CLASS IS";
|
| + break;
|
| case ST_SEQUENCE:
|
| p = "SEQUENCE";
|
| break;
|
| @@ -1464,16 +1543,23 @@ accept_statement (gfc_statement st)
|
|
|
| /* If the statement is the end of a block, lay down a special code
|
| that allows a branch to the end of the block from within the
|
| - construct. */
|
| + construct. IF and SELECT are treated differently from DO
|
| + (where EXEC_NOP is added inside the loop) for two
|
| + reasons:
|
| + 1. END DO has a meaning in the sense that after a GOTO to
|
| + it, the loop counter must be increased.
|
| + 2. IF blocks and SELECT blocks can consist of multiple
|
| + parallel blocks (IF ... ELSE IF ... ELSE ... END IF).
|
| + Putting the label before the END IF would make the jump
|
| + from, say, the ELSE IF block to the END IF illegal. */
|
|
|
| case ST_ENDIF:
|
| case ST_END_SELECT:
|
| if (gfc_statement_label != NULL)
|
| {
|
| - new_st.op = EXEC_NOP;
|
| + new_st.op = EXEC_END_BLOCK;
|
| add_statement ();
|
| }
|
| -
|
| break;
|
|
|
| /* The end-of-program unit statements do not get the special
|
| @@ -1488,6 +1574,11 @@ accept_statement (gfc_statement st)
|
| new_st.op = EXEC_RETURN;
|
| add_statement ();
|
| }
|
| + else
|
| + {
|
| + new_st.op = EXEC_END_PROCEDURE;
|
| + add_statement ();
|
| + }
|
|
|
| break;
|
|
|
| @@ -1572,13 +1663,20 @@ unexpected_statement (gfc_statement st)
|
|
|
| */
|
|
|
| +enum state_order
|
| +{
|
| + ORDER_START,
|
| + ORDER_USE,
|
| + ORDER_IMPORT,
|
| + ORDER_IMPLICIT_NONE,
|
| + ORDER_IMPLICIT,
|
| + ORDER_SPEC,
|
| + ORDER_EXEC
|
| +};
|
| +
|
| typedef struct
|
| {
|
| - enum
|
| - { ORDER_START, ORDER_USE, ORDER_IMPORT, ORDER_IMPLICIT_NONE,
|
| - ORDER_IMPLICIT, ORDER_SPEC, ORDER_EXEC
|
| - }
|
| - state;
|
| + enum state_order state;
|
| gfc_statement last_statement;
|
| locus where;
|
| }
|
| @@ -1845,7 +1943,6 @@ parse_derived (void)
|
| int compiling_type, seen_private, seen_sequence, seen_component, error_flag;
|
| gfc_statement st;
|
| gfc_state_data s;
|
| - gfc_symbol *derived_sym = NULL;
|
| gfc_symbol *sym;
|
| gfc_component *c;
|
|
|
| @@ -1870,15 +1967,11 @@ parse_derived (void)
|
| unexpected_eof ();
|
|
|
| case ST_DATA_DECL:
|
| + case ST_PROCEDURE:
|
| accept_statement (st);
|
| seen_component = 1;
|
| break;
|
|
|
| - case ST_PROCEDURE:
|
| - gfc_error ("PROCEDURE binding at %C must be inside CONTAINS");
|
| - error_flag = 1;
|
| - break;
|
| -
|
| case ST_FINAL:
|
| gfc_error ("FINAL declaration at %C must be inside CONTAINS");
|
| error_flag = 1;
|
| @@ -1970,25 +2063,33 @@ endType:
|
| /* need to verify that all fields of the derived type are
|
| * interoperable with C if the type is declared to be bind(c)
|
| */
|
| - derived_sym = gfc_current_block();
|
| -
|
| sym = gfc_current_block ();
|
| for (c = sym->components; c; c = c->next)
|
| {
|
| /* Look for allocatable components. */
|
| if (c->attr.allocatable
|
| - || (c->ts.type == BT_DERIVED && c->ts.derived->attr.alloc_comp))
|
| + || (c->ts.type == BT_CLASS
|
| + && c->ts.u.derived->components->attr.allocatable)
|
| + || (c->ts.type == BT_DERIVED && c->ts.u.derived->attr.alloc_comp))
|
| sym->attr.alloc_comp = 1;
|
|
|
| /* Look for pointer components. */
|
| if (c->attr.pointer
|
| - || (c->ts.type == BT_DERIVED && c->ts.derived->attr.pointer_comp))
|
| + || (c->ts.type == BT_CLASS
|
| + && c->ts.u.derived->components->attr.pointer)
|
| + || (c->ts.type == BT_DERIVED && c->ts.u.derived->attr.pointer_comp))
|
| sym->attr.pointer_comp = 1;
|
|
|
| + /* Look for procedure pointer components. */
|
| + if (c->attr.proc_pointer
|
| + || (c->ts.type == BT_DERIVED
|
| + && c->ts.u.derived->attr.proc_pointer_comp))
|
| + sym->attr.proc_pointer_comp = 1;
|
| +
|
| /* Look for private components. */
|
| if (sym->component_access == ACCESS_PRIVATE
|
| || c->attr.access == ACCESS_PRIVATE
|
| - || (c->ts.type == BT_DERIVED && c->ts.derived->attr.private_comp))
|
| + || (c->ts.type == BT_DERIVED && c->ts.u.derived->attr.private_comp))
|
| sym->attr.private_comp = 1;
|
| }
|
|
|
| @@ -2105,14 +2206,6 @@ loop:
|
| gfc_free_namespace (gfc_current_ns);
|
| goto loop;
|
| }
|
| - if (current_interface.type != INTERFACE_ABSTRACT &&
|
| - !gfc_new_block->attr.dummy &&
|
| - gfc_add_external (&gfc_new_block->attr, &gfc_current_locus) == FAILURE)
|
| - {
|
| - reject_statement ();
|
| - gfc_free_namespace (gfc_current_ns);
|
| - goto loop;
|
| - }
|
| break;
|
|
|
| case ST_PROCEDURE:
|
| @@ -2142,9 +2235,9 @@ loop:
|
| {
|
| if (current_state == COMP_NONE)
|
| {
|
| - if (new_state == COMP_FUNCTION)
|
| + if (new_state == COMP_FUNCTION && sym)
|
| gfc_add_function (&sym->attr, sym->name, NULL);
|
| - else if (new_state == COMP_SUBROUTINE)
|
| + else if (new_state == COMP_SUBROUTINE && sym)
|
| gfc_add_subroutine (&sym->attr, sym->name, NULL);
|
|
|
| current_state = new_state;
|
| @@ -2205,6 +2298,10 @@ decl:
|
| goto decl;
|
| }
|
|
|
| + /* Add EXTERNAL attribute to function or subroutine. */
|
| + if (current_interface.type != INTERFACE_ABSTRACT && !prog_unit->attr.dummy)
|
| + gfc_add_external (&prog_unit->attr, &gfc_current_locus);
|
| +
|
| current_interface = save;
|
| gfc_add_interface (prog_unit);
|
| pop_state ();
|
| @@ -2246,7 +2343,7 @@ match_deferred_characteristics (gfc_typespec * ts)
|
| {
|
| ts->kind = 0;
|
|
|
| - if (!ts->derived || !ts->derived->components)
|
| + if (!ts->u.derived)
|
| m = MATCH_ERROR;
|
| }
|
|
|
| @@ -2286,8 +2383,8 @@ check_function_result_typed (void)
|
|
|
| /* Check type-parameters, at the moment only CHARACTER lengths possible. */
|
| /* TODO: Extend when KIND type parameters are implemented. */
|
| - if (ts->type == BT_CHARACTER && ts->cl && ts->cl->length)
|
| - gfc_expr_check_typed (ts->cl->length, gfc_current_ns, true);
|
| + if (ts->type == BT_CHARACTER && ts->u.cl && ts->u.cl->length)
|
| + gfc_expr_check_typed (ts->u.cl->length, gfc_current_ns, true);
|
| }
|
|
|
|
|
| @@ -2320,6 +2417,27 @@ parse_spec (gfc_statement st)
|
| }
|
|
|
| loop:
|
| +
|
| + /* If we're inside a BLOCK construct, some statements are disallowed.
|
| + Check this here. Attribute declaration statements like INTENT, OPTIONAL
|
| + or VALUE are also disallowed, but they don't have a particular ST_*
|
| + key so we have to check for them individually in their matcher routine. */
|
| + if (gfc_current_state () == COMP_BLOCK)
|
| + switch (st)
|
| + {
|
| + case ST_IMPLICIT:
|
| + case ST_IMPLICIT_NONE:
|
| + case ST_NAMELIST:
|
| + case ST_COMMON:
|
| + case ST_EQUIVALENCE:
|
| + case ST_STATEMENT_FUNCTION:
|
| + gfc_error ("%s statement is not allowed inside of BLOCK at %C",
|
| + gfc_ascii_statement (st));
|
| + break;
|
| +
|
| + default:
|
| + break;
|
| + }
|
|
|
| /* If we find a statement that can not be followed by an IMPLICIT statement
|
| (and thus we can expect to see none any further), type the function result
|
| @@ -2466,7 +2584,7 @@ declSt:
|
|
|
| gfc_current_block ()->ts.kind = 0;
|
| /* Keep the derived type; if it's bad, it will be discovered later. */
|
| - if (!(ts->type == BT_DERIVED && ts->derived))
|
| + if (!(ts->type == BT_DERIVED && ts->u.derived))
|
| ts->type = BT_UNKNOWN;
|
| }
|
|
|
| @@ -2490,10 +2608,10 @@ parse_where_block (void)
|
| push_state (&s, COMP_WHERE, gfc_new_block);
|
|
|
| d = add_statement ();
|
| - d->expr = top->expr;
|
| + d->expr1 = top->expr1;
|
| d->op = EXEC_WHERE;
|
|
|
| - top->expr = NULL;
|
| + top->expr1 = NULL;
|
| top->block = d;
|
|
|
| seen_empty_else = 0;
|
| @@ -2523,12 +2641,12 @@ parse_where_block (void)
|
| break;
|
| }
|
|
|
| - if (new_st.expr == NULL)
|
| + if (new_st.expr1 == NULL)
|
| seen_empty_else = 1;
|
|
|
| d = new_level (gfc_state_stack->head);
|
| d->op = EXEC_WHERE;
|
| - d->expr = new_st.expr;
|
| + d->expr1 = new_st.expr1;
|
|
|
| accept_statement (st);
|
|
|
| @@ -2633,8 +2751,8 @@ parse_if_block (void)
|
| new_st.op = EXEC_IF;
|
| d = add_statement ();
|
|
|
| - d->expr = top->expr;
|
| - top->expr = NULL;
|
| + d->expr1 = top->expr1;
|
| + top->expr1 = NULL;
|
| top->block = d;
|
|
|
| do
|
| @@ -2658,7 +2776,7 @@ parse_if_block (void)
|
|
|
| d = new_level (gfc_state_stack->head);
|
| d->op = EXEC_IF;
|
| - d->expr = new_st.expr;
|
| + d->expr1 = new_st.expr1;
|
|
|
| accept_statement (st);
|
|
|
| @@ -2773,6 +2891,93 @@ parse_select_block (void)
|
| }
|
|
|
|
|
| +/* Pop the current selector from the SELECT TYPE stack. */
|
| +
|
| +static void
|
| +select_type_pop (void)
|
| +{
|
| + gfc_select_type_stack *old = select_type_stack;
|
| + select_type_stack = old->prev;
|
| + gfc_free (old);
|
| +}
|
| +
|
| +
|
| +/* Parse a SELECT TYPE construct (F03:R821). */
|
| +
|
| +static void
|
| +parse_select_type_block (void)
|
| +{
|
| + gfc_statement st;
|
| + gfc_code *cp;
|
| + gfc_state_data s;
|
| +
|
| + accept_statement (ST_SELECT_TYPE);
|
| +
|
| + cp = gfc_state_stack->tail;
|
| + push_state (&s, COMP_SELECT_TYPE, gfc_new_block);
|
| +
|
| + /* Make sure that the next statement is a TYPE IS, CLASS IS, CLASS DEFAULT
|
| + or END SELECT. */
|
| + for (;;)
|
| + {
|
| + st = next_statement ();
|
| + if (st == ST_NONE)
|
| + unexpected_eof ();
|
| + if (st == ST_END_SELECT)
|
| + /* Empty SELECT CASE is OK. */
|
| + goto done;
|
| + if (st == ST_TYPE_IS || st == ST_CLASS_IS)
|
| + break;
|
| +
|
| + gfc_error ("Expected TYPE IS, CLASS IS or END SELECT statement "
|
| + "following SELECT TYPE at %C");
|
| +
|
| + reject_statement ();
|
| + }
|
| +
|
| + /* At this point, we're got a nonempty select block. */
|
| + cp = new_level (cp);
|
| + *cp = new_st;
|
| +
|
| + accept_statement (st);
|
| +
|
| + do
|
| + {
|
| + st = parse_executable (ST_NONE);
|
| + switch (st)
|
| + {
|
| + case ST_NONE:
|
| + unexpected_eof ();
|
| +
|
| + case ST_TYPE_IS:
|
| + case ST_CLASS_IS:
|
| + cp = new_level (gfc_state_stack->head);
|
| + *cp = new_st;
|
| + gfc_clear_new_st ();
|
| +
|
| + accept_statement (st);
|
| + /* Fall through */
|
| +
|
| + case ST_END_SELECT:
|
| + break;
|
| +
|
| + /* Can't have an executable statement because of
|
| + parse_executable(). */
|
| + default:
|
| + unexpected_statement (st);
|
| + break;
|
| + }
|
| + }
|
| + while (st != ST_END_SELECT);
|
| +
|
| +done:
|
| + pop_state ();
|
| + accept_statement (st);
|
| + gfc_current_ns = gfc_current_ns->parent;
|
| + select_type_pop ();
|
| +}
|
| +
|
| +
|
| /* Given a symbol, make sure it is not an iteration variable for a DO
|
| statement. This subroutine is called when the symbol is seen in a
|
| context that causes it to become redefined. If the symbol is an
|
| @@ -2816,7 +3021,6 @@ check_do_closure (void)
|
|
|
| if (p->ext.end_do_label == gfc_statement_label)
|
| {
|
| -
|
| if (p == gfc_state_stack)
|
| return 1;
|
|
|
| @@ -2838,6 +3042,71 @@ check_do_closure (void)
|
| }
|
|
|
|
|
| +/* Parse a series of contained program units. */
|
| +
|
| +static void parse_progunit (gfc_statement);
|
| +
|
| +
|
| +/* Set up the local namespace for a BLOCK construct. */
|
| +
|
| +gfc_namespace*
|
| +gfc_build_block_ns (gfc_namespace *parent_ns)
|
| +{
|
| + gfc_namespace* my_ns;
|
| +
|
| + my_ns = gfc_get_namespace (parent_ns, 1);
|
| + my_ns->construct_entities = 1;
|
| +
|
| + /* Give the BLOCK a symbol of flavor LABEL; this is later needed for correct
|
| + code generation (so it must not be NULL).
|
| + We set its recursive argument if our container procedure is recursive, so
|
| + that local variables are accordingly placed on the stack when it
|
| + will be necessary. */
|
| + if (gfc_new_block)
|
| + my_ns->proc_name = gfc_new_block;
|
| + else
|
| + {
|
| + gfc_try t;
|
| +
|
| + gfc_get_symbol ("block@", my_ns, &my_ns->proc_name);
|
| + t = gfc_add_flavor (&my_ns->proc_name->attr, FL_LABEL,
|
| + my_ns->proc_name->name, NULL);
|
| + gcc_assert (t == SUCCESS);
|
| + }
|
| +
|
| + if (parent_ns->proc_name)
|
| + my_ns->proc_name->attr.recursive = parent_ns->proc_name->attr.recursive;
|
| +
|
| + return my_ns;
|
| +}
|
| +
|
| +
|
| +/* Parse a BLOCK construct. */
|
| +
|
| +static void
|
| +parse_block_construct (void)
|
| +{
|
| + gfc_namespace* my_ns;
|
| + gfc_state_data s;
|
| +
|
| + gfc_notify_std (GFC_STD_F2008, "Fortran 2008: BLOCK construct at %C");
|
| +
|
| + my_ns = gfc_build_block_ns (gfc_current_ns);
|
| +
|
| + new_st.op = EXEC_BLOCK;
|
| + new_st.ext.ns = my_ns;
|
| + accept_statement (ST_BLOCK);
|
| +
|
| + push_state (&s, COMP_BLOCK, my_ns->proc_name);
|
| + gfc_current_ns = my_ns;
|
| +
|
| + parse_progunit (ST_NONE);
|
| +
|
| + gfc_current_ns = gfc_current_ns->parent;
|
| + pop_state ();
|
| +}
|
| +
|
| +
|
| /* Parse a DO loop. Note that the ST_CYCLE and ST_EXIT statements are
|
| handled inside of parse_executable(), because they aren't really
|
| loop statements. */
|
| @@ -2850,7 +3119,7 @@ parse_do_block (void)
|
| gfc_state_data s;
|
| gfc_symtree *stree;
|
|
|
| - s.ext.end_do_label = new_st.label;
|
| + s.ext.end_do_label = new_st.label1;
|
|
|
| if (new_st.ext.iterator != NULL)
|
| stree = new_st.ext.iterator->var->symtree;
|
| @@ -2894,7 +3163,7 @@ loop:
|
| name, but in that case we must have seen ST_ENDDO first).
|
| We only complain about this in pedantic mode. */
|
| if (gfc_current_block () != NULL)
|
| - gfc_error_now ("named block DO at %L requires matching ENDDO name",
|
| + gfc_error_now ("Named block DO at %L requires matching ENDDO name",
|
| &gfc_current_block()->declared_at);
|
|
|
| break;
|
| @@ -3231,6 +3500,10 @@ parse_executable (gfc_statement st)
|
| return ST_IMPLIED_ENDDO;
|
| break;
|
|
|
| + case ST_BLOCK:
|
| + parse_block_construct ();
|
| + break;
|
| +
|
| case ST_IF_BLOCK:
|
| parse_if_block ();
|
| break;
|
| @@ -3239,6 +3512,10 @@ parse_executable (gfc_statement st)
|
| parse_select_block ();
|
| break;
|
|
|
| + case ST_SELECT_TYPE:
|
| + parse_select_type_block();
|
| + break;
|
| +
|
| case ST_DO:
|
| parse_do_block ();
|
| if (check_do_closure () == 1)
|
| @@ -3289,11 +3566,6 @@ parse_executable (gfc_statement st)
|
| }
|
|
|
|
|
| -/* Parse a series of contained program units. */
|
| -
|
| -static void parse_progunit (gfc_statement);
|
| -
|
| -
|
| /* Fix the symbols for sibling functions. These are incorrectly added to
|
| the child namespace as the parser didn't know about this procedure. */
|
|
|
| @@ -3307,7 +3579,7 @@ gfc_fixup_sibling_symbols (gfc_symbol *sym, gfc_namespace *siblings)
|
| sym->attr.referenced = 1;
|
| for (ns = siblings; ns; ns = ns->sibling)
|
| {
|
| - gfc_find_sym_tree (sym->name, ns, 0, &st);
|
| + st = gfc_find_symtree (ns->sym_root, sym->name);
|
|
|
| if (!st || (st->n.sym->attr.dummy && ns == st->n.sym->ns))
|
| goto fixup_contained;
|
| @@ -3322,6 +3594,7 @@ gfc_fixup_sibling_symbols (gfc_symbol *sym, gfc_namespace *siblings)
|
| || (old_sym->ts.type != BT_UNKNOWN
|
| && !old_sym->attr.implicit_type)
|
| || old_sym->attr.flavor == FL_PARAMETER
|
| + || old_sym->attr.use_assoc
|
| || old_sym->attr.in_common
|
| || old_sym->attr.in_equivalence
|
| || old_sym->attr.data
|
| @@ -3475,7 +3748,7 @@ parse_contained (int module)
|
| }
|
|
|
|
|
| -/* Parse a PROGRAM, SUBROUTINE or FUNCTION unit. */
|
| +/* Parse a PROGRAM, SUBROUTINE, FUNCTION unit or BLOCK construct. */
|
|
|
| static void
|
| parse_progunit (gfc_statement st)
|
| @@ -3490,7 +3763,10 @@ parse_progunit (gfc_statement st)
|
| unexpected_eof ();
|
|
|
| case ST_CONTAINS:
|
| - goto contains;
|
| + /* This is not allowed within BLOCK! */
|
| + if (gfc_current_state () != COMP_BLOCK)
|
| + goto contains;
|
| + break;
|
|
|
| case_end:
|
| accept_statement (st);
|
| @@ -3514,7 +3790,10 @@ loop:
|
| unexpected_eof ();
|
|
|
| case ST_CONTAINS:
|
| - goto contains;
|
| + /* This is not allowed within BLOCK! */
|
| + if (gfc_current_state () != COMP_BLOCK)
|
| + goto contains;
|
| + break;
|
|
|
| case_end:
|
| accept_statement (st);
|
| @@ -3687,6 +3966,8 @@ loop:
|
| st = next_statement ();
|
| goto loop;
|
| }
|
| +
|
| + s->ns = gfc_current_ns;
|
| }
|
|
|
|
|
| @@ -3708,6 +3989,7 @@ add_global_procedure (int sub)
|
| s->type = sub ? GSYM_SUBROUTINE : GSYM_FUNCTION;
|
| s->where = gfc_current_locus;
|
| s->defined = 1;
|
| + s->ns = gfc_current_ns;
|
| }
|
| }
|
|
|
| @@ -3730,7 +4012,78 @@ add_global_program (void)
|
| s->type = GSYM_PROGRAM;
|
| s->where = gfc_current_locus;
|
| s->defined = 1;
|
| + s->ns = gfc_current_ns;
|
| + }
|
| +}
|
| +
|
| +
|
| +/* Resolve all the program units when whole file scope option
|
| + is active. */
|
| +static void
|
| +resolve_all_program_units (gfc_namespace *gfc_global_ns_list)
|
| +{
|
| + gfc_free_dt_list ();
|
| + gfc_current_ns = gfc_global_ns_list;
|
| + for (; gfc_current_ns; gfc_current_ns = gfc_current_ns->sibling)
|
| + {
|
| + gfc_current_locus = gfc_current_ns->proc_name->declared_at;
|
| + gfc_resolve (gfc_current_ns);
|
| + gfc_current_ns->derived_types = gfc_derived_types;
|
| + gfc_derived_types = NULL;
|
| + }
|
| +}
|
| +
|
| +
|
| +static void
|
| +clean_up_modules (gfc_gsymbol *gsym)
|
| +{
|
| + if (gsym == NULL)
|
| + return;
|
| +
|
| + clean_up_modules (gsym->left);
|
| + clean_up_modules (gsym->right);
|
| +
|
| + if (gsym->type != GSYM_MODULE || !gsym->ns)
|
| + return;
|
| +
|
| + gfc_current_ns = gsym->ns;
|
| + gfc_derived_types = gfc_current_ns->derived_types;
|
| + gfc_done_2 ();
|
| + gsym->ns = NULL;
|
| + return;
|
| +}
|
| +
|
| +
|
| +/* Translate all the program units when whole file scope option
|
| + is active. This could be in a different order to resolution if
|
| + there are forward references in the file. */
|
| +static void
|
| +translate_all_program_units (gfc_namespace *gfc_global_ns_list)
|
| +{
|
| + int errors;
|
| +
|
| + gfc_current_ns = gfc_global_ns_list;
|
| + gfc_get_errors (NULL, &errors);
|
| +
|
| + for (; !errors && gfc_current_ns; gfc_current_ns = gfc_current_ns->sibling)
|
| + {
|
| + gfc_current_locus = gfc_current_ns->proc_name->declared_at;
|
| + gfc_derived_types = gfc_current_ns->derived_types;
|
| + gfc_generate_code (gfc_current_ns);
|
| + gfc_current_ns->translated = 1;
|
| + }
|
| +
|
| + /* Clean up all the namespaces after translation. */
|
| + gfc_current_ns = gfc_global_ns_list;
|
| + for (;gfc_current_ns;)
|
| + {
|
| + gfc_namespace *ns = gfc_current_ns->sibling;
|
| + gfc_derived_types = gfc_current_ns->derived_types;
|
| + gfc_done_2 ();
|
| + gfc_current_ns = ns;
|
| }
|
| +
|
| + clean_up_modules (gfc_gsym_root);
|
| }
|
|
|
|
|
| @@ -3743,6 +4096,7 @@ gfc_parse_file (void)
|
| gfc_state_data top, s;
|
| gfc_statement st;
|
| locus prog_locus;
|
| + gfc_namespace *next;
|
|
|
| gfc_start_source_files ();
|
|
|
| @@ -3761,6 +4115,10 @@ gfc_parse_file (void)
|
| if (setjmp (eof_buf))
|
| return FAILURE; /* Come here on unexpected EOF */
|
|
|
| + /* Prepare the global namespace that will contain the
|
| + program units. */
|
| + gfc_global_ns_list = next = NULL;
|
| +
|
| seen_program = 0;
|
|
|
| /* Exit early for empty files. */
|
| @@ -3787,6 +4145,8 @@ loop:
|
| accept_statement (st);
|
| add_global_program ();
|
| parse_progunit (ST_NONE);
|
| + if (gfc_option.flag_whole_file)
|
| + goto prog_units;
|
| break;
|
|
|
| case ST_SUBROUTINE:
|
| @@ -3794,6 +4154,8 @@ loop:
|
| push_state (&s, COMP_SUBROUTINE, gfc_new_block);
|
| accept_statement (st);
|
| parse_progunit (ST_NONE);
|
| + if (gfc_option.flag_whole_file)
|
| + goto prog_units;
|
| break;
|
|
|
| case ST_FUNCTION:
|
| @@ -3801,6 +4163,8 @@ loop:
|
| push_state (&s, COMP_FUNCTION, gfc_new_block);
|
| accept_statement (st);
|
| parse_progunit (ST_NONE);
|
| + if (gfc_option.flag_whole_file)
|
| + goto prog_units;
|
| break;
|
|
|
| case ST_BLOCK_DATA:
|
| @@ -3827,9 +4191,12 @@ loop:
|
| push_state (&s, COMP_PROGRAM, gfc_new_block);
|
| main_program_symbol (gfc_current_ns, "MAIN__");
|
| parse_progunit (st);
|
| + if (gfc_option.flag_whole_file)
|
| + goto prog_units;
|
| break;
|
| }
|
|
|
| + /* Handle the non-program units. */
|
| gfc_current_ns->code = s.head;
|
|
|
| gfc_resolve (gfc_current_ns);
|
| @@ -3844,18 +4211,64 @@ loop:
|
| gfc_dump_module (s.sym->name, errors_before == errors);
|
| if (errors == 0)
|
| gfc_generate_module_code (gfc_current_ns);
|
| + pop_state ();
|
| + if (!gfc_option.flag_whole_file)
|
| + gfc_done_2 ();
|
| + else
|
| + {
|
| + gfc_current_ns->derived_types = gfc_derived_types;
|
| + gfc_derived_types = NULL;
|
| + gfc_current_ns = NULL;
|
| + }
|
| }
|
| else
|
| {
|
| if (errors == 0)
|
| gfc_generate_code (gfc_current_ns);
|
| + pop_state ();
|
| + gfc_done_2 ();
|
| }
|
|
|
| + goto loop;
|
| +
|
| +prog_units:
|
| + /* The main program and non-contained procedures are put
|
| + in the global namespace list, so that they can be processed
|
| + later and all their interfaces resolved. */
|
| + gfc_current_ns->code = s.head;
|
| + if (next)
|
| + next->sibling = gfc_current_ns;
|
| + else
|
| + gfc_global_ns_list = gfc_current_ns;
|
| +
|
| + next = gfc_current_ns;
|
| +
|
| pop_state ();
|
| - gfc_done_2 ();
|
| goto loop;
|
|
|
| -done:
|
| + done:
|
| +
|
| + if (!gfc_option.flag_whole_file)
|
| + goto termination;
|
| +
|
| + /* Do the resolution. */
|
| + resolve_all_program_units (gfc_global_ns_list);
|
| +
|
| + /* Do the parse tree dump. */
|
| + gfc_current_ns
|
| + = gfc_option.dump_parse_tree ? gfc_global_ns_list : NULL;
|
| +
|
| + for (; gfc_current_ns; gfc_current_ns = gfc_current_ns->sibling)
|
| + {
|
| + gfc_dump_parse_tree (gfc_current_ns, stdout);
|
| + fputs ("------------------------------------------\n\n", stdout);
|
| + }
|
| +
|
| + /* Do the translation. */
|
| + translate_all_program_units (gfc_global_ns_list);
|
| +
|
| +termination:
|
| +
|
| gfc_end_source_files ();
|
| return SUCCESS;
|
|
|
|
|