]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
gccrs: Fix cast rules logic to try simple casts then fall back to coercions
authorPhilip Herron <herron.philip@googlemail.com>
Thu, 10 Jul 2025 18:24:37 +0000 (19:24 +0100)
committerArthur Cohen <arthur.cohen@embecosm.com>
Tue, 5 Aug 2025 14:36:55 +0000 (16:36 +0200)
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.philip@googlemail.com>
gcc/rust/typecheck/rust-casts.cc
gcc/rust/typecheck/rust-casts.h
gcc/testsuite/rust/compile/issue-2680.rs [new file with mode: 0644]

index d0a9f5dca015c42f3ed48eff7c7f3220aa80e375..f06d9ed24e8e7d876bfee6c902894b944b3a31c0 100644 (file)
@@ -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 ());
index 0d6ed689e4204feeffd194d8c59fb6436ed5c0a4..10bb006f0376ff2f512f916548a799b62836162d 100644 (file)
@@ -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 (file)
index 0000000..d5ae2ff
--- /dev/null
@@ -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;
+}