Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<clang::PointerType>()) {
if (ptr_ty->getPointeeType()->isFunctionType()) {
Expand Down Expand Up @@ -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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<i32>,
}
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand All @@ -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);
Expand Down
41 changes: 41 additions & 0 deletions tests/unit/in_class_field_initializer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include <cassert>
#include <string>

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 <typename T> 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<int> boxed(5, 9);
assert(boxed.v == 5);
assert(boxed.tag == 9);
return 0;
};
10 changes: 9 additions & 1 deletion tests/unit/out/refcount/array_of_noncopy_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<i32>>,
pub tag: Value<i32>,
Expand All @@ -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
Expand Down
163 changes: 163 additions & 0 deletions tests/unit/out/refcount/in_class_field_initializer.rs
Original file line number Diff line number Diff line change
@@ -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<i32>,
pub y: Value<i32>,
}
impl Clone for Inner {
fn clone(&self) -> Self {
let __this: Value<Inner> = Rc::new(RefCell::new(Self {
x: Rc::new(RefCell::new((*self.x.borrow()))),
y: Rc::new(RefCell::new((*self.y.borrow()))),
}));
let this: Ptr<Inner> = __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(<i32>::from_bytes(&buf[0..4]))),
y: Rc::new(RefCell::new(<i32>::from_bytes(&buf[4..8]))),
}
}
}
#[derive()]
pub struct S {
pub a: Value<i32>,
pub b: Value<u8>,
pub c: Value<Inner>,
pub d: Value<Inner>,
}
impl Clone for S {
fn clone(&self) -> Self {
let __this: Value<S> = 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<S> = __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: <Value<Inner>>::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(<i32>::from_bytes(&buf[0..4]))),
b: Rc::new(RefCell::new(<u8>::from_bytes(&buf[4..5]))),
c: Rc::new(RefCell::new(<Inner>::from_bytes(&buf[8..16]))),
d: Rc::new(RefCell::new(<Inner>::from_bytes(&buf[16..24]))),
}
}
}
#[derive()]
pub struct Boxed_int_ {
pub v: Value<i32>,
pub tag: Value<i32>,
}
impl Boxed_int_ {
pub fn Boxed_int_(x: i32, t: i32) -> Self {
let x: Value<i32> = Rc::new(RefCell::new(x));
let t: Value<i32> = Rc::new(RefCell::new(t));
let __this: Value<Boxed_int_> = Rc::new(RefCell::new(Self {
v: Rc::new(RefCell::new((*x.borrow()))),
tag: Rc::new(RefCell::new((*t.borrow()))),
}));
let this: Ptr<Boxed_int_> = __this.as_pointer();
Rc::try_unwrap(__this).ok().unwrap().into_inner()
}
}
impl Clone for Boxed_int_ {
fn clone(&self) -> Self {
let __this: Value<Boxed_int_> = Rc::new(RefCell::new(Self {
v: Rc::new(RefCell::new((*self.v.borrow()))),
tag: Rc::new(RefCell::new((*self.tag.borrow()))),
}));
let this: Ptr<Boxed_int_> = __this.as_pointer();
Rc::try_unwrap(__this).ok().unwrap().into_inner()
}
}
impl Default for Boxed_int_ {
fn default() -> Self {
Boxed_int_ {
v: <Value<i32>>::default(),
tag: <Value<i32>>::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(<i32>::from_bytes(&buf[0..4]))),
tag: Rc::new(RefCell::new(<i32>::from_bytes(&buf[4..8]))),
}
}
}
pub fn main() {
std::process::exit(main_0());
}
fn main_0() -> i32 {
let s: Value<S> = Rc::new(RefCell::new(<S>::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<Boxed_int_> = Rc::new(RefCell::new(Boxed_int_::Boxed_int_({ 5 }, { 9 })));
assert!(((*(*boxed.borrow()).v.borrow()) == 5));
assert!(((*(*boxed.borrow()).tag.borrow()) == 9));
return 0;
}
10 changes: 9 additions & 1 deletion tests/unit/out/unsafe/array_of_noncopy_struct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<i32>,
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);
Expand Down
75 changes: 75 additions & 0 deletions tests/unit/out/unsafe/in_class_field_initializer.rs
Original file line number Diff line number Diff line change
@@ -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 },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c should be initialized like d

@lucic71 lucic71 Sep 10, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if Inner is defined as:

struct Inner {
  int x; // was int x = 3;
  int y = 4;
}

?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inner x{} would initialize 'x' to zero, While 'Inner x' doesn't. But we probably need to default initialize everything anyway.

d: <Inner>::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 = <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;
}
Loading