Skip to content

Commit f2f97e4

Browse files
committed
Defer the emission of vtable impls to the end of the file
1 parent 18f3057 commit f2f97e4

5 files changed

Lines changed: 94 additions & 33 deletions

File tree

‎cpp2rust/converter/converter.cpp‎

Lines changed: 61 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ std::vector<std::string> Converter::global_inits_;
3030
std::unordered_set<std::string> Converter::abstract_structs_;
3131
Converter::RecordIndex Converter::record_decls_;
3232
std::map<std::string, Converter::MethodsOnPtr> Converter::methods_on_ptr_;
33+
std::map<std::string, Converter::DeferredBlock> Converter::vtable_impls_;
3334

3435
void Converter::ConvertUniquePtrDeref(clang::CXXOperatorCallExpr *expr) {
3536
bool is_star = expr->getOperator() == clang::OverloadedOperatorKind::OO_Star;
@@ -60,16 +61,24 @@ use std::rc::Rc;
6061
)");
6162
}
6263

64+
void Converter::EmitDeferredBlock(const DeferredBlock &block,
65+
std::string &out) {
66+
out += block.header;
67+
out += " {\n";
68+
out += block.body;
69+
out += "}\n";
70+
}
71+
72+
void Converter::EmitVTableImpls(std::string &out) {
73+
for (const auto &[name, impl] : vtable_impls_) {
74+
EmitDeferredBlock(impl, out);
75+
}
76+
}
77+
6378
void Converter::EmitMethodsOnPtr(std::string &out) {
6479
for (const auto &[name, methods] : methods_on_ptr_) {
65-
out += methods.trait_header;
66-
out += " {\n";
67-
out += methods.trait_body;
68-
out += "}\n";
69-
out += methods.impl_header;
70-
out += " {\n";
71-
out += methods.impl_body;
72-
out += "}\n";
80+
EmitDeferredBlock(methods.trait, out);
81+
EmitDeferredBlock(methods.impl, out);
7382
}
7483
}
7584

