From: Yap Zhi Heng <[email protected]>

gcc/rust/ChangeLog:

        * typecheck/rust-tyty.h (BaseType::is_zero_sized): New function.
        (TupleType::is_zero_sized): New function.
        (ArrayType::is_zero_sized): New function.
        (ADTType::is_zero_sized): New function.
        * typecheck/rust-tyty.cc (BaseType::is_zero_sized): Implement checking 
of
        whether a type is zero-sized.
        (TupleType::is_zero_sized): Ditto.
        (ArrayType::is_zero_sized): Ditto.
        (ADTType::is_zero_sized): Ditto.
        * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit 
(StructStruct)): Update
        transparent repr type-checking to check for zero-sized members.
        * backend/rust-compile-type.cc (TyTyResolveCompile::visit 
(TyTy::ADTType)): Support
        compilation of transparent repr structs with more than 1 fields.

gcc/testsuite/ChangeLog:

        * rust/compile/repr_transparent_fields.rs: Add new test case with 
PhantomData.

Signed-Off-By: Yap Zhi Heng <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.


Commit on github: 
https://github.com/Rust-GCC/gccrs/commit/941f9359546ea10c548c8f379bb0edfd9df3c52a

The commit has NOT been mentioned in any issue.

The commit has been mentioned in the following pull-request(s):
 - https://github.com/Rust-GCC/gccrs/pull/4698

 gcc/rust/backend/rust-compile-type.cc         |  17 ++-
 .../typecheck/rust-hir-type-check-item.cc     |  26 +++--
 gcc/rust/typecheck/rust-tyty.cc               | 106 ++++++++++++++++++
 gcc/rust/typecheck/rust-tyty.h                |  10 ++
 .../rust/compile/repr_transparent_fields.rs   |  14 ++-
 5 files changed, 162 insertions(+), 11 deletions(-)

diff --git a/gcc/rust/backend/rust-compile-type.cc 
b/gcc/rust/backend/rust-compile-type.cc
index 01f80da52..f0c2d1bf1 100644
--- a/gcc/rust/backend/rust-compile-type.cc
+++ b/gcc/rust/backend/rust-compile-type.cc
@@ -302,7 +302,6 @@ TyTyResolveCompile::visit (const TyTy::ADTType &type)
       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
@@ -313,13 +312,27 @@ TyTyResolveCompile::visit (const TyTy::ADTType &type)
          // For now, treat it as a unit struct
          type_record = Backend::struct_type ({});
        }
-      else
+      else if (variant.num_fields () == 1)
        {
          // single field transparent repr
          const TyTy::StructFieldType *field = variant.get_field_at_index (0);
          type_record
            = TyTyResolveCompile::compile (ctx, field->get_field_type ());
        }
+      else
+       {
+         // more than one field - typechecking already ensures there's only one
+         // non-zero-sized field, just compile accessor for that
+         // non-zero-sized.
+         for (size_t i = 0; i < variant.num_fields (); i++)
+           {
+             auto field_ty = variant.get_field_at_index (i)->get_field_type ();
+             if (!field_ty->is_zero_sized ())
+               {
+                 type_record = TyTyResolveCompile::compile (ctx, field_ty);
+               }
+           }
+       }
     }
 
   // compilation of non-transparent ADTs below
diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc 
b/gcc/rust/typecheck/rust-hir-type-check-item.cc
index ac0eeaf27..6c1d91132 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-item.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc
@@ -343,14 +343,6 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl)
   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 ())
@@ -373,6 +365,24 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl)
       context->insert_type (field.get_mappings (), ty_field->get_field_type 
());
     }
 
+  if (repr.repr_kind == TyTy::ADTType::ReprKind::TRANSPARENT)
+    {
+      size_t num_non_zst = 0;
+      for (auto &field : fields)
+       {
+         if (!field->get_field_type ()->is_zero_sized ())
+           num_non_zst++;
+       }
+      if (num_non_zst > 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 ());
+         return;
+       }
+    }
+
   auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
 
   CanonicalPath path
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index d5ef3b063..825febe6f 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -926,6 +926,58 @@ BaseType::is_concrete () const
   return false;
 }
 
+bool
+BaseType::is_zero_sized () const
+{
+  const TyTy::BaseType *x = destructure ();
+  switch (x->get_kind ())
+    {
+    // primitives that are always non-zero size
+    case FNPTR:
+    case FNDEF:
+    case SLICE:
+    case POINTER:
+    case REF:
+    case CLOSURE:
+    case INFER:
+    case BOOL:
+    case CHAR:
+    case INT:
+    case UINT:
+    case FLOAT:
+    case USIZE:
+    case ISIZE:
+    case OPAQUE:
+    case STR:
+    case DYNAMIC:
+    case CONST:
+    case PARAM:
+    case PROJECTION:
+    case PLACEHOLDER:
+    case ERROR:
+      return false;
+
+    case NEVER:
+      return true;
+    case TUPLE:
+      {
+       const TupleType *tuple_ty = static_cast<const TupleType *> (x);
+       return tuple_ty->is_zero_sized ();
+      }
+    case ARRAY:
+      {
+       const ArrayType *array_ty = static_cast<const ArrayType *> (x);
+       return array_ty->is_zero_sized ();
+      }
+    case ADT:
+      {
+       const ADTType *adt_ty = static_cast<const ADTType *> (x);
+       return adt_ty->is_zero_sized ();
+      }
+    }
+  return false;
+}
+
 bool
 BaseType::has_substitutions_defined () const
 {
@@ -1881,6 +1933,27 @@ ADTType::is_equal (const BaseType &other) const
   return true;
 }
 
+bool
+ADTType::is_zero_sized () const
+{
+  auto phantom = Analysis::Mappings::get ().lookup_lang_item (
+    LangItem::Kind::PHANTOM_DATA);
+  if (phantom.has_value () && phantom.value () == get_id ())
+    return true;
+
+  for (auto *variant : get_variants ())
+    {
+      for (size_t i = 0; i < variant->num_fields (); i++)
+       {
+         if (!variant->get_field_at_index (i)
+                ->get_field_type ()
+                ->is_zero_sized ())
+           return false;
+       }
+    }
+  return true;
+}
+
 DefId
 ADTType::get_id () const
 {
@@ -2084,6 +2157,19 @@ TupleType::is_equal (const BaseType &other) const
   return true;
 }
 
+bool
+TupleType::is_zero_sized () const
+{
+  if (num_fields () == 0)
+    return true;
+  for (size_t i = 0; i < num_fields (); i++)
+    {
+      if (!get_field (i)->is_zero_sized ())
+       return false;
+    }
+  return true;
+}
+
 BaseType *
 TupleType::clone () const
 {
@@ -2513,6 +2599,26 @@ ArrayType::is_equal (const BaseType &other) const
   return this_element_type->is_equal (*other_element_type);
 }
 
+bool
+ArrayType::is_zero_sized () const
+{
+  auto *capacity_ty = get_capacity ();
+  if (capacity_ty != nullptr
+      && capacity_ty->get_kind () == TyTy::TypeKind::CONST)
+    {
+      auto *capacity_const = capacity_ty->as_const_type ();
+      auto &capacity_value
+       = *static_cast<TyTy::ConstValueType *> (capacity_const);
+      auto cap_tree = capacity_value.get_value ();
+      size_t cap_wi = (size_t) wi::to_wide (cap_tree).to_uhwi ();
+      if (cap_wi == 0)
+       {
+         return true;
+       }
+    }
+  return false;
+}
+
 BaseType *
 ArrayType::get_element_type () const
 {
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index f645f673f..ec9b71123 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -256,6 +256,10 @@ public:
   // primitives
   bool is_concrete () const;
 
+  // returns if the type is a zero-sized type, which is a type that occupies no
+  // space in memory
+  bool is_zero_sized () const;
+
   // return the type-kind
   TypeKind get_kind () const;
 
@@ -775,6 +779,8 @@ public:
 
   bool is_equal (const BaseType &other) const override;
 
+  bool is_zero_sized () const;
+
   size_t num_fields () const;
 
   BaseType *get_field (size_t index) const;
@@ -974,6 +980,8 @@ public:
 
   bool is_equal (const BaseType &other) const override;
 
+  bool is_zero_sized () const;
+
   std::string get_identifier () const { return identifier; }
 
   std::string get_name () const override final
@@ -1375,6 +1383,8 @@ public:
 
   bool is_equal (const BaseType &other) const override;
 
+  bool is_zero_sized () const;
+
   BaseType *get_element_type () const;
   const TyVar &get_var_element_type () const;
 
diff --git a/gcc/testsuite/rust/compile/repr_transparent_fields.rs 
b/gcc/testsuite/rust/compile/repr_transparent_fields.rs
index 190021386..72219e486 100644
--- a/gcc/testsuite/rust/compile/repr_transparent_fields.rs
+++ b/gcc/testsuite/rust/compile/repr_transparent_fields.rs
@@ -1,6 +1,12 @@
-#![feature(no_core)]
+#![feature(no_core, lang_items)]
 #![no_core]
 
+#[lang = "sized"]
+trait Sized {}
+
+#[lang = "phantom_data"]
+pub struct PhantomData<T: ?Sized>;
+
 #[repr(transparent)]
 struct Foo { // { dg-error "transparent struct needs at most one field with 
non-trivial size or alignment, but has 2" }
     foo: i32,
@@ -14,3 +20,9 @@ struct Bar {}
 struct Baz {
     foo: i32
 }
+
+#[repr(transparent)]
+struct Qux {
+    foo: i32,
+    phantom: PhantomData<i32>,
+}

base-commit: ef5bf0e0183fc81701b17d93ad3911a172facdc8
-- 
2.54.0

Reply via email to