Commit 03af1e4c by Daniel Kraft Committed by Daniel Kraft

re PR fortran/38936 ([F03] ASSOCIATE construct / improved SELECT TYPE (a=>expr))

2010-06-10  Daniel Kraft  <d@domob.eu>

	PR fortran/38936
	* gfortran.h (enum gfc_statement): Add ST_ASSOCIATE, ST_END_ASSOCIATE.
	(struct gfc_symbol): New field `assoc'.
	(struct gfc_association_list): New struct.
	(struct gfc_code): New struct `block' in union, move `ns' there
	and add association list.
	(gfc_free_association_list): New method.
	(gfc_has_vector_subscript): Made public;
	* match.h (gfc_match_associate): New method.
	* parse.h (enum gfc_compile_state): Add COMP_ASSOCIATE.
	* decl.c (gfc_match_end): Handle ST_END_ASSOCIATE.
	* interface.c (gfc_has_vector_subscript): Made public.
	(compare_actual_formal): Rename `has_vector_subscript' accordingly.
	* match.c (gfc_match_associate): New method.
	(gfc_match_select_type): Change reference to gfc_code's `ns' field.
	* primary.c (match_variable): Don't allow names associated to expr here.
	* parse.c (decode_statement): Try matching ASSOCIATE statement.
	(case_exec_markers, case_end): Add ASSOCIATE statement.
	(gfc_ascii_statement): Hande ST_ASSOCIATE and ST_END_ASSOCIATE.
	(parse_associate): New method.
	(parse_executable): Handle ST_ASSOCIATE.
	(parse_block_construct): Change reference to gfc_code's `ns' field.
	* resolve.c (resolve_select_type): Ditto.
	(resolve_code): Ditto.
	(resolve_block_construct): Ditto and add comment.
	(resolve_select_type): Set association list in generated BLOCK to NULL.
	(resolve_symbol): Resolve associate names.
	* st.c (gfc_free_statement): Change reference to gfc_code's `ns' field
	and free association list.
	(gfc_free_association_list): New method.
	* symbol.c (gfc_new_symbol): NULL new field `assoc'.
	* trans-stmt.c (gfc_trans_block_construct): Change reference to
	gfc_code's `ns' field.

2010-06-10  Daniel Kraft  <d@domob.eu>

	PR fortran/38936
	* gfortran.dg/associate_1.f03: New test.
	* gfortran.dg/associate_2.f95: New test.
	* gfortran.dg/associate_3.f03: New test.
	* gfortran.dg/associate_4.f08: New test.

