https://gcc.gnu.org/g:ecc21e255dabd1c5ac0d898ace94caa60cc3def0
commit r17-4110-gecc21e255dabd1c5ac0d898ace94caa60cc3def0 Author: Enes Cevik <[email protected]> Date: Mon Jul 20 16:50:11 2026 +0300 gccrs: typecheck: Add ADT to ADT unsize coercion support This patch adds basic support for ADT to ADT unsized coercions. It also refactors the main coerce_unsized function into smaller helper functions for better readability and maintainability. gcc/rust/ChangeLog: * backend/rust-compile-base.h (resolve_adjustments): Fix typo. (resolve_unsized_adt_adjustment): New declaration. * backend/rust-compile-expr.cc (CompileExpr::visit): Fix typo. (HIRCompileBase::resolve_unsized_adt_adjustment): New function. (HIRCompileBase::resolve_unsized_adjustment): Use it. (CompileExpr::generate_possible_fn_trait_call): Likewise. (HIRCompileBase::coercion_site): Fix typo. * typecheck/rust-coercion.cc (TypeCoercionRules::coerce_unsized): Use helper functions. (TypeCoercionRules::unwrap_ptrs_and_refs): New function. (TypeCoercionRules::coerce_unsized_array_to_slice): Likewise. (TypeCoercionRules::coerce_unsized_dyn): Likewise. (TypeCoercionRules::coerce_unsized_adt): Liksewise. (TypeCoercionRules::apply_reborrow_adjustment): Likewise. * typecheck/rust-coercion.h (struct CoercionSetup): New struct. (coerce_unsized): Add is_inner parameter. (unwrap_ptrs_and_refs): New declaration. (coerce_unsized_array_to_slice): Likewise. (coerce_unsized_dyn): Likewise. (coerce_unsized_adt): Likewise. * util/rust-lang-item.cc (Rust::LangItem::lang_items): Add coerce_unsized to the BiMap. * util/rust-lang-item.h (class LangItem): Add COERCE_UNSIZED to the Kind enum. gcc/testsuite/ChangeLog: * rust/compile/coercion2.rs: New test. Signed-off-by: Enes Cevik <[email protected]> Diff: --- gcc/rust/backend/rust-compile-base.h | 7 +- gcc/rust/backend/rust-compile-expr.cc | 116 +++++++++++++- gcc/rust/typecheck/rust-coercion.cc | 258 ++++++++++++++++++++++---------- gcc/rust/typecheck/rust-coercion.h | 25 +++- gcc/rust/util/rust-lang-item.cc | 1 + gcc/rust/util/rust-lang-item.h | 3 + gcc/testsuite/rust/compile/coercion2.rs | 47 ++++++ 7 files changed, 372 insertions(+), 85 deletions(-) diff --git a/gcc/rust/backend/rust-compile-base.h b/gcc/rust/backend/rust-compile-base.h index d93cc3ba3dfe..15356942d853 100644 --- a/gcc/rust/backend/rust-compile-base.h +++ b/gcc/rust/backend/rust-compile-base.h @@ -76,8 +76,8 @@ protected: const Analysis::NodeMapping &mappings, location_t expr_locus, bool is_qualified_path); - tree resolve_adjustements (std::vector<Resolver::Adjustment> &adjustments, - tree expression, location_t locus); + tree resolve_adjustments (std::vector<Resolver::Adjustment> &adjustments, + tree expression, location_t locus); tree resolve_deref_adjustment (Resolver::Adjustment &adjustment, tree expression, location_t locus); @@ -91,6 +91,9 @@ protected: tree resolve_unsized_slice_adjustment (Resolver::Adjustment &adjustment, tree expression, location_t locus); + tree resolve_unsized_adt_adjustment (Resolver::Adjustment &adjustment, + tree expression, location_t locus); + tree resolve_unsized_dyn_adjustment (Resolver::Adjustment &adjustment, tree expression, location_t locus); diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index 9eac66e8bcc6..574099672b51 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -504,7 +504,7 @@ CompileExpr::visit (HIR::TypeCastExpr &expr) if (ok) { casted_expr - = resolve_adjustements (*adjustments, casted_expr, expr.get_locus ()); + = resolve_adjustments (*adjustments, casted_expr, expr.get_locus ()); } translated @@ -1761,8 +1761,8 @@ CompileExpr::visit (HIR::MethodCallExpr &expr) rust_assert (ok); // apply adjustments for the fn call - self = resolve_adjustements (*adjustments, self, - expr.get_receiver ().get_locus ()); + self = resolve_adjustments (*adjustments, self, + expr.get_receiver ().get_locus ()); std::vector<tree> args; args.push_back (self); // adjusted self @@ -1895,7 +1895,7 @@ CompileExpr::resolve_operator_overload ( rust_assert (ok); // apply adjustments for the fn call - tree self = resolve_adjustements (*adjustments, lhs, lhs_expr.get_locus ()); + tree self = resolve_adjustments (*adjustments, lhs, lhs_expr.get_locus ()); std::vector<tree> args; args.push_back (self); // adjusted self @@ -2398,7 +2398,7 @@ CompileExpr::array_copied_expr (location_t expr_locus, } tree -HIRCompileBase::resolve_adjustements ( +HIRCompileBase::resolve_adjustments ( std::vector<Resolver::Adjustment> &adjustments, tree expression, location_t locus) { @@ -2492,6 +2492,8 @@ HIRCompileBase::resolve_unsized_adjustment (Resolver::Adjustment &adjustment, = adjustment.get_expected ()->get_kind () == TyTy::TypeKind::SLICE; bool expect_dyn = adjustment.get_expected ()->get_kind () == TyTy::TypeKind::DYNAMIC; + bool expect_adt + = adjustment.get_expected ()->get_kind () == TyTy::TypeKind::ADT; // assumes this is an array tree expr_type = TREE_TYPE (expression); @@ -2501,6 +2503,9 @@ HIRCompileBase::resolve_unsized_adjustment (Resolver::Adjustment &adjustment, return resolve_unsized_slice_adjustment (adjustment, expression, locus); } + if (expect_adt) + return resolve_unsized_adt_adjustment (adjustment, expression, locus); + rust_assert (expect_dyn); return resolve_unsized_dyn_adjustment (adjustment, expression, locus); } @@ -2537,6 +2542,105 @@ HIRCompileBase::resolve_unsized_slice_adjustment ( locus); } +tree +HIRCompileBase::resolve_unsized_adt_adjustment ( + Resolver::Adjustment &adjustment, tree expression, location_t locus) +{ + /* + * FIXME: This method is implemented as a temporary workaround to enable the + * compilation of intra-ADT conversions for the `coerce_unsized` lang item. + * Currently, it generates incorrect GIMPLE, though it allows the compilation + * to succeed. Execution tests relying on this will exhibit undefined behavior + * at runtime. This must be revisited and properly refactored once the DST + * memory layout is fully supported. + */ + + auto source_adt + = static_cast<const TyTy::ADTType *> (adjustment.get_actual ()); + auto target_adt + = static_cast<const TyTy::ADTType *> (adjustment.get_expected ()); + + auto s_variant = source_adt->get_variants ().front (); + auto t_variant = target_adt->get_variants ().front (); + + std::vector<tree> constructor_elements; + + for (size_t i = 0; i < s_variant->num_fields (); i++) + { + auto s_field_ty = s_variant->get_field_at_index (i) + ->get_field_type () + ->monomorphized_clone (); + auto t_field_ty = t_variant->get_field_at_index (i) + ->get_field_type () + ->monomorphized_clone (); + + tree field_expr = Backend::struct_field_expression (expression, i, locus); + if (s_field_ty->is_equal (*t_field_ty)) + constructor_elements.push_back (field_expr); + else + { + bool is_ptr = s_field_ty->get_kind () == TyTy::TypeKind::POINTER; + bool is_ref = s_field_ty->get_kind () == TyTy::TypeKind::REF; + + if (is_ptr || is_ref) + { + TyTy::BaseType *s_base = nullptr; + TyTy::BaseType *t_base = nullptr; + Resolver::Adjustment::AdjustmentType ref_adj_type + = Resolver::Adjustment::AdjustmentType::IMM_REF; + + if (is_ptr) + { + auto s_ptr + = static_cast<const TyTy::PointerType *> (s_field_ty); + auto t_ptr + = static_cast<const TyTy::PointerType *> (t_field_ty); + s_base = s_ptr->get_base (); + t_base = t_ptr->get_base (); + if (t_ptr->mutability () == Mutability::Mut) + ref_adj_type + = Resolver::Adjustment::AdjustmentType::MUT_REF; + } + else + { + auto s_ref + = static_cast<const TyTy::ReferenceType *> (s_field_ty); + auto t_ref + = static_cast<const TyTy::ReferenceType *> (t_field_ty); + s_base = s_ref->get_base (); + t_base = t_ref->get_base (); + if (t_ref->mutability () == Mutability::Mut) + ref_adj_type + = Resolver::Adjustment::AdjustmentType::MUT_REF; + } + std::vector<Resolver::Adjustment> inner_adjs; + inner_adjs.push_back (Resolver::Adjustment ( + Resolver::Adjustment::AdjustmentType::INDIRECTION, s_field_ty, + s_base)); + inner_adjs.push_back (Resolver::Adjustment ( + Resolver::Adjustment::AdjustmentType::UNSIZE, s_base, t_base)); + inner_adjs.push_back ( + Resolver::Adjustment (ref_adj_type, t_base, t_field_ty)); + + tree coerced_ptr + = resolve_adjustments (inner_adjs, field_expr, locus); + constructor_elements.push_back (coerced_ptr); + } + else + { + Resolver::Adjustment inner_adj (adjustment.get_type (), + s_field_ty, t_field_ty); + tree unsized_inner_expr + = resolve_unsized_adjustment (inner_adj, field_expr, locus); + constructor_elements.push_back (unsized_inner_expr); + } + } + } + tree target_type_tree = TyTyResolveCompile::compile (ctx, target_adt); + return Backend::constructor_expression (target_type_tree, false, + constructor_elements, -1, locus); +} + tree HIRCompileBase::resolve_unsized_dyn_adjustment ( Resolver::Adjustment &adjustment, tree expression, location_t locus) @@ -2987,7 +3091,7 @@ CompileExpr::generate_possible_fn_trait_call (HIR::CallExpr &expr, rust_assert (ok); // apply adjustments for the fn call - tree self = resolve_adjustements (*adjustments, receiver, expr.get_locus ()); + tree self = resolve_adjustments (*adjustments, receiver, expr.get_locus ()); // resolve the arguments std::vector<tree> tuple_arg_vals; diff --git a/gcc/rust/typecheck/rust-coercion.cc b/gcc/rust/typecheck/rust-coercion.cc index a423449badf8..fab689c24203 100644 --- a/gcc/rust/typecheck/rust-coercion.cc +++ b/gcc/rust/typecheck/rust-coercion.cc @@ -316,17 +316,80 @@ TypeCoercionRules::coerce_borrowed_pointer (TyTy::BaseType *receiver, tl::expected<TypeCoercionRules::CoercionResult, TypeCoercionRules::CoerceUnsizedError> TypeCoercionRules::coerce_unsized (TyTy::BaseType *source, - TyTy::BaseType *target) + TyTy::BaseType *target, bool is_inner) { rust_debug ("coerce_unsized(source={%s}, target={%s})", source->debug_str ().c_str (), target->debug_str ().c_str ()); + size_t adjustments_size = adjustments.size (); + auto setup = unwrap_ptrs_and_refs (source, target); + if (!setup) + return tl::unexpected<CoerceUnsizedError> (setup.error ()); + + // FIXME + // there is a bunch of code to ensure something is coerce able to a dyn + // trait we need to support but we need to support a few more lang items for + // that see: + // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs#L582 + + auto a = setup->ty_a; + auto b = setup->ty_b; + + tl::expected<TyTy::BaseType *, CoerceUnsizedError> inner_result + = tl::unexpected (CoerceUnsizedError::Regular); + + bool expect_dyn = b->get_kind () == TyTy::TypeKind::DYNAMIC; + bool need_unsize = a->get_kind () != TyTy::TypeKind::DYNAMIC; + + bool expect_slice = b->get_kind () == TyTy::TypeKind::SLICE; + bool is_array = a->get_kind () == TyTy::TypeKind::ARRAY; + + bool expect_adt = b->get_kind () == TyTy::TypeKind::ADT; + bool is_adt = a->get_kind () == TyTy::TypeKind::ADT; + + if (expect_dyn && need_unsize) + inner_result + = (!setup->unwrapped_pointer && !is_inner) + ? tl::unexpected<CoerceUnsizedError> (inner_result.error ()) + : coerce_unsized_dyn (a, b); + + else if (expect_slice && is_array) + inner_result + = (!setup->unwrapped_pointer && !is_inner) + ? tl::unexpected<CoerceUnsizedError> (inner_result.error ()) + : coerce_unsized_array_to_slice (a, b); + + else if (expect_adt && is_adt) + inner_result = coerce_unsized_adt (a, b, setup->needs_reborrow); + + if (!inner_result) + { + adjustments.erase (adjustments.begin () + adjustments_size, + adjustments.end ()); + return tl::unexpected<CoerceUnsizedError> (inner_result.error ()); + } + + TyTy::BaseType *result = inner_result.value (); + + if (setup->needs_reborrow) + result = apply_reborrow_adjustment (source, target, result, + setup->expected_mutability); + + return CoercionResult{adjustments, result}; +} + +tl::expected<TypeCoercionRules::CoercionSetup, + TypeCoercionRules::CoerceUnsizedError> +TypeCoercionRules::unwrap_ptrs_and_refs (TyTy::BaseType *source, + TyTy::BaseType *target) +{ bool source_is_ref = source->get_kind () == TyTy::TypeKind::REF; bool source_is_ptr = source->get_kind () == TyTy::TypeKind::POINTER; bool target_is_ref = target->get_kind () == TyTy::TypeKind::REF; bool target_is_ptr = target->get_kind () == TyTy::TypeKind::POINTER; bool needs_reborrow = false; + bool unwrapped_pointer = false; TyTy::BaseType *ty_a = source; TyTy::BaseType *ty_b = target; Mutability expected_mutability = Mutability::Imm; @@ -351,6 +414,7 @@ TypeCoercionRules::coerce_unsized (TyTy::BaseType *source, ty_a = source_ref->get_base (); ty_b = target_ref->get_base (); needs_reborrow = true; + unwrapped_pointer = true; expected_mutability = to_mutbl; adjustments.emplace_back (Adjustment::AdjustmentType::INDIRECTION, @@ -376,6 +440,7 @@ TypeCoercionRules::coerce_unsized (TyTy::BaseType *source, ty_a = source_ref->get_base (); ty_b = target_ref->get_base (); needs_reborrow = true; + unwrapped_pointer = true; expected_mutability = to_mutbl; adjustments.emplace_back (Adjustment::AdjustmentType::INDIRECTION, @@ -400,104 +465,145 @@ TypeCoercionRules::coerce_unsized (TyTy::BaseType *source, ty_a = source_ref->get_base (); ty_b = target_ref->get_base (); needs_reborrow = true; + unwrapped_pointer = true; expected_mutability = to_mutbl; adjustments.emplace_back (Adjustment::AdjustmentType::INDIRECTION, source_ref, ty_a); } - // FIXME - // there is a bunch of code to ensure something is coerce able to a dyn trait - // we need to support but we need to support a few more lang items for that - // see: - // https://github.com/rust-lang/rust/blob/7eac88abb2e57e752f3302f02be5f3ce3d7adfb4/compiler/rustc_typeck/src/check/coercion.rs#L582 + return CoercionSetup{ty_a, ty_b, needs_reborrow, expected_mutability, + unwrapped_pointer}; +} + +tl::expected<TyTy::BaseType *, TypeCoercionRules::CoerceUnsizedError> +TypeCoercionRules::coerce_unsized_array_to_slice (TyTy::BaseType *a, + TyTy::BaseType *b) +{ + auto array_type = static_cast<const TyTy::ArrayType *> (a); + auto slice_type = static_cast<const TyTy::SliceType *> (b); - const auto a = ty_a; - const auto b = ty_b; + TyTy::BaseType *array_element = array_type->get_element_type (); + TyTy::BaseType *slice_element = slice_type->get_element_type (); - bool expect_dyn = b->get_kind () == TyTy::TypeKind::DYNAMIC; - bool need_unsize = a->get_kind () != TyTy::TypeKind::DYNAMIC; + if (!array_element->is_equal (*slice_element)) + return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular); - bool expect_slice = b->get_kind () == TyTy::TypeKind::SLICE; - bool is_array = a->get_kind () == TyTy::TypeKind::ARRAY; + TyTy::BaseType *result = b->clone (); - if (expect_dyn && need_unsize) - { - bool bounds_compatible = b->bounds_compatible (*a, locus, false); - if (!bounds_compatible) - return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Unsafe); + adjustments.emplace_back (Adjustment::UNSIZE, a, result); + + return result; +} +tl::expected<TyTy::BaseType *, TypeCoercionRules::CoerceUnsizedError> +TypeCoercionRules::coerce_unsized_dyn (TyTy::BaseType *a, TyTy::BaseType *b) +{ + bool bounds_compatible = b->bounds_compatible (*a, locus, false); + if (!bounds_compatible) + return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Unsafe); + + // return the unsize coercion + TyTy::BaseType *result = b->clone (); + // result->set_ref (a->get_ref ()); + + // append a dyn coercion adjustment + adjustments.emplace_back (Adjustment::UNSIZE, a, result); + + return result; +} +tl::expected<TyTy::BaseType *, TypeCoercionRules::CoerceUnsizedError> +TypeCoercionRules::coerce_unsized_adt (TyTy::BaseType *a, TyTy::BaseType *b, + bool needs_reborrow) +{ + auto source_adt = static_cast<const TyTy::ADTType *> (a); + auto target_adt = static_cast<const TyTy::ADTType *> (b); + + if ((!source_adt->is_struct_struct () && !source_adt->is_tuple_struct ()) + || (!target_adt->is_struct_struct () && !target_adt->is_tuple_struct ()) + || (source_adt->get_id () != target_adt->get_id ()) + || (source_adt->get_variants ().front ()->num_fields () + != target_adt->get_variants ().front ()->num_fields ())) + return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular); - // return the unsize coercion - TyTy::BaseType *result = b->clone (); - // result->set_ref (a->get_ref ()); + auto source_variant = source_adt->get_variants ().front (); + auto target_variant = target_adt->get_variants ().front (); - // append a dyn coercion adjustment - adjustments.emplace_back (Adjustment::UNSIZE, a, result); + TyTy::BaseType *differing_source_field = nullptr; + TyTy::BaseType *differing_target_field = nullptr; + size_t diff_count = 0; + bool is_last_field = false; - // reborrow if needed - if (needs_reborrow) + for (size_t i = 0; i < source_variant->num_fields (); i++) + { + auto s_field_raw + = source_variant->get_field_at_index (i)->get_field_type (); + auto t_field_raw + = target_variant->get_field_at_index (i)->get_field_type (); + auto s_field = s_field_raw->contains_infer () + ? s_field_raw + : s_field_raw->monomorphized_clone (); + auto t_field = t_field_raw->contains_infer () + ? t_field_raw + : t_field_raw->monomorphized_clone (); + + if (s_field->is_zero_sized () && t_field->is_zero_sized ()) + continue; + + if (!s_field->is_equal (*t_field)) { - TyTy::ReferenceType *reborrow - = new TyTy::ReferenceType (source->get_ref (), - TyTy::TyVar (result->get_ref ()), - expected_mutability); - - Adjustment::AdjustmentType borrow_type - = expected_mutability == Mutability::Imm ? Adjustment::IMM_REF - : Adjustment::MUT_REF; - adjustments.emplace_back (borrow_type, result, reborrow); - result = reborrow; + differing_source_field = s_field; + differing_target_field = t_field; + diff_count++; + is_last_field = (i == source_variant->num_fields () - 1); } - return CoercionResult{adjustments, result}; } - else if (expect_slice && is_array) - { - auto array_type = static_cast<const TyTy::ArrayType *> (a); - auto slice_type = static_cast<const TyTy::SliceType *> (b); - TyTy::BaseType *array_element = array_type->get_element_type (); - TyTy::BaseType *slice_element = slice_type->get_element_type (); + if (diff_count != 1) + return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular); - if (!array_element->is_equal (*slice_element)) - { - adjustments.clear (); - return tl::unexpected<CoerceUnsizedError> ( - CoerceUnsizedError::Regular); - } - TyTy::BaseType *result = b->clone (); + if (needs_reborrow && !is_last_field) + return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular); - adjustments.emplace_back (Adjustment::UNSIZE, a, result); + auto adjustments_size = adjustments.size (); + auto inner_coercion + = coerce_unsized (differing_source_field, differing_target_field, true); + if (!inner_coercion) + return tl::unexpected<CoerceUnsizedError> (inner_coercion.error ()); + adjustments.erase (adjustments.begin () + adjustments_size, + adjustments.end ()); - if (needs_reborrow) - { - TyTy::BaseType *reborrow = nullptr; - if (target->get_kind () == TyTy::TypeKind::POINTER) - { - reborrow - = new TyTy::PointerType (source->get_ref (), - TyTy::TyVar (result->get_ref ()), - expected_mutability); - } - else - { - reborrow - = new TyTy::ReferenceType (source->get_ref (), - TyTy::TyVar (result->get_ref ()), - expected_mutability); - } - - Adjustment::AdjustmentType borrow_type - = expected_mutability == Mutability::Imm ? Adjustment::IMM_REF - : Adjustment::MUT_REF; - adjustments.emplace_back (borrow_type, result, reborrow); - result = reborrow; - } + TyTy::BaseType *result = b->clone (); + adjustments.emplace_back (Adjustment::UNSIZE, a, result); - return CoercionResult{adjustments, result}; + return result; +} +TyTy::BaseType * +TypeCoercionRules::apply_reborrow_adjustment (TyTy::BaseType *source, + TyTy::BaseType *target, + TyTy::BaseType *result, + Mutability expected_mutability) +{ + TyTy::BaseType *reborrow = nullptr; + + if (target->get_kind () == TyTy::TypeKind::POINTER) + { + reborrow = new TyTy::PointerType (source->get_ref (), + TyTy::TyVar (result->get_ref ()), + expected_mutability); } + else + { + reborrow = new TyTy::ReferenceType (source->get_ref (), + TyTy::TyVar (result->get_ref ()), + expected_mutability); + } + + Adjustment::AdjustmentType borrow_type + = expected_mutability == Mutability::Imm ? Adjustment::IMM_REF + : Adjustment::MUT_REF; - adjustments.clear (); - return tl::unexpected<CoerceUnsizedError> (CoerceUnsizedError::Regular); + adjustments.emplace_back (borrow_type, result, reborrow); + return reborrow; } bool diff --git a/gcc/rust/typecheck/rust-coercion.h b/gcc/rust/typecheck/rust-coercion.h index d52f61051501..0674cf5df568 100644 --- a/gcc/rust/typecheck/rust-coercion.h +++ b/gcc/rust/typecheck/rust-coercion.h @@ -68,7 +68,8 @@ public: Mutability mutability); tl::expected<CoercionResult, CoerceUnsizedError> - coerce_unsized (TyTy::BaseType *receiver, TyTy::BaseType *expected); + coerce_unsized (TyTy::BaseType *receiver, TyTy::BaseType *expected, + bool is_inner = false); static bool coerceable_mutability (Mutability from_mutbl, Mutability to_mutbl); @@ -87,6 +88,28 @@ protected: bool do_coercion (TyTy::BaseType *receiver); + struct CoercionSetup + { + TyTy::BaseType *ty_a; + TyTy::BaseType *ty_b; + bool needs_reborrow; + Mutability expected_mutability; + bool unwrapped_pointer; + }; + tl::expected<CoercionSetup, CoerceUnsizedError> + unwrap_ptrs_and_refs (TyTy::BaseType *source, TyTy::BaseType *target); + tl::expected<TyTy::BaseType *, CoerceUnsizedError> + coerce_unsized_array_to_slice (TyTy::BaseType *a, TyTy::BaseType *b); + tl::expected<TyTy::BaseType *, CoerceUnsizedError> + coerce_unsized_dyn (TyTy::BaseType *a, TyTy::BaseType *b); + tl::expected<TyTy::BaseType *, CoerceUnsizedError> + coerce_unsized_adt (TyTy::BaseType *a, TyTy::BaseType *b, + bool needs_reborrow); + TyTy::BaseType *apply_reborrow_adjustment (TyTy::BaseType *source, + TyTy::BaseType *target, + TyTy::BaseType *result, + Mutability expected_mutability); + private: // context info Analysis::Mappings &mappings; diff --git a/gcc/rust/util/rust-lang-item.cc b/gcc/rust/util/rust-lang-item.cc index a54b2e594609..3be15a805fcc 100644 --- a/gcc/rust/util/rust-lang-item.cc +++ b/gcc/rust/util/rust-lang-item.cc @@ -56,6 +56,7 @@ const BiMap<std::string, LangItem::Kind> Rust::LangItem::lang_items = {{ {"RangeInclusive", Kind::RANGE_INCLUSIVE}, {"RangeToInclusive", Kind::RANGE_TO_INCLUSIVE}, {"range_inclusive_new", Kind::RANGE_INCLUSIVE_NEW}, + {"coerce_unsized", Kind::COERCE_UNSIZED}, {"phantom_data", Kind::PHANTOM_DATA}, {"fn", Kind::FN}, {"fn_mut", Kind::FN_MUT}, diff --git a/gcc/rust/util/rust-lang-item.h b/gcc/rust/util/rust-lang-item.h index 476752367b91..8cadfd0c227e 100644 --- a/gcc/rust/util/rust-lang-item.h +++ b/gcc/rust/util/rust-lang-item.h @@ -79,6 +79,9 @@ public: RANGE_TO_INCLUSIVE, RANGE_INCLUSIVE_NEW, + // https://github.com/rust-lang/rust/blob/master/library/core/src/ops/unsize.rs + COERCE_UNSIZED, + // https://github.com/rust-lang/rust/blob/master/library/core/src/marker.rs PHANTOM_DATA, diff --git a/gcc/testsuite/rust/compile/coercion2.rs b/gcc/testsuite/rust/compile/coercion2.rs new file mode 100644 index 000000000000..d852f3f0439f --- /dev/null +++ b/gcc/testsuite/rust/compile/coercion2.rs @@ -0,0 +1,47 @@ +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} + +#[lang = "phantom_data"] +pub struct PhantomData<T: ?Sized>; + +#[lang = "coerce_unsized"] +pub trait CoerceUnsized<T: ?Sized> { + // This lang item is not used for now. +} + +pub struct NonNull<T: ?Sized> { + _ptr: *const T, +} + +pub struct Unique<T: ?Sized> { + _pointer: NonNull<T>, + _marker: PhantomData<T>, +} + +pub struct MyBox<T: ?Sized> { + _inner: Unique<T>, +} + +pub struct TailStruct<T: ?Sized> { + _header: usize, + _data: T, +} + +pub fn test_nested_coercions() { + let tail: TailStruct<[i32; 3]> = TailStruct { _header: 1, _data: [1, 2, 3] }; + let tail_ptr: *const TailStruct<[i32; 3]> = &tail; + + let non_null = NonNull::<TailStruct<[i32; 3]>> { _ptr: tail_ptr }; + + let unique = Unique::<TailStruct<[i32; 3]>> { + _pointer: non_null, + _marker: PhantomData::<TailStruct<[i32; 3]>> + }; + + let my_box = MyBox::<TailStruct<[i32; 3]>> { _inner: unique }; + + let _my_box_slice: MyBox<TailStruct<[i32]>> = my_box; +}
