From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1643) id 97EDA388B5A5; Wed, 8 Jun 2022 12:50:14 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 97EDA388B5A5 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Thomas Schwinge To: gcc-cvs@gcc.gnu.org Subject: [gcc/devel/rust/master] Str's have the same layout as [T] X-Act-Checkin: gcc X-Git-Author: Philip Herron X-Git-Refname: refs/heads/devel/rust/master X-Git-Oldrev: 79d977e759b073a0a4d422b9a1032427ddc05295 X-Git-Newrev: 4cfd6942c07021db05beae40e1128901e37109e6 Message-Id: <20220608125014.97EDA388B5A5@sourceware.org> Date: Wed, 8 Jun 2022 12:50:14 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 08 Jun 2022 12:50:14 -0000 https://gcc.gnu.org/g:4cfd6942c07021db05beae40e1128901e37109e6 commit 4cfd6942c07021db05beae40e1128901e37109e6 Author: Philip Herron Date: Wed May 25 11:48:54 2022 +0100 Str's have the same layout as [T] Raw strings have a very specific type layout which maps over to Slices. It also has very specific type checking rules so for example: let a:&str = "TEST 1"; let b:&str = &"TEST 2"; Are both the same type this is likely to be for all DST's but lets do one rule at a time. Fixes #1023 #1271 Diff: --- gcc/rust/backend/rust-compile-expr.cc | 19 +++- gcc/rust/backend/rust-compile-type.cc | 54 ++++++++++- gcc/rust/backend/rust-compile-type.h | 1 + gcc/rust/backend/rust-compile.cc | 31 +++--- gcc/rust/typecheck/rust-hir-type-check-expr.h | 20 ++++ gcc/rust/typecheck/rust-tycheck-dump.h | 8 ++ gcc/rust/typecheck/rust-tyty.h | 112 ++++++++++++++-------- gcc/testsuite/rust/compile/issue-1023.rs | 4 + gcc/testsuite/rust/compile/issue-1271.rs | 5 + gcc/testsuite/rust/compile/xfail/slice1.rs | 5 - gcc/testsuite/rust/execute/torture/str-layout1.rs | 56 +++++++++++ 11 files changed, 249 insertions(+), 66 deletions(-) diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc index b176ed2cf36..4168bb8806b 100644 --- a/gcc/rust/backend/rust-compile-expr.cc +++ b/gcc/rust/backend/rust-compile-expr.cc @@ -1014,13 +1014,28 @@ tree CompileExpr::compile_string_literal (const HIR::LiteralExpr &expr, const TyTy::BaseType *tyty) { + tree fat_pointer = TyTyResolveCompile::compile (ctx, tyty); + rust_assert (expr.get_lit_type () == HIR::Literal::STRING); const auto literal_value = expr.get_literal (); auto base = ctx->get_backend ()->string_constant_expression ( literal_value.as_string ()); - return address_expression (base, build_pointer_type (TREE_TYPE (base)), - expr.get_locus ()); + tree data = address_expression (base, build_pointer_type (TREE_TYPE (base)), + expr.get_locus ()); + + TyTy::BaseType *usize = nullptr; + bool ok = ctx->get_tyctx ()->lookup_builtin ("usize", &usize); + rust_assert (ok); + tree type = TyTyResolveCompile::compile (ctx, usize); + + mpz_t ival; + mpz_init_set_ui (ival, literal_value.as_string ().size ()); + tree size = double_int_to_tree (type, mpz_get_double_int (type, ival, true)); + + return ctx->get_backend ()->constructor_expression (fat_pointer, false, + {data, size}, -1, + expr.get_locus ()); } tree diff --git a/gcc/rust/backend/rust-compile-type.cc b/gcc/rust/backend/rust-compile-type.cc index 707b2afcbe3..6068e0d81fd 100644 --- a/gcc/rust/backend/rust-compile-type.cc +++ b/gcc/rust/backend/rust-compile-type.cc @@ -525,6 +525,7 @@ void TyTyResolveCompile::visit (const TyTy::ReferenceType &type) { const TyTy::SliceType *slice = nullptr; + const TyTy::StrType *str = nullptr; if (type.is_dyn_slice_type (&slice)) { tree type_record = create_slice_type_record (*slice); @@ -538,6 +539,18 @@ TyTyResolveCompile::visit (const TyTy::ReferenceType &type) return; } + else if (type.is_dyn_str_type (&str)) + { + tree type_record = create_str_type_record (*str); + std::string dyn_str_type_str + = std::string (type.is_mutable () ? "&mut " : "&") + "str"; + + translated + = ctx->get_backend ()->named_type (dyn_str_type_str, type_record, + str->get_locus ()); + + return; + } tree base_compiled_type = TyTyResolveCompile::compile (ctx, type.get_base (), trait_object_mode); @@ -556,6 +569,7 @@ void TyTyResolveCompile::visit (const TyTy::PointerType &type) { const TyTy::SliceType *slice = nullptr; + const TyTy::StrType *str = nullptr; if (type.is_dyn_slice_type (&slice)) { tree type_record = create_slice_type_record (*slice); @@ -569,6 +583,18 @@ TyTyResolveCompile::visit (const TyTy::PointerType &type) return; } + else if (type.is_dyn_str_type (&str)) + { + tree type_record = create_str_type_record (*str); + std::string dyn_str_type_str + = std::string (type.is_mutable () ? "*mut " : "*const ") + "str"; + + translated + = ctx->get_backend ()->named_type (dyn_str_type_str, type_record, + str->get_locus ()); + + return; + } tree base_compiled_type = TyTyResolveCompile::compile (ctx, type.get_base (), trait_object_mode); @@ -586,7 +612,7 @@ TyTyResolveCompile::visit (const TyTy::PointerType &type) void TyTyResolveCompile::visit (const TyTy::StrType &type) { - tree raw_str = ctx->get_backend ()->raw_str_type (); + tree raw_str = create_str_type_record (type); translated = ctx->get_backend ()->named_type ("str", raw_str, Linemap::predeclared_location ()); @@ -657,5 +683,31 @@ TyTyResolveCompile::create_slice_type_record (const TyTy::SliceType &type) return record; } +tree +TyTyResolveCompile::create_str_type_record (const TyTy::StrType &type) +{ + // lookup usize + TyTy::BaseType *usize = nullptr; + bool ok = ctx->get_tyctx ()->lookup_builtin ("usize", &usize); + rust_assert (ok); + + tree char_ptr = build_pointer_type (char_type_node); + tree const_char_type = build_qualified_type (char_ptr, TYPE_QUAL_CONST); + + tree element_type = const_char_type; + tree data_field_ty = build_pointer_type (element_type); + Backend::typed_identifier data_field ("data", data_field_ty, + type.get_locus ()); + + tree len_field_ty = TyTyResolveCompile::compile (ctx, usize); + 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; + TYPE_MAIN_VARIANT (record) = ctx->insert_main_variant (record); + + return record; +} + } // namespace Compile } // namespace Rust diff --git a/gcc/rust/backend/rust-compile-type.h b/gcc/rust/backend/rust-compile-type.h index aefacea5e60..c9b6b621046 100644 --- a/gcc/rust/backend/rust-compile-type.h +++ b/gcc/rust/backend/rust-compile-type.h @@ -62,6 +62,7 @@ public: protected: tree create_slice_type_record (const TyTy::SliceType &type); + tree create_str_type_record (const TyTy::StrType &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 18a2df6b97a..9bcd01c814c 100644 --- a/gcc/rust/backend/rust-compile.cc +++ b/gcc/rust/backend/rust-compile.cc @@ -210,6 +210,12 @@ HIRCompileBase::coercion_site (tree rvalue, const TyTy::BaseType *rval, if (expected->get_kind () == TyTy::TypeKind::REF) { + // this is a dyn object + if (SLICE_TYPE_P (TREE_TYPE (rvalue))) + { + return rvalue; + } + // bad coercion... of something to a reference if (actual->get_kind () != TyTy::TypeKind::REF) return error_mark_node; @@ -218,11 +224,6 @@ HIRCompileBase::coercion_site (tree rvalue, const TyTy::BaseType *rval, = static_cast (expected); const TyTy::ReferenceType *act = static_cast (actual); - if (act->is_dyn_slice_type ()) - { - // nothing to do - return rvalue; - } tree expected_type = TyTyResolveCompile::compile (ctx, act->get_base ()); tree deref_rvalue @@ -232,7 +233,7 @@ HIRCompileBase::coercion_site (tree rvalue, const TyTy::BaseType *rval, tree coerced = coercion_site (deref_rvalue, act->get_base (), exp->get_base (), lvalue_locus, rvalue_locus); - if (exp->is_dyn_slice_type () && SLICE_TYPE_P (TREE_TYPE (coerced))) + if (exp->is_dyn_object () && SLICE_TYPE_P (TREE_TYPE (coerced))) return coerced; return address_expression (coerced, @@ -241,6 +242,12 @@ HIRCompileBase::coercion_site (tree rvalue, const TyTy::BaseType *rval, } else if (expected->get_kind () == TyTy::TypeKind::POINTER) { + // this is a dyn object + if (SLICE_TYPE_P (TREE_TYPE (rvalue))) + { + return rvalue; + } + // bad coercion... of something to a reference bool valid_coercion = actual->get_kind () == TyTy::TypeKind::REF || actual->get_kind () == TyTy::TypeKind::POINTER; @@ -256,11 +263,6 @@ HIRCompileBase::coercion_site (tree rvalue, const TyTy::BaseType *rval, { const TyTy::ReferenceType *act = static_cast (actual); - if (act->is_dyn_slice_type ()) - { - // nothing to do - return rvalue; - } actual_base = act->get_base (); expected_type = TyTyResolveCompile::compile (ctx, act->get_base ()); @@ -269,11 +271,6 @@ HIRCompileBase::coercion_site (tree rvalue, const TyTy::BaseType *rval, { const TyTy::PointerType *act = static_cast (actual); - if (act->is_dyn_slice_type ()) - { - // nothing to do - return rvalue; - } actual_base = act->get_base (); expected_type = TyTyResolveCompile::compile (ctx, act->get_base ()); @@ -286,6 +283,8 @@ HIRCompileBase::coercion_site (tree rvalue, const TyTy::BaseType *rval, rvalue_locus); tree coerced = coercion_site (deref_rvalue, actual_base, exp->get_base (), lvalue_locus, rvalue_locus); + if (exp->is_dyn_object () && SLICE_TYPE_P (TREE_TYPE (coerced))) + return coerced; return address_expression (coerced, build_pointer_type (TREE_TYPE (coerced)), diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h index 411d45de41f..d895ce43d37 100644 --- a/gcc/rust/typecheck/rust-hir-type-check-expr.h +++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h @@ -974,6 +974,26 @@ public: TyTy::BaseType *resolved_base = TypeCheckExpr::Resolve (expr.get_expr ().get (), false); + // In Rust this is valid because of DST's + // + // fn test() { + // let a:&str = "TEST 1"; + // let b:&str = &"TEST 2"; + // } + if (resolved_base->get_kind () == TyTy::TypeKind::REF) + { + const TyTy::ReferenceType *ref + = static_cast (resolved_base); + + // this might end up being a more generic is_dyn object check but lets + // double check dyn traits type-layout first + if (ref->is_dyn_str_type ()) + { + infered = resolved_base; + return; + } + } + if (expr.get_is_double_borrow ()) { // FIXME double_reference diff --git a/gcc/rust/typecheck/rust-tycheck-dump.h b/gcc/rust/typecheck/rust-tycheck-dump.h index 70f0b11964a..ab7f59a349a 100644 --- a/gcc/rust/typecheck/rust-tycheck-dump.h +++ b/gcc/rust/typecheck/rust-tycheck-dump.h @@ -98,6 +98,7 @@ public: void visit (HIR::BlockExpr &expr) override { + dump += "{\n"; indentation_level++; for (auto &s : expr.get_statements ()) @@ -115,6 +116,13 @@ public: } indentation_level--; + dump += "}\n"; + } + + void visit (HIR::UnsafeBlockExpr &expr) override + { + dump += "unsafe "; + expr.get_block_expr ()->accept_vis (*this); } void visit (HIR::LetStmt &stmt) override diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h index 31d26dc3340..1a44c75aace 100644 --- a/gcc/rust/typecheck/rust-tyty.h +++ b/gcc/rust/typecheck/rust-tyty.h @@ -2126,6 +2126,42 @@ public: bool is_concrete () const override final { return true; } }; +class StrType : public BaseType +{ +public: + StrType (HirId ref, std::set refs = std::set ()) + : BaseType (ref, ref, TypeKind::STR, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs) + {} + + StrType (HirId ref, HirId ty_ref, std::set refs = std::set ()) + : BaseType (ref, ty_ref, TypeKind::STR, + {Resolver::CanonicalPath::create_empty (), + Linemap::predeclared_location ()}, + refs) + {} + + std::string get_name () const override final { return as_string (); } + + void accept_vis (TyVisitor &vis) override; + void accept_vis (TyConstVisitor &vis) const override; + + std::string as_string () const override; + + BaseType *unify (BaseType *other) override; + bool can_eq (const BaseType *other, bool emit_errors) const override final; + BaseType *coerce (BaseType *other) override; + BaseType *cast (BaseType *other) override; + + bool is_equal (const BaseType &other) const override; + + BaseType *clone () const final override; + BaseType *monomorphized_clone () const final override; + bool is_concrete () const override final { return true; } +}; + class ReferenceType : public BaseType { public: @@ -2180,21 +2216,35 @@ public: bool is_mutable () const { return mut == Mutability::Mut; } - bool is_dyn_slice_type () const + bool is_dyn_object () const { - return get_base ()->destructure ()->get_kind () == TyTy::TypeKind::SLICE; + return is_dyn_slice_type () || is_dyn_str_type (); } - bool is_dyn_slice_type (const TyTy::SliceType **slice) const + bool is_dyn_slice_type (const TyTy::SliceType **slice = nullptr) const { const TyTy::BaseType *element = get_base ()->destructure (); if (element->get_kind () != TyTy::TypeKind::SLICE) return false; + if (slice == nullptr) + return true; *slice = static_cast (element); return true; } + bool is_dyn_str_type (const TyTy::StrType **str = nullptr) const + { + const TyTy::BaseType *element = get_base ()->destructure (); + if (element->get_kind () != TyTy::TypeKind::STR) + return false; + if (str == nullptr) + return true; + + *str = static_cast (element); + return true; + } + private: TyVar base; Mutability mut; @@ -2256,62 +2306,40 @@ public: bool is_const () const { return mut == Mutability::Imm; } - bool is_dyn_slice_type () const + bool is_dyn_object () const { - return get_base ()->destructure ()->get_kind () == TyTy::TypeKind::SLICE; + return is_dyn_slice_type () || is_dyn_str_type (); } - bool is_dyn_slice_type (const TyTy::SliceType **slice) const + bool is_dyn_slice_type (const TyTy::SliceType **slice = nullptr) const { const TyTy::BaseType *element = get_base ()->destructure (); if (element->get_kind () != TyTy::TypeKind::SLICE) return false; + if (slice == nullptr) + return true; *slice = static_cast (element); return true; } + bool is_dyn_str_type (const TyTy::StrType **str = nullptr) const + { + const TyTy::BaseType *element = get_base ()->destructure (); + if (element->get_kind () != TyTy::TypeKind::STR) + return false; + if (str == nullptr) + return true; + + *str = static_cast (element); + return true; + } + private: TyVar base; Mutability mut; }; -class StrType : public BaseType -{ -public: - StrType (HirId ref, std::set refs = std::set ()) - : BaseType (ref, ref, TypeKind::STR, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs) - {} - - StrType (HirId ref, HirId ty_ref, std::set refs = std::set ()) - : BaseType (ref, ty_ref, TypeKind::STR, - {Resolver::CanonicalPath::create_empty (), - Linemap::predeclared_location ()}, - refs) - {} - - std::string get_name () const override final { return as_string (); } - - void accept_vis (TyVisitor &vis) override; - void accept_vis (TyConstVisitor &vis) const override; - - std::string as_string () const override; - - BaseType *unify (BaseType *other) override; - bool can_eq (const BaseType *other, bool emit_errors) const override final; - BaseType *coerce (BaseType *other) override; - BaseType *cast (BaseType *other) override; - - bool is_equal (const BaseType &other) const override; - - BaseType *clone () const final override; - BaseType *monomorphized_clone () const final override; - bool is_concrete () const override final { return true; } -}; - // https://doc.rust-lang.org/std/primitive.never.html // // Since the `!` type is really complicated and it is even still unstable diff --git a/gcc/testsuite/rust/compile/issue-1023.rs b/gcc/testsuite/rust/compile/issue-1023.rs new file mode 100644 index 00000000000..5a0fe6cf530 --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1023.rs @@ -0,0 +1,4 @@ +// { dg-additional-options "-w" } +fn foo(e: &str) -> &str { + &"" +} diff --git a/gcc/testsuite/rust/compile/issue-1271.rs b/gcc/testsuite/rust/compile/issue-1271.rs new file mode 100644 index 00000000000..5dd6418de4c --- /dev/null +++ b/gcc/testsuite/rust/compile/issue-1271.rs @@ -0,0 +1,5 @@ +// { dg-additional-options "-w" } +fn test() { + let a: &str = "TEST 1"; + let b: &str = &"TEST 2"; +} diff --git a/gcc/testsuite/rust/compile/xfail/slice1.rs b/gcc/testsuite/rust/compile/xfail/slice1.rs deleted file mode 100644 index 3087d4d0a5f..00000000000 --- a/gcc/testsuite/rust/compile/xfail/slice1.rs +++ /dev/null @@ -1,5 +0,0 @@ -// { dg-additional-options "-w" } - -fn foo(e: &str) -> &str { // { dg-bogus "expected" "#391" { xfail *-*-* } } - &"" // { dg-bogus "expected" "#391" { xfail *-*-* } } -} diff --git a/gcc/testsuite/rust/execute/torture/str-layout1.rs b/gcc/testsuite/rust/execute/torture/str-layout1.rs new file mode 100644 index 00000000000..be89184ed38 --- /dev/null +++ b/gcc/testsuite/rust/execute/torture/str-layout1.rs @@ -0,0 +1,56 @@ +// { dg-additional-options "-w" } +// { dg-output "t1sz=5 t2sz=10" } +mod mem { + extern "rust-intrinsic" { + fn transmute(_: T) -> U; + } +} + +extern "C" { + fn printf(s: *const i8, ...); +} + +struct FatPtr { + data: *const T, + len: usize, +} + +pub union Repr { + rust: *const [T], + rust_mut: *mut [T], + raw: FatPtr, +} + +impl [T] { + pub const fn len(&self) -> usize { + unsafe { Repr { rust: self }.raw.len } + } +} + +impl str { + pub const fn len(&self) -> usize { + self.as_bytes().len() + } + + pub const fn as_bytes(&self) -> &[u8] { + unsafe { mem::transmute(self) } + } +} + +fn main() -> i32 { + let t1: &str = "TEST1"; + let t2: &str = &"TEST_12345"; + + let t1sz = t1.len(); + let t2sz = t2.len(); + + unsafe { + let a = "t1sz=%i t2sz=%i\n"; + let b = a as *const str; + let c = b as *const i8; + + printf(c, t1sz as i32, t2sz as i32); + } + + 0 +}