public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] Str's have the same layout as [T]
@ 2022-06-08 12:50 Thomas Schwinge
  0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2022-06-08 12:50 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:4cfd6942c07021db05beae40e1128901e37109e6

commit 4cfd6942c07021db05beae40e1128901e37109e6
Author: Philip Herron <philip.herron@embecosm.com>
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<const TyTy::ReferenceType *> (expected);
       const TyTy::ReferenceType *act
 	= static_cast<const TyTy::ReferenceType *> (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<const TyTy::ReferenceType *> (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<const TyTy::PointerType *> (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<const TyTy::ReferenceType *> (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<HirId> refs = std::set<HirId> ())
+    : BaseType (ref, ref, TypeKind::STR,
+		{Resolver::CanonicalPath::create_empty (),
+		 Linemap::predeclared_location ()},
+		refs)
+  {}
+
+  StrType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ())
+    : 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<const TyTy::SliceType *> (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<const TyTy::StrType *> (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<const TyTy::SliceType *> (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<const TyTy::StrType *> (element);
+    return true;
+  }
+
 private:
   TyVar base;
   Mutability mut;
 };
 
-class StrType : public BaseType
-{
-public:
-  StrType (HirId ref, std::set<HirId> refs = std::set<HirId> ())
-    : BaseType (ref, ref, TypeKind::STR,
-		{Resolver::CanonicalPath::create_empty (),
-		 Linemap::predeclared_location ()},
-		refs)
-  {}
-
-  StrType (HirId ref, HirId ty_ref, std::set<HirId> refs = std::set<HirId> ())
-    : 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>(_: T) -> U;
+    }
+}
+
+extern "C" {
+    fn printf(s: *const i8, ...);
+}
+
+struct FatPtr<T> {
+    data: *const T,
+    len: usize,
+}
+
+pub union Repr<T> {
+    rust: *const [T],
+    rust_mut: *mut [T],
+    raw: FatPtr<T>,
+}
+
+impl<T> [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
+}


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-06-08 12:50 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-06-08 12:50 [gcc/devel/rust/master] Str's have the same layout as [T] Thomas Schwinge

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).