Skip to content

Commit a8625eb

Browse files
authored
Use default literals instead of Default::default() in const initialization (#66)
`Default::default()` is not a const function, hence it cannot be used to initialize global objects such as `pub static mut static_outer: Outer = Outer::default()`. To overcome this limitation, emit the default literal for the object, for example: ```rs pub static mut static_outer: Outer = Outer { p1: std::ptr::null_mut(), p2: std::ptr::null(), arr: [std::ptr::null_mut(); 3], cp: std::ptr::null(), pp: std::ptr::null_mut(), inner: Inner { v: 0_i32, name: std::ptr::null(), }, x: 0_i32, fn_: None, }; ```
1 parent 999aabf commit a8625eb

5 files changed

Lines changed: 499 additions & 7 deletions

File tree

cpp2rust/converter/converter.cpp

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,8 @@ void Converter::ConvertVarDecl(clang::VarDecl *decl) {
445445
return;
446446
}
447447
auto qual_type = decl->getType();
448+
PushConstInitializer static_init(*this, decl->isFileVarDecl() ||
449+
decl->isStaticLocal());
448450
if (decl->hasInit()) {
449451
StrCat(token::kAssign);
450452
ConvertVarInit(qual_type, decl->getInit());
@@ -3043,6 +3045,18 @@ std::string Converter::GetDefaultAsStringFallback(clang::QualType qual_type) {
30433045
return std::format("0.0_{}", ToString(qual_type));
30443046
}
30453047

3048+
if (auto record = qual_type->getAsRecordDecl();
3049+
record && in_const_initializer_) {
3050+
if (auto cxx = clang::dyn_cast<clang::CXXRecordDecl>(record)) {
3051+
ENSURE(GetUserDefinedDefaultConstructor(cxx) == nullptr &&
3052+
"Default initializing globals using default constructor is not "
3053+
"supported");
3054+
}
3055+
Buffer buf(*this);
3056+
EmitDefaultStructLiteral(record);
3057+
return std::move(buf).str();
3058+
}
3059+
30463060
return std::format("<{}>::default()", ToString(qual_type));
30473061
}
30483062

@@ -3458,13 +3472,15 @@ void Converter::AddDefaultTrait(const clang::RecordDecl *decl) {
34583472
}
34593473
}
34603474

3461-
StrCat(struct_name);
3462-
{
3463-
PushBrace struct_brace(*this);
3464-
for (auto *field : decl->fields()) {
3465-
StrCat(GetNamedDeclAsString(field), token::kColon,
3466-
GetDefaultAsString(field->getType()), token::kComma);
3467-
}
3475+
EmitDefaultStructLiteral(decl);
3476+
}
3477+
3478+
void Converter::EmitDefaultStructLiteral(const clang::RecordDecl *decl) {
3479+
StrCat(GetRecordName(decl));
3480+
PushBrace brace(*this);
3481+
for (auto *field : decl->fields()) {
3482+
StrCat(GetNamedDeclAsString(field), token::kColon,
3483+
GetDefaultAsString(field->getType()), token::kComma);
34683484
}
34693485
}
34703486

cpp2rust/converter/converter.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
464464

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

467+
void EmitDefaultStructLiteral(const clang::RecordDecl *decl);
468+
467469
virtual void AddByteReprTrait(const clang::RecordDecl *decl);
468470

469471
virtual void
@@ -517,6 +519,7 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
517519
clang::ASTContext &ctx_;
518520
clang::FunctionDecl *curr_function_ = nullptr;
519521
bool in_function_formals_ = false;
522+
bool in_const_initializer_ = false;
520523
std::optional<bool> autoref_mut_;
521524

522525
struct PushExplicitAutoref {
@@ -528,6 +531,23 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
528531
}
529532
~PushExplicitAutoref() { c.autoref_mut_ = prev; }
530533
};
534+
535+
struct PushConstInitializer {
536+
Converter &c;
537+
bool prev;
538+
bool enabled;
539+
PushConstInitializer(Converter &c, bool enabled)
540+
: c(c), prev(c.in_const_initializer_), enabled(enabled) {
541+
if (enabled) {
542+
c.in_const_initializer_ = true;
543+
}
544+
}
545+
~PushConstInitializer() {
546+
if (enabled) {
547+
c.in_const_initializer_ = prev;
548+
}
549+
}
550+
};
531551
std::stack<clang::Expr *> curr_for_inc_;
532552
std::stack<clang::QualType> curr_init_type_;
533553

tests/unit/default_in_statics.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#include <cassert>
2+
#include <cstddef>
3+
4+
typedef int (*FnPtr)(int);
5+
6+
struct Inner {
7+
int v;
8+
const char *name;
9+
};
10+
11+
struct Outer {
12+
int *p1;
13+
const int *p2;
14+
int *arr[3];
15+
const char *cp;
16+
int **pp;
17+
Inner inner;
18+
int x;
19+
FnPtr fn;
20+
};
21+
22+
struct Foo {
23+
const char *s1;
24+
const char *s2;
25+
FnPtr fn1;
26+
FnPtr fn2;
27+
int n;
28+
};
29+
30+
static FnPtr static_fn;
31+
static Outer static_outer;
32+
static Inner static_inner_array[2];
33+
34+
static Foo static_foo = {"hello", 0, 0, 0, 42};
35+
36+
static Foo static_foo_array[2] = {
37+
{"first", 0, 0, 0, 1},
38+
{"second", 0, 0, 0, 2},
39+
};
40+
41+
void check_local_static() {
42+
static Outer local_outer;
43+
static FnPtr local_fn;
44+
static int *local_p;
45+
assert(local_outer.p1 == nullptr);
46+
assert(local_outer.fn == nullptr);
47+
assert(local_fn == nullptr);
48+
assert(local_p == nullptr);
49+
}
50+
51+
int main() {
52+
assert(static_fn == nullptr);
53+
54+
assert(static_outer.p1 == nullptr);
55+
assert(static_outer.p2 == nullptr);
56+
assert(static_outer.cp == nullptr);
57+
assert(static_outer.pp == nullptr);
58+
assert(static_outer.fn == nullptr);
59+
for (int i = 0; i < 3; ++i) {
60+
assert(static_outer.arr[i] == nullptr);
61+
}
62+
assert(static_outer.inner.name == nullptr);
63+
64+
for (int i = 0; i < 2; ++i) {
65+
assert(static_inner_array[i].name == nullptr);
66+
}
67+
68+
assert(static_foo.s2 == nullptr);
69+
assert(static_foo.fn1 == nullptr);
70+
assert(static_foo.fn2 == nullptr);
71+
assert(static_foo.n == 42);
72+
73+
for (int i = 0; i < 2; ++i) {
74+
assert(static_foo_array[i].s2 == nullptr);
75+
assert(static_foo_array[i].fn1 == nullptr);
76+
assert(static_foo_array[i].fn2 == nullptr);
77+
}
78+
79+
check_local_static();
80+
81+
return 0;
82+
}
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
extern crate libcc2rs;
2+
use libcc2rs::*;
3+
use std::cell::RefCell;
4+
use std::collections::BTreeMap;
5+
use std::io::prelude::*;
6+
use std::io::{Read, Seek, Write};
7+
use std::os::fd::AsFd;
8+
use std::rc::{Rc, Weak};
9+
#[derive(Default)]
10+
pub struct Inner {
11+
pub v: Value<i32>,
12+
pub name: Value<Ptr<u8>>,
13+
}
14+
impl Clone for Inner {
15+
fn clone(&self) -> Self {
16+
let mut this = Self {
17+
v: Rc::new(RefCell::new((*self.v.borrow()))),
18+
name: Rc::new(RefCell::new((*self.name.borrow()).clone())),
19+
};
20+
this
21+
}
22+
}
23+
impl ByteRepr for Inner {}
24+
#[derive()]
25+
pub struct Outer {
26+
pub p1: Value<Ptr<i32>>,
27+
pub p2: Value<Ptr<i32>>,
28+
pub arr: Value<Box<[Ptr<i32>]>>,
29+
pub cp: Value<Ptr<u8>>,
30+
pub pp: Value<Ptr<Ptr<i32>>>,
31+
pub inner: Value<Inner>,
32+
pub x: Value<i32>,
33+
pub fn_: Value<FnPtr<fn(i32) -> i32>>,
34+
}
35+
impl Clone for Outer {
36+
fn clone(&self) -> Self {
37+
let mut this = Self {
38+
p1: Rc::new(RefCell::new((*self.p1.borrow()).clone())),
39+
p2: Rc::new(RefCell::new((*self.p2.borrow()).clone())),
40+
arr: Rc::new(RefCell::new((*self.arr.borrow()).clone())),
41+
cp: Rc::new(RefCell::new((*self.cp.borrow()).clone())),
42+
pp: Rc::new(RefCell::new((*self.pp.borrow()).clone())),
43+
inner: Rc::new(RefCell::new((*self.inner.borrow()).clone())),
44+
x: Rc::new(RefCell::new((*self.x.borrow()))),
45+
fn_: Rc::new(RefCell::new((*self.fn_.borrow()).clone())),
46+
};
47+
this
48+
}
49+
}
50+
impl Default for Outer {
51+
fn default() -> Self {
52+
Outer {
53+
p1: Rc::new(RefCell::new(Ptr::<i32>::null())),
54+
p2: Rc::new(RefCell::new(Ptr::<i32>::null())),
55+
arr: Rc::new(RefCell::new(
56+
(0..3)
57+
.map(|_| Ptr::<i32>::null())
58+
.collect::<Box<[Ptr<i32>]>>(),
59+
)),
60+
cp: Rc::new(RefCell::new(Ptr::<u8>::null())),
61+
pp: Rc::new(RefCell::new(Ptr::<Ptr<i32>>::null())),
62+
inner: <Value<Inner>>::default(),
63+
x: <Value<i32>>::default(),
64+
fn_: Rc::new(RefCell::new(FnPtr::null())),
65+
}
66+
}
67+
}
68+
impl ByteRepr for Outer {}
69+
#[derive()]
70+
pub struct Foo {
71+
pub s1: Value<Ptr<u8>>,
72+
pub s2: Value<Ptr<u8>>,
73+
pub fn1: Value<FnPtr<fn(i32) -> i32>>,
74+
pub fn2: Value<FnPtr<fn(i32) -> i32>>,
75+
pub n: Value<i32>,
76+
}
77+
impl Clone for Foo {
78+
fn clone(&self) -> Self {
79+
let mut this = Self {
80+
s1: Rc::new(RefCell::new((*self.s1.borrow()).clone())),
81+
s2: Rc::new(RefCell::new((*self.s2.borrow()).clone())),
82+
fn1: Rc::new(RefCell::new((*self.fn1.borrow()).clone())),
83+
fn2: Rc::new(RefCell::new((*self.fn2.borrow()).clone())),
84+
n: Rc::new(RefCell::new((*self.n.borrow()))),
85+
};
86+
this
87+
}
88+
}
89+
impl Default for Foo {
90+
fn default() -> Self {
91+
Foo {
92+
s1: Rc::new(RefCell::new(Ptr::<u8>::null())),
93+
s2: Rc::new(RefCell::new(Ptr::<u8>::null())),
94+
fn1: Rc::new(RefCell::new(FnPtr::null())),
95+
fn2: Rc::new(RefCell::new(FnPtr::null())),
96+
n: <Value<i32>>::default(),
97+
}
98+
}
99+
}
100+
impl ByteRepr for Foo {}
101+
thread_local!(
102+
pub static static_fn: Value<FnPtr<fn(i32) -> i32>> = Rc::new(RefCell::new(FnPtr::null()));
103+
);
104+
thread_local!(
105+
pub static static_outer: Value<Outer> = Rc::new(RefCell::new(<Outer>::default()));
106+
);
107+
thread_local!(
108+
pub static static_inner_array: Value<Box<[Inner]>> = Rc::new(RefCell::new(
109+
(0..2).map(|_| <Inner>::default()).collect::<Box<[Inner]>>(),
110+
));
111+
);
112+
thread_local!(
113+
pub static static_foo: Value<Foo> = Rc::new(RefCell::new(Foo {
114+
s1: Rc::new(RefCell::new(Ptr::from_string_literal("hello"))),
115+
s2: Rc::new(RefCell::new(Default::default())),
116+
fn1: Rc::new(RefCell::new(FnPtr::null())),
117+
fn2: Rc::new(RefCell::new(FnPtr::null())),
118+
n: Rc::new(RefCell::new(42)),
119+
}));
120+
);
121+
thread_local!(
122+
pub static static_foo_array: Value<Box<[Foo]>> = Rc::new(RefCell::new(Box::new([
123+
Foo {
124+
s1: Rc::new(RefCell::new(Ptr::from_string_literal("first"))),
125+
s2: Rc::new(RefCell::new(Default::default())),
126+
fn1: Rc::new(RefCell::new(FnPtr::null())),
127+
fn2: Rc::new(RefCell::new(FnPtr::null())),
128+
n: Rc::new(RefCell::new(1)),
129+
},
130+
Foo {
131+
s1: Rc::new(RefCell::new(Ptr::from_string_literal("second"))),
132+
s2: Rc::new(RefCell::new(Default::default())),
133+
fn1: Rc::new(RefCell::new(FnPtr::null())),
134+
fn2: Rc::new(RefCell::new(FnPtr::null())),
135+
n: Rc::new(RefCell::new(2)),
136+
},
137+
])));
138+
);
139+
pub fn check_local_static_0() {
140+
thread_local!(
141+
static local_outer: Value<Outer> = Rc::new(RefCell::new(<Outer>::default()));
142+
);
143+
thread_local!(
144+
static local_fn: Value<FnPtr<fn(i32) -> i32>> = Rc::new(RefCell::new(FnPtr::null()));
145+
);
146+
thread_local!(
147+
static local_p: Value<Ptr<i32>> = Rc::new(RefCell::new(Ptr::<i32>::null()));
148+
);
149+
assert!((*(*local_outer.with(Value::clone).borrow()).p1.borrow()).is_null());
150+
assert!((*(*local_outer.with(Value::clone).borrow()).fn_.borrow()).is_null());
151+
assert!((*local_fn.with(Value::clone).borrow()).is_null());
152+
assert!((*local_p.with(Value::clone).borrow()).is_null());
153+
}
154+
pub fn main() {
155+
std::process::exit(main_0());
156+
}
157+
fn main_0() -> i32 {
158+
assert!((*static_fn.with(Value::clone).borrow()).is_null());
159+
assert!((*(*static_outer.with(Value::clone).borrow()).p1.borrow()).is_null());
160+
assert!((*(*static_outer.with(Value::clone).borrow()).p2.borrow()).is_null());
161+
assert!((*(*static_outer.with(Value::clone).borrow()).cp.borrow()).is_null());
162+
assert!((*(*static_outer.with(Value::clone).borrow()).pp.borrow()).is_null());
163+
assert!((*(*static_outer.with(Value::clone).borrow()).fn_.borrow()).is_null());
164+
let i: Value<i32> = Rc::new(RefCell::new(0));
165+
'loop_: while ((*i.borrow()) < 3) {
166+
assert!(((*(*static_outer.with(Value::clone).borrow()).arr.borrow())
167+
[(*i.borrow()) as usize])
168+
.is_null());
169+
(*i.borrow_mut()).prefix_inc();
170+
}
171+
assert!(
172+
(*(*(*static_outer.with(Value::clone).borrow()).inner.borrow())
173+
.name
174+
.borrow())
175+
.is_null()
176+
);
177+
let i: Value<i32> = Rc::new(RefCell::new(0));
178+
'loop_: while ((*i.borrow()) < 2) {
179+
assert!(
180+
(*(*static_inner_array.with(Value::clone).borrow())[(*i.borrow()) as usize]
181+
.name
182+
.borrow())
183+
.is_null()
184+
);
185+
(*i.borrow_mut()).prefix_inc();
186+
}
187+
assert!((*(*static_foo.with(Value::clone).borrow()).s2.borrow()).is_null());
188+
assert!((*(*static_foo.with(Value::clone).borrow()).fn1.borrow()).is_null());
189+
assert!((*(*static_foo.with(Value::clone).borrow()).fn2.borrow()).is_null());
190+
assert!(((*(*static_foo.with(Value::clone).borrow()).n.borrow()) == 42));
191+
let i: Value<i32> = Rc::new(RefCell::new(0));
192+
'loop_: while ((*i.borrow()) < 2) {
193+
assert!(
194+
(*(*static_foo_array.with(Value::clone).borrow())[(*i.borrow()) as usize]
195+
.s2
196+
.borrow())
197+
.is_null()
198+
);
199+
assert!(
200+
(*(*static_foo_array.with(Value::clone).borrow())[(*i.borrow()) as usize]
201+
.fn1
202+
.borrow())
203+
.is_null()
204+
);
205+
assert!(
206+
(*(*static_foo_array.with(Value::clone).borrow())[(*i.borrow()) as usize]
207+
.fn2
208+
.borrow())
209+
.is_null()
210+
);
211+
(*i.borrow_mut()).prefix_inc();
212+
}
213+
({ check_local_static_0() });
214+
return 0;
215+
}

0 commit comments

Comments
 (0)