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 (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 @@ class LiteralExpr : public ExprWithoutBlock 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 +}