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).