diff options
author | Daniel Franke <dfranke@gcc.gnu.org> | 2007-07-22 12:31:11 -0400 |
---|---|---|
committer | Daniel Franke <dfranke@gcc.gnu.org> | 2007-07-22 12:31:11 -0400 |
commit | e1633d825dba019d03cbab83a89eb16297257604 (patch) | |
tree | 897c943e7e0ac632965a6aad7afcb4a9cdfc6087 /gcc/fortran/expr.c | |
parent | 4195a76796f2a88bbbcb0947b3fc8cfb590bcf28 (diff) | |
download | gcc-e1633d825dba019d03cbab83a89eb16297257604.zip gcc-e1633d825dba019d03cbab83a89eb16297257604.tar.gz gcc-e1633d825dba019d03cbab83a89eb16297257604.tar.bz2 |
re PR fortran/29962 (Initialization expressions)
gcc/fortran:
2007-07-22 Daniel Franke <franke.daniel@gmail.com>
PR fortran/29962
PR fortran/31253
PR fortran/31265
PR fortran/31639
* gfortran.h (gfc_intrinsic_sym): Changed members elemental, pure,
generic, specific, actual_ok, noreturn into bits of a bitfield,
added bits for inquiry, transformational, conversion.
* check.c (non_init_transformational): Removed, removed all callers.
* intrinsic.c (enum class): New.
(add_sym*): Replaced argument elemetal by enum class. Changed all
callers.
(add_functions): Assign appropriate classes to intrinsic functions.
(add_subroutines): Assign appropriate classes to intrinsic subroutines.
(add_conv): Set conversion attribute.
(gfc_init_expr_extensions): Removed, removed all callers.
(gfc_intrinsic_func_interface): Reimplemented check for non-standard
initializatione expressions.
* expr.c (check_specification_function): New.
(gfc_is_constant_expr): Added check for specification functions.
(check_init_expr_arguments): New.
(check_inquiry): Changed return value to MATCH, added checks for
inquiry functions defined by F2003.
(check_transformational): New.
(check_null): New.
(check_elemental): New.
(check_conversion): New.
(check_init_expr): Call new check functions, add more specific error
messages.
gcc/testsuite:
2007-07-22 Daniel Franke <franke.daniel@gmail.com>
PR fortran/29962
* gfortran.dg/array_initializer_1.f90: Removed warning.
* gfortran.dg/initialization_1.f90: Adjusted messages.
* gfortran.dg/nested_modules_6.f90: Removed warning.
PR fortran/31253
* gfortran.dg/initialization_7.f90: New test.
PR fortran/31639
* gfortran.dg/initialization_8.f90: New test.
From-SVN: r126826
Diffstat (limited to 'gcc/fortran/expr.c')
-rw-r--r-- | gcc/fortran/expr.c | 319 |
1 files changed, 246 insertions, 73 deletions
diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c index d90dd21..257349a 100644 --- a/gcc/fortran/expr.c +++ b/gcc/fortran/expr.c @@ -689,6 +689,27 @@ done: } +static match +check_specification_function (gfc_expr *e) +{ + gfc_symbol *sym; + sym = e->symtree->n.sym; + + /* F95, 7.1.6.2; F2003, 7.1.7 */ + if (sym + && sym->attr.function + && sym->attr.pure + && !sym->attr.intrinsic + && !sym->attr.recursive + && sym->attr.proc != PROC_INTERNAL + && sym->attr.proc != PROC_ST_FUNCTION + && sym->attr.proc != PROC_UNKNOWN + && sym->formal == NULL) + return MATCH_YES; + + return MATCH_NO; +} + /* Function to determine if an expression is constant or not. This function expects that the expression has already been simplified. */ @@ -715,6 +736,13 @@ gfc_is_constant_expr (gfc_expr *e) break; case EXPR_FUNCTION: + /* Specification functions are constant. */ + if (check_specification_function (e) == MATCH_YES) + { + rv = 1; + break; + } + /* Call to intrinsic with at least one argument. */ rv = 0; if (e->value.function.isym && e->value.function.actual) @@ -1849,69 +1877,184 @@ not_numeric: } +static match +check_init_expr_arguments (gfc_expr *e) +{ + gfc_actual_arglist *ap; -/* Certain inquiry functions are specifically allowed to have variable - arguments, which is an exception to the normal requirement that an - initialization function have initialization arguments. We head off - this problem here. */ + for (ap = e->value.function.actual; ap; ap = ap->next) + if (check_init_expr (ap->expr) == FAILURE) + return MATCH_ERROR; -static try + return MATCH_YES; +} + +/* F95, 7.1.6.1, Initialization expressions, (7) + F2003, 7.1.7 Initialization expression, (8) */ + +static match check_inquiry (gfc_expr *e, int not_restricted) { const char *name; + const char *const *functions; + + static const char *const inquiry_func_f95[] = { + "lbound", "shape", "size", "ubound", + "bit_size", "len", "kind", + "digits", "epsilon", "huge", "maxexponent", "minexponent", + "precision", "radix", "range", "tiny", + NULL + }; - /* FIXME: This should be moved into the intrinsic definitions, - to eliminate this ugly hack. */ - static const char * const inquiry_function[] = { - "digits", "epsilon", "huge", "kind", "len", "maxexponent", "minexponent", - "precision", "radix", "range", "tiny", "bit_size", "size", "shape", - "lbound", "ubound", NULL + static const char *const inquiry_func_f2003[] = { + "lbound", "shape", "size", "ubound", + "bit_size", "len", "kind", + "digits", "epsilon", "huge", "maxexponent", "minexponent", + "precision", "radix", "range", "tiny", + "new_line", NULL }; int i; + gfc_actual_arglist *ap; + + if (!e->value.function.isym + || !e->value.function.isym->inquiry) + return MATCH_NO; /* An undeclared parameter will get us here (PR25018). */ if (e->symtree == NULL) - return FAILURE; + return MATCH_NO; name = e->symtree->n.sym->name; - for (i = 0; inquiry_function[i]; i++) - if (strcmp (inquiry_function[i], name) == 0) - break; - - if (inquiry_function[i] == NULL) - return FAILURE; + functions = (gfc_option.warn_std & GFC_STD_F2003) + ? inquiry_func_f2003 : inquiry_func_f95; - e = e->value.function.actual->expr; + for (i = 0; functions[i]; i++) + if (strcmp (functions[i], name) == 0) + break; - if (e == NULL || e->expr_type != EXPR_VARIABLE) - return FAILURE; + if (functions[i] == NULL) + { + gfc_error ("Inquiry function '%s' at %L is not permitted " + "in an initialization expression", name, &e->where); + return MATCH_ERROR; + } /* At this point we have an inquiry function with a variable argument. The type of the variable might be undefined, but we need it now, because the - arguments of these functions are allowed to be undefined. */ + arguments of these functions are not allowed to be undefined. */ - if (e->ts.type == BT_UNKNOWN) + for (ap = e->value.function.actual; ap; ap = ap->next) { - if (e->symtree->n.sym->ts.type == BT_UNKNOWN - && gfc_set_default_type (e->symtree->n.sym, 0, gfc_current_ns) - == FAILURE) - return FAILURE; + if (!ap->expr) + continue; + + if (ap->expr->ts.type == BT_UNKNOWN) + { + if (ap->expr->symtree->n.sym->ts.type == BT_UNKNOWN + && gfc_set_default_type (ap->expr->symtree->n.sym, 0, gfc_current_ns) + == FAILURE) + return MATCH_NO; - e->ts = e->symtree->n.sym->ts; + ap->expr->ts = ap->expr->symtree->n.sym->ts; + } + + /* Assumed character length will not reduce to a constant expression + with LEN, as required by the standard. */ + if (i == 5 && not_restricted + && ap->expr->symtree->n.sym->ts.type == BT_CHARACTER + && ap->expr->symtree->n.sym->ts.cl->length == NULL) + { + if (gfc_notify_std (GFC_STD_GNU, "assumed character length " + "variable '%s' in constant expression at %L", + e->symtree->n.sym->name, &e->where) == FAILURE) + return MATCH_ERROR; + } + else if (not_restricted && check_init_expr (ap->expr) == FAILURE) + return MATCH_ERROR; } - /* Assumed character length will not reduce to a constant expression - with LEN, as required by the standard. */ - if (i == 4 && not_restricted - && e->symtree->n.sym->ts.type == BT_CHARACTER - && e->symtree->n.sym->ts.cl->length == NULL) - gfc_notify_std (GFC_STD_GNU, "assumed character length " - "variable '%s' in constant expression at %L", - e->symtree->n.sym->name, &e->where); + return MATCH_YES; +} + - return SUCCESS; +/* F95, 7.1.6.1, Initialization expressions, (5) + F2003, 7.1.7 Initialization expression, (5) */ + +static match +check_transformational (gfc_expr *e) +{ + static const char * const trans_func_f95[] = { + "repeat", "reshape", "selected_int_kind", + "selected_real_kind", "transfer", "trim", NULL + }; + + int i; + const char *name; + + if (!e->value.function.isym + || !e->value.function.isym->transformational) + return MATCH_NO; + + name = e->symtree->n.sym->name; + + /* NULL() is dealt with below. */ + if (strcmp ("null", name) == 0) + return MATCH_NO; + + for (i = 0; trans_func_f95[i]; i++) + if (strcmp (trans_func_f95[i], name) == 0) + break; + + if (trans_func_f95[i] == NULL + && gfc_notify_std (GFC_STD_F2003, + "transformational intrinsic '%s' at %L is not permitted " + "in an initialization expression", name, &e->where) == FAILURE) + return MATCH_ERROR; + + return check_init_expr_arguments (e); +} + + +/* F95, 7.1.6.1, Initialization expressions, (6) + F2003, 7.1.7 Initialization expression, (6) */ + +static match +check_null (gfc_expr *e) +{ + if (strcmp ("null", e->symtree->n.sym->name) != 0) + return MATCH_NO; + + return check_init_expr_arguments (e); +} + + +static match +check_elemental (gfc_expr *e) +{ + if (!e->value.function.isym + || !e->value.function.isym->elemental) + return MATCH_NO; + + if ((e->ts.type != BT_INTEGER || e->ts.type != BT_CHARACTER) + && gfc_notify_std (GFC_STD_F2003, "Extension: Evaluation of " + "nonstandard initialization expression at %L", + &e->where) == FAILURE) + return MATCH_ERROR; + + return check_init_expr_arguments (e); +} + + +static match +check_conversion (gfc_expr *e) +{ + if (!e->value.function.isym + || !e->value.function.isym->conversion) + return MATCH_NO; + + return check_init_expr_arguments (e); } @@ -1925,7 +2068,6 @@ check_inquiry (gfc_expr *e, int not_restricted) static try check_init_expr (gfc_expr *e) { - gfc_actual_arglist *ap; match m; try t; gfc_intrinsic_sym *isym; @@ -1943,42 +2085,44 @@ check_init_expr (gfc_expr *e) break; case EXPR_FUNCTION: - t = SUCCESS; - - if (check_inquiry (e, 1) != SUCCESS) - { - t = SUCCESS; - for (ap = e->value.function.actual; ap; ap = ap->next) - if (check_init_expr (ap->expr) == FAILURE) - { - t = FAILURE; - break; - } - } - - /* Try to scalarize an elemental intrinsic function that has an - array argument. */ - isym = gfc_find_function (e->symtree->n.sym->name); - if (isym && isym->elemental - && e->value.function.actual->expr->expr_type == EXPR_ARRAY) - { - if (scalarize_intrinsic_call (e) == SUCCESS) - break; - } + t = FAILURE; - if (t == SUCCESS) + if ((m = check_specification_function (e)) != MATCH_YES) { - m = gfc_intrinsic_func_interface (e, 0); + if ((m = gfc_intrinsic_func_interface (e, 0)) != MATCH_YES) + { + gfc_error ("Function '%s' in initialization expression at %L " + "must be an intrinsic or a specification function", + e->symtree->n.sym->name, &e->where); + break; + } - if (m == MATCH_NO) - gfc_error ("Function '%s' in initialization expression at %L " - "must be an intrinsic function", - e->symtree->n.sym->name, &e->where); + if ((m = check_conversion (e)) == MATCH_NO + && (m = check_inquiry (e, 1)) == MATCH_NO + && (m = check_null (e)) == MATCH_NO + && (m = check_transformational (e)) == MATCH_NO + && (m = check_elemental (e)) == MATCH_NO) + { + gfc_error ("Intrinsic function '%s' at %L is not permitted " + "in an initialization expression", + e->symtree->n.sym->name, &e->where); + m = MATCH_ERROR; + } - if (m != MATCH_YES) - t = FAILURE; + /* Try to scalarize an elemental intrinsic function that has an + array argument. */ + isym = gfc_find_function (e->symtree->n.sym->name); + if (isym && isym->elemental + && e->value.function.actual->expr->expr_type == EXPR_ARRAY) + { + if ((t = scalarize_intrinsic_call (e)) == SUCCESS) + break; + } } + if (m == MATCH_YES) + t = SUCCESS; + break; case EXPR_VARIABLE: @@ -1996,10 +2140,39 @@ check_init_expr (gfc_expr *e) if (gfc_in_match_data ()) break; - gfc_error ("Parameter '%s' at %L has not been declared or is " - "a variable, which does not reduce to a constant " - "expression", e->symtree->n.sym->name, &e->where); t = FAILURE; + + if (e->symtree->n.sym->as) + { + switch (e->symtree->n.sym->as->type) + { + case AS_ASSUMED_SIZE: + gfc_error ("assumed size array '%s' at %L is not permitted " + "in an initialization expression", + e->symtree->n.sym->name, &e->where); + break; + + case AS_ASSUMED_SHAPE: + gfc_error ("assumed shape array '%s' at %L is not permitted " + "in an initialization expression", + e->symtree->n.sym->name, &e->where); + break; + + case AS_DEFERRED: + gfc_error ("deferred array '%s' at %L is not permitted " + "in an initialization expression", + e->symtree->n.sym->name, &e->where); + break; + + default: + gcc_unreachable(); + } + } + else + gfc_error ("Parameter '%s' at %L has not been declared or is " + "a variable, which does not reduce to a constant " + "expression", e->symtree->n.sym->name, &e->where); + break; case EXPR_CONSTANT: @@ -2078,7 +2251,7 @@ gfc_match_init_expr (gfc_expr **result) /* Not all inquiry functions are simplified to constant expressions so it is necessary to call check_inquiry again. */ - if (!gfc_is_constant_expr (expr) && check_inquiry (expr, 1) == FAILURE + if (!gfc_is_constant_expr (expr) && check_inquiry (expr, 1) != MATCH_YES && !gfc_in_match_data ()) { gfc_error ("Initialization expression didn't reduce %C"); @@ -2161,7 +2334,7 @@ static try restricted_intrinsic (gfc_expr *e) { /* TODO: Check constraints on inquiry functions. 7.1.6.2 (7). */ - if (check_inquiry (e, 0) == SUCCESS) + if (check_inquiry (e, 0) == MATCH_YES) return SUCCESS; return restricted_args (e->value.function.actual); |