+2004-07-16 Tobias Schlueter <tobias.schlueter@physik.uni-muenchen.de>
+
+ PR fortran/16404
+ (parts ported from g95)
+ * parse.h (gfc_state_data): New field do_variable.
+ (gfc_check_do_variable): Add prototype.
+ * parse.c (push_state): Initialize field 'do_variable'.
+ (gfc_check_do_variable): New function.
+ (parse_do_block): Remember do iterator variable.
+ (parse_file): Initialize field 'do_variable'.
+ * match.c (gfc_match_assignment, gfc_match_do,
+ gfc_match_allocate, gfc_match_nullify, gfc_match_deallocate):
+ Add previously missing checks.
+ (gfc_match_return): Reformat error message.
+ * io.c (match_out_tag): New function.
+ (match_open_element, match_close_element,
+ match_file_element, match_dt_element): Call match_out_tag
+ instead of match_vtag where appropriate.
+ (match_io_iterator, match_io_element): Add missing check.
+ (match_io): Reformat error message.
+ (match_inquire_element): Call match_out_tag where appropriate.
+
2004-07-15 Tobias Schlueter <tobias.schlueter@physik.uni-muenchen.de>
PR fortran/15129
}
+/* Match I/O tags that cause variables to become redefined. */
+
+static match
+match_out_tag(const io_tag *tag, gfc_expr **result)
+{
+ match m;
+
+ m = match_vtag(tag, result);
+ if (m == MATCH_YES)
+ gfc_check_do_variable((*result)->symtree);
+
+ return m;
+}
+
+
/* Match a label I/O tag. */
static match
m = match_etag (&tag_unit, &open->unit);
if (m != MATCH_NO)
return m;
- m = match_vtag (&tag_iostat, &open->iostat);
+ m = match_out_tag (&tag_iostat, &open->iostat);
if (m != MATCH_NO)
return m;
m = match_etag (&tag_file, &open->file);
m = match_etag (&tag_status, &close->status);
if (m != MATCH_NO)
return m;
- m = match_vtag (&tag_iostat, &close->iostat);
+ m = match_out_tag (&tag_iostat, &close->iostat);
if (m != MATCH_NO)
return m;
m = match_ltag (&tag_err, &close->err);
m = match_etag (&tag_unit, &fp->unit);
if (m != MATCH_NO)
return m;
- m = match_vtag (&tag_iostat, &fp->iostat);
+ m = match_out_tag (&tag_iostat, &fp->iostat);
if (m != MATCH_NO)
return m;
m = match_ltag (&tag_err, &fp->err);
m = match_etag (&tag_rec, &dt->rec);
if (m != MATCH_NO)
return m;
- m = match_vtag (&tag_iostat, &dt->iostat);
+ m = match_out_tag (&tag_iostat, &dt->iostat);
if (m != MATCH_NO)
return m;
m = match_ltag (&tag_err, &dt->err);
m = match_etag (&tag_advance, &dt->advance);
if (m != MATCH_NO)
return m;
- m = match_vtag (&tag_size, &dt->size);
+ m = match_out_tag (&tag_size, &dt->size);
if (m != MATCH_NO)
return m;
if (m == MATCH_ERROR)
goto cleanup;
if (m == MATCH_YES)
- break;
+ {
+ gfc_check_do_variable (iter->var->symtree);
+ break;
+ }
m = match_io_element (k, &new);
if (m == MATCH_ERROR)
m = MATCH_ERROR;
}
+ if (gfc_check_do_variable (expr->symtree))
+ m = MATCH_ERROR;
+
break;
case M_WRITE:
if (!comma_flag
&& gfc_match_char (',') == MATCH_YES
&& k == M_WRITE
- && gfc_notify_std (GFC_STD_GNU, "Comma before output item list "
- "at %C is an extension") == FAILURE)
+ && gfc_notify_std (GFC_STD_GNU, "Extension: Comma before output "
+ "item list at %C is an extension") == FAILURE)
return MATCH_ERROR;
io_code = NULL;
m = match_etag (&tag_unit, &inquire->unit);
RETM m = match_etag (&tag_file, &inquire->file);
RETM m = match_ltag (&tag_err, &inquire->err);
- RETM m = match_vtag (&tag_iostat, &inquire->iostat);
+ RETM m = match_out_tag (&tag_iostat, &inquire->iostat);
RETM m = match_vtag (&tag_exist, &inquire->exist);
RETM m = match_vtag (&tag_opened, &inquire->opened);
RETM m = match_vtag (&tag_named, &inquire->named);
RETM m = match_vtag (&tag_name, &inquire->name);
- RETM m = match_vtag (&tag_number, &inquire->number);
+ RETM m = match_out_tag (&tag_number, &inquire->number);
RETM m = match_vtag (&tag_s_access, &inquire->access);
RETM m = match_vtag (&tag_sequential, &inquire->sequential);
RETM m = match_vtag (&tag_direct, &inquire->direct);
RETM m = match_vtag (&tag_s_form, &inquire->form);
RETM m = match_vtag (&tag_formatted, &inquire->formatted);
RETM m = match_vtag (&tag_unformatted, &inquire->unformatted);
- RETM m = match_vtag (&tag_s_recl, &inquire->recl);
- RETM m = match_vtag (&tag_nextrec, &inquire->nextrec);
+ RETM m = match_out_tag (&tag_s_recl, &inquire->recl);
+ RETM m = match_out_tag (&tag_nextrec, &inquire->nextrec);
RETM m = match_vtag (&tag_s_blank, &inquire->blank);
RETM m = match_vtag (&tag_s_position, &inquire->position);
RETM m = match_vtag (&tag_s_action, &inquire->action);
if (m != MATCH_YES)
goto cleanup;
+ if (lvalue->symtree->n.sym->attr.flavor == FL_PARAMETER)
+ {
+ gfc_error ("Cannot assign to a PARAMETER variable at %C");
+ m = MATCH_ERROR;
+ goto cleanup;
+ }
+
m = gfc_match (" %e%t", &rvalue);
if (m != MATCH_YES)
goto cleanup;
new_st.expr = lvalue;
new_st.expr2 = rvalue;
+ gfc_check_do_variable (lvalue->symtree);
+
return MATCH_YES;
cleanup:
if (m == MATCH_ERROR)
goto cleanup;
+ gfc_check_do_variable (iter.var->symtree);
+
if (gfc_match_eos () != MATCH_YES)
{
gfc_syntax_error (ST_DO);
if (m == MATCH_ERROR)
goto cleanup;
+ if (gfc_check_do_variable (tail->expr->symtree))
+ goto cleanup;
+
if (gfc_pure (NULL)
&& gfc_impure_variable (tail->expr->symtree->n.sym))
{
"procedure");
goto cleanup;
}
+
+ if (stat->symtree->n.sym->attr.flavor != FL_VARIABLE)
+ {
+ gfc_error("STAT expression at %C must be a variable");
+ goto cleanup;
+ }
+
+ gfc_check_do_variable(stat->symtree);
}
if (gfc_match (" )%t") != MATCH_YES)
if (m == MATCH_NO)
goto syntax;
+ if (gfc_check_do_variable(p->symtree))
+ goto cleanup;
+
if (gfc_pure (NULL) && gfc_impure_variable (p->symtree->n.sym))
{
gfc_error
if (m == MATCH_NO)
goto syntax;
+ if (gfc_check_do_variable (tail->expr->symtree))
+ goto cleanup;
+
if (gfc_pure (NULL)
&& gfc_impure_variable (tail->expr->symtree->n.sym))
{
break;
}
- if (stat != NULL && stat->symtree->n.sym->attr.intent == INTENT_IN)
+ if (stat != NULL)
{
- gfc_error ("STAT variable '%s' of DEALLOCATE statement at %C cannot be "
- "INTENT(IN)", stat->symtree->n.sym->name);
- goto cleanup;
+ if (stat->symtree->n.sym->attr.intent == INTENT_IN)
+ {
+ gfc_error ("STAT variable '%s' of DEALLOCATE statement at %C "
+ "cannot be INTENT(IN)", stat->symtree->n.sym->name);
+ goto cleanup;
+ }
+
+ if (gfc_pure(NULL) && gfc_impure_variable (stat->symtree->n.sym))
+ {
+ gfc_error ("Illegal STAT variable in DEALLOCATE statement at %C "
+ "for a PURE procedure");
+ goto cleanup;
+ }
+
+ if (stat->symtree->n.sym->attr.flavor != FL_VARIABLE)
+ {
+ gfc_error("STAT expression at %C must be a variable");
+ goto cleanup;
+ }
+
+ gfc_check_do_variable(stat->symtree);
}
if (gfc_match (" )%t") != MATCH_YES)
gfc_enclosing_unit (&s);
if (s == COMP_PROGRAM
- && gfc_notify_std (GFC_STD_GNU, "RETURN statement in a main "
- "program at %C is an extension.") == FAILURE)
+ && gfc_notify_std (GFC_STD_GNU, "Extension: RETURN statement in "
+ "main program at %C") == FAILURE)
return MATCH_ERROR;
e = NULL;
p->previous = gfc_state_stack;
p->sym = sym;
p->head = p->tail = NULL;
+ p->do_variable = NULL;
gfc_state_stack = p;
}
}
+/* 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
+ iterator, we generate an error message and return nonzero. */
+
+int
+gfc_check_do_variable (gfc_symtree *st)
+{
+ gfc_state_data *s;
+
+ for (s=gfc_state_stack; s; s = s->previous)
+ if (s->do_variable == st)
+ {
+ gfc_error_now("Variable '%s' at %C cannot be redefined inside "
+ "loop beginning at %L", st->name, &s->tail->loc);
+ return 1;
+ }
+
+ return 0;
+}
+
+
/* Checks to see if the current statement label closes an enddo.
Returns 0 if not, 1 if closes an ENDDO correctly, or 2 (and issues
an error) if it incorrectly closes an ENDDO. */
gfc_statement st;
gfc_code *top;
gfc_state_data s;
+ gfc_symtree *stree;
s.ext.end_do_label = new_st.label;
+ if (new_st.ext.iterator != NULL)
+ stree = new_st.ext.iterator->var->symtree;
+ else
+ stree = NULL;
+
accept_statement (ST_DO);
top = gfc_state_stack->tail;
push_state (&s, COMP_DO, gfc_new_block);
+ s.do_variable = stree;
+
top->block = new_level (top);
top->block->op = EXEC_DO;
top.sym = NULL;
top.previous = NULL;
top.head = top.tail = NULL;
+ top.do_variable = NULL;
gfc_state_stack = ⊤
{
gfc_compile_state state;
gfc_symbol *sym; /* Block name associated with this level */
+ gfc_symtree *do_variable; /* For DO blocks the iterator variable. */
+
struct gfc_code *head, *tail;
struct gfc_state_data *previous;
#define gfc_current_block() (gfc_state_stack->sym)
#define gfc_current_state() (gfc_state_stack->state)
+int gfc_check_do_variable (gfc_symtree *);
try gfc_find_state (gfc_compile_state);
gfc_state_data *gfc_enclosing_unit (gfc_compile_state *);
const char *gfc_ascii_statement (gfc_statement);