Skip to content
Merged
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
30 changes: 23 additions & 7 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,8 @@ void Converter::ConvertVarDecl(clang::VarDecl *decl) {
return;
}
auto qual_type = decl->getType();
PushConstInitializer static_init(*this, decl->isFileVarDecl() ||
decl->isStaticLocal());
if (decl->hasInit()) {
StrCat(token::kAssign);
ConvertVarInit(qual_type, decl->getInit());
Expand Down Expand Up @@ -3043,6 +3045,18 @@ std::string Converter::GetDefaultAsStringFallback(clang::QualType qual_type) {
return std::format("0.0_{}", ToString(qual_type));
}

if (auto record = qual_type->getAsRecordDecl();
record && in_const_initializer_) {
if (auto cxx = clang::dyn_cast<clang::CXXRecordDecl>(record)) {
ENSURE(GetUserDefinedDefaultConstructor(cxx) == nullptr &&
"Default initializing globals using default constructor is not "
"supported");
}
Buffer buf(*this);
EmitDefaultStructLiteral(record);
return std::move(buf).str();
}

return std::format("<{}>::default()", ToString(qual_type));
}

Expand Down Expand Up @@ -3458,13 +3472,15 @@ void Converter::AddDefaultTrait(const clang::RecordDecl *decl) {
}
}

StrCat(struct_name);
{
PushBrace struct_brace(*this);
for (auto *field : decl->fields()) {
StrCat(GetNamedDeclAsString(field), token::kColon,
GetDefaultAsString(field->getType()), token::kComma);
}
EmitDefaultStructLiteral(decl);
}

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);
}
}

Expand Down
20 changes: 20 additions & 0 deletions cpp2rust/converter/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {

virtual void AddDefaultTraitForUnion(const clang::RecordDecl *decl);

void EmitDefaultStructLiteral(const clang::RecordDecl *decl);

virtual void AddByteReprTrait(const clang::RecordDecl *decl);

virtual void
Expand Down Expand Up @@ -517,6 +519,7 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
clang::ASTContext &ctx_;
clang::FunctionDecl *curr_function_ = nullptr;
bool in_function_formals_ = false;
bool in_const_initializer_ = false;
std::optional<bool> autoref_mut_;

struct PushExplicitAutoref {
Expand All @@ -528,6 +531,23 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
}
~PushExplicitAutoref() { c.autoref_mut_ = prev; }
};

struct PushConstInitializer {
Converter &c;
bool prev;
bool enabled;
PushConstInitializer(Converter &c, bool enabled)
: c(c), prev(c.in_const_initializer_), enabled(enabled) {
if (enabled) {
c.in_const_initializer_ = true;
}
}
~PushConstInitializer() {
if (enabled) {
c.in_const_initializer_ = prev;
}
}
};
std::stack<clang::Expr *> curr_for_inc_;
std::stack<clang::QualType> curr_init_type_;

Expand Down
82 changes: 82 additions & 0 deletions tests/unit/default_in_statics.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#include <cassert>
#include <cstddef>

typedef int (*FnPtr)(int);

struct Inner {
int v;
const char *name;
};

struct Outer {
int *p1;
const int *p2;
int *arr[3];
const char *cp;
int **pp;
Inner inner;
int x;
FnPtr fn;
};

struct Foo {
const char *s1;
const char *s2;
FnPtr fn1;
FnPtr fn2;
int n;
};

static FnPtr static_fn;
static Outer static_outer;
static Inner static_inner_array[2];

static Foo static_foo = {"hello", 0, 0, 0, 42};

static Foo static_foo_array[2] = {
{"first", 0, 0, 0, 1},
{"second", 0, 0, 0, 2},
};

void check_local_static() {
static Outer local_outer;
static FnPtr local_fn;
static int *local_p;
assert(local_outer.p1 == nullptr);
assert(local_outer.fn == nullptr);
assert(local_fn == nullptr);
assert(local_p == nullptr);
}

int main() {
assert(static_fn == nullptr);

assert(static_outer.p1 == nullptr);
assert(static_outer.p2 == nullptr);
assert(static_outer.cp == nullptr);
assert(static_outer.pp == nullptr);
assert(static_outer.fn == nullptr);
for (int i = 0; i < 3; ++i) {
assert(static_outer.arr[i] == nullptr);
}
assert(static_outer.inner.name == nullptr);

for (int i = 0; i < 2; ++i) {
assert(static_inner_array[i].name == nullptr);
}

assert(static_foo.s2 == nullptr);
assert(static_foo.fn1 == nullptr);
assert(static_foo.fn2 == nullptr);
assert(static_foo.n == 42);

for (int i = 0; i < 2; ++i) {
assert(static_foo_array[i].s2 == nullptr);
assert(static_foo_array[i].fn1 == nullptr);
assert(static_foo_array[i].fn2 == nullptr);
}

check_local_static();

return 0;
}
215 changes: 215 additions & 0 deletions tests/unit/out/refcount/default_in_statics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
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(Default)]
pub struct Inner {
pub v: Value<i32>,
pub name: Value<Ptr<u8>>,
}
impl Clone for Inner {
fn clone(&self) -> Self {
let mut this = Self {
v: Rc::new(RefCell::new((*self.v.borrow()))),
name: Rc::new(RefCell::new((*self.name.borrow()).clone())),
};
this
}
}
impl ByteRepr for Inner {}
#[derive()]
pub struct Outer {
pub p1: Value<Ptr<i32>>,
pub p2: Value<Ptr<i32>>,
pub arr: Value<Box<[Ptr<i32>]>>,
pub cp: Value<Ptr<u8>>,
pub pp: Value<Ptr<Ptr<i32>>>,
pub inner: Value<Inner>,
pub x: Value<i32>,
pub fn_: Value<FnPtr<fn(i32) -> i32>>,
}
impl Clone for Outer {
fn clone(&self) -> Self {
let mut this = Self {
p1: Rc::new(RefCell::new((*self.p1.borrow()).clone())),
p2: Rc::new(RefCell::new((*self.p2.borrow()).clone())),
arr: Rc::new(RefCell::new((*self.arr.borrow()).clone())),
cp: Rc::new(RefCell::new((*self.cp.borrow()).clone())),
pp: Rc::new(RefCell::new((*self.pp.borrow()).clone())),
inner: Rc::new(RefCell::new((*self.inner.borrow()).clone())),
x: Rc::new(RefCell::new((*self.x.borrow()))),
fn_: Rc::new(RefCell::new((*self.fn_.borrow()).clone())),
};
this
}
}
impl Default for Outer {
fn default() -> Self {
Outer {
p1: Rc::new(RefCell::new(Ptr::<i32>::null())),
p2: Rc::new(RefCell::new(Ptr::<i32>::null())),
arr: Rc::new(RefCell::new(
(0..3)
.map(|_| Ptr::<i32>::null())
.collect::<Box<[Ptr<i32>]>>(),
)),
cp: Rc::new(RefCell::new(Ptr::<u8>::null())),
pp: Rc::new(RefCell::new(Ptr::<Ptr<i32>>::null())),
inner: <Value<Inner>>::default(),
x: <Value<i32>>::default(),
fn_: Rc::new(RefCell::new(FnPtr::null())),
}
}
}
impl ByteRepr for Outer {}
#[derive()]
pub struct Foo {
pub s1: Value<Ptr<u8>>,
pub s2: Value<Ptr<u8>>,
pub fn1: Value<FnPtr<fn(i32) -> i32>>,
pub fn2: Value<FnPtr<fn(i32) -> i32>>,
pub n: Value<i32>,
}
impl Clone for Foo {
fn clone(&self) -> Self {
let mut this = Self {
s1: Rc::new(RefCell::new((*self.s1.borrow()).clone())),
s2: Rc::new(RefCell::new((*self.s2.borrow()).clone())),
fn1: Rc::new(RefCell::new((*self.fn1.borrow()).clone())),
fn2: Rc::new(RefCell::new((*self.fn2.borrow()).clone())),
n: Rc::new(RefCell::new((*self.n.borrow()))),
};
this
}
}
impl Default for Foo {
fn default() -> Self {
Foo {
s1: Rc::new(RefCell::new(Ptr::<u8>::null())),
s2: Rc::new(RefCell::new(Ptr::<u8>::null())),
fn1: Rc::new(RefCell::new(FnPtr::null())),
fn2: Rc::new(RefCell::new(FnPtr::null())),
n: <Value<i32>>::default(),
}
}
}
impl ByteRepr for Foo {}
thread_local!(
pub static static_fn: Value<FnPtr<fn(i32) -> i32>> = Rc::new(RefCell::new(FnPtr::null()));
);
thread_local!(
pub static static_outer: Value<Outer> = Rc::new(RefCell::new(<Outer>::default()));
);
thread_local!(
pub static static_inner_array: Value<Box<[Inner]>> = Rc::new(RefCell::new(
(0..2).map(|_| <Inner>::default()).collect::<Box<[Inner]>>(),
));
);
thread_local!(
pub static static_foo: Value<Foo> = Rc::new(RefCell::new(Foo {
s1: Rc::new(RefCell::new(Ptr::from_string_literal("hello"))),
s2: Rc::new(RefCell::new(Default::default())),
fn1: Rc::new(RefCell::new(FnPtr::null())),
fn2: Rc::new(RefCell::new(FnPtr::null())),
n: Rc::new(RefCell::new(42)),
}));
);
thread_local!(
pub static static_foo_array: Value<Box<[Foo]>> = Rc::new(RefCell::new(Box::new([
Foo {
s1: Rc::new(RefCell::new(Ptr::from_string_literal("first"))),
s2: Rc::new(RefCell::new(Default::default())),
fn1: Rc::new(RefCell::new(FnPtr::null())),
fn2: Rc::new(RefCell::new(FnPtr::null())),
n: Rc::new(RefCell::new(1)),
},
Foo {
s1: Rc::new(RefCell::new(Ptr::from_string_literal("second"))),
s2: Rc::new(RefCell::new(Default::default())),
fn1: Rc::new(RefCell::new(FnPtr::null())),
fn2: Rc::new(RefCell::new(FnPtr::null())),
n: Rc::new(RefCell::new(2)),
},
])));
);
pub fn check_local_static_0() {
thread_local!(
static local_outer: Value<Outer> = Rc::new(RefCell::new(<Outer>::default()));
);
thread_local!(
static local_fn: Value<FnPtr<fn(i32) -> i32>> = Rc::new(RefCell::new(FnPtr::null()));
);
thread_local!(
static local_p: Value<Ptr<i32>> = Rc::new(RefCell::new(Ptr::<i32>::null()));
);
assert!((*(*local_outer.with(Value::clone).borrow()).p1.borrow()).is_null());
assert!((*(*local_outer.with(Value::clone).borrow()).fn_.borrow()).is_null());
assert!((*local_fn.with(Value::clone).borrow()).is_null());
assert!((*local_p.with(Value::clone).borrow()).is_null());
}
pub fn main() {
std::process::exit(main_0());
}
fn main_0() -> i32 {
assert!((*static_fn.with(Value::clone).borrow()).is_null());
assert!((*(*static_outer.with(Value::clone).borrow()).p1.borrow()).is_null());
assert!((*(*static_outer.with(Value::clone).borrow()).p2.borrow()).is_null());
assert!((*(*static_outer.with(Value::clone).borrow()).cp.borrow()).is_null());
assert!((*(*static_outer.with(Value::clone).borrow()).pp.borrow()).is_null());
assert!((*(*static_outer.with(Value::clone).borrow()).fn_.borrow()).is_null());
let i: Value<i32> = Rc::new(RefCell::new(0));
'loop_: while ((*i.borrow()) < 3) {
assert!(((*(*static_outer.with(Value::clone).borrow()).arr.borrow())
[(*i.borrow()) as usize])
.is_null());
(*i.borrow_mut()).prefix_inc();
}
assert!(
(*(*(*static_outer.with(Value::clone).borrow()).inner.borrow())
.name
.borrow())
.is_null()
);
let i: Value<i32> = Rc::new(RefCell::new(0));
'loop_: while ((*i.borrow()) < 2) {
assert!(
(*(*static_inner_array.with(Value::clone).borrow())[(*i.borrow()) as usize]
.name
.borrow())
.is_null()
);
(*i.borrow_mut()).prefix_inc();
}
assert!((*(*static_foo.with(Value::clone).borrow()).s2.borrow()).is_null());
assert!((*(*static_foo.with(Value::clone).borrow()).fn1.borrow()).is_null());
assert!((*(*static_foo.with(Value::clone).borrow()).fn2.borrow()).is_null());
assert!(((*(*static_foo.with(Value::clone).borrow()).n.borrow()) == 42));
let i: Value<i32> = Rc::new(RefCell::new(0));
'loop_: while ((*i.borrow()) < 2) {
assert!(
(*(*static_foo_array.with(Value::clone).borrow())[(*i.borrow()) as usize]
.s2
.borrow())
.is_null()
);
assert!(
(*(*static_foo_array.with(Value::clone).borrow())[(*i.borrow()) as usize]
.fn1
.borrow())
.is_null()
);
assert!(
(*(*static_foo_array.with(Value::clone).borrow())[(*i.borrow()) as usize]
.fn2
.borrow())
.is_null()
);
(*i.borrow_mut()).prefix_inc();
}
({ check_local_static_0() });
return 0;
}
Loading
Loading