Skip to content

Commit 157f292

Browse files
authored
Allow initialization of enums in global context (#64)
Previously, in C, enums were initialized with the `Enum::from(X as i32)` pattern because enum variants are represented as int and the type of variable is represented as enum. The From trait is not allowed in global context because it's non-const. This PR fixes this by short-circuiting `ConvertIntegerToEnumeralCast` to emit `X` instead of `Enum::from(X as i32)`
1 parent f59ca0e commit 157f292

19 files changed

Lines changed: 362 additions & 37 deletions

cpp2rust/converter/converter.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1733,6 +1733,19 @@ bool Converter::VisitCXXBoolLiteralExpr(clang::CXXBoolLiteralExpr *expr) {
17331733

17341734
void Converter::ConvertIntegerToEnumeralCast(clang::Expr *to,
17351735
clang::Expr *from) {
1736+
// Short circuit `Enum::from(X as i32)` to `X`
1737+
if (auto ref =
1738+
clang::dyn_cast<clang::DeclRefExpr>(from->IgnoreParenImpCasts())) {
1739+
if (auto ec = clang::dyn_cast<clang::EnumConstantDecl>(ref->getDecl())) {
1740+
auto src_enum = clang::dyn_cast<clang::EnumDecl>(ec->getDeclContext());
1741+
auto dst_enum = to->getType()->getAs<clang::EnumType>();
1742+
if (src_enum && dst_enum && dst_enum->getDecl() == src_enum) {
1743+
StrCat(std::format("{}::{}", GetRecordName(src_enum),
1744+
std::string_view(ec->getName())));
1745+
return;
1746+
}
1747+
}
1748+
}
17361749
StrCat(GetUnsafeTypeAsString(to->getType()), "::from");
17371750
PushParen paren(*this);
17381751
Convert(from);

tests/unit/enum_int_interop.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,22 @@ typedef enum {
1515
TAG_TWO = 2,
1616
} Tag;
1717

18+
struct Entry {
19+
const char *name;
20+
Color color;
21+
Option opt;
22+
};
23+
24+
static Color global_color = GREEN;
25+
static Option global_opt = OPT_B;
26+
static Tag global_tag = TAG_TWO;
27+
28+
static Entry entries[3] = {
29+
{"first", RED, OPT_NONE},
30+
{"second", GREEN, OPT_A},
31+
{"third", BLUE, OPT_C},
32+
};
33+
1834
int as_int(Color c) { return c; }
1935

2036
int classify_option(int option) {
@@ -113,5 +129,16 @@ int main() {
113129
int extra = (int)RED + (int)GREEN + (int)BLUE;
114130
assert(extra == 0 + 1 + 2);
115131

132+
assert(global_color == GREEN);
133+
assert(global_opt == OPT_B);
134+
assert(global_tag == TAG_TWO);
135+
136+
assert(entries[0].color == RED);
137+
assert(entries[0].opt == OPT_NONE);
138+
assert(entries[1].color == GREEN);
139+
assert(entries[1].opt == OPT_A);
140+
assert(entries[2].color == BLUE);
141+
assert(entries[2].opt == OPT_C);
142+
116143
return 0;
117144
}

tests/unit/enum_int_interop_c.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,22 @@ typedef enum {
1515
TAG_TWO = 2,
1616
} Tag;
1717

18+
struct Entry {
19+
const char *name;
20+
enum Color color;
21+
enum Option opt;
22+
};
23+
24+
static enum Color global_color = GREEN;
25+
static enum Option global_opt = OPT_B;
26+
static Tag global_tag = TAG_TWO;
27+
28+
static struct Entry entries[3] = {
29+
{"first", RED, OPT_NONE},
30+
{"second", GREEN, OPT_A},
31+
{"third", BLUE, OPT_C},
32+
};
33+
1834
int as_int(enum Color c) { return c; }
1935

2036
int classify_option(int option) {
@@ -113,5 +129,16 @@ int main() {
113129
int extra = (int)RED + (int)GREEN + (int)BLUE;
114130
assert(extra == 0 + 1 + 2);
115131

132+
assert(global_color == GREEN);
133+
assert(global_opt == OPT_B);
134+
assert(global_tag == TAG_TWO);
135+
136+
assert(entries[0].color == RED);
137+
assert(entries[0].opt == OPT_NONE);
138+
assert(entries[1].color == GREEN);
139+
assert(entries[1].opt == OPT_A);
140+
assert(entries[2].color == BLUE);
141+
assert(entries[2].opt == OPT_C);
142+
116143
return 0;
117144
}

tests/unit/out/refcount/anonymous_enum_c.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,18 +99,18 @@ fn main_0() -> i32 {
9999
assert!(((((anon_enum_3::FIRST_A as i32) != (anon_enum_3::FIRST_B as i32)) as i32) != 0));
100100
assert!(((((anon_enum_11::SECOND_A as i32) != (anon_enum_11::SECOND_B as i32)) as i32) != 0));
101101
assert!(((((anon_enum_31::THIRD_A as i32) != (anon_enum_31::THIRD_B as i32)) as i32) != 0));
102-
let td: Value<TdEnum> = Rc::new(RefCell::new(TdEnum::from((TdEnum::TD_A as i32))));
102+
let td: Value<TdEnum> = Rc::new(RefCell::new(TdEnum::TD_A));
103103
assert!((((((*td.borrow()) as u32) == ((TdEnum::TD_A as i32) as u32)) as i32) != 0));
104-
(*td.borrow_mut()) = TdEnum::from((TdEnum::TD_B as i32));
104+
(*td.borrow_mut()) = TdEnum::TD_B;
105105
assert!((((((*td.borrow()) as u32) == ((TdEnum::TD_B as i32) as u32)) as i32) != 0));
106106
let w: Value<WithAnonField> = <Value<WithAnonField>>::default();
107-
(*(*w.borrow()).field.borrow_mut()) = anon_enum_24::from((anon_enum_24::FIELD_A as i32));
107+
(*(*w.borrow()).field.borrow_mut()) = anon_enum_24::FIELD_A;
108108
assert!(
109109
(((((*(*w.borrow()).field.borrow()) as u32) == ((anon_enum_24::FIELD_A as i32) as u32))
110110
as i32)
111111
!= 0)
112112
);
113-
(*(*w.borrow()).field.borrow_mut()) = anon_enum_24::from((anon_enum_24::FIELD_B as i32));
113+
(*(*w.borrow()).field.borrow_mut()) = anon_enum_24::FIELD_B;
114114
assert!(
115115
(((((*(*w.borrow()).field.borrow()) as u32) == ((anon_enum_24::FIELD_B as i32) as u32))
116116
as i32)

tests/unit/out/refcount/bool_condition_enum_c.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ pub fn main() {
2727
std::process::exit(main_0());
2828
}
2929
fn main_0() -> i32 {
30-
let code: Value<Code> = Rc::new(RefCell::new(Code::from((Code::CODE_OK as i32))));
31-
let err: Value<Code> = Rc::new(RefCell::new(Code::from((Code::CODE_ERR as i32))));
30+
let code: Value<Code> = Rc::new(RefCell::new(Code::CODE_OK));
31+
let err: Value<Code> = Rc::new(RefCell::new(Code::CODE_ERR));
3232
if ((*code.borrow()) != Code::from(0)) {
3333
assert!((0 != 0));
3434
}

tests/unit/out/refcount/bool_condition_logical_c.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ fn main_0() -> i32 {
4747
let p: Value<Ptr<i32>> = Rc::new(RefCell::new((storage.as_pointer())));
4848
let np: Value<Ptr<i32>> = Rc::new(RefCell::new(Default::default()));
4949
let u: Value<u32> = Rc::new(RefCell::new(4_u32));
50-
let code: Value<Code> = Rc::new(RefCell::new(Code::from((Code::CODE_OK as i32))));
50+
let code: Value<Code> = Rc::new(RefCell::new(Code::CODE_OK));
5151
if (((((*n.borrow()) != 0) && (!(*p.borrow()).is_null())) as i32) != 0) {
5252
assert!((1 != 0));
5353
}

tests/unit/out/refcount/c_struct.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ fn main_0() -> i32 {
9696
a: Rc::new(RefCell::new(5)),
9797
b: Rc::new(RefCell::new(6)),
9898
})),
99-
color: Rc::new(RefCell::new(Color::from((Color::GREEN as i32)))),
99+
color: Rc::new(RefCell::new(Color::GREEN)),
100100
count: Rc::new(RefCell::new(42)),
101101
}));
102102
assert!(((((*(*(*c.borrow()).inner.borrow()).a.borrow()) == 5) as i32) != 0));
@@ -107,7 +107,7 @@ fn main_0() -> i32 {
107107
);
108108
assert!(((((*(*c.borrow()).count.borrow()) == 42) as i32) != 0));
109109
let c2: Value<Container> = <Value<Container>>::default();
110-
(*(*c2.borrow()).color.borrow_mut()) = Color::from((Color::BLUE as i32));
110+
(*(*c2.borrow()).color.borrow_mut()) = Color::BLUE;
111111
assert!((((((*(*c2.borrow()).color.borrow()) as u32) == 2_u32) as i32) != 0));
112112
return 0;
113113
}

tests/unit/out/refcount/enum_int_interop.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,51 @@ impl From<i32> for Tag {
5959
}
6060
}
6161
}
62+
#[derive(Default)]
63+
pub struct Entry {
64+
pub name: Value<Ptr<u8>>,
65+
pub color: Value<Color>,
66+
pub opt: Value<Option>,
67+
}
68+
impl Clone for Entry {
69+
fn clone(&self) -> Self {
70+
let mut this = Self {
71+
name: Rc::new(RefCell::new((*self.name.borrow()).clone())),
72+
color: Rc::new(RefCell::new((*self.color.borrow()).clone())),
73+
opt: Rc::new(RefCell::new((*self.opt.borrow()).clone())),
74+
};
75+
this
76+
}
77+
}
78+
impl ByteRepr for Entry {}
79+
thread_local!(
80+
pub static global_color: Value<Color> = Rc::new(RefCell::new(Color::GREEN));
81+
);
82+
thread_local!(
83+
pub static global_opt: Value<Option> = Rc::new(RefCell::new(Option::OPT_B));
84+
);
85+
thread_local!(
86+
pub static global_tag: Value<Tag> = Rc::new(RefCell::new(Tag::TAG_TWO));
87+
);
88+
thread_local!(
89+
pub static entries: Value<Box<[Entry]>> = Rc::new(RefCell::new(Box::new([
90+
Entry {
91+
name: Rc::new(RefCell::new(Ptr::from_string_literal("first"))),
92+
color: Rc::new(RefCell::new(Color::RED)),
93+
opt: Rc::new(RefCell::new(Option::OPT_NONE)),
94+
},
95+
Entry {
96+
name: Rc::new(RefCell::new(Ptr::from_string_literal("second"))),
97+
color: Rc::new(RefCell::new(Color::GREEN)),
98+
opt: Rc::new(RefCell::new(Option::OPT_A)),
99+
},
100+
Entry {
101+
name: Rc::new(RefCell::new(Ptr::from_string_literal("third"))),
102+
color: Rc::new(RefCell::new(Color::BLUE)),
103+
opt: Rc::new(RefCell::new(Option::OPT_C)),
104+
},
105+
])));
106+
);
62107
pub fn as_int_0(c: Color) -> i32 {
63108
let c: Value<Color> = Rc::new(RefCell::new(c));
64109
return ((*c.borrow()) as i32).clone();
@@ -183,5 +228,44 @@ fn main_0() -> i32 {
183228
(((Color::RED as i32) + (Color::GREEN as i32)) + (Color::BLUE as i32)),
184229
));
185230
assert!(((*extra.borrow()) == ((0 + 1) + 2)));
231+
assert!((((*global_color.with(Value::clone).borrow()) as i32) == (Color::GREEN as i32)));
232+
assert!((((*global_opt.with(Value::clone).borrow()) as i32) == (Option::OPT_B as i32)));
233+
assert!((((*global_tag.with(Value::clone).borrow()) as i32) == (Tag::TAG_TWO as i32)));
234+
assert!(
235+
(((*(*entries.with(Value::clone).borrow())[(0) as usize]
236+
.color
237+
.borrow()) as i32)
238+
== (Color::RED as i32))
239+
);
240+
assert!(
241+
(((*(*entries.with(Value::clone).borrow())[(0) as usize]
242+
.opt
243+
.borrow()) as i32)
244+
== (Option::OPT_NONE as i32))
245+
);
246+
assert!(
247+
(((*(*entries.with(Value::clone).borrow())[(1) as usize]
248+
.color
249+
.borrow()) as i32)
250+
== (Color::GREEN as i32))
251+
);
252+
assert!(
253+
(((*(*entries.with(Value::clone).borrow())[(1) as usize]
254+
.opt
255+
.borrow()) as i32)
256+
== (Option::OPT_A as i32))
257+
);
258+
assert!(
259+
(((*(*entries.with(Value::clone).borrow())[(2) as usize]
260+
.color
261+
.borrow()) as i32)
262+
== (Color::BLUE as i32))
263+
);
264+
assert!(
265+
(((*(*entries.with(Value::clone).borrow())[(2) as usize]
266+
.opt
267+
.borrow()) as i32)
268+
== (Option::OPT_C as i32))
269+
);
186270
return 0;
187271
}

tests/unit/out/refcount/enum_int_interop_c.rs

Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,41 @@ impl From<i32> for Tag {
5959
}
6060
}
6161
}
62+
#[derive(Default)]
63+
pub struct Entry {
64+
pub name: Value<Ptr<u8>>,
65+
pub color: Value<Color>,
66+
pub opt: Value<Option>,
67+
}
68+
impl ByteRepr for Entry {}
69+
thread_local!(
70+
pub static global_color: Value<Color> = Rc::new(RefCell::new(Color::GREEN));
71+
);
72+
thread_local!(
73+
pub static global_opt: Value<Option> = Rc::new(RefCell::new(Option::OPT_B));
74+
);
75+
thread_local!(
76+
pub static global_tag: Value<Tag> = Rc::new(RefCell::new(Tag::TAG_TWO));
77+
);
78+
thread_local!(
79+
pub static entries: Value<Box<[Entry]>> = Rc::new(RefCell::new(Box::new([
80+
Entry {
81+
name: Rc::new(RefCell::new(Ptr::from_string_literal("first"))),
82+
color: Rc::new(RefCell::new(Color::RED)),
83+
opt: Rc::new(RefCell::new(Option::OPT_NONE)),
84+
},
85+
Entry {
86+
name: Rc::new(RefCell::new(Ptr::from_string_literal("second"))),
87+
color: Rc::new(RefCell::new(Color::GREEN)),
88+
opt: Rc::new(RefCell::new(Option::OPT_A)),
89+
},
90+
Entry {
91+
name: Rc::new(RefCell::new(Ptr::from_string_literal("third"))),
92+
color: Rc::new(RefCell::new(Color::BLUE)),
93+
opt: Rc::new(RefCell::new(Option::OPT_C)),
94+
},
95+
])));
96+
);
6297
pub fn as_int_0(c: Color) -> i32 {
6398
let c: Value<Color> = Rc::new(RefCell::new(c));
6499
return ((*c.borrow()) as i32).clone();
@@ -95,7 +130,7 @@ pub fn main() {
95130
std::process::exit(main_0());
96131
}
97132
fn main_0() -> i32 {
98-
let c: Value<Color> = Rc::new(RefCell::new(Color::from((Color::RED as i32))));
133+
let c: Value<Color> = Rc::new(RefCell::new(Color::RED));
99134
assert!((((((*c.borrow()) as u32) == ((Color::RED as i32) as u32)) as i32) != 0));
100135
assert!((((((*c.borrow()) as u32) == 0_u32) as i32) != 0));
101136
assert!((((((*c.borrow()) as u32) != 1_u32) as i32) != 0));
@@ -137,7 +172,7 @@ fn main_0() -> i32 {
137172
(((*c.borrow()) as u32).wrapping_add(1_u32)) as i32,
138173
)));
139174
assert!((((((*cmp.borrow()) as u32) == ((Color::BLUE as i32) as u32)) as i32) != 0));
140-
let o: Value<Option> = Rc::new(RefCell::new(Option::from((Option::OPT_A as i32))));
175+
let o: Value<Option> = Rc::new(RefCell::new(Option::OPT_A));
141176
assert!((((((*o.borrow()) as u32) == ((Option::OPT_A as i32) as u32)) as i32) != 0));
142177
assert!((((((*o.borrow()) as u32) == 10_u32) as i32) != 0));
143178
let oi: Value<i32> = Rc::new(RefCell::new(((*o.borrow()) as i32).clone()));
@@ -161,7 +196,7 @@ fn main_0() -> i32 {
161196
classify_option_1(_option)
162197
});
163198
assert!(((((*rc.borrow()) == 3) as i32) != 0));
164-
let t: Value<Tag> = Rc::new(RefCell::new(Tag::from((Tag::TAG_ONE as i32))));
199+
let t: Value<Tag> = Rc::new(RefCell::new(Tag::TAG_ONE));
165200
assert!((((((*t.borrow()) as u32) == 1_u32) as i32) != 0));
166201
assert!((((((*t.borrow()) as u32) == ((Tag::TAG_ONE as i32) as u32)) as i32) != 0));
167202
let ti: Value<i32> = Rc::new(RefCell::new(((*t.borrow()) as i32).clone()));
@@ -187,5 +222,62 @@ fn main_0() -> i32 {
187222
(((Color::RED as i32) + (Color::GREEN as i32)) + (Color::BLUE as i32)),
188223
));
189224
assert!(((((*extra.borrow()) == ((0 + 1) + 2)) as i32) != 0));
225+
assert!(
226+
(((((*global_color.with(Value::clone).borrow()) as u32) == ((Color::GREEN as i32) as u32))
227+
as i32)
228+
!= 0)
229+
);
230+
assert!(
231+
(((((*global_opt.with(Value::clone).borrow()) as u32) == ((Option::OPT_B as i32) as u32))
232+
as i32)
233+
!= 0)
234+
);
235+
assert!(
236+
(((((*global_tag.with(Value::clone).borrow()) as u32) == ((Tag::TAG_TWO as i32) as u32))
237+
as i32)
238+
!= 0)
239+
);
240+
assert!(
241+
(((((*(*entries.with(Value::clone).borrow())[(0) as usize]
242+
.color
243+
.borrow()) as u32)
244+
== ((Color::RED as i32) as u32)) as i32)
245+
!= 0)
246+
);
247+
assert!(
248+
(((((*(*entries.with(Value::clone).borrow())[(0) as usize]
249+
.opt
250+
.borrow()) as u32)
251+
== ((Option::OPT_NONE as i32) as u32)) as i32)
252+
!= 0)
253+
);
254+
assert!(
255+
(((((*(*entries.with(Value::clone).borrow())[(1) as usize]
256+
.color
257+
.borrow()) as u32)
258+
== ((Color::GREEN as i32) as u32)) as i32)
259+
!= 0)
260+
);
261+
assert!(
262+
(((((*(*entries.with(Value::clone).borrow())[(1) as usize]
263+
.opt
264+
.borrow()) as u32)
265+
== ((Option::OPT_A as i32) as u32)) as i32)
266+
!= 0)
267+
);
268+
assert!(
269+
(((((*(*entries.with(Value::clone).borrow())[(2) as usize]
270+
.color
271+
.borrow()) as u32)
272+
== ((Color::BLUE as i32) as u32)) as i32)
273+
!= 0)
274+
);
275+
assert!(
276+
(((((*(*entries.with(Value::clone).borrow())[(2) as usize]
277+
.opt
278+
.borrow()) as u32)
279+
== ((Option::OPT_C as i32) as u32)) as i32)
280+
!= 0)
281+
);
190282
return 0;
191283
}

0 commit comments

Comments
 (0)