From c9600aa54d7412f5bbff97be2046c8054e201c3c Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Mon, 8 May 2023 14:10:57 +0100 Subject: gccrs: unify how we handle DST's DST's are not truely reference types they are "unsized types" so the exact size of them is not known at compile time. We actually achieve this by pretending they are a reference but really its struct we pass around. Fixes #2180 gcc/rust/ChangeLog: * backend/rust-compile-expr.cc (CompileExpr::visit): refactr (CompileExpr::get_fn_addr_from_dyn): likewise (CompileExpr::get_receiver_from_dyn): likewise (CompileExpr::type_cast_expression): likewise * backend/rust-compile-type.cc (TyTyResolveCompile::visit): likewise (TyTyResolveCompile::create_dyn_obj_record): likewise (TyTyResolveCompile::create_slice_type_record): likewise (TyTyResolveCompile::create_str_type_record): likewise * backend/rust-compile-type.h: likewise * backend/rust-compile.cc (HIRCompileBase::coercion_site1): likewise (HIRCompileBase::coerce_to_dyn_object): refactor * backend/rust-tree.h (SLICE_FLAG): removed (SLICE_TYPE_P): removed (RS_DST_FLAG): new flag (RS_DST_FLAG_P): new predicate * typecheck/rust-tyty.cc (ReferenceType::is_dyn_object): new helper (ReferenceType::is_dyn_obj_type): likewise (PointerType::is_dyn_object): likewise (PointerType::is_dyn_obj_type): likewise * typecheck/rust-tyty.h (class DynamicObjectType): moved up gcc/testsuite/ChangeLog: * rust/execute/torture/issue-2180.rs: New test. Signed-off-by: Philip Herron --- gcc/rust/backend/rust-compile-expr.cc | 27 ++++------- gcc/rust/backend/rust-compile-type.cc | 47 ++++++++++++++++-- gcc/rust/backend/rust-compile-type.h | 1 + gcc/rust/backend/rust-compile.cc | 14 ++++-- gcc/rust/backend/rust-tree.h | 4 +- gcc/rust/typecheck/rust-tyty.cc | 30 +++++++++++- gcc/rust/typecheck/rust-tyty.h | 62 ++++++++++++------------ gcc/testsuite/rust/execute/torture/issue-2180.rs | 34 +++++++++++++ 8 files changed, 157 insertions(+), 62 deletions(-) create mode 100644 gcc/testsuite/rust/execute/torture/issue-2180.rs (limited to 'gcc') diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index 07e5d79..59afc01 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -29,6 +29,7 @@ #include "fold-const.h" #include "realmpfr.h" #include "convert.h" +#include "print-tree.h" namespace Rust { namespace Compile { @@ -791,7 +792,7 @@ void CompileExpr::visit (HIR::BorrowExpr &expr) { tree main_expr = CompileExpr::Compile (expr.get_expr ().get (), ctx); - if (SLICE_TYPE_P (TREE_TYPE (main_expr))) + if (RS_DST_FLAG_P (TREE_TYPE (main_expr))) { translated = main_expr; return; @@ -836,7 +837,7 @@ CompileExpr::visit (HIR::DereferenceExpr &expr) } tree expected_type = TyTyResolveCompile::compile (ctx, tyty); - if (SLICE_TYPE_P (TREE_TYPE (main_expr)) && SLICE_TYPE_P (expected_type)) + if (RS_DST_FLAG_P (TREE_TYPE (main_expr)) && RS_DST_FLAG_P (expected_type)) { translated = main_expr; return; @@ -908,6 +909,10 @@ CompileExpr::visit (HIR::AssignmentExpr &expr) expected, expr.get_lhs ()->get_locus (), expr.get_rhs ()->get_locus ()); + // rust_debug_loc (expr.get_locus (), "XXXXXX assignment"); + // debug_tree (rvalue); + // debug_tree (lvalue); + tree assignment = ctx->get_backend ()->assignment_statement (lvalue, rvalue, expr.get_locus ()); @@ -1810,13 +1815,6 @@ CompileExpr::get_fn_addr_from_dyn (const TyTy::DynamicObjectType *dyn, if (ref == nullptr) return error_mark_node; - // get any indirection sorted out - if (receiver->get_kind () == TyTy::TypeKind::REF) - { - tree indirect = indirect_expression (receiver_ref, expr_locus); - receiver_ref = indirect; - } - // cast it to the correct fntype tree expected_fntype = TyTyResolveCompile::compile (ctx, fntype, true); tree idx = build_int_cst (size_type_node, offs); @@ -1841,13 +1839,6 @@ CompileExpr::get_receiver_from_dyn (const TyTy::DynamicObjectType *dyn, TyTy::FnType *fntype, tree receiver_ref, Location expr_locus) { - // get any indirection sorted out - if (receiver->get_kind () == TyTy::TypeKind::REF) - { - tree indirect = indirect_expression (receiver_ref, expr_locus); - receiver_ref = indirect; - } - // access the offs + 1 for the fnptr and offs=0 for the reciever obj return ctx->get_backend ()->struct_field_expression (receiver_ref, 0, expr_locus); @@ -2130,7 +2121,7 @@ CompileExpr::type_cast_expression (tree type_to_cast_to, tree expr_tree, type_to_cast_to, expr_tree); } else if (TREE_CODE (type_to_cast_to) == POINTER_TYPE - && SLICE_TYPE_P (TREE_TYPE (expr_tree))) + && RS_DST_FLAG (TREE_TYPE (expr_tree))) { // returning a raw cast using NOP_EXPR seems to resut in an ICE: // @@ -2327,7 +2318,7 @@ HIRCompileBase::resolve_adjustements ( case Resolver::Adjustment::AdjustmentType::IMM_REF: case Resolver::Adjustment::AdjustmentType::MUT_REF: { - if (!SLICE_TYPE_P (TREE_TYPE (e))) + if (!RS_DST_FLAG (TREE_TYPE (e))) { e = address_expression (e, locus); } diff --git a/gcc/rust/backend/rust-compile-type.cc b/gcc/rust/backend/rust-compile-type.cc index 29f7cca..76b38c5 100644 --- a/gcc/rust/backend/rust-compile-type.cc +++ b/gcc/rust/backend/rust-compile-type.cc @@ -576,6 +576,7 @@ TyTyResolveCompile::visit (const TyTy::ReferenceType &type) { const TyTy::SliceType *slice = nullptr; const TyTy::StrType *str = nullptr; + const TyTy::DynamicObjectType *dyn = nullptr; if (type.is_dyn_slice_type (&slice)) { tree type_record = create_slice_type_record (*slice); @@ -601,6 +602,18 @@ TyTyResolveCompile::visit (const TyTy::ReferenceType &type) return; } + else if (type.is_dyn_obj_type (&dyn)) + { + tree type_record = create_dyn_obj_record (*dyn); + std::string dyn_str_type_str + = std::string (type.is_mutable () ? "&mut " : "& ") + dyn->get_name (); + + translated + = ctx->get_backend ()->named_type (dyn_str_type_str, type_record, + dyn->get_locus ()); + + return; + } tree base_compiled_type = TyTyResolveCompile::compile (ctx, type.get_base (), trait_object_mode); @@ -620,6 +633,7 @@ TyTyResolveCompile::visit (const TyTy::PointerType &type) { const TyTy::SliceType *slice = nullptr; const TyTy::StrType *str = nullptr; + const TyTy::DynamicObjectType *dyn = nullptr; if (type.is_dyn_slice_type (&slice)) { tree type_record = create_slice_type_record (*slice); @@ -645,6 +659,19 @@ TyTyResolveCompile::visit (const TyTy::PointerType &type) return; } + else if (type.is_dyn_obj_type (&dyn)) + { + tree type_record = create_dyn_obj_record (*dyn); + std::string dyn_str_type_str + = std::string (type.is_mutable () ? "*mut " : "*const ") + + dyn->get_name (); + + translated + = ctx->get_backend ()->named_type (dyn_str_type_str, type_record, + dyn->get_locus ()); + + return; + } tree base_compiled_type = TyTyResolveCompile::compile (ctx, type.get_base (), trait_object_mode); @@ -684,6 +711,14 @@ TyTyResolveCompile::visit (const TyTy::DynamicObjectType &type) return; } + tree type_record = create_dyn_obj_record (type); + translated = ctx->get_backend ()->named_type (type.get_name (), type_record, + type.get_ident ().locus); +} + +tree +TyTyResolveCompile::create_dyn_obj_record (const TyTy::DynamicObjectType &type) +{ // create implicit struct auto items = type.get_object_items (); std::vector fields; @@ -704,9 +739,11 @@ TyTyResolveCompile::visit (const TyTy::DynamicObjectType &type) type.get_ty_ref ())); fields.push_back (std::move (vtf)); - tree type_record = ctx->get_backend ()->struct_type (fields); - translated = ctx->get_backend ()->named_type (type.get_name (), type_record, - type.get_ident ().locus); + tree record = ctx->get_backend ()->struct_type (fields); + RS_DST_FLAG (record) = 1; + TYPE_MAIN_VARIANT (record) = ctx->insert_main_variant (record); + + return record; } tree @@ -727,7 +764,7 @@ TyTyResolveCompile::create_slice_type_record (const TyTy::SliceType &type) Backend::typed_identifier len_field ("len", len_field_ty, type.get_locus ()); tree record = ctx->get_backend ()->struct_type ({data_field, len_field}); - SLICE_FLAG (record) = 1; + RS_DST_FLAG (record) = 1; TYPE_MAIN_VARIANT (record) = ctx->insert_main_variant (record); return record; @@ -753,7 +790,7 @@ TyTyResolveCompile::create_str_type_record (const TyTy::StrType &type) Backend::typed_identifier len_field ("len", len_field_ty, type.get_locus ()); tree record = ctx->get_backend ()->struct_type ({data_field, len_field}); - SLICE_FLAG (record) = 1; + RS_DST_FLAG (record) = 1; TYPE_MAIN_VARIANT (record) = ctx->insert_main_variant (record); return record; diff --git a/gcc/rust/backend/rust-compile-type.h b/gcc/rust/backend/rust-compile-type.h index ce13795..44bd218 100644 --- a/gcc/rust/backend/rust-compile-type.h +++ b/gcc/rust/backend/rust-compile-type.h @@ -65,6 +65,7 @@ public: protected: tree create_slice_type_record (const TyTy::SliceType &type); tree create_str_type_record (const TyTy::StrType &type); + tree create_dyn_obj_record (const TyTy::DynamicObjectType &type); private: TyTyResolveCompile (Context *ctx, bool trait_object_mode); diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc index ea7cc15..a5d6abb 100644 --- a/gcc/rust/backend/rust-compile.cc +++ b/gcc/rust/backend/rust-compile.cc @@ -78,7 +78,7 @@ HIRCompileBase::coercion_site1 (tree rvalue, TyTy::BaseType *rval, if (expected->get_kind () == TyTy::TypeKind::REF) { // this is a dyn object - if (SLICE_TYPE_P (TREE_TYPE (rvalue))) + if (RS_DST_FLAG_P (TREE_TYPE (rvalue))) { return rvalue; } @@ -96,7 +96,7 @@ HIRCompileBase::coercion_site1 (tree rvalue, TyTy::BaseType *rval, tree coerced = coercion_site1 (deref_rvalue, act->get_base (), exp->get_base (), lvalue_locus, rvalue_locus); - if (exp->is_dyn_object () && SLICE_TYPE_P (TREE_TYPE (coerced))) + if (exp->is_dyn_object () && RS_DST_FLAG_P (TREE_TYPE (coerced))) return coerced; return address_expression (coerced, rvalue_locus); @@ -104,7 +104,7 @@ HIRCompileBase::coercion_site1 (tree rvalue, TyTy::BaseType *rval, else if (expected->get_kind () == TyTy::TypeKind::POINTER) { // this is a dyn object - if (SLICE_TYPE_P (TREE_TYPE (rvalue))) + if (RS_DST_FLAG_P (TREE_TYPE (rvalue))) { return rvalue; } @@ -140,7 +140,7 @@ HIRCompileBase::coercion_site1 (tree rvalue, TyTy::BaseType *rval, = coercion_site1 (deref_rvalue, actual_base, exp->get_base (), lvalue_locus, rvalue_locus); - if (exp->is_dyn_object () && SLICE_TYPE_P (TREE_TYPE (coerced))) + if (exp->is_dyn_object () && RS_DST_FLAG_P (TREE_TYPE (coerced))) return coerced; return address_expression (coerced, rvalue_locus); @@ -183,7 +183,11 @@ HIRCompileBase::coerce_to_dyn_object (tree compiled_ref, const TyTy::DynamicObjectType *ty, Location locus) { - tree dynamic_object = TyTyResolveCompile::compile (ctx, ty); + // DST's get wrapped in a pseudo reference that doesnt exist... + const TyTy::ReferenceType r (ctx->get_mappings ()->get_next_hir_id (), + TyTy::TyVar (ty->get_ref ()), Mutability::Imm); + + tree dynamic_object = TyTyResolveCompile::compile (ctx, &r); tree dynamic_object_fields = TYPE_FIELDS (dynamic_object); tree vtable_field = DECL_CHAIN (dynamic_object_fields); rust_assert (TREE_CODE (TREE_TYPE (vtable_field)) == ARRAY_TYPE); diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h index 1f0e12f..b4c058f 100644 --- a/gcc/rust/backend/rust-tree.h +++ b/gcc/rust/backend/rust-tree.h @@ -78,8 +78,8 @@ // this is a helper to differentiate RECORD types between actual records and // slices -#define SLICE_FLAG TREE_LANG_FLAG_0 -#define SLICE_TYPE_P(TYPE) \ +#define RS_DST_FLAG TREE_LANG_FLAG_0 +#define RS_DST_FLAG_P(TYPE) \ (TREE_CODE (TYPE) == RECORD_TYPE && TREE_LANG_FLAG_0 (TYPE)) // lambda? diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc index 1c67318..5e9af52 100644 --- a/gcc/rust/typecheck/rust-tyty.cc +++ b/gcc/rust/typecheck/rust-tyty.cc @@ -2961,7 +2961,7 @@ ReferenceType::is_mutable () const bool ReferenceType::is_dyn_object () const { - return is_dyn_slice_type () || is_dyn_str_type (); + return is_dyn_slice_type () || is_dyn_str_type () || is_dyn_obj_type (); } bool @@ -2990,6 +2990,19 @@ ReferenceType::is_dyn_str_type (const TyTy::StrType **str) const return true; } +bool +ReferenceType::is_dyn_obj_type (const TyTy::DynamicObjectType **dyn) const +{ + const TyTy::BaseType *element = get_base ()->destructure (); + if (element->get_kind () != TyTy::TypeKind::DYNAMIC) + return false; + if (dyn == nullptr) + return true; + + *dyn = static_cast (element); + return true; +} + void ReferenceType::accept_vis (TyVisitor &vis) { @@ -3112,7 +3125,7 @@ PointerType::is_const () const bool PointerType::is_dyn_object () const { - return is_dyn_slice_type () || is_dyn_str_type (); + return is_dyn_slice_type () || is_dyn_str_type () || is_dyn_obj_type (); } bool @@ -3141,6 +3154,19 @@ PointerType::is_dyn_str_type (const TyTy::StrType **str) const return true; } +bool +PointerType::is_dyn_obj_type (const TyTy::DynamicObjectType **dyn) const +{ + const TyTy::BaseType *element = get_base ()->destructure (); + if (element->get_kind () != TyTy::TypeKind::DYNAMIC) + return false; + if (dyn == nullptr) + return true; + + *dyn = static_cast (element); + return true; +} + void PointerType::accept_vis (TyVisitor &vis) { diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index cd6be34..a6a373a 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -1147,6 +1147,36 @@ public: BaseType *clone () const final override; }; +class DynamicObjectType : public BaseType +{ +public: + DynamicObjectType (HirId ref, RustIdent ident, + std::vector specified_bounds, + std::set refs = std::set ()); + + DynamicObjectType (HirId ref, HirId ty_ref, RustIdent ident, + std::vector specified_bounds, + std::set refs = std::set ()); + + void accept_vis (TyVisitor &vis) override; + void accept_vis (TyConstVisitor &vis) const override; + + std::string as_string () const override; + + bool can_eq (const BaseType *other, bool emit_errors) const override final; + + bool is_equal (const BaseType &other) const override; + + BaseType *clone () const final override; + + std::string get_name () const override final; + + // this returns a flat list of items including super trait bounds + const std::vector< + std::pair> + get_object_items () const; +}; + class ReferenceType : public BaseType { public: @@ -1179,6 +1209,7 @@ public: bool is_dyn_object () const; bool is_dyn_slice_type (const TyTy::SliceType **slice = nullptr) const; bool is_dyn_str_type (const TyTy::StrType **str = nullptr) const; + bool is_dyn_obj_type (const TyTy::DynamicObjectType **dyn = nullptr) const; private: TyVar base; @@ -1216,6 +1247,7 @@ public: bool is_dyn_object () const; bool is_dyn_slice_type (const TyTy::SliceType **slice = nullptr) const; bool is_dyn_str_type (const TyTy::StrType **str = nullptr) const; + bool is_dyn_obj_type (const TyTy::DynamicObjectType **dyn = nullptr) const; private: TyVar base; @@ -1328,36 +1360,6 @@ private: DefId item; }; -class DynamicObjectType : public BaseType -{ -public: - DynamicObjectType (HirId ref, RustIdent ident, - std::vector specified_bounds, - std::set refs = std::set ()); - - DynamicObjectType (HirId ref, HirId ty_ref, RustIdent ident, - std::vector specified_bounds, - std::set refs = std::set ()); - - void accept_vis (TyVisitor &vis) override; - void accept_vis (TyConstVisitor &vis) const override; - - std::string as_string () const override; - - bool can_eq (const BaseType *other, bool emit_errors) const override final; - - bool is_equal (const BaseType &other) const override; - - BaseType *clone () const final override; - - std::string get_name () const override final; - - // this returns a flat list of items including super trait bounds - const std::vector< - std::pair> - get_object_items () const; -}; - } // namespace TyTy } // namespace Rust diff --git a/gcc/testsuite/rust/execute/torture/issue-2180.rs b/gcc/testsuite/rust/execute/torture/issue-2180.rs new file mode 100644 index 0000000..3a7ea10 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/issue-2180.rs @@ -0,0 +1,34 @@ +// { dg-output "123\n" } +trait A { + fn get_int(&self) -> i32; +} + +impl A for i32 { + fn get_int(&self) -> i32 { + *self + } +} + +fn get_dyn_a(x: &i32) -> &dyn A { + x as &dyn A +} + +fn clobber_stack() { + let _z: [usize; 8] = [1, 2, 3, 4, 5, 6, 7, 8]; +} + +extern "C" { + fn printf(s: *const i8, ...) -> i32; +} + +fn main() -> i32 { + let x = 123; + let y = get_dyn_a(&x); + clobber_stack(); + let value = y.get_int(); + let fmt_string = "%d\n\0" as *const str as *const i8; + unsafe { + printf(fmt_string, value); + } + return 0; +} -- cgit v1.1