Skip to content

Commit 5b56999

Browse files
committed
Codegen for safe union
1 parent f41beca commit 5b56999

4 files changed

Lines changed: 76 additions & 2 deletions

File tree

cpp2rust/converter/converter.cpp

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,11 @@ void Converter::EmitRustStructOrUnion(clang::RecordDecl *decl) {
753753
}
754754
}
755755

756+
if (decl->isUnion()) {
757+
EmitRustUnion(decl);
758+
return;
759+
}
760+
756761
// Derived traits
757762
if (EmitsReprCForRecords()) {
758763
StrCat("#[repr(C)]");
@@ -770,8 +775,7 @@ void Converter::EmitRustStructOrUnion(clang::RecordDecl *decl) {
770775
auto access = clang::dyn_cast<clang::CXXRecordDecl>(decl)
771776
? AccessSpecifierAsString(decl->getAccess())
772777
: keyword::kPub;
773-
StrCat(access, decl->isUnion() ? keyword::kUnion : keyword::kStruct,
774-
GetRecordName(decl));
778+
StrCat(access, keyword::kStruct, GetRecordName(decl));
775779
{
776780
PushBrace brace(*this);
777781
for (auto *field : decl->fields()) {
@@ -817,6 +821,31 @@ void Converter::EmitRustStructOrUnion(clang::RecordDecl *decl) {
817821
AddByteReprTrait(decl);
818822
}
819823

824+
void Converter::EmitRustUnion(clang::RecordDecl *decl) {
825+
if (EmitsReprCForRecords()) {
826+
StrCat("#[repr(C)]");
827+
}
828+
auto attrs = GetStructAttributes(decl);
829+
Mapper::SetDerives(ctx_.getCanonicalTagType(decl),
830+
std::vector<std::string>(attrs.begin(), attrs.end()));
831+
StrCat("#[derive(");
832+
for (auto *attr : attrs) {
833+
StrCat(attr, ',');
834+
}
835+
StrCat(")]");
836+
837+
StrCat(keyword::kPub, keyword::kUnion, GetRecordName(decl));
838+
{
839+
PushBrace brace(*this);
840+
for (auto *field : decl->fields()) {
841+
VisitFieldDecl(field);
842+
}
843+
}
844+
845+
AddDefaultTrait(decl);
846+
AddByteReprTrait(decl);
847+
}
848+
820849
bool Converter::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) {
821850
if (clang::isa<clang::ClassTemplateSpecializationDecl>(decl)) {
822851
materializeTemplateSpecialization(decl);

cpp2rust/converter/converter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
112112

113113
virtual void EmitRustStructOrUnion(clang::RecordDecl *decl);
114114

115+
virtual void EmitRustUnion(clang::RecordDecl *decl);
116+
115117
virtual bool EmitsReprCForRecords() const { return true; }
116118

117119
virtual bool VisitCXXMethodDecl(clang::CXXMethodDecl *decl);

cpp2rust/converter/models/converter_refcount.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,42 @@ void ConverterRefCount::AddDefaultTrait(const clang::RecordDecl *decl) {
469469
}
470470

471471
void ConverterRefCount::AddDefaultTraitForUnion(const clang::RecordDecl *decl) {
472+
auto name = GetRecordName(decl);
473+
StrCat(std::format("impl Default for {}", name));
474+
PushBrace impl_brace(*this);
475+
StrCat("fn default() -> Self");
476+
PushBrace fn_brace(*this);
477+
StrCat(std::format("{} {{ __store: libcc2rs::UnionStore::new({}) }}", name,
478+
ctx_.getASTRecordLayout(decl).getSize().getQuantity()));
479+
}
480+
481+
void ConverterRefCount::EmitRustUnion(clang::RecordDecl *decl) {
482+
auto name = GetRecordName(decl);
483+
484+
auto attrs = GetStructAttributes(decl);
485+
Mapper::SetDerives(ctx_.getCanonicalTagType(decl),
486+
std::vector<std::string>(attrs.begin(), attrs.end()));
487+
StrCat("#[derive(");
488+
for (auto *attr : attrs) {
489+
StrCat(attr, ',');
490+
}
491+
StrCat(")]");
492+
493+
StrCat(
494+
std::format("pub struct {} {{ __store: libcc2rs::UnionStore, }}", name));
495+
496+
StrCat(std::format("impl {}", name));
497+
{
498+
PushBrace impl_brace(*this);
499+
for (auto *field : decl->fields()) {
500+
StrCat(std::format(
501+
"pub fn {}(&self) -> Ptr<{}> {{ self.__store.pod(0) }}",
502+
GetNamedDeclAsString(field), Mapper::Map(field->getType())));
503+
}
504+
}
505+
506+
AddDefaultTrait(decl);
507+
AddByteReprTrait(decl);
472508
}
473509

474510
void ConverterRefCount::AddDropTrait(const clang::CXXRecordDecl *decl) {
@@ -1789,6 +1825,11 @@ std::vector<const char *>
17891825
ConverterRefCount::GetStructAttributes(const clang::RecordDecl *decl) {
17901826
std::vector<const char *> attrs;
17911827

1828+
if (decl->isUnion()) {
1829+
attrs.emplace_back("Clone");
1830+
return attrs;
1831+
}
1832+
17921833
if (RecordDerivesDefault(decl)) {
17931834
attrs.emplace_back("Default");
17941835
}

cpp2rust/converter/models/converter_refcount.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class ConverterRefCount final : public Converter {
2828

2929
bool VisitCXXRecordDecl(clang::CXXRecordDecl *decl) override;
3030

31+
void EmitRustUnion(clang::RecordDecl *decl) override;
32+
3133
bool EmitsReprCForRecords() const override { return false; }
3234

3335
void ConvertOrdAndPartialOrdTraits(const clang::CXXRecordDecl *decl,

0 commit comments

Comments
 (0)