diff --git a/gcc/rust/typecheck/rust-casts.cc b/gcc/rust/typecheck/rust-casts.cc
index d0a9f5dca015..f06d9ed24e8e 100644
--- a/gcc/rust/typecheck/rust-casts.cc
+++ b/gcc/rust/typecheck/rust-casts.cc
@@ -17,6 +17,7 @@
// .
#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 ();
+ const auto &to_ref = *to.get_ty ()->as ();
+
+ 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 (*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 0d6ed689e420..10bb006f0376 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 000000000000..d5ae2ff4450b
--- /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;
+}