diff options
author | Daniel Kraft <d@domob.eu> | 2010-09-23 10:37:54 +0200 |
---|---|---|
committer | Daniel Kraft <domob@gcc.gnu.org> | 2010-09-23 10:37:54 +0200 |
commit | 8c91ab34b56a860e60459d56b488054774d4f6ee (patch) | |
tree | 67d09d55027e1b23ccff6e1f28d4f0e70c767536 /gcc/fortran | |
parent | 42d9f9dd0f1f957a29afcefb29299f327643a008 (diff) | |
download | gcc-8c91ab34b56a860e60459d56b488054774d4f6ee.zip gcc-8c91ab34b56a860e60459d56b488054774d4f6ee.tar.gz gcc-8c91ab34b56a860e60459d56b488054774d4f6ee.tar.bz2 |
re PR fortran/38936 ([F03] ASSOCIATE construct / improved SELECT TYPE (a=>expr))
2010-09-23 Daniel Kraft <d@domob.eu>
PR fortran/38936
PR fortran/44044
PR fortran/45474
* gfortran.h (gfc_check_vardef_context): New method.
(struct symbol_attribute): New flag `select_type_temporary'.
* primary.c (gfc_variable_attr): Clarify initialization of ref.
(match_variable): Remove PROTECTED check and assignment check
for PARAMETERs (this is now done later).
* match.c (gfc_match_iterator): Remove INTENT(IN) check.
(gfc_match_associate): Defer initialization of newAssoc->variable.
(gfc_match_nullify): Remove PURE definability check.
(select_type_set_tmp): Set new `select_type_temporary' flag.
* expr.c (gfc_check_assign): Remove INTENT(IN) check here.
(gfc_check_pointer_assign): Ditto (and other checks removed).
(gfc_check_vardef_context): New method.
* interface.c (compare_parameter_protected): Removed.
(compare_actual_formal): Use `gfc_check_vardef_context' for checks
related to INTENT([IN]OUT) arguments.
* intrinsic.c (check_arglist): Check INTENT for intrinsics.
* resolve.c (gfc_resolve_iterator): Use `gfc_check_vardef_context'.
(remove_last_array_ref): New method.
(resolve_deallocate_expr), (resolve_allocate_expr): Ditto.
(resolve_allocate_deallocate): Ditto (for STAT and ERRMSG).
(resolve_assoc_var): Remove checks for definability here.
(resolve_select_type): Handle resolving of code->block here.
(resolve_ordinary_assign): Remove PURE check.
(resolve_code): Do not resolve code->blocks for SELECT TYPE here.
Use `gfc_check_vardef_context' for assignments and pointer-assignments.
2010-09-23 Daniel Kraft <d@domob.eu>
PR fortran/38936
PR fortran/44044
PR fortran/45474
* gfortran.dg/intrinsic_intent_1.f03: New test.
* gfortran.dg/select_type_17.f03: New test.
* gfortran.dg/associate_5.f03: More definability tests.
* gfortran.dg/enum_2.f90: Check definability.
* gfortran.dg/allocatable_dummy_2.f90: Change expected error message.
* gfortran.dg/allocate_alloc_opt_2.f90: Ditto.
* gfortran.dg/char_expr_2.f90: Ditto.
* gfortran.dg/deallocate_alloc_opt_2.f90: Ditto.
* gfortran.dg/enum_5.f90: Ditto.
* gfortran.dg/equiv_constraint_8.f90: Ditto.
* gfortran.dg/impure_assignment_2.f90: Ditto.
* gfortran.dg/impure_assignment_3.f90: Ditto.
* gfortran.dg/intent_out_1.f90: Ditto.
* gfortran.dg/intent_out_3.f90: Ditto.
* gfortran.dg/pointer_assign_7.f90: Ditto.
* gfortran.dg/pointer_intent_3.f90: Ditto.
* gfortran.dg/pr19936_1.f90: Ditto.
* gfortran.dg/proc_ptr_comp_3.f90: Ditto.
* gfortran.dg/simpleif_2.f90: Ditto.
* gfortran.dg/protected_5.f90: Ditto.
* gfortran.dg/protected_4.f90: Ditto and remove invalid error check.
* gfortran.dg/protected_6.f90: Ditto.
* gfortran.dg/protected_7.f90: Ditto.
From-SVN: r164550
Diffstat (limited to 'gcc/fortran')
-rw-r--r-- | gcc/fortran/ChangeLog | 31 | ||||
-rw-r--r-- | gcc/fortran/expr.c | 233 | ||||
-rw-r--r-- | gcc/fortran/gfortran.h | 4 | ||||
-rw-r--r-- | gcc/fortran/interface.c | 61 | ||||
-rw-r--r-- | gcc/fortran/intrinsic.c | 13 | ||||
-rw-r--r-- | gcc/fortran/match.c | 18 | ||||
-rw-r--r-- | gcc/fortran/primary.c | 35 | ||||
-rw-r--r-- | gcc/fortran/resolve.c | 181 |
8 files changed, 356 insertions, 220 deletions
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 8fbff60d..2860897 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,34 @@ +2010-09-23 Daniel Kraft <d@domob.eu> + + PR fortran/38936 + PR fortran/44044 + PR fortran/45474 + * gfortran.h (gfc_check_vardef_context): New method. + (struct symbol_attribute): New flag `select_type_temporary'. + * primary.c (gfc_variable_attr): Clarify initialization of ref. + (match_variable): Remove PROTECTED check and assignment check + for PARAMETERs (this is now done later). + * match.c (gfc_match_iterator): Remove INTENT(IN) check. + (gfc_match_associate): Defer initialization of newAssoc->variable. + (gfc_match_nullify): Remove PURE definability check. + (select_type_set_tmp): Set new `select_type_temporary' flag. + * expr.c (gfc_check_assign): Remove INTENT(IN) check here. + (gfc_check_pointer_assign): Ditto (and other checks removed). + (gfc_check_vardef_context): New method. + * interface.c (compare_parameter_protected): Removed. + (compare_actual_formal): Use `gfc_check_vardef_context' for checks + related to INTENT([IN]OUT) arguments. + * intrinsic.c (check_arglist): Check INTENT for intrinsics. + * resolve.c (gfc_resolve_iterator): Use `gfc_check_vardef_context'. + (remove_last_array_ref): New method. + (resolve_deallocate_expr), (resolve_allocate_expr): Ditto. + (resolve_allocate_deallocate): Ditto (for STAT and ERRMSG). + (resolve_assoc_var): Remove checks for definability here. + (resolve_select_type): Handle resolving of code->block here. + (resolve_ordinary_assign): Remove PURE check. + (resolve_code): Do not resolve code->blocks for SELECT TYPE here. + Use `gfc_check_vardef_context' for assignments and pointer-assignments. + 2010-08-22 Ralf Wildenhues <Ralf.Wildenhues@gmx.de> * gfortran.texi (Argument list functions): Allow URL to wrap. diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c index 76ceec9..5711634 100644 --- a/gcc/fortran/expr.c +++ b/gcc/fortran/expr.c @@ -3043,10 +3043,8 @@ gfc_check_assign (gfc_expr *lvalue, gfc_expr *rvalue, int conform) sym = lvalue->symtree->n.sym; - /* Check INTENT(IN), unless the object itself is the component or - sub-component of a pointer. */ + /* See if this is the component or subcomponent of a pointer. */ has_pointer = sym->attr.pointer; - for (ref = lvalue->ref; ref; ref = ref->next) if (ref->type == REF_COMPONENT && ref->u.c.component->attr.pointer) { @@ -3054,13 +3052,6 @@ gfc_check_assign (gfc_expr *lvalue, gfc_expr *rvalue, int conform) break; } - if (!has_pointer && sym->attr.intent == INTENT_IN) - { - gfc_error ("Cannot assign to INTENT(IN) variable '%s' at %L", - sym->name, &lvalue->where); - return FAILURE; - } - /* 12.5.2.2, Note 12.26: The result variable is very similar to any other variable local to a function subprogram. Its existence begins when execution of the function is initiated and ends when execution of the @@ -3239,7 +3230,7 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue) symbol_attribute attr; gfc_ref *ref; bool is_pure, rank_remap; - int pointer, check_intent_in, proc_pointer; + int proc_pointer; if (lvalue->symtree->n.sym->ts.type == BT_UNKNOWN && !lvalue->symtree->n.sym->attr.proc_pointer) @@ -3259,24 +3250,13 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue) return FAILURE; } - - /* Check INTENT(IN), unless the object itself is the component or - sub-component of a pointer. */ - check_intent_in = 1; - pointer = lvalue->symtree->n.sym->attr.pointer; proc_pointer = lvalue->symtree->n.sym->attr.proc_pointer; rank_remap = false; for (ref = lvalue->ref; ref; ref = ref->next) { - if (pointer) - check_intent_in = 0; - if (ref->type == REF_COMPONENT) - { - pointer = ref->u.c.component->attr.pointer; - proc_pointer = ref->u.c.component->attr.proc_pointer; - } + proc_pointer = ref->u.c.component->attr.proc_pointer; if (ref->type == REF_ARRAY && ref->next == NULL) { @@ -3332,30 +3312,8 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue) } } - if (check_intent_in && lvalue->symtree->n.sym->attr.intent == INTENT_IN) - { - gfc_error ("Cannot assign to INTENT(IN) variable '%s' at %L", - lvalue->symtree->n.sym->name, &lvalue->where); - return FAILURE; - } - - if (!pointer && !proc_pointer - && !(lvalue->ts.type == BT_CLASS - && CLASS_DATA (lvalue)->attr.class_pointer)) - { - gfc_error ("Pointer assignment to non-POINTER at %L", &lvalue->where); - return FAILURE; - } - is_pure = gfc_pure (NULL); - if (is_pure && gfc_impure_variable (lvalue->symtree->n.sym) - && lvalue->symtree->n.sym->value != rvalue) - { - gfc_error ("Bad pointer object in PURE procedure at %L", &lvalue->where); - return FAILURE; - } - /* If rvalue is a NULL() or NULLIFY, we're done. Otherwise the type, kind, etc for lvalue and rvalue must match, and rvalue must be a pure variable if we're in a pure function. */ @@ -4338,3 +4296,188 @@ gfc_build_intrinsic_call (const char* name, locus where, unsigned numarg, ...) return result; } + + +/* Check if an expression may appear in a variable definition context + (F2008, 16.6.7) or pointer association context (F2008, 16.6.8). + This is called from the various places when resolving + the pieces that make up such a context. + + Optionally, a possible error message can be suppressed if context is NULL + and just the return status (SUCCESS / FAILURE) be requested. */ + +gfc_try +gfc_check_vardef_context (gfc_expr* e, bool pointer, const char* context) +{ + gfc_symbol* sym; + bool is_pointer; + bool check_intentin; + bool ptr_component; + symbol_attribute attr; + gfc_ref* ref; + + if (e->expr_type != EXPR_VARIABLE) + { + if (context) + gfc_error ("Non-variable expression in variable definition context (%s)" + " at %L", context, &e->where); + return FAILURE; + } + + gcc_assert (e->symtree); + sym = e->symtree->n.sym; + + if (!pointer && sym->attr.flavor == FL_PARAMETER) + { + if (context) + gfc_error ("Named constant '%s' in variable definition context (%s)" + " at %L", sym->name, context, &e->where); + return FAILURE; + } + if (!pointer && sym->attr.flavor != FL_VARIABLE + && !(sym->attr.flavor == FL_PROCEDURE && sym == sym->result) + && !(sym->attr.flavor == FL_PROCEDURE && sym->attr.proc_pointer)) + { + if (context) + gfc_error ("'%s' in variable definition context (%s) at %L is not" + " a variable", sym->name, context, &e->where); + return FAILURE; + } + + /* Find out whether the expr is a pointer; this also means following + component references to the last one. */ + attr = gfc_expr_attr (e); + is_pointer = (attr.pointer || attr.proc_pointer); + if (pointer && !is_pointer) + { + if (context) + gfc_error ("Non-POINTER in pointer association context (%s)" + " at %L", context, &e->where); + return FAILURE; + } + + /* INTENT(IN) dummy argument. Check this, unless the object itself is + the component of sub-component of a pointer. Obviously, + procedure pointers are of no interest here. */ + check_intentin = true; + ptr_component = sym->attr.pointer; + for (ref = e->ref; ref && check_intentin; ref = ref->next) + { + if (ptr_component && ref->type == REF_COMPONENT) + check_intentin = false; + if (ref->type == REF_COMPONENT && ref->u.c.component->attr.pointer) + ptr_component = true; + } + if (check_intentin && sym->attr.intent == INTENT_IN) + { + if (pointer && is_pointer) + { + if (context) + gfc_error ("Dummy argument '%s' with INTENT(IN) in pointer" + " association context (%s) at %L", + sym->name, context, &e->where); + return FAILURE; + } + if (!pointer && !is_pointer) + { + if (context) + gfc_error ("Dummy argument '%s' with INTENT(IN) in variable" + " definition context (%s) at %L", + sym->name, context, &e->where); + return FAILURE; + } + } + + /* PROTECTED and use-associated. */ + if (sym->attr.is_protected && sym->attr.use_assoc) + { + if (pointer && is_pointer) + { + if (context) + gfc_error ("Variable '%s' is PROTECTED and can not appear in a" + " pointer association context (%s) at %L", + sym->name, context, &e->where); + return FAILURE; + } + if (!pointer && !is_pointer) + { + if (context) + gfc_error ("Variable '%s' is PROTECTED and can not appear in a" + " variable definition context (%s) at %L", + sym->name, context, &e->where); + return FAILURE; + } + } + + /* Variable not assignable from a PURE procedure but appears in + variable definition context. */ + if (!pointer && gfc_pure (NULL) && gfc_impure_variable (sym)) + { + if (context) + gfc_error ("Variable '%s' can not appear in a variable definition" + " context (%s) at %L in PURE procedure", + sym->name, context, &e->where); + return FAILURE; + } + + /* Check variable definition context for associate-names. */ + if (!pointer && sym->assoc) + { + const char* name; + gfc_association_list* assoc; + + gcc_assert (sym->assoc->target); + + /* If this is a SELECT TYPE temporary (the association is used internally + for SELECT TYPE), silently go over to the target. */ + if (sym->attr.select_type_temporary) + { + gfc_expr* t = sym->assoc->target; + + gcc_assert (t->expr_type == EXPR_VARIABLE); + name = t->symtree->name; + + if (t->symtree->n.sym->assoc) + assoc = t->symtree->n.sym->assoc; + else + assoc = sym->assoc; + } + else + { + name = sym->name; + assoc = sym->assoc; + } + gcc_assert (name && assoc); + + /* Is association to a valid variable? */ + if (!assoc->variable) + { + if (context) + { + if (assoc->target->expr_type == EXPR_VARIABLE) + gfc_error ("'%s' at %L associated to vector-indexed target can" + " not be used in a variable definition context (%s)", + name, &e->where, context); + else + gfc_error ("'%s' at %L associated to expression can" + " not be used in a variable definition context (%s)", + name, &e->where, context); + } + return FAILURE; + } + + /* Target must be allowed to appear in a variable definition context. */ + if (gfc_check_vardef_context (assoc->target, pointer, NULL) == FAILURE) + { + if (context) + gfc_error ("Associate-name '%s' can not appear in a variable" + " definition context (%s) at %L because its target" + " at %L can not, either", + name, context, &e->where, + &assoc->target->where); + return FAILURE; + } + } + + return SUCCESS; +} diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 947f1ff..94b2b19 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -784,6 +784,9 @@ typedef struct unsigned alloc_comp:1, pointer_comp:1, proc_pointer_comp:1, private_comp:1, zero_comp:1, coarray_comp:1; + /* This is a temporary selector for SELECT TYPE. */ + unsigned select_type_temporary:1; + /* Attributes set by compiler extensions (!GCC$ ATTRIBUTES). */ unsigned ext_attr:EXT_ATTR_NUM; @@ -2726,6 +2729,7 @@ bool gfc_has_ultimate_allocatable (gfc_expr *); bool gfc_has_ultimate_pointer (gfc_expr *); gfc_expr* gfc_build_intrinsic_call (const char*, locus, unsigned, ...); +gfc_try gfc_check_vardef_context (gfc_expr*, bool, const char*); /* st.c */ diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c index 044ccd6..5024fe8 100644 --- a/gcc/fortran/interface.c +++ b/gcc/fortran/interface.c @@ -1655,36 +1655,6 @@ compare_parameter (gfc_symbol *formal, gfc_expr *actual, } -/* Given a symbol of a formal argument list and an expression, see if - the two are compatible as arguments. Returns nonzero if - compatible, zero if not compatible. */ - -static int -compare_parameter_protected (gfc_symbol *formal, gfc_expr *actual) -{ - if (actual->expr_type != EXPR_VARIABLE) - return 1; - - if (!actual->symtree->n.sym->attr.is_protected) - return 1; - - if (!actual->symtree->n.sym->attr.use_assoc) - return 1; - - if (formal->attr.intent == INTENT_IN - || formal->attr.intent == INTENT_UNKNOWN) - return 1; - - if (!actual->symtree->n.sym->attr.pointer) - return 0; - - if (actual->symtree->n.sym->attr.pointer && formal->attr.pointer) - return 0; - - return 1; -} - - /* Returns the storage size of a symbol (formal argument) or zero if it cannot be determined. */ @@ -2205,27 +2175,20 @@ compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal, } /* Check intent = OUT/INOUT for definable actual argument. */ - if ((a->expr->expr_type != EXPR_VARIABLE - || (a->expr->symtree->n.sym->attr.flavor != FL_VARIABLE - && a->expr->symtree->n.sym->attr.flavor != FL_PROCEDURE)) - && (f->sym->attr.intent == INTENT_OUT - || f->sym->attr.intent == INTENT_INOUT)) + if ((f->sym->attr.intent == INTENT_OUT + || f->sym->attr.intent == INTENT_INOUT)) { - if (where) - gfc_error ("Actual argument at %L must be definable as " - "the dummy argument '%s' is INTENT = OUT/INOUT", - &a->expr->where, f->sym->name); - return 0; - } + const char* context = (where + ? _("actual argument to INTENT = OUT/INOUT") + : NULL); - if (!compare_parameter_protected(f->sym, a->expr)) - { - if (where) - gfc_error ("Actual argument at %L is use-associated with " - "PROTECTED attribute and dummy argument '%s' is " - "INTENT = OUT/INOUT", - &a->expr->where,f->sym->name); - return 0; + if (f->sym->attr.pointer + && gfc_check_vardef_context (a->expr, true, context) + == FAILURE) + return 0; + if (gfc_check_vardef_context (a->expr, false, context) + == FAILURE) + return 0; } if ((f->sym->attr.intent == INTENT_OUT diff --git a/gcc/fortran/intrinsic.c b/gcc/fortran/intrinsic.c index 9c69d7d..795c8ca 100644 --- a/gcc/fortran/intrinsic.c +++ b/gcc/fortran/intrinsic.c @@ -3585,6 +3585,19 @@ check_arglist (gfc_actual_arglist **ap, gfc_intrinsic_sym *sym, gfc_typename (&actual->expr->ts)); return FAILURE; } + + /* If the formal argument is INTENT([IN]OUT), check for definability. */ + if (formal->intent == INTENT_INOUT || formal->intent == INTENT_OUT) + { + const char* context = (error_flag + ? _("actual argument to INTENT = OUT/INOUT") + : NULL); + + /* No pointer arguments for intrinsics. */ + if (gfc_check_vardef_context (actual->expr, false, context) + == FAILURE) + return FAILURE; + } } return SUCCESS; diff --git a/gcc/fortran/match.c b/gcc/fortran/match.c index ff0ef44..836c95c 100644 --- a/gcc/fortran/match.c +++ b/gcc/fortran/match.c @@ -978,13 +978,6 @@ gfc_match_iterator (gfc_iterator *iter, int init_flag) goto cleanup; } - if (var->symtree->n.sym->attr.intent == INTENT_IN) - { - gfc_error ("Loop variable '%s' at %C cannot be INTENT(IN)", - var->symtree->n.sym->name); - goto cleanup; - } - gfc_match_char ('='); var->symtree->n.sym->attr.implied_index = 1; @@ -1847,9 +1840,7 @@ gfc_match_associate (void) /* The `variable' field is left blank for now; because the target is not yet resolved, we can't use gfc_has_vector_subscript to determine it - for now. Instead, if the symbol is matched as variable, this field - is set -- and during resolution we check that. */ - newAssoc->variable = 0; + for now. This is set during resolution. */ /* Put it into the list. */ newAssoc->next = new_st.ext.block.assoc; @@ -3166,12 +3157,6 @@ gfc_match_nullify (void) if (gfc_check_do_variable (p->symtree)) goto cleanup; - if (gfc_pure (NULL) && gfc_impure_variable (p->symtree->n.sym)) - { - gfc_error ("Illegal variable in NULLIFY at %C for a PURE procedure"); - goto cleanup; - } - /* build ' => NULL() '. */ e = gfc_get_null_expr (&gfc_current_locus); @@ -4523,6 +4508,7 @@ select_type_set_tmp (gfc_typespec *ts) &tmp->n.sym->as, false); tmp->n.sym->attr.class_ok = 1; } + tmp->n.sym->attr.select_type_temporary = 1; /* Add an association for it, so the rest of the parser knows it is an associate-name. The target will be set during resolution. */ diff --git a/gcc/fortran/primary.c b/gcc/fortran/primary.c index b07632d..f6ceae9 100644 --- a/gcc/fortran/primary.c +++ b/gcc/fortran/primary.c @@ -2007,7 +2007,6 @@ gfc_variable_attr (gfc_expr *expr, gfc_typespec *ts) if (expr->expr_type != EXPR_VARIABLE && expr->expr_type != EXPR_FUNCTION) gfc_internal_error ("gfc_variable_attr(): Expression isn't a variable"); - ref = expr->ref; sym = expr->symtree->n.sym; attr = sym->attr; @@ -2031,7 +2030,7 @@ gfc_variable_attr (gfc_expr *expr, gfc_typespec *ts) if (ts != NULL && expr->ts.type == BT_UNKNOWN) *ts = sym->ts; - for (; ref; ref = ref->next) + for (ref = expr->ref; ref; ref = ref->next) switch (ref->type) { case REF_ARRAY: @@ -2986,13 +2985,7 @@ match_variable (gfc_expr **result, int equiv_flag, int host_flag) switch (sym->attr.flavor) { case FL_VARIABLE: - if (sym->attr.is_protected && sym->attr.use_assoc) - { - gfc_error ("Assigning to PROTECTED variable at %C"); - return MATCH_ERROR; - } - if (sym->assoc) - sym->assoc->variable = 1; + /* Everything is alright. */ break; case FL_UNKNOWN: @@ -3024,22 +3017,24 @@ match_variable (gfc_expr **result, int equiv_flag, int host_flag) case FL_PARAMETER: if (equiv_flag) - gfc_error ("Named constant at %C in an EQUIVALENCE"); - else - gfc_error ("Cannot assign to a named constant at %C"); - return MATCH_ERROR; + { + gfc_error ("Named constant at %C in an EQUIVALENCE"); + return MATCH_ERROR; + } + /* Otherwise this is checked for and an error given in the + variable definition context checks. */ break; case FL_PROCEDURE: /* Check for a nonrecursive function result variable. */ if (sym->attr.function - && !sym->attr.external - && sym->result == sym - && (gfc_is_function_return_value (sym, gfc_current_ns) - || (sym->attr.entry - && sym->ns == gfc_current_ns) - || (sym->attr.entry - && sym->ns == gfc_current_ns->parent))) + && !sym->attr.external + && sym->result == sym + && (gfc_is_function_return_value (sym, gfc_current_ns) + || (sym->attr.entry + && sym->ns == gfc_current_ns) + || (sym->attr.entry + && sym->ns == gfc_current_ns->parent))) { /* If a function result is a derived type, then the derived type may still have to be resolved. */ diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index 2d5e04f..30ca7ce 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -2859,8 +2859,6 @@ gfc_iso_c_func_interface (gfc_symbol *sym, gfc_actual_arglist *args, /* Resolve a function call, which means resolving the arguments, then figuring out which entity the name refers to. */ -/* TODO: Check procedure arguments so that an INTENT(IN) isn't passed - to INTENT(OUT) or INTENT(INOUT). */ static gfc_try resolve_function (gfc_expr *expr) @@ -6131,12 +6129,9 @@ gfc_resolve_iterator (gfc_iterator *iter, bool real_ok) == FAILURE) return FAILURE; - if (gfc_pure (NULL) && gfc_impure_variable (iter->var->symtree->n.sym)) - { - gfc_error ("Cannot assign to loop variable in PURE procedure at %L", - &iter->var->where); - return FAILURE; - } + if (gfc_check_vardef_context (iter->var, false, _("iterator variable")) + == FAILURE) + return FAILURE; if (gfc_resolve_iterator_expr (iter->start, real_ok, "Start expression in DO loop") == FAILURE) @@ -6331,14 +6326,11 @@ static gfc_try resolve_deallocate_expr (gfc_expr *e) { symbol_attribute attr; - int allocatable, pointer, check_intent_in; + int allocatable, pointer; gfc_ref *ref; gfc_symbol *sym; gfc_component *c; - /* Check INTENT(IN), unless the object is a sub-component of a pointer. */ - check_intent_in = 1; - if (gfc_resolve_expr (e) == FAILURE) return FAILURE; @@ -6359,9 +6351,6 @@ resolve_deallocate_expr (gfc_expr *e) } for (ref = e->ref; ref; ref = ref->next) { - if (pointer) - check_intent_in = 0; - switch (ref->type) { case REF_ARRAY: @@ -6399,12 +6388,11 @@ resolve_deallocate_expr (gfc_expr *e) return FAILURE; } - if (check_intent_in && sym->attr.intent == INTENT_IN) - { - gfc_error ("Cannot deallocate INTENT(IN) variable '%s' at %L", - sym->name, &e->where); - return FAILURE; - } + if (pointer + && gfc_check_vardef_context (e, true, _("DEALLOCATE object")) == FAILURE) + return FAILURE; + if (gfc_check_vardef_context (e, false, _("DEALLOCATE object")) == FAILURE) + return FAILURE; if (e->ts.type == BT_CLASS) { @@ -6464,6 +6452,31 @@ gfc_expr_to_initialize (gfc_expr *e) } +/* If the last ref of an expression is an array ref, return a copy of the + expression with that one removed. Otherwise, a copy of the original + expression. This is used for allocate-expressions and pointer assignment + LHS, where there may be an array specification that needs to be stripped + off when using gfc_check_vardef_context. */ + +static gfc_expr* +remove_last_array_ref (gfc_expr* e) +{ + gfc_expr* e2; + gfc_ref** r; + + e2 = gfc_copy_expr (e); + for (r = &e2->ref; *r; r = &(*r)->next) + if ((*r)->type == REF_ARRAY && !(*r)->next) + { + gfc_free_ref_list (*r); + *r = NULL; + break; + } + + return e2; +} + + /* Used in resolve_allocate_expr to check that a allocation-object and a source-expr are conformable. This does not catch all possible cases; in particular a runtime checking is needed. */ @@ -6526,17 +6539,16 @@ conformable_arrays (gfc_expr *e1, gfc_expr *e2) static gfc_try resolve_allocate_expr (gfc_expr *e, gfc_code *code) { - int i, pointer, allocatable, dimension, check_intent_in, is_abstract; + int i, pointer, allocatable, dimension, is_abstract; int codimension; symbol_attribute attr; gfc_ref *ref, *ref2; + gfc_expr *e2; gfc_array_ref *ar; gfc_symbol *sym = NULL; gfc_alloc *a; gfc_component *c; - - /* Check INTENT(IN), unless the object is a sub-component of a pointer. */ - check_intent_in = 1; + gfc_try t; /* Mark the ultimost array component as being in allocate to allow DIMEN_STAR checking of coarrays. */ @@ -6588,9 +6600,6 @@ resolve_allocate_expr (gfc_expr *e, gfc_code *code) for (ref = e->ref; ref; ref2 = ref, ref = ref->next) { - if (pointer) - check_intent_in = 0; - switch (ref->type) { case REF_ARRAY: @@ -6677,12 +6686,18 @@ resolve_allocate_expr (gfc_expr *e, gfc_code *code) goto failure; } - if (check_intent_in && sym->attr.intent == INTENT_IN) - { - gfc_error ("Cannot allocate INTENT(IN) variable '%s' at %L", - sym->name, &e->where); - goto failure; - } + /* In the variable definition context checks, gfc_expr_attr is used + on the expression. This is fooled by the array specification + present in e, thus we have to eliminate that one temporarily. */ + e2 = remove_last_array_ref (e); + t = SUCCESS; + if (t == SUCCESS && pointer) + t = gfc_check_vardef_context (e2, true, _("ALLOCATE object")); + if (t == SUCCESS) + t = gfc_check_vardef_context (e2, false, _("ALLOCATE object")); + gfc_free_expr (e2); + if (t == FAILURE) + goto failure; if (!code->expr3) { @@ -6733,9 +6748,9 @@ resolve_allocate_expr (gfc_expr *e, gfc_code *code) if (pointer || (dimension == 0 && codimension == 0)) goto success; - /* Make sure the next-to-last reference node is an array specification. */ + /* Make sure the last reference node is an array specifiction. */ - if (ref2 == NULL || ref2->type != REF_ARRAY || ref2->u.ar.type == AR_FULL + if (!ref2 || ref2->type != REF_ARRAY || ref2->u.ar.type == AR_FULL || (dimension && ref2->u.ar.dimen == 0)) { gfc_error ("Array specification required in ALLOCATE statement " @@ -6846,20 +6861,13 @@ resolve_allocate_deallocate (gfc_code *code, const char *fcn) gfc_expr *stat, *errmsg, *pe, *qe; gfc_alloc *a, *p, *q; - stat = code->expr1 ? code->expr1 : NULL; - - errmsg = code->expr2 ? code->expr2 : NULL; + stat = code->expr1; + errmsg = code->expr2; /* Check the stat variable. */ if (stat) { - if (stat->symtree->n.sym->attr.intent == INTENT_IN) - gfc_error ("Stat-variable '%s' at %L cannot be INTENT(IN)", - stat->symtree->n.sym->name, &stat->where); - - if (gfc_pure (NULL) && gfc_impure_variable (stat->symtree->n.sym)) - gfc_error ("Illegal stat-variable at %L for a PURE procedure", - &stat->where); + gfc_check_vardef_context (stat, false, _("STAT variable")); if ((stat->ts.type != BT_INTEGER && !(stat->ref && (stat->ref->type == REF_ARRAY @@ -6902,13 +6910,7 @@ resolve_allocate_deallocate (gfc_code *code, const char *fcn) gfc_warning ("ERRMSG at %L is useless without a STAT tag", &errmsg->where); - if (errmsg->symtree->n.sym->attr.intent == INTENT_IN) - gfc_error ("Errmsg-variable '%s' at %L cannot be INTENT(IN)", - errmsg->symtree->n.sym->name, &errmsg->where); - - if (gfc_pure (NULL) && gfc_impure_variable (errmsg->symtree->n.sym)) - gfc_error ("Illegal errmsg-variable at %L for a PURE procedure", - &errmsg->where); + gfc_check_vardef_context (errmsg, false, _("ERRMSG variable")); if ((errmsg->ts.type != BT_CHARACTER && !(errmsg->ref @@ -7539,7 +7541,6 @@ static void resolve_assoc_var (gfc_symbol* sym, bool resolve_target) { gfc_expr* target; - bool to_var; gcc_assert (sym->assoc); gcc_assert (sym->attr.flavor == FL_VARIABLE); @@ -7573,22 +7574,8 @@ resolve_assoc_var (gfc_symbol* sym, bool resolve_target) gcc_assert (sym->ts.type != BT_UNKNOWN); /* See if this is a valid association-to-variable. */ - to_var = (target->expr_type == EXPR_VARIABLE - && !gfc_has_vector_subscript (target)); - if (sym->assoc->variable && !to_var) - { - if (target->expr_type == EXPR_VARIABLE) - gfc_error ("'%s' at %L associated to vector-indexed target can not" - " be used in a variable definition context", - sym->name, &sym->declared_at); - else - gfc_error ("'%s' at %L associated to expression can not" - " be used in a variable definition context", - sym->name, &sym->declared_at); - - return; - } - sym->assoc->variable = to_var; + sym->assoc->variable = (target->expr_type == EXPR_VARIABLE + && !gfc_has_vector_subscript (target)); /* Finally resolve if this is an array or not. */ if (sym->attr.dimension && target->rank == 0) @@ -7617,7 +7604,7 @@ resolve_assoc_var (gfc_symbol* sym, bool resolve_target) /* Resolve a SELECT TYPE statement. */ static void -resolve_select_type (gfc_code *code) +resolve_select_type (gfc_code *code, gfc_namespace *old_ns) { gfc_symbol *selector_type; gfc_code *body, *new_st, *if_st, *tail; @@ -7895,8 +7882,13 @@ resolve_select_type (gfc_code *code) default_case->next = if_st; } - resolve_select (code); + /* Resolve the internal code. This can not be done earlier because + it requires that the sym->assoc of selectors is set already. */ + gfc_current_ns = ns; + gfc_resolve_blocks (code->block, gfc_current_ns); + gfc_current_ns = old_ns; + resolve_select (code); } @@ -8657,7 +8649,6 @@ resolve_ordinary_assign (gfc_code *code, gfc_namespace *ns) } } - if (lhs->ts.type == BT_CHARACTER && gfc_option.warn_character_truncation) { @@ -8698,15 +8689,6 @@ resolve_ordinary_assign (gfc_code *code, gfc_namespace *ns) if (gfc_pure (NULL)) { - if (gfc_impure_variable (lhs->symtree->n.sym)) - { - gfc_error ("Cannot assign to variable '%s' in PURE " - "procedure at %L", - lhs->symtree->n.sym->name, - &lhs->where); - return rval; - } - if (lhs->ts.type == BT_DERIVED && lhs->expr_type == EXPR_VARIABLE && lhs->ts.u.derived->attr.pointer_comp @@ -8810,9 +8792,8 @@ resolve_code (gfc_code *code, gfc_namespace *ns) gfc_resolve_omp_do_blocks (code, ns); break; case EXEC_SELECT_TYPE: - gfc_current_ns = code->ext.block.ns; - gfc_resolve_blocks (code->block, gfc_current_ns); - gfc_current_ns = ns; + /* Blocks are handled in resolve_select_type because we have + to transform the SELECT TYPE into ASSOCIATE first. */ break; case EXEC_OMP_WORKSHARE: omp_workshare_save = omp_workshare_flag; @@ -8899,6 +8880,10 @@ resolve_code (gfc_code *code, gfc_namespace *ns) if (t == FAILURE) break; + if (gfc_check_vardef_context (code->expr1, false, _("assignment")) + == FAILURE) + break; + if (resolve_ordinary_assign (code, ns)) { if (code->op == EXEC_COMPCALL) @@ -8923,11 +8908,27 @@ resolve_code (gfc_code *code, gfc_namespace *ns) break; case EXEC_POINTER_ASSIGN: - if (t == FAILURE) - break; + { + gfc_expr* e; - gfc_check_pointer_assign (code->expr1, code->expr2); - break; + if (t == FAILURE) + break; + + /* This is both a variable definition and pointer assignment + context, so check both of them. For rank remapping, a final + array ref may be present on the LHS and fool gfc_expr_attr + used in gfc_check_vardef_context. Remove it. */ + e = remove_last_array_ref (code->expr1); + t = gfc_check_vardef_context (e, true, _("pointer assignment")); + if (t == SUCCESS) + t = gfc_check_vardef_context (e, false, _("pointer assignment")); + gfc_free_expr (e); + if (t == FAILURE) + break; + + gfc_check_pointer_assign (code->expr1, code->expr2); + break; + } case EXEC_ARITHMETIC_IF: if (t == SUCCESS @@ -8970,7 +8971,7 @@ resolve_code (gfc_code *code, gfc_namespace *ns) break; case EXEC_SELECT_TYPE: - resolve_select_type (code); + resolve_select_type (code, ns); break; case EXEC_BLOCK: |