aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-05-23 14:57:55 +0000
committerGitHub <noreply@github.com>2022-05-23 14:57:55 +0000
commitbf6d540b1043bb944450dfe9da4c91124cdf31d3 (patch)
tree6edb9359d5ac9d9b63938019e0fd9b336c1dd43e /gcc
parent63762cc243c643c10aca7e07dfd6abe9b78748f8 (diff)
parentcd39861da5e1113207193bb8b3e6fb3dde92895f (diff)
downloadgcc-bf6d540b1043bb944450dfe9da4c91124cdf31d3.zip
gcc-bf6d540b1043bb944450dfe9da4c91124cdf31d3.tar.gz
gcc-bf6d540b1043bb944450dfe9da4c91124cdf31d3.tar.bz2
Merge #1268
1268: Fix Slice Type Layout r=philberty a=philberty Slices in Rust are represented by TypePaths such as '[i32]'. Though if you actually try to use this explicit type-path you will hit errors such as this type has an unknown size at compile time. This is because this is actually what Rust calls a dynamically sized type. This means when you use types such as: '&[i32]' it is not actually a reference type to a slice. Its a slice in its entirety this means for lack of a better word when you use '*const [i32]' or '&mut [i32]' we end up actually passing around a struct by value _not_ at pointer/reference to it. This patch changes the type-layout so that we handle this layout change properly. This patch will also need to be applied to str types which I believe have a similar layout for safety. The patch also sets up TYPE_MAIN_VARIANT so that we can avoid unnessecary view_convert_expressions between *const [i32] and &mut [i32] which will have the same layout. Reference: https://doc.rust-lang.org/reference/dynamically-sized-types.html https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=672adac002939a2dab43b8d231adc1dc Fixes #1232 Co-authored-by: Philip Herron <philip.herron@embecosm.com>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/backend/rust-compile-context.h12
-rw-r--r--gcc/rust/backend/rust-compile-expr.cc56
-rw-r--r--gcc/rust/backend/rust-compile-type.cc82
-rw-r--r--gcc/rust/backend/rust-compile-type.h8
-rw-r--r--gcc/rust/backend/rust-compile.cc19
-rw-r--r--gcc/rust/backend/rust-tree.h6
-rw-r--r--gcc/rust/typecheck/rust-tyty.h30
-rw-r--r--gcc/testsuite/rust/execute/torture/issue-1232.rs159
8 files changed, 345 insertions, 27 deletions
diff --git a/gcc/rust/backend/rust-compile-context.h b/gcc/rust/backend/rust-compile-context.h
index 8378554..096b65f 100644
--- a/gcc/rust/backend/rust-compile-context.h
+++ b/gcc/rust/backend/rust-compile-context.h
@@ -67,6 +67,17 @@ public:
return type;
}
+ tree insert_main_variant (tree type)
+ {
+ hashval_t h = type_hasher (type);
+ auto it = main_variants.find (h);
+ if (it != main_variants.end ())
+ return it->second;
+
+ main_variants.insert ({h, type});
+ return type;
+ }
+
::Backend *get_backend () { return backend; }
Resolver::Resolver *get_resolver () { return resolver; }
Resolver::TypeCheckContext *get_tyctx () { return tyctx; }
@@ -314,6 +325,7 @@ private:
std::map<DefId, std::vector<std::pair<const TyTy::BaseType *, tree>>>
mono_fns;
std::map<HirId, tree> implicit_pattern_bindings;
+ std::map<hashval_t, tree> main_variants;
// To GCC middle-end
std::vector<tree> type_decls;
diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc
index 824d6d3..b176ed2 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -123,6 +123,11 @@ void
CompileExpr::visit (HIR::BorrowExpr &expr)
{
tree main_expr = CompileExpr::Compile (expr.get_expr ().get (), ctx);
+ if (SLICE_TYPE_P (TREE_TYPE (main_expr)))
+ {
+ translated = main_expr;
+ return;
+ }
TyTy::BaseType *tyty = nullptr;
if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
@@ -164,6 +169,12 @@ 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))
+ {
+ translated = main_expr;
+ return;
+ }
+
bool known_valid = true;
translated
= ctx->get_backend ()->indirect_expression (expected_type, main_expr,
@@ -1092,6 +1103,32 @@ CompileExpr::type_cast_expression (tree type_to_cast_to, tree expr_tree,
return fold_build1_loc (location.gcc_location (), VIEW_CONVERT_EXPR,
type_to_cast_to, expr_tree);
}
+ else if (TREE_CODE (type_to_cast_to) == POINTER_TYPE
+ && SLICE_TYPE_P (TREE_TYPE (expr_tree)))
+ {
+ // returning a raw cast using NOP_EXPR seems to resut in an ICE:
+ //
+ // Analyzing compilation unit
+ // Performing interprocedural optimizations
+ // <*free_lang_data> {heap 2644k} <visibility> {heap 2644k}
+ // <build_ssa_passes> {heap 2644k} <opt_local_passes> {heap 2644k}during
+ // GIMPLE pass: cddce
+ // In function ‘*T::as_ptr<i32>’:
+ // rust1: internal compiler error: in propagate_necessity, at
+ // tree-ssa-dce.cc:984 0x1d5b43e propagate_necessity
+ // ../../gccrs/gcc/tree-ssa-dce.cc:984
+ // 0x1d5e180 perform_tree_ssa_dce
+ // ../../gccrs/gcc/tree-ssa-dce.cc:1876
+ // 0x1d5e2c8 tree_ssa_cd_dce
+ // ../../gccrs/gcc/tree-ssa-dce.cc:1920
+ // 0x1d5e49a execute
+ // ../../gccrs/gcc/tree-ssa-dce.cc:1992
+
+ // this is returning the direct raw pointer of the slice an assumes a very
+ // specific layout
+ return ctx->get_backend ()->struct_field_expression (expr_tree, 0,
+ location);
+ }
return fold_convert_loc (location.gcc_location (), type_to_cast_to,
expr_tree);
@@ -1261,9 +1298,13 @@ HIRCompileBase::resolve_adjustements (
case Resolver::Adjustment::AdjustmentType::IMM_REF:
case Resolver::Adjustment::AdjustmentType::MUT_REF: {
- tree ptrtype
- = TyTyResolveCompile::compile (ctx, adjustment.get_expected ());
- e = address_expression (e, ptrtype, locus);
+ if (!SLICE_TYPE_P (TREE_TYPE (e)))
+ {
+ tree ptrtype
+ = TyTyResolveCompile::compile (ctx,
+ adjustment.get_expected ());
+ e = address_expression (e, ptrtype, locus);
+ }
}
break;
@@ -1619,6 +1660,15 @@ CompileExpr::visit (HIR::ArrayIndexExpr &expr)
index, expr.get_array_expr (),
expr.get_index_expr ());
+ tree actual_type = TREE_TYPE (operator_overload_call);
+ bool can_indirect = TYPE_PTR_P (actual_type) || TYPE_REF_P (actual_type);
+ if (!can_indirect)
+ {
+ // nothing to do
+ translated = operator_overload_call;
+ return;
+ }
+
// lookup the expected type for this expression
TyTy::BaseType *tyty = nullptr;
bool ok
diff --git a/gcc/rust/backend/rust-compile-type.cc b/gcc/rust/backend/rust-compile-type.cc
index 102bc0a..707b2af 100644
--- a/gcc/rust/backend/rust-compile-type.cc
+++ b/gcc/rust/backend/rust-compile-type.cc
@@ -25,6 +25,13 @@
namespace Rust {
namespace Compile {
+static const std::string RUST_ENUM_DISR_FIELD_NAME = "RUST$ENUM$DISR";
+
+TyTyResolveCompile::TyTyResolveCompile (Context *ctx, bool trait_object_mode)
+ : ctx (ctx), trait_object_mode (trait_object_mode),
+ translated (error_mark_node), recurisve_ops (0)
+{}
+
tree
TyTyResolveCompile::compile (Context *ctx, const TyTy::BaseType *ty,
bool trait_object_mode)
@@ -42,8 +49,6 @@ TyTyResolveCompile::compile (Context *ctx, const TyTy::BaseType *ty,
return compiler.translated;
}
-static const std::string RUST_ENUM_DISR_FIELD_NAME = "RUST$ENUM$DISR";
-
// see: gcc/c/c-decl.cc:8230-8241
// https://github.com/Rust-GCC/gccrs/blob/0024bc2f028369b871a65ceb11b2fddfb0f9c3aa/gcc/c/c-decl.c#L8229-L8241
tree
@@ -375,24 +380,7 @@ TyTyResolveCompile::visit (const TyTy::ArrayType &type)
void
TyTyResolveCompile::visit (const TyTy::SliceType &type)
{
- std::vector<Backend::typed_identifier> fields;
-
- tree element_type
- = TyTyResolveCompile::compile (ctx, type.get_element_type ());
- tree data_field_ty = build_pointer_type (element_type);
- Backend::typed_identifier data_field ("data", data_field_ty, Location ());
- fields.push_back (std::move (data_field));
-
- // lookup usize
- TyTy::BaseType *usize = nullptr;
- bool ok = ctx->get_tyctx ()->lookup_builtin ("usize", &usize);
- rust_assert (ok);
-
- tree len_field_ty = TyTyResolveCompile::compile (ctx, usize);
- Backend::typed_identifier len_field ("len", len_field_ty, Location ());
- fields.push_back (std::move (len_field));
-
- tree type_record = ctx->get_backend ()->struct_type (fields);
+ tree type_record = create_slice_type_record (type);
std::string named_struct_str
= std::string ("[") + type.get_element_type ()->get_name () + "]";
@@ -536,6 +524,21 @@ TyTyResolveCompile::visit (const TyTy::CharType &type)
void
TyTyResolveCompile::visit (const TyTy::ReferenceType &type)
{
+ const TyTy::SliceType *slice = nullptr;
+ if (type.is_dyn_slice_type (&slice))
+ {
+ tree type_record = create_slice_type_record (*slice);
+ std::string dyn_slice_type_str
+ = std::string (type.is_mutable () ? "&mut " : "&") + "["
+ + slice->get_element_type ()->get_name () + "]";
+
+ translated
+ = ctx->get_backend ()->named_type (dyn_slice_type_str, type_record,
+ slice->get_locus ());
+
+ return;
+ }
+
tree base_compiled_type
= TyTyResolveCompile::compile (ctx, type.get_base (), trait_object_mode);
if (type.is_mutable ())
@@ -552,6 +555,21 @@ TyTyResolveCompile::visit (const TyTy::ReferenceType &type)
void
TyTyResolveCompile::visit (const TyTy::PointerType &type)
{
+ const TyTy::SliceType *slice = nullptr;
+ if (type.is_dyn_slice_type (&slice))
+ {
+ tree type_record = create_slice_type_record (*slice);
+ std::string dyn_slice_type_str
+ = std::string (type.is_mutable () ? "*mut " : "*const ") + "["
+ + slice->get_element_type ()->get_name () + "]";
+
+ translated
+ = ctx->get_backend ()->named_type (dyn_slice_type_str, type_record,
+ slice->get_locus ());
+
+ return;
+ }
+
tree base_compiled_type
= TyTyResolveCompile::compile (ctx, type.get_base (), trait_object_mode);
if (type.is_mutable ())
@@ -615,5 +633,29 @@ TyTyResolveCompile::visit (const TyTy::DynamicObjectType &type)
type.get_ident ().locus);
}
+tree
+TyTyResolveCompile::create_slice_type_record (const TyTy::SliceType &type)
+{
+ // lookup usize
+ TyTy::BaseType *usize = nullptr;
+ bool ok = ctx->get_tyctx ()->lookup_builtin ("usize", &usize);
+ rust_assert (ok);
+
+ tree element_type
+ = TyTyResolveCompile::compile (ctx, type.get_element_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 262b8fc..aefacea 100644
--- a/gcc/rust/backend/rust-compile-type.h
+++ b/gcc/rust/backend/rust-compile-type.h
@@ -60,11 +60,11 @@ public:
public:
static hashval_t type_hasher (tree type);
+protected:
+ tree create_slice_type_record (const TyTy::SliceType &type);
+
private:
- TyTyResolveCompile (Context *ctx, bool trait_object_mode)
- : ctx (ctx), trait_object_mode (trait_object_mode),
- translated (error_mark_node), recurisve_ops (0)
- {}
+ TyTyResolveCompile (Context *ctx, bool trait_object_mode);
Context *ctx;
bool trait_object_mode;
diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc
index d9349d5..18a2df6 100644
--- a/gcc/rust/backend/rust-compile.cc
+++ b/gcc/rust/backend/rust-compile.cc
@@ -218,6 +218,11 @@ 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
@@ -227,6 +232,8 @@ 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)))
+ return coerced;
return address_expression (coerced,
build_reference_type (TREE_TYPE (coerced)),
@@ -249,6 +256,12 @@ 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 ());
}
@@ -256,6 +269,12 @@ 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 ());
}
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index c50e090..2b480ad 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -74,6 +74,12 @@
(INDIRECT_REF_P (NODE) && TREE_TYPE (TREE_OPERAND (NODE, 0)) \
&& TYPE_REF_P (TREE_TYPE (TREE_OPERAND ((NODE), 0))))
+// 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) \
+ (TREE_CODE (TYPE) == RECORD_TYPE && TREE_LANG_FLAG_0 (TYPE))
+
namespace Rust {
// forked from gcc/cp/cvt.cc convert_to_void
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index a2950e9..31d26dc 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -2180,6 +2180,21 @@ public:
bool is_mutable () const { return mut == Mutability::Mut; }
+ bool is_dyn_slice_type () const
+ {
+ return get_base ()->destructure ()->get_kind () == TyTy::TypeKind::SLICE;
+ }
+
+ bool is_dyn_slice_type (const TyTy::SliceType **slice) const
+ {
+ const TyTy::BaseType *element = get_base ()->destructure ();
+ if (element->get_kind () != TyTy::TypeKind::SLICE)
+ return false;
+
+ *slice = static_cast<const TyTy::SliceType *> (element);
+ return true;
+ }
+
private:
TyVar base;
Mutability mut;
@@ -2241,6 +2256,21 @@ public:
bool is_const () const { return mut == Mutability::Imm; }
+ bool is_dyn_slice_type () const
+ {
+ return get_base ()->destructure ()->get_kind () == TyTy::TypeKind::SLICE;
+ }
+
+ bool is_dyn_slice_type (const TyTy::SliceType **slice) const
+ {
+ const TyTy::BaseType *element = get_base ()->destructure ();
+ if (element->get_kind () != TyTy::TypeKind::SLICE)
+ return false;
+
+ *slice = static_cast<const TyTy::SliceType *> (element);
+ return true;
+ }
+
private:
TyVar base;
Mutability mut;
diff --git a/gcc/testsuite/rust/execute/torture/issue-1232.rs b/gcc/testsuite/rust/execute/torture/issue-1232.rs
new file mode 100644
index 0000000..983ea41
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/issue-1232.rs
@@ -0,0 +1,159 @@
+// { dg-additional-options "-w" }
+// { dg-output "slice_access=3\n" }
+extern "rust-intrinsic" {
+ fn offset<T>(dst: *const T, offset: isize) -> *const T;
+}
+
+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>,
+}
+
+pub enum Option<T> {
+ None,
+ Some(T),
+}
+
+#[lang = "Range"]
+pub struct Range<Idx> {
+ pub start: Idx,
+ pub end: Idx,
+}
+
+#[lang = "const_slice_ptr"]
+impl<T> *const [T] {
+ pub const fn len(self) -> usize {
+ let a = unsafe { Repr { rust: self }.raw };
+ a.len
+ }
+
+ pub const fn as_ptr(self) -> *const T {
+ self as *const T
+ }
+}
+
+#[lang = "const_ptr"]
+impl<T> *const T {
+ pub const unsafe fn offset(self, count: isize) -> *const T {
+ unsafe { offset(self, count) }
+ }
+
+ pub const unsafe fn add(self, count: usize) -> Self {
+ unsafe { self.offset(count as isize) }
+ }
+
+ pub const fn as_ptr(self) -> *const T {
+ self as *const T
+ }
+}
+
+const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
+ unsafe {
+ Repr {
+ raw: FatPtr { data, len },
+ }
+ .rust
+ }
+}
+
+#[lang = "index"]
+trait Index<Idx> {
+ type Output;
+
+ fn index(&self, index: Idx) -> &Self::Output;
+}
+
+pub unsafe trait SliceIndex<T> {
+ type Output;
+
+ fn get(self, slice: &T) -> Option<&Self::Output>;
+
+ unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output;
+
+ fn index(self, slice: &T) -> &Self::Output;
+}
+
+unsafe impl<T> SliceIndex<[T]> for usize {
+ type Output = T;
+
+ fn get(self, slice: &[T]) -> Option<&T> {
+ unsafe { Option::Some(&*self.get_unchecked(slice)) }
+ }
+
+ unsafe fn get_unchecked(self, slice: *const [T]) -> *const T {
+ // SAFETY: the caller guarantees that `slice` is not dangling, so it
+ // cannot be longer than `isize::MAX`. They also guarantee that
+ // `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
+ // so the call to `add` is safe.
+ unsafe { slice.as_ptr().add(self) }
+ }
+
+ fn index(self, slice: &[T]) -> &T {
+ // N.B., use intrinsic indexing
+ // &(*slice)[self]
+ unsafe { &*self.get_unchecked(slice) }
+ }
+}
+
+unsafe impl<T> SliceIndex<[T]> for Range<usize> {
+ type Output = [T];
+
+ fn get(self, slice: &[T]) -> Option<&[T]> {
+ if self.start > self.end
+ /* || self.end > slice.len() */
+ {
+ Option::None
+ } else {
+ unsafe { Option::Some(&*self.get_unchecked(slice)) }
+ }
+ }
+
+ unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] {
+ unsafe {
+ let a: *const T = slice.as_ptr();
+ let b: *const T = a.add(self.start);
+ slice_from_raw_parts(b, self.end - self.start)
+ }
+ }
+
+ fn index(self, slice: &[T]) -> &[T] {
+ unsafe { &*self.get_unchecked(slice) }
+ }
+}
+
+impl<T, I> Index<I> for [T]
+where
+ I: SliceIndex<[T]>,
+{
+ type Output = I::Output;
+
+ fn index(&self, index: I) -> &I::Output {
+ index.index(self)
+ }
+}
+
+fn main() -> i32 {
+ let array = [1, 2, 3, 4, 5];
+ let slice = &array[1..3];
+ let slice_access = slice[1];
+
+ unsafe {
+ let a = "slice_access=%i\n";
+ let b = a as *const str;
+ let c = b as *const i8;
+
+ printf(c, slice_access);
+ }
+
+ 0
+}