/* Given an arithmetic error code, return a pointer to a string that
explains the error. */
-static const char *
+const char *
gfc_arith_error (arith code)
{
const char *p;
case ARITH_INVALID_TYPE:
p = G_("Invalid type in arithmetic operation at %L");
break;
-
+ case ARITH_UNSIGNED_TRUNCATED:
+ p = G_("Unsigned constant truncated at %L");
+ break;
+ case ARITH_UNSIGNED_NEGATIVE:
+ p = G_("Truncated negative unsigned constant at %L");
+ break;
default:
gfc_internal_error ("gfc_arith_error(): Bad error code");
}
{
for (uint_info = gfc_unsigned_kinds; uint_info->kind != 0; uint_info++)
{
+ /* UNSIGNED is radix 2. */
+ gcc_assert (uint_info->radix == 2);
/* Huge. */
mpz_init (uint_info->huge);
- mpz_set_ui (uint_info->huge, uint_info->radix);
+ mpz_set_ui (uint_info->huge, 2);
mpz_pow_ui (uint_info->huge, uint_info->huge, uint_info->digits);
+ mpz_sub_ui (uint_info->huge, uint_info->huge, 1);
- /* UNSIGNED is radix 2. */
- gcc_assert (uint_info->radix == 2);
+ /* int_min - the smallest number we can reasonably convert from. */
+
+ mpz_init (uint_info->int_min);
+ mpz_set_ui (uint_info->int_min, 2);
+ mpz_pow_ui (uint_info->int_min, uint_info->int_min,
+ uint_info->digits - 1);
+ mpz_neg (uint_info->int_min, uint_info->int_min);
/* Range. */
mpfr_set_z (a, uint_info->huge, GFC_RND_MODE);
return result;
}
+/* Same as above. */
+arith
+gfc_check_unsigned_range (mpz_t p, int kind)
+{
+ arith result;
+ int i;
+
+ i = gfc_validate_kind (BT_UNSIGNED, kind, false);
+ result = ARITH_OK;
+
+ if (mpz_cmp (p, gfc_unsigned_kinds[i].int_min) < 0)
+ result = ARITH_UNSIGNED_TRUNCATED;
+
+ if (mpz_cmp (p, gfc_unsigned_kinds[i].huge) > 0)
+ result = ARITH_UNSIGNED_TRUNCATED;
+
+ return result;
+}
/* Given a real and a kind, make sure that the real lies within the
range of the kind. Returns ARITH_OK, ARITH_OVERFLOW or
rc = gfc_check_integer_range (e->value.integer, e->ts.kind);
break;
+ case BT_UNSIGNED:
+ rc = gfc_check_unsigned_range (e->value.integer, e->ts.kind);
+ break;
+
case BT_REAL:
rc = gfc_check_real_range (e->value.real, e->ts.kind);
if (rc == ARITH_UNDERFLOW)
{
gfc_expr *result;
arith rc;
+ int k;
result = gfc_get_constant_expr (op1->ts.type, op1->ts.kind, &op1->where);
mpz_neg (result->value.integer, op1->value.integer);
break;
+ case BT_UNSIGNED:
+ {
+ arith neg_rc;
+ mpz_neg (result->value.integer, op1->value.integer);
+ k = gfc_validate_kind (BT_UNSIGNED, op1->ts.kind, false);
+ neg_rc = gfc_range_check (result);
+ if (neg_rc != ARITH_OK)
+ gfc_warning (0, gfc_arith_error (neg_rc), &result->where);
+
+ mpz_and (result->value.integer, result->value.integer,
+ gfc_unsigned_kinds[k].huge);
+ if (pedantic)
+ rc = neg_rc;
+ }
+ break;
+
case BT_REAL:
mpfr_neg (result->value.real, op1->value.real, GFC_RND_MODE);
break;
enum arith
{ ARITH_OK = 1, ARITH_OVERFLOW, ARITH_UNDERFLOW, ARITH_NAN,
ARITH_DIV0, ARITH_INCOMMENSURATE, ARITH_ASYMMETRIC, ARITH_PROHIBIT,
- ARITH_WRONGCONCAT, ARITH_INVALID_TYPE, ARITH_NOT_REDUCED
+ ARITH_WRONGCONCAT, ARITH_INVALID_TYPE, ARITH_NOT_REDUCED,
+ ARITH_UNSIGNED_TRUNCATED, ARITH_UNSIGNED_NEGATIVE
};
/* Statements. */
typedef struct
{
- mpz_t huge;
+ mpz_t huge, int_min;
int kind, radix, digits, bit_size, range;
void gfc_arith_init_1 (void);
void gfc_arith_done_1 (void);
arith gfc_check_integer_range (mpz_t p, int kind);
+arith gfc_check_unsigned_range (mpz_t p, int kind);
bool gfc_check_character_range (gfc_char_t, int);
+const char *gfc_arith_error (arith);
extern bool gfc_seen_div0;
gfc_expr *gfc_simplify_ieee_functions (gfc_expr *);
bool gfc_is_constant_array_expr (gfc_expr *);
bool gfc_is_size_zero_array (gfc_expr *);
-void gfc_convert_mpz_to_unsigned (mpz_t, int, bool check = true);
+void gfc_convert_mpz_to_unsigned (mpz_t, int, bool sign = true);
/* trans-array.cc */
gfc_expr *e;
const char *t;
int k;
+ arith rc;
e = gfc_get_constant_expr (BT_UNSIGNED, kind, where);
/* A leading plus is allowed, but not by mpz_set_str. */
mpz_set_str (e->value.integer, t, radix);
k = gfc_validate_kind (BT_UNSIGNED, kind, false);
+
+ /* XXX Maybe move this somewhere else. */
+ rc = gfc_range_check (e);
+ if (rc != ARITH_OK)
+ gfc_warning (0, gfc_arith_error (rc), &e->where);
+
gfc_convert_mpz_to_unsigned (e->value.integer, gfc_unsigned_kinds[k].bit_size,
false);
be accomplished by masking out the high bits. */
void
-gfc_convert_mpz_to_unsigned (mpz_t x, int bitsize, bool check)
+gfc_convert_mpz_to_unsigned (mpz_t x, int bitsize, bool sign)
{
mpz_t mask;
{
/* Confirm that no bits above the signed range are unset if we
are doing range checking. */
- if (flag_range_check != 0)
+ if (sign && flag_range_check != 0)
gcc_assert (mpz_scan0 (x, bitsize-1) == ULONG_MAX);
mpz_init_set_ui (mask, 1);
{
/* Confirm that no bits above the signed range are set if we
are doing range checking. */
- if (check && flag_range_check != 0)
+ if (sign && flag_range_check != 0)
gcc_assert (mpz_scan1 (x, bitsize-1) == ULONG_MAX);
}
}
PUSH_TYPE (name_buf, type);
}
- if (flag_unsigned)
- {
- for (index = 0; gfc_unsigned_kinds[index].kind != 0;++index)
- {
- type = gfc_build_unsigned_type (&gfc_unsigned_kinds[index]);
- gfc_unsigned_types[index] = type;
- snprintf (name_buf, sizeof(name_buf), "unsigned(kind=%d",
- gfc_integer_kinds[index].kind);
- PUSH_TYPE (name_buf, type);
- }
- }
-
for (index = 0; gfc_logical_kinds[index].kind != 0; ++index)
{
type = gfc_build_logical_type (&gfc_logical_kinds[index]);
}
gfc_character1_type_node = gfc_character_types[0];
+ /* The middle end only recognizes a single unsigned type. For
+ compatibility of existing test cases, let's just use the
+ character type. The reader of tree dumps is expected to be able
+ to deal with this. */
+
+ if (flag_unsigned)
+ {
+ for (index = 0; gfc_unsigned_kinds[index].kind != 0;++index)
+ {
+ int index_char = -1;
+ for (int i=0; gfc_character_kinds[i].kind != 0; i++)
+ {
+ if (gfc_character_kinds[i].bit_size ==
+ gfc_unsigned_kinds[index].bit_size)
+ {
+ index_char = i;
+ break;
+ }
+ }
+ if (index_char > 0)
+ {
+ gfc_unsigned_types[index] = gfc_character_types[index_char];
+ }
+ else
+ {
+ type = gfc_build_unsigned_type (&gfc_unsigned_kinds[index]);
+ gfc_unsigned_types[index] = type;
+ snprintf (name_buf, sizeof(name_buf), "unsigned(kind=%d)",
+ gfc_integer_kinds[index].kind);
+ PUSH_TYPE (name_buf, type);
+ }
+ }
+ }
+
PUSH_TYPE ("byte", unsigned_char_type_node);
PUSH_TYPE ("void", void_type_node);
tree
gfc_get_unsigned_type (int kind)
{
- int index = gfc_validate_kind (BT_INTEGER, kind, true);
- return index < 0 ? 0 : gfc_integer_types[index];
+ int index = gfc_validate_kind (BT_UNSIGNED, kind, true);
+ return index < 0 ? 0 : gfc_unsigned_types[index];
}
tree
--- /dev/null
+! { dg-do compile }
+! { dg-options "-funsigned" }
+! Test that overflow warned about.
+program main
+ unsigned(1) :: u
+ u = 256u_1 ! { dg-warning "Unsigned constant truncated" }
+ u = -127u_1
+ u = 255u_1
+ u = -129u_1 ! { dg-warning "Unsigned constant truncated" }
+end