Skip to content

Commit 9d88938

Browse files
committed
Translate C structs
1 parent 7b5d4c5 commit 9d88938

4 files changed

Lines changed: 125 additions & 81 deletions

File tree

cpp2rust/converter/converter.cpp

Lines changed: 114 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,113 @@ static bool recordDerivesCopy(const clang::CXXRecordDecl *decl) {
580580
return true;
581581
}
582582

583+
bool Converter::VisitRecordDecl(clang::RecordDecl *decl) {
584+
decl->dumpColor();
585+
586+
// VisitCXXRecordDecl already visited the record
587+
if (clang::isa<clang::CXXRecordDecl>(decl)) {
588+
return true;
589+
}
590+
591+
if (!decl->isCompleteDefinition()) {
592+
return false;
593+
}
594+
595+
if (!record_decls_.insert(GetID(decl)).second) {
596+
return false;
597+
}
598+
599+
Mapper::AddRuleForUserDefinedType(decl);
600+
EmitRustStruct(decl);
601+
602+
return false;
603+
}
604+
605+
void Converter::EmitRustStruct(clang::RecordDecl *decl) {
606+
// Enums and static variables. In rust they live outside the record
607+
for (auto *d : decl->decls()) {
608+
if (auto *enum_decl = llvm::dyn_cast<clang::EnumDecl>(d)) {
609+
VisitEnumDecl(enum_decl);
610+
}
611+
if (auto *var_decl = clang::dyn_cast<clang::VarDecl>(d)) {
612+
VisitVarDecl(var_decl);
613+
}
614+
}
615+
616+
// Inner records. In rust they live outside the record
617+
for (auto *d : decl->decls()) {
618+
if (auto *nested = clang::dyn_cast<clang::RecordDecl>(d)) {
619+
if (!nested->isImplicit()) {
620+
inner_structs_[GetID(nested)] = GetRecordName(nested);
621+
if (auto *cxx = clang::dyn_cast<clang::CXXRecordDecl>(nested)) {
622+
VisitCXXRecordDecl(cxx);
623+
} else {
624+
VisitRecordDecl(nested);
625+
}
626+
}
627+
}
628+
}
629+
630+
// Derived traits
631+
StrCat("#[derive(");
632+
if (auto *cxx = clang::dyn_cast<clang::CXXRecordDecl>(decl)) {
633+
for (auto *attr : GetStructAttributes(cxx)) {
634+
StrCat(attr, ",");
635+
}
636+
} else {
637+
StrCat("Clone, Default");
638+
}
639+
StrCat(")]");
640+
641+
// Fields
642+
auto access = clang::dyn_cast<clang::CXXRecordDecl>(decl)
643+
? AccessSpecifierAsString(decl->getAccess())
644+
: keyword::kPub;
645+
StrCat(access, keyword::kStruct, GetRecordName(decl),
646+
token::kOpenCurlyBracket);
647+
for (auto *field : decl->fields()) {
648+
VisitFieldDecl(field);
649+
}
650+
StrCat(token::kCloseCurlyBracket);
651+
652+
// C++ method decls
653+
if (auto *cxx = clang::dyn_cast<clang::CXXRecordDecl>(decl)) {
654+
auto struct_name = GetRecordName(cxx);
655+
656+
ConvertCXXMethodDecls(
657+
cxx, std::string(keyword::kImpl) + ' ' + struct_name,
658+
[](const auto *method) {
659+
return !method->isImplicit() &&
660+
!(method->getDefinition() &&
661+
method->getDefinition()->isDefaulted()) &&
662+
(method->isThisDeclarationADefinition() ||
663+
clang::isa<clang::CXXConstructorDecl>(method)) &&
664+
!method->isVirtual() &&
665+
!clang::isa<clang::CXXDestructorDecl>(method);
666+
});
667+
668+
if (cxx->bases_begin() != cxx->bases_end()) {
669+
ConvertCXXMethodDecls(
670+
cxx,
671+
std::format("{} impl {} for {}", keyword_unsafe_,
672+
GetUnsafeTypeAsString(cxx->bases_begin()->getType()),
673+
struct_name),
674+
[](const auto *method) {
675+
return !method->isImplicit() && method->isVirtual();
676+
});
677+
}
678+
}
679+
680+
// Traits
681+
if (auto *cxx = clang::dyn_cast<clang::CXXRecordDecl>(decl)) {
682+
AddOrdTrait(cxx);
683+
AddCloneTrait(cxx);
684+
AddDropTrait(cxx);
685+
AddDefaultTrait(cxx);
686+
}
687+
AddByteReprTrait(decl);
688+
}
689+
583690
bool Converter::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) {
584691
if (clang::isa<clang::ClassTemplateSpecializationDecl>(decl)) {
585692
materializeTemplateSpecialization(decl);
@@ -623,74 +730,7 @@ bool Converter::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) {
623730
}
624731
}
625732

