aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/expr.c
diff options
context:
space:
mode:
authorDaniel Kraft <d@domob.eu>2010-09-23 10:37:54 +0200
committerDaniel Kraft <domob@gcc.gnu.org>2010-09-23 10:37:54 +0200
commit8c91ab34b56a860e60459d56b488054774d4f6ee (patch)
tree67d09d55027e1b23ccff6e1f28d4f0e70c767536 /gcc/fortran/expr.c
parent42d9f9dd0f1f957a29afcefb29299f327643a008 (diff)
downloadgcc-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.c233
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;
+}