aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/expr.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fortran/expr.c')
-rw-r--r--gcc/fortran/expr.c319
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);