626-
auto struct_name = GetRecordName(decl);
627-
628-
// First visit the nested enums
629-
for (auto d : decl->decls()) {
630-
if (auto enum_decl = llvm::dyn_cast<clang::EnumDecl>(d)) {
631-
VisitEnumDecl(enum_decl);
632-
}
633-
}
634-
635-
for (auto *decl : decl->decls()) {
636-
if (auto var_decl = clang::dyn_cast<clang::VarDecl>(decl)) {
637-
VisitVarDecl(var_decl);
638-
}
639-
}
640-
641-
auto nested = GetNestedStructs(decl);
642-
for (auto *record_decl : nested) {
643-
auto ID = GetID(record_decl);
644-
inner_structs_[ID] = GetRecordName(record_decl);
645-
VisitCXXRecordDecl(record_decl);
646-
}
647-
648-
StrCat(token::kHash, token::kOpenBracket, "derive", token::kOpenParen);
649-
bool derives_default = RecordDerivesDefault(decl);
650-
651-
for (auto *struct_attr : GetStructAttributes(decl, derives_default)) {
652-
StrCat(struct_attr, token::kComma);
653-
}
654-
StrCat(token::kCloseParen, token::kCloseBracket);
655-
656-
auto access_specifier = decl->getAccess();
657-
StrCat(AccessSpecifierAsString(access_specifier), keyword::kStruct,
658-
struct_name, token::kOpenCurlyBracket);
659-
for (auto *field : decl->fields()) {
660-
VisitFieldDecl(field);
661-
}
662-
StrCat(token::kCloseCurlyBracket);
663-
664-
ConvertCXXMethodDecls(
665-
decl, std::string(keyword::kImpl) + ' ' + struct_name,
666-
[](const auto *method) {
667-
return !method->isImplicit() &&
668-
!(method->getDefinition() &&
669-
method->getDefinition()->isDefaulted()) &&
670-
(method->isThisDeclarationADefinition() ||
671-
clang::isa<clang::CXXConstructorDecl>(method)) &&
672-
!method->isVirtual() &&
673-
!clang::isa<clang::CXXDestructorDecl>(method);
674-
});
675-
676-
AddOrdTrait(decl);
677-
AddCloneTrait(decl);
678-
AddDropTrait(decl);
679-
if (!derives_default) {
680-
AddDefaultTrait(decl);
681-
}
682-
AddByteReprTrait(decl);
683-
684-
if (decl->bases_begin() != decl->bases_end()) {
685-
ConvertCXXMethodDecls(
686-
decl,
687-
std::format("{} impl {} for {}", keyword_unsafe_,
688-
GetUnsafeTypeAsString(decl->bases_begin()->getType()),
689-
struct_name),
690-
[](const auto *method) {
691-
return !method->isImplicit() && method->isVirtual();
692-
});
693-
}
733+
EmitRustStruct(decl);
694734
} else {
695735
// FIXME: improve error handling
696736
assert(0 && "unsupported union");
@@ -2797,8 +2837,7 @@ std::string Converter::GetRecordName(const clang::NamedDecl *decl) const {
27972837
}
27982838

27992839
std::vector<const char *>
2800-
Converter::GetStructAttributes(const clang::CXXRecordDecl *decl,
2801-
bool &out_impl_default) {
2840+
Converter::GetStructAttributes(const clang::CXXRecordDecl *decl) {
28022841
std::vector<const char *> struct_attrs = {};
28032842

28042843
if (recordDerivesCopy(decl)) {
@@ -3106,11 +3145,14 @@ void Converter::AddCloneTrait(const clang::CXXRecordDecl *decl) {}
31063145
void Converter::AddDropTrait(const clang::CXXRecordDecl *decl) {}
31073146

31083147
void Converter::AddDefaultTrait(const clang::CXXRecordDecl *decl) {
3148+
if (RecordDerivesDefault(decl)) {
3149+
return;
3150+
}
31093151
auto struct_name = GetRecordName(decl);
31103152
StrCat(std::format("impl Default for {}", struct_name),
31113153
token::kOpenCurlyBracket, "fn default() -> Self",
31123154
token::kOpenCurlyBracket);
3113-
if (auto default_ctor = GetUserDefinedDefaultConstructor(decl)) {
3155+
if (auto *default_ctor = GetUserDefinedDefaultConstructor(decl)) {
31143156
StrCat(keyword_unsafe_, token::kOpenCurlyBracket);
31153157
Convert(clang::CXXConstructExpr::Create(
31163158
ctx_, ctx_.getCanonicalTagType(decl), clang::SourceLocation(),
@@ -3133,7 +3175,7 @@ void Converter::AddDefaultTrait(const clang::CXXRecordDecl *decl) {
31333175
StrCat(token::kCloseCurlyBracket, token::kCloseCurlyBracket);
31343176
}
31353177

3136-
void Converter::AddByteReprTrait(const clang::CXXRecordDecl *decl) {}
3178+
void Converter::AddByteReprTrait(const clang::RecordDecl *decl) {}
31373179

31383180
void Converter::ConvertUnsignedArithBinaryOperator(clang::BinaryOperator *op,
31393181
clang::Expr *expr) {

cpp2rust/converter/converter.h

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

9696
virtual bool ConvertLambdaVarDecl(clang::VarDecl *decl);
9797

98+
bool VisitRecordDecl(clang::RecordDecl *decl);
99+
98100
virtual bool VisitCXXRecordDecl(clang::CXXRecordDecl *decl);
99101

102+
void EmitRustStruct(clang::RecordDecl *decl);
103+
100104
virtual bool VisitCXXMethodDecl(clang::CXXMethodDecl *decl);
101105
virtual std::string GetSelfMaybeWithMut(const clang::CXXMethodDecl *decl);
102106

@@ -355,7 +359,7 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
355359
virtual std::string GetRecordName(const clang::NamedDecl *decl) const;
356360

357361
virtual std::vector<const char *>
358-
GetStructAttributes(const clang::CXXRecordDecl *decl, bool &out_impl_default);
362+
GetStructAttributes(const clang::CXXRecordDecl *decl);
359363

360364
virtual std::string GetUnsafeTypeAsString(clang::QualType qual_type) const;
361365

@@ -410,7 +414,7 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
410414

411415
virtual void AddDefaultTrait(const clang::CXXRecordDecl *decl);
412416

413-
virtual void AddByteReprTrait(const clang::CXXRecordDecl *decl);
417+
virtual void AddByteReprTrait(const clang::RecordDecl *decl);
414418

415419
virtual void
416420
ConvertUnsignedArithBinaryOperator(clang::BinaryOperator *binary_operator,

cpp2rust/converter/models/converter_refcount.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ void ConverterRefCount::AddDropTrait(const clang::CXXRecordDecl *decl) {
494494
StrCat("}");
495495
}
496496

497-
void ConverterRefCount::AddByteReprTrait(const clang::CXXRecordDecl *decl) {
497+
void ConverterRefCount::AddByteReprTrait(const clang::RecordDecl *decl) {
498498
auto struct_name = GetRecordName(decl);
499499
StrCat(std::format("impl ByteRepr for {}", struct_name),
500500
token::kOpenCurlyBracket, token::kCloseCurlyBracket);
@@ -1604,11 +1604,10 @@ ConverterRefCount::ConvertVarDefaultInit(clang::QualType qual_type) {
16041604
}
16051605

16061606
std::vector<const char *>
1607-
ConverterRefCount::GetStructAttributes(const clang::CXXRecordDecl *decl,
1608-
bool &out_impl_default) {
1607+
ConverterRefCount::GetStructAttributes(const clang::CXXRecordDecl *decl) {
16091608
std::vector<const char *> attrs = {};
16101609

1611-
if (out_impl_default) {
1610+
if (RecordDerivesDefault(decl)) {
16121611
attrs.emplace_back("Default");
16131612
}
16141613
return attrs;

cpp2rust/converter/models/converter_refcount.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class ConverterRefCount final : public Converter {
3535

3636
void AddDropTrait(const clang::CXXRecordDecl *decl) override;
3737

38-
void AddByteReprTrait(const clang::CXXRecordDecl *decl) override;
38+
void AddByteReprTrait(const clang::RecordDecl *decl) override;
3939

4040
void AddDefaultTrait(const clang::CXXRecordDecl *decl) override;
4141

@@ -121,8 +121,7 @@ class ConverterRefCount final : public Converter {
121121
std::string ConvertVarDefaultInit(clang::QualType qual_type) override;
122122

123123
std::vector<const char *>
124-
GetStructAttributes(const clang::CXXRecordDecl *decl,
125-
bool &out_impl_default) override;
124+
GetStructAttributes(const clang::CXXRecordDecl *decl) override;
126125

127126
bool MayCauseBorrowMutError(const clang::Expr *lhs, const clang::Expr *rhs);
128127

0 commit comments

Comments
 (0)