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; +}