From-SVN: r160550
parent 29aba2bb
2010-06-10 Daniel Kraft <d@domob.eu>
PR fortran/38936
* gfortran.h (enum gfc_statement): Add ST_ASSOCIATE, ST_END_ASSOCIATE.
(struct gfc_symbol): New field `assoc'.
(struct gfc_association_list): New struct.
(struct gfc_code): New struct `block' in union, move `ns' there
and add association list.
(gfc_free_association_list): New method.
(gfc_has_vector_subscript): Made public;
* match.h (gfc_match_associate): New method.
* parse.h (enum gfc_compile_state): Add COMP_ASSOCIATE.
* decl.c (gfc_match_end): Handle ST_END_ASSOCIATE.
* interface.c (gfc_has_vector_subscript): Made public.
(compare_actual_formal): Rename `has_vector_subscript' accordingly.
* match.c (gfc_match_associate): New method.
(gfc_match_select_type): Change reference to gfc_code's `ns' field.
* primary.c (match_variable): Don't allow names associated to expr here.
* parse.c (decode_statement): Try matching ASSOCIATE statement.
(case_exec_markers, case_end): Add ASSOCIATE statement.
(gfc_ascii_statement): Hande ST_ASSOCIATE and ST_END_ASSOCIATE.
(parse_associate): New method.
(parse_executable): Handle ST_ASSOCIATE.
(parse_block_construct): Change reference to gfc_code's `ns' field.
* resolve.c (resolve_select_type): Ditto.
(resolve_code): Ditto.
(resolve_block_construct): Ditto and add comment.
(resolve_select_type): Set association list in generated BLOCK to NULL.
(resolve_symbol): Resolve associate names.
* st.c (gfc_free_statement): Change reference to gfc_code's `ns' field
and free association list.
(gfc_free_association_list): New method.
* symbol.c (gfc_new_symbol): NULL new field `assoc'.
* trans-stmt.c (gfc_trans_block_construct): Change reference to
gfc_code's `ns' field.
2010-06-10 Kai Tietz <kai.tietz@onevision.com> 2010-06-10 Kai Tietz <kai.tietz@onevision.com>
* error.c (error_print): Pre-initialize loc by NULL. * error.c (error_print): Pre-initialize loc by NULL.
......
...@@ -5483,14 +5483,23 @@ gfc_match_end (gfc_statement *st) ...@@ -5483,14 +5483,23 @@ gfc_match_end (gfc_statement *st)
block_name = gfc_current_block () == NULL block_name = gfc_current_block () == NULL
? NULL : gfc_current_block ()->name; ? NULL : gfc_current_block ()->name;
if (state == COMP_BLOCK && !strcmp (block_name, "block@")) switch (state)
block_name = NULL;
if (state == COMP_CONTAINS || state == COMP_DERIVED_CONTAINS)
{ {
case COMP_ASSOCIATE:
case COMP_BLOCK:
if (!strcmp (block_name, "block@"))
block_name = NULL;
break;
case COMP_CONTAINS:
case COMP_DERIVED_CONTAINS:
state = gfc_state_stack->previous->state; state = gfc_state_stack->previous->state;
block_name = gfc_state_stack->previous->sym == NULL block_name = gfc_state_stack->previous->sym == NULL
? NULL : gfc_state_stack->previous->sym->name; ? NULL : gfc_state_stack->previous->sym->name;
break;
default:
break;
} }
switch (state) switch (state)
...@@ -5539,6 +5548,12 @@ gfc_match_end (gfc_statement *st) ...@@ -5539,6 +5548,12 @@ gfc_match_end (gfc_statement *st)
eos_ok = 0; eos_ok = 0;
break; break;
case COMP_ASSOCIATE:
*st = ST_END_ASSOCIATE;
target = " associate";
eos_ok = 0;
break;
case COMP_BLOCK: case COMP_BLOCK:
*st = ST_END_BLOCK; *st = ST_END_BLOCK;
target = " block"; target = " block";
...@@ -5622,7 +5637,7 @@ gfc_match_end (gfc_statement *st) ...@@ -5622,7 +5637,7 @@ gfc_match_end (gfc_statement *st)
if (*st != ST_ENDDO && *st != ST_ENDIF && *st != ST_END_SELECT if (*st != ST_ENDDO && *st != ST_ENDIF && *st != ST_END_SELECT
&& *st != ST_END_FORALL && *st != ST_END_WHERE && *st != ST_END_BLOCK && *st != ST_END_FORALL && *st != ST_END_WHERE && *st != ST_END_BLOCK
&& *st != ST_END_CRITICAL) && *st != ST_END_ASSOCIATE && *st != ST_END_CRITICAL)
return MATCH_YES; return MATCH_YES;
if (!block_name) if (!block_name)
......
...@@ -205,11 +205,12 @@ arith; ...@@ -205,11 +205,12 @@ arith;
/* Statements. */ /* Statements. */
typedef enum typedef enum
{ {
ST_ARITHMETIC_IF, ST_ALLOCATE, ST_ATTR_DECL, ST_BACKSPACE, ST_ARITHMETIC_IF, ST_ALLOCATE, ST_ATTR_DECL, ST_ASSOCIATE,
ST_BLOCK, ST_BLOCK_DATA, ST_BACKSPACE, ST_BLOCK, ST_BLOCK_DATA,
ST_CALL, ST_CASE, ST_CLOSE, ST_COMMON, ST_CONTINUE, ST_CONTAINS, ST_CYCLE, ST_CALL, ST_CASE, ST_CLOSE, ST_COMMON, ST_CONTINUE, ST_CONTAINS, ST_CYCLE,
ST_DATA, ST_DATA_DECL, ST_DEALLOCATE, ST_DO, ST_ELSE, ST_ELSEIF, ST_DATA, ST_DATA_DECL, ST_DEALLOCATE, ST_DO, ST_ELSE, ST_ELSEIF,
ST_ELSEWHERE, ST_END_BLOCK, ST_END_BLOCK_DATA, ST_ENDDO, ST_IMPLIED_ENDDO, ST_ELSEWHERE, ST_END_ASSOCIATE, ST_END_BLOCK, ST_END_BLOCK_DATA,
ST_ENDDO, ST_IMPLIED_ENDDO,
ST_END_FILE, ST_FINAL, ST_FLUSH, ST_END_FORALL, ST_END_FUNCTION, ST_ENDIF, ST_END_FILE, ST_FINAL, ST_FLUSH, ST_END_FORALL, ST_END_FUNCTION, ST_ENDIF,
ST_END_INTERFACE, ST_END_MODULE, ST_END_PROGRAM, ST_END_SELECT, ST_END_INTERFACE, ST_END_MODULE, ST_END_PROGRAM, ST_END_SELECT,
ST_END_SUBROUTINE, ST_END_WHERE, ST_END_TYPE, ST_ENTRY, ST_EQUIVALENCE, ST_END_SUBROUTINE, ST_END_WHERE, ST_END_TYPE, ST_ENTRY, ST_EQUIVALENCE,
...@@ -1201,6 +1202,9 @@ typedef struct gfc_symbol ...@@ -1201,6 +1202,9 @@ typedef struct gfc_symbol
char binding_label[GFC_MAX_BINDING_LABEL_LEN + 1]; char binding_label[GFC_MAX_BINDING_LABEL_LEN + 1];
/* Store a reference to the common_block, if this symbol is in one. */ /* Store a reference to the common_block, if this symbol is in one. */
struct gfc_common_head *common_block; struct gfc_common_head *common_block;
/* Link to corresponding association-list if this is an associate name. */
struct gfc_association_list *assoc;
} }
gfc_symbol; gfc_symbol;
...@@ -1974,6 +1978,25 @@ typedef struct gfc_forall_iterator ...@@ -1974,6 +1978,25 @@ typedef struct gfc_forall_iterator
gfc_forall_iterator; gfc_forall_iterator;
/* Linked list to store associations in an ASSOCIATE statement. */
typedef struct gfc_association_list
{
struct gfc_association_list *next;
/* Whether this is association to a variable that can be changed; otherwise,
it's association to an expression and the name may not be used as
lvalue. */
unsigned variable:1;
char name[GFC_MAX_SYMBOL_LEN + 1];
gfc_symtree *st; /* Symtree corresponding to name. */
gfc_expr *target;
}
gfc_association_list;
#define gfc_get_association_list() XCNEW (gfc_association_list)
/* Executable statements that fill gfc_code structures. */ /* Executable statements that fill gfc_code structures. */
typedef enum typedef enum
{ {
...@@ -2026,6 +2049,13 @@ typedef struct gfc_code ...@@ -2026,6 +2049,13 @@ typedef struct gfc_code
} }
alloc; alloc;
struct
{
gfc_namespace *ns;
gfc_association_list *assoc;
}
block;
gfc_open *open; gfc_open *open;
gfc_close *close; gfc_close *close;
gfc_filepos *filepos; gfc_filepos *filepos;
...@@ -2040,7 +2070,6 @@ typedef struct gfc_code ...@@ -2040,7 +2070,6 @@ typedef struct gfc_code
const char *omp_name; const char *omp_name;
gfc_namelist *omp_namelist; gfc_namelist *omp_namelist;
bool omp_bool; bool omp_bool;
gfc_namespace *ns;
} }
ext; /* Points to additional structures required by statement */ ext; /* Points to additional structures required by statement */
...@@ -2647,6 +2676,7 @@ gfc_code *gfc_get_code (void); ...@@ -2647,6 +2676,7 @@ gfc_code *gfc_get_code (void);
gfc_code *gfc_append_code (gfc_code *, gfc_code *); gfc_code *gfc_append_code (gfc_code *, gfc_code *);
void gfc_free_statement (gfc_code *); void gfc_free_statement (gfc_code *);
void gfc_free_statements (gfc_code *); void gfc_free_statements (gfc_code *);
void gfc_free_association_list (gfc_association_list *);
/* resolve.c */ /* resolve.c */
gfc_try gfc_resolve_expr (gfc_expr *); gfc_try gfc_resolve_expr (gfc_expr *);
...@@ -2719,6 +2749,7 @@ void gfc_set_current_interface_head (gfc_interface *); ...@@ -2719,6 +2749,7 @@ void gfc_set_current_interface_head (gfc_interface *);
gfc_symtree* gfc_find_sym_in_symtree (gfc_symbol*); gfc_symtree* gfc_find_sym_in_symtree (gfc_symbol*);
bool gfc_arglist_matches_symbol (gfc_actual_arglist**, gfc_symbol*); bool gfc_arglist_matches_symbol (gfc_actual_arglist**, gfc_symbol*);
bool gfc_check_operator_interface (gfc_symbol*, gfc_intrinsic_op, locus); bool gfc_check_operator_interface (gfc_symbol*, gfc_intrinsic_op, locus);
int gfc_has_vector_subscript (gfc_expr*);
/* io.c */ /* io.c */
extern gfc_st_label format_asterisk; extern gfc_st_label format_asterisk;
......
...@@ -1821,8 +1821,8 @@ get_expr_storage_size (gfc_expr *e) ...@@ -1821,8 +1821,8 @@ get_expr_storage_size (gfc_expr *e)
which has a vector subscript. If it has, one is returned, which has a vector subscript. If it has, one is returned,
otherwise zero. */ otherwise zero. */
static int int
has_vector_subscript (gfc_expr *e) gfc_has_vector_subscript (gfc_expr *e)
{ {
int i; int i;
gfc_ref *ref; gfc_ref *ref;
...@@ -2134,7 +2134,7 @@ compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal, ...@@ -2134,7 +2134,7 @@ compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,
if ((f->sym->attr.intent == INTENT_OUT if ((f->sym->attr.intent == INTENT_OUT
|| f->sym->attr.intent == INTENT_INOUT || f->sym->attr.intent == INTENT_INOUT
|| f->sym->attr.volatile_) || f->sym->attr.volatile_)
&& has_vector_subscript (a->expr)) && gfc_has_vector_subscript (a->expr))
{ {
if (where) if (where)
gfc_error ("Array-section actual argument with vector subscripts " gfc_error ("Array-section actual argument with vector subscripts "
......
...@@ -1797,6 +1797,98 @@ gfc_match_block (void) ...@@ -1797,6 +1797,98 @@ gfc_match_block (void)
} }
/* Match an ASSOCIATE statement. */
match
gfc_match_associate (void)
{
if (gfc_match_label () == MATCH_ERROR)
return MATCH_ERROR;
if (gfc_match (" associate") != MATCH_YES)
return MATCH_NO;
/* Match the association list. */
if (gfc_match_char ('(') != MATCH_YES)
{
gfc_error ("Expected association list at %C");
return MATCH_ERROR;
}
new_st.ext.block.assoc = NULL;
while (true)
{
gfc_association_list* newAssoc = gfc_get_association_list ();
gfc_association_list* a;
/* Match the next association. */
if (gfc_match (" %n => %e", newAssoc->name, &newAssoc->target)
!= MATCH_YES)
{
gfc_error ("Expected association at %C");
goto assocListError;
}
/* Check that the current name is not yet in the list. */
for (a = new_st.ext.block.assoc; a; a = a->next)
if (!strcmp (a->name, newAssoc->name))
{
gfc_error ("Duplicate name '%s' in association at %C",
newAssoc->name);
goto assocListError;
}
/* The target expression must not be coindexed. */
if (gfc_is_coindexed (newAssoc->target))
{
gfc_error ("Association target at %C must not be coindexed");
goto assocListError;
}
/* The target is a variable (and may be used as lvalue) if it's an
EXPR_VARIABLE and does not have vector-subscripts. */
newAssoc->variable = (newAssoc->target->expr_type == EXPR_VARIABLE
&& !gfc_has_vector_subscript (newAssoc->target));
/* Put it into the list. */
newAssoc->next = new_st.ext.block.assoc;
new_st.ext.block.assoc = newAssoc;
/* Try next one or end if closing parenthesis is found. */
gfc_gobble_whitespace ();
if (gfc_peek_char () == ')')
break;
if (gfc_match_char (',') != MATCH_YES)
{
gfc_error ("Expected ')' or ',' at %C");
return MATCH_ERROR;
}
continue;
assocListError:
gfc_free (newAssoc);
goto error;
}
if (gfc_match_char (')') != MATCH_YES)
{
/* This should never happen as we peek above. */
gcc_unreachable ();
}
if (gfc_match_eos () != MATCH_YES)
{
gfc_error ("Junk after ASSOCIATE statement at %C");
goto error;
}
return MATCH_YES;
error:
gfc_free_association_list (new_st.ext.block.assoc);
return MATCH_ERROR;
}
/* Match a DO statement. */ /* Match a DO statement. */
match match
...@@ -4361,7 +4453,7 @@ gfc_match_select_type (void) ...@@ -4361,7 +4453,7 @@ gfc_match_select_type (void)
new_st.op = EXEC_SELECT_TYPE; new_st.op = EXEC_SELECT_TYPE;
new_st.expr1 = expr1; new_st.expr1 = expr1;
new_st.expr2 = expr2; new_st.expr2 = expr2;
new_st.ext.ns = gfc_current_ns; new_st.ext.block.ns = gfc_current_ns;
select_type_push (expr1->symtree->n.sym); select_type_push (expr1->symtree->n.sym);
......
...@@ -69,6 +69,7 @@ match gfc_match_else (void); ...@@ -69,6 +69,7 @@ match gfc_match_else (void);
match gfc_match_elseif (void); match gfc_match_elseif (void);
match gfc_match_critical (void); match gfc_match_critical (void);
match gfc_match_block (void); match gfc_match_block (void);
match gfc_match_associate (void);
match gfc_match_do (void); match gfc_match_do (void);
match gfc_match_cycle (void); match gfc_match_cycle (void);
match gfc_match_exit (void); match gfc_match_exit (void);
......
...@@ -292,7 +292,7 @@ decode_statement (void) ...@@ -292,7 +292,7 @@ decode_statement (void)
gfc_undo_symbols (); gfc_undo_symbols ();
gfc_current_locus = old_locus; gfc_current_locus = old_locus;
/* Check for the IF, DO, SELECT, WHERE, FORALL, CRITICAL, and BLOCK /* Check for the IF, DO, SELECT, WHERE, FORALL, CRITICAL, BLOCK and ASSOCIATE
statements, which might begin with a block label. The match functions for statements, which might begin with a block label. The match functions for
these statements are unusual in that their keyword is not seen before these statements are unusual in that their keyword is not seen before
the matcher is called. */ the matcher is called. */
...@@ -314,6 +314,7 @@ decode_statement (void) ...@@ -314,6 +314,7 @@ decode_statement (void)
match (NULL, gfc_match_do, ST_DO); match (NULL, gfc_match_do, ST_DO);
match (NULL, gfc_match_block, ST_BLOCK); match (NULL, gfc_match_block, ST_BLOCK);
match (NULL, gfc_match_associate, ST_ASSOCIATE);
match (NULL, gfc_match_critical, ST_CRITICAL); match (NULL, gfc_match_critical, ST_CRITICAL);
match (NULL, gfc_match_select, ST_SELECT_CASE); match (NULL, gfc_match_select, ST_SELECT_CASE);
match (NULL, gfc_match_select_type, ST_SELECT_TYPE); match (NULL, gfc_match_select_type, ST_SELECT_TYPE);
...@@ -949,7 +950,7 @@ next_statement (void) ...@@ -949,7 +950,7 @@ next_statement (void)
/* Statements that mark other executable statements. */ /* Statements that mark other executable statements. */
#define case_exec_markers case ST_DO: case ST_FORALL_BLOCK: \ #define case_exec_markers case ST_DO: case ST_FORALL_BLOCK: \
case ST_IF_BLOCK: case ST_BLOCK: \ case ST_IF_BLOCK: case ST_BLOCK: case ST_ASSOCIATE: \
case ST_WHERE_BLOCK: case ST_SELECT_CASE: case ST_SELECT_TYPE: \ case ST_WHERE_BLOCK: case ST_SELECT_CASE: case ST_SELECT_TYPE: \
case ST_OMP_PARALLEL: \ case ST_OMP_PARALLEL: \
case ST_OMP_PARALLEL_SECTIONS: case ST_OMP_SECTIONS: case ST_OMP_ORDERED: \ case ST_OMP_PARALLEL_SECTIONS: case ST_OMP_SECTIONS: case ST_OMP_ORDERED: \
...@@ -970,7 +971,7 @@ next_statement (void) ...@@ -970,7 +971,7 @@ next_statement (void)
#define case_end case ST_END_BLOCK_DATA: case ST_END_FUNCTION: \ #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 case ST_END_BLOCK: case ST_END_ASSOCIATE
/* Push a new state onto the stack. */ /* Push a new state onto the stack. */
...@@ -1155,6 +1156,9 @@ gfc_ascii_statement (gfc_statement st) ...@@ -1155,6 +1156,9 @@ gfc_ascii_statement (gfc_statement st)
case ST_ALLOCATE: case ST_ALLOCATE:
p = "ALLOCATE"; p = "ALLOCATE";
break; break;
case ST_ASSOCIATE:
p = "ASSOCIATE";
break;
case ST_ATTR_DECL: case ST_ATTR_DECL:
p = _("attribute declaration"); p = _("attribute declaration");
break; break;
...@@ -1215,6 +1219,9 @@ gfc_ascii_statement (gfc_statement st) ...@@ -1215,6 +1219,9 @@ gfc_ascii_statement (gfc_statement st)
case ST_ELSEWHERE: case ST_ELSEWHERE:
p = "ELSEWHERE"; p = "ELSEWHERE";
break; break;
case ST_END_ASSOCIATE:
p = "END ASSOCIATE";
break;
case ST_END_BLOCK: case ST_END_BLOCK:
p = "END BLOCK"; p = "END BLOCK";
break; break;
...@@ -3160,7 +3167,8 @@ parse_block_construct (void) ...@@ -3160,7 +3167,8 @@ parse_block_construct (void)
my_ns = gfc_build_block_ns (gfc_current_ns); my_ns = gfc_build_block_ns (gfc_current_ns);
new_st.op = EXEC_BLOCK; new_st.op = EXEC_BLOCK;
new_st.ext.ns = my_ns; new_st.ext.block.ns = my_ns;
new_st.ext.block.assoc = NULL;
accept_statement (ST_BLOCK); accept_statement (ST_BLOCK);
push_state (&s, COMP_BLOCK, my_ns->proc_name); push_state (&s, COMP_BLOCK, my_ns->proc_name);
...@@ -3173,6 +3181,92 @@ parse_block_construct (void) ...@@ -3173,6 +3181,92 @@ parse_block_construct (void)
} }
/* Parse an ASSOCIATE construct. This is essentially a BLOCK construct
behind the scenes with compiler-generated variables. */
static void
parse_associate (void)
{
gfc_namespace* my_ns;
gfc_state_data s;
gfc_statement st;
gfc_association_list* a;
gfc_code* assignTail;
gfc_notify_std (GFC_STD_F2003, "Fortran 2003: ASSOCIATE construct at %C");
my_ns = gfc_build_block_ns (gfc_current_ns);
new_st.op = EXEC_BLOCK;
new_st.ext.block.ns = my_ns;
gcc_assert (new_st.ext.block.assoc);
/* Add all associations to expressions as BLOCK variables, and create
assignments to them giving their values. */
gfc_current_ns = my_ns;
assignTail = NULL;
for (a = new_st.ext.block.assoc; a; a = a->next)
if (!a->variable)
{
gfc_code* newAssign;
if (gfc_get_sym_tree (a->name, NULL, &a->st, false))
gcc_unreachable ();
/* Note that in certain cases, the target-expression's type is not yet
known and so we have to adapt the symbol's ts also during resolution
for these cases. */
a->st->n.sym->ts = a->target->ts;
a->st->n.sym->attr.flavor = FL_VARIABLE;
a->st->n.sym->assoc = a;
gfc_set_sym_referenced (a->st->n.sym);
/* Create the assignment to calculate the expression and set it. */
newAssign = gfc_get_code ();
newAssign->op = EXEC_ASSIGN;
newAssign->loc = gfc_current_locus;
newAssign->expr1 = gfc_get_variable_expr (a->st);
newAssign->expr2 = a->target;
/* Hang it in. */
if (assignTail)
assignTail->next = newAssign;
else
gfc_current_ns->code = newAssign;
assignTail = newAssign;
}
else
{
gfc_error ("Association to variables is not yet supported at %C");
return;
}
gcc_assert (assignTail);
accept_statement (ST_ASSOCIATE);
push_state (&s, COMP_ASSOCIATE, my_ns->proc_name);
loop:
st = parse_executable (ST_NONE);
switch (st)
{
case ST_NONE:
unexpected_eof ();
case_end:
accept_statement (st);
assignTail->next = gfc_state_stack->head;
break;
default:
unexpected_statement (st);
goto loop;
}
gfc_current_ns = gfc_current_ns->parent;
pop_state ();
}
/* Parse a DO loop. Note that the ST_CYCLE and ST_EXIT statements are /* Parse a DO loop. Note that the ST_CYCLE and ST_EXIT statements are
handled inside of parse_executable(), because they aren't really handled inside of parse_executable(), because they aren't really
loop statements. */ loop statements. */
...@@ -3542,8 +3636,6 @@ parse_executable (gfc_statement st) ...@@ -3542,8 +3636,6 @@ parse_executable (gfc_statement st)
case ST_END_SUBROUTINE: case ST_END_SUBROUTINE:
case ST_DO: case ST_DO:
case ST_CRITICAL:
case ST_BLOCK:
case ST_FORALL: case ST_FORALL:
case ST_WHERE: case ST_WHERE:
case ST_SELECT_CASE: case ST_SELECT_CASE:
...@@ -3573,6 +3665,10 @@ parse_executable (gfc_statement st) ...@@ -3573,6 +3665,10 @@ parse_executable (gfc_statement st)
parse_block_construct (); parse_block_construct ();
break; break;
case ST_ASSOCIATE:
parse_associate ();
break;
case ST_IF_BLOCK: case ST_IF_BLOCK:
parse_if_block (); parse_if_block ();
break; break;
......
...@@ -28,7 +28,7 @@ typedef enum ...@@ -28,7 +28,7 @@ typedef enum
{ {
COMP_NONE, COMP_PROGRAM, COMP_MODULE, COMP_SUBROUTINE, COMP_FUNCTION, COMP_NONE, COMP_PROGRAM, COMP_MODULE, COMP_SUBROUTINE, COMP_FUNCTION,
COMP_BLOCK_DATA, COMP_INTERFACE, COMP_DERIVED, COMP_DERIVED_CONTAINS, COMP_BLOCK_DATA, COMP_INTERFACE, COMP_DERIVED, COMP_DERIVED_CONTAINS,
COMP_BLOCK, COMP_IF, COMP_BLOCK, COMP_ASSOCIATE, COMP_IF,
COMP_DO, COMP_SELECT, COMP_FORALL, COMP_WHERE, COMP_CONTAINS, COMP_ENUM, COMP_DO, COMP_SELECT, COMP_FORALL, COMP_WHERE, COMP_CONTAINS, COMP_ENUM,
COMP_SELECT_TYPE, COMP_OMP_STRUCTURED_BLOCK, COMP_CRITICAL COMP_SELECT_TYPE, COMP_OMP_STRUCTURED_BLOCK, COMP_CRITICAL
} }
......
...@@ -2975,6 +2975,12 @@ match_variable (gfc_expr **result, int equiv_flag, int host_flag) ...@@ -2975,6 +2975,12 @@ match_variable (gfc_expr **result, int equiv_flag, int host_flag)
gfc_error ("Assigning to PROTECTED variable at %C"); gfc_error ("Assigning to PROTECTED variable at %C");
return MATCH_ERROR; return MATCH_ERROR;
} }
if (sym->assoc && !sym->assoc->variable)
{
gfc_error ("'%s' associated to expression can't appear in a variable"
" definition context at %C", sym->name);
return MATCH_ERROR;
}
break; break;
case FL_UNKNOWN: case FL_UNKNOWN:
......
...@@ -7158,7 +7158,7 @@ resolve_select_type (gfc_code *code) ...@@ -7158,7 +7158,7 @@ resolve_select_type (gfc_code *code)
gfc_namespace *ns; gfc_namespace *ns;
int error = 0; int error = 0;
ns = code->ext.ns; ns = code->ext.block.ns;
gfc_resolve (ns); gfc_resolve (ns);
/* Check for F03:C813. */ /* Check for F03:C813. */
...@@ -7245,6 +7245,7 @@ resolve_select_type (gfc_code *code) ...@@ -7245,6 +7245,7 @@ resolve_select_type (gfc_code *code)
else else
ns->code->next = new_st; ns->code->next = new_st;
code->op = EXEC_BLOCK; code->op = EXEC_BLOCK;
code->ext.block.assoc = NULL;
code->expr1 = code->expr2 = NULL; code->expr1 = code->expr2 = NULL;
code->block = NULL; code->block = NULL;
...@@ -7988,10 +7989,11 @@ gfc_resolve_forall (gfc_code *code, gfc_namespace *ns, int forall_save) ...@@ -7988,10 +7989,11 @@ gfc_resolve_forall (gfc_code *code, gfc_namespace *ns, int forall_save)
static void static void
resolve_block_construct (gfc_code* code) resolve_block_construct (gfc_code* code)
{ {
/* Eventually, we may want to do some checks here or handle special stuff. /* For an ASSOCIATE block, the associations (and their targets) are already
But so far the only thing we can do is resolving the local namespace. */ resolved during gfc_resolve_symbol. */
gfc_resolve (code->ext.ns); /* Resolve the BLOCK's namespace. */
gfc_resolve (code->ext.block.ns);
} }
...@@ -8312,7 +8314,7 @@ resolve_code (gfc_code *code, gfc_namespace *ns) ...@@ -8312,7 +8314,7 @@ resolve_code (gfc_code *code, gfc_namespace *ns)
gfc_resolve_omp_do_blocks (code, ns); gfc_resolve_omp_do_blocks (code, ns);
break; break;
case EXEC_SELECT_TYPE: case EXEC_SELECT_TYPE:
gfc_current_ns = code->ext.ns; gfc_current_ns = code->ext.block.ns;
gfc_resolve_blocks (code->block, gfc_current_ns); gfc_resolve_blocks (code->block, gfc_current_ns);
gfc_current_ns = ns; gfc_current_ns = ns;
break; break;
...@@ -8476,7 +8478,7 @@ resolve_code (gfc_code *code, gfc_namespace *ns) ...@@ -8476,7 +8478,7 @@ resolve_code (gfc_code *code, gfc_namespace *ns)
break; break;
case EXEC_BLOCK: case EXEC_BLOCK:
gfc_resolve (code->ext.ns); gfc_resolve (code->ext.block.ns);
break; break;
case EXEC_DO: case EXEC_DO:
...@@ -11341,7 +11343,6 @@ resolve_symbol (gfc_symbol *sym) ...@@ -11341,7 +11343,6 @@ resolve_symbol (gfc_symbol *sym)
can. */ can. */
mp_flag = (sym->result != NULL && sym->result != sym); mp_flag = (sym->result != NULL && sym->result != sym);
/* Make sure that the intrinsic is consistent with its internal /* Make sure that the intrinsic is consistent with its internal
representation. This needs to be done before assigning a default representation. This needs to be done before assigning a default
type to avoid spurious warnings. */ type to avoid spurious warnings. */
...@@ -11349,6 +11350,18 @@ resolve_symbol (gfc_symbol *sym) ...@@ -11349,6 +11350,18 @@ resolve_symbol (gfc_symbol *sym)
&& resolve_intrinsic (sym, &sym->declared_at) == FAILURE) && resolve_intrinsic (sym, &sym->declared_at) == FAILURE)
return; return;
/* For associate names, resolve corresponding expression and make sure
they get their type-spec set this way. */
if (sym->assoc)
{
gcc_assert (sym->attr.flavor == FL_VARIABLE);
if (gfc_resolve_expr (sym->assoc->target) != SUCCESS)
return;
sym->ts = sym->assoc->target->ts;
gcc_assert (sym->ts.type != BT_UNKNOWN);
}
/* Assign default type to symbols that need one and don't have one. */ /* Assign default type to symbols that need one and don't have one. */
if (sym->ts.type == BT_UNKNOWN) if (sym->ts.type == BT_UNKNOWN)
{ {
......
...@@ -116,7 +116,8 @@ gfc_free_statement (gfc_code *p) ...@@ -116,7 +116,8 @@ gfc_free_statement (gfc_code *p)
break; break;
case EXEC_BLOCK: case EXEC_BLOCK:
gfc_free_namespace (p->ext.ns); gfc_free_namespace (p->ext.block.ns);
gfc_free_association_list (p->ext.block.assoc);
break; break;
case EXEC_COMPCALL: case EXEC_COMPCALL:
...@@ -231,3 +232,15 @@ gfc_free_statements (gfc_code *p) ...@@ -231,3 +232,15 @@ gfc_free_statements (gfc_code *p)
} }
} }
/* Free an association list (of an ASSOCIATE statement). */
void
gfc_free_association_list (gfc_association_list* assoc)
{
if (!assoc)
return;
gfc_free_association_list (assoc->next);
gfc_free (assoc);
}
...@@ -2512,6 +2512,7 @@ gfc_new_symbol (const char *name, gfc_namespace *ns) ...@@ -2512,6 +2512,7 @@ gfc_new_symbol (const char *name, gfc_namespace *ns)
/* Clear the ptrs we may need. */ /* Clear the ptrs we may need. */
p->common_block = NULL; p->common_block = NULL;
p->f2k_derived = NULL; p->f2k_derived = NULL;
p->assoc = NULL;
return p; return p;
} }
......
...@@ -850,7 +850,7 @@ gfc_trans_block_construct (gfc_code* code) ...@@ -850,7 +850,7 @@ gfc_trans_block_construct (gfc_code* code)
stmtblock_t body; stmtblock_t body;
tree tmp; tree tmp;
ns = code->ext.ns; ns = code->ext.block.ns;
gcc_assert (ns); gcc_assert (ns);
sym = ns->proc_name; sym = ns->proc_name;
gcc_assert (sym); gcc_assert (sym);
......
2010-06-10 Daniel Kraft <d@domob.eu>
PR fortran/38936
* gfortran.dg/associate_1.f03: New test.
* gfortran.dg/associate_2.f95: New test.
* gfortran.dg/associate_3.f03: New test.
* gfortran.dg/associate_4.f08: New test.
2010-06-10 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org> 2010-06-10 Francois-Xavier Coudert <fxcoudert@gcc.gnu.org>
* gfortran.dg/selected_char_kind_4.f90: New test. * gfortran.dg/selected_char_kind_4.f90: New test.
......
! { dg-do run }
! { dg-options "-std=f2003 -fall-intrinsics" }
! PR fortran/38936
! Check the basic semantics of the ASSOCIATE construct.
PROGRAM main
IMPLICIT NONE
REAL :: a, b, c
INTEGER, ALLOCATABLE :: arr(:)
a = -2.0
b = 3.0
c = 4.0
! Simple association to expressions.
ASSOCIATE (r => SQRT (a**2 + b**2 + c**2), t => a + b)
PRINT *, t, a, b
IF (ABS (r - SQRT (4.0 + 9.0 + 16.0)) > 1.0e-3) CALL abort ()
IF (ABS (t - a - b) > 1.0e-3) CALL abort ()
END ASSOCIATE
! TODO: Test association to variables when that is supported.
! TODO: Test association to derived types.
! Test association to arrays.
! TODO: Enable when working.
!ALLOCATE (arr(3))
!arr = (/ 1, 2, 3 /)
!ASSOCIATE (doubled => 2 * arr)
! IF (doubled(1) /= 2 .OR. doubled(2) /= 4 .OR. doubled(3) /= 6) &
! CALL abort ()
!END ASSOCIATE
! Named and nested associate.
myname: ASSOCIATE (x => a - b * c)
ASSOCIATE (y => 2.0 * x)
IF (ABS (y - 2.0 * (a - b * c)) > 1.0e-3) CALL abort ()
END ASSOCIATE
END ASSOCIATE myname ! Matching end-label.
! Correct behaviour when shadowing already existing names.
ASSOCIATE (a => 1 * b, b => 1 * a, x => 1, y => 2)
IF (ABS (a - 3.0) > 1.0e-3 .OR. ABS (b + 2.0) > 1.0e-3) CALL abort ()
ASSOCIATE (x => 1 * y, y => 1 * x)
IF (x /= 2 .OR. y /= 1) CALL abort ()
END ASSOCIATE
END ASSOCIATE
END PROGRAM main
! { dg-do compile }
! { dg-options "-std=f95" }
! PR fortran/38936
! Test that F95 rejects ASSOCIATE.
PROGRAM main
IMPLICIT NONE
ASSOCIATE (a => 5) ! { dg-error "Fortran 2003" }
END ASSOCIATE
END PROGRAM main
! { dg-do compile }
! { dg-options "-std=f2003" }
! PR fortran/38936
! Check for errors with ASSOCIATE.
PROGRAM main
IMPLICIT NONE
ASSOCIATE ! { dg-error "Expected association list" }
ASSOCIATE () ! { dg-error "Expected association" }
ASSOCIATE (a => 1) 5 ! { dg-error "Junk after ASSOCIATE" }
ASSOCIATE (x =>) ! { dg-error "Expected association" }
ASSOCIATE (=> 5) ! { dg-error "Expected association" }
ASSOCIATE (x => 5, ) ! { dg-error "Expected association" }
myname: ASSOCIATE (a => 1)
END ASSOCIATE ! { dg-error "Expected block name of 'myname'" }
ASSOCIATE (b => 2)
END ASSOCIATE myname ! { dg-error "Syntax error in END ASSOCIATE" }
myname2: ASSOCIATE (c => 3)
END ASSOCIATE myname3 ! { dg-error "Expected label 'myname2'" }
ASSOCIATE (a => 1, b => 2, a => 3) ! { dg-error "Duplicate name 'a'" }
ASSOCIATE (a => 5)
a = 4 ! { dg-error "variable definition context" }
ENd ASSOCIATE
ASSOCIATE (a => 5)
INTEGER :: b ! { dg-error "Unexpected data declaration statement" }
END ASSOCIATE
END PROGRAM main ! { dg-error "Expecting END ASSOCIATE" }
! { dg-excess-errors "Unexpected end of file" }
! { dg-do compile }
! { dg-options "-std=f2008 -fcoarray=single" }
! PR fortran/38936
! Check for error with coindexed target.
PROGRAM main
IMPLICIT NONE
INTEGER :: a[*]
ASSOCIATE (x => a[1]) ! { dg-error "must not be coindexed" }
END PROGRAM main
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment