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]>
---
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 01f80da52a4..f0c2d1bf1e0 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 ac0eeaf277e..6c1d9113291 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 d5ef3b063b4..825febe6f6e 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 f645f673f86..ec9b71123ba 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 19002138696..72219e48674 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>,
+}
--
2.50.1
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.