https://gcc.gnu.org/g:ba7b5a42302b6ac7b13c527307feaa5937569d0c

commit ba7b5a42302b6ac7b13c527307feaa5937569d0c
Author: JoanVC <github-9...@joanvc.cat>
Date:   Tue Sep 10 21:52:50 2024 +0200

    [#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-9...@joanvc.cat>

Diff:
---
 gcc/rust/backend/rust-compile-expr.cc    | 67 +++++++++++++++++++++++++++++---
 gcc/rust/hir/tree/rust-hir-expr.h        |  9 +++++
 gcc/testsuite/rust/compile/issue-3141.rs | 62 +++++++++++++++++++++++++++++
 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 51a5fd4cb3cc..f6b9dfd67c57 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 da91f3645619..56cb7d8b6e4a 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 000000000000..3e9bb125b56f
--- /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
+}

Reply via email to