Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions gcc/rust/backend/rust-compile-type.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
26 changes: 18 additions & 8 deletions gcc/rust/typecheck/rust-hir-type-check-item.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 ())
Expand All @@ -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
Expand Down
106 changes: 106 additions & 0 deletions gcc/rust/typecheck/rust-tyty.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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:
{
Comment thread
Polygonalr marked this conversation as resolved.
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
{
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -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
{
Expand Down
10 changes: 10 additions & 0 deletions gcc/rust/typecheck/rust-tyty.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,10 @@ class BaseType : public TypeBoundsMappings
// 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;

Expand Down Expand Up @@ -775,6 +779,8 @@ class TupleType : public BaseType

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;
Expand Down Expand Up @@ -974,6 +980,8 @@ class ADTType : public BaseType, public SubstitutionRef

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
Expand Down Expand Up @@ -1375,6 +1383,8 @@ class ArrayType : public BaseType

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;

Expand Down
14 changes: 13 additions & 1 deletion gcc/testsuite/rust/compile/repr_transparent_fields.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -14,3 +20,9 @@ struct Bar {}
struct Baz {
foo: i32
}

#[repr(transparent)]
struct Qux {
foo: i32,
phantom: PhantomData<i32>,
}
Loading