Skip to content

Commit c809b02

Browse files
authored
Translate destructors in unsafe (#330)
Fixes #310 Furthermore, droppable types don't implement copy.
1 parent 2d6388a commit c809b02

8 files changed

Lines changed: 607 additions & 9 deletions

File tree

‎cpp2rust/converter/converter.cpp‎

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ bool Converter::VisitFunctionDecl(clang::FunctionDecl *decl) {
348348
return false;
349349
}
350350
decl->dump(log());
351-
curr_function_ = decl;
351+
PushCurrFunction push_fn(*this, decl);
352352
std::string function_name;
353353
if (decl->isMain()) {
354354
function_name = "main_0";
@@ -677,6 +677,10 @@ bool Converter::RecordDerivesCopy(const clang::RecordDecl *decl) const {
677677
}
678678

679679
bool Converter::RecordHasCopyableFields(const clang::RecordDecl *decl) {
680+
if (auto *cxx = clang::dyn_cast<clang::CXXRecordDecl>(decl);
681+
cxx && !cxx->hasTrivialDestructor()) {
682+
return false;
683+
}
680684
for (auto f : decl->fields()) {
681685
// Records that contain std::vector, std::array, std::string or anything
682686
// that is translated to Vec<>, do not derive Copy
@@ -931,7 +935,7 @@ bool Converter::VisitCXXMethodDecl(clang::CXXMethodDecl *decl) {
931935
if (!decl_ids_.insert(GetMethodID(decl)).second) {
932936
return false;
933937
}
934-
curr_function_ = decl;
938+
PushCurrFunction push_fn(*this, decl);
935939

936940
if (decl->isOutOfLine() && !decl->overridden_methods().empty()) {
937941
return false;
@@ -991,7 +995,7 @@ bool Converter::VisitCXXConstructorDecl(clang::CXXConstructorDecl *decl) {
991995
if (decl->isOutOfLine() || decl->isImplicit()) {
992996
return false;
993997
}
994-
curr_function_ = decl;
998+
PushCurrFunction push_fn(*this, decl);
995999

9961000
if (decl->isCopyOrMoveConstructor()) {
9971001
// FIXME: improve error handling
@@ -3279,11 +3283,9 @@ bool Converter::VisitLambdaExpr(clang::LambdaExpr *expr) {
32793283
}
32803284
StrCat("| {");
32813285
EmitFunctionPreamble(expr->getLambdaClass()->getLambdaCallOperator());
3282-
// TODO: replace with a stack
3283-
auto old_function = curr_function_;
3284-
curr_function_ = expr->getLambdaClass()->getLambdaCallOperator();
3286+
PushCurrFunction push_fn(*this,
3287+
expr->getLambdaClass()->getLambdaCallOperator());
32853288
ConvertFunctionBody(curr_function_);
3286-
curr_function_ = old_function;
32873289
StrCat('}');
32883290
return false;
32893291
}
@@ -3969,7 +3971,20 @@ void Converter::AddOrdTrait(const clang::CXXRecordDecl *decl) {
39693971

39703972
void Converter::AddCloneTrait(const clang::RecordDecl *decl) {}
39713973

3972-
void Converter::AddDropTrait(const clang::CXXRecordDecl *decl) {}
3974+
void Converter::AddDropTrait(const clang::CXXRecordDecl *decl) {
3975+
auto *dtor = GetTranslatableDestructor(decl);
3976+
if (!dtor) {
3977+
return;
3978+
}
3979+
PushCurrFunction push_fn(*this, dtor);
3980+
StrCat(keyword::kImpl, "Drop for", GetRecordName(decl));
3981+
PushBrace impl_brace(*this);
3982+
StrCat("fn drop(&mut self)");
3983+
PushBrace fn_brace(*this);
3984+
StrCat(keyword_unsafe_);
3985+
PushBrace unsafe_brace(*this);
3986+
ConvertBodyStmts(dtor->getDefinition()->getBody());
3987+
}
39733988

39743989
void Converter::AddDefaultTraitForUnion(const clang::RecordDecl *decl) {
39753990
StrCat(std::format("impl Default for {}", GetRecordName(decl)));

‎cpp2rust/converter/converter.h‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,16 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
854854

855855
void dump_expr_kinds();
856856

857+
struct PushCurrFunction {
858+
Converter &c;
859+
clang::FunctionDecl *prev;
860+
PushCurrFunction(Converter &c, clang::FunctionDecl *decl)
861+
: c(c), prev(c.curr_function_) {
862+
c.curr_function_ = decl;
863+
}
864+
~PushCurrFunction() { c.curr_function_ = prev; }
865+
};
866+
857867
struct PushExprKind {
858868
Converter &c;
859869
PushExprKind(Converter &c, ExprKind k, const char *file = __builtin_FILE(),

‎cpp2rust/converter/converter_lib.cpp‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,19 @@ const char *GetOverloadedOperator(const clang::FunctionDecl *decl) {
587587
}
588588
}
589589

590+
clang::CXXDestructorDecl *
591+
GetTranslatableDestructor(const clang::CXXRecordDecl *decl) {
592+
if (!IsUserDefinedDecl(decl)) {
593+
return nullptr;
594+
}
595+
auto *dtor = decl->getDestructor();
596+
if (!dtor || dtor->isImplicit()) {
597+
return nullptr;
598+
}
599+
auto *definition = dtor->getDefinition();
600+
return definition && !definition->isDefaulted() ? dtor : nullptr;
601+
}
602+
590603
bool IsOverloadedComparisonOperator(const clang::CXXMethodDecl *decl) {
591604
if (decl->isOverloadedOperator()) {
592605
switch (decl->getOverloadedOperator()) {

‎cpp2rust/converter/converter_lib.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ const char *GetOverloadedOperator(const clang::FunctionDecl *decl);
119119

120120
bool IsOverloadedComparisonOperator(const clang::CXXMethodDecl *decl);
121121

122+
clang::CXXDestructorDecl *
123+
GetTranslatableDestructor(const clang::CXXRecordDecl *decl);
124+
122125
clang::Expr *ToAddrOf(clang::ASTContext &ctx, clang::Expr *expr);
123126

124127
std::vector<clang::CXXRecordDecl *>

‎cpp2rust/converter/models/converter_refcount.cpp‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,10 @@ void ConverterRefCount::AddDropTrait(const clang::CXXRecordDecl *decl) {
586586

587587
StrCat(keyword::kImpl, "Drop for", record_name, '{');
588588
StrCat("fn drop(&mut self)");
589-
ConvertBody(body);
589+
{
590+
PushCurrFunction push_fn(*this, dtor);
591+
ConvertBody(body);
592+
}
590593
StrCat('}');
591594
}
592595

‎tests/unit/destructor.cpp‎

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#include <cassert>
2+
3+
int global = 0;
4+
5+
struct S {
6+
~S() { global++; }
7+
};
8+
9+
struct Defaulted {
10+
S s;
11+
~Defaulted() = default;
12+
};
13+
14+
struct Middle {
15+
S s;
16+
};
17+
18+
struct Outer {
19+
Middle m;
20+
};
21+
22+
struct ArrayMember {
23+
S items[3];
24+
};
25+
26+
struct EmptyBody {
27+
S s;
28+
~EmptyBody() {}
29+
};
30+
31+
template <typename T> struct Templated {
32+
T v;
33+
~Templated() { global += sizeof(T); }
34+
};
35+
36+
struct Copied {
37+
int v;
38+
~Copied() { global++; }
39+
};
40+
41+
int main() {
42+
{
43+
S s{};
44+
}
45+
assert(global == 1);
46+
47+
{
48+
S s{};
49+
}
50+
assert(global == 2);
51+
52+
{
53+
Defaulted d{};
54+
}
55+
assert(global == 3);
56+
57+
{
58+
Outer o{};
59+
}
60+
assert(global == 4);
61+
62+
{
63+
ArrayMember am{};
64+
}
65+
assert(global == 7);
66+
67+
{
68+
EmptyBody e{};
69+
}
70+
assert(global == 8);
71+
72+
{
73+
Templated<char> tc{};
74+
Templated<int> ti{};
75+
}
76+
assert(global == 13);
77+
78+
{
79+
Copied a{5};
80+
Copied b = a;
81+
assert(b.v == 5);
82+
}
83+
assert(global == 15);
84+
85+
return 0;
86+
}

0 commit comments

Comments
 (0)