blob: 0c2cb50c6a7cd5ce10c59b9548c15b8e82a4272c [file] [log] [blame]
/* Check functions
Copyright (C) 2002-2022 Free Software Foundation, Inc.
Contributed by Andy Vaught & Katherine Holcomb
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
/* These functions check to see if an argument list is compatible with
a particular intrinsic function or subroutine. Presence of
required arguments has already been established, the argument list
has been sorted into the right order and has NULL arguments in the
correct places for missing optional arguments. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "options.h"
#include "gfortran.h"
#include "intrinsic.h"
#include "constructor.h"
#include "target-memory.h"
/* Reset a BOZ to a zero value. This is used to prevent run-on errors
from resolve.cc(resolve_function). */
static void
reset_boz (gfc_expr *x)
{
/* Clear boz info. */
x->boz.rdx = 0;
x->boz.len = 0;
free (x->boz.str);
x->ts.type = BT_INTEGER;
x->ts.kind = gfc_default_integer_kind;
mpz_init (x->value.integer);
mpz_set_ui (x->value.integer, 0);
}
/* A BOZ literal constant can appear in a limited number of contexts.
gfc_invalid_boz() is a helper function to simplify error/warning
generation. gfortran accepts the nonstandard 'X' for 'Z', and gfortran
allows the BOZ indicator to appear as a suffix. If -fallow-invalid-boz
is used, then issue a warning; otherwise issue an error. */
bool
gfc_invalid_boz (const char *msg, locus *loc)
{
if (flag_allow_invalid_boz)
{
gfc_warning (0, msg, loc);
return false;
}
const char *hint = _(" [see %<-fno-allow-invalid-boz%>]");
size_t len = strlen (msg) + strlen (hint) + 1;
char *msg2 = (char *) alloca (len);
strcpy (msg2, msg);
strcat (msg2, hint);
gfc_error (msg2, loc);
return true;
}
/* Issue an error for an illegal BOZ argument. */
static bool
illegal_boz_arg (gfc_expr *x)
{
if (x->ts.type == BT_BOZ)
{
gfc_error ("BOZ literal constant at %L cannot be an actual argument "
"to %qs", &x->where, gfc_current_intrinsic);
reset_boz (x);
return true;
}
return false;
}
/* Some precedures take two arguments such that both cannot be BOZ. */
static bool
boz_args_check(gfc_expr *i, gfc_expr *j)
{
if (i->ts.type == BT_BOZ && j->ts.type == BT_BOZ)
{
gfc_error ("Arguments of %qs at %L and %L cannot both be BOZ "
"literal constants", gfc_current_intrinsic, &i->where,
&j->where);
reset_boz (i);
reset_boz (j);
return false;
}
return true;
}
/* Check that a BOZ is a constant. */
static bool
is_boz_constant (gfc_expr *a)
{
if (a->expr_type != EXPR_CONSTANT)
{
gfc_error ("Invalid use of BOZ literal constant at %L", &a->where);
return false;
}
return true;
}
/* Convert a octal string into a binary string. This is used in the
fallback conversion of an octal string to a REAL. */
static char *
oct2bin(int nbits, char *oct)
{
const char bits[8][5] = {
"000", "001", "010", "011", "100", "101", "110", "111"};
char *buf, *bufp;
int i, j, n;
j = nbits + 1;
if (nbits == 64) j++;
bufp = buf = XCNEWVEC (char, j + 1);
memset (bufp, 0, j + 1);
n = strlen (oct);
for (i = 0; i < n; i++, oct++)
{
j = *oct - 48;
strcpy (bufp, &bits[j][0]);
bufp += 3;
}
bufp = XCNEWVEC (char, nbits + 1);
if (nbits == 64)
strcpy (bufp, buf + 2);
else
strcpy (bufp, buf + 1);
free (buf);
return bufp;
}
/* Convert a hexidecimal string into a binary string. This is used in the
fallback conversion of a hexidecimal string to a REAL. */
static char *
hex2bin(int nbits, char *hex)
{
const char bits[16][5] = {
"0000", "0001", "0010", "0011", "0100", "0101", "0110", "0111",
"1000", "1001", "1010", "1011", "1100", "1101", "1110", "1111"};
char *buf, *bufp;
int i, j, n;
bufp = buf = XCNEWVEC (char, nbits + 1);
memset (bufp, 0, nbits + 1);
n = strlen (hex);
for (i = 0; i < n; i++, hex++)
{
j = *hex;
if (j > 47 && j < 58)
j -= 48;
else if (j > 64 && j < 71)
j -= 55;
else if (j > 96 && j < 103)
j -= 87;
else
gcc_unreachable ();
strcpy (bufp, &bits[j][0]);
bufp += 4;
}
return buf;
}
/* Fallback conversion of a BOZ string to REAL. */
static void
bin2real (gfc_expr *x, int kind)
{
char buf[114], *sp;
int b, i, ie, t, w;
bool sgn;
mpz_t em;
i = gfc_validate_kind (BT_REAL, kind, false);
t = gfc_real_kinds[i].digits - 1;
/* Number of bits in the exponent. */
if (gfc_real_kinds[i].max_exponent == 16384)
w = 15;
else if (gfc_real_kinds[i].max_exponent == 1024)
w = 11;
else
w = 8;
if (x->boz.rdx == 16)
sp = hex2bin (gfc_real_kinds[i].mode_precision, x->boz.str);
else if (x->boz.rdx == 8)
sp = oct2bin (gfc_real_kinds[i].mode_precision, x->boz.str);
else
sp = x->boz.str;
/* Extract sign bit. */
sgn = *sp != '0';
/* Extract biased exponent. */
memset (buf, 0, 114);
strncpy (buf, ++sp, w);
mpz_init (em);
mpz_set_str (em, buf, 2);
ie = mpz_get_si (em);
mpfr_init2 (x->value.real, t + 1);
x->ts.type = BT_REAL;
x->ts.kind = kind;
sp += w; /* Set to first digit in significand. */
b = (1 << w) - 1;
if ((i == 0 && ie == b) || (i == 1 && ie == b)
|| ((i == 2 || i == 3) && ie == b))
{
bool zeros = true;
if (i == 2) sp++;
for (; *sp; sp++)
{
if (*sp != '0')
{
zeros = false;
break;
}
}
if (zeros)
mpfr_set_inf (x->value.real, 1);
else
mpfr_set_nan (x->value.real);
}
else
{
if (i == 2)
strncpy (buf, sp, t + 1);
else
{
/* Significand with hidden bit. */
buf[0] = '1';
strncpy (&buf[1], sp, t);
}
/* Convert to significand to integer. */
mpz_set_str (em, buf, 2);
ie -= ((1 << (w - 1)) - 1); /* Unbiased exponent. */
mpfr_set_z_2exp (x->value.real, em, ie - t, GFC_RND_MODE);
}
if (sgn) mpfr_neg (x->value.real, x->value.real, GFC_RND_MODE);
mpz_clear (em);
}
/* Fortran 2018 treats a BOZ as simply a string of bits. gfc_boz2real ()
converts the string into a REAL of the appropriate kind. The treatment
of the sign bit is processor dependent. */
bool
gfc_boz2real (gfc_expr *x, int kind)
{
extern int gfc_max_integer_kind;
gfc_typespec ts;
int len;
char *buf, *str;
if (!is_boz_constant (x))
return false;
/* Determine the length of the required string. */
len = 8 * kind;
if (x->boz.rdx == 16) len /= 4;
if (x->boz.rdx == 8) len = len / 3 + 1;
buf = (char *) alloca (len + 1); /* +1 for NULL terminator. */
if (x->boz.len >= len) /* Truncate if necessary. */
{
str = x->boz.str + (x->boz.len - len);
strcpy(buf, str);
}
else /* Copy and pad. */
{
memset (buf, 48, len);
str = buf + (len - x->boz.len);
strcpy (str, x->boz.str);
}
/* Need to adjust leading bits in an octal string. */
if (x->boz.rdx == 8)
{
/* Clear first bit. */
if (kind == 4 || kind == 10 || kind == 16)
{
if (buf[0] == '4')
buf[0] = '0';
else if (buf[0] == '5')
buf[0] = '1';
else if (buf[0] == '6')
buf[0] = '2';
else if (buf[0] == '7')
buf[0] = '3';
}
/* Clear first two bits. */
else
{
if (buf[0] == '2' || buf[0] == '4' || buf[0] == '6')
buf[0] = '0';
else if (buf[0] == '3' || buf[0] == '5' || buf[0] == '7')
buf[0] = '1';
}
}
/* Reset BOZ string to the truncated or padded version. */
free (x->boz.str);
x->boz.len = len;
x->boz.str = XCNEWVEC (char, len + 1);
strncpy (x->boz.str, buf, len);
/* For some targets, the largest INTEGER in terms of bits is smaller than
the bits needed to hold the REAL. Fortunately, the kind type parameter
indicates the number of bytes required to an INTEGER and a REAL. */
if (gfc_max_integer_kind < kind)
{
bin2real (x, kind);
}
else
{
/* Convert to widest possible integer. */
gfc_boz2int (x, gfc_max_integer_kind);
ts.type = BT_REAL;
ts.kind = kind;
if (!gfc_convert_boz (x, &ts))
{
gfc_error ("Failure in conversion of BOZ to REAL at %L", &x->where);
return false;
}
}
return true;
}
/* Fortran 2018 treats a BOZ as simply a string of bits. gfc_boz2int ()
converts the string into an INTEGER of the appropriate kind. The
treatment of the sign bit is processor dependent. If the converted
value exceeds the range of the type, then wrap-around semantics are
applied. */
bool
gfc_boz2int (gfc_expr *x, int kind)
{
int i, len;
char *buf, *str;
mpz_t tmp1;
if (!is_boz_constant (x))
return false;
i = gfc_validate_kind (BT_INTEGER, kind, false);
len = gfc_integer_kinds[i].bit_size;
if (x->boz.rdx == 16) len /= 4;
if (x->boz.rdx == 8) len = len / 3 + 1;
buf = (char *) alloca (len + 1); /* +1 for NULL terminator. */
if (x->boz.len >= len) /* Truncate if necessary. */
{
str = x->boz.str + (x->boz.len - len);
strcpy(buf, str);
}
else /* Copy and pad. */
{
memset (buf, 48, len);
str = buf + (len - x->boz.len);
strcpy (str, x->boz.str);
}
/* Need to adjust leading bits in an octal string. */
if (x->boz.rdx == 8)
{
/* Clear first bit. */
if (kind == 1 || kind == 4 || kind == 16)
{
if (buf[0] == '4')
buf[0] = '0';
else if (buf[0] == '5')
buf[0] = '1';
else if (buf[0] == '6')
buf[0] = '2';
else if (buf[0] == '7')
buf[0] = '3';
}
/* Clear first two bits. */
else
{
if (buf[0] == '2' || buf[0] == '4' || buf[0] == '6')
buf[0] = '0';
else if (buf[0] == '3' || buf[0] == '5' || buf[0] == '7')
buf[0] = '1';
}
}
/* Convert as-if unsigned integer. */
mpz_init (tmp1);
mpz_set_str (tmp1, buf, x->boz.rdx);
/* Check for wrap-around. */
if (mpz_cmp (tmp1, gfc_integer_kinds[i].huge) > 0)
{
mpz_t tmp2;
mpz_init (tmp2);
mpz_add_ui (tmp2, gfc_integer_kinds[i].huge, 1);
mpz_mod (tmp1, tmp1, tmp2);
mpz_sub (tmp1, tmp1, tmp2);
mpz_clear (tmp2);
}
/* Clear boz info. */
x->boz.rdx = 0;
x->boz.len = 0;
free (x->boz.str);
mpz_init (x->value.integer);
mpz_set (x->value.integer, tmp1);
x->ts.type = BT_INTEGER;
x->ts.kind = kind;
mpz_clear (tmp1);
return true;
}
/* Make sure an expression is a scalar. */
static bool
scalar_check (gfc_expr *e, int n)
{
if (e->rank == 0)
return true;
gfc_error ("%qs argument of %qs intrinsic at %L must be a scalar",
gfc_current_intrinsic_arg[n]->name, gfc_current_intrinsic,
&e->where);
return false;
}
/* Check the type of an expression. */
static bool
type_check (gfc_expr *e, int n, bt type)
{
if (e->ts.type == type)
return true;
gfc_error ("%qs argument of %qs intrinsic at %L must be %s",
gfc_current_intrinsic_arg[n]->name, gfc_current_intrinsic,
&e->where, gfc_basic_typename (type));
return false;
}
/* Check that the expression is a numeric type. */
static bool
numeric_check (gfc_expr *e, int n)
{
/* Users sometime use a subroutine designator as an actual argument to
an intrinsic subprogram that expects an argument with a numeric type. */
if (e->symtree && e->symtree->n.sym->attr.subroutine)
goto error;
if (gfc_numeric_ts (&e->ts))
return true;
/* If the expression has not got a type, check if its namespace can
offer a default type. */
if ((e->expr_type == EXPR_VARIABLE || e->expr_type == EXPR_FUNCTION)
&& e->symtree->n.sym->ts.type == BT_UNKNOWN
&& gfc_set_default_type (e->symtree->n.sym, 0, e->symtree->n.sym->ns)
&& gfc_numeric_ts (&e->symtree->n.sym->ts))
{
e->ts = e->symtree->n.sym->ts;
return true;
}
error:
gfc_error ("%qs argument of %qs intrinsic at %L must have a numeric type",
gfc_current_intrinsic_arg[n]->name, gfc_current_intrinsic,
&e->where);
return false;
}
/* Check that an expression is integer or real. */
static bool
int_or_real_check (gfc_expr *e, int n)
{
if (e->ts.type != BT_INTEGER && e->ts.type != BT_REAL)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be INTEGER "
"or REAL", gfc_current_intrinsic_arg[n]->name,
gfc_current_intrinsic, &e->where);
return false;
}
return true;
}
/* Check that an expression is integer or real; allow character for
F2003 or later. */
static bool
int_or_real_or_char_check_f2003 (gfc_expr *e, int n)
{
if (e->ts.type != BT_INTEGER && e->ts.type != BT_REAL)
{
if (e->ts.type == BT_CHARACTER)
return gfc_notify_std (GFC_STD_F2003, "Fortran 2003: Character for "
"%qs argument of %qs intrinsic at %L",
gfc_current_intrinsic_arg[n]->name,
gfc_current_intrinsic, &e->where);
else
{
if (gfc_option.allow_std & GFC_STD_F2003)
gfc_error ("%qs argument of %qs intrinsic at %L must be INTEGER "
"or REAL or CHARACTER",
gfc_current_intrinsic_arg[n]->name,
gfc_current_intrinsic, &e->where);
else
gfc_error ("%qs argument of %qs intrinsic at %L must be INTEGER "
"or REAL", gfc_current_intrinsic_arg[n]->name,
gfc_current_intrinsic, &e->where);
}
return false;
}
return true;
}
/* Check that an expression is an intrinsic type. */
static bool
intrinsic_type_check (gfc_expr *e, int n)
{
if (e->ts.type != BT_INTEGER && e->ts.type != BT_REAL
&& e->ts.type != BT_COMPLEX && e->ts.type != BT_CHARACTER
&& e->ts.type != BT_LOGICAL)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be of intrinsic type",
gfc_current_intrinsic_arg[n]->name,
gfc_current_intrinsic, &e->where);
return false;
}
return true;
}
/* Check that an expression is real or complex. */
static bool
real_or_complex_check (gfc_expr *e, int n)
{
if (e->ts.type != BT_REAL && e->ts.type != BT_COMPLEX)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be REAL "
"or COMPLEX", gfc_current_intrinsic_arg[n]->name,
gfc_current_intrinsic, &e->where);
return false;
}
return true;
}
/* Check that an expression is INTEGER or PROCEDURE. */
static bool
int_or_proc_check (gfc_expr *e, int n)
{
if (e->ts.type != BT_INTEGER && e->ts.type != BT_PROCEDURE)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be INTEGER "
"or PROCEDURE", gfc_current_intrinsic_arg[n]->name,
gfc_current_intrinsic, &e->where);
return false;
}
return true;
}
/* Check that the expression is an optional constant integer
and that it specifies a valid kind for that type. */
static bool
kind_check (gfc_expr *k, int n, bt type)
{
int kind;
if (k == NULL)
return true;
if (!type_check (k, n, BT_INTEGER))
return false;
if (!scalar_check (k, n))
return false;
if (!gfc_check_init_expr (k))
{
gfc_error ("%qs argument of %qs intrinsic at %L must be a constant",
gfc_current_intrinsic_arg[n]->name, gfc_current_intrinsic,
&k->where);
return false;
}
if (gfc_extract_int (k, &kind)
|| gfc_validate_kind (type, kind, true) < 0)
{
gfc_error ("Invalid kind for %s at %L", gfc_basic_typename (type),
&k->where);
return false;
}
return true;
}
/* Make sure the expression is a double precision real. */
static bool
double_check (gfc_expr *d, int n)
{
if (!type_check (d, n, BT_REAL))
return false;
if (d->ts.kind != gfc_default_double_kind)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be double "
"precision", gfc_current_intrinsic_arg[n]->name,
gfc_current_intrinsic, &d->where);
return false;
}
return true;
}
static bool
coarray_check (gfc_expr *e, int n)
{
if (e->ts.type == BT_CLASS && gfc_expr_attr (e).class_ok
&& CLASS_DATA (e)->attr.codimension
&& CLASS_DATA (e)->as->corank)
{
gfc_add_class_array_ref (e);
return true;
}
if (!gfc_is_coarray (e))
{
gfc_error ("Expected coarray variable as %qs argument to the %s "
"intrinsic at %L", gfc_current_intrinsic_arg[n]->name,
gfc_current_intrinsic, &e->where);
return false;
}
return true;
}
/* Make sure the expression is a logical array. */
static bool
logical_array_check (gfc_expr *array, int n)
{
if (array->ts.type != BT_LOGICAL || array->rank == 0)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be a logical "
"array", gfc_current_intrinsic_arg[n]->name,
gfc_current_intrinsic, &array->where);
return false;
}
return true;
}
/* Make sure an expression is an array. */
static bool
array_check (gfc_expr *e, int n)
{
if (e->rank != 0 && e->ts.type == BT_CLASS && gfc_expr_attr (e).class_ok
&& CLASS_DATA (e)->attr.dimension
&& CLASS_DATA (e)->as->rank)
{
gfc_add_class_array_ref (e);
}
if (e->rank != 0 && e->ts.type != BT_PROCEDURE)
return true;
gfc_error ("%qs argument of %qs intrinsic at %L must be an array",
gfc_current_intrinsic_arg[n]->name, gfc_current_intrinsic,
&e->where);
return false;
}
/* If expr is a constant, then check to ensure that it is greater than
of equal to zero. */
static bool
nonnegative_check (const char *arg, gfc_expr *expr)
{
int i;
if (expr->expr_type == EXPR_CONSTANT)
{
gfc_extract_int (expr, &i);
if (i < 0)
{
gfc_error ("%qs at %L must be nonnegative", arg, &expr->where);
return false;
}
}
return true;
}
/* If expr is a constant, then check to ensure that it is greater than zero. */
static bool
positive_check (int n, gfc_expr *expr)
{
int i;
if (expr->expr_type == EXPR_CONSTANT)
{
gfc_extract_int (expr, &i);
if (i <= 0)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be positive",
gfc_current_intrinsic_arg[n]->name, gfc_current_intrinsic,
&expr->where);
return false;
}
}
return true;
}
/* If expr2 is constant, then check that the value is less than
(less than or equal to, if 'or_equal' is true) bit_size(expr1). */
static bool
less_than_bitsize1 (const char *arg1, gfc_expr *expr1, const char *arg2,
gfc_expr *expr2, bool or_equal)
{
int i2, i3;
if (expr2->expr_type == EXPR_CONSTANT)
{
gfc_extract_int (expr2, &i2);
i3 = gfc_validate_kind (BT_INTEGER, expr1->ts.kind, false);
/* For ISHFT[C], check that |shift| <= bit_size(i). */
if (arg2 == NULL)
{
if (i2 < 0)
i2 = -i2;
if (i2 > gfc_integer_kinds[i3].bit_size)
{
gfc_error ("The absolute value of SHIFT at %L must be less "
"than or equal to BIT_SIZE(%qs)",
&expr2->where, arg1);
return false;
}
}
if (or_equal)
{
if (i2 > gfc_integer_kinds[i3].bit_size)
{
gfc_error ("%qs at %L must be less than "
"or equal to BIT_SIZE(%qs)",
arg2, &expr2->where, arg1);
return false;
}
}
else
{
if (i2 >= gfc_integer_kinds[i3].bit_size)
{
gfc_error ("%qs at %L must be less than BIT_SIZE(%qs)",
arg2, &expr2->where, arg1);
return false;
}
}
}
return true;
}
/* If expr is constant, then check that the value is less than or equal
to the bit_size of the kind k. */
static bool
less_than_bitsizekind (const char *arg, gfc_expr *expr, int k)
{
int i, val;
if (expr->expr_type != EXPR_CONSTANT)
return true;
i = gfc_validate_kind (BT_INTEGER, k, false);
gfc_extract_int (expr, &val);
if (val > gfc_integer_kinds[i].bit_size)
{
gfc_error ("%qs at %L must be less than or equal to the BIT_SIZE of "
"INTEGER(KIND=%d)", arg, &expr->where, k);
return false;
}
return true;
}
/* If expr2 and expr3 are constants, then check that the value is less than
or equal to bit_size(expr1). */
static bool
less_than_bitsize2 (const char *arg1, gfc_expr *expr1, const char *arg2,
gfc_expr *expr2, const char *arg3, gfc_expr *expr3)
{
int i2, i3;
if (expr2->expr_type == EXPR_CONSTANT && expr3->expr_type == EXPR_CONSTANT)
{
gfc_extract_int (expr2, &i2);
gfc_extract_int (expr3, &i3);
i2 += i3;
i3 = gfc_validate_kind (BT_INTEGER, expr1->ts.kind, false);
if (i2 > gfc_integer_kinds[i3].bit_size)
{
gfc_error ("%<%s + %s%> at %L must be less than or equal "
"to BIT_SIZE(%qs)",
arg2, arg3, &expr2->where, arg1);
return false;
}
}
return true;
}
/* Make sure two expressions have the same type. */
static bool
same_type_check (gfc_expr *e, int n, gfc_expr *f, int m, bool assoc = false)
{
gfc_typespec *ets = &e->ts;
gfc_typespec *fts = &f->ts;
if (assoc)
{
/* Procedure pointer component expressions have the type of the interface
procedure. If they are being tested for association with a procedure
pointer (ie. not a component), the type of the procedure must be
determined. */
if (e->ts.type == BT_PROCEDURE && e->symtree->n.sym)
ets = &e->symtree->n.sym->ts;
if (f->ts.type == BT_PROCEDURE && f->symtree->n.sym)
fts = &f->symtree->n.sym->ts;
}
if (gfc_compare_types (ets, fts))
return true;
gfc_error ("%qs argument of %qs intrinsic at %L must be the same type "
"and kind as %qs", gfc_current_intrinsic_arg[m]->name,
gfc_current_intrinsic, &f->where,
gfc_current_intrinsic_arg[n]->name);
return false;
}
/* Make sure that an expression has a certain (nonzero) rank. */
static bool
rank_check (gfc_expr *e, int n, int rank)
{
if (e->rank == rank)
return true;
gfc_error ("%qs argument of %qs intrinsic at %L must be of rank %d",
gfc_current_intrinsic_arg[n]->name, gfc_current_intrinsic,
&e->where, rank);
return false;
}
/* Make sure a variable expression is not an optional dummy argument. */
static bool
nonoptional_check (gfc_expr *e, int n)
{
if (e->expr_type == EXPR_VARIABLE && e->symtree->n.sym->attr.optional)
{
gfc_error ("%qs argument of %qs intrinsic at %L must not be OPTIONAL",
gfc_current_intrinsic_arg[n]->name, gfc_current_intrinsic,
&e->where);
}
/* TODO: Recursive check on nonoptional variables? */
return true;
}
/* Check for ALLOCATABLE attribute. */
static bool
allocatable_check (gfc_expr *e, int n)
{
symbol_attribute attr;
attr = gfc_variable_attr (e, NULL);
if (!attr.allocatable
|| (attr.associate_var && !attr.select_rank_temporary))
{
gfc_error ("%qs argument of %qs intrinsic at %L must be ALLOCATABLE",
gfc_current_intrinsic_arg[n]->name, gfc_current_intrinsic,
&e->where);
return false;
}
return true;
}
/* Check that an expression has a particular kind. */
static bool
kind_value_check (gfc_expr *e, int n, int k)
{
if (e->ts.kind == k)
return true;
gfc_error ("%qs argument of %qs intrinsic at %L must be of kind %d",
gfc_current_intrinsic_arg[n]->name, gfc_current_intrinsic,
&e->where, k);
return false;
}
/* Make sure an expression is a variable. */
static bool
variable_check (gfc_expr *e, int n, bool allow_proc)
{
if (e->expr_type == EXPR_VARIABLE
&& e->symtree->n.sym->attr.intent == INTENT_IN
&& (gfc_current_intrinsic_arg[n]->intent == INTENT_OUT
|| gfc_current_intrinsic_arg[n]->intent == INTENT_INOUT)
&& !gfc_check_vardef_context (e, false, true, false, NULL))
{
gfc_error ("%qs argument of %qs intrinsic at %L cannot be INTENT(IN)",
gfc_current_intrinsic_arg[n]->name,
gfc_current_intrinsic, &e->where);
return false;
}
if (e->expr_type == EXPR_VARIABLE
&& e->symtree->n.sym->attr.flavor != FL_PARAMETER
&& (allow_proc || !e->symtree->n.sym->attr.function))
return true;
if (e->expr_type == EXPR_VARIABLE && e->symtree->n.sym->attr.function
&& e->symtree->n.sym == e->symtree->n.sym->result)
{
gfc_namespace *ns;
for (ns = gfc_current_ns; ns; ns = ns->parent)
if (ns->proc_name == e->symtree->n.sym)
return true;
}
/* F2018:R902: function reference having a data pointer result. */
if (e->expr_type == EXPR_FUNCTION
&& e->symtree->n.sym->attr.flavor == FL_PROCEDURE
&& e->symtree->n.sym->attr.function
&& e->symtree->n.sym->attr.pointer)
return true;
gfc_error ("%qs argument of %qs intrinsic at %L must be a variable",
gfc_current_intrinsic_arg[n]->name, gfc_current_intrinsic, &e->where);
return false;
}
/* Check the common DIM parameter for correctness. */
static bool
dim_check (gfc_expr *dim, int n, bool optional)
{
if (dim == NULL)
return true;
if (!type_check (dim, n, BT_INTEGER))
return false;
if (!scalar_check (dim, n))
return false;
if (!optional && !nonoptional_check (dim, n))
return false;
return true;
}
/* If a coarray DIM parameter is a constant, make sure that it is greater than
zero and less than or equal to the corank of the given array. */
static bool
dim_corank_check (gfc_expr *dim, gfc_expr *array)
{
int corank;
gcc_assert (array->expr_type == EXPR_VARIABLE);
if (dim->expr_type != EXPR_CONSTANT)
return true;
if (array->ts.type == BT_CLASS)
return true;
corank = gfc_get_corank (array);
if (mpz_cmp_ui (dim->value.integer, 1) < 0
|| mpz_cmp_ui (dim->value.integer, corank) > 0)
{
gfc_error ("%<dim%> argument of %qs intrinsic at %L is not a valid "
"codimension index", gfc_current_intrinsic, &dim->where);
return false;
}
return true;
}
/* If a DIM parameter is a constant, make sure that it is greater than
zero and less than or equal to the rank of the given array. If
allow_assumed is zero then dim must be less than the rank of the array
for assumed size arrays. */
static bool
dim_rank_check (gfc_expr *dim, gfc_expr *array, int allow_assumed)
{
gfc_array_ref *ar;
int rank;
if (dim == NULL)
return true;
if (dim->expr_type != EXPR_CONSTANT)
return true;
if (array->expr_type == EXPR_FUNCTION && array->value.function.isym
&& array->value.function.isym->id == GFC_ISYM_SPREAD)
rank = array->rank + 1;
else
rank = array->rank;
/* Assumed-rank array. */
if (rank == -1)
rank = GFC_MAX_DIMENSIONS;
if (array->expr_type == EXPR_VARIABLE)
{
ar = gfc_find_array_ref (array, true);
if (!ar)
return false;
if (ar->as->type == AS_ASSUMED_SIZE
&& !allow_assumed
&& ar->type != AR_ELEMENT
&& ar->type != AR_SECTION)
rank--;
}
if (mpz_cmp_ui (dim->value.integer, 1) < 0
|| mpz_cmp_ui (dim->value.integer, rank) > 0)
{
gfc_error ("%<dim%> argument of %qs intrinsic at %L is not a valid "
"dimension index", gfc_current_intrinsic, &dim->where);
return false;
}
return true;
}
/* Compare the size of a along dimension ai with the size of b along
dimension bi, returning 0 if they are known not to be identical,
and 1 if they are identical, or if this cannot be determined. */
static int
identical_dimen_shape (gfc_expr *a, int ai, gfc_expr *b, int bi)
{
mpz_t a_size, b_size;
int ret;
gcc_assert (a->rank > ai);
gcc_assert (b->rank > bi);
ret = 1;
if (gfc_array_dimen_size (a, ai, &a_size))
{
if (gfc_array_dimen_size (b, bi, &b_size))
{
if (mpz_cmp (a_size, b_size) != 0)
ret = 0;
mpz_clear (b_size);
}
mpz_clear (a_size);
}
return ret;
}
/* Calculate the length of a character variable, including substrings.
Strip away parentheses if necessary. Return -1 if no length could
be determined. */
static long
gfc_var_strlen (const gfc_expr *a)
{
gfc_ref *ra;
while (a->expr_type == EXPR_OP && a->value.op.op == INTRINSIC_PARENTHESES)
a = a->value.op.op1;
for (ra = a->ref; ra != NULL && ra->type != REF_SUBSTRING; ra = ra->next)
;
if (ra)
{
long start_a, end_a;
if (!ra->u.ss.end)
return -1;
if ((!ra->u.ss.start || ra->u.ss.start->expr_type == EXPR_CONSTANT)
&& ra->u.ss.end->expr_type == EXPR_CONSTANT)
{
start_a = ra->u.ss.start ? mpz_get_si (ra->u.ss.start->value.integer)
: 1;
end_a = mpz_get_si (ra->u.ss.end->value.integer);
return (end_a < start_a) ? 0 : end_a - start_a + 1;
}
else if (ra->u.ss.start
&& gfc_dep_compare_expr (ra->u.ss.start, ra->u.ss.end) == 0)
return 1;
else
return -1;
}
if (a->ts.u.cl && a->ts.u.cl->length
&& a->ts.u.cl->length->expr_type == EXPR_CONSTANT)
return mpz_get_si (a->ts.u.cl->length->value.integer);
else if (a->expr_type == EXPR_CONSTANT
&& (a->ts.u.cl == NULL || a->ts.u.cl->length == NULL))
return a->value.character.length;
else
return -1;
}
/* Check whether two character expressions have the same length;
returns true if they have or if the length cannot be determined,
otherwise return false and raise a gfc_error. */
bool
gfc_check_same_strlen (const gfc_expr *a, const gfc_expr *b, const char *name)
{
long len_a, len_b;
len_a = gfc_var_strlen(a);
len_b = gfc_var_strlen(b);
if (len_a == -1 || len_b == -1 || len_a == len_b)
return true;
else
{
gfc_error ("Unequal character lengths (%ld/%ld) in %s at %L",
len_a, len_b, name, &a->where);
return false;
}
}
/***** Check functions *****/
/* Check subroutine suitable for intrinsics taking a real argument and
a kind argument for the result. */
static bool
check_a_kind (gfc_expr *a, gfc_expr *kind, bt type)
{
if (!type_check (a, 0, BT_REAL))
return false;
if (!kind_check (kind, 1, type))
return false;
return true;
}
/* Check subroutine suitable for ceiling, floor and nint. */
bool
gfc_check_a_ikind (gfc_expr *a, gfc_expr *kind)
{
return check_a_kind (a, kind, BT_INTEGER);
}
/* Check subroutine suitable for aint, anint. */
bool
gfc_check_a_xkind (gfc_expr *a, gfc_expr *kind)
{
return check_a_kind (a, kind, BT_REAL);
}
bool
gfc_check_abs (gfc_expr *a)
{
if (!numeric_check (a, 0))
return false;
return true;
}
bool
gfc_check_achar (gfc_expr *a, gfc_expr *kind)
{
if (a->ts.type == BT_BOZ)
{
if (gfc_invalid_boz (G_("BOZ literal constant at %L cannot appear in "
"ACHAR intrinsic subprogram"), &a->where))
return false;
if (!gfc_boz2int (a, gfc_default_integer_kind))
return false;
}
if (!type_check (a, 0, BT_INTEGER))
return false;
if (!kind_check (kind, 1, BT_CHARACTER))
return false;
return true;
}
bool
gfc_check_access_func (gfc_expr *name, gfc_expr *mode)
{
if (!type_check (name, 0, BT_CHARACTER)
|| !scalar_check (name, 0))
return false;
if (!kind_value_check (name, 0, gfc_default_character_kind))
return false;
if (!type_check (mode, 1, BT_CHARACTER)
|| !scalar_check (mode, 1))
return false;
if (!kind_value_check (mode, 1, gfc_default_character_kind))
return false;
return true;
}
bool
gfc_check_all_any (gfc_expr *mask, gfc_expr *dim)
{
if (!logical_array_check (mask, 0))
return false;
if (!dim_check (dim, 1, false))
return false;
if (!dim_rank_check (dim, mask, 0))
return false;
return true;
}
/* Limited checking for ALLOCATED intrinsic. Additional checking
is performed in intrinsic.cc(sort_actual), because ALLOCATED
has two mutually exclusive non-optional arguments. */
bool
gfc_check_allocated (gfc_expr *array)
{
/* Tests on allocated components of coarrays need to detour the check to
argument of the _caf_get. */
if (flag_coarray == GFC_FCOARRAY_LIB && array->expr_type == EXPR_FUNCTION
&& array->value.function.isym
&& array->value.function.isym->id == GFC_ISYM_CAF_GET)
{
array = array->value.function.actual->expr;
if (!array->ref)
return false;
}
if (!variable_check (array, 0, false))
return false;
if (!allocatable_check (array, 0))
return false;
return true;
}
/* Common check function where the first argument must be real or
integer and the second argument must be the same as the first. */
bool
gfc_check_a_p (gfc_expr *a, gfc_expr *p)
{
if (!int_or_real_check (a, 0))
return false;
if (a->ts.type != p->ts.type)
{
gfc_error ("%qs and %qs arguments of %qs intrinsic at %L must "
"have the same type", gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic_arg[1]->name, gfc_current_intrinsic,
&p->where);
return false;
}
if (a->ts.kind != p->ts.kind)
{
if (!gfc_notify_std (GFC_STD_GNU, "Different type kinds at %L",
&p->where))
return false;
}
return true;
}
bool
gfc_check_x_yd (gfc_expr *x, gfc_expr *y)
{
if (!double_check (x, 0) || !double_check (y, 1))
return false;
return true;
}
bool
gfc_invalid_null_arg (gfc_expr *x)
{
if (x->expr_type == EXPR_NULL)
{
gfc_error ("NULL at %L is not permitted as actual argument "
"to %qs intrinsic function", &x->where,
gfc_current_intrinsic);
return true;
}
return false;
}
bool
gfc_check_associated (gfc_expr *pointer, gfc_expr *target)
{
symbol_attribute attr1, attr2;
int i;
bool t;
if (gfc_invalid_null_arg (pointer))
return false;
attr1 = gfc_expr_attr (pointer);
if (!attr1.pointer && !attr1.proc_pointer)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be a POINTER",
gfc_current_intrinsic_arg[0]->name, gfc_current_intrinsic,
&pointer->where);
return false;
}
/* F2008, C1242. */
if (attr1.pointer && gfc_is_coindexed (pointer))
{
gfc_error ("%qs argument of %qs intrinsic at %L shall not be "
"coindexed", gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic, &pointer->where);
return false;
}
/* Target argument is optional. */
if (target == NULL)
return true;
if (gfc_invalid_null_arg (target))
return false;
if (target->expr_type == EXPR_VARIABLE || target->expr_type == EXPR_FUNCTION)
attr2 = gfc_expr_attr (target);
else
{
gfc_error ("%qs argument of %qs intrinsic at %L must be a pointer "
"or target VARIABLE or FUNCTION",
gfc_current_intrinsic_arg[1]->name, gfc_current_intrinsic,
&target->where);
return false;
}
if (attr1.pointer && !attr2.pointer && !attr2.target)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be a POINTER "
"or a TARGET", gfc_current_intrinsic_arg[1]->name,
gfc_current_intrinsic, &target->where);
return false;
}
/* F2008, C1242. */
if (attr1.pointer && gfc_is_coindexed (target))
{
gfc_error ("%qs argument of %qs intrinsic at %L shall not be "
"coindexed", gfc_current_intrinsic_arg[1]->name,
gfc_current_intrinsic, &target->where);
return false;
}
t = true;
if (!same_type_check (pointer, 0, target, 1, true))
t = false;
/* F2018 C838 explicitly allows an assumed-rank variable as the first
argument of intrinsic inquiry functions. */
if (pointer->rank != -1 && !rank_check (target, 0, pointer->rank))
t = false;
if (target->rank > 0 && target->ref)
{
for (i = 0; i < target->rank; i++)
if (target->ref->u.ar.dimen_type[i] == DIMEN_VECTOR)
{
gfc_error ("Array section with a vector subscript at %L shall not "
"be the target of a pointer",
&target->where);
t = false;
break;
}
}
return t;
}
bool
gfc_check_atan_2 (gfc_expr *y, gfc_expr *x)
{
/* gfc_notify_std would be a waste of time as the return value
is seemingly used only for the generic resolution. The error
will be: Too many arguments. */
if ((gfc_option.allow_std & GFC_STD_F2008) == 0)
return false;
return gfc_check_atan2 (y, x);
}
bool
gfc_check_atan2 (gfc_expr *y, gfc_expr *x)
{
if (!type_check (y, 0, BT_REAL))
return false;
if (!same_type_check (y, 0, x, 1))
return false;
return true;
}
static bool
gfc_check_atomic (gfc_expr *atom, int atom_no, gfc_expr *value, int val_no,
gfc_expr *stat, int stat_no)
{
if (!scalar_check (atom, atom_no) || !scalar_check (value, val_no))
return false;
if (!(atom->ts.type == BT_INTEGER && atom->ts.kind == gfc_atomic_int_kind)
&& !(atom->ts.type == BT_LOGICAL
&& atom->ts.kind == gfc_atomic_logical_kind))
{
gfc_error ("ATOM argument at %L to intrinsic function %s shall be an "
"integer of ATOMIC_INT_KIND or a logical of "
"ATOMIC_LOGICAL_KIND", &atom->where, gfc_current_intrinsic);
return false;
}
if (!gfc_is_coarray (atom) && !gfc_is_coindexed (atom))
{
gfc_error ("ATOM argument at %L of the %s intrinsic function shall be a "
"coarray or coindexed", &atom->where, gfc_current_intrinsic);
return false;
}
if (atom->ts.type != value->ts.type)
{
gfc_error ("%qs argument of %qs intrinsic at %L shall have the same "
"type as %qs at %L", gfc_current_intrinsic_arg[val_no]->name,
gfc_current_intrinsic, &value->where,
gfc_current_intrinsic_arg[atom_no]->name, &atom->where);
return false;
}
if (stat != NULL)
{
if (!type_check (stat, stat_no, BT_INTEGER))
return false;
if (!scalar_check (stat, stat_no))
return false;
if (!variable_check (stat, stat_no, false))
return false;
if (!kind_value_check (stat, stat_no, gfc_default_integer_kind))
return false;
if (!gfc_notify_std (GFC_STD_F2018, "STAT= argument to %s at %L",
gfc_current_intrinsic, &stat->where))
return false;
}
return true;
}
bool
gfc_check_atomic_def (gfc_expr *atom, gfc_expr *value, gfc_expr *stat)
{
if (atom->expr_type == EXPR_FUNCTION
&& atom->value.function.isym
&& atom->value.function.isym->id == GFC_ISYM_CAF_GET)
atom = atom->value.function.actual->expr;
if (!gfc_check_vardef_context (atom, false, false, false, NULL))
{
gfc_error ("ATOM argument of the %s intrinsic function at %L shall be "
"definable", gfc_current_intrinsic, &atom->where);
return false;
}
return gfc_check_atomic (atom, 0, value, 1, stat, 2);
}
bool
gfc_check_atomic_op (gfc_expr *atom, gfc_expr *value, gfc_expr *stat)
{
if (atom->ts.type != BT_INTEGER || atom->ts.kind != gfc_atomic_int_kind)
{
gfc_error ("ATOM argument at %L to intrinsic function %s shall be an "
"integer of ATOMIC_INT_KIND", &atom->where,
gfc_current_intrinsic);
return false;
}
return gfc_check_atomic_def (atom, value, stat);
}
bool
gfc_check_atomic_ref (gfc_expr *value, gfc_expr *atom, gfc_expr *stat)
{
if (atom->expr_type == EXPR_FUNCTION
&& atom->value.function.isym
&& atom->value.function.isym->id == GFC_ISYM_CAF_GET)
atom = atom->value.function.actual->expr;
if (!gfc_check_vardef_context (value, false, false, false, NULL))
{
gfc_error ("VALUE argument of the %s intrinsic function at %L shall be "
"definable", gfc_current_intrinsic, &value->where);
return false;
}
return gfc_check_atomic (atom, 1, value, 0, stat, 2);
}
bool
gfc_check_image_status (gfc_expr *image, gfc_expr *team)
{
/* IMAGE has to be a positive, scalar integer. */
if (!type_check (image, 0, BT_INTEGER) || !scalar_check (image, 0)
|| !positive_check (0, image))
return false;
if (team)
{
gfc_error ("%qs argument of %qs intrinsic at %L not yet supported",
gfc_current_intrinsic_arg[1]->name, gfc_current_intrinsic,
&team->where);
return false;
}
return true;
}
bool
gfc_check_failed_or_stopped_images (gfc_expr *team, gfc_expr *kind)
{
if (team)
{
gfc_error ("%qs argument of %qs intrinsic at %L not yet supported",
gfc_current_intrinsic_arg[0]->name, gfc_current_intrinsic,
&team->where);
return false;
}
if (kind)
{
int k;
if (!type_check (kind, 1, BT_INTEGER) || !scalar_check (kind, 1)
|| !positive_check (1, kind))
return false;
/* Get the kind, reporting error on non-constant or overflow. */
gfc_current_locus = kind->where;
if (gfc_extract_int (kind, &k, 1))
return false;
if (gfc_validate_kind (BT_INTEGER, k, true) == -1)
{
gfc_error ("%qs argument of %qs intrinsic at %L shall specify a "
"valid integer kind", gfc_current_intrinsic_arg[1]->name,
gfc_current_intrinsic, &kind->where);
return false;
}
}
return true;
}
bool
gfc_check_get_team (gfc_expr *level)
{
if (level)
{
gfc_error ("%qs argument of %qs intrinsic at %L not yet supported",
gfc_current_intrinsic_arg[0]->name, gfc_current_intrinsic,
&level->where);
return false;
}
return true;
}
bool
gfc_check_atomic_cas (gfc_expr *atom, gfc_expr *old, gfc_expr *compare,
gfc_expr *new_val, gfc_expr *stat)
{
if (atom->expr_type == EXPR_FUNCTION
&& atom->value.function.isym
&& atom->value.function.isym->id == GFC_ISYM_CAF_GET)
atom = atom->value.function.actual->expr;
if (!gfc_check_atomic (atom, 0, new_val, 3, stat, 4))
return false;
if (!scalar_check (old, 1) || !scalar_check (compare, 2))
return false;
if (!same_type_check (atom, 0, old, 1))
return false;
if (!same_type_check (atom, 0, compare, 2))
return false;
if (!gfc_check_vardef_context (atom, false, false, false, NULL))
{
gfc_error ("ATOM argument of the %s intrinsic function at %L shall be "
"definable", gfc_current_intrinsic, &atom->where);
return false;
}
if (!gfc_check_vardef_context (old, false, false, false, NULL))
{
gfc_error ("OLD argument of the %s intrinsic function at %L shall be "
"definable", gfc_current_intrinsic, &old->where);
return false;
}
return true;
}
bool
gfc_check_event_query (gfc_expr *event, gfc_expr *count, gfc_expr *stat)
{
if (event->ts.type != BT_DERIVED
|| event->ts.u.derived->from_intmod != INTMOD_ISO_FORTRAN_ENV
|| event->ts.u.derived->intmod_sym_id != ISOFORTRAN_EVENT_TYPE)
{
gfc_error ("EVENT argument at %L to the intrinsic EVENT_QUERY "
"shall be of type EVENT_TYPE", &event->where);
return false;
}
if (!scalar_check (event, 0))
return false;
if (!gfc_check_vardef_context (count, false, false, false, NULL))
{
gfc_error ("COUNT argument of the EVENT_QUERY intrinsic function at %L "
"shall be definable", &count->where);
return false;
}
if (!type_check (count, 1, BT_INTEGER))
return false;
int i = gfc_validate_kind (BT_INTEGER, count->ts.kind, false);
int j = gfc_validate_kind (BT_INTEGER, gfc_default_integer_kind, false);
if (gfc_integer_kinds[i].range < gfc_integer_kinds[j].range)
{
gfc_error ("COUNT argument of the EVENT_QUERY intrinsic function at %L "
"shall have at least the range of the default integer",
&count->where);
return false;
}
if (stat != NULL)
{
if (!type_check (stat, 2, BT_INTEGER))
return false;
if (!scalar_check (stat, 2))
return false;
if (!variable_check (stat, 2, false))
return false;
if (!gfc_notify_std (GFC_STD_F2018, "STAT= argument to %s at %L",
gfc_current_intrinsic, &stat->where))
return false;
}
return true;
}
bool
gfc_check_atomic_fetch_op (gfc_expr *atom, gfc_expr *value, gfc_expr *old,
gfc_expr *stat)
{
if (atom->expr_type == EXPR_FUNCTION
&& atom->value.function.isym
&& atom->value.function.isym->id == GFC_ISYM_CAF_GET)
atom = atom->value.function.actual->expr;
if (atom->ts.type != BT_INTEGER || atom->ts.kind != gfc_atomic_int_kind)
{
gfc_error ("ATOM argument at %L to intrinsic function %s shall be an "
"integer of ATOMIC_INT_KIND", &atom->where,
gfc_current_intrinsic);
return false;
}
if (!gfc_check_atomic (atom, 0, value, 1, stat, 3))
return false;
if (!scalar_check (old, 2))
return false;
if (!same_type_check (atom, 0, old, 2))
return false;
if (!gfc_check_vardef_context (atom, false, false, false, NULL))
{
gfc_error ("ATOM argument of the %s intrinsic function at %L shall be "
"definable", gfc_current_intrinsic, &atom->where);
return false;
}
if (!gfc_check_vardef_context (old, false, false, false, NULL))
{
gfc_error ("OLD argument of the %s intrinsic function at %L shall be "
"definable", gfc_current_intrinsic, &old->where);
return false;
}
return true;
}
/* BESJN and BESYN functions. */
bool
gfc_check_besn (gfc_expr *n, gfc_expr *x)
{
if (!type_check (n, 0, BT_INTEGER))
return false;
if (n->expr_type == EXPR_CONSTANT)
{
int i;
gfc_extract_int (n, &i);
if (i < 0 && !gfc_notify_std (GFC_STD_GNU, "Negative argument "
"N at %L", &n->where))
return false;
}
if (!type_check (x, 1, BT_REAL))
return false;
return true;
}
/* Transformational version of the Bessel JN and YN functions. */
bool
gfc_check_bessel_n2 (gfc_expr *n1, gfc_expr *n2, gfc_expr *x)
{
if (!type_check (n1, 0, BT_INTEGER))
return false;
if (!scalar_check (n1, 0))
return false;
if (!nonnegative_check ("N1", n1))
return false;
if (!type_check (n2, 1, BT_INTEGER))
return false;
if (!scalar_check (n2, 1))
return false;
if (!nonnegative_check ("N2", n2))
return false;
if (!type_check (x, 2, BT_REAL))
return false;
if (!scalar_check (x, 2))
return false;
return true;
}
bool
gfc_check_bge_bgt_ble_blt (gfc_expr *i, gfc_expr *j)
{
extern int gfc_max_integer_kind;
/* If i and j are both BOZ, convert to widest INTEGER. */
if (i->ts.type == BT_BOZ && j->ts.type == BT_BOZ)
{
if (!gfc_boz2int (i, gfc_max_integer_kind))
return false;
if (!gfc_boz2int (j, gfc_max_integer_kind))
return false;
}
/* If i is BOZ and j is integer, convert i to type of j. */
if (i->ts.type == BT_BOZ && j->ts.type == BT_INTEGER
&& !gfc_boz2int (i, j->ts.kind))
return false;
/* If j is BOZ and i is integer, convert j to type of i. */
if (j->ts.type == BT_BOZ && i->ts.type == BT_INTEGER
&& !gfc_boz2int (j, i->ts.kind))
return false;
if (!type_check (i, 0, BT_INTEGER))
return false;
if (!type_check (j, 1, BT_INTEGER))
return false;
return true;
}
bool
gfc_check_bitfcn (gfc_expr *i, gfc_expr *pos)
{
if (!type_check (i, 0, BT_INTEGER))
return false;
if (!type_check (pos, 1, BT_INTEGER))
return false;
if (!nonnegative_check ("pos", pos))
return false;
if (!less_than_bitsize1 ("i", i, "pos", pos, false))
return false;
return true;
}
bool
gfc_check_char (gfc_expr *i, gfc_expr *kind)
{
if (i->ts.type == BT_BOZ)
{
if (gfc_invalid_boz (G_("BOZ literal constant at %L cannot appear in "
"CHAR intrinsic subprogram"), &i->where))
return false;
if (!gfc_boz2int (i, gfc_default_integer_kind))
return false;
}
if (!type_check (i, 0, BT_INTEGER))
return false;
if (!kind_check (kind, 1, BT_CHARACTER))
return false;
return true;
}
bool
gfc_check_chdir (gfc_expr *dir)
{
if (!type_check (dir, 0, BT_CHARACTER))
return false;
if (!kind_value_check (dir, 0, gfc_default_character_kind))
return false;
return true;
}
bool
gfc_check_chdir_sub (gfc_expr *dir, gfc_expr *status)
{
if (!type_check (dir, 0, BT_CHARACTER))
return false;
if (!kind_value_check (dir, 0, gfc_default_character_kind))
return false;
if (status == NULL)
return true;
if (!type_check (status, 1, BT_INTEGER))
return false;
if (!scalar_check (status, 1))
return false;
return true;
}
bool
gfc_check_chmod (gfc_expr *name, gfc_expr *mode)
{
if (!type_check (name, 0, BT_CHARACTER))
return false;
if (!kind_value_check (name, 0, gfc_default_character_kind))
return false;
if (!type_check (mode, 1, BT_CHARACTER))
return false;
if (!kind_value_check (mode, 1, gfc_default_character_kind))
return false;
return true;
}
bool
gfc_check_chmod_sub (gfc_expr *name, gfc_expr *mode, gfc_expr *status)
{
if (!type_check (name, 0, BT_CHARACTER))
return false;
if (!kind_value_check (name, 0, gfc_default_character_kind))
return false;
if (!type_check (mode, 1, BT_CHARACTER))
return false;
if (!kind_value_check (mode, 1, gfc_default_character_kind))
return false;
if (status == NULL)
return true;
if (!type_check (status, 2, BT_INTEGER))
return false;
if (!scalar_check (status, 2))
return false;
return true;
}
bool
gfc_check_cmplx (gfc_expr *x, gfc_expr *y, gfc_expr *kind)
{
int k;
/* Check kind first, because it may be needed in conversion of a BOZ. */
if (kind)
{
if (!kind_check (kind, 2, BT_COMPLEX))
return false;
gfc_extract_int (kind, &k);
}
else
k = gfc_default_complex_kind;
if (x->ts.type == BT_BOZ && !gfc_boz2real (x, k))
return false;
if (!numeric_check (x, 0))
return false;
if (y != NULL)
{
if (y->ts.type == BT_BOZ && !gfc_boz2real (y, k))
return false;
if (!numeric_check (y, 1))
return false;
if (x->ts.type == BT_COMPLEX)
{
gfc_error ("%qs argument of %qs intrinsic at %L must not be "
"present if %<x%> is COMPLEX",
gfc_current_intrinsic_arg[1]->name, gfc_current_intrinsic,
&y->where);
return false;
}
if (y->ts.type == BT_COMPLEX)
{
gfc_error ("%qs argument of %qs intrinsic at %L must have a type "
"of either REAL or INTEGER",
gfc_current_intrinsic_arg[1]->name, gfc_current_intrinsic,
&y->where);
return false;
}
}
if (!kind && warn_conversion
&& x->ts.type == BT_REAL && x->ts.kind > gfc_default_real_kind)
gfc_warning_now (OPT_Wconversion, "Conversion from %s to default-kind "
"COMPLEX(%d) at %L might lose precision, consider using "
"the KIND argument", gfc_typename (&x->ts),
gfc_default_real_kind, &x->where);
else if (y && !kind && warn_conversion
&& y->ts.type == BT_REAL && y->ts.kind > gfc_default_real_kind)
gfc_warning_now (OPT_Wconversion, "Conversion from %s to default-kind "
"COMPLEX(%d) at %L might lose precision, consider using "
"the KIND argument", gfc_typename (&y->ts),
gfc_default_real_kind, &y->where);
return true;
}
static bool
check_co_collective (gfc_expr *a, gfc_expr *image_idx, gfc_expr *stat,
gfc_expr *errmsg, bool co_reduce)
{
if (!variable_check (a, 0, false))
return false;
if (!gfc_check_vardef_context (a, false, false, false, "argument 'A' with "
"INTENT(INOUT)"))
return false;
/* Fortran 2008, 12.5.2.4, paragraph 18. */
if (gfc_has_vector_subscript (a))
{
gfc_error ("Argument %<A%> with INTENT(INOUT) at %L of the intrinsic "
"subroutine %s shall not have a vector subscript",
&a->where, gfc_current_intrinsic);
return false;
}
if (gfc_is_coindexed (a))
{
gfc_error ("The A argument at %L to the intrinsic %s shall not be "
"coindexed", &a->where, gfc_current_intrinsic);
return false;
}
if (image_idx != NULL)
{
if (!type_check (image_idx, co_reduce ? 2 : 1, BT_INTEGER))
return false;
if (!scalar_check (image_idx, co_reduce ? 2 : 1))
return false;
}
if (stat != NULL)
{
if (!type_check (stat, co_reduce ? 3 : 2, BT_INTEGER))
return false;
if (!scalar_check (stat, co_reduce ? 3 : 2))
return false;
if (!variable_check (stat, co_reduce ? 3 : 2, false))
return false;
if (stat->ts.kind != 4)
{
gfc_error ("The stat= argument at %L must be a kind=4 integer "
"variable", &stat->where);
return false;
}
}
if (errmsg != NULL)
{
if (!type_check (errmsg, co_reduce ? 4 : 3, BT_CHARACTER))
return false;
if (!scalar_check (errmsg, co_reduce ? 4 : 3))
return false;
if (!variable_check (errmsg, co_reduce ? 4 : 3, false))
return false;
if (errmsg->ts.kind != 1)
{
gfc_error ("The errmsg= argument at %L must be a default-kind "
"character variable", &errmsg->where);
return false;
}
}
if (flag_coarray == GFC_FCOARRAY_NONE)
{
gfc_fatal_error ("Coarrays disabled at %L, use %<-fcoarray=%> to enable",
&a->where);
return false;
}
return true;
}
bool
gfc_check_co_broadcast (gfc_expr *a, gfc_expr *source_image, gfc_expr *stat,
gfc_expr *errmsg)
{
if (a->ts.type == BT_CLASS || gfc_expr_attr (a).alloc_comp)
{
gfc_error ("Support for the A argument at %L which is polymorphic A "
"argument or has allocatable components is not yet "
"implemented", &a->where);
return false;
}
return check_co_collective (a, source_image, stat, errmsg, false);
}
bool
gfc_check_co_reduce (gfc_expr *a, gfc_expr *op, gfc_expr *result_image,
gfc_expr *stat, gfc_expr *errmsg)
{
symbol_attribute attr;
gfc_formal_arglist *formal;
gfc_symbol *sym;
if (a->ts.type == BT_CLASS)
{
gfc_error ("The A argument at %L of CO_REDUCE shall not be polymorphic",
&a->where);
return false;
}
if (gfc_expr_attr (a).alloc_comp)
{
gfc_error ("Support for the A argument at %L with allocatable components"
" is not yet implemented", &a->where);
return false;
}
if (!check_co_collective (a, result_image, stat, errmsg, true))
return false;
if (!gfc_resolve_expr (op))
return false;
attr = gfc_expr_attr (op);
if (!attr.pure || !attr.function)
{
gfc_error ("OPERATION argument at %L must be a PURE function",
&op->where);
return false;
}
if (attr.intrinsic)
{
/* None of the intrinsics fulfills the criteria of taking two arguments,
returning the same type and kind as the arguments and being permitted
as actual argument. */
gfc_error ("Intrinsic function %s at %L is not permitted for CO_REDUCE",
op->symtree->n.sym->name, &op->where);
return false;
}
if (gfc_is_proc_ptr_comp (op))
{
gfc_component *comp = gfc_get_proc_ptr_comp (op);
sym = comp->ts.interface;
}
else
sym = op->symtree->n.sym;
formal = sym->formal;
if (!formal || !formal->next || formal->next->next)
{
gfc_error ("The function passed as OPERATION at %L shall have two "
"arguments", &op->where);
return false;
}
if (sym->result->ts.type == BT_UNKNOWN)
gfc_set_default_type (sym->result, 0, NULL);
if (!gfc_compare_types (&a->ts, &sym->result->ts))
{
gfc_error ("The A argument at %L has type %s but the function passed as "
"OPERATION at %L returns %s",
&a->where, gfc_typename (a), &op->where,
gfc_typename (&sym->result->ts));
return false;
}
if (!gfc_compare_types (&a->ts, &formal->sym->ts)
|| !gfc_compare_types (&a->ts, &formal->next->sym->ts))
{
gfc_error ("The function passed as OPERATION at %L has arguments of type "
"%s and %s but shall have type %s", &op->where,
gfc_typename (&formal->sym->ts),
gfc_typename (&formal->next->sym->ts), gfc_typename (a));
return false;
}
if (op->rank || attr.allocatable || attr.pointer || formal->sym->as
|| formal->next->sym->as || formal->sym->attr.allocatable
|| formal->next->sym->attr.allocatable || formal->sym->attr.pointer
|| formal->next->sym->attr.pointer)
{
gfc_error ("The function passed as OPERATION at %L shall have scalar "
"nonallocatable nonpointer arguments and return a "
"nonallocatable nonpointer scalar", &op->where);
return false;
}
if (formal->sym->attr.value != formal->next->sym->attr.value)
{
gfc_error ("The function passed as OPERATION at %L shall have the VALUE "
"attribute either for none or both arguments", &op->where);
return false;
}
if (formal->sym->attr.target != formal->next->sym->attr.target)
{
gfc_error ("The function passed as OPERATION at %L shall have the TARGET "
"attribute either for none or both arguments", &op->where);
return false;
}
if (formal->sym->attr.asynchronous != formal->next->sym->attr.asynchronous)
{
gfc_error ("The function passed as OPERATION at %L shall have the "
"ASYNCHRONOUS attribute either for none or both arguments",
&op->where);
return false;
}
if (formal->sym->attr.optional || formal->next->sym->attr.optional)
{
gfc_error ("The function passed as OPERATION at %L shall not have the "
"OPTIONAL attribute for either of the arguments", &op->where);
return false;
}
if (a->ts.type == BT_CHARACTER)
{
gfc_charlen *cl;
unsigned long actual_size, formal_size1, formal_size2, result_size;
cl = a->ts.u.cl;
actual_size = cl && cl->length && cl->length->expr_type == EXPR_CONSTANT
? mpz_get_ui (cl->length->value.integer) : 0;
cl = formal->sym->ts.u.cl;
formal_size1 = cl && cl->length && cl->length->expr_type == EXPR_CONSTANT
? mpz_get_ui (cl->length->value.integer) : 0;
cl = formal->next->sym->ts.u.cl;
formal_size2 = cl && cl->length && cl->length->expr_type == EXPR_CONSTANT
? mpz_get_ui (cl->length->value.integer) : 0;
cl = sym->ts.u.cl;
result_size = cl && cl->length && cl->length->expr_type == EXPR_CONSTANT
? mpz_get_ui (cl->length->value.integer) : 0;
if (actual_size
&& ((formal_size1 && actual_size != formal_size1)
|| (formal_size2 && actual_size != formal_size2)))
{
gfc_error ("The character length of the A argument at %L and of the "
"arguments of the OPERATION at %L shall be the same",
&a->where, &op->where);
return false;
}
if (actual_size && result_size && actual_size != result_size)
{
gfc_error ("The character length of the A argument at %L and of the "
"function result of the OPERATION at %L shall be the same",
&a->where, &op->where);
return false;
}
}
return true;
}
bool
gfc_check_co_minmax (gfc_expr *a, gfc_expr *result_image, gfc_expr *stat,
gfc_expr *errmsg)
{
if (a->ts.type != BT_INTEGER && a->ts.type != BT_REAL
&& a->ts.type != BT_CHARACTER)
{
gfc_error ("%qs argument of %qs intrinsic at %L shall be of type "
"integer, real or character",
gfc_current_intrinsic_arg[0]->name, gfc_current_intrinsic,
&a->where);
return false;
}
return check_co_collective (a, result_image, stat, errmsg, false);
}
bool
gfc_check_co_sum (gfc_expr *a, gfc_expr *result_image, gfc_expr *stat,
gfc_expr *errmsg)
{
if (!numeric_check (a, 0))
return false;
return check_co_collective (a, result_image, stat, errmsg, false);
}
bool
gfc_check_complex (gfc_expr *x, gfc_expr *y)
{
if (!boz_args_check (x, y))
return false;
if (x->ts.type == BT_BOZ)
{
if (gfc_invalid_boz (G_("BOZ constant at %L cannot appear in the COMPLEX"
" intrinsic subprogram"), &x->where))
{
reset_boz (x);
return false;
}
if (y->ts.type == BT_INTEGER && !gfc_boz2int (x, y->ts.kind))
return false;
if (y->ts.type == BT_REAL && !gfc_boz2real (x, y->ts.kind))
return false;
}
if (y->ts.type == BT_BOZ)
{
if (gfc_invalid_boz (G_("BOZ constant at %L cannot appear in the COMPLEX"
" intrinsic subprogram"), &y->where))
{
reset_boz (y);
return false;
}
if (x->ts.type == BT_INTEGER && !gfc_boz2int (y, x->ts.kind))
return false;
if (x->ts.type == BT_REAL && !gfc_boz2real (y, x->ts.kind))
return false;
}
if (!int_or_real_check (x, 0))
return false;
if (!scalar_check (x, 0))
return false;
if (!int_or_real_check (y, 1))
return false;
if (!scalar_check (y, 1))
return false;
return true;
}
bool
gfc_check_count (gfc_expr *mask, gfc_expr *dim, gfc_expr *kind)
{
if (!logical_array_check (mask, 0))
return false;
if (!dim_check (dim, 1, false))
return false;
if (!dim_rank_check (dim, mask, 0))
return false;
if (!kind_check (kind, 2, BT_INTEGER))
return false;
if (kind && !gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
"with KIND argument at %L",
gfc_current_intrinsic, &kind->where))
return false;
return true;
}
bool
gfc_check_cshift (gfc_expr *array, gfc_expr *shift, gfc_expr *dim)
{
if (!array_check (array, 0))
return false;
if (!type_check (shift, 1, BT_INTEGER))
return false;
if (!dim_check (dim, 2, true))
return false;
if (!dim_rank_check (dim, array, false))
return false;
if (array->rank == 1 || shift->rank == 0)
{
if (!scalar_check (shift, 1))
return false;
}
else if (shift->rank == array->rank - 1)
{
int d;
if (!dim)
d = 1;
else if (dim->expr_type == EXPR_CONSTANT)
gfc_extract_int (dim, &d);
else
d = -1;
if (d > 0)
{
int i, j;
for (i = 0, j = 0; i < array->rank; i++)
if (i != d - 1)
{
if (!identical_dimen_shape (array, i, shift, j))
{
gfc_error ("%qs argument of %qs intrinsic at %L has "
"invalid shape in dimension %d (%ld/%ld)",
gfc_current_intrinsic_arg[1]->name,
gfc_current_intrinsic, &shift->where, i + 1,
mpz_get_si (array->shape[i]),
mpz_get_si (shift->shape[j]));
return false;
}
j += 1;
}
}
}
else
{
gfc_error ("%qs argument of intrinsic %qs at %L of must have rank "
"%d or be a scalar", gfc_current_intrinsic_arg[1]->name,
gfc_current_intrinsic, &shift->where, array->rank - 1);
return false;
}
return true;
}
bool
gfc_check_ctime (gfc_expr *time)
{
if (!scalar_check (time, 0))
return false;
if (!type_check (time, 0, BT_INTEGER))
return false;
return true;
}
bool gfc_check_datan2 (gfc_expr *y, gfc_expr *x)
{
if (!double_check (y, 0) || !double_check (x, 1))
return false;
return true;
}
bool
gfc_check_dcmplx (gfc_expr *x, gfc_expr *y)
{
if (x->ts.type == BT_BOZ && !gfc_boz2real (x, gfc_default_double_kind))
return false;
if (!numeric_check (x, 0))
return false;
if (y != NULL)
{
if (y->ts.type == BT_BOZ && !gfc_boz2real (y, gfc_default_double_kind))
return false;
if (!numeric_check (y, 1))
return false;
if (x->ts.type == BT_COMPLEX)
{
gfc_error ("%qs argument of %qs intrinsic at %L must not be "
"present if %<x%> is COMPLEX",
gfc_current_intrinsic_arg[1]->name, gfc_current_intrinsic,
&y->where);
return false;
}
if (y->ts.type == BT_COMPLEX)
{
gfc_error ("%qs argument of %qs intrinsic at %L must have a type "
"of either REAL or INTEGER",
gfc_current_intrinsic_arg[1]->name, gfc_current_intrinsic,
&y->where);
return false;
}
}
return true;
}
bool
gfc_check_dble (gfc_expr *x)
{
if (x->ts.type == BT_BOZ && !gfc_boz2real (x, gfc_default_double_kind))
return false;
if (!numeric_check (x, 0))
return false;
return true;
}
bool
gfc_check_digits (gfc_expr *x)
{
if (!int_or_real_check (x, 0))
return false;
return true;
}
bool
gfc_check_dot_product (gfc_expr *vector_a, gfc_expr *vector_b)
{
switch (vector_a->ts.type)
{
case BT_LOGICAL:
if (!type_check (vector_b, 1, BT_LOGICAL))
return false;
break;
case BT_INTEGER:
case BT_REAL:
case BT_COMPLEX:
if (!numeric_check (vector_b, 1))
return false;
break;
default:
gfc_error ("%qs argument of %qs intrinsic at %L must be numeric "
"or LOGICAL", gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic, &vector_a->where);
return false;
}
if (!rank_check (vector_a, 0, 1))
return false;
if (!rank_check (vector_b, 1, 1))
return false;
if (! identical_dimen_shape (vector_a, 0, vector_b, 0))
{
gfc_error ("Different shape for arguments %qs and %qs at %L for "
"intrinsic %<dot_product%>",
gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic_arg[1]->name, &vector_a->where);
return false;
}
return true;
}
bool
gfc_check_dprod (gfc_expr *x, gfc_expr *y)
{
if (!type_check (x, 0, BT_REAL)
|| !type_check (y, 1, BT_REAL))
return false;
if (x->ts.kind != gfc_default_real_kind)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be default "
"real", gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic, &x->where);
return false;
}
if (y->ts.kind != gfc_default_real_kind)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be default "
"real", gfc_current_intrinsic_arg[1]->name,
gfc_current_intrinsic, &y->where);
return false;
}
return true;
}
bool
gfc_check_dshift (gfc_expr *i, gfc_expr *j, gfc_expr *shift)
{
/* i and j cannot both be BOZ literal constants. */
if (!boz_args_check (i, j))
return false;
/* If i is BOZ and j is integer, convert i to type of j. If j is not
an integer, clear the BOZ; otherwise, check that i is an integer. */
if (i->ts.type == BT_BOZ)
{
if (j->ts.type != BT_INTEGER)
reset_boz (i);
else if (!gfc_boz2int (i, j->ts.kind))
return false;
}
else if (!type_check (i, 0, BT_INTEGER))
{
if (j->ts.type == BT_BOZ)
reset_boz (j);
return false;
}
/* If j is BOZ and i is integer, convert j to type of i. If i is not
an integer, clear the BOZ; otherwise, check that i is an integer. */
if (j->ts.type == BT_BOZ)
{
if (i->ts.type != BT_INTEGER)
reset_boz (j);
else if (!gfc_boz2int (j, i->ts.kind))
return false;
}
else if (!type_check (j, 1, BT_INTEGER))
return false;
if (!same_type_check (i, 0, j, 1))
return false;
if (!type_check (shift, 2, BT_INTEGER))
return false;
if (!nonnegative_check ("SHIFT", shift))
return false;
if (!less_than_bitsize1 ("I", i, "SHIFT", shift, true))
return false;
return true;
}
bool
gfc_check_eoshift (gfc_expr *array, gfc_expr *shift, gfc_expr *boundary,
gfc_expr *dim)
{
int d;
if (!array_check (array, 0))
return false;
if (!type_check (shift, 1, BT_INTEGER))
return false;
if (!dim_check (dim, 3, true))
return false;
if (!dim_rank_check (dim, array, false))
return false;
if (!dim)
d = 1;
else if (dim->expr_type == EXPR_CONSTANT)
gfc_extract_int (dim, &d);
else
d = -1;
if (array->rank == 1 || shift->rank == 0)
{
if (!scalar_check (shift, 1))
return false;
}
else if (shift->rank == array->rank - 1)
{
if (d > 0)
{
int i, j;
for (i = 0, j = 0; i < array->rank; i++)
if (i != d - 1)
{
if (!identical_dimen_shape (array, i, shift, j))
{
gfc_error ("%qs argument of %qs intrinsic at %L has "
"invalid shape in dimension %d (%ld/%ld)",
gfc_current_intrinsic_arg[1]->name,
gfc_current_intrinsic, &shift->where, i + 1,
mpz_get_si (array->shape[i]),
mpz_get_si (shift->shape[j]));
return false;
}
j += 1;
}
}
}
else
{
gfc_error ("%qs argument of intrinsic %qs at %L of must have rank "
"%d or be a scalar", gfc_current_intrinsic_arg[1]->name,
gfc_current_intrinsic, &shift->where, array->rank - 1);
return false;
}
if (boundary != NULL)
{
if (!same_type_check (array, 0, boundary, 2))
return false;
/* Reject unequal string lengths and emit a better error message than
gfc_check_same_strlen would. */
if (array->ts.type == BT_CHARACTER)
{
ssize_t len_a, len_b;
len_a = gfc_var_strlen (array);
len_b = gfc_var_strlen (boundary);
if (len_a != -1 && len_b != -1 && len_a != len_b)
{
gfc_error ("%qs must be of same type and kind as %qs at %L in %qs",
gfc_current_intrinsic_arg[2]->name,
gfc_current_intrinsic_arg[0]->name,
&boundary->where, gfc_current_intrinsic);
return false;
}
}
if (array->rank == 1 || boundary->rank == 0)
{
if (!scalar_check (boundary, 2))
return false;
}
else if (boundary->rank == array->rank - 1)
{
if (d > 0)
{
int i,j;
for (i = 0, j = 0; i < array->rank; i++)
{
if (i != d - 1)
{
if (!identical_dimen_shape (array, i, boundary, j))
{
gfc_error ("%qs argument of %qs intrinsic at %L has "
"invalid shape in dimension %d (%ld/%ld)",
gfc_current_intrinsic_arg[2]->name,
gfc_current_intrinsic, &shift->where, i+1,
mpz_get_si (array->shape[i]),
mpz_get_si (boundary->shape[j]));
return false;
}
j += 1;
}
}
}
}
else
{
gfc_error ("%qs argument of intrinsic %qs at %L of must have "
"rank %d or be a scalar",
gfc_current_intrinsic_arg[1]->name, gfc_current_intrinsic,
&shift->where, array->rank - 1);
return false;
}
}
else
{
switch (array->ts.type)
{
case BT_INTEGER:
case BT_LOGICAL:
case BT_REAL:
case BT_COMPLEX:
case BT_CHARACTER:
break;
default:
gfc_error ("Missing %qs argument to %qs intrinsic at %L for %qs "
"of type %qs", gfc_current_intrinsic_arg[2]->name,
gfc_current_intrinsic, &array->where,
gfc_current_intrinsic_arg[0]->name,
gfc_typename (array));
return false;
}
}
return true;
}
bool
gfc_check_float (gfc_expr *a)
{
if (a->ts.type == BT_BOZ)
{
if (gfc_invalid_boz (G_("BOZ literal constant at %L cannot appear in the"
" FLOAT intrinsic subprogram"), &a->where))
{
reset_boz (a);
return false;
}
if (!gfc_boz2int (a, gfc_default_integer_kind))
return false;
}
if (!type_check (a, 0, BT_INTEGER))
return false;
if ((a->ts.kind != gfc_default_integer_kind)
&& !gfc_notify_std (GFC_STD_GNU, "non-default INTEGER "
"kind argument to %s intrinsic at %L",
gfc_current_intrinsic, &a->where))
return false;
return true;
}
/* A single complex argument. */
bool
gfc_check_fn_c (gfc_expr *a)
{
if (!type_check (a, 0, BT_COMPLEX))
return false;
return true;
}
/* A single real argument. */
bool
gfc_check_fn_r (gfc_expr *a)
{
if (!type_check (a, 0, BT_REAL))
return false;
return true;
}
/* A single double argument. */
bool
gfc_check_fn_d (gfc_expr *a)
{
if (!double_check (a, 0))
return false;
return true;
}
/* A single real or complex argument. */
bool
gfc_check_fn_rc (gfc_expr *a)
{
if (!real_or_complex_check (a, 0))
return false;
return true;
}
bool
gfc_check_fn_rc2008 (gfc_expr *a)
{
if (!real_or_complex_check (a, 0))
return false;
if (a->ts.type == BT_COMPLEX
&& !gfc_notify_std (GFC_STD_F2008, "COMPLEX argument %qs "
"of %qs intrinsic at %L",
gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic, &a->where))
return false;
return true;
}
bool
gfc_check_fnum (gfc_expr *unit)
{
if (!type_check (unit, 0, BT_INTEGER))
return false;
if (!scalar_check (unit, 0))
return false;
return true;
}
bool
gfc_check_huge (gfc_expr *x)
{
if (!int_or_real_check (x, 0))
return false;
return true;
}
bool
gfc_check_hypot (gfc_expr *x, gfc_expr *y)
{
if (!type_check (x, 0, BT_REAL))
return false;
if (!same_type_check (x, 0, y, 1))
return false;
return true;
}
/* Check that the single argument is an integer. */
bool
gfc_check_i (gfc_expr *i)
{
if (!type_check (i, 0, BT_INTEGER))
return false;
return true;
}
bool
gfc_check_iand_ieor_ior (gfc_expr *i, gfc_expr *j)
{
/* i and j cannot both be BOZ literal constants. */
if (!boz_args_check (i, j))
return false;
/* If i is BOZ and j is integer, convert i to type of j. */
if (i->ts.type == BT_BOZ && j->ts.type == BT_INTEGER
&& !gfc_boz2int (i, j->ts.kind))
return false;
/* If j is BOZ and i is integer, convert j to type of i. */
if (j->ts.type == BT_BOZ && i->ts.type == BT_INTEGER
&& !gfc_boz2int (j, i->ts.kind))
return false;
if (!type_check (i, 0, BT_INTEGER))
return false;
if (!type_check (j, 1, BT_INTEGER))
return false;
if (i->ts.kind != j->ts.kind)
{
gfc_error ("Arguments of %qs have different kind type parameters "
"at %L", gfc_current_intrinsic, &i->where);
return false;
}
return true;
}
bool
gfc_check_ibits (gfc_expr *i, gfc_expr *pos, gfc_expr *len)
{
if (!type_check (i, 0, BT_INTEGER))
return false;
if (!type_check (pos, 1, BT_INTEGER))
return false;
if (!type_check (len, 2, BT_INTEGER))
return false;
if (!nonnegative_check ("pos", pos))
return false;
if (!nonnegative_check ("len", len))
return false;
if (!less_than_bitsize2 ("i", i, "pos", pos, "len", len))
return false;
return true;
}
bool
gfc_check_ichar_iachar (gfc_expr *c, gfc_expr *kind)
{
int i;
if (!type_check (c, 0, BT_CHARACTER))
return false;
if (!kind_check (kind, 1, BT_INTEGER))
return false;
if (kind && !gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
"with KIND argument at %L",
gfc_current_intrinsic, &kind->where))
return false;
if (c->expr_type == EXPR_VARIABLE || c->expr_type == EXPR_SUBSTRING)
{
gfc_expr *start;
gfc_expr *end;
gfc_ref *ref;
/* Substring references don't have the charlength set. */
ref = c->ref;
while (ref && ref->type != REF_SUBSTRING)
ref = ref->next;
gcc_assert (ref == NULL || ref->type == REF_SUBSTRING);
if (!ref)
{
/* Check that the argument is length one. Non-constant lengths
can't be checked here, so assume they are ok. */
if (c->ts.u.cl && c->ts.u.cl->length)
{
/* If we already have a length for this expression then use it. */
if (c->ts.u.cl->length->expr_type != EXPR_CONSTANT)
return true;
i = mpz_get_si (c->ts.u.cl->length->value.integer);
}
else
return true;
}
else
{
start = ref->u.ss.start;
end = ref->u.ss.end;
gcc_assert (start);
if (end == NULL || end->expr_type != EXPR_CONSTANT
|| start->expr_type != EXPR_CONSTANT)
return true;
i = mpz_get_si (end->value.integer) + 1
- mpz_get_si (start->value.integer);
}
}
else
return true;
if (i != 1)
{
gfc_error ("Argument of %s at %L must be of length one",
gfc_current_intrinsic, &c->where);
return false;
}
return true;
}
bool
gfc_check_idnint (gfc_expr *a)
{
if (!double_check (a, 0))
return false;
return true;
}
bool
gfc_check_index (gfc_expr *string, gfc_expr *substring, gfc_expr *back,
gfc_expr *kind)
{
if (!type_check (string, 0, BT_CHARACTER)
|| !type_check (substring, 1, BT_CHARACTER))
return false;
if (back != NULL && !type_check (back, 2, BT_LOGICAL))
return false;
if (!kind_check (kind, 3, BT_INTEGER))
return false;
if (kind && !gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
"with KIND argument at %L",
gfc_current_intrinsic, &kind->where))
return false;
if (string->ts.kind != substring->ts.kind)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be the same "
"kind as %qs", gfc_current_intrinsic_arg[1]->name,
gfc_current_intrinsic, &substring->where,
gfc_current_intrinsic_arg[0]->name);
return false;
}
return true;
}
bool
gfc_check_int (gfc_expr *x, gfc_expr *kind)
{
/* BOZ is dealt within simplify_int*. */
if (x->ts.type == BT_BOZ)
return true;
if (!numeric_check (x, 0))
return false;
if (!kind_check (kind, 1, BT_INTEGER))
return false;
return true;
}
bool
gfc_check_intconv (gfc_expr *x)
{
if (strcmp (gfc_current_intrinsic, "short") == 0
|| strcmp (gfc_current_intrinsic, "long") == 0)
{
gfc_error ("%qs intrinsic subprogram at %L has been removed. "
"Use INT intrinsic subprogram.", gfc_current_intrinsic,
&x->where);
return false;
}
/* BOZ is dealt within simplify_int*. */
if (x->ts.type == BT_BOZ)
return true;
if (!numeric_check (x, 0))
return false;
return true;
}
bool
gfc_check_ishft (gfc_expr *i, gfc_expr *shift)
{
if (!type_check (i, 0, BT_INTEGER)
|| !type_check (shift, 1, BT_INTEGER))
return false;
if (!less_than_bitsize1 ("I", i, NULL, shift, true))
return false;
return true;
}
bool
gfc_check_ishftc (gfc_expr *i, gfc_expr *shift, gfc_expr *size)
{
if (!type_check (i, 0, BT_INTEGER)
|| !type_check (shift, 1, BT_INTEGER))
return false;
if (size != NULL)
{
int i2, i3;
if (!type_check (size, 2, BT_INTEGER))
return false;
if (!less_than_bitsize1 ("I", i, "SIZE", size, true))
return false;
if (size->expr_type == EXPR_CONSTANT)
{
gfc_extract_int (size, &i3);
if (i3 <= 0)
{
gfc_error ("SIZE at %L must be positive", &size->where);
return false;
}
if (shift->expr_type == EXPR_CONSTANT)
{
gfc_extract_int (shift, &i2);
if (i2 < 0)
i2 = -i2;
if (i2 > i3)
{
gfc_error ("The absolute value of SHIFT at %L must be less "
"than or equal to SIZE at %L", &shift->where,
&size->where);
return false;
}
}
}
}
else if (!less_than_bitsize1 ("I", i, NULL, shift, true))
return false;
return true;
}
bool
gfc_check_kill (gfc_expr *pid, gfc_expr *sig)
{
if (!type_check (pid, 0, BT_INTEGER))
return false;
if (!scalar_check (pid, 0))
return false;
if (!type_check (sig, 1, BT_INTEGER))
return false;
if (!scalar_check (sig, 1))
return false;
return true;
}
bool
gfc_check_kill_sub (gfc_expr *pid, gfc_expr *sig, gfc_expr *status)
{
if (!type_check (pid, 0, BT_INTEGER))
return false;
if (!scalar_check (pid, 0))
return false;
if (!type_check (sig, 1, BT_INTEGER))
return false;
if (!scalar_check (sig, 1))
return false;
if (status)
{
if (!type_check (status, 2, BT_INTEGER))
return false;
if (!scalar_check (status, 2))
return false;
if (status->expr_type != EXPR_VARIABLE)
{
gfc_error ("STATUS at %L shall be an INTENT(OUT) variable",
&status->where);
return false;
}
if (status->expr_type == EXPR_VARIABLE
&& status->symtree && status->symtree->n.sym
&& status->symtree->n.sym->attr.intent == INTENT_IN)
{
gfc_error ("%qs at %L shall be an INTENT(OUT) variable",
status->symtree->name, &status->where);
return false;
}
}
return true;
}
bool
gfc_check_kind (gfc_expr *x)
{
if (gfc_invalid_null_arg (x))
return false;
if (gfc_bt_struct (x->ts.type) || x->ts.type == BT_CLASS)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be of "
"intrinsic type", gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic, &x->where);
return false;
}
if (x->ts.type == BT_PROCEDURE)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be a data entity",
gfc_current_intrinsic_arg[0]->name, gfc_current_intrinsic,
&x->where);
return false;
}
return true;
}
bool
gfc_check_lbound (gfc_expr *array, gfc_expr *dim, gfc_expr *kind)
{
if (!array_check (array, 0))
return false;
if (!dim_check (dim, 1, false))
return false;
if (!dim_rank_check (dim, array, 1))
return false;
if (!kind_check (kind, 2, BT_INTEGER))
return false;
if (kind && !gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
"with KIND argument at %L",
gfc_current_intrinsic, &kind->where))
return false;
return true;
}
bool
gfc_check_lcobound (gfc_expr *coarray, gfc_expr *dim, gfc_expr *kind)
{
if (flag_coarray == GFC_FCOARRAY_NONE)
{
gfc_fatal_error ("Coarrays disabled at %C, use %<-fcoarray=%> to enable");
return false;
}
if (!coarray_check (coarray, 0))
return false;
if (dim != NULL)
{
if (!dim_check (dim, 1, false))
return false;
if (!dim_corank_check (dim, coarray))
return false;
}
if (!kind_check (kind, 2, BT_INTEGER))
return false;
return true;
}
bool
gfc_check_len_lentrim (gfc_expr *s, gfc_expr *kind)
{
if (!type_check (s, 0, BT_CHARACTER))
return false;
if (gfc_invalid_null_arg (s))
return false;
if (!kind_check (kind, 1, BT_INTEGER))
return false;
if (kind && !gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
"with KIND argument at %L",
gfc_current_intrinsic, &kind->where))
return false;
return true;
}
bool
gfc_check_lge_lgt_lle_llt (gfc_expr *a, gfc_expr *b)
{
if (!type_check (a, 0, BT_CHARACTER))
return false;
if (!kind_value_check (a, 0, gfc_default_character_kind))
return false;
if (!type_check (b, 1, BT_CHARACTER))
return false;
if (!kind_value_check (b, 1, gfc_default_character_kind))
return false;
return true;
}
bool
gfc_check_link (gfc_expr *path1, gfc_expr *path2)
{
if (!type_check (path1, 0, BT_CHARACTER))
return false;
if (!kind_value_check (path1, 0, gfc_default_character_kind))
return false;
if (!type_check (path2, 1, BT_CHARACTER))
return false;
if (!kind_value_check (path2, 1, gfc_default_character_kind))
return false;
return true;
}
bool
gfc_check_link_sub (gfc_expr *path1, gfc_expr *path2, gfc_expr *status)
{
if (!type_check (path1, 0, BT_CHARACTER))
return false;
if (!kind_value_check (path1, 0, gfc_default_character_kind))
return false;
if (!type_check (path2, 1, BT_CHARACTER))
return false;
if (!kind_value_check (path2, 0, gfc_default_character_kind))
return false;
if (status == NULL)
return true;
if (!type_check (status, 2, BT_INTEGER))
return false;
if (!scalar_check (status, 2))
return false;
return true;
}
bool
gfc_check_loc (gfc_expr *expr)
{
return variable_check (expr, 0, true);
}
bool
gfc_check_symlnk (gfc_expr *path1, gfc_expr *path2)
{
if (!type_check (path1, 0, BT_CHARACTER))
return false;
if (!kind_value_check (path1, 0, gfc_default_character_kind))
return false;
if (!type_check (path2, 1, BT_CHARACTER))
return false;
if (!kind_value_check (path2, 1, gfc_default_character_kind))
return false;
return true;
}
bool
gfc_check_symlnk_sub (gfc_expr *path1, gfc_expr *path2, gfc_expr *status)
{
if (!type_check (path1, 0, BT_CHARACTER))
return false;
if (!kind_value_check (path1, 0, gfc_default_character_kind))
return false;
if (!type_check (path2, 1, BT_CHARACTER))
return false;
if (!kind_value_check (path2, 1, gfc_default_character_kind))
return false;
if (status == NULL)
return true;
if (!type_check (status, 2, BT_INTEGER))
return false;
if (!scalar_check (status, 2))
return false;
return true;
}
bool
gfc_check_logical (gfc_expr *a, gfc_expr *kind)
{
if (!type_check (a, 0, BT_LOGICAL))
return false;
if (!kind_check (kind, 1, BT_LOGICAL))
return false;
return true;
}
/* Min/max family. */
static bool
min_max_args (gfc_actual_arglist *args)
{
gfc_actual_arglist *arg;
int i, j, nargs, *nlabels, nlabelless;
bool a1 = false, a2 = false;
if (args == NULL || args->next == NULL)
{
gfc_error ("Intrinsic %qs at %L must have at least two arguments",
gfc_current_intrinsic, gfc_current_intrinsic_where);
return false;
}
if (!args->name)
a1 = true;
if (!args->next->name)
a2 = true;
nargs = 0;
for (arg = args; arg; arg = arg->next)
if (arg->name)
nargs++;
if (nargs == 0)
return true;
/* Note: Having a keywordless argument after an "arg=" is checked before. */
nlabelless = 0;
nlabels = XALLOCAVEC (int, nargs);
for (arg = args, i = 0; arg; arg = arg->next, i++)
if (arg->name)
{
int n;
char *endp;
if (arg->name[0] != 'a' || arg->name[1] < '1' || arg->name[1] > '9')
goto unknown;
n = strtol (&arg->name[1], &endp, 10);
if (endp[0] != '\0')
goto unknown;
if (n <= 0)
goto unknown;
if (n <= nlabelless)
goto duplicate;
nlabels[i] = n;
if (n == 1)
a1 = true;
if (n == 2)
a2 = true;
}
else
nlabelless++;
if (!a1 || !a2)
{
gfc_error ("Missing %qs argument to the %s intrinsic at %L",
!a1 ? "a1" : "a2", gfc_current_intrinsic,
gfc_current_intrinsic_where);
return false;
}
/* Check for duplicates. */
for (i = 0; i < nargs; i++)
for (j = i + 1; j < nargs; j++)
if (nlabels[i] == nlabels[j])
goto duplicate;
return true;
duplicate:
gfc_error ("Duplicate argument %qs at %L to intrinsic %s", arg->name,
&arg->expr->where, gfc_current_intrinsic);
return false;
unknown:
gfc_error ("Unknown argument %qs at %L to intrinsic %s", arg->name,
&arg->expr->where, gfc_current_intrinsic);
return false;
}
static bool
check_rest (bt type, int kind, gfc_actual_arglist *arglist)
{
gfc_actual_arglist *arg, *tmp;
gfc_expr *x;
int m, n;
if (!min_max_args (arglist))
return false;
for (arg = arglist, n=1; arg; arg = arg->next, n++)
{
x = arg->expr;
if (x->ts.type != type || x->ts.kind != kind)
{
if (x->ts.type == type)
{
if (x->ts.type == BT_CHARACTER)
{
gfc_error ("Different character kinds at %L", &x->where);
return false;
}
if (!gfc_notify_std (GFC_STD_GNU, "Different type "
"kinds at %L", &x->where))
return false;
}
else
{
gfc_error ("%<a%d%> argument of %qs intrinsic at %L must be "
"%s(%d)", n, gfc_current_intrinsic, &x->where,
gfc_basic_typename (type), kind);
return false;
}
}
for (tmp = arglist, m=1; tmp != arg; tmp = tmp->next, m++)
if (!gfc_check_conformance (tmp->expr, x,
_("arguments 'a%d' and 'a%d' for "
"intrinsic '%s'"), m, n,
gfc_current_intrinsic))
return false;
}
return true;
}
bool
gfc_check_min_max (gfc_actual_arglist *arg)
{
gfc_expr *x;
if (!min_max_args (arg))
return false;
x = arg->expr;
if (x->ts.type == BT_CHARACTER)
{
if (!gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
"with CHARACTER argument at %L",
gfc_current_intrinsic, &x->where))
return false;
}
else if (x->ts.type != BT_INTEGER && x->ts.type != BT_REAL)
{
gfc_error ("%<a1%> argument of %qs intrinsic at %L must be INTEGER, "
"REAL or CHARACTER", gfc_current_intrinsic, &x->where);
return false;
}
return check_rest (x->ts.type, x->ts.kind, arg);
}
bool
gfc_check_min_max_integer (gfc_actual_arglist *arg)
{
return check_rest (BT_INTEGER, gfc_default_integer_kind, arg);
}
bool
gfc_check_min_max_real (gfc_actual_arglist *arg)
{
return check_rest (BT_REAL, gfc_default_real_kind, arg);
}
bool
gfc_check_min_max_double (gfc_actual_arglist *arg)
{
return check_rest (BT_REAL, gfc_default_double_kind, arg);
}
/* End of min/max family. */
bool
gfc_check_malloc (gfc_expr *size)
{
if (!type_check (size, 0, BT_INTEGER))
return false;
if (!scalar_check (size, 0))
return false;
return true;
}
bool
gfc_check_matmul (gfc_expr *matrix_a, gfc_expr *matrix_b)
{
if ((matrix_a->ts.type != BT_LOGICAL) && !gfc_numeric_ts (&matrix_a->ts))
{
gfc_error ("%qs argument of %qs intrinsic at %L must be numeric "
"or LOGICAL", gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic, &matrix_a->where);
return false;
}
if ((matrix_b->ts.type != BT_LOGICAL) && !gfc_numeric_ts (&matrix_b->ts))
{
gfc_error ("%qs argument of %qs intrinsic at %L must be numeric "
"or LOGICAL", gfc_current_intrinsic_arg[1]->name,
gfc_current_intrinsic, &matrix_b->where);
return false;
}
if ((matrix_a->ts.type == BT_LOGICAL && gfc_numeric_ts (&matrix_b->ts))
|| (gfc_numeric_ts (&matrix_a->ts) && matrix_b->ts.type == BT_LOGICAL))
{
gfc_error ("Argument types of %qs intrinsic at %L must match (%s/%s)",
gfc_current_intrinsic, &matrix_a->where,
gfc_typename(&matrix_a->ts), gfc_typename(&matrix_b->ts));
return false;
}
switch (matrix_a->rank)
{
case 1:
if (!rank_check (matrix_b, 1, 2))
return false;
/* Check for case matrix_a has shape(m), matrix_b has shape (m, k). */
if (!identical_dimen_shape (matrix_a, 0, matrix_b, 0))
{
gfc_error ("Different shape on dimension 1 for arguments %qs "
"and %qs at %L for intrinsic matmul",
gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic_arg[1]->name, &matrix_a->where);
return false;
}
break;
case 2:
if (matrix_b->rank != 2)
{
if (!rank_check (matrix_b, 1, 1))
return false;
}
/* matrix_b has rank 1 or 2 here. Common check for the cases
- matrix_a has shape (n,m) and matrix_b has shape (m, k)
- matrix_a has shape (n,m) and matrix_b has shape (m). */
if (!identical_dimen_shape (matrix_a, 1, matrix_b, 0))
{
gfc_error ("Different shape on dimension 2 for argument %qs and "
"dimension 1 for argument %qs at %L for intrinsic "
"matmul", gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic_arg[1]->name, &matrix_a->where);
return false;
}
break;
default:
gfc_error ("%qs argument of %qs intrinsic at %L must be of rank "
"1 or 2", gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic, &matrix_a->where);
return false;
}
return true;
}
/* Whoever came up with this interface was probably on something.
The possibilities for the occupation of the second and third
parameters are:
Arg #2 Arg #3
NULL NULL
DIM NULL
MASK NULL
NULL MASK minloc(array, mask=m)
DIM MASK
I.e. in the case of minloc(array,mask), mask will be in the second
position of the argument list and we'll have to fix that up. Also,
add the BACK argument if that isn't present. */
bool
gfc_check_minloc_maxloc (gfc_actual_arglist *ap)
{
gfc_expr *a, *m, *d, *k, *b;
a = ap->expr;
if (!int_or_real_or_char_check_f2003 (a, 0) || !array_check (a, 0))
return false;
d = ap->next->expr;
m = ap->next->next->expr;
k = ap->next->next->next->expr;
b = ap->next->next->next->next->expr;
if (b)
{
if (!type_check (b, 4, BT_LOGICAL) || !scalar_check (b,4))
return false;
}
else
{
b = gfc_get_logical_expr (gfc_logical_4_kind, NULL, 0);
ap->next->next->next->next->expr = b;
}
if (m == NULL && d != NULL && d->ts.type == BT_LOGICAL
&& ap->next->name == NULL)
{
m = d;
d = NULL;
ap->next->expr = NULL;
ap->next->next->expr = m;
}
if (!dim_check (d, 1, false))
return false;
if (!dim_rank_check (d, a, 0))
return false;
if (m != NULL && !type_check (m, 2, BT_LOGICAL))
return false;
if (m != NULL
&& !gfc_check_conformance (a, m,
_("arguments '%s' and '%s' for intrinsic %s"),
gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic_arg[2]->name,
gfc_current_intrinsic))
return false;
if (!kind_check (k, 1, BT_INTEGER))
return false;
return true;
}
/* Check function for findloc. Mostly like gfc_check_minloc_maxloc
above, with the additional "value" argument. */
bool
gfc_check_findloc (gfc_actual_arglist *ap)
{
gfc_expr *a, *v, *m, *d, *k, *b;
bool a1, v1;
a = ap->expr;
if (!intrinsic_type_check (a, 0) || !array_check (a, 0))
return false;
v = ap->next->expr;
if (!intrinsic_type_check (v, 1) || !scalar_check (v,1))
return false;
/* Check if the type are both logical. */
a1 = a->ts.type == BT_LOGICAL;
v1 = v->ts.type == BT_LOGICAL;
if ((a1 && !v1) || (!a1 && v1))
goto incompat;
/* Check if the type are both character. */
a1 = a->ts.type == BT_CHARACTER;
v1 = v->ts.type == BT_CHARACTER;
if ((a1 && !v1) || (!a1 && v1))
goto incompat;
/* Check the kind of the characters argument match. */
if (a1 && v1 && a->ts.kind != v->ts.kind)
goto incompat;
d = ap->next->next->expr;
m = ap->next->next->next->expr;
k = ap->next->next->next->next->expr;
b = ap->next->next->next->next->next->expr;
if (b)
{
if (!type_check (b, 5, BT_LOGICAL) || !scalar_check (b,4))
return false;
}
else
{
b = gfc_get_logical_expr (gfc_logical_4_kind, NULL, 0);
ap->next->next->next->next->next->expr = b;
}
if (m == NULL && d != NULL && d->ts.type == BT_LOGICAL
&& ap->next->name == NULL)
{
m = d;
d = NULL;
ap->next->next->expr = NULL;
ap->next->next->next->expr = m;
}
if (!dim_check (d, 2, false))
return false;
if (!dim_rank_check (d, a, 0))
return false;
if (m != NULL && !type_check (m, 3, BT_LOGICAL))
return false;
if (m != NULL
&& !gfc_check_conformance (a, m,
_("arguments '%s' and '%s' for intrinsic %s"),
gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic_arg[3]->name,
gfc_current_intrinsic))
return false;
if (!kind_check (k, 1, BT_INTEGER))
return false;
return true;
incompat:
gfc_error ("Argument %qs of %qs intrinsic at %L must be in type "
"conformance to argument %qs at %L",
gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic, &a->where,
gfc_current_intrinsic_arg[1]->name, &v->where);
return false;
}
/* Similar to minloc/maxloc, the argument list might need to be
reordered for the MINVAL, MAXVAL, PRODUCT, and SUM intrinsics. The
difference is that MINLOC/MAXLOC take an additional KIND argument.
The possibilities are:
Arg #2 Arg #3
NULL NULL
DIM NULL
MASK NULL
NULL MASK minval(array, mask=m)
DIM MASK
I.e. in the case of minval(array,mask), mask will be in the second
position of the argument list and we'll have to fix that up. */
static bool
check_reduction (gfc_actual_arglist *ap)
{
gfc_expr *a, *m, *d;
a = ap->expr;
d = ap->next->expr;
m = ap->next->next->expr;
if (m == NULL && d != NULL && d->ts.type == BT_LOGICAL
&& ap->next->name == NULL)
{
m = d;
d = NULL;
ap->next->expr = NULL;
ap->next->next->expr = m;
}
if (!dim_check (d, 1, false))
return false;
if (!dim_rank_check (d, a, 0))
return false;
if (m != NULL && !type_check (m, 2, BT_LOGICAL))
return false;
if (m != NULL
&& !gfc_check_conformance (a, m,
_("arguments '%s' and '%s' for intrinsic %s"),
gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic_arg[2]->name,
gfc_current_intrinsic))
return false;
return true;
}
bool
gfc_check_minval_maxval (gfc_actual_arglist *ap)
{
if (!int_or_real_or_char_check_f2003 (ap->expr, 0)
|| !array_check (ap->expr, 0))
return false;
return check_reduction (ap);
}
bool
gfc_check_product_sum (gfc_actual_arglist *ap)
{
if (!numeric_check (ap->expr, 0)
|| !array_check (ap->expr, 0))
return false;
return check_reduction (ap);
}
/* For IANY, IALL and IPARITY. */
bool
gfc_check_mask (gfc_expr *i, gfc_expr *kind)
{
int k;
if (!type_check (i, 0, BT_INTEGER))
return false;
if (!nonnegative_check ("I", i))
return false;
if (!kind_check (kind, 1, BT_INTEGER))
return false;
if (kind)
gfc_extract_int (kind, &k);
else
k = gfc_default_integer_kind;
if (!less_than_bitsizekind ("I", i, k))
return false;
return true;
}
bool
gfc_check_transf_bit_intrins (gfc_actual_arglist *ap)
{
if (ap->expr->ts.type != BT_INTEGER)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be INTEGER",
gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic, &ap->expr->where);
return false;
}
if (!array_check (ap->expr, 0))
return false;
return check_reduction (ap);
}
bool
gfc_check_merge (gfc_expr *tsource, gfc_expr *fsource, gfc_expr *mask)
{
if (gfc_invalid_null_arg (tsource))
return false;
if (gfc_invalid_null_arg (fsource))
return false;
if (!same_type_check (tsource, 0, fsource, 1))
return false;
if (!type_check (mask, 2, BT_LOGICAL))
return false;
if (tsource->ts.type == BT_CHARACTER)
return gfc_check_same_strlen (tsource, fsource, "MERGE intrinsic");
return true;
}
bool
gfc_check_merge_bits (gfc_expr *i, gfc_expr *j, gfc_expr *mask)
{
/* i and j cannot both be BOZ literal constants. */
if (!boz_args_check (i, j))
return false;
/* If i is BOZ and j is integer, convert i to type of j. */
if (i->ts.type == BT_BOZ && j->ts.type == BT_INTEGER
&& !gfc_boz2int (i, j->ts.kind))
return false;
/* If j is BOZ and i is integer, convert j to type of i. */
if (j->ts.type == BT_BOZ && i->ts.type == BT_INTEGER
&& !gfc_boz2int (j, i->ts.kind))
return false;
if (!type_check (i, 0, BT_INTEGER))
return false;
if (!type_check (j, 1, BT_INTEGER))
return false;
if (!same_type_check (i, 0, j, 1))
return false;
if (mask->ts.type == BT_BOZ && !gfc_boz2int(mask, i->ts.kind))
return false;
if (!type_check (mask, 2, BT_INTEGER))
return false;
if (!same_type_check (i, 0, mask, 2))
return false;
return true;
}
bool
gfc_check_move_alloc (gfc_expr *from, gfc_expr *to)
{
if (!variable_check (from, 0, false))
return false;
if (!allocatable_check (from, 0))
return false;
if (gfc_is_coindexed (from))
{
gfc_error ("The FROM argument to MOVE_ALLOC at %L shall not be "
"coindexed", &from->where);
return false;
}
if (!variable_check (to, 1, false))
return false;
if (!allocatable_check (to, 1))
return false;
if (gfc_is_coindexed (to))
{
gfc_error ("The TO argument to MOVE_ALLOC at %L shall not be "
"coindexed", &to->where);
return false;
}
if (from->ts.type == BT_CLASS && to->ts.type == BT_DERIVED)
{
gfc_error ("The TO arguments in MOVE_ALLOC at %L must be "
"polymorphic if FROM is polymorphic",
&to->where);
return false;
}
if (!same_type_check (to, 1, from, 0))
return false;
if (to->rank != from->rank)
{
gfc_error ("The FROM and TO arguments of the MOVE_ALLOC intrinsic at %L "
"must have the same rank %d/%d", &to->where, from->rank,
to->rank);
return false;
}
/* IR F08/0040; cf. 12-006A. */
if (gfc_get_corank (to) != gfc_get_corank (from))
{
gfc_error ("The FROM and TO arguments of the MOVE_ALLOC intrinsic at %L "
"must have the same corank %d/%d", &to->where,
gfc_get_corank (from), gfc_get_corank (to));
return false;
}
/* This is based losely on F2003 12.4.1.7. It is intended to prevent
the likes of to = sym->cmp1->cmp2 and from = sym->cmp1, where cmp1
and cmp2 are allocatable. After the allocation is transferred,
the 'to' chain is broken by the nullification of the 'from'. A bit
of reflection reveals that this can only occur for derived types
with recursive allocatable components. */
if (to->expr_type == EXPR_VARIABLE && from->expr_type == EXPR_VARIABLE
&& !strcmp (to->symtree->n.sym->name, from->symtree->n.sym->name))
{
gfc_ref *to_ref, *from_ref;
to_ref = to->ref;
from_ref = from->ref;
bool aliasing = true;
for (; from_ref && to_ref;
from_ref = from_ref->next, to_ref = to_ref->next)
{
if (to_ref->type != from->ref->type)
aliasing = false;
else if (to_ref->type == REF_ARRAY
&& to_ref->u.ar.type != AR_FULL
&& from_ref->u.ar.type != AR_FULL)
/* Play safe; assume sections and elements are different. */
aliasing = false;
else if (to_ref->type == REF_COMPONENT
&& to_ref->u.c.component != from_ref->u.c.component)
aliasing = false;
if (!aliasing)
break;
}
if (aliasing)
{
gfc_error ("The FROM and TO arguments at %L violate aliasing "
"restrictions (F2003 12.4.1.7)", &to->where);
return false;
}
}
/* CLASS arguments: Make sure the vtab of from is present. */
if (to->ts.type == BT_CLASS && !UNLIMITED_POLY (from))
gfc_find_vtab (&from->ts);
return true;
}
bool
gfc_check_nearest (gfc_expr *x, gfc_expr *s)
{
if (!type_check (x, 0, BT_REAL))
return false;
if (!type_check (s, 1, BT_REAL))
return false;
if (s->expr_type == EXPR_CONSTANT)
{
if (mpfr_sgn (s->value.real) == 0)
{
gfc_error ("Argument %<S%> of NEAREST at %L shall not be zero",
&s->where);
return false;
}
}
return true;
}
bool
gfc_check_new_line (gfc_expr *a)
{
if (!type_check (a, 0, BT_CHARACTER))
return false;
return true;
}
bool
gfc_check_norm2 (gfc_expr *array, gfc_expr *dim)
{
if (!type_check (array, 0, BT_REAL))
return false;
if (!array_check (array, 0))
return false;
if (!dim_check (dim, 1, false))
return false;
if (!dim_rank_check (dim, array, false))
return false;
return true;
}
bool
gfc_check_null (gfc_expr *mold)
{
symbol_attribute attr;
if (mold == NULL)
return true;
if (!variable_check (mold, 0, true))
return false;
attr = gfc_variable_attr (mold, NULL);
if (!attr.pointer && !attr.proc_pointer && !attr.allocatable)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be a POINTER, "
"ALLOCATABLE or procedure pointer",
gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic, &mold->where);
return false;
}
if (attr.allocatable
&& !gfc_notify_std (GFC_STD_F2003, "NULL intrinsic with "
"allocatable MOLD at %L", &mold->where))
return false;
/* F2008, C1242. */
if (gfc_is_coindexed (mold))
{
gfc_error ("%qs argument of %qs intrinsic at %L shall not be "
"coindexed", gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic, &mold->where);
return false;
}
return true;
}
bool
gfc_check_pack (gfc_expr *array, gfc_expr *mask, gfc_expr *vector)
{
if (!array_check (array, 0))
return false;
if (!type_check (mask, 1, BT_LOGICAL))
return false;
if (!gfc_check_conformance (array, mask,
_("arguments '%s' and '%s' for intrinsic '%s'"),
gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic_arg[1]->name,
gfc_current_intrinsic))
return false;
if (vector != NULL)
{
mpz_t array_size, vector_size;
bool have_array_size, have_vector_size;
if (!same_type_check (array, 0, vector, 2))
return false;
if (!rank_check (vector, 2, 1))
return false;
/* VECTOR requires at least as many elements as MASK
has .TRUE. values. */
have_array_size = gfc_array_size(array, &array_size);
have_vector_size = gfc_array_size(vector, &vector_size);
if (have_vector_size
&& (mask->expr_type == EXPR_ARRAY
|| (mask->expr_type == EXPR_CONSTANT
&& have_array_size)))
{
int mask_true_values = 0;
if (mask->expr_type == EXPR_ARRAY)
{
gfc_constructor *mask_ctor;
mask_ctor = gfc_constructor_first (mask->value.constructor);
while (mask_ctor)
{
if (mask_ctor->expr->expr_type != EXPR_CONSTANT)
{
mask_true_values = 0;
break;
}
if (mask_ctor->expr->value.logical)
mask_true_values++;
mask_ctor = gfc_constructor_next (mask_ctor);
}
}
else if (mask->expr_type == EXPR_CONSTANT && mask->value.logical)
mask_true_values = mpz_get_si (array_size);
if (mpz_get_si (vector_size) < mask_true_values)
{
gfc_error ("%qs argument of %qs intrinsic at %L must "
"provide at least as many elements as there "
"are .TRUE. values in %qs (%ld/%d)",
gfc_current_intrinsic_arg[2]->name,
gfc_current_intrinsic, &vector->where,
gfc_current_intrinsic_arg[1]->name,
mpz_get_si (vector_size), mask_true_values);
return false;
}
}
if (have_array_size)
mpz_clear (array_size);
if (have_vector_size)
mpz_clear (vector_size);
}
return true;
}
bool
gfc_check_parity (gfc_expr *mask, gfc_expr *dim)
{
if (!type_check (mask, 0, BT_LOGICAL))
return false;
if (!array_check (mask, 0))
return false;
if (!dim_check (dim, 1, false))
return false;
if (!dim_rank_check (dim, mask, false))
return false;
return true;
}
bool
gfc_check_precision (gfc_expr *x)
{
if (!real_or_complex_check (x, 0))
return false;
return true;
}
bool
gfc_check_present (gfc_expr *a)
{
gfc_symbol *sym;
if (!variable_check (a, 0, true))
return false;
sym = a->symtree->n.sym;
if (!sym->attr.dummy)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be of a "
"dummy variable", gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic, &a->where);
return false;
}
/* For CLASS, the optional attribute might be set at either location. */
if ((sym->ts.type != BT_CLASS || !CLASS_DATA (sym)->attr.optional)
&& !sym->attr.optional)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be of "
"an OPTIONAL dummy variable",
gfc_current_intrinsic_arg[0]->name, gfc_current_intrinsic,
&a->where);
return false;
}
/* 13.14.82 PRESENT(A)
......
Argument. A shall be the name of an optional dummy argument that is
accessible in the subprogram in which the PRESENT function reference
appears... */
if (a->ref != NULL
&& !(a->ref->next == NULL && a->ref->type == REF_ARRAY
&& (a->ref->u.ar.type == AR_FULL
|| (a->ref->u.ar.type == AR_ELEMENT
&& a->ref->u.ar.as->rank == 0))))
{
gfc_error ("%qs argument of %qs intrinsic at %L must not be a "
"subobject of %qs", gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic, &a->where, sym->name);
return false;
}
return true;
}
bool
gfc_check_radix (gfc_expr *x)
{
if (!int_or_real_check (x, 0))
return false;
return true;
}
bool
gfc_check_range (gfc_expr *x)
{
if (!numeric_check (x, 0))
return false;
return true;
}
bool
gfc_check_rank (gfc_expr *a)
{
/* Any data object is allowed; a "data object" is a "constant (4.1.3),
variable (6), or subobject of a constant (2.4.3.2.3)" (F2008, 1.3.45). */
bool is_variable = true;
/* Functions returning pointers are regarded as variable, cf. F2008, R602. */
if (a->expr_type == EXPR_FUNCTION)
is_variable = a->value.function.esym
? a->value.function.esym->result->attr.pointer
: a->symtree->n.sym->result->attr.pointer;
if (a->expr_type == EXPR_OP
|| a->expr_type == EXPR_NULL
|| a->expr_type == EXPR_COMPCALL
|| a->expr_type == EXPR_PPC
|| a->ts.type == BT_PROCEDURE
|| !is_variable)
{
gfc_error ("The argument of the RANK intrinsic at %L must be a data "
"object", &a->where);
return false;
}
return true;
}
bool
gfc_check_real (gfc_expr *a, gfc_expr *kind)
{
if (!kind_check (kind, 1, BT_REAL))
return false;
/* BOZ is dealt with in gfc_simplify_real. */
if (a->ts.type == BT_BOZ)
return true;
if (!numeric_check (a, 0))
return false;
return true;
}
bool
gfc_check_rename (gfc_expr *path1, gfc_expr *path2)
{
if (!type_check (path1, 0, BT_CHARACTER))
return false;
if (!kind_value_check (path1, 0, gfc_default_character_kind))
return false;
if (!type_check (path2, 1, BT_CHARACTER))
return false;
if (!kind_value_check (path2, 1, gfc_default_character_kind))
return false;
return true;
}
bool
gfc_check_rename_sub (gfc_expr *path1, gfc_expr *path2, gfc_expr *status)
{
if (!type_check (path1, 0, BT_CHARACTER))
return false;
if (!kind_value_check (path1, 0, gfc_default_character_kind))
return false;
if (!type_check (path2, 1, BT_CHARACTER))
return false;
if (!kind_value_check (path2, 1, gfc_default_character_kind))
return false;
if (status == NULL)
return true;
if (!type_check (status, 2, BT_INTEGER))
return false;
if (!scalar_check (status, 2))
return false;
return true;
}
bool
gfc_check_repeat (gfc_expr *x, gfc_expr *y)
{
if (!type_check (x, 0, BT_CHARACTER))
return false;
if (!scalar_check (x, 0))
return false;
if (!type_check (y, 0, BT_INTEGER))
return false;
if (!scalar_check (y, 1))
return false;
return true;
}
bool
gfc_check_reshape (gfc_expr *source, gfc_expr *shape,
gfc_expr *pad, gfc_expr *order)
{
mpz_t size;
mpz_t nelems;
int shape_size;
bool shape_is_const;
if (!array_check (source, 0))
return false;
if (!rank_check (shape, 1, 1))
return false;
if (!type_check (shape, 1, BT_INTEGER))
return false;
if (!gfc_array_size (shape, &size))
{
gfc_error ("%<shape%> argument of %<reshape%> intrinsic at %L must be an "
"array of constant size", &shape->where);
return false;
}
shape_size = mpz_get_ui (size);
mpz_clear (size);
if (shape_size <= 0)
{
gfc_error ("%qs argument of %qs intrinsic at %L is empty",
gfc_current_intrinsic_arg[1]->name, gfc_current_intrinsic,
&shape->where);
return false;
}
else if (shape_size > GFC_MAX_DIMENSIONS)
{
gfc_error ("%<shape%> argument of %<reshape%> intrinsic at %L has more "
"than %d elements", &shape->where, GFC_MAX_DIMENSIONS);
return false;
}
gfc_simplify_expr (shape, 0);
shape_is_const = gfc_is_constant_expr (shape);
if (shape->expr_type == EXPR_ARRAY && shape_is_const)
{
gfc_expr *e;
int i, extent;
for (i = 0; i < shape_size; ++i)
{
e = gfc_constructor_lookup_expr (shape->value.constructor, i);
if (e->expr_type != EXPR_CONSTANT)
continue;
gfc_extract_int (e, &extent);
if (extent < 0)
{
gfc_error ("%qs argument of %qs intrinsic at %L has "
"negative element (%d)",
gfc_current_intrinsic_arg[1]->name,
gfc_current_intrinsic, &shape->where, extent);
return false;
}
}
}
if (pad != NULL)
{
if (!same_type_check (source, 0, pad, 2))
return false;
if (!array_check (pad, 2))
return false;
}
if (order != NULL)
{
if (!array_check (order, 3))
return false;
if (!type_check (order, 3, BT_INTEGER))
return false;
if (order->expr_type == EXPR_ARRAY && gfc_is_constant_expr (order))
{
int i, order_size, dim, perm[GFC_MAX_DIMENSIONS];
gfc_expr *e;
for (i = 0; i < GFC_MAX_DIMENSIONS; ++i)
perm[i] = 0;
gfc_array_size (order, &size);
order_size = mpz_get_ui (size);
mpz_clear (size);
if (order_size != shape_size)
{
gfc_error ("%qs argument of %qs intrinsic at %L "
"has wrong number of elements (%d/%d)",
gfc_current_intrinsic_arg[3]->name,
gfc_current_intrinsic, &order->where,
order_size, shape_size);
return false;
}
for (i = 1; i <= order_size; ++i)
{
e = gfc_constructor_lookup_expr (order->value.constructor, i-1);
if (e->expr_type != EXPR_CONSTANT)
continue;
gfc_extract_int (e, &dim);
if (dim < 1 || dim > order_size)
{
gfc_error ("%qs argument of %qs intrinsic at %L "
"has out-of-range dimension (%d)",
gfc_current_intrinsic_arg[3]->name,
gfc_current_intrinsic, &e->where, dim);
return false;
}
if (perm[dim-1] != 0)
{
gfc_error ("%qs argument of %qs intrinsic at %L has "
"invalid permutation of dimensions (dimension "
"%qd duplicated)",
gfc_current_intrinsic_arg[3]->name,
gfc_current_intrinsic, &e->where, dim);
return false;
}
perm[dim-1] = 1;
}
}
}
if (pad == NULL && shape->expr_type == EXPR_ARRAY && shape_is_const
&& !(source->expr_type == EXPR_VARIABLE && source->symtree->n.sym->as
&& source->symtree->n.sym->as->type == AS_ASSUMED_SIZE))
{
/* Check the match in size between source and destination. */
if (gfc_array_size (source, &nelems))
{
gfc_constructor *c;
bool test;
mpz_init_set_ui (size, 1);
for (c = gfc_constructor_first (shape->value.constructor);
c; c = gfc_constructor_next (c))
mpz_mul (size, size, c->expr->value.integer);
test = mpz_cmp (nelems, size) < 0 && mpz_cmp_ui (size, 0) > 0;
mpz_clear (nelems);
mpz_clear (size);
if (test)
{
gfc_error ("Without padding, there are not enough elements "
"in the intrinsic RESHAPE source at %L to match "
"the shape", &source->where);
return false;
}
}
}
return true;
}
bool
gfc_check_same_type_as (gfc_expr *a, gfc_expr *b)
{
if (a->ts.type != BT_DERIVED && a->ts.type != BT_CLASS)
{
gfc_error ("%qs argument of %qs intrinsic at %L "
"cannot be of type %s",
gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic,
&a->where, gfc_typename (a));
return false;
}
if (!(gfc_type_is_extensible (a->ts.u.derived) || UNLIMITED_POLY (a)))
{
gfc_error ("%qs argument of %qs intrinsic at %L "
"must be of an extensible type",
gfc_current_intrinsic_arg[0]->name, gfc_current_intrinsic,
&a->where);
return false;
}
if (b->ts.type != BT_DERIVED && b->ts.type != BT_CLASS)
{
gfc_error ("%qs argument of %qs intrinsic at %L "
"cannot be of type %s",
gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic,
&b->where, gfc_typename (b));
return false;
}
if (!(gfc_type_is_extensible (b->ts.u.derived) || UNLIMITED_POLY (b)))
{
gfc_error ("%qs argument of %qs intrinsic at %L "
"must be of an extensible type",
gfc_current_intrinsic_arg[1]->name, gfc_current_intrinsic,
&b->where);
return false;
}
return true;
}
bool
gfc_check_scale (gfc_expr *x, gfc_expr *i)
{
if (!type_check (x, 0, BT_REAL))
return false;
if (!type_check (i, 1, BT_INTEGER))
return false;
return true;
}
bool
gfc_check_scan (gfc_expr *x, gfc_expr *y, gfc_expr *z, gfc_expr *kind)
{
if (!type_check (x, 0, BT_CHARACTER))
return false;
if (!type_check (y, 1, BT_CHARACTER))
return false;
if (z != NULL && !type_check (z, 2, BT_LOGICAL))
return false;
if (!kind_check (kind, 3, BT_INTEGER))
return false;
if (kind && !gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
"with KIND argument at %L",
gfc_current_intrinsic, &kind->where))
return false;
if (!same_type_check (x, 0, y, 1))
return false;
return true;
}
bool
gfc_check_secnds (gfc_expr *r)
{
if (!type_check (r, 0, BT_REAL))
return false;
if (!kind_value_check (r, 0, 4))
return false;
if (!scalar_check (r, 0))
return false;
return true;
}
bool
gfc_check_selected_char_kind (gfc_expr *name)
{
if (!type_check (name, 0, BT_CHARACTER))
return false;
if (!kind_value_check (name, 0, gfc_default_character_kind))
return false;
if (!scalar_check (name, 0))
return false;
return true;
}
bool
gfc_check_selected_int_kind (gfc_expr *r)
{
if (!type_check (r, 0, BT_INTEGER))
return false;
if (!scalar_check (r, 0))
return false;
return true;
}
bool
gfc_check_selected_real_kind (gfc_expr *p, gfc_expr *r, gfc_expr *radix)
{
if (p == NULL && r == NULL
&& !gfc_notify_std (GFC_STD_F2008, "SELECTED_REAL_KIND with"
" neither %<P%> nor %<R%> argument at %L",
gfc_current_intrinsic_where))
return false;
if (p)
{
if (!type_check (p, 0, BT_INTEGER))
return false;
if (!scalar_check (p, 0))
return false;
}
if (r)
{
if (!type_check (r, 1, BT_INTEGER))
return false;
if (!scalar_check (r, 1))
return false;
}
if (radix)
{
if (!type_check (radix, 1, BT_INTEGER))
return false;
if (!scalar_check (radix, 1))
return false;
if (!gfc_notify_std (GFC_STD_F2008, "%qs intrinsic with "
"RADIX argument at %L", gfc_current_intrinsic,
&radix->where))
return false;
}
return true;
}
bool
gfc_check_set_exponent (gfc_expr *x, gfc_expr *i)
{
if (!type_check (x, 0, BT_REAL))
return false;
if (!type_check (i, 1, BT_INTEGER))
return false;
return true;
}
bool
gfc_check_shape (gfc_expr *source, gfc_expr *kind)
{
gfc_array_ref *ar;
if (gfc_invalid_null_arg (source))
return false;
if (!kind_check (kind, 1, BT_INTEGER))
return false;
if (kind && !gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
"with KIND argument at %L",
gfc_current_intrinsic, &kind->where))
return false;
if (source->rank == 0 || source->expr_type != EXPR_VARIABLE)
return true;
if (source->ref == NULL)
return false;
ar = gfc_find_array_ref (source);
if (ar->as && ar->as->type == AS_ASSUMED_SIZE && ar->type == AR_FULL)
{
gfc_error ("%<source%> argument of %<shape%> intrinsic at %L must not be "
"an assumed size array", &source->where);
return false;
}
return true;
}
bool
gfc_check_shift (gfc_expr *i, gfc_expr *shift)
{
if (!type_check (i, 0, BT_INTEGER))
return false;
if (!type_check (shift, 0, BT_INTEGER))
return false;
if (!nonnegative_check ("SHIFT", shift))
return false;
if (!less_than_bitsize1 ("I", i, "SHIFT", shift, true))
return false;
return true;
}
bool
gfc_check_sign (gfc_expr *a, gfc_expr *b)
{
if (!int_or_real_check (a, 0))
return false;
if (!same_type_check (a, 0, b, 1))
return false;
return true;
}
bool
gfc_check_size (gfc_expr *array, gfc_expr *dim, gfc_expr *kind)
{
if (!array_check (array, 0))
return false;
if (!dim_check (dim, 1, true))
return false;
if (!dim_rank_check (dim, array, 0))
return false;
if (!kind_check (kind, 2, BT_INTEGER))
return false;
if (kind && !gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
"with KIND argument at %L",
gfc_current_intrinsic, &kind->where))
return false;
return true;
}
bool
gfc_check_sizeof (gfc_expr *arg)
{
if (gfc_invalid_null_arg (arg))
return false;
if (arg->ts.type == BT_PROCEDURE)
{
gfc_error ("%qs argument of %qs intrinsic at %L shall not be a procedure",
gfc_current_intrinsic_arg[0]->name, gfc_current_intrinsic,
&arg->where);
return false;
}
if (illegal_boz_arg (arg))
return false;
/* TYPE(*) is acceptable if and only if it uses an array descriptor. */
if (arg->ts.type == BT_ASSUMED
&& (arg->symtree->n.sym->as == NULL
|| (arg->symtree->n.sym->as->type != AS_ASSUMED_SHAPE
&& arg->symtree->n.sym->as->type != AS_DEFERRED
&& arg->symtree->n.sym->as->type != AS_ASSUMED_RANK)))
{
gfc_error ("%qs argument of %qs intrinsic at %L shall not be TYPE(*)",
gfc_current_intrinsic_arg[0]->name, gfc_current_intrinsic,
&arg->where);
return false;
}
if (arg->rank && arg->expr_type == EXPR_VARIABLE
&& arg->symtree->n.sym->as != NULL
&& arg->symtree->n.sym->as->type == AS_ASSUMED_SIZE && arg->ref
&& arg->ref->type == REF_ARRAY && arg->ref->u.ar.type == AR_FULL)
{
gfc_error ("%qs argument of %qs intrinsic at %L shall not be an "
"assumed-size array", gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic, &arg->where);
return false;
}
return true;
}
/* Check whether an expression is interoperable. When returning false,
msg is set to a string telling why the expression is not interoperable,
otherwise, it is set to NULL. The msg string can be used in diagnostics.
If c_loc is true, character with len > 1 are allowed (cf. Fortran
2003corr5); additionally, assumed-shape/assumed-rank/deferred-shape
arrays are permitted. And if c_f_ptr is true, deferred-shape arrays
are permitted. */
static bool
is_c_interoperable (gfc_expr *expr, const char **msg, bool c_loc, bool c_f_ptr)
{
*msg = NULL;
if (expr->expr_type == EXPR_NULL)
{
*msg = "NULL() is not interoperable";
return false;
}
if (expr->ts.type == BT_BOZ)
{
*msg = "BOZ literal constant";
return false;
}
if (expr->ts.type == BT_CLASS)
{
*msg = "Expression is polymorphic";
return false;
}
if (expr->ts.type == BT_DERIVED && !expr->ts.u.derived->attr.is_bind_c
&& !expr->ts.u.derived->ts.is_iso_c)
{
*msg = "Expression is a noninteroperable derived type";
return false;
}
if (expr->ts.type == BT_PROCEDURE)
{
*msg = "Procedure unexpected as argument";
return false;
}
if (gfc_notification_std (GFC_STD_GNU) && expr->ts.type == BT_LOGICAL)
{
int i;
for (i = 0; gfc_logical_kinds[i].kind; i++)
if (gfc_logical_kinds[i].kind == expr->ts.kind)
return true;
*msg = "Extension to use a non-C_Bool-kind LOGICAL";
return false;
}
if (gfc_notification_std (GFC_STD_GNU) && expr->ts.type == BT_CHARACTER
&& expr->ts.kind != 1)
{
*msg = "Extension to use a non-C_CHAR-kind CHARACTER";
return false;
}
if (expr->ts.type == BT_CHARACTER) {
if (expr->ts.deferred)
{
/* TS 29113 allows deferred-length strings as dummy arguments,
but it is not an interoperable type. */
*msg = "Expression shall not be a deferred-length string";
return false;
}
if (expr->ts.u.cl && expr->ts.u.cl->length
&& !gfc_simplify_expr (expr->ts.u.cl->length, 0))
gfc_internal_error ("is_c_interoperable(): gfc_simplify_expr failed");
if (!c_loc && expr->ts.u.cl
&& (!expr->ts.u.cl->length
|| expr->ts.u.cl->length->expr_type != EXPR_CONSTANT
|| mpz_cmp_si (expr->ts.u.cl->length->value.integer, 1) != 0))
{
*msg = "Type shall have a character length of 1";
return false;
}
}
/* Note: The following checks are about interoperatable variables, Fortran
15.3.5/15.3.6. In intrinsics like C_LOC or in procedure interface, more
is allowed, e.g. assumed-shape arrays with TS 29113. */
if (gfc_is_coarray (expr))
{
*msg = "Coarrays are not interoperable";
return false;
}
if (!c_loc && expr->rank > 0 && expr->expr_type != EXPR_ARRAY)
{
gfc_array_ref *ar = gfc_find_array_ref (expr);
if (ar->type != AR_FULL)
{
*msg = "Only whole-arrays are interoperable";
return false;
}
if (!c_f_ptr && ar->as->type != AS_EXPLICIT
&& ar->as->type != AS_ASSUMED_SIZE)
{
*msg = "Only explicit-size and assumed-size arrays are interoperable";
return false;
}
}
return true;
}
bool
gfc_check_c_sizeof (gfc_expr *arg)
{
const char *msg;
if (!is_c_interoperable (arg, &msg, false, false))
{
gfc_error ("%qs argument of %qs intrinsic at %L must be an "
"interoperable data entity: %s",
gfc_current_intrinsic_arg[0]->name, gfc_current_intrinsic,
&arg->where, msg);
return false;
}
if (arg->ts.type == BT_ASSUMED)
{
gfc_error ("%qs argument of %qs intrinsic at %L shall not be "
"TYPE(*)",
gfc_current_intrinsic_arg[0]->name, gfc_current_intrinsic,
&arg->where);
return false;
}
if (arg->rank && arg->expr_type == EXPR_VARIABLE
&& arg->symtree->n.sym->as != NULL
&& arg->symtree->n.sym->as->type == AS_ASSUMED_SIZE && arg->ref
&& arg->ref->type == REF_ARRAY && arg->ref->u.ar.type == AR_FULL)
{
gfc_error ("%qs argument of %qs intrinsic at %L shall not be an "
"assumed-size array", gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic, &arg->where);
return false;
}
return true;
}
bool
gfc_check_c_associated (gfc_expr *c_ptr_1, gfc_expr *c_ptr_2)
{
if (c_ptr_1->ts.type != BT_DERIVED
|| c_ptr_1->ts.u.derived->from_intmod != INTMOD_ISO_C_BINDING
|| (c_ptr_1->ts.u.derived->intmod_sym_id != ISOCBINDING_PTR
&& c_ptr_1->ts.u.derived->intmod_sym_id != ISOCBINDING_FUNPTR))
{
gfc_error ("Argument C_PTR_1 at %L to C_ASSOCIATED shall have the "
"type TYPE(C_PTR) or TYPE(C_FUNPTR)", &c_ptr_1->where);
return false;
}
if (!scalar_check (c_ptr_1, 0))
return false;
if (c_ptr_2
&& (c_ptr_2->ts.type != BT_DERIVED
|| c_ptr_2->ts.u.derived->from_intmod != INTMOD_ISO_C_BINDING
|| (c_ptr_1->ts.u.derived->intmod_sym_id
!= c_ptr_2->ts.u.derived->intmod_sym_id)))
{
gfc_error ("Argument C_PTR_2 at %L to C_ASSOCIATED shall have the "
"same type as C_PTR_1: %s instead of %s", &c_ptr_1->where,
gfc_typename (&c_ptr_1->ts),
gfc_typename (&c_ptr_2->ts));
return false;
}
if (c_ptr_2 && !scalar_check (c_ptr_2, 1))
return false;
return true;
}
bool
gfc_check_c_f_pointer (gfc_expr *cptr, gfc_expr *fptr, gfc_expr *shape)
{
symbol_attribute attr;
const char *msg;
if (cptr->ts.type != BT_DERIVED
|| cptr->ts.u.derived->from_intmod != INTMOD_ISO_C_BINDING
|| cptr->ts.u.derived->intmod_sym_id != ISOCBINDING_PTR)
{
gfc_error ("Argument CPTR at %L to C_F_POINTER shall have the "
"type TYPE(C_PTR)", &cptr->where);
return false;
}
if (!scalar_check (cptr, 0))
return false;
attr = gfc_expr_attr (fptr);
if (!attr.pointer)
{
gfc_error ("Argument FPTR at %L to C_F_POINTER must be a pointer",
&fptr->where);
return false;
}
if (fptr->ts.type == BT_CLASS)
{
gfc_error ("FPTR argument at %L to C_F_POINTER shall not be polymorphic",
&fptr->where);
return false;
}
if (gfc_is_coindexed (fptr))
{
gfc_error ("Argument FPTR at %L to C_F_POINTER shall not be "
"coindexed", &fptr->where);
return false;
}
if (fptr->rank == 0 && shape)
{
gfc_error ("Unexpected SHAPE argument at %L to C_F_POINTER with scalar "
"FPTR", &fptr->where);
return false;
}
else if (fptr->rank && !shape)
{
gfc_error ("Expected SHAPE argument to C_F_POINTER with array "
"FPTR at %L", &fptr->where);
return false;
}
if (shape && !rank_check (shape, 2, 1))
return false;
if (shape && !type_check (shape, 2, BT_INTEGER))
return false;
if (shape)
{
mpz_t size;
if (gfc_array_size (shape, &size))
{
if (mpz_cmp_ui (size, fptr->rank) != 0)
{
mpz_clear (size);
gfc_error ("SHAPE argument at %L to C_F_POINTER must have the same "
"size as the RANK of FPTR", &shape->where);
return false;
}
mpz_clear (size);
}
}
if (fptr->ts.type == BT_CLASS)
{
gfc_error ("Polymorphic FPTR at %L to C_F_POINTER", &fptr->where);
return false;
}
if (fptr->rank > 0 && !is_c_interoperable (fptr, &msg, false, true))
return gfc_notify_std (GFC_STD_F2018, "Noninteroperable array FPTR "
"at %L to C_F_POINTER: %s", &fptr->where, msg);
return true;
}
bool
gfc_check_c_f_procpointer (gfc_expr *cptr, gfc_expr *fptr)
{
symbol_attribute attr;
if (cptr->ts.type != BT_DERIVED
|| cptr->ts.u.derived->from_intmod != INTMOD_ISO_C_BINDING
|| cptr->ts.u.derived->intmod_sym_id != ISOCBINDING_FUNPTR)
{
gfc_error ("Argument CPTR at %L to C_F_PROCPOINTER shall have the "
"type TYPE(C_FUNPTR)", &cptr->where);
return false;
}
if (!scalar_check (cptr, 0))
return false;
attr = gfc_expr_attr (fptr);
if (!attr.proc_pointer)
{
gfc_error ("Argument FPTR at %L to C_F_PROCPOINTER shall be a procedure "
"pointer", &fptr->where);
return false;
}
if (gfc_is_coindexed (fptr))
{
gfc_error ("Argument FPTR at %L to C_F_PROCPOINTER shall not be "
"coindexed", &fptr->where);
return false;
}
if (!attr.is_bind_c)
return gfc_notify_std (GFC_STD_F2018, "Noninteroperable procedure "
"pointer at %L to C_F_PROCPOINTER", &fptr->where);
return true;
}
bool
gfc_check_c_funloc (gfc_expr *x)
{
symbol_attribute attr;
if (gfc_is_coindexed (x))
{
gfc_error ("Argument X at %L to C_FUNLOC shall not be "
"coindexed", &x->where);
return false;
}
attr = gfc_expr_attr (x);
if (attr.function && !attr.proc_pointer && x->expr_type == EXPR_VARIABLE
&& x->symtree->n.sym == x->symtree->n.sym->result)
for (gfc_namespace *ns = gfc_current_ns; ns; ns = ns->parent)
if (x->symtree->n.sym == ns->proc_name)
{
gfc_error ("Function result %qs at %L is invalid as X argument "
"to C_FUNLOC", x->symtree->n.sym->name, &x->where);
return false;
}
if (attr.flavor != FL_PROCEDURE)
{
gfc_error ("Argument X at %L to C_FUNLOC shall be a procedure "
"or a procedure pointer", &x->where);
return false;
}
if (!attr.is_bind_c)
return gfc_notify_std (GFC_STD_F2018, "Noninteroperable procedure "
"at %L to C_FUNLOC", &x->where);
return true;
}
bool
gfc_check_c_loc (gfc_expr *x)
{
symbol_attribute attr;
const char *msg;
if (gfc_is_coindexed (x))
{
gfc_error ("Argument X at %L to C_LOC shall not be coindexed", &x->where);
return false;
}
if (x->ts.type == BT_CLASS)
{
gfc_error ("X argument at %L to C_LOC shall not be polymorphic",
&x->where);
return false;
}
attr = gfc_expr_attr (x);
if (!attr.pointer
&& (x->expr_type != EXPR_VARIABLE || !attr.target
|| attr.flavor == FL_PARAMETER))
{
gfc_error ("Argument X at %L to C_LOC shall have either "
"the POINTER or the TARGET attribute", &x->where);
return false;
}
if (x->ts.type == BT_CHARACTER
&& gfc_var_strlen (x) == 0)
{
gfc_error ("Argument X at %L to C_LOC shall be not be a zero-sized "
"string", &x->where);
return false;
}
if (!is_c_interoperable (x, &msg, true, false))
{
if (x->ts.type == BT_CLASS)
{
gfc_error ("Argument at %L to C_LOC shall not be polymorphic",
&x->where);
return false;
}
if (x->rank
&& !gfc_notify_std (GFC_STD_F2018,
"Noninteroperable array at %L as"
" argument to C_LOC: %s", &x->where, msg))
return false;
}
else if (x->rank > 0 && gfc_notification_std (GFC_STD_F2008))
{
gfc_array_ref *ar = gfc_find_array_ref (x);
if (ar->as->type != AS_EXPLICIT && ar->as->type != AS_ASSUMED_SIZE
&& !attr.allocatable
&& !gfc_notify_std (GFC_STD_F2008,
"Array of interoperable type at %L "
"to C_LOC which is nonallocatable and neither "
"assumed size nor explicit size", &x->where))
return false;
else if (ar->type != AR_FULL
&& !gfc_notify_std (GFC_STD_F2008, "Array section at %L "
"to C_LOC", &x->where))
return false;
}
return true;
}
bool
gfc_check_sleep_sub (gfc_expr *seconds)
{
if (!type_check (seconds, 0, BT_INTEGER))
return false;
if (!scalar_check (seconds, 0))
return false;
return true;
}
bool
gfc_check_sngl (gfc_expr *a)
{
if (!type_check (a, 0, BT_REAL))
return false;
if ((a->ts.kind != gfc_default_double_kind)
&& !gfc_notify_std (GFC_STD_GNU, "non double precision "
"REAL argument to %s intrinsic at %L",
gfc_current_intrinsic, &a->where))
return false;
return true;
}
bool
gfc_check_spread (gfc_expr *source, gfc_expr *dim, gfc_expr *ncopies)
{
if (gfc_invalid_null_arg (source))
return false;
if (source->rank >= GFC_MAX_DIMENSIONS)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be less "
"than rank %d", gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic, &source->where, GFC_MAX_DIMENSIONS);
return false;
}
if (dim == NULL)
return false;
if (!dim_check (dim, 1, false))
return false;
/* dim_rank_check() does not apply here. */
if (dim
&& dim->expr_type == EXPR_CONSTANT
&& (mpz_cmp_ui (dim->value.integer, 1) < 0
|| mpz_cmp_ui (dim->value.integer, source->rank + 1) > 0))
{
gfc_error ("%qs argument of %qs intrinsic at %L is not a valid "
"dimension index", gfc_current_intrinsic_arg[1]->name,
gfc_current_intrinsic, &dim->where);
return false;
}
if (!type_check (ncopies, 2, BT_INTEGER))
return false;
if (!scalar_check (ncopies, 2))
return false;
return true;
}
/* Functions for checking FGETC, FPUTC, FGET and FPUT (subroutines and
functions). */
bool
arg_strlen_is_zero (gfc_expr *c, int n)
{
if (gfc_var_strlen (c) == 0)
{
gfc_error ("%qs argument of %qs intrinsic at %L must have "
"length at least 1", gfc_current_intrinsic_arg[n]->name,
gfc_current_intrinsic, &c->where);
return true;
}
return false;
}
bool
gfc_check_fgetputc_sub (gfc_expr *unit, gfc_expr *c, gfc_expr *status)
{
if (!type_check (unit, 0, BT_INTEGER))
return false;
if (!scalar_check (unit, 0))
return false;
if (!type_check (c, 1, BT_CHARACTER))
return false;
if (!kind_value_check (c, 1, gfc_default_character_kind))
return false;
if (strcmp (gfc_current_intrinsic, "fgetc") == 0
&& !variable_check (c, 1, false))
return false;
if (arg_strlen_is_zero (c, 1))
return false;
if (status == NULL)
return true;
if (!type_check (status, 2, BT_INTEGER)
|| !kind_value_check (status, 2, gfc_default_integer_kind)
|| !scalar_check (status, 2)
|| !variable_check (status, 2, false))
return false;
return true;
}
bool
gfc_check_fgetputc (gfc_expr *unit, gfc_expr *c)
{
return gfc_check_fgetputc_sub (unit, c, NULL);
}
bool
gfc_check_fgetput_sub (gfc_expr *c, gfc_expr *status)
{
if (!type_check (c, 0, BT_CHARACTER))
return false;
if (!kind_value_check (c, 0, gfc_default_character_kind))
return false;
if (strcmp (gfc_current_intrinsic, "fget") == 0
&& !variable_check (c, 0, false))
return false;
if (arg_strlen_is_zero (c, 0))
return false;
if (status == NULL)
return true;
if (!type_check (status, 1, BT_INTEGER)
|| !kind_value_check (status, 1, gfc_default_integer_kind)
|| !scalar_check (status, 1)
|| !variable_check (status, 1, false))
return false;
return true;
}
bool
gfc_check_fgetput (gfc_expr *c)
{
return gfc_check_fgetput_sub (c, NULL);
}
bool
gfc_check_fseek_sub (gfc_expr *unit, gfc_expr *offset, gfc_expr *whence, gfc_expr *status)
{
if (!type_check (unit, 0, BT_INTEGER))
return false;
if (!scalar_check (unit, 0))
return false;
if (!type_check (offset, 1, BT_INTEGER))
return false;
if (!scalar_check (offset, 1))
return false;
if (!type_check (whence, 2, BT_INTEGER))
return false;
if (!scalar_check (whence, 2))
return false;
if (status == NULL)
return true;
if (!type_check (status, 3, BT_INTEGER))
return false;
if (!kind_value_check (status, 3, 4))
return false;
if (!scalar_check (status, 3))
return false;
return true;
}
bool
gfc_check_fstat (gfc_expr *unit, gfc_expr *array)
{
if (!type_check (unit, 0, BT_INTEGER))
return false;
if (!scalar_check (unit, 0))
return false;
if (!type_check (array, 1, BT_INTEGER)
|| !kind_value_check (unit, 0, gfc_default_integer_kind))
return false;
if (!array_check (array, 1))
return false;
return true;
}
bool
gfc_check_fstat_sub (gfc_expr *unit, gfc_expr *array, gfc_expr *status)
{
if (!type_check (unit, 0, BT_INTEGER))
return false;
if (!scalar_check (unit, 0))
return false;
if (!type_check (array, 1, BT_INTEGER)
|| !kind_value_check (array, 1, gfc_default_integer_kind))
return false;
if (!array_check (array, 1))
return false;
if (status == NULL)
return true;
if (!type_check (status, 2, BT_INTEGER)
|| !kind_value_check (status, 2, gfc_default_integer_kind))
return false;
if (!scalar_check (status, 2))
return false;
return true;
}
bool
gfc_check_ftell (gfc_expr *unit)
{
if (!type_check (unit, 0, BT_INTEGER))
return false;
if (!scalar_check (unit, 0))
return false;
return true;
}
bool
gfc_check_ftell_sub (gfc_expr *unit, gfc_expr *offset)
{
if (!type_check (unit, 0, BT_INTEGER))
return false;
if (!scalar_check (unit, 0))
return false;
if (!type_check (offset, 1, BT_INTEGER))
return false;
if (!scalar_check (offset, 1))
return false;
return true;
}
bool
gfc_check_stat (gfc_expr *name, gfc_expr *array)
{
if (!type_check (name, 0, BT_CHARACTER))
return false;
if (!kind_value_check (name, 0, gfc_default_character_kind))
return false;
if (!type_check (array, 1, BT_INTEGER)
|| !kind_value_check (array, 1, gfc_default_integer_kind))
return false;
if (!array_check (array, 1))
return false;
return true;
}
bool
gfc_check_stat_sub (gfc_expr *name, gfc_expr *array, gfc_expr *status)
{
if (!type_check (name, 0, BT_CHARACTER))
return false;
if (!kind_value_check (name, 0, gfc_default_character_kind))
return false;
if (!type_check (array, 1, BT_INTEGER)
|| !kind_value_check (array, 1, gfc_default_integer_kind))
return false;
if (!array_check (array, 1))
return false;
if (status == NULL)
return true;
if (!type_check (status, 2, BT_INTEGER)
|| !kind_value_check (array, 1, gfc_default_integer_kind))
return false;
if (!scalar_check (status, 2))
return false;
return true;
}
bool
gfc_check_image_index (gfc_expr *coarray, gfc_expr *sub)
{
mpz_t nelems;
if (flag_coarray == GFC_FCOARRAY_NONE)
{
gfc_fatal_error ("Coarrays disabled at %C, use %<-fcoarray=%> to enable");
return false;
}
if (!coarray_check (coarray, 0))
return false;
if (sub->rank != 1)
{
gfc_error ("%s argument to IMAGE_INDEX must be a rank one array at %L",
gfc_current_intrinsic_arg[1]->name, &sub->where);
return false;
}
if (sub->ts.type != BT_INTEGER)
{
gfc_error ("Type of %s argument of IMAGE_INDEX at %L shall be INTEGER",
gfc_current_intrinsic_arg[1]->name, &sub->where);
return false;
}
if (gfc_array_size (sub, &nelems))
{
int corank = gfc_get_corank (coarray);
if (mpz_cmp_ui (nelems, corank) != 0)
{
gfc_error ("The number of array elements of the SUB argument to "
"IMAGE_INDEX at %L shall be %d (corank) not %d",
&sub->where, corank, (int) mpz_get_si (nelems));
mpz_clear (nelems);
return false;
}
mpz_clear (nelems);
}
return true;
}
bool
gfc_check_num_images (gfc_expr *distance, gfc_expr *failed)
{
if (flag_coarray == GFC_FCOARRAY_NONE)
{
gfc_fatal_error ("Coarrays disabled at %C, use %<-fcoarray=%> to enable");
return false;
}
if (distance)
{
if (!type_check (distance, 0, BT_INTEGER))
return false;
if (!nonnegative_check ("DISTANCE", distance))
return false;
if (!scalar_check (distance, 0))
return false;
if (!gfc_notify_std (GFC_STD_F2018, "DISTANCE= argument to "
"NUM_IMAGES at %L", &distance->where))
return false;
}
if (failed)
{
if (!type_check (failed, 1, BT_LOGICAL))
return false;
if (!scalar_check (failed, 1))
return false;
if (!gfc_notify_std (GFC_STD_F2018, "FAILED= argument to "
"NUM_IMAGES at %L", &failed->where))
return false;
}
return true;
}
bool
gfc_check_team_number (gfc_expr *team)
{
if (flag_coarray == GFC_FCOARRAY_NONE)
{
gfc_fatal_error ("Coarrays disabled at %C, use %<-fcoarray=%> to enable");
return false;
}
if (team)
{
if (team->ts.type != BT_DERIVED
|| team->ts.u.derived->from_intmod != INTMOD_ISO_FORTRAN_ENV
|| team->ts.u.derived->intmod_sym_id != ISOFORTRAN_TEAM_TYPE)
{
gfc_error ("TEAM argument at %L to the intrinsic TEAM_NUMBER "
"shall be of type TEAM_TYPE", &team->where);
return false;
}
}
else
return true;
return true;
}
bool
gfc_check_this_image (gfc_expr *coarray, gfc_expr *dim, gfc_expr *distance)
{
if (flag_coarray == GFC_FCOARRAY_NONE)
{
gfc_fatal_error ("Coarrays disabled at %C, use %<-fcoarray=%> to enable");
return false;
}
if (coarray == NULL && dim == NULL && distance == NULL)
return true;
if (dim != NULL && coarray == NULL)
{
gfc_error ("DIM argument without COARRAY argument not allowed for "
"THIS_IMAGE intrinsic at %L", &dim->where);
return false;
}
if (distance && (coarray || dim))
{
gfc_error ("The DISTANCE argument may not be specified together with the "
"COARRAY or DIM argument in intrinsic at %L",
&distance->where);
return false;
}
/* Assume that we have "this_image (distance)". */
if (coarray && !gfc_is_coarray (coarray) && coarray->ts.type == BT_INTEGER)
{
if (dim)
{
gfc_error ("Unexpected DIM argument with noncoarray argument at %L",
&coarray->where);
return false;
}
distance = coarray;
}
if (distance)
{
if (!type_check (distance, 2, BT_INTEGER))
return false;
if (!nonnegative_check ("DISTANCE", distance))
return false;
if (!scalar_check (distance, 2))
return false;
if (!gfc_notify_std (GFC_STD_F2018, "DISTANCE= argument to "
"THIS_IMAGE at %L", &distance->where))
return false;
return true;
}
if (!coarray_check (coarray, 0))
return false;
if (dim != NULL)
{
if (!dim_check (dim, 1, false))
return false;
if (!dim_corank_check (dim, coarray))
return false;
}
return true;
}
/* Calculate the sizes for transfer, used by gfc_check_transfer and also
by gfc_simplify_transfer. Return false if we cannot do so. */
bool
gfc_calculate_transfer_sizes (gfc_expr *source, gfc_expr *mold, gfc_expr *size,
size_t *source_size, size_t *result_size,
size_t *result_length_p)
{
size_t result_elt_size;
if (source->expr_type == EXPR_FUNCTION)
return false;
if (size && size->expr_type != EXPR_CONSTANT)
return false;
/* Calculate the size of the source. */
if (!gfc_target_expr_size (source, source_size))
return false;
/* Determine the size of the element. */
if (!gfc_element_size (mold, &result_elt_size))
return false;
/* If the storage size of SOURCE is greater than zero and MOLD is an array,
* a scalar with the type and type parameters of MOLD shall not have a
* storage size equal to zero.
* If MOLD is a scalar and SIZE is absent, the result is a scalar.
* If MOLD is an array and SIZE is absent, the result is an array and of
* rank one. Its size is as small as possible such that its physical
* representation is not shorter than that of SOURCE.
* If SIZE is present, the result is an array of rank one and size SIZE.
*/
if (result_elt_size == 0 && *source_size > 0
&& (mold->expr_type == EXPR_ARRAY || mold->rank))
{
gfc_error ("%<MOLD%> argument of %<TRANSFER%> intrinsic at %L is an "
"array and shall not have storage size 0 when %<SOURCE%> "
"argument has size greater than 0", &mold->where);
return false;
}
if (result_elt_size == 0 && *source_size == 0 && !size)
{
*result_size = 0;
if (result_length_p)
*result_length_p = 0;
return true;
}
if ((result_elt_size > 0 && (mold->expr_type == EXPR_ARRAY || mold->rank))
|| size)
{
int result_length;
if (size)
result_length = (size_t)mpz_get_ui (size->value.integer);
else
{
result_length = *source_size / result_elt_size;
if (result_length * result_elt_size < *source_size)
result_length += 1;
}
*result_size = result_length * result_elt_size;
if (result_length_p)
*result_length_p = result_length;
}
else
*result_size = result_elt_size;
return true;
}
bool
gfc_check_transfer (gfc_expr *source, gfc_expr *mold, gfc_expr *size)
{
size_t source_size;
size_t result_size;
if (gfc_invalid_null_arg (source))
return false;
/* SOURCE shall be a scalar or array of any type. */
if (source->ts.type == BT_PROCEDURE
&& source->symtree->n.sym->attr.subroutine == 1)
{
gfc_error ("%<SOURCE%> argument of %<TRANSFER%> intrinsic at %L "
"must not be a %s", &source->where,
gfc_basic_typename (source->ts.type));
return false;
}
if (source->ts.type == BT_BOZ && illegal_boz_arg (source))
return false;
if (mold->ts.type == BT_BOZ && illegal_boz_arg (mold))
return false;
if (gfc_invalid_null_arg (mold))
return false;
/* MOLD shall be a scalar or array of any type. */
if (mold->ts.type == BT_PROCEDURE
&& mold->symtree->n.sym->attr.subroutine == 1)
{
gfc_error ("%<MOLD%> argument of %<TRANSFER%> intrinsic at %L "
"must not be a %s", &mold->where,
gfc_basic_typename (mold->ts.type));
return false;
}
if (mold->ts.type == BT_HOLLERITH)
{
gfc_error ("%<MOLD%> argument of %<TRANSFER%> intrinsic at %L must not be"
" %s", &mold->where, gfc_basic_typename (BT_HOLLERITH));
return false;
}
/* SIZE (optional) shall be an integer scalar. The corresponding actual
argument shall not be an optional dummy argument. */
if (size != NULL)
{
if (!type_check (size, 2, BT_INTEGER))
{
if (size->ts.type == BT_BOZ)
reset_boz (size);
return false;
}
if (!scalar_check (size, 2))
return false;
if (!nonoptional_check (size, 2))
return false;
}
if (!warn_surprising)
return true;
/* If we can't calculate the sizes, we cannot check any more.
Return true for that case. */
if (!gfc_calculate_transfer_sizes (source, mold, size, &source_size,
&result_size, NULL))
return true;
if (source_size < result_size)
gfc_warning (OPT_Wsurprising,
"Intrinsic TRANSFER at %L has partly undefined result: "
"source size %ld < result size %ld", &source->where,
(long) source_size, (long) result_size);
return true;
}
bool
gfc_check_transpose (gfc_expr *matrix)
{
if (!rank_check (matrix, 0, 2))
return false;
return true;
}
bool
gfc_check_ubound (gfc_expr *array, gfc_expr *dim, gfc_expr *kind)
{
if (!array_check (array, 0))
return false;
if (!dim_check (dim, 1, false))
return false;
if (!dim_rank_check (dim, array, 0))
return false;
if (!kind_check (kind, 2, BT_INTEGER))
return false;
if (kind && !gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
"with KIND argument at %L",
gfc_current_intrinsic, &kind->where))
return false;
return true;
}
bool
gfc_check_ucobound (gfc_expr *coarray, gfc_expr *dim, gfc_expr *kind)
{
if (flag_coarray == GFC_FCOARRAY_NONE)
{
gfc_fatal_error ("Coarrays disabled at %C, use %<-fcoarray=%> to enable");
return false;
}
if (!coarray_check (coarray, 0))
return false;
if (dim != NULL)
{
if (!dim_check (dim, 1, false))
return false;
if (!dim_corank_check (dim, coarray))
return false;
}
if (!kind_check (kind, 2, BT_INTEGER))
return false;
return true;
}
bool
gfc_check_unpack (gfc_expr *vector, gfc_expr *mask, gfc_expr *field)
{
mpz_t vector_size;
if (!rank_check (vector, 0, 1))
return false;
if (!array_check (mask, 1))
return false;
if (!type_check (mask, 1, BT_LOGICAL))
return false;
if (!same_type_check (vector, 0, field, 2))
return false;
if (mask->expr_type == EXPR_ARRAY
&& gfc_array_size (vector, &vector_size))
{
int mask_true_count = 0;
gfc_constructor *mask_ctor;
mask_ctor = gfc_constructor_first (mask->value.constructor);
while (mask_ctor)
{
if (mask_ctor->expr->expr_type != EXPR_CONSTANT)
{
mask_true_count = 0;
break;
}
if (mask_ctor->expr->value.logical)
mask_true_count++;
mask_ctor = gfc_constructor_next (mask_ctor);
}
if (mpz_get_si (vector_size) < mask_true_count)
{
gfc_error ("%qs argument of %qs intrinsic at %L must "
"provide at least as many elements as there "
"are .TRUE. values in %qs (%ld/%d)",
gfc_current_intrinsic_arg[0]->name, gfc_current_intrinsic,
&vector->where, gfc_current_intrinsic_arg[1]->name,
mpz_get_si (vector_size), mask_true_count);
return false;
}
mpz_clear (vector_size);
}
if (mask->rank != field->rank && field->rank != 0)
{
gfc_error ("%qs argument of %qs intrinsic at %L must have "
"the same rank as %qs or be a scalar",
gfc_current_intrinsic_arg[2]->name, gfc_current_intrinsic,
&field->where, gfc_current_intrinsic_arg[1]->name);
return false;
}
if (mask->rank == field->rank)
{
int i;
for (i = 0; i < field->rank; i++)
if (! identical_dimen_shape (mask, i, field, i))
{
gfc_error ("%qs and %qs arguments of %qs intrinsic at %L "
"must have identical shape.",
gfc_current_intrinsic_arg[2]->name,
gfc_current_intrinsic_arg[1]->name, gfc_current_intrinsic,
&field->where);
}
}
return true;
}
bool
gfc_check_verify (gfc_expr *x, gfc_expr *y, gfc_expr *z, gfc_expr *kind)
{
if (!type_check (x, 0, BT_CHARACTER))
return false;
if (!same_type_check (x, 0, y, 1))
return false;
if (z != NULL && !type_check (z, 2, BT_LOGICAL))
return false;
if (!kind_check (kind, 3, BT_INTEGER))
return false;
if (kind && !gfc_notify_std (GFC_STD_F2003, "%qs intrinsic "
"with KIND argument at %L",
gfc_current_intrinsic, &kind->where))
return false;
return true;
}
bool
gfc_check_trim (gfc_expr *x)
{
if (!type_check (x, 0, BT_CHARACTER))
return false;
if (gfc_invalid_null_arg (x))
return false;
if (!scalar_check (x, 0))
return false;
return true;
}
bool
gfc_check_ttynam (gfc_expr *unit)
{
if (!scalar_check (unit, 0))
return false;
if (!type_check (unit, 0, BT_INTEGER))
return false;
return true;
}
/************* Check functions for intrinsic subroutines *************/
bool
gfc_check_cpu_time (gfc_expr *time)
{
if (!scalar_check (time, 0))
return false;
if (!type_check (time, 0, BT_REAL))
return false;
if (!variable_check (time, 0, false))
return false;
return true;
}
bool
gfc_check_date_and_time (gfc_expr *date, gfc_expr *time,
gfc_expr *zone, gfc_expr *values)
{
if (date != NULL)
{
if (!type_check (date, 0, BT_CHARACTER))
return false;
if (!kind_value_check (date, 0, gfc_default_character_kind))
return false;
if (!scalar_check (date, 0))
return false;
if (!variable_check (date, 0, false))
return false;
}
if (time != NULL)
{
if (!type_check (time, 1, BT_CHARACTER))
return false;
if (!kind_value_check (time, 1, gfc_default_character_kind))
return false;
if (!scalar_check (time, 1))
return false;
if (!variable_check (time, 1, false))
return false;
}
if (zone != NULL)
{
if (!type_check (zone, 2, BT_CHARACTER))
return false;
if (!kind_value_check (zone, 2, gfc_default_character_kind))
return false;
if (!scalar_check (zone, 2))
return false;
if (!variable_check (zone, 2, false))
return false;
}
if (values != NULL)
{
if (!type_check (values, 3, BT_INTEGER))
return false;
if (!array_check (values, 3))
return false;
if (!rank_check (values, 3, 1))
return false;
if (!variable_check (values, 3, false))
return false;
}
return true;
}
bool
gfc_check_mvbits (gfc_expr *from, gfc_expr *frompos, gfc_expr *len,
gfc_expr *to, gfc_expr *topos)
{
if (!type_check (from, 0, BT_INTEGER))
return false;
if (!type_check (frompos, 1, BT_INTEGER))
return false;
if (!type_check (len, 2, BT_INTEGER))
return false;
if (!same_type_check (from, 0, to, 3))
return false;
if (!variable_check (to, 3, false))
return false;
if (!type_check (topos, 4, BT_INTEGER))
return false;
if (!nonnegative_check ("frompos", frompos))
return false;
if (!nonnegative_check ("topos", topos))
return false;
if (!nonnegative_check ("len", len))
return false;
if (!less_than_bitsize2 ("from", from, "frompos", frompos, "len", len))
return false;
if (!less_than_bitsize2 ("to", to, "topos", topos, "len", len))
return false;
return true;
}
/* Check the arguments for RANDOM_INIT. */
bool
gfc_check_random_init (gfc_expr *repeatable, gfc_expr *image_distinct)
{
if (!type_check (repeatable, 0, BT_LOGICAL))
return false;
if (!scalar_check (repeatable, 0))
return false;
if (!type_check (image_distinct, 1, BT_LOGICAL))
return false;
if (!scalar_check (image_distinct, 1))
return false;
return true;
}
bool
gfc_check_random_number (gfc_expr *harvest)
{
if (!type_check (harvest, 0, BT_REAL))
return false;
if (!variable_check (harvest, 0, false))
return false;
return true;
}
bool
gfc_check_random_seed (gfc_expr *size, gfc_expr *put, gfc_expr *get)
{
unsigned int nargs = 0, seed_size;
locus *where = NULL;
mpz_t put_size, get_size;
/* Keep the number of bytes in sync with master_state in
libgfortran/intrinsics/random.c. */
seed_size = 32 / gfc_default_integer_kind;
if (size != NULL)
{
if (size->expr_type != EXPR_VARIABLE
|| !size->symtree->n.sym->attr.optional)
nargs++;
if (!scalar_check (size, 0))
return false;
if (!type_check (size, 0, BT_INTEGER))
return false;
if (!variable_check (size, 0, false))
return false;
if (!kind_value_check (size, 0, gfc_default_integer_kind))
return false;
}
if (put != NULL)
{
if (put->expr_type != EXPR_VARIABLE
|| !put->symtree->n.sym->attr.optional)
{
nargs++;
where = &put->where;
}
if (!array_check (put, 1))
return false;
if (!rank_check (put, 1, 1))
return false;
if (!type_check (put, 1, BT_INTEGER))
return false;
if (!kind_value_check (put, 1, gfc_default_integer_kind))
return false;
if (gfc_array_size (put, &put_size)
&& mpz_get_ui (put_size) < seed_size)
gfc_error ("Size of %qs argument of %qs intrinsic at %L "
"too small (%i/%i)",
gfc_current_intrinsic_arg[1]->name, gfc_current_intrinsic,
&put->where, (int) mpz_get_ui (put_size), seed_size);
}
if (get != NULL)
{
if (get->expr_type != EXPR_VARIABLE
|| !get->symtree->n.sym->attr.optional)
{
nargs++;
where = &get->where;
}
if (!array_check (get, 2))
return false;
if (!rank_check (get, 2, 1))
return false;
if (!type_check (get, 2, BT_INTEGER))
return false;
if (!variable_check (get, 2, false))
return false;
if (!kind_value_check (get, 2, gfc_default_integer_kind))
return false;
if (gfc_array_size (get, &get_size)
&& mpz_get_ui (get_size) < seed_size)
gfc_error ("Size of %qs argument of %qs intrinsic at %L "
"too small (%i/%i)",
gfc_current_intrinsic_arg[2]->name, gfc_current_intrinsic,
&get->where, (int) mpz_get_ui (get_size), seed_size);
}
/* RANDOM_SEED may not have more than one non-optional argument. */
if (nargs > 1)
gfc_error ("Too many arguments to %s at %L", gfc_current_intrinsic, where);
return true;
}
bool
gfc_check_fe_runtime_error (gfc_actual_arglist *a)
{
gfc_expr *e;
size_t len, i;
int num_percent, nargs;
e = a->expr;
if (e->expr_type != EXPR_CONSTANT)
return true;
len = e->value.character.length;
if (e->value.character.string[len-1] != '\0')
gfc_internal_error ("fe_runtime_error string must be null terminated");
num_percent = 0;
for (i=0; i<len-1; i++)
if (e->value.character.string[i] == '%')
num_percent ++;
nargs = 0;
for (; a; a = a->next)
nargs ++;
if (nargs -1 != num_percent)
gfc_internal_error ("fe_runtime_error: Wrong number of arguments (%d instead of %d)",
nargs, num_percent++);
return true;
}
bool
gfc_check_second_sub (gfc_expr *time)
{
if (!scalar_check (time, 0))
return false;
if (!type_check (time, 0, BT_REAL))
return false;
if (!kind_value_check (time, 0, 4))
return false;
return true;
}
/* COUNT and COUNT_MAX of SYSTEM_CLOCK are scalar, default-kind integer
variables in Fortran 95. In Fortran 2003 and later, they can be of any
kind, and COUNT_RATE can be of type real. Note, count, count_rate, and
count_max are all optional arguments */
bool
gfc_check_system_clock (gfc_expr *count, gfc_expr *count_rate,
gfc_expr *count_max)
{
if (count != NULL)
{
if (!scalar_check (count, 0))
return false;
if (!type_check (count, 0, BT_INTEGER))
return false;
if (count->ts.kind != gfc_default_integer_kind
&& !gfc_notify_std (GFC_STD_F2003, "COUNT argument to "
"SYSTEM_CLOCK at %L has non-default kind",
&count->where))
return false;
if (!variable_check (count, 0, false))
return false;
}
if (count_rate != NULL)
{
if (!scalar_check (count_rate, 1))
return false;
if (!variable_check (count_rate, 1, false))
return false;
if (count_rate->ts.type == BT_REAL)
{
if (!gfc_notify_std (GFC_STD_F2003, "Real COUNT_RATE argument to "
"SYSTEM_CLOCK at %L", &count_rate->where))
return false;
}
else
{
if (!type_check (count_rate, 1, BT_INTEGER))
return false;
if (count_rate->ts.kind != gfc_default_integer_kind
&& !gfc_notify_std (GFC_STD_F2003, "COUNT_RATE argument to "
"SYSTEM_CLOCK at %L has non-default kind",
&count_rate->where))
return false;
}
}
if (count_max != NULL)
{
if (!scalar_check (count_max, 2))
return false;
if (!type_check (count_max, 2, BT_INTEGER))
return false;
if (count_max->ts.kind != gfc_default_integer_kind
&& !gfc_notify_std (GFC_STD_F2003, "COUNT_MAX argument to "
"SYSTEM_CLOCK at %L has non-default kind",
&count_max->where))
return false;
if (!variable_check (count_max, 2, false))
return false;
}
return true;
}
bool
gfc_check_irand (gfc_expr *x)
{
if (x == NULL)
return true;
if (!scalar_check (x, 0))
return false;
if (!type_check (x, 0, BT_INTEGER))
return false;
if (!kind_value_check (x, 0, 4))
return false;
return true;
}
bool
gfc_check_alarm_sub (gfc_expr *seconds, gfc_expr *handler, gfc_expr *status)
{
if (!scalar_check (seconds, 0))
return false;
if (!type_check (seconds, 0, BT_INTEGER))
return false;
if (!int_or_proc_check (handler, 1))
return false;
if (handler->ts.type == BT_INTEGER && !scalar_check (handler, 1))
return false;
if (status == NULL)
return true;
if (!scalar_check (status, 2))
return false;
if (!type_check (status, 2, BT_INTEGER))
return false;
if (!kind_value_check (status, 2, gfc_default_integer_kind))
return false;
return true;
}
bool
gfc_check_rand (gfc_expr *x)
{
if (x == NULL)
return true;
if (!scalar_check (x, 0))
return false;
if (!type_check (x, 0, BT_INTEGER))
return false;
if (!kind_value_check (x, 0, 4))
return false;
return true;
}
bool
gfc_check_srand (gfc_expr *x)
{
if (!scalar_check (x, 0))
return false;
if (!type_check (x, 0, BT_INTEGER))
return false;
if (!kind_value_check (x, 0, 4))
return false;
return true;
}
bool
gfc_check_ctime_sub (gfc_expr *time, gfc_expr *result)
{
if (!scalar_check (time, 0))
return false;
if (!type_check (time, 0, BT_INTEGER))
return false;
if (!type_check (result, 1, BT_CHARACTER))
return false;
if (!kind_value_check (result, 1, gfc_default_character_kind))
return false;
return true;
}
bool
gfc_check_dtime_etime (gfc_expr *x)
{
if (!array_check (x, 0))
return false;
if (!rank_check (x, 0, 1))
return false;
if (!variable_check (x, 0, false))
return false;
if (!type_check (x, 0, BT_REAL))
return false;
if (!kind_value_check (x, 0, 4))
return false;
return true;
}
bool
gfc_check_dtime_etime_sub (gfc_expr *values, gfc_expr *time)
{
if (!array_check (values, 0))
return false;
if (!rank_check (values, 0, 1))
return false;
if (!variable_check (values, 0, false))
return false;
if (!type_check (values, 0, BT_REAL))
return false;
if (!kind_value_check (values, 0, 4))
return false;
if (!scalar_check (time, 1))
return false;
if (!type_check (time, 1, BT_REAL))
return false;
if (!kind_value_check (time, 1, 4))
return false;
return true;
}
bool
gfc_check_fdate_sub (gfc_expr *date)
{
if (!type_check (date, 0, BT_CHARACTER))
return false;
if (!kind_value_check (date, 0, gfc_default_character_kind))
return false;
return true;
}
bool
gfc_check_gerror (gfc_expr *msg)
{
if (!type_check (msg, 0, BT_CHARACTER))
return false;
if (!kind_value_check (msg, 0, gfc_default_character_kind))
return false;
return true;
}
bool
gfc_check_getcwd_sub (gfc_expr *cwd, gfc_expr *status)
{
if (!type_check (cwd, 0, BT_CHARACTER))
return false;
if (!kind_value_check (cwd, 0, gfc_default_character_kind))
return false;
if (status == NULL)
return true;
if (!scalar_check (status, 1))
return false;
if (!type_check (status, 1, BT_INTEGER))
return false;
return true;
}
bool
gfc_check_getarg (gfc_expr *pos, gfc_expr *value)
{
if (!type_check (pos, 0, BT_INTEGER))
return false;
if (pos->ts.kind > gfc_default_integer_kind)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be of a kind "
"not wider than the default kind (%d)",
gfc_current_intrinsic_arg[0]->name, gfc_current_intrinsic,
&pos->where, gfc_default_integer_kind);
return false;
}
if (!type_check (value, 1, BT_CHARACTER))
return false;
if (!kind_value_check (value, 1, gfc_default_character_kind))
return false;
return true;
}
bool
gfc_check_getlog (gfc_expr *msg)
{
if (!type_check (msg, 0, BT_CHARACTER))
return false;
if (!kind_value_check (msg, 0, gfc_default_character_kind))
return false;
return true;
}
bool
gfc_check_exit (gfc_expr *status)
{
if (status == NULL)
return true;
if (!type_check (status, 0, BT_INTEGER))
return false;
if (!scalar_check (status, 0))
return false;
return true;
}
bool
gfc_check_flush (gfc_expr *unit)
{
if (unit == NULL)
return true;
if (!type_check (unit, 0, BT_INTEGER))
return false;
if (!scalar_check (unit, 0))
return false;
return true;
}
bool
gfc_check_free (gfc_expr *i)
{
if (!type_check (i, 0, BT_INTEGER))
return false;
if (!scalar_check (i, 0))
return false;
return true;
}
bool
gfc_check_hostnm (gfc_expr *name)
{
if (!type_check (name, 0, BT_CHARACTER))
return false;
if (!kind_value_check (name, 0, gfc_default_character_kind))
return false;
return true;
}
bool
gfc_check_hostnm_sub (gfc_expr *name, gfc_expr *status)
{
if (!type_check (name, 0, BT_CHARACTER))
return false;
if (!kind_value_check (name, 0, gfc_default_character_kind))
return false;
if (status == NULL)
return true;
if (!scalar_check (status, 1))
return false;
if (!type_check (status, 1, BT_INTEGER))
return false;
return true;
}
bool
gfc_check_itime_idate (gfc_expr *values)
{
if (!array_check (values, 0))
return false;
if (!rank_check (values, 0, 1))
return false;
if (!variable_check (values, 0, false))
return false;
if (!type_check (values, 0, BT_INTEGER))
return false;
if (!kind_value_check (values, 0, gfc_default_integer_kind))
return false;
return true;
}
bool
gfc_check_ltime_gmtime (gfc_expr *time, gfc_expr *values)
{
if (!type_check (time, 0, BT_INTEGER))
return false;
if (!kind_value_check (time, 0, gfc_default_integer_kind))
return false;
if (!scalar_check (time, 0))
return false;
if (!array_check (values, 1))
return false;
if (!rank_check (values, 1, 1))
return false;
if (!variable_check (values, 1, false))
return false;
if (!type_check (values, 1, BT_INTEGER))
return false;
if (!kind_value_check (values, 1, gfc_default_integer_kind))
return false;
return true;
}
bool
gfc_check_ttynam_sub (gfc_expr *unit, gfc_expr *name)
{
if (!scalar_check (unit, 0))
return false;
if (!type_check (unit, 0, BT_INTEGER))
return false;
if (!type_check (name, 1, BT_CHARACTER))
return false;
if (!kind_value_check (name, 1, gfc_default_character_kind))
return false;
return true;
}
bool
gfc_check_is_contiguous (gfc_expr *array)
{
if (array->expr_type == EXPR_NULL)
{
gfc_error ("Actual argument at %L of %qs intrinsic shall be an "
"associated pointer", &array->where, gfc_current_intrinsic);
return false;
}
if (!array_check (array, 0))
return false;
return true;
}
bool
gfc_check_isatty (gfc_expr *unit)
{
if (unit == NULL)
return false;
if (!type_check (unit, 0, BT_INTEGER))
return false;
if (!scalar_check (unit, 0))
return false;
return true;
}
bool
gfc_check_isnan (gfc_expr *x)
{
if (!type_check (x, 0, BT_REAL))
return false;
return true;
}
bool
gfc_check_perror (gfc_expr *string)
{
if (!type_check (string, 0, BT_CHARACTER))
return false;
if (!kind_value_check (string, 0, gfc_default_character_kind))
return false;
return true;
}
bool
gfc_check_umask (gfc_expr *mask)
{
if (!type_check (mask, 0, BT_INTEGER))
return false;
if (!scalar_check (mask, 0))
return false;
return true;
}
bool
gfc_check_umask_sub (gfc_expr *mask, gfc_expr *old)
{
if (!type_check (mask, 0, BT_INTEGER))
return false;
if (!scalar_check (mask, 0))
return false;
if (old == NULL)
return true;
if (!scalar_check (old, 1))
return false;
if (!type_check (old, 1, BT_INTEGER))
return false;
return true;
}
bool
gfc_check_unlink (gfc_expr *name)
{
if (!type_check (name, 0, BT_CHARACTER))
return false;
if (!kind_value_check (name, 0, gfc_default_character_kind))
return false;
return true;
}
bool
gfc_check_unlink_sub (gfc_expr *name, gfc_expr *status)
{
if (!type_check (name, 0, BT_CHARACTER))
return false;
if (!kind_value_check (name, 0, gfc_default_character_kind))
return false;
if (status == NULL)
return true;
if (!scalar_check (status, 1))
return false;
if (!type_check (status, 1, BT_INTEGER))
return false;
return true;
}
bool
gfc_check_signal (gfc_expr *number, gfc_expr *handler)
{
if (!scalar_check (number, 0))
return false;
if (!type_check (number, 0, BT_INTEGER))
return false;
if (!int_or_proc_check (handler, 1))
return false;
if (handler->ts.type == BT_INTEGER && !scalar_check (handler, 1))
return false;
return true;
}
bool
gfc_check_signal_sub (gfc_expr *number, gfc_expr *handler, gfc_expr *status)
{
if (!scalar_check (number, 0))
return false;
if (!type_check (number, 0, BT_INTEGER))
return false;
if (!int_or_proc_check (handler, 1))
return false;
if (handler->ts.type == BT_INTEGER && !scalar_check (handler, 1))
return false;
if (status == NULL)
return true;
if (!type_check (status, 2, BT_INTEGER))
return false;
if (!scalar_check (status, 2))
return false;
return true;
}
bool
gfc_check_system_sub (gfc_expr *cmd, gfc_expr *status)
{
if (!type_check (cmd, 0, BT_CHARACTER))
return false;
if (!kind_value_check (cmd, 0, gfc_default_character_kind))
return false;
if (!scalar_check (status, 1))
return false;
if (!type_check (status, 1, BT_INTEGER))
return false;
if (!kind_value_check (status, 1, gfc_default_integer_kind))
return false;
return true;
}
/* This is used for the GNU intrinsics AND, OR and XOR. */
bool
gfc_check_and (gfc_expr *i, gfc_expr *j)
{
if (i->ts.type != BT_INTEGER
&& i->ts.type != BT_LOGICAL
&& i->ts.type != BT_BOZ)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be INTEGER, "
"LOGICAL, or a BOZ literal constant",
gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic, &i->where);
return false;
}
if (j->ts.type != BT_INTEGER
&& j->ts.type != BT_LOGICAL
&& j->ts.type != BT_BOZ)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be INTEGER, "
"LOGICAL, or a BOZ literal constant",
gfc_current_intrinsic_arg[1]->name,
gfc_current_intrinsic, &j->where);
return false;
}
/* i and j cannot both be BOZ literal constants. */
if (!boz_args_check (i, j))
return false;
/* If i is BOZ and j is integer, convert i to type of j. */
if (i->ts.type == BT_BOZ)
{
if (j->ts.type != BT_INTEGER)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be INTEGER",
gfc_current_intrinsic_arg[1]->name,
gfc_current_intrinsic, &j->where);
reset_boz (i);
return false;
}
if (!gfc_boz2int (i, j->ts.kind))
return false;
}
/* If j is BOZ and i is integer, convert j to type of i. */
if (j->ts.type == BT_BOZ)
{
if (i->ts.type != BT_INTEGER)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be INTEGER",
gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic, &j->where);
reset_boz (j);
return false;
}
if (!gfc_boz2int (j, i->ts.kind))
return false;
}
if (!same_type_check (i, 0, j, 1, false))
return false;
if (!scalar_check (i, 0))
return false;
if (!scalar_check (j, 1))
return false;
return true;
}
bool
gfc_check_storage_size (gfc_expr *a, gfc_expr *kind)
{
if (a->expr_type == EXPR_NULL)
{
gfc_error ("Intrinsic function NULL at %L cannot be an actual "
"argument to STORAGE_SIZE, because it returns a "
"disassociated pointer", &a->where);
return false;
}
if (a->ts.type == BT_ASSUMED)
{
gfc_error ("%qs argument of %qs intrinsic at %L shall not be TYPE(*)",
gfc_current_intrinsic_arg[0]->name, gfc_current_intrinsic,
&a->where);
return false;
}
if (a->ts.type == BT_PROCEDURE)
{
gfc_error ("%qs argument of %qs intrinsic at %L shall not be a "
"procedure", gfc_current_intrinsic_arg[0]->name,
gfc_current_intrinsic, &a->where);
return false;
}
if (a->ts.type == BT_BOZ && illegal_boz_arg (a))
return false;
if (kind == NULL)
return true;
if (!type_check (kind, 1, BT_INTEGER))
return false;
if (!scalar_check (kind, 1))
return false;
if (kind->expr_type != EXPR_CONSTANT)
{
gfc_error ("%qs argument of %qs intrinsic at %L must be a constant",
gfc_current_intrinsic_arg[1]->name, gfc_current_intrinsic,
&kind->where);
return false;
}
return true;
}