Skip to content

Commit a240458

Browse files
committed
gccrs: Support ZST type checking for #[repr(transparent)]
gcc/rust/ChangeLog: * typecheck/rust-tyty.h (BaseType::is_zero_sized): New function. * typecheck/rust-tyty.cc (BaseType::is_zero_sized): Implement checking of whether a type is zero-sized. * 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 <yapzhhg@gmail.com>
1 parent 76397e8 commit a240458

5 files changed

Lines changed: 138 additions & 11 deletions

File tree

gcc/rust/backend/rust-compile-type.cc

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,6 @@ TyTyResolveCompile::visit (const TyTy::ADTType &type)
302302
rust_assert (type.number_of_variants () == 1);
303303
TyTy::VariantDef &variant = *type.get_variants ().at (0);
304304

305-
rust_assert (variant.num_fields () <= 1);
306305
if (variant.num_fields () == 0)
307306
{
308307
// 0-field transparent repr
@@ -313,13 +312,27 @@ TyTyResolveCompile::visit (const TyTy::ADTType &type)
313312
// For now, treat it as a unit struct
314313
type_record = Backend::struct_type ({});
315314
}
316-
else
315+
else if (variant.num_fields () == 1)
317316
{
318317
// single field transparent repr
319318
const TyTy::StructFieldType *field = variant.get_field_at_index (0);
320319
type_record
321320
= TyTyResolveCompile::compile (ctx, field->get_field_type ());
322321
}
322+
else
323+
{
324+
// more than one field - typechecking already ensures there's only one
325+
// non-zero-sized field, just compile accessor for that
326+
// non-zero-sized.
327+
for (size_t i = 0; i < variant.num_fields (); i++)
328+
{
329+
auto field_ty = variant.get_field_at_index (i)->get_field_type ();
330+
if (!field_ty->is_zero_sized ())
331+
{
332+
type_record = TyTyResolveCompile::compile (ctx, field_ty);
333+
}
334+
}
335+
}
323336
}
324337

325338
// compilation of non-transparent ADTs below

gcc/rust/typecheck/rust-hir-type-check-item.cc

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -343,14 +343,6 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl)
343343
const AST::AttrVec &attrs = struct_decl.get_outer_attrs ();
344344
TyTy::ADTType::ReprOptions repr
345345
= parse_repr_options (attrs, struct_decl.get_locus ());
346-
if (repr.repr_kind == TyTy::ADTType::ReprKind::TRANSPARENT
347-
&& struct_decl.get_fields ().size () > 1)
348-
{
349-
rust_error_at (struct_decl.get_locus (), ErrorCode::E0690,
350-
"transparent struct needs at most one field with "
351-
"non-trivial size or alignment, but has %lu",
352-
(unsigned long) struct_decl.get_fields ().size ());
353-
}
354346

355347
std::vector<TyTy::StructFieldType *> fields;
356348
for (auto &field : struct_decl.get_fields ())
@@ -373,6 +365,24 @@ TypeCheckItem::visit (HIR::StructStruct &struct_decl)
373365
context->insert_type (field.get_mappings (), ty_field->get_field_type ());
374366
}
375367

368+
if (repr.repr_kind == TyTy::ADTType::ReprKind::TRANSPARENT)
369+
{
370+
size_t num_non_zst = 0;
371+
for (auto &field : fields)
372+
{
373+
if (!field->get_field_type ()->is_zero_sized ())
374+
num_non_zst++;
375+
}
376+
if (num_non_zst > 1)
377+
{
378+
rust_error_at (struct_decl.get_locus (), ErrorCode::E0690,
379+
"transparent struct needs at most one field with "
380+
"non-trivial size or alignment, but has %lu",
381+
(unsigned long) struct_decl.get_fields ().size ());
382+
return;
383+
}
384+
}
385+
376386
auto &nr_ctx = Resolver2_0::FinalizedNameResolutionContext::get ();
377387

378388
CanonicalPath path

gcc/rust/typecheck/rust-tyty.cc

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,94 @@ BaseType::is_concrete () const
926926
return false;
927927
}
928928

