Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 53 additions & 14 deletions gcc/rust/backend/rust-compile-expr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -769,10 +769,22 @@ CompileExpr::visit (HIR::StructExprStructFields &struct_expr)

if (!adt->is_enum ())
{
translated
= Backend::constructor_expression (compiled_adt_type, adt->is_enum (),
arguments, union_disriminator,
struct_expr.get_locus ());
auto repr_kind = adt->get_repr_options ().repr_kind;
if (repr_kind == TyTy::ADTType::ReprKind::TRANSPARENT)
{
translated
= fold_build1_loc (struct_expr.get_locus (), VIEW_CONVERT_EXPR,
compiled_adt_type, arguments.front ());
}
else
{
translated
= Backend::constructor_expression (compiled_adt_type,
adt->is_enum (), arguments,
union_disriminator,
struct_expr.get_locus ());
}

return;
}

Expand Down Expand Up @@ -843,6 +855,15 @@ CompileExpr::visit (HIR::FieldAccessExpr &expr)
bool ok = variant->lookup_field (expr.get_field_name ().as_string (),
nullptr, &field_index);
rust_assert (ok);

auto repr_kind = adt->get_repr_options ().repr_kind;
if (repr_kind == TyTy::ADTType::ReprKind::TRANSPARENT)
{
translated
= compile_transparent_field_access (variant, expr.get_locus (),
receiver_ref);
return;
}
}
else if (receiver->get_kind () == TyTy::TypeKind::REF)
{
Expand All @@ -859,22 +880,30 @@ CompileExpr::visit (HIR::FieldAccessExpr &expr)
nullptr, &field_index);
rust_assert (ok);

// TODO this check is only used for CStr, test again when we support
// compilation of #[repr(transparent)] structs
if (RS_DST_FLAG_P (TREE_TYPE (receiver_ref)))
auto repr_kind = adt->get_repr_options ().repr_kind;
if (repr_kind == TyTy::ADTType::ReprKind::TRANSPARENT)
{
const TyTy::StructFieldType *field
= variant->get_field_at_index (field_index);
tree field_type
= TyTyResolveCompile::compile (ctx, field->get_field_type ());
translated = fold_build1_loc (expr.get_locus (), VIEW_CONVERT_EXPR,
field_type, receiver_ref);
translated
= compile_transparent_field_access (variant, expr.get_locus (),
receiver_ref);
return;
}
else
{
tree indirect = indirect_expression (receiver_ref, expr.get_locus ());
receiver_ref = indirect;

auto repr_kind = adt->get_repr_options ().repr_kind;
if (repr_kind == TyTy::ADTType::ReprKind::TRANSPARENT)
{
translated
= compile_transparent_field_access (variant, expr.get_locus (),
indirect);
return;
}
else
{
receiver_ref = indirect;
}
}
Comment on lines -862 to 907

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Repeat check of repr_kind?

}

Expand Down Expand Up @@ -2114,6 +2143,16 @@ CompileExpr::compile_c_string_literal (const HIR::LiteralExpr &expr,
expr.get_locus ());
}

tree
CompileExpr::compile_transparent_field_access (TyTy::VariantDef *variant,
location_t locus,
tree source_expr)
{
const TyTy::StructFieldType *field = variant->get_field_at_index (0);
tree field_type = TyTyResolveCompile::compile (ctx, field->get_field_type ());
return fold_build1_loc (locus, VIEW_CONVERT_EXPR, field_type, source_expr);
}

tree
CompileExpr::type_cast_expression (tree type_to_cast_to, tree expr_tree,
location_t location)
Expand Down
3 changes: 3 additions & 0 deletions gcc/rust/backend/rust-compile-expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ class CompileExpr : private HIRCompileBase, protected HIR::HIRExpressionVisitor
const TyTy::ArrayType &array_tyty, tree array_type,
HIR::ArrayElemsCopied &elems);

tree compile_transparent_field_access (TyTy::VariantDef *variant,
location_t locus, tree source_expr);

