Skip to content

Commit 296fbd9

Browse files
committed
Remove unneeded Value<T> boxing from constructors
1 parent 2fb31f8 commit 296fbd9

41 files changed

Lines changed: 241 additions & 417 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎cpp2rust/converter/models/converter_refcount.cpp‎

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -581,16 +581,26 @@ bool ConverterRefCount::RecordImplementsClone(const clang::RecordDecl *decl) {
581581
HasCallableCopyConstructor(decl);
582582
}
583583

584+
// Bases are translated to traits, so they hold no state of the struct; they
585+
// only need to be copied without side effects.
586+
static bool HasDefaultedBaseCopies(const clang::CXXRecordDecl *decl) {
587+
return std::ranges::all_of(decl->bases(), [](auto &base) {
588+
auto *record = base.getType()->getAsCXXRecordDecl();
589+
return record && HasDefaultedCopyConstructor(record) &&
590+
HasDefaultedBaseCopies(record);
591+
});
592+
}
593+
584594
bool ConverterRefCount::RecordDerivesClone(const clang::RecordDecl *decl) {
585595
if (HasDefaultedCopyConstructor(decl) && RecordHasOnlyReferenceFields(decl)) {
586596
return true;
587597
}
588598
// The copy of a struct copies each field, which a derived Clone does too,
589599
// except for Values, which it shares.
590600
auto *cxx = clang::dyn_cast<clang::CXXRecordDecl>(decl);
591-
if (decl->isUnion() ||
592-
(cxx && (!HasCallableCopyConstructor(cxx) ||
593-
GetUserDefinedCopyConstructor(cxx) || cxx->getNumBases() > 0))) {
601+
if (decl->isUnion() || (cxx && (!HasCallableCopyConstructor(cxx) ||
602+
GetUserDefinedCopyConstructor(cxx) ||
603+
!HasDefaultedBaseCopies(cxx)))) {
594604
return false;
595605
}
596606
PushConversionKind push(*this, ConversionKind::Pointee);
@@ -611,7 +621,7 @@ bool ConverterRefCount::RecordDerivesDeepClone(const clang::RecordDecl *decl) {
611621
// own clone(), and Values are copied deeply.
612622
auto *cxx = clang::dyn_cast<clang::CXXRecordDecl>(decl);
613623
return !cxx ||
614-
(!GetUserDefinedCopyConstructor(cxx) && cxx->getNumBases() == 0);
624+
(!GetUserDefinedCopyConstructor(cxx) && HasDefaultedBaseCopies(cxx));
615625
}
616626

617627
void ConverterRefCount::AddCloneTrait(const clang::RecordDecl *decl) {
@@ -3146,6 +3156,7 @@ void ConverterRefCount::SetUFCSReceiver(clang::Expr *base, bool is_arrow,
31463156
bool in_ctor =
31473157
curr_function_ && clang::isa<clang::CXXConstructorDecl>(curr_function_);
31483158
if (in_ctor) {
3159+
ctor_uses_this_ = true;
31493160
ufcs_receiver_ = "&this";
31503161
} else if (ThisIsRustPtr()) {
31513162
ufcs_receiver_ = keyword::kSelfValue;
@@ -3307,21 +3318,43 @@ void ConverterRefCount::ConvertCXXConstructorBody(
33073318
clang::CXXConstructorDecl *decl) {
33083319
EmitFunctionPreamble(decl);
33093320
auto record_name = GetRecordName(decl->getParent());
3321+
auto saved_uses_this = std::exchange(ctor_uses_this_, false);
3322+
std::string init;
3323+
{
3324+
Buffer buf(*this);
3325+
if (decl->isDelegatingConstructor()) {
3326+
Convert((*decl->init_begin())->getInit());
3327+
} else {
3328+
StrCat("Self");
3329+
PushBrace this_init(*this);
3330+
EmitConstructorFieldInits(decl);
3331+
}
3332+
init = std::move(buf).str();
3333+
}
3334+
std::string body;
3335+
{
3336+
Buffer buf(*this);
3337+
ConvertBodyStmts(decl->getBody());
3338+
body = std::move(buf).str();
3339+
}
3340+
bool uses_this = std::exchange(ctor_uses_this_, saved_uses_this);
3341+
3342+
if (!uses_this) {
3343+
if (Trim(body).empty()) {
3344+
StrCat(init);
3345+
} else {
3346+
StrCat(keyword::kLet, "__this", token::kColon, record_name,
3347+
token::kAssign, init, token::kSemiColon, body, "__this");
3348+
}
3349+
return;
3350+
}
33103351
StrCat(keyword::kLet, "__this", token::kColon,
33113352
std::format("Value<{}>", record_name), token::kAssign,
3312-
"Rc::new(RefCell::new(");
3313-
if (decl->isDelegatingConstructor()) {
3314-
Convert((*decl->init_begin())->getInit());
3315-
} else {
3316-
StrCat("Self");
3317-
PushBrace this_init(*this);
3318-
EmitConstructorFieldInits(decl);
3319-
}
3320-
StrCat("))", token::kSemiColon);
3353+
std::format("Rc::new(RefCell::new({}))", init), token::kSemiColon);
33213354
StrCat(keyword::kLet, "this", token::kColon,
33223355
std::format("Ptr<{}>", record_name), token::kAssign,
33233356
"__this.as_pointer()", token::kSemiColon);
3324-
ConvertBodyStmts(decl->getBody());
3357+
StrCat(body);
33253358
StrCat("Rc::try_unwrap(__this).ok().unwrap().into_inner()");
33263359
}
33273360

@@ -3338,6 +3371,7 @@ bool ConverterRefCount::VisitCXXThisExpr(
33383371
bool in_ctor =
33393372
curr_function_ && clang::isa<clang::CXXConstructorDecl>(curr_function_);
33403373
if (in_ctor) {
3374+
ctor_uses_this_ = true;
33413375
StrCat("this");
33423376
} else {
33433377
StrCat("(*", keyword::kSelfValue, ')');

‎cpp2rust/converter/models/converter_refcount.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,10 @@ class ConverterRefCount final : public Converter {
412412
bool IsUnboxedVar(const clang::ValueDecl *decl) const;
413413
std::shared_ptr<const BoxedVars> boxed_vars_;
414414

415+
// Set when a constructor's translation refers to `this`, which then needs
416+
// the object being built to be in a Value.
417+
bool ctor_uses_this_ = false;
418+
415419
/// The kind of conversion that should be performed.
416420
enum class ConversionKind : uint8_t {
417421
Unboxed,

‎tests/multi-file/defaulted_move_cross_tu/out/refcount/defaulted_move_cross_tu.rs‎

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,23 @@ pub struct S {
1919
impl S {
2020
pub fn new(x: i32) -> Self {
2121
let x: Value<i32> = Rc::new(RefCell::new(x));
22-
let __this: Value<S> = Rc::new(RefCell::new(Self {
22+
Self {
2323
v: Rc::new(RefCell::new(vec![
2424
(*x.borrow());
2525
((*x.borrow()) as usize) as usize
2626
])),
2727
n: Rc::new(RefCell::new(Box::new([(*x.borrow()), ((*x.borrow()) + 1)]))),
28-
}));
29-
let this: Ptr<S> = __this.as_pointer();
30-
Rc::try_unwrap(__this).ok().unwrap().into_inner()
28+
}
3129
}
3230
pub fn move_from(_a0: Ptr<S>) -> Self {
33-
let __this: Value<S> = Rc::new(RefCell::new(Self {
31+
Self {
3432
v: Rc::new(RefCell::new(std::mem::take(
3533
&mut (*{ (*_a0.upgrade().deref()).v.clone() }.borrow_mut()),
3634
))),
3735
n: Rc::new(RefCell::new(Box::new(std::array::from_fn::<_, 2, _>(
3836
|__i: usize| (*{ (*_a0.upgrade().deref()).n.clone() }.borrow())[(__i) as usize],
3937
)))),
40-
}));
41-
let this: Ptr<S> = __this.as_pointer();
42-
Rc::try_unwrap(__this).ok().unwrap().into_inner()
38+
}
4339
}
4440
}
4541
impl Default for S {

‎tests/multi-file/out_of_line_methods_cross_tu/out/refcount/out_of_line_methods_cross_tu.rs‎

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,13 @@ impl S {}
1616
pub trait Base {
1717
fn apply(&mut self, x: i32) -> i32;
1818
}
19-
#[derive(Record, ByteRepr, VaArg, FnPtrArg, Default)]
19+
#[derive(Clone, Record, ByteRepr, VaArg, FnPtrArg, Default)]
2020
#[byte_size(16)]
2121
pub struct Derived {
2222
#[offset(8)]
2323
pub factor: i32,
2424
}
2525
impl Derived {}
26-
impl Clone for Derived {
27-
fn clone(&self) -> Self {
28-
let __this: Value<Derived> = Rc::new(RefCell::new(Self {
29-
factor: { self.factor },
30-
}));
31-
let this: Ptr<Derived> = __this.as_pointer();
32-
Rc::try_unwrap(__this).ok().unwrap().into_inner()
33-
}
34-
}
3526
pub fn main() {
3627
__cpp2rust_init_globals();
3728
std::process::exit(main_0());
@@ -49,16 +40,12 @@ fn main_0() -> i32 {
4940
}
5041
impl S {
5142
pub fn new(mut x: i32) -> Self {
52-
let __this: Value<S> = Rc::new(RefCell::new(Self { v: x }));
53-
let this: Ptr<S> = __this.as_pointer();
54-
Rc::try_unwrap(__this).ok().unwrap().into_inner()
43+
Self { v: x }
5544
}
5645
}
5746
impl Derived {
5847
pub fn new(mut factor: i32) -> Self {
59-
let __this: Value<Derived> = Rc::new(RefCell::new(Self { factor: factor }));
60-
let this: Ptr<Derived> = __this.as_pointer();
61-
Rc::try_unwrap(__this).ok().unwrap().into_inner()
48+
Self { factor: factor }
6249
}
6350
}
6451
impl S {}

‎tests/ub/out/refcount/ctor_ref_member.rs‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,7 @@ pub struct S {
1515
}
1616
impl S {
1717
pub fn new(x: Ptr<i32>) -> Self {
18-
let __this: Value<S> = Rc::new(RefCell::new(Self { r: (x).clone() }));
19-
let this: Ptr<S> = __this.as_pointer();
20-
Rc::try_unwrap(__this).ok().unwrap().into_inner()
18+
Self { r: (x).clone() }
2119
}
2220
}
2321
pub fn main() {

‎tests/unit/out/refcount/10_struct.rs‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,7 @@ pub struct Partial {
3333
}
3434
impl Partial {
3535
pub fn new_1(mut q: Ptr<i32>) -> Self {
36-
let __this: Value<Partial> = Rc::new(RefCell::new(Self { p: (q).clone() }));
37-
let this: Ptr<Partial> = __this.as_pointer();
38-
Rc::try_unwrap(__this).ok().unwrap().into_inner()
36+
Self { p: (q).clone() }
3937
}
4038
}
4139
impl Default for Partial {

‎tests/unit/out/refcount/constructor.rs‎

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,7 @@ pub struct Point {
3434
}
3535
impl Point {
3636
pub fn new_1(mut x: i32, mut y: i32) -> Self {
37-
let __this: Value<Point> = Rc::new(RefCell::new(Self { x: x, y: y }));
38-
let this: Ptr<Point> = __this.as_pointer();
39-
Rc::try_unwrap(__this).ok().unwrap().into_inner()
37+
Self { x: x, y: y }
4038
}
4139
pub fn new_2(mut v: i32) -> Self {
4240
let __this: Value<Point> = Rc::new(RefCell::new(Point::new_1({ v }, { (v + 1) })));

‎tests/unit/out/refcount/copy_assign.rs‎

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,13 @@ pub struct Partial {
1919
}
2020
impl Partial {
2121
pub fn new(mut v: i32, mut keep: i32) -> Self {
22-
let __this: Value<Partial> = Rc::new(RefCell::new(Self { v: v, keep: keep }));
23-
let this: Ptr<Partial> = __this.as_pointer();
24-
Rc::try_unwrap(__this).ok().unwrap().into_inner()
22+
Self { v: v, keep: keep }
2523
}
2624
pub fn copy_from(o: Ptr<Partial>) -> Self {
27-
let __this: Value<Partial> = Rc::new(RefCell::new(Self {
25+
Self {
2826
v: o.with(|__s| __s.v),
2927
keep: o.with(|__s| __s.keep),
30-
}));
31-
let this: Ptr<Partial> = __this.as_pointer();
32-
Rc::try_unwrap(__this).ok().unwrap().into_inner()
28+
}
3329
}
3430
}
3531
impl Clone for Partial {
@@ -49,9 +45,7 @@ pub struct NonConstAssign {
4945
}
5046
impl NonConstAssign {
5147
pub fn new() -> Self {
52-
let __this: Value<NonConstAssign> = Rc::new(RefCell::new(Self { mark: 0 }));
53-
let this: Ptr<NonConstAssign> = __this.as_pointer();
54-
Rc::try_unwrap(__this).ok().unwrap().into_inner()
48+
Self { mark: 0 }
5549
}
5650
}
5751
impl Default for NonConstAssign {
@@ -67,9 +61,7 @@ pub struct RefQualified {
6761
}
6862
impl RefQualified {
6963
pub fn new() -> Self {
70-
let __this: Value<RefQualified> = Rc::new(RefCell::new(Self { mark: 0 }));
71-
let this: Ptr<RefQualified> = __this.as_pointer();
72-
Rc::try_unwrap(__this).ok().unwrap().into_inner()
64+
Self { mark: 0 }
7365
}
7466
}
7567
impl Default for RefQualified {

‎tests/unit/out/refcount/copy_ctor.rs‎

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,14 @@ pub struct Counted {
1717
}
1818
impl Counted {
1919
pub fn new(mut v: i32) -> Self {
20-
let __this: Value<Counted> = Rc::new(RefCell::new(Self { v: v }));
21-
let this: Ptr<Counted> = __this.as_pointer();
22-
Rc::try_unwrap(__this).ok().unwrap().into_inner()
20+
Self { v: v }
2321
}
2422
pub fn copy_from(o: Ptr<Counted>) -> Self {
25-
let __this: Value<Counted> = Rc::new(RefCell::new(Self {
23+
let __this: Counted = Self {
2624
v: o.with(|__s| __s.v),
27-
}));
28-
let this: Ptr<Counted> = __this.as_pointer();
25+
};
2926
(*copies_0.with(Value::clone).borrow_mut()).prefix_inc();
30-
Rc::try_unwrap(__this).ok().unwrap().into_inner()
27+
__this
3128
}
3229
}
3330
impl Clone for Counted {
@@ -44,23 +41,17 @@ pub struct NonConst {
4441
}
4542
impl NonConst {
4643
pub fn new() -> Self {
47-
let __this: Value<NonConst> = Rc::new(RefCell::new(Self { mark: 0 }));
48-
let this: Ptr<NonConst> = __this.as_pointer();
49-
Rc::try_unwrap(__this).ok().unwrap().into_inner()
44+
Self { mark: 0 }
5045
}
5146
pub fn new_1(o: Ptr<NonConst>) -> Self {
52-
let __this: Value<NonConst> = Rc::new(RefCell::new(Self {
47+
Self {
5348
mark: (o.with(|__s| __s.mark) + 1),
54-
}));
55-
let this: Ptr<NonConst> = __this.as_pointer();
56-
Rc::try_unwrap(__this).ok().unwrap().into_inner()
49+
}
5750
}
5851
pub fn new_2(o: Ptr<NonConst>) -> Self {
59-
let __this: Value<NonConst> = Rc::new(RefCell::new(Self {
52+
Self {
6053
mark: (o.with(|__s| __s.mark) + 10),
61-
}));
62-
let this: Ptr<NonConst> = __this.as_pointer();
63-
Rc::try_unwrap(__this).ok().unwrap().into_inner()
54+
}
6455
}
6556
}
6657
impl Clone for NonConst {
@@ -84,15 +75,12 @@ pub struct Ignored {
8475
}
8576
impl Ignored {
8677
pub fn new(mut v: i32) -> Self {
87-
let __this: Value<Ignored> = Rc::new(RefCell::new(Self { v: v }));
88-
let this: Ptr<Ignored> = __this.as_pointer();
89-
Rc::try_unwrap(__this).ok().unwrap().into_inner()
78+
Self { v: v }
9079
}
9180
pub fn copy_from(_a0: Ptr<Ignored>) -> Self {
92-
let __this: Value<Ignored> = Rc::new(RefCell::new(Self { v: -1_i32 }));
93-
let this: Ptr<Ignored> = __this.as_pointer();
81+
let __this: Ignored = Self { v: -1_i32 };
9482
(*copies_0.with(Value::clone).borrow_mut()).prefix_inc();
95-
Rc::try_unwrap(__this).ok().unwrap().into_inner()
83+
__this
9684
}
9785
}
9886
impl Clone for Ignored {

0 commit comments

Comments
 (0)