@@ -866,20 +875,8 @@ void Converter::EmitRustStructOrUnion(clang::RecordDecl *decl) {
866875

867876
// C++ method decls
868877
if (auto *cxx = clang::dyn_cast<clang::CXXRecordDecl>(decl)) {
869-
auto struct_name = GetRecordName(cxx);
870-
871878
ConvertCXXRecordMethods(cxx);
872-
873-
if (cxx->bases_begin() != cxx->bases_end()) {
874-
ConvertCXXMethodDecls(
875-
cxx,
876-
std::format("{} impl {} for {}", keyword_unsafe_,
877-
GetUnsafeTypeAsString(cxx->bases_begin()->getType()),
878-
struct_name),
879-
[](auto *method) {
880-
return !method->isImplicit() && method->isVirtual();
881-
});
882-
}
879+
ConvertVTableMethods(cxx);
883880
}
884881

885882
// Traits
@@ -1076,7 +1073,7 @@ bool Converter::VisitCXXMethodDecl(clang::CXXMethodDecl *decl) {
10761073
PushCurrFunction push_fn(*this, decl);
10771074

10781075
if (decl->isOutOfLine() && !decl->overridden_methods().empty()) {
1079-
return false;
1076+
return ConvertVTableMethod(decl);
10801077
}
10811078
if (decl->isOutOfLine() && !decl->isTemplateInstantiation()) {
10821079
return ConvertOutOfLineMethod(decl);
@@ -4475,6 +4472,48 @@ void Converter::ConvertCXXMethodDecls(
44754472
}
44764473
}
44774474

4475+
Converter::DeferredBlock &
4476+
Converter::VTableImplFor(const clang::CXXRecordDecl *decl) {
4477+
auto name = GetRecordName(decl);
4478+
auto [it, inserted] = vtable_impls_.try_emplace(name);
4479+
if (inserted) {
4480+
it->second.header = std::format(
4481+
"{} impl {} for {}", keyword_unsafe_,
4482+
GetUnsafeTypeAsString(decl->bases_begin()->getType()), name);
4483+
}
4484+
return it->second;
4485+
}
4486+
4487+
void Converter::ConvertVTableMethods(clang::CXXRecordDecl *decl) {
4488+
if (decl->bases_begin() == decl->bases_end()) {
4489+
return;
4490+
}
4491+
bool any = false;
4492+
Buffer buf(*this);
4493+
for (auto *method : decl->methods()) {
4494+
if (!method->isImplicit() && method->isVirtual()) {
4495+
any = true;
4496+
VisitCXXMethodDecl(method);
4497+
}
4498+
}
4499+
auto body = std::move(buf).str();
4500+
if (!any) {
4501+
return;
4502+
}
4503+
VTableImplFor(decl).body += body;
4504+
}
4505+
4506+
bool Converter::ConvertVTableMethod(clang::CXXMethodDecl *decl) {
4507+
auto *record = decl->getParent();
4508+
if (record->bases_begin() == record->bases_end()) {
4509+
return false;
4510+
}
4511+
Buffer buf(*this);
4512+
auto emitted = ConvertCXXMethodDecl(decl);
4513+
VTableImplFor(record).body += std::move(buf).str();
4514+
return emitted;
4515+
}
4516+
44784517
void Converter::ConvertOrdAndPartialOrdTraitsBase(
44794518
std::string_view cmp_body, std::string_view eq_body,
44804519
std::string_view record_name) {

‎cpp2rust/converter/converter.h‎

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
5757

5858
static void EmitMethodsOnPtr(std::string &out);
5959

60+
static void EmitVTableImpls(std::string &out);
61+
6062
virtual bool VisitBuiltinType(clang::BuiltinType *type);
6163

6264
virtual bool VisitRecordType(clang::RecordType *type);
@@ -603,6 +605,10 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
603605
const std::string_view signature,
604606
bool (*predicate)(clang::CXXMethodDecl *));
605607

608+
void ConvertVTableMethods(clang::CXXRecordDecl *decl);
609+
610+
bool ConvertVTableMethod(clang::CXXMethodDecl *decl);
611+
606612
void AddOrdTrait(const clang::CXXRecordDecl *decl);
607613

608614
void ConvertOrdAndPartialOrdTraits(const clang::CXXRecordDecl *decl,
@@ -906,16 +912,25 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
906912
std::unordered_map<std::string, bool> entries_;
907913
};
908914
static RecordIndex record_decls_;
915+
struct DeferredBlock {
916+
std::string header;
917+
std::string body;
918+
};
909919
struct MethodsOnPtr {
910-
std::string trait_header;
911-
std::string trait_body;
912-
std::string impl_header;
913-
std::string impl_body;
920+
DeferredBlock trait;
921+
DeferredBlock impl;
914922
};
915923
// record name -> trait and impl for Ptr<record>, emitted after all
916924
// translation units.
917925
static std::map<std::string, MethodsOnPtr> methods_on_ptr_;
918926

927+
static std::map<std::string, DeferredBlock> vtable_impls_;
928+
929+
static void EmitDeferredBlock(const DeferredBlock &block,
930+
std::string &out);
931+
932+
DeferredBlock &VTableImplFor(const clang::CXXRecordDecl *decl);
933+
919934
std::string hoisted_records_;
920935

921936
enum class ExprKind : uint8_t {

‎cpp2rust/converter/models/converter_refcount.cpp‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2884,8 +2884,8 @@ ConverterRefCount::MethodsOnPtrFor(const clang::CXXRecordDecl *decl) {
28842884
auto name = GetRecordName(decl);
28852885
auto [it, inserted] = methods_on_ptr_.try_emplace(name);
28862886
if (inserted) {
2887-
it->second.trait_header = std::format("pub trait {}", TraitName(decl));
2888-
it->second.impl_header =
2887+
it->second.trait.header = std::format("pub trait {}", TraitName(decl));
2888+
it->second.impl.header =
28892889
std::format("impl {} for Ptr<{}>", TraitName(decl), name);
28902890
}
28912891
return it->second;
@@ -2900,7 +2900,7 @@ bool ConverterRefCount::ConvertOutOfLineMethod(clang::CXXMethodDecl *decl) {
29002900
PushMethodTarget push(*this, MethodTarget::PtrImpl);
29012901
ConvertCXXMethodDecl(decl);
29022902
}
2903-
MethodsOnPtrFor(decl->getParent()).impl_body += std::move(buf).str();
2903+
MethodsOnPtrFor(decl->getParent()).impl.body += std::move(buf).str();
29042904
return false;
29052905
}
29062906

@@ -2914,7 +2914,7 @@ void ConverterRefCount::ConvertMethodOnPtrTraitDecl(
29142914
: MethodTarget::TraitDefault);
29152915
ConvertCXXMethodDecl(method);
29162916
}
2917-
MethodsOnPtrFor(method->getParent()).trait_body += std::move(buf).str();
2917+
MethodsOnPtrFor(method->getParent()).trait.body += std::move(buf).str();
29182918
}
29192919

29202920
void ConverterRefCount::ConvertMethodOnPtr(clang::CXXMethodDecl *method) {
@@ -2926,7 +2926,7 @@ void ConverterRefCount::ConvertMethodOnPtr(clang::CXXMethodDecl *method) {
29262926
PushMethodTarget push(*this, MethodTarget::PtrImpl);
29272927
VisitCXXMethodDecl(method);
29282928
}
2929-
MethodsOnPtrFor(method->getParent()).impl_body += std::move(buf).str();
2929+
MethodsOnPtrFor(method->getParent()).impl.body += std::move(buf).str();
29302930
}
29312931

29322932
void ConverterRefCount::ConvertLateInstantiatedMethods(
@@ -2971,9 +2971,9 @@ void ConverterRefCount::ConvertCXXRecordMethods(clang::CXXRecordDecl *decl) {
29712971
ForEachTemplateInstantiatedMethod(decl, convert_method);
29722972

29732973
if (!GetUserDefinedDestructor(decl) && HasFieldsNeedingDestruction(decl)) {
2974-
MethodsOnPtrFor(decl).trait_body +=
2974+
MethodsOnPtrFor(decl).trait.body +=
29752975
std::format("fn {}(&self);\n", kDestructorName);
2976-
MethodsOnPtrFor(decl).impl_body += std::format(
2976+
MethodsOnPtrFor(decl).impl.body += std::format(
29772977
"fn {}(&self) {{ {} }}\n", kDestructorName, DestroyMembers(decl));
29782978
}
29792979
}

‎cpp2rust/converter/models/converter_refcount.h‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,10 +242,15 @@ class ConverterRefCount final : public Converter {
242242
private:
243243
void SetUFCSReceiver(clang::Expr *base, bool is_arrow,
244244
const clang::CXXMethodDecl *method) override;
245+
245246
std::string GetUFCSName(const clang::CXXMethodDecl *method) const override;
247+
246248
std::string TraitName(const clang::CXXRecordDecl *decl) const;
249+
247250
MethodsOnPtr &MethodsOnPtrFor(const clang::CXXRecordDecl *decl);
251+
248252
std::string DestroyMembers(const clang::CXXRecordDecl *decl) override;
253+
249254
void EmitScopedDestructor(const clang::VarDecl *decl) override;
250255

251256
std::pair<std::string, std::string>

‎cpp2rust/cpp2rust_lib.cpp‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ std::string TranspileSrc(std::string_view cc_code, Model model,
3131
cc_code, tool_args, std::filesystem::path(filename).filename().string(),
3232
filename.ends_with(".c") ? CLANG_C_COMPILER : CLANG_CXX_COMPILER);
3333
Converter::EmitOpaqueRecords(rs_code);
34+
Converter::EmitVTableImpls(rs_code);
3435
Converter::EmitMethodsOnPtr(rs_code);
3536
Converter::EmitGlobalInits(model, rs_code);
3637
return rs_code;
@@ -73,6 +74,7 @@ std::string TranspileDir(std::string_view build_dir, Model model,
7374
FrontendActionFactory factory(rs_code, model, rules_dir);
7475
Tool.run(&factory);
7576
Converter::EmitOpaqueRecords(rs_code);
77+
Converter::EmitVTableImpls(rs_code);
7678
Converter::EmitMethodsOnPtr(rs_code);
7779
Converter::EmitGlobalInits(model, rs_code);
7880
return rs_code;

0 commit comments

Comments
 (0)