@@ -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;
}
@@ -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)
{
@@ -859,16 +880,12 @@ 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
@@ -2114,6 +2131,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)
@@ -145,6 +145,9 @@ protected:
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,
@@ -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);
@@ -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 ();
@@ -5,6 +5,7 @@
type c_char = u8;
#[lang = "CStr"]
+#[repr(transparent)]
pub struct CStr {
inner: [c_char]
}
new file mode 100644
@@ -0,0 +1,21 @@
+// { dg-additional-options "-fdump-tree-gimple" }
+#![feature(no_core)]
+#![no_core]
+
+struct NonTransparent {
+ foo: i32
+}
+
+#[repr(transparent)]
+struct Transparent {
+ foo: i32
+}
+
+fn main () -> i32 {
+ // { dg-final { scan-tree-dump-times {(?n)my_obj . 42;$} 1 gimple } }
+ let mut my_obj = Transparent { foo: 42 };
+ // { dg-final { scan-tree-dump-times {(?n)my_obj2.foo . 40;$} 1 gimple } }
+ let my_obj2 = NonTransparent { foo: 40 };
+ my_obj.foo -= 2;
+ my_obj.foo - my_obj2.foo
+}
\ No newline at end of file
new file mode 100644
@@ -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 }
+}
@@ -10,6 +10,7 @@ extern "C" {
type c_char = u8;
#[lang = "CStr"]
+#[repr(transparent)]
pub struct CStr {
inner: [c_char]
}
@@ -33,6 +33,7 @@ extern "C" {
type c_char = u8;
#[lang = "CStr"]
+#[repr(transparent)]
pub struct CStr {
inner: [c_char]
}