diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index d60d3f2b..c961dd32 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -640,6 +640,10 @@ bool Converter::RecordDerivesDefault(const clang::RecordDecl *decl) { } for (auto f : decl->fields()) { + if (f->hasInClassInitializer()) { + return false; + } + // Records that contain function pointer do not derive Default if (auto ptr_ty = f->getType()->getAs()) { if (ptr_ty->getPointeeType()->isFunctionType()) { @@ -4306,8 +4310,13 @@ void Converter::EmitDefaultStructLiteral(const clang::RecordDecl *decl) { StrCat(GetRecordName(decl)); PushBrace brace(*this); for (auto *field : decl->fields()) { - StrCat(GetNamedDeclAsString(field), token::kColon, - GetDefaultAsString(field->getType()), token::kComma); + StrCat(GetNamedDeclAsString(field), token::kColon); + if (auto *init = field->getInClassInitializer()) { + ConvertVarInit(field->getType(), init); + } else { + StrCat(GetDefaultAsString(field->getType())); + } + StrCat(token::kComma); } } diff --git a/tests/multi-file/template_method_late_instantiation/out/refcount/template_method_late_instantiation.rs b/tests/multi-file/template_method_late_instantiation/out/refcount/template_method_late_instantiation.rs index 285f4984..609855ac 100644 --- a/tests/multi-file/template_method_late_instantiation/out/refcount/template_method_late_instantiation.rs +++ b/tests/multi-file/template_method_late_instantiation/out/refcount/template_method_late_instantiation.rs @@ -6,7 +6,7 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Default)] +#[derive()] pub struct S_int_ { pub x: Value, } @@ -19,6 +19,13 @@ impl Clone for S_int_ { Rc::try_unwrap(__this).ok().unwrap().into_inner() } } +impl Default for S_int_ { + fn default() -> Self { + S_int_ { + x: Rc::new(RefCell::new(0)), + } + } +} impl ByteRepr for S_int_ { fn byte_size() -> usize { 4 diff --git a/tests/multi-file/template_method_late_instantiation/out/unsafe/template_method_late_instantiation.rs b/tests/multi-file/template_method_late_instantiation/out/unsafe/template_method_late_instantiation.rs index 880214e0..352b9ad2 100644 --- a/tests/multi-file/template_method_late_instantiation/out/unsafe/template_method_late_instantiation.rs +++ b/tests/multi-file/template_method_late_instantiation/out/unsafe/template_method_late_instantiation.rs @@ -7,7 +7,7 @@ use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; #[repr(C)] -#[derive(Copy, Clone, Default)] +#[derive(Copy, Clone)] pub struct S_int_ { pub x: i32, } @@ -16,6 +16,11 @@ impl S_int_ { self.x = v; } } +impl Default for S_int_ { + fn default() -> Self { + S_int_ { x: 0 } + } +} pub fn main() { unsafe { std::process::exit(main_0() as i32); diff --git a/tests/unit/in_class_field_initializer.cpp b/tests/unit/in_class_field_initializer.cpp new file mode 100644 index 00000000..70015ccf --- /dev/null +++ b/tests/unit/in_class_field_initializer.cpp @@ -0,0 +1,41 @@ +#include +#include + +struct Inner { + int x = 3; + int y = 4; +}; + +struct S { + int a = 1; + char b = 2; + Inner c = {}; + Inner d; +}; + +// Boxed::tag is in-class initialized. However the default constructor is never +// instantiated, only the explicit one is used. +// +// Because no default constructor is instantiated, the specialization does not +// contain the in-class initializer. In Rust, the Default trait initializes +// Boxed::tag with 0. This is correct because the C++ program never reads the +// in-class initializer of Boxed::tag, hence Rust also does not read it. +template struct Boxed { + T v = T(); + int tag = 7; + Boxed(T x, int t) : v(x), tag(t) {} +}; + +int main() { + S s; + assert(s.a == 1); + assert(s.b == 2); + assert(s.c.x == 3); + assert(s.c.y == 4); + assert(s.d.x == 3); + assert(s.d.y == 4); + Boxed boxed(5, 9); + assert(boxed.v == 5); + assert(boxed.tag == 9); + return 0; +}; diff --git a/tests/unit/out/refcount/array_of_noncopy_struct.rs b/tests/unit/out/refcount/array_of_noncopy_struct.rs index 93f13175..43229f4b 100644 --- a/tests/unit/out/refcount/array_of_noncopy_struct.rs +++ b/tests/unit/out/refcount/array_of_noncopy_struct.rs @@ -6,7 +6,7 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Default)] +#[derive()] pub struct NonCopy { pub data: Value>, pub tag: Value, @@ -21,6 +21,14 @@ impl Clone for NonCopy { Rc::try_unwrap(__this).ok().unwrap().into_inner() } } +impl Default for NonCopy { + fn default() -> Self { + NonCopy { + data: Rc::new(RefCell::new(Default::default())), + tag: Rc::new(RefCell::new(0)), + } + } +} impl ByteRepr for NonCopy { fn byte_size() -> usize { 32 diff --git a/tests/unit/out/refcount/in_class_field_initializer.rs b/tests/unit/out/refcount/in_class_field_initializer.rs new file mode 100644 index 00000000..3d211be2 --- /dev/null +++ b/tests/unit/out/refcount/in_class_field_initializer.rs @@ -0,0 +1,163 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +#[derive()] +pub struct Inner { + pub x: Value, + pub y: Value, +} +impl Clone for Inner { + 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 Inner { + fn default() -> Self { + Inner { + x: Rc::new(RefCell::new(3)), + y: Rc::new(RefCell::new(4)), + } + } +} +impl ByteRepr for Inner { + 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]))), + } + } +} +#[derive()] +pub struct S { + pub a: Value, + pub b: Value, + pub c: Value, + pub d: Value, +} +impl Clone for S { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + a: Rc::new(RefCell::new((*self.a.borrow()))), + b: Rc::new(RefCell::new((*self.b.borrow()))), + c: Rc::new(RefCell::new((*self.c.borrow()).clone())), + d: Rc::new(RefCell::new((*self.d.borrow()).clone())), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl Default for S { + fn default() -> Self { + S { + a: Rc::new(RefCell::new(1)), + b: Rc::new(RefCell::new(2_u8)), + c: Rc::new(RefCell::new(Inner { + x: Rc::new(RefCell::new(3)), + y: Rc::new(RefCell::new(4)), + })), + d: >::default(), + } + } +} +impl ByteRepr for S { + fn byte_size() -> usize { + 24 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.a.borrow()).to_bytes(&mut buf[0..4]); + (*self.b.borrow()).to_bytes(&mut buf[4..5]); + (*self.c.borrow()).to_bytes(&mut buf[8..16]); + (*self.d.borrow()).to_bytes(&mut buf[16..24]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + a: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + b: Rc::new(RefCell::new(::from_bytes(&buf[4..5]))), + c: Rc::new(RefCell::new(::from_bytes(&buf[8..16]))), + d: Rc::new(RefCell::new(::from_bytes(&buf[16..24]))), + } + } +} +#[derive()] +pub struct Boxed_int_ { + pub v: Value, + pub tag: Value, +} +impl Boxed_int_ { + pub fn Boxed_int_(x: i32, t: i32) -> Self { + let x: Value = Rc::new(RefCell::new(x)); + let t: Value = Rc::new(RefCell::new(t)); + let __this: Value = Rc::new(RefCell::new(Self { + v: Rc::new(RefCell::new((*x.borrow()))), + tag: Rc::new(RefCell::new((*t.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl Clone for Boxed_int_ { + fn clone(&self) -> Self { + let __this: Value = Rc::new(RefCell::new(Self { + v: Rc::new(RefCell::new((*self.v.borrow()))), + tag: Rc::new(RefCell::new((*self.tag.borrow()))), + })); + let this: Ptr = __this.as_pointer(); + Rc::try_unwrap(__this).ok().unwrap().into_inner() + } +} +impl Default for Boxed_int_ { + fn default() -> Self { + Boxed_int_ { + v: >::default(), + tag: >::default(), + } + } +} +impl ByteRepr for Boxed_int_ { + fn byte_size() -> usize { + 8 + } + fn to_bytes(&self, buf: &mut [u8]) { + (*self.v.borrow()).to_bytes(&mut buf[0..4]); + (*self.tag.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + v: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + tag: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let s: Value = Rc::new(RefCell::new(::default())); + assert!(((*(*s.borrow()).a.borrow()) == 1)); + assert!((((*(*s.borrow()).b.borrow()) as i32) == 2)); + assert!(((*(*(*s.borrow()).c.borrow()).x.borrow()) == 3)); + assert!(((*(*(*s.borrow()).c.borrow()).y.borrow()) == 4)); + assert!(((*(*(*s.borrow()).d.borrow()).x.borrow()) == 3)); + assert!(((*(*(*s.borrow()).d.borrow()).y.borrow()) == 4)); + let boxed: Value = Rc::new(RefCell::new(Boxed_int_::Boxed_int_({ 5 }, { 9 }))); + assert!(((*(*boxed.borrow()).v.borrow()) == 5)); + assert!(((*(*boxed.borrow()).tag.borrow()) == 9)); + return 0; +} diff --git a/tests/unit/out/unsafe/array_of_noncopy_struct.rs b/tests/unit/out/unsafe/array_of_noncopy_struct.rs index 7fedfe8c..ba020323 100644 --- a/tests/unit/out/unsafe/array_of_noncopy_struct.rs +++ b/tests/unit/out/unsafe/array_of_noncopy_struct.rs @@ -7,11 +7,19 @@ use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; #[repr(C)] -#[derive(Clone, Default)] +#[derive(Clone)] pub struct NonCopy { pub data: Vec, pub tag: i32, } +impl Default for NonCopy { + fn default() -> Self { + NonCopy { + data: Default::default(), + tag: 0, + } + } +} pub fn main() { unsafe { std::process::exit(main_0() as i32); diff --git a/tests/unit/out/unsafe/in_class_field_initializer.rs b/tests/unit/out/unsafe/in_class_field_initializer.rs new file mode 100644 index 00000000..5707c8b0 --- /dev/null +++ b/tests/unit/out/unsafe/in_class_field_initializer.rs @@ -0,0 +1,75 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Inner { + pub x: i32, + pub y: i32, +} +impl Default for Inner { + fn default() -> Self { + Inner { x: 3, y: 4 } + } +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct S { + pub a: i32, + pub b: libc::c_char, + pub c: Inner, + pub d: Inner, +} +impl Default for S { + fn default() -> Self { + S { + a: 1, + b: (2 as libc::c_char), + c: Inner { x: 3, y: 4 }, + d: ::default(), + } + } +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Boxed_int_ { + pub v: i32, + pub tag: i32, +} +impl Boxed_int_ { + pub unsafe fn Boxed_int_(mut x: i32, mut t: i32) -> Self { + let mut this = Self { v: x, tag: t }; + this + } +} +impl Default for Boxed_int_ { + fn default() -> Self { + Boxed_int_ { + v: 0_i32, + tag: 0_i32, + } + } +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut s: S = ::default(); + assert!(((s.a) == (1))); + assert!(((s.b as i32) == (2))); + assert!(((s.c.x) == (3))); + assert!(((s.c.y) == (4))); + assert!(((s.d.x) == (3))); + assert!(((s.d.y) == (4))); + let mut boxed: Boxed_int_ = Boxed_int_::Boxed_int_({ 5 }, { 9 }); + assert!(((boxed.v) == (5))); + assert!(((boxed.tag) == (9))); + return 0; +}