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/expr.c | |
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/expr.c')
-rw-r--r-- | gcc/fortran/expr.c | 233 |
1 files changed, 188 insertions, 45 deletions
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; +} |