Skip to content

Commit 9d1d39e

Browse files
authored
Add isize conversion for enum values used as subscript (#254)
C allows indexing an array with an enum value
1 parent 707cad8 commit 9d1d39e

5 files changed

Lines changed: 91 additions & 4 deletions

File tree

cpp2rust/converter/models/converter_refcount.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2165,7 +2165,7 @@ bool ConverterRefCount::ConvertCXXOperatorCallExpr(
21652165
pending_deref_.set(std::format("({} as {}).offset({})",
21662166
ConvertObject(expr->getArg(0)),
21672167
ConvertPtrType(expr->getArg(0)->getType()),
2168-
ConvertRValue(expr->getArg(1))),
2168+
ConvertSubscriptIndex(expr->getArg(1))),
21692169
expr);
21702170
break;
21712171
}
@@ -2185,7 +2185,7 @@ bool ConverterRefCount::ConvertCXXOperatorCallExpr(
21852185
StrCat(std::format("({} as {}).offset({})",
21862186
ConvertObject(expr->getArg(0)),
21872187
ConvertPtrType(expr->getArg(0)->getType()),
2188-
ConvertRValue(expr->getArg(1))));
2188+
ConvertSubscriptIndex(expr->getArg(1))));
21892189

21902190
if (is_inner_boxed) {
21912191
StrCat(GetPointerDerefSuffix(expr->getType()), ".as_pointer()");
@@ -2220,6 +2220,14 @@ void ConverterRefCount::ConvertFunctionParameters(clang::FunctionDecl *decl) {
22202220
}
22212221
}
22222222

2223+
std::string ConverterRefCount::ConvertSubscriptIndex(clang::Expr *idx) {
2224+
auto str = ConvertRValue(idx);
2225+
if (idx->getType()->isEnumeralType()) {
2226+
return std::format("({}) as isize", str);
2227+
}
2228+
return str;
2229+
}
2230+
22232231
void ConverterRefCount::ConvertArraySubscript(clang::Expr *base,
22242232
clang::Expr *idx,
22252233
clang::QualType type) {
@@ -2236,12 +2244,12 @@ void ConverterRefCount::ConvertArraySubscript(clang::Expr *base,
22362244
if (IsStringLiteralExpr(base)) {
22372245
StrCat(std::format("Ptr::from_string_literal({}).offset({})",
22382246
ToString(base->IgnoreParens()->IgnoreImplicit()),
2239-
ConvertRValue(idx)));
2247+
ConvertSubscriptIndex(idx)));
22402248
} else {
22412249
StrCat(std::format("({} as {}).offset({})",
22422250
ToString(base->IgnoreImplicit()),
22432251
ConvertPtrType(base->IgnoreImplicit()->getType()),
2244-
ConvertRValue(idx)));
2252+
ConvertSubscriptIndex(idx)));
22452253
}
22462254

22472255
if (is_inner_boxed) {

cpp2rust/converter/models/converter_refcount.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,8 @@ class ConverterRefCount final : public Converter {
244244
std::string ConvertPtrType(clang::QualType type);
245245
std::string ConvertPointeeType(clang::QualType ptr_type) override;
246246

247+
std::string ConvertSubscriptIndex(clang::Expr *idx);
248+
247249
std::string GetSafeTypeAsString(clang::QualType qual_type) const;
248250

249251
/// The kind of conversion that should be performed.

tests/unit/enum_int_interop_c.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,5 +140,16 @@ int main() {
140140
assert(entries[2].color == BLUE);
141141
assert(entries[2].opt == OPT_C);
142142

143+
const char *names[] = {"red", "green", "blue"};
144+
enum Color idx = GREEN;
145+
assert(names[idx][0] == 'g');
146+
assert(entries[idx].opt == OPT_A);
147+
assert(names[global_tag][0] == 'b');
148+
149+
const char **pp = &names[idx];
150+
assert((*pp)[0] == 'g');
151+
struct Entry *pe = &entries[idx];
152+
assert(pe->opt == OPT_A);
153+
143154
return 0;
144155
}

tests/unit/out/refcount/enum_int_interop_c.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,5 +319,50 @@ fn main_0() -> i32 {
319319
== ((Option::OPT_C as i32) as u32)) as i32)
320320
!= 0)
321321
);
322+
let names: Value<Box<[Ptr<u8>]>> = Rc::new(RefCell::new(Box::new([
323+
Ptr::from_string_literal(b"red"),
324+
Ptr::from_string_literal(b"green"),
325+
Ptr::from_string_literal(b"blue"),
326+
])));
327+
let idx: Value<Color> = Rc::new(RefCell::new(Color::GREEN));
328+
assert!(
329+
((((((*names.borrow())[(*idx.borrow()) as usize]
330+
.offset((0) as isize)
331+
.read()) as i32)
332+
== ('g' as i32)) as i32)
333+
!= 0)
334+
);
335+
assert!(
336+
(((((*(*entries_3.with(Value::clone).borrow())[(*idx.borrow()) as usize]
337+
.opt
338+
.borrow()) as u32)
339+
== ((Option::OPT_A as i32) as u32)) as i32)
340+
!= 0)
341+
);
342+
assert!(
343+
((((((*names.borrow())[(*global_tag_2.with(Value::clone).borrow()) as usize]
344+
.offset((0) as isize)
345+
.read()) as i32)
346+
== ('b' as i32)) as i32)
347+
!= 0)
348+
);
349+
let pp: Value<Ptr<Ptr<u8>>> = Rc::new(RefCell::new(
350+
((names.as_pointer() as Ptr<Ptr<u8>>).offset((*idx.borrow()) as isize)),
351+
));
352+
assert!(
353+
(((((((*pp.borrow()).read()).offset((0) as isize).read()) as i32) == ('g' as i32)) as i32)
354+
!= 0)
355+
);
356+
let pe: Value<Ptr<Entry>> = Rc::new(RefCell::new(
357+
((entries_3.with(Value::clone).as_pointer() as Ptr<Entry>)
358+
.offset((*idx.borrow()) as isize)),
359+
));
360+
assert!(
361+
((({
362+
let _lhs = ((*(*(*pe.borrow()).upgrade().deref()).opt.borrow()) as u32).clone();
363+
_lhs == ((Option::OPT_A as i32) as u32)
364+
}) as i32)
365+
!= 0)
366+
);
322367
return 0;
323368
}

tests/unit/out/unsafe/enum_int_interop_c.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,5 +220,26 @@ unsafe fn main_0() -> i32 {
220220
assert!(
221221
((((entries_3[(2) as usize].opt as u32) == ((Option::OPT_C as i32) as u32)) as i32) != 0)
222222
);
223+
let mut names: [*const libc::c_char; 3] = [
224+
(c"red".as_ptr().cast_mut()).cast_const(),
225+
(c"green".as_ptr().cast_mut()).cast_const(),
226+
(c"blue".as_ptr().cast_mut()).cast_const(),
227+
];
228+
let mut idx: Color = Color::GREEN;
229+
assert!(
230+
(((((*names[(idx) as usize].offset((0) as isize)) as i32) == ('g' as i32)) as i32) != 0)
231+
);
232+
assert!(
233+
((((entries_3[(idx) as usize].opt as u32) == ((Option::OPT_A as i32) as u32)) as i32) != 0)
234+
);
235+
assert!(
236+
(((((*names[(global_tag_2) as usize].offset((0) as isize)) as i32) == ('b' as i32))
237+
as i32)
238+
!= 0)
239+
);
240+
let mut pp: *mut *const libc::c_char = (&mut names[(idx) as usize] as *mut *const libc::c_char);
241+
assert!((((((*(*pp).offset((0) as isize)) as i32) == ('g' as i32)) as i32) != 0));
242+
let mut pe: *mut Entry = (&mut entries_3[(idx) as usize] as *mut Entry);
243+
assert!((((((*pe).opt as u32) == ((Option::OPT_A as i32) as u32)) as i32) != 0));
223244
return 0;
224245
}

0 commit comments

Comments
 (0)