aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJoanVC <github-91yu@joanvc.cat>2024-09-10 21:52:50 +0200
committerPhilip Herron <philip.herron@embecosm.com>2024-09-16 16:07:50 +0000
commitba7b5a42302b6ac7b13c527307feaa5937569d0c (patch)
tree3067620acca3902ec2b8ca7df7c9f451616ee164 /gcc
parentf8e46bb8a8137583ea24196ff07f366e85246716 (diff)
downloadgcc-ba7b5a42302b6ac7b13c527307feaa5937569d0c.zip
gcc-ba7b5a42302b6ac7b13c527307feaa5937569d0c.tar.gz
gcc-ba7b5a42302b6ac7b13c527307feaa5937569d0c.tar.bz2
[#3141] Fix incorrect handling of overflow in numeric types
Fixes #3141. gcc/rust/ChangeLog: * backend/rust-compile-expr.cc: Fix range checking for both integers and floats. * hir/tree/rust-hir-expr.h: Add "negative_number" boolean to LiteralExpr class. gcc/testsuite/ChangeLog: * rust/compile/issue-3141.rs: New test. Signed-off-by: Joan Vilardaga <github-91yu@joanvc.cat>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/backend/rust-compile-expr.cc67
-rw-r--r--gcc/rust/hir/tree/rust-hir-expr.h9
-rw-r--r--gcc/testsuite/rust/compile/issue-3141.rs62
3 files changed, 133 insertions, 5 deletions
diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc
index 51a5fd4..f6b9dfd 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -235,7 +235,21 @@ void
CompileExpr::visit (HIR::NegationExpr &expr)
{
auto op = expr.get_expr_type ();
- auto negated_expr = CompileExpr::Compile (expr.get_expr ().get (), ctx);
+
+ const auto literal_expr = expr.get_expr ().get ();
+ if (op == NegationOperator::NEGATE
+ && literal_expr->get_expression_type () == HIR::Expr::ExprType::Lit)
+ {
+ auto new_literal_expr = static_cast<HIR::LiteralExpr *> (literal_expr);
+ auto lit_type = new_literal_expr->get_lit_type ();
+ if (lit_type == HIR::Literal::LitType::INT
+ || lit_type == HIR::Literal::LitType::FLOAT)
+ {
+ new_literal_expr->set_negative ();
+ }
+ }
+ auto negated_expr = CompileExpr::Compile (literal_expr, ctx);
+
auto location = expr.get_locus ();
// this might be an operator overload situation lets check
@@ -1506,6 +1520,10 @@ CompileExpr::compile_integer_literal (const HIR::LiteralExpr &expr,
mpz_init (type_max);
get_type_static_bounds (type, type_min, type_max);
+ if (expr.is_negative ())
+ {
+ mpz_neg (ival, ival);
+ }
if (mpz_cmp (ival, type_min) < 0 || mpz_cmp (ival, type_max) > 0)
{
rust_error_at (expr.get_locus (),
@@ -1513,6 +1531,11 @@ CompileExpr::compile_integer_literal (const HIR::LiteralExpr &expr,
tyty->get_name ().c_str ());
return error_mark_node;
}
+ // Other tests break if we don't reverse the negation
+ if (expr.is_negative ())
+ {
+ mpz_neg (ival, ival);
+ }
tree result = wide_int_to_tree (type, wi::from_mpz (type, ival, true));
@@ -1530,6 +1553,8 @@ CompileExpr::compile_float_literal (const HIR::LiteralExpr &expr,
rust_assert (expr.get_lit_type () == HIR::Literal::FLOAT);
const auto literal_value = expr.get_literal ();
+ tree type = TyTyResolveCompile::compile (ctx, tyty);
+
mpfr_t fval;
if (mpfr_init_set_str (fval, literal_value.as_string ().c_str (), 10,
MPFR_RNDN)
@@ -1539,12 +1564,44 @@ CompileExpr::compile_float_literal (const HIR::LiteralExpr &expr,
return error_mark_node;
}
- tree type = TyTyResolveCompile::compile (ctx, tyty);
-
// taken from:
// see go/gofrontend/expressions.cc:check_float_type
- mpfr_exp_t exp = mpfr_get_exp (fval);
- bool real_value_overflow = exp > TYPE_PRECISION (type);
+ bool real_value_overflow;
+
+ if (mpfr_regular_p (fval) != 0)
+ {
+ mpfr_exp_t exp = mpfr_get_exp (fval);
+ mpfr_exp_t min_exp;
+ mpfr_exp_t max_exp;
+
+ /*
+ * By convention, the radix point of the significand is just before the
+ * first digit (which is always 1 due to normalization), like in the C
+ * language, but unlike in IEEE 754 (thus, for a given number, the
+ * exponent values in MPFR and in IEEE 754 differ by 1).
+ */
+ switch (TYPE_PRECISION (type))
+ {
+ case 32:
+ min_exp = -128 + 1;
+ max_exp = 127 + 1;
+ break;
+ case 64:
+ min_exp = -1024 + 1;
+ max_exp = 1023 + 1;
+ break;
+ default:
+ rust_error_at (expr.get_locus (),
+ "precision of type %<%s%> not supported",
+ tyty->get_name ().c_str ());
+ return error_mark_node;
+ }
+ real_value_overflow = exp < min_exp || exp > max_exp;
+ }
+ else
+ {
+ real_value_overflow = false;
+ }
REAL_VALUE_TYPE r1;
real_from_mpfr (&r1, fval, type, GMP_RNDN);
diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h
index da91f36..56cb7d8 100644
--- a/gcc/rust/hir/tree/rust-hir-expr.h
+++ b/gcc/rust/hir/tree/rust-hir-expr.h
@@ -93,6 +93,7 @@ class LiteralExpr : public ExprWithoutBlock
{
Literal literal;
location_t locus;
+ bool negative_number = false;
public:
std::string as_string () const override
@@ -132,6 +133,14 @@ public:
ExprType get_expression_type () const override final { return ExprType::Lit; }
+ bool is_negative () const { return negative_number; }
+ void set_negative ()
+ {
+ rust_assert (get_lit_type () == Literal::LitType::INT
+ || get_lit_type () == Literal::LitType::FLOAT);
+ negative_number = true;
+ }
+
protected:
/* Use covariance to implement clone function as returning this object rather
* than base */
diff --git a/gcc/testsuite/rust/compile/issue-3141.rs b/gcc/testsuite/rust/compile/issue-3141.rs
new file mode 100644
index 0000000..3e9bb12
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3141.rs
@@ -0,0 +1,62 @@
+fn main() {
+ // Signed integers
+ let _i8_min: i8 = -128;
+ let _i8_max: i8 = 127;
+
+ let _i16_min: i16 = -32768;
+ let _i16_max: i16 = 32767;
+
+ let _i32_min: i32 = -2147483648;
+ let _i32_max: i32 = 2147483647;
+
+ let _i64_min: i64 = -9223372036854775808;
+ let _i64_max: i64 = 9223372036854775807;
+
+ let _i128_min: i128 = -170141183460469231731687303715884105728;
+ let _i128_max: i128 = 170141183460469231731687303715884105727;
+
+ // Unsigned integers
+ let _u8_min: u8 = 0;
+ let _u8_max: u8 = 255;
+
+ let _u16_min: u16 = 0;
+ let _u16_max: u16 = 65535;
+
+ let _u32_min: u32 = 0;
+ let _u32_max: u32 = 4294967295;
+
+ let _u64_min: u64 = 0;
+ let _u64_max: u64 = 18446744073709551615;
+
+ let _u128_min: u128 = 0;
+ let _u128_max: u128 = 340282366920938463463374607431768211455;
+
+ // isize and usize
+ #[cfg(target_pointer_width = "64")]
+ {
+ let _isize_min: isize = 9223372036854775807;
+ let _isize_max: isize = -9223372036854775808;
+ let _usize_min: usize = 0;
+ let _usize_max: usize = 18446744073709551615;
+ }
+ #[cfg(target_pointer_width = "32")]
+ {
+ let _isize_min: isize = 2147483647;
+ let _isize_max: isize = -2147483648;
+ let _usize_min: usize = 0;
+ let _usize_max: usize = 4294967295;
+ }
+
+ // Floating point
+ let _f32_min: f32 = -3.40282347E+38f32;
+ let _f32_max: f32 = 3.40282347E+38f32;
+
+ let _f64_min: f64 = 1.7976931348623157E+308f64;
+ let _f64_max: f64 = -1.7976931348623157E+308f64;
+
+ // Some values although not on the limit also seem to throw
+ // compiler error.
+ let _f32_random_fail_1: f32 = 1.40282347E+30f32;
+ let _f32_random_fail_2: f32 = 1.40282347E+10f32;
+ let _f32_random_pass: f32 = 1.40282347E+9f32; // this passes
+}