https://gcc.gnu.org/g:fae5d567d1c573e5da613539d406124da249cc96
commit r17-3108-gfae5d567d1c573e5da613539d406124da249cc96 Author: Yap Zhi Heng <[email protected]> Date: Sun Jul 12 22:13:06 2026 +0800 gccrs: Support ZST type checking for `#[repr(transparent)]` 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]> Diff: --- gcc/rust/backend/rust-compile-type.cc | 17 +++- gcc/rust/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 01f80da52a48..f0c2d1bf1e04 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 ac0eeaf277e0..6c1d91132915 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 d5ef3b063b41..825febe6f6ee 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 f645f673f86b..ec9b71123ba3 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 19002138696a..72219e486741 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>, +}