protected:
tree generate_closure_function (HIR::ClosureExpr &expr,
TyTy::ClosureType &closure_tyty,
Expand Down
54 changes: 42 additions & 12 deletions gcc/rust/backend/rust-compile-type.cc
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,35 @@ void
TyTyResolveCompile::visit (const TyTy::ADTType &type)
{
tree type_record = error_mark_node;
if (!type.is_enum ())

TyTy::ADTType::ReprOptions repr = type.get_repr_options ();
if (repr.repr_kind == TyTy::ADTType::ReprKind::TRANSPARENT)
{
rust_assert (type.number_of_variants () == 1);
TyTy::VariantDef &variant = *type.get_variants ().at (0);

rust_assert (variant.num_fields () <= 1);
if (variant.num_fields () == 0)
{
// 0-field transparent repr
// Rustonomicon states that transparent structs should have a single
// non-zero-sized field, but rustc compiles one with 0 fields happily
// without errors, so not sure what's the correct treatment.
//
// For now, treat it as a unit struct
type_record = Backend::struct_type ({});
}
else
{
// single field transparent repr
const TyTy::StructFieldType *field = variant.get_field_at_index (0);
type_record
= TyTyResolveCompile::compile (ctx, field->get_field_type ());
}
}

// compilation of non-transparent ADTs below
else if (!type.is_enum ())
{
rust_assert (type.number_of_variants () == 1);

Expand Down Expand Up @@ -442,22 +470,24 @@ TyTyResolveCompile::visit (const TyTy::ADTType &type)
// TODO: "packed" should only narrow type alignment and "align" should only
// widen it. Do we need to check and enforce this here, or is it taken care of
// later on in the gcc middle-end?
TyTy::ADTType::ReprOptions repr = type.get_repr_options ();
if (repr.pack)
if (repr.repr_kind != TyTy::ADTType::ReprKind::TRANSPARENT)
{
TYPE_PACKED (type_record) = 1;
if (repr.pack > 1)
if (repr.pack)
{
TYPE_PACKED (type_record) = 1;
if (repr.pack > 1)
{
SET_TYPE_ALIGN (type_record, repr.pack * 8);
TYPE_USER_ALIGN (type_record) = 1;
}
}
else if (repr.align)
{
SET_TYPE_ALIGN (type_record, repr.pack * 8);
SET_TYPE_ALIGN (type_record, repr.align * 8);
TYPE_USER_ALIGN (type_record) = 1;
}
layout_type (type_record);
}
else if (repr.align)
{
SET_TYPE_ALIGN (type_record, repr.align * 8);
TYPE_USER_ALIGN (type_record) = 1;
}
layout_type (type_record);

std::string named_struct_str
= type.get_ident ().path.get () + type.subst_as_string ();
Expand Down
22 changes: 19 additions & 3 deletions gcc/rust/typecheck/rust-hir-type-check-base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -516,12 +516,12 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus)
bool is_align = false;
bool is_c = false;
bool is_integer = false;
bool is_transparent = false;
unsigned char value = 1;

if (oparen == std::string::npos)
{
is_pack = inline_option.compare ("packed") == 0;
is_align = inline_option.compare ("align") == 0;
is_c = inline_option.compare ("C") == 0;
is_integer = (inline_option.compare ("isize") == 0
|| inline_option.compare ("i8") == 0
Expand All @@ -535,6 +535,7 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus)
|| inline_option.compare ("u32") == 0
|| inline_option.compare ("u64") == 0
|| inline_option.compare ("u128") == 0);
is_transparent = inline_option.compare ("transparent") == 0;
}

else
Expand All @@ -553,7 +554,16 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus)
value = strtoul (value_str.c_str () + 1, NULL, 10);
}

if (is_pack)
if (is_transparent)
{
if (is_pack || is_align || is_c || is_integer)
rust_error_at (
locus, ErrorCode::E0692,
"transparent struct cannot have other repr hints");

repr.repr_kind = TyTy::ADTType::ReprKind::TRANSPARENT;
}
else if (is_pack)
{
repr.repr_kind = TyTy::ADTType::ReprKind::PACKED;
repr.pack = value;
Expand All @@ -573,9 +583,15 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus)
bool ok = context->lookup_builtin (inline_option, &repr.repr);
if (!ok)
{
rust_error_at (attr.get_locus (), "Invalid repr type");
rust_error_at (attr.get_locus (), ErrorCode::E0552,
"unrecognized representation hint");
}
}
else
{
rust_error_at (attr.get_locus (), ErrorCode::E0552,
"unrecognized representation hint");
}

delete meta_items;

Expand Down
18 changes: 13 additions & 5 deletions gcc/rust/typecheck/rust-hir-type-check-item.cc
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,19 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl)
ResolveWhereClauseItem::Resolve (*where_clause_item, region_constraints);
}

// Process #[repr(X)] attribute, if any
const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
TyTy::ADTType::ReprOptions repr
= parse_repr_options (attrs, struct_decl.get_locus ());
if (repr.repr_kind == TyTy::ADTType::ReprKind::TRANSPARENT
&& struct_decl.get_fields ().size () > 1)
{
rust_error_at (struct_decl.get_locus (), ErrorCode::E0690,
"transparent struct needs at most one field with "
"non-trivial size or alignment, but has %lu",
(unsigned long) struct_decl.get_fields ().size ());
}

std::vector<TyTy::StructFieldType *> fields;
for (auto &field : struct_decl.get_fields ())
{
Expand Down Expand Up @@ -379,11 +392,6 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl)
struct_decl.get_identifier ().as_string (), ident,
variant_type, tl::nullopt, std::move (fields)));

// Process #[repr(X)] attribute, if any
const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
TyTy::ADTType::ReprOptions repr
= parse_repr_options (attrs, struct_decl.get_locus ());

auto *type = new TyTy::ADTType (
struct_decl.get_mappings ().get_defid (),
struct_decl.get_mappings ().get_hirid (),
Expand Down
2 changes: 1 addition & 1 deletion gcc/rust/typecheck/rust-tyty.h
Original file line number Diff line number Diff line change
Expand Up @@ -910,7 +910,7 @@ class ADTType : public BaseType, public SubstitutionRef
INT,
ALIGN,
PACKED,
// TRANSPARENT,
TRANSPARENT,
// SIMD,
// ...
};
Expand Down
1 change: 1 addition & 0 deletions gcc/testsuite/rust/compile/c_string_null_byte_check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
type c_char = u8;

#[lang = "CStr"]
#[repr(transparent)]
pub struct CStr {
inner: [c_char]
}
Expand Down
12 changes: 12 additions & 0 deletions gcc/testsuite/rust/compile/invalid_repr_hint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#![feature(no_core)]
#![no_core]

#[repr(InvalidRepr)] // { dg-error "unrecognized representation hint" }
struct Foo {
x: i32,
}

#[repr(align)] // { dg-error "unrecognized representation hint" }
struct Bar {
x: i32,
}
16 changes: 16 additions & 0 deletions gcc/testsuite/rust/compile/repr_transparent_fields.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#![feature(no_core)]
#![no_core]

#[repr(transparent)]
struct Foo { // { dg-error "transparent struct needs at most one field with non-trivial size or alignment, but has 2" }
foo: i32,
bar: i32
}

#[repr(transparent)]
struct Bar {}

#[repr(transparent)]
struct Baz {
foo: i32
}
43 changes: 43 additions & 0 deletions gcc/testsuite/rust/compile/transparent_struct_deref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#![feature(no_core, intrinsics, staged_api, lang_items)]
#![no_core]

#[lang = "sized"]
pub trait Sized {}

// below's helper code copied from issue-1232.rs
extern "rust-intrinsic" {
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
fn offset<T>(dst: *const T, offset: isize) -> *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
}
}

#[repr(transparent)]
pub struct Foo {
inner: i32
}

impl Foo {
pub const fn to_ptr(&self) -> *const i32 {
&self.inner as *const i32
}
}

pub fn main() -> i32 {
let a = Foo { inner: 67 };
let val = unsafe { a.to_ptr() };
unsafe { *val - 67 }
}
1 change: 1 addition & 0 deletions gcc/testsuite/rust/execute/torture/c_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ extern "C" {
type c_char = u8;

#[lang = "CStr"]
#[repr(transparent)]
pub struct CStr {
inner: [c_char]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ extern "C" {
type c_char = u8;

#[lang = "CStr"]
#[repr(transparent)]
pub struct CStr {
inner: [c_char]
}
Expand Down
Loading