Skip to content

Commit 8f23ec6

Browse files
committed
gccrs: Fix cast rules logic to try simple casts then fall back to coercions
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 #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 <[email protected]>
1 parent 3c708c5 commit 8f23ec6

File tree

3 files changed

+46
-15
lines changed

3 files changed

+46
-15
lines changed

gcc/rust/typecheck/rust-casts.cc

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// <http://www.gnu.org/licenses/>.
1818

1919
#include "rust-casts.h"
20+
#include "rust-tyty-util.h"
2021

2122
namespace Rust {
2223
namespace Resolver {
@@ -28,15 +29,20 @@ TypeCastRules::TypeCastRules (location_t locus, TyTy::TyWithLocation from,
2829

2930
TypeCoercionRules::CoercionResult
3031
TypeCastRules::resolve (location_t locus, TyTy::TyWithLocation from,
31-
TyTy::TyWithLocation to)
32+
TyTy::TyWithLocation to, bool emit_error)
3233
{
3334
TypeCastRules cast_rules (locus, from, to);
34-
return cast_rules.check ();
35+
return cast_rules.check (emit_error);
3536
}
3637

3738
TypeCoercionRules::CoercionResult
38-
TypeCastRules::check ()
39+
TypeCastRules::check (bool emit_error)
3940
{
41+
// try the simple cast rules
42+
auto simple_cast = cast_rules ();
43+
if (!simple_cast.is_error ())
44+
return simple_cast;
45+
4046
// https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/cast.rs#L565-L582
4147
auto possible_coercion
4248
= TypeCoercionRules::TryCoerce (from.get_ty (), to.get_ty (), locus,
@@ -51,13 +57,9 @@ TypeCastRules::check ()
5157
true /*is_cast_site*/);
5258
}
5359

54-
// try the simple cast rules
55-
auto simple_cast = cast_rules ();
56-
if (!simple_cast.is_error ())
57-
return simple_cast;
60+
if (emit_error)
61+
TypeCastRules::emit_cast_error (locus, from, to);
5862

59-
// failed to cast
60-
emit_cast_error ();
6163
return TypeCoercionRules::CoercionResult::get_error ();
6264
}
6365

@@ -329,7 +331,27 @@ TypeCastRules::check_ptr_ptr_cast ()
329331
}
330332
else if (from_is_ref && to_is_ref)
331333
{
332-
// mutability must be coercedable
334+
const auto &from_ref = *from.get_ty ()->as<TyTy::ReferenceType> ();
335+
const auto &to_ref = *to.get_ty ()->as<TyTy::ReferenceType> ();
336+
337+
if (from_ref.is_dyn_object () != to_ref.is_dyn_object ())
338+
{
339+
// this needs to be handled by coercion logic
340+
return TypeCoercionRules::CoercionResult::get_error ();
341+
}
342+
343+
// are the underlying types safely simple castable?
344+
const auto to_underly = to_ref.get_base ();
345+
const auto from_underly = from_ref.get_base ();
346+
auto res = resolve (locus, TyTy::TyWithLocation (from_underly),
347+
TyTy::TyWithLocation (to_underly), false);
348+
if (res.is_error ())
349+
{
350+
// this needs to be handled by coercion logic
351+
return TypeCoercionRules::CoercionResult::get_error ();
352+
}
353+
354+
// mutability must be coerceable
333355
TyTy::ReferenceType &f
334356
= static_cast<TyTy::ReferenceType &> (*from.get_ty ());
335357
TyTy::ReferenceType &t
@@ -346,7 +368,8 @@ TypeCastRules::check_ptr_ptr_cast ()
346368
}
347369

348370
void
349-
TypeCastRules::emit_cast_error () const
371+
TypeCastRules::emit_cast_error (location_t locus, TyTy::TyWithLocation from,
372+
TyTy::TyWithLocation to)
350373
{
351374
rich_location r (line_table, locus);
352375
r.add_range (from.get_locus ());

gcc/rust/typecheck/rust-casts.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,17 @@ class TypeCastRules
3030
public:
3131
static TypeCoercionRules::CoercionResult resolve (location_t locus,
3232
TyTy::TyWithLocation from,
33-
TyTy::TyWithLocation to);
33+
TyTy::TyWithLocation to,
34+
bool emit_error = true);
35+
36+
static void emit_cast_error (location_t locus, TyTy::TyWithLocation from,
37+
TyTy::TyWithLocation to);
3438

3539
protected:
36-
TypeCoercionRules::CoercionResult check ();
40+
TypeCoercionRules::CoercionResult check (bool emit_error);
3741
TypeCoercionRules::CoercionResult cast_rules ();
3842
TypeCoercionRules::CoercionResult check_ptr_ptr_cast ();
3943

40-
void emit_cast_error () const;
41-
4244
protected:
4345
TypeCastRules (location_t locus, TyTy::TyWithLocation from,
4446
TyTy::TyWithLocation to);
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// { dg-additional-options "-fdump-tree-gimple" }
2+
pub fn test_cast() {
3+
let i = 1;
4+
// { dg-final { scan-tree-dump-times {const i32 i;} 1 gimple } }
5+
let _j = i as i64;
6+
}

0 commit comments

Comments
 (0)