929+
bool
930+
BaseType::is_zero_sized () const
931+
{
932+
const TyTy::BaseType *x = destructure ();
933+
switch (x->get_kind ())
934+
{
935+
// primitives that are always non-zero size
936+
case FNPTR:
937+
case FNDEF:
938+
case SLICE:
939+
case POINTER:
940+
case REF:
941+
case CLOSURE:
942+
case INFER:
943+
case BOOL:
944+
case CHAR:
945+
case INT:
946+
case UINT:
947+
case FLOAT:
948+
case USIZE:
949+
case ISIZE:
950+
case OPAQUE:
951+
case STR:
952+
case DYNAMIC:
953+
case CONST:
954+
case PARAM:
955+
case PROJECTION:
956+
case PLACEHOLDER:
957+
case ERROR:
958+
return false;
959+
960+
case NEVER:
961+
return true;
962+
case TUPLE:
963+
{
964+
const TupleType *tuple_ty = static_cast<const TupleType *> (x);
965+
if (tuple_ty->num_fields () == 0)
966+
return true;
967+
for (size_t i = 0; i < tuple_ty->num_fields (); i++)
968+
{
969+
if (!tuple_ty->get_field (i)->is_zero_sized ())
970+
return false;
971+
}
972+
return true;
973+
}
974+
case ARRAY:
975+
{
976+
const ArrayType *array_ty = static_cast<const ArrayType *> (x);
977+
auto *capacity_ty = array_ty->get_capacity ();
978+
if (capacity_ty != nullptr
979+
&& capacity_ty->get_kind () == TyTy::TypeKind::CONST)
980+
{
981+
auto *capacity_const = capacity_ty->as_const_type ();
982+
auto &capacity_value
983+
= *static_cast<TyTy::ConstValueType *> (capacity_const);
984+
auto cap_tree = capacity_value.get_value ();
985+
size_t cap_wi = (size_t) wi::to_wide (cap_tree).to_uhwi ();
986+
if (cap_wi == 0)
987+
{
988+
return true;
989+
}
990+
}
991+
return false;
992+
}
993+
case ADT:
994+
{
995+
const ADTType *adt_ty = static_cast<const ADTType *> (x);
996+
auto phantom = Analysis::Mappings::get ().lookup_lang_item (
997+
LangItem::Kind::PHANTOM_DATA);
998+
if (phantom.has_value () && phantom.value () == adt_ty->get_id ())
999+
return true;
1000+
1001+
for (auto *variant : adt_ty->get_variants ())
1002+
{
1003+
for (size_t i = 0; i < variant->num_fields (); i++)
1004+
{
1005+
if (!variant->get_field_at_index (i)
1006+
->get_field_type ()
1007+
->is_zero_sized ())
1008+
return false;
1009+
}
1010+
}
1011+
return true;
1012+
}
1013+
}
1014+
return false;
1015+
}
1016+
9291017
bool
9301018
BaseType::has_substitutions_defined () const
9311019
{

gcc/rust/typecheck/rust-tyty.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,10 @@ class BaseType : public TypeBoundsMappings
256256
// primitives
257257
bool is_concrete () const;
258258

259+
// returns if the type is a zero-sized type, which is a type that occupies no
260+
// space in memory
261+
bool is_zero_sized () const;
262+
259263
// return the type-kind
260264
TypeKind get_kind () const;
261265

gcc/testsuite/rust/compile/repr_transparent_fields.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
1-
#![feature(no_core)]
1+
#![feature(no_core, lang_items)]
22
#![no_core]
33

4+
#[lang = "sized"]
5+
trait Sized {}
6+
7+
#[lang = "phantom_data"]
8+
pub struct PhantomData<T: ?Sized>;
9+
410
#[repr(transparent)]
511
struct Foo { // { dg-error "transparent struct needs at most one field with non-trivial size or alignment, but has 2" }
612
foo: i32,
@@ -14,3 +20,9 @@ struct Bar {}
1420
struct Baz {
1521
foo: i32
1622
}
23+
24+
#[repr(transparent)]
25+
struct Qux {
26+
foo: i32,
27+
phantom: PhantomData<i32>,
28+
}

0 commit comments

Comments
 (0)