diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index db7b4d6dc..a242907f2 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1165,8 +1165,11 @@ bool Converter::VisitCXXConstructorDecl(clang::CXXConstructorDecl *decl) { void Converter::ConvertCXXConstructorBody(clang::CXXConstructorDecl *decl) { EmitFunctionPreamble(decl); - StrCat(keyword::kLet, "mut", "this", token::kAssign, "Self"); - { + StrCat(keyword::kLet, "mut", "this", token::kAssign); + if (decl->isDelegatingConstructor()) { + Convert((*decl->init_begin())->getInit()); + } else { + StrCat("Self"); PushBrace this_init(*this); EmitConstructorFieldInits(decl); } @@ -1182,26 +1185,23 @@ void Converter::EmitConstructorFieldInits(clang::CXXConstructorDecl *decl) { assert(definition_or_null); auto *definition = clang::cast(definition_or_null); - bool has_inits = !definition->inits().empty(); - auto **ctor_initializer_list = definition->inits().begin(); - int curr_init = - has_inits ? (ctor_initializer_list[0]->isBaseInitializer() ? 1 : 0) : 0; - for (const auto *field : record_decl->fields()) { auto field_name = GetNamedDeclAsString(field); auto field_type = field->getType(); - auto *ctor_initializer = - has_inits ? ctor_initializer_list[curr_init] : nullptr; + const clang::CXXCtorInitializer *ctor_initializer = nullptr; + for (const auto *init : definition->inits()) { + if (init->isMemberInitializer() && init->getMember() == field) { + ctor_initializer = init; + break; + } + } - if (has_inits && - GetNamedDeclAsString(ctor_initializer->getMember()) == field_name) { - auto *ctor_init_expr = ctor_initializer->getInit(); + if (ctor_initializer) { StrCat(field_name, token::kColon); - ConvertVarInit(field_type, ctor_init_expr); - curr_init = (curr_init + 1) % definition->getNumCtorInitializers(); - } else if (field->hasInClassInitializer()) { + ConvertVarInit(field_type, ctor_initializer->getInit()); + } else if (auto *init = field->getInClassInitializer()) { StrCat(field_name, token::kColon); - ConvertVarInit(field_type, field->getInClassInitializer()); + ConvertVarInit(field_type, init); } else { StrCat(field_name, token::kColon, GetDefaultAsString(field_type)); } diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 54b0e0b54..7104ce044 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -2959,8 +2959,11 @@ void ConverterRefCount::ConvertCXXConstructorBody( auto record_name = GetRecordName(decl->getParent()); StrCat(keyword::kLet, "__this", token::kColon, std::format("Value<{}>", record_name), token::kAssign, - "Rc::new(RefCell::new(Self"); - { + "Rc::new(RefCell::new("); + if (decl->isDelegatingConstructor()) { + Convert((*decl->init_begin())->getInit()); + } else { + StrCat("Self"); PushBrace this_init(*this); EmitConstructorFieldInits(decl); } diff --git a/tests/unit/constructor.cpp b/tests/unit/constructor.cpp index 660b64d1f..6cd1b2f3c 100644 --- a/tests/unit/constructor.cpp +++ b/tests/unit/constructor.cpp @@ -18,6 +18,14 @@ struct S { } }; +struct Point { + int x; + int y; + Point(int x, int y) : x(x), y(y) {} + Point(int v) : Point(v, v + 1) { y *= 10; } + Point() : Point(4) { x += 100; } +}; + int main() { { S s(3); @@ -25,5 +33,11 @@ int main() { assert(total == 8); } assert(total == 18); + Point p; + assert(p.x == 104); + assert(p.y == 50); + Point q(7); + assert(q.x == 7); + assert(q.y == 80); return 0; } diff --git a/tests/unit/out/refcount/constructor.rs b/tests/unit/out/refcount/constructor.rs index e53aaaf01..7a29963fd 100644 --- a/tests/unit/out/refcount/constructor.rs +++ b/tests/unit/out/refcount/constructor.rs @@ -47,6 +47,68 @@ impl ByteRepr for S { } } } +#[derive()] +pub struct Point { + pub x: Value, + pub y: Value, +} +impl Point { + pub fn Point1(x: i32, y: i32) -> Self { + let x: Value = Rc::new(RefCell::new(x)); + let y: Value = Rc::new(RefCell::new(y)); + let __this: Value = Rc::new(RefCell::new(Self { + x: Rc::new(RefCell::new((*x.borrow()))), + y: Rc::new(RefCell::new((*y.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } + pub fn Point2(v: i32) -> Self { + let v: Value = Rc::new(RefCell::new(v)); + let __this: Value = Rc::new(RefCell::new(Point::Point1({ (*v.borrow()) }, { + ((*v.borrow()) + 1) + }))); + let this: Ptr = __this.as_pointer(); + (*(*this.upgrade().deref()).y.borrow_mut()) *= 10; + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } + pub fn Point3() -> Self { + let __this: Value = Rc::new(RefCell::new(Point::Point2({ 4 }))); + let this: Ptr = __this.as_pointer(); + (*(*this.upgrade().deref()).x.borrow_mut()) += 100; + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl Clone for Point { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + x: Rc::new(RefCell::new((*self.x.borrow()))), + y: Rc::new(RefCell::new((*self.y.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl Default for Point { + fn default() -> Self { + { Point::Point3() } + } +} +impl ByteRepr for Point { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.x.borrow()).to_bytes(&mut buf[0..4]); + (*self.y.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + x: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + y: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} pub fn main() { __cpp2rust_init_globals(); std::process::exit(main_0()); @@ -59,6 +121,12 @@ fn main_0() -> i32 { assert!((total_0.with(|rc| *rc.borrow()) == 8)); } assert!((total_0.with(|rc| *rc.borrow()) == 18)); + let p: Value = Rc::new(RefCell::new(Point::Point3())); + assert!(((*(*p.borrow()).x.borrow()) == 104)); + assert!(((*(*p.borrow()).y.borrow()) == 50)); + let q: Value = Rc::new(RefCell::new(Point::Point2({ 7 }))); + assert!(((*(*q.borrow()).x.borrow()) == 7)); + assert!(((*(*q.borrow()).y.borrow()) == 80)); return 0; } pub trait SImpl { diff --git a/tests/unit/out/unsafe/constructor.rs b/tests/unit/out/unsafe/constructor.rs index 77b3345ad..9b4747381 100644 --- a/tests/unit/out/unsafe/constructor.rs +++ b/tests/unit/out/unsafe/constructor.rs @@ -32,6 +32,33 @@ impl S { (unsafe { S::const_method(self) }); } } +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Point { + pub x: i32, + pub y: i32, +} +impl Point { + pub unsafe fn Point1(mut x: i32, mut y: i32) -> Self { + let mut this = Self { x: x, y: y }; + this + } + pub unsafe fn Point2(mut v: i32) -> Self { + let mut this = Point::Point1({ v }, { ((v) + (1)) }); + this.y *= 10; + this + } + pub unsafe fn Point3() -> Self { + let mut this = Point::Point2({ 4 }); + this.x += 100; + this + } +} +impl Default for Point { + fn default() -> Self { + unsafe { Point::Point3() } + } +} pub fn main() { unsafe { __cpp2rust_init_globals(); @@ -46,6 +73,12 @@ unsafe fn main_0() -> i32 { assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut total_0)) == (8))); } assert!(((*std::cell::LazyCell::force_mut(&mut *&raw mut total_0)) == (18))); + let mut p: Point = Point::Point3(); + assert!(((p.x) == (104))); + assert!(((p.y) == (50))); + let mut q: Point = Point::Point2({ 7 }); + assert!(((q.x) == (7))); + assert!(((q.y) == (80))); return 0; } pub unsafe fn __cpp2rust_init_globals() {