From: Philip Herron <herron.phi...@googlemail.com>

This case:

    let i = 1;
    let j = i as i64;

'i' is meant to default to i32 but the inference was making both of these
i64 because the code was prefering coercion logic which can end up with a
default unify which causes the ?integer to unify with i64 making them both
i64.

But all we need to do is allow the simple cast rules to run first then
fallback to coercions but special consideration has to be made to ensure
that if there are dyn objects needed then this needs a unsize coercion, but
also we need to ensure the underlying types are a valid simple cast too
otherwise these also need to fallback to the coercion code.

Fixes Rust-GCC#2680

gcc/rust/ChangeLog:

        * typecheck/rust-casts.cc (TypeCastRules::resolve): optional emit_error 
flag
        (TypeCastRules::check): try the simple cast rules then fallback to 
coercions
        (TypeCastRules::check_ptr_ptr_cast): ensure the underlying's
        (TypeCastRules::emit_cast_error): make this a static helper
        * typecheck/rust-casts.h: new emit_error prototype

gcc/testsuite/ChangeLog:

        * rust/compile/issue-2680.rs: New test.

Signed-off-by: Philip Herron <herron.phi...@googlemail.com>
---
 gcc/rust/typecheck/rust-casts.cc         | 45 ++++++++++++++++++------
 gcc/rust/typecheck/rust-casts.h          | 10 +++---
 gcc/testsuite/rust/compile/issue-2680.rs |  6 ++++
 3 files changed, 46 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/rust/compile/issue-2680.rs

diff --git a/gcc/rust/typecheck/rust-casts.cc b/gcc/rust/typecheck/rust-casts.cc
index d0a9f5dca01..f06d9ed24e8 100644
--- a/gcc/rust/typecheck/rust-casts.cc
+++ b/gcc/rust/typecheck/rust-casts.cc
@@ -17,6 +17,7 @@
 // <http://www.gnu.org/licenses/>.
 
 #include "rust-casts.h"
+#include "rust-tyty-util.h"
 
 namespace Rust {
 namespace Resolver {
@@ -28,15 +29,20 @@ TypeCastRules::TypeCastRules (location_t locus, 
TyTy::TyWithLocation from,
 
 TypeCoercionRules::CoercionResult
 TypeCastRules::resolve (location_t locus, TyTy::TyWithLocation from,
-                       TyTy::TyWithLocation to)
+                       TyTy::TyWithLocation to, bool emit_error)
 {
   TypeCastRules cast_rules (locus, from, to);
-  return cast_rules.check ();
+  return cast_rules.check (emit_error);
 }
 
 TypeCoercionRules::CoercionResult
-TypeCastRules::check ()
+TypeCastRules::check (bool emit_error)
 {
+  // try the simple cast rules
+  auto simple_cast = cast_rules ();
+  if (!simple_cast.is_error ())
+    return simple_cast;
+
   // 
https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L565-L582
   auto possible_coercion
     = TypeCoercionRules::TryCoerce (from.get_ty (), to.get_ty (), locus,
@@ -51,13 +57,9 @@ TypeCastRules::check ()
                                        true /*is_cast_site*/);
     }
 
-  // try the simple cast rules
-  auto simple_cast = cast_rules ();
-  if (!simple_cast.is_error ())
-    return simple_cast;
+  if (emit_error)
+    TypeCastRules::emit_cast_error (locus, from, to);
 
-  // failed to cast
-  emit_cast_error ();
   return TypeCoercionRules::CoercionResult::get_error ();
 }
 
@@ -329,7 +331,27 @@ TypeCastRules::check_ptr_ptr_cast ()
     }
   else if (from_is_ref && to_is_ref)
     {
-      // mutability must be coercedable
+      const auto &from_ref = *from.get_ty ()->as<TyTy::ReferenceType> ();
+      const auto &to_ref = *to.get_ty ()->as<TyTy::ReferenceType> ();
+
+      if (from_ref.is_dyn_object () != to_ref.is_dyn_object ())
+       {
+         // this needs to be handled by coercion logic
+         return TypeCoercionRules::CoercionResult::get_error ();
+       }
+
+      // are the underlying types safely simple castable?
+      const auto to_underly = to_ref.get_base ();
+      const auto from_underly = from_ref.get_base ();
+      auto res = resolve (locus, TyTy::TyWithLocation (from_underly),
+                         TyTy::TyWithLocation (to_underly), false);
+      if (res.is_error ())
+       {
+         // this needs to be handled by coercion logic
+         return TypeCoercionRules::CoercionResult::get_error ();
+       }
+
+      // mutability must be coerceable
       TyTy::ReferenceType &f
        = static_cast<TyTy::ReferenceType &> (*from.get_ty ());
       TyTy::ReferenceType &t
@@ -346,7 +368,8 @@ TypeCastRules::check_ptr_ptr_cast ()
 }
 
 void
-TypeCastRules::emit_cast_error () const
+TypeCastRules::emit_cast_error (location_t locus, TyTy::TyWithLocation from,
+                               TyTy::TyWithLocation to)
 {
   rich_location r (line_table, locus);
   r.add_range (from.get_locus ());
diff --git a/gcc/rust/typecheck/rust-casts.h b/gcc/rust/typecheck/rust-casts.h
index 0d6ed689e42..10bb006f037 100644
--- a/gcc/rust/typecheck/rust-casts.h
+++ b/gcc/rust/typecheck/rust-casts.h
@@ -30,15 +30,17 @@ class TypeCastRules
 public:
   static TypeCoercionRules::CoercionResult resolve (location_t locus,
                                                    TyTy::TyWithLocation from,
-                                                   TyTy::TyWithLocation to);
+                                                   TyTy::TyWithLocation to,
+                                                   bool emit_error = true);
+
+  static void emit_cast_error (location_t locus, TyTy::TyWithLocation from,
+                              TyTy::TyWithLocation to);
 
 protected:
-  TypeCoercionRules::CoercionResult check ();
+  TypeCoercionRules::CoercionResult check (bool emit_error);
   TypeCoercionRules::CoercionResult cast_rules ();
   TypeCoercionRules::CoercionResult check_ptr_ptr_cast ();
 
-  void emit_cast_error () const;
-
 protected:
   TypeCastRules (location_t locus, TyTy::TyWithLocation from,
                 TyTy::TyWithLocation to);
diff --git a/gcc/testsuite/rust/compile/issue-2680.rs 
b/gcc/testsuite/rust/compile/issue-2680.rs
new file mode 100644
index 00000000000..d5ae2ff4450
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-2680.rs
@@ -0,0 +1,6 @@
+// { dg-additional-options "-fdump-tree-gimple" }
+pub fn test_cast() {
+    let i = 1;
+    // { dg-final { scan-tree-dump-times {const i32 i;} 1 gimple } }
+    let _j = i as i64;
+}
-- 
2.49.0

Reply via email to