Index: gcc/gcc/fortran/check.c |
diff --git a/gcc/gcc/fortran/check.c b/gcc/gcc/fortran/check.c |
index b967d78cf2af5901ad5fd358b19aa5109b5cc3c5..2d8cfefb79be215c417943a560c8a93d5cf13298 100644 |
--- a/gcc/gcc/fortran/check.c |
+++ b/gcc/gcc/fortran/check.c |
@@ -214,6 +214,80 @@ array_check (gfc_expr *e, int n) |
} |
+/* If expr is a constant, then check to ensure that it is greater than |
+ of equal to zero. */ |
+ |
+static gfc_try |
+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 ("'%s' at %L must be nonnegative", arg, &expr->where); |
+ return FAILURE; |
+ } |
+ } |
+ |
+ return SUCCESS; |
+} |
+ |
+ |
+/* If expr2 is constant, then check that the value is less than |
+ bit_size(expr1). */ |
+ |
+static gfc_try |
+less_than_bitsize1 (const char *arg1, gfc_expr *expr1, const char *arg2, |
+ gfc_expr *expr2) |
+{ |
+ int i2, i3; |
+ |
+ if (expr2->expr_type == EXPR_CONSTANT) |
+ { |
+ gfc_extract_int (expr2, &i2); |
+ i3 = gfc_validate_kind (BT_INTEGER, expr1->ts.kind, false); |
+ if (i2 >= gfc_integer_kinds[i3].bit_size) |
+ { |
+ gfc_error ("'%s' at %L must be less than BIT_SIZE('%s')", |
+ arg2, &expr2->where, arg1); |
+ return FAILURE; |
+ } |
+ } |
+ |
+ return SUCCESS; |
+} |
+ |
+ |
+/* If expr2 and expr3 are constants, then check that the value is less than |
+ or equal to bit_size(expr1). */ |
+ |
+static gfc_try |
+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('%s')", |
+ arg2, arg3, &expr2->where, arg1); |
+ return FAILURE; |
+ } |
+ } |
+ |
+ return SUCCESS; |
+} |
+ |
/* Make sure two expressions have the same type. */ |
static gfc_try |
@@ -339,6 +413,9 @@ dim_rank_check (gfc_expr *dim, gfc_expr *array, int allow_assumed) |
gfc_array_ref *ar; |
int rank; |
+ if (dim == NULL) |
+ return SUCCESS; |
+ |
if (dim->expr_type != EXPR_CONSTANT |
|| (array->expr_type != EXPR_VARIABLE |
&& array->expr_type != EXPR_ARRAY)) |
@@ -407,20 +484,20 @@ gfc_check_same_strlen (const gfc_expr *a, const gfc_expr *b, const char *name) |
long len_a, len_b; |
len_a = len_b = -1; |
- if (a->ts.cl && a->ts.cl->length |
- && a->ts.cl->length->expr_type == EXPR_CONSTANT) |
- len_a = mpz_get_si (a->ts.cl->length->value.integer); |
+ if (a->ts.u.cl && a->ts.u.cl->length |
+ && a->ts.u.cl->length->expr_type == EXPR_CONSTANT) |
+ len_a = mpz_get_si (a->ts.u.cl->length->value.integer); |
else if (a->expr_type == EXPR_CONSTANT |
- && (a->ts.cl == NULL || a->ts.cl->length == NULL)) |
+ && (a->ts.u.cl == NULL || a->ts.u.cl->length == NULL)) |
len_a = a->value.character.length; |
else |
return SUCCESS; |
- if (b->ts.cl && b->ts.cl->length |
- && b->ts.cl->length->expr_type == EXPR_CONSTANT) |
- len_b = mpz_get_si (b->ts.cl->length->value.integer); |
+ if (b->ts.u.cl && b->ts.u.cl->length |
+ && b->ts.u.cl->length->expr_type == EXPR_CONSTANT) |
+ len_b = mpz_get_si (b->ts.u.cl->length->value.integer); |
else if (b->expr_type == EXPR_CONSTANT |
- && (b->ts.cl == NULL || b->ts.cl->length == NULL)) |
+ && (b->ts.u.cl == NULL || b->ts.u.cl->length == NULL)) |
len_b = b->value.character.length; |
else |
return SUCCESS; |
@@ -519,6 +596,9 @@ gfc_check_all_any (gfc_expr *mask, gfc_expr *dim) |
if (dim_check (dim, 1, false) == FAILURE) |
return FAILURE; |
+ if (dim_rank_check (dim, mask, 0) == FAILURE) |
+ return FAILURE; |
+ |
return SUCCESS; |
} |
@@ -540,9 +620,6 @@ gfc_check_allocated (gfc_expr *array) |
return FAILURE; |
} |
- if (array_check (array, 0) == FAILURE) |
- return FAILURE; |
- |
return SUCCESS; |
} |
@@ -666,6 +743,19 @@ null_arg: |
gfc_try |
+gfc_check_atan_2 (gfc_expr *y, gfc_expr *x) |
+{ |
+ /* gfc_notify_std would be a wast 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 FAILURE; |
+ |
+ return gfc_check_atan2 (y, x); |
+} |
+ |
+ |
+gfc_try |
gfc_check_atan2 (gfc_expr *y, gfc_expr *x) |
{ |
if (type_check (y, 0, BT_REAL) == FAILURE) |
@@ -693,13 +783,20 @@ gfc_check_besn (gfc_expr *n, gfc_expr *x) |
gfc_try |
-gfc_check_btest (gfc_expr *i, gfc_expr *pos) |
+gfc_check_bitfcn (gfc_expr *i, gfc_expr *pos) |
{ |
if (type_check (i, 0, BT_INTEGER) == FAILURE) |
return FAILURE; |
+ |
if (type_check (pos, 1, BT_INTEGER) == FAILURE) |
return FAILURE; |
+ if (nonnegative_check ("pos", pos) == FAILURE) |
+ return FAILURE; |
+ |
+ if (less_than_bitsize1 ("i", i, "pos", pos) == FAILURE) |
+ return FAILURE; |
+ |
return SUCCESS; |
} |
@@ -861,6 +958,8 @@ gfc_check_count (gfc_expr *mask, gfc_expr *dim, gfc_expr *kind) |
return FAILURE; |
if (dim_check (dim, 1, false) == FAILURE) |
return FAILURE; |
+ if (dim_rank_check (dim, mask, 0) == FAILURE) |
+ return FAILURE; |
if (kind_check (kind, 2, BT_INTEGER) == FAILURE) |
return FAILURE; |
if (kind && gfc_notify_std (GFC_STD_F2003, "Fortran 2003: '%s' intrinsic " |
@@ -881,24 +980,56 @@ gfc_check_cshift (gfc_expr *array, gfc_expr *shift, gfc_expr *dim) |
if (type_check (shift, 1, BT_INTEGER) == FAILURE) |
return FAILURE; |
- if (array->rank == 1) |
+ if (dim_check (dim, 2, true) == FAILURE) |
+ return FAILURE; |
+ |
+ if (dim_rank_check (dim, array, false) == FAILURE) |
+ return FAILURE; |
+ |
+ if (array->rank == 1 || shift->rank == 0) |
{ |
if (scalar_check (shift, 1) == FAILURE) |
return FAILURE; |
} |
- else if (shift->rank != array->rank - 1 && shift->rank != 0) |
+ else if (shift->rank == array->rank - 1) |
{ |
- gfc_error ("SHIFT argument at %L of CSHIFT must have rank %d or be a " |
- "scalar", &shift->where, 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 ("'%s' argument of '%s' intrinsic at %L has " |
+ "invalid shape in dimension %d (%ld/%ld)", |
+ gfc_current_intrinsic_arg[1], |
+ gfc_current_intrinsic, &shift->where, i + 1, |
+ mpz_get_si (array->shape[i]), |
+ mpz_get_si (shift->shape[j])); |
+ return FAILURE; |
+ } |
+ |
+ j += 1; |
+ } |
+ } |
+ } |
+ else |
+ { |
+ gfc_error ("'%s' argument of intrinsic '%s' at %L of must have rank " |
+ "%d or be a scalar", gfc_current_intrinsic_arg[1], |
+ gfc_current_intrinsic, &shift->where, array->rank - 1); |
return FAILURE; |
} |
- /* TODO: Add shape conformance check between array (w/o dimension dim) |
- and shift. */ |
- |
- if (dim_check (dim, 2, true) == FAILURE) |
- return FAILURE; |
- |
return SUCCESS; |
} |
@@ -1055,55 +1186,85 @@ gfc_check_eoshift (gfc_expr *array, gfc_expr *shift, gfc_expr *boundary, |
if (type_check (shift, 1, BT_INTEGER) == FAILURE) |
return FAILURE; |
- if (array->rank == 1) |
+ if (dim_check (dim, 3, true) == FAILURE) |
+ return FAILURE; |
+ |
+ if (dim_rank_check (dim, array, false) == FAILURE) |
+ return FAILURE; |
+ |
+ if (array->rank == 1 || shift->rank == 0) |
{ |
- if (scalar_check (shift, 2) == FAILURE) |
+ if (scalar_check (shift, 1) == FAILURE) |
return FAILURE; |
} |
- else if (shift->rank != array->rank - 1 && shift->rank != 0) |
+ 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 ("'%s' argument of '%s' intrinsic at %L has " |
+ "invalid shape in dimension %d (%ld/%ld)", |
+ gfc_current_intrinsic_arg[1], |
+ gfc_current_intrinsic, &shift->where, i + 1, |
+ mpz_get_si (array->shape[i]), |
+ mpz_get_si (shift->shape[j])); |
+ return FAILURE; |
+ } |
+ |
+ j += 1; |
+ } |
+ } |
+ } |
+ else |
{ |
- gfc_error ("SHIFT argument at %L of EOSHIFT must have rank %d or be a " |
- "scalar", &shift->where, array->rank - 1); |
+ gfc_error ("'%s' argument of intrinsic '%s' at %L of must have rank " |
+ "%d or be a scalar", gfc_current_intrinsic_arg[1], |
+ gfc_current_intrinsic, &shift->where, array->rank - 1); |
return FAILURE; |
} |
- /* TODO: Add shape conformance check between array (w/o dimension dim) |
- and shift. */ |
- |
if (boundary != NULL) |
{ |
if (same_type_check (array, 0, boundary, 2) == FAILURE) |
return FAILURE; |
- if (array->rank == 1) |
+ if (array->rank == 1 || boundary->rank == 0) |
{ |
if (scalar_check (boundary, 2) == FAILURE) |
return FAILURE; |
} |
- else if (boundary->rank != array->rank - 1 && boundary->rank != 0) |
+ else if (boundary->rank == array->rank - 1) |
{ |
- gfc_error ("BOUNDARY argument at %L of EOSHIFT must have rank %d or be " |
- "a scalar", &boundary->where, array->rank - 1); |
- return FAILURE; |
+ if (gfc_check_conformance (shift, boundary, |
+ "arguments '%s' and '%s' for " |
+ "intrinsic %s", |
+ gfc_current_intrinsic_arg[1], |
+ gfc_current_intrinsic_arg[2], |
+ gfc_current_intrinsic ) == FAILURE) |
+ return FAILURE; |
} |
- |
- if (shift->rank == boundary->rank) |
+ else |
{ |
- int i; |
- for (i = 0; i < shift->rank; i++) |
- if (! identical_dimen_shape (shift, i, boundary, i)) |
- { |
- gfc_error ("Different shape in dimension %d for SHIFT and " |
- "BOUNDARY arguments of EOSHIFT at %L", shift->rank, |
- &boundary->where); |
- return FAILURE; |
- } |
+ gfc_error ("'%s' argument of intrinsic '%s' at %L of must have " |
+ "rank %d or be a scalar", gfc_current_intrinsic_arg[1], |
+ gfc_current_intrinsic, &shift->where, array->rank - 1); |
+ return FAILURE; |
} |
} |
- if (dim_check (dim, 4, true) == FAILURE) |
- return FAILURE; |
- |
return SUCCESS; |
} |
@@ -1155,6 +1316,23 @@ gfc_check_fn_rc (gfc_expr *a) |
gfc_try |
+gfc_check_fn_rc2008 (gfc_expr *a) |
+{ |
+ if (real_or_complex_check (a, 0) == FAILURE) |
+ return FAILURE; |
+ |
+ if (a->ts.type == BT_COMPLEX |
+ && gfc_notify_std (GFC_STD_F2008, "Fortran 2008: COMPLEX argument '%s' " |
+ "argument of '%s' intrinsic at %L", |
+ gfc_current_intrinsic_arg[0], gfc_current_intrinsic, |
+ &a->where) == FAILURE) |
+ return FAILURE; |
+ |
+ return SUCCESS; |
+} |
+ |
+ |
+gfc_try |
gfc_check_fnum (gfc_expr *unit) |
{ |
if (type_check (unit, 0, BT_INTEGER) == FAILURE) |
@@ -1222,19 +1400,6 @@ gfc_check_iand (gfc_expr *i, gfc_expr *j) |
gfc_try |
-gfc_check_ibclr (gfc_expr *i, gfc_expr *pos) |
-{ |
- if (type_check (i, 0, BT_INTEGER) == FAILURE) |
- return FAILURE; |
- |
- if (type_check (pos, 1, BT_INTEGER) == FAILURE) |
- return FAILURE; |
- |
- return SUCCESS; |
-} |
- |
- |
-gfc_try |
gfc_check_ibits (gfc_expr *i, gfc_expr *pos, gfc_expr *len) |
{ |
if (type_check (i, 0, BT_INTEGER) == FAILURE) |
@@ -1246,17 +1411,13 @@ gfc_check_ibits (gfc_expr *i, gfc_expr *pos, gfc_expr *len) |
if (type_check (len, 2, BT_INTEGER) == FAILURE) |
return FAILURE; |
- return SUCCESS; |
-} |
- |
+ if (nonnegative_check ("pos", pos) == FAILURE) |
+ return FAILURE; |
-gfc_try |
-gfc_check_ibset (gfc_expr *i, gfc_expr *pos) |
-{ |
- if (type_check (i, 0, BT_INTEGER) == FAILURE) |
+ if (nonnegative_check ("len", len) == FAILURE) |
return FAILURE; |
- if (type_check (pos, 1, BT_INTEGER) == FAILURE) |
+ if (less_than_bitsize2 ("i", i, "pos", pos, "len", len) == FAILURE) |
return FAILURE; |
return SUCCESS; |
@@ -1296,12 +1457,12 @@ gfc_check_ichar_iachar (gfc_expr *c, gfc_expr *kind) |
{ |
/* Check that the argument is length one. Non-constant lengths |
can't be checked here, so assume they are ok. */ |
- if (c->ts.cl && c->ts.cl->length) |
+ 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.cl->length->expr_type != EXPR_CONSTANT) |
+ if (c->ts.u.cl->length->expr_type != EXPR_CONSTANT) |
return SUCCESS; |
- i = mpz_get_si (c->ts.cl->length->value.integer); |
+ i = mpz_get_si (c->ts.u.cl->length->value.integer); |
} |
else |
return SUCCESS; |
@@ -1525,14 +1686,11 @@ gfc_check_lbound (gfc_expr *array, gfc_expr *dim, gfc_expr *kind) |
if (array_check (array, 0) == FAILURE) |
return FAILURE; |
- if (dim != NULL) |
- { |
- if (dim_check (dim, 1, false) == FAILURE) |
- return FAILURE; |
+ if (dim_check (dim, 1, false) == FAILURE) |
+ return FAILURE; |
- if (dim_rank_check (dim, array, 1) == FAILURE) |
- return FAILURE; |
- } |
+ if (dim_rank_check (dim, array, 1) == FAILURE) |
+ return FAILURE; |
if (kind_check (kind, 2, BT_INTEGER) == FAILURE) |
return FAILURE; |
@@ -1732,13 +1890,11 @@ check_rest (bt type, int kind, gfc_actual_arglist *arglist) |
} |
for (tmp = arglist, m=1; tmp != arg; tmp = tmp->next, m++) |
- { |
- char buffer[80]; |
- snprintf (buffer, 80, "arguments 'a%d' and 'a%d' for intrinsic '%s'", |
- m, n, gfc_current_intrinsic); |
- if (gfc_check_conformance (buffer, tmp->expr, x) == FAILURE) |
+ if (gfc_check_conformance (tmp->expr, x, |
+ "arguments 'a%d' and 'a%d' for " |
+ "intrinsic '%s'", m, n, |
+ gfc_current_intrinsic) == FAILURE) |
return FAILURE; |
- } |
} |
return SUCCESS; |
@@ -1918,24 +2074,22 @@ gfc_check_minloc_maxloc (gfc_actual_arglist *ap) |
ap->next->next->expr = m; |
} |
- if (d && dim_check (d, 1, false) == FAILURE) |
+ if (dim_check (d, 1, false) == FAILURE) |
return FAILURE; |
- if (d && dim_rank_check (d, a, 0) == FAILURE) |
+ if (dim_rank_check (d, a, 0) == FAILURE) |
return FAILURE; |
if (m != NULL && type_check (m, 2, BT_LOGICAL) == FAILURE) |
return FAILURE; |
- if (m != NULL) |
- { |
- char buffer[80]; |
- snprintf (buffer, 80, "arguments '%s' and '%s' for intrinsic %s", |
- gfc_current_intrinsic_arg[0], gfc_current_intrinsic_arg[2], |
- gfc_current_intrinsic); |
- if (gfc_check_conformance (buffer, a, m) == FAILURE) |
- return FAILURE; |
- } |
+ if (m != NULL |
+ && gfc_check_conformance (a, m, |
+ "arguments '%s' and '%s' for intrinsic %s", |
+ gfc_current_intrinsic_arg[0], |
+ gfc_current_intrinsic_arg[2], |
+ gfc_current_intrinsic ) == FAILURE) |
+ return FAILURE; |
return SUCCESS; |
} |
@@ -1974,24 +2128,22 @@ check_reduction (gfc_actual_arglist *ap) |
ap->next->next->expr = m; |
} |
- if (d && dim_check (d, 1, false) == FAILURE) |
+ if (dim_check (d, 1, false) == FAILURE) |
return FAILURE; |
- if (d && dim_rank_check (d, a, 0) == FAILURE) |
+ if (dim_rank_check (d, a, 0) == FAILURE) |
return FAILURE; |
if (m != NULL && type_check (m, 2, BT_LOGICAL) == FAILURE) |
return FAILURE; |
- if (m != NULL) |
- { |
- char buffer[80]; |
- snprintf (buffer, 80, "arguments '%s' and '%s' for intrinsic %s", |
- gfc_current_intrinsic_arg[0], gfc_current_intrinsic_arg[2], |
- gfc_current_intrinsic); |
- if (gfc_check_conformance (buffer, a, m) == FAILURE) |
- return FAILURE; |
- } |
+ if (m != NULL |
+ && gfc_check_conformance (a, m, |
+ "arguments '%s' and '%s' for intrinsic %s", |
+ gfc_current_intrinsic_arg[0], |
+ gfc_current_intrinsic_arg[2], |
+ gfc_current_intrinsic) == FAILURE) |
+ return FAILURE; |
return SUCCESS; |
} |
@@ -2043,9 +2195,6 @@ gfc_check_move_alloc (gfc_expr *from, gfc_expr *to) |
if (variable_check (from, 0) == FAILURE) |
return FAILURE; |
- if (array_check (from, 0) == FAILURE) |
- return FAILURE; |
- |
attr = gfc_variable_attr (from, NULL); |
if (!attr.allocatable) |
{ |
@@ -2058,9 +2207,6 @@ gfc_check_move_alloc (gfc_expr *from, gfc_expr *to) |
if (variable_check (to, 0) == FAILURE) |
return FAILURE; |
- if (array_check (to, 0) == FAILURE) |
- return FAILURE; |
- |
attr = gfc_variable_attr (to, NULL); |
if (!attr.allocatable) |
{ |
@@ -2070,7 +2216,7 @@ gfc_check_move_alloc (gfc_expr *from, gfc_expr *to) |
return FAILURE; |
} |
- if (same_type_check (from, 0, to, 1) == FAILURE) |
+ if (same_type_check (to, 1, from, 0) == FAILURE) |
return FAILURE; |
if (to->rank != from->rank) |
@@ -2146,29 +2292,78 @@ gfc_check_null (gfc_expr *mold) |
gfc_try |
gfc_check_pack (gfc_expr *array, gfc_expr *mask, gfc_expr *vector) |
{ |
- char buffer[80]; |
- |
if (array_check (array, 0) == FAILURE) |
return FAILURE; |
if (type_check (mask, 1, BT_LOGICAL) == FAILURE) |
return FAILURE; |
- snprintf (buffer, 80, "arguments '%s' and '%s' for intrinsic '%s'", |
- gfc_current_intrinsic_arg[0], gfc_current_intrinsic_arg[1], |
- gfc_current_intrinsic); |
- if (gfc_check_conformance (buffer, array, mask) == FAILURE) |
+ if (gfc_check_conformance (array, mask, |
+ "arguments '%s' and '%s' for intrinsic '%s'", |
+ gfc_current_intrinsic_arg[0], |
+ gfc_current_intrinsic_arg[1], |
+ gfc_current_intrinsic) == FAILURE) |
return FAILURE; |
if (vector != NULL) |
{ |
+ mpz_t array_size, vector_size; |
+ bool have_array_size, have_vector_size; |
+ |
if (same_type_check (array, 0, vector, 2) == FAILURE) |
return FAILURE; |
if (rank_check (vector, 2, 1) == FAILURE) |
return FAILURE; |
- /* TODO: More constraints here. */ |
+ /* VECTOR requires at least as many elements as MASK |
+ has .TRUE. values. */ |
+ have_array_size = gfc_array_size (array, &array_size) == SUCCESS; |
+ have_vector_size = gfc_array_size (vector, &vector_size) == SUCCESS; |
+ |
+ 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->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 = mask_ctor->next; |
+ } |
+ } |
+ 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 ("'%s' argument of '%s' intrinsic at %L must " |
+ "provide at least as many elements as there " |
+ "are .TRUE. values in '%s' (%ld/%d)", |
+ gfc_current_intrinsic_arg[2],gfc_current_intrinsic, |
+ &vector->where, gfc_current_intrinsic_arg[1], |
+ mpz_get_si (vector_size), mask_true_values); |
+ return FAILURE; |
+ } |
+ } |
+ |
+ if (have_array_size) |
+ mpz_clear (array_size); |
+ if (have_vector_size) |
+ mpz_clear (vector_size); |
} |
return SUCCESS; |
@@ -2337,7 +2532,7 @@ gfc_check_reshape (gfc_expr *source, gfc_expr *shape, |
{ |
mpz_t size; |
mpz_t nelems; |
- int m; |
+ int shape_size; |
if (array_check (source, 0) == FAILURE) |
return FAILURE; |
@@ -2355,26 +2550,121 @@ gfc_check_reshape (gfc_expr *source, gfc_expr *shape, |
return FAILURE; |
} |
- m = mpz_cmp_ui (size, GFC_MAX_DIMENSIONS); |
+ shape_size = mpz_get_ui (size); |
mpz_clear (size); |
- if (m > 0) |
+ if (shape_size <= 0) |
+ { |
+ gfc_error ("'%s' argument of '%s' intrinsic at %L is empty", |
+ gfc_current_intrinsic_arg[1], gfc_current_intrinsic, |
+ &shape->where); |
+ return FAILURE; |
+ } |
+ 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 FAILURE; |
} |
+ else if (shape->expr_type == EXPR_ARRAY) |
+ { |
+ gfc_expr *e; |
+ int i, extent; |
+ for (i = 0; i < shape_size; ++i) |
+ { |
+ e = gfc_get_array_element (shape, i); |
+ if (e->expr_type != EXPR_CONSTANT) |
+ { |
+ gfc_free_expr (e); |
+ continue; |
+ } |
+ |
+ gfc_extract_int (e, &extent); |
+ if (extent < 0) |
+ { |
+ gfc_error ("'%s' argument of '%s' intrinsic at %L has " |
+ "negative element (%d)", gfc_current_intrinsic_arg[1], |
+ gfc_current_intrinsic, &e->where, extent); |
+ return FAILURE; |
+ } |
+ |
+ gfc_free_expr (e); |
+ } |
+ } |
if (pad != NULL) |
{ |
if (same_type_check (source, 0, pad, 2) == FAILURE) |
return FAILURE; |
+ |
if (array_check (pad, 2) == FAILURE) |
return FAILURE; |
} |
- if (order != NULL && array_check (order, 3) == FAILURE) |
- return FAILURE; |
+ if (order != NULL) |
+ { |
+ if (array_check (order, 3) == FAILURE) |
+ return FAILURE; |
+ |
+ if (type_check (order, 3, BT_INTEGER) == FAILURE) |
+ return FAILURE; |
+ |
+ if (order->expr_type == EXPR_ARRAY) |
+ { |
+ 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 ("'%s' argument of '%s' intrinsic at %L " |
+ "has wrong number of elements (%d/%d)", |
+ gfc_current_intrinsic_arg[3], |
+ gfc_current_intrinsic, &order->where, |
+ order_size, shape_size); |
+ return FAILURE; |
+ } |
+ |
+ for (i = 1; i <= order_size; ++i) |
+ { |
+ e = gfc_get_array_element (order, i-1); |
+ if (e->expr_type != EXPR_CONSTANT) |
+ { |
+ gfc_free_expr (e); |
+ continue; |
+ } |
+ |
+ gfc_extract_int (e, &dim); |
+ |
+ if (dim < 1 || dim > order_size) |
+ { |
+ gfc_error ("'%s' argument of '%s' intrinsic at %L " |
+ "has out-of-range dimension (%d)", |
+ gfc_current_intrinsic_arg[3], |
+ gfc_current_intrinsic, &e->where, dim); |
+ return FAILURE; |
+ } |
+ |
+ if (perm[dim-1] != 0) |
+ { |
+ gfc_error ("'%s' argument of '%s' intrinsic at %L has " |
+ "invalid permutation of dimensions (dimension " |
+ "'%d' duplicated)", gfc_current_intrinsic_arg[3], |
+ gfc_current_intrinsic, &e->where, dim); |
+ return FAILURE; |
+ } |
+ |
+ perm[dim-1] = 1; |
+ gfc_free_expr (e); |
+ } |
+ } |
+ } |
if (pad == NULL && shape->expr_type == EXPR_ARRAY |
&& gfc_is_constant_expr (shape) |
@@ -2411,6 +2701,46 @@ gfc_check_reshape (gfc_expr *source, gfc_expr *shape, |
gfc_try |
+gfc_check_same_type_as (gfc_expr *a, gfc_expr *b) |
+{ |
+ |
+ if (a->ts.type != BT_DERIVED && a->ts.type != BT_CLASS) |
+ { |
+ gfc_error ("'%s' argument of '%s' intrinsic at %L " |
+ "must be of a derived type", gfc_current_intrinsic_arg[0], |
+ gfc_current_intrinsic, &a->where); |
+ return FAILURE; |
+ } |
+ |
+ if (!gfc_type_is_extensible (a->ts.u.derived)) |
+ { |
+ gfc_error ("'%s' argument of '%s' intrinsic at %L " |
+ "must be of an extensible type", gfc_current_intrinsic_arg[0], |
+ gfc_current_intrinsic, &a->where); |
+ return FAILURE; |
+ } |
+ |
+ if (b->ts.type != BT_DERIVED && b->ts.type != BT_CLASS) |
+ { |
+ gfc_error ("'%s' argument of '%s' intrinsic at %L " |
+ "must be of a derived type", gfc_current_intrinsic_arg[1], |
+ gfc_current_intrinsic, &b->where); |
+ return FAILURE; |
+ } |
+ |
+ if (!gfc_type_is_extensible (b->ts.u.derived)) |
+ { |
+ gfc_error ("'%s' argument of '%s' intrinsic at %L " |
+ "must be of an extensible type", gfc_current_intrinsic_arg[1], |
+ gfc_current_intrinsic, &b->where); |
+ return FAILURE; |
+ } |
+ |
+ return SUCCESS; |
+} |
+ |
+ |
+gfc_try |
gfc_check_scale (gfc_expr *x, gfc_expr *i) |
{ |
if (type_check (x, 0, BT_REAL) == FAILURE) |
@@ -2505,11 +2835,23 @@ gfc_check_selected_real_kind (gfc_expr *p, gfc_expr *r) |
return FAILURE; |
} |
- if (p != NULL && type_check (p, 0, BT_INTEGER) == FAILURE) |
- return FAILURE; |
+ if (p) |
+ { |
+ if (type_check (p, 0, BT_INTEGER) == FAILURE) |
+ return FAILURE; |
- if (r != NULL && type_check (r, 1, BT_INTEGER) == FAILURE) |
- return FAILURE; |
+ if (scalar_check (p, 0) == FAILURE) |
+ return FAILURE; |
+ } |
+ |
+ if (r) |
+ { |
+ if (type_check (r, 1, BT_INTEGER) == FAILURE) |
+ return FAILURE; |
+ |
+ if (scalar_check (r, 1) == FAILURE) |
+ return FAILURE; |
+ } |
return SUCCESS; |
} |
@@ -2568,14 +2910,11 @@ gfc_check_size (gfc_expr *array, gfc_expr *dim, gfc_expr *kind) |
if (array_check (array, 0) == FAILURE) |
return FAILURE; |
- if (dim != NULL) |
- { |
- if (dim_check (dim, 1, true) == FAILURE) |
- return FAILURE; |
+ if (dim_check (dim, 1, true) == FAILURE) |
+ return FAILURE; |
- if (dim_rank_check (dim, array, 0) == FAILURE) |
- return FAILURE; |
- } |
+ if (dim_rank_check (dim, array, 0) == FAILURE) |
+ return FAILURE; |
if (kind_check (kind, 2, BT_INTEGER) == FAILURE) |
return FAILURE; |
@@ -2627,6 +2966,18 @@ gfc_check_spread (gfc_expr *source, gfc_expr *dim, gfc_expr *ncopies) |
if (dim_check (dim, 1, false) == FAILURE) |
return FAILURE; |
+ /* 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 ("'%s' argument of '%s' intrinsic at %L is not a valid " |
+ "dimension index", gfc_current_intrinsic_arg[1], |
+ gfc_current_intrinsic, &dim->where); |
+ return FAILURE; |
+ } |
+ |
if (type_check (ncopies, 2, BT_INTEGER) == FAILURE) |
return FAILURE; |
@@ -2911,14 +3262,11 @@ gfc_check_ubound (gfc_expr *array, gfc_expr *dim, gfc_expr *kind) |
if (array_check (array, 0) == FAILURE) |
return FAILURE; |
- if (dim != NULL) |
- { |
- if (dim_check (dim, 1, false) == FAILURE) |
- return FAILURE; |
+ if (dim_check (dim, 1, false) == FAILURE) |
+ return FAILURE; |
- if (dim_rank_check (dim, array, 0) == FAILURE) |
- return FAILURE; |
- } |
+ if (dim_rank_check (dim, array, 0) == FAILURE) |
+ return FAILURE; |
if (kind_check (kind, 2, BT_INTEGER) == FAILURE) |
return FAILURE; |
@@ -2934,6 +3282,8 @@ gfc_check_ubound (gfc_expr *array, gfc_expr *dim, gfc_expr *kind) |
gfc_try |
gfc_check_unpack (gfc_expr *vector, gfc_expr *mask, gfc_expr *field) |
{ |
+ mpz_t vector_size; |
+ |
if (rank_check (vector, 0, 1) == FAILURE) |
return FAILURE; |
@@ -2946,10 +3296,45 @@ gfc_check_unpack (gfc_expr *vector, gfc_expr *mask, gfc_expr *field) |
if (same_type_check (vector, 0, field, 2) == FAILURE) |
return FAILURE; |
+ if (mask->expr_type == EXPR_ARRAY |
+ && gfc_array_size (vector, &vector_size) == SUCCESS) |
+ { |
+ int mask_true_count = 0; |
+ gfc_constructor *mask_ctor = 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 = mask_ctor->next; |
+ } |
+ |
+ if (mpz_get_si (vector_size) < mask_true_count) |
+ { |
+ gfc_error ("'%s' argument of '%s' intrinsic at %L must " |
+ "provide at least as many elements as there " |
+ "are .TRUE. values in '%s' (%ld/%d)", |
+ gfc_current_intrinsic_arg[0], gfc_current_intrinsic, |
+ &vector->where, gfc_current_intrinsic_arg[1], |
+ mpz_get_si (vector_size), mask_true_count); |
+ return FAILURE; |
+ } |
+ |
+ mpz_clear (vector_size); |
+ } |
+ |
if (mask->rank != field->rank && field->rank != 0) |
{ |
- gfc_error ("FIELD argument at %L of UNPACK must have the same rank as " |
- "MASK or be a scalar", &field->where); |
+ gfc_error ("'%s' argument of '%s' intrinsic at %L must have " |
+ "the same rank as '%s' or be a scalar", |
+ gfc_current_intrinsic_arg[2], gfc_current_intrinsic, |
+ &field->where, gfc_current_intrinsic_arg[1]); |
return FAILURE; |
} |
@@ -2959,9 +3344,11 @@ gfc_check_unpack (gfc_expr *vector, gfc_expr *mask, gfc_expr *field) |
for (i = 0; i < field->rank; i++) |
if (! identical_dimen_shape (mask, i, field, i)) |
{ |
- gfc_error ("Different shape in dimension %d for MASK and FIELD " |
- "arguments of UNPACK at %L", mask->rank, &field->where); |
- return FAILURE; |
+ gfc_error ("'%s' and '%s' arguments of '%s' intrinsic at %L " |
+ "must have identical shape.", |
+ gfc_current_intrinsic_arg[2], |
+ gfc_current_intrinsic_arg[1], gfc_current_intrinsic, |
+ &field->where); |
} |
} |
@@ -3127,6 +3514,22 @@ gfc_check_mvbits (gfc_expr *from, gfc_expr *frompos, gfc_expr *len, |
if (type_check (topos, 4, BT_INTEGER) == FAILURE) |
return FAILURE; |
+ if (nonnegative_check ("frompos", frompos) == FAILURE) |
+ return FAILURE; |
+ |
+ if (nonnegative_check ("topos", topos) == FAILURE) |
+ return FAILURE; |
+ |
+ if (nonnegative_check ("len", len) == FAILURE) |
+ return FAILURE; |
+ |
+ if (less_than_bitsize2 ("from", from, "frompos", frompos, "len", len) |
+ == FAILURE) |
+ return FAILURE; |
+ |
+ if (less_than_bitsize2 ("to", to, "topos", topos, "len", len) == FAILURE) |
+ return FAILURE; |
+ |
return SUCCESS; |
} |