From 8a9145e138f0e6834845178e53bbdbd5124ee861 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 7 Jul 2026 11:33:35 +0100 Subject: [PATCH] Add isize conversion for enum values used as subscript --- .../converter/models/converter_refcount.cpp | 14 ++++-- .../converter/models/converter_refcount.h | 2 + tests/unit/enum_int_interop_c.c | 11 +++++ tests/unit/out/refcount/enum_int_interop_c.rs | 45 +++++++++++++++++++ tests/unit/out/unsafe/enum_int_interop_c.rs | 21 +++++++++ 5 files changed, 90 insertions(+), 3 deletions(-) diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 483c7fdb..2a60af80 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -2154,7 +2154,7 @@ bool ConverterRefCount::ConvertCXXOperatorCallExpr( pending_deref_.set(std::format("({} as {}).offset({})", ConvertObject(expr->getArg(0)), ConvertPtrType(expr->getArg(0)->getType()), - ConvertRValue(expr->getArg(1))), + ConvertSubscriptIndex(expr->getArg(1))), expr); break; } @@ -2174,7 +2174,7 @@ bool ConverterRefCount::ConvertCXXOperatorCallExpr( StrCat(std::format("({} as {}).offset({})", ConvertObject(expr->getArg(0)), ConvertPtrType(expr->getArg(0)->getType()), - ConvertRValue(expr->getArg(1)))); + ConvertSubscriptIndex(expr->getArg(1)))); if (is_inner_boxed) { StrCat(GetPointerDerefSuffix(expr->getType()), ".as_pointer()"); @@ -2209,6 +2209,14 @@ void ConverterRefCount::ConvertFunctionParameters(clang::FunctionDecl *decl) { } } +std::string ConverterRefCount::ConvertSubscriptIndex(clang::Expr *idx) { + auto str = ConvertRValue(idx); + if (idx->getType()->isEnumeralType()) { + return std::format("({}) as isize", str); + } + return str; +} + void ConverterRefCount::ConvertArraySubscript(clang::Expr *base, clang::Expr *idx, clang::QualType type) { @@ -2225,7 +2233,7 @@ void ConverterRefCount::ConvertArraySubscript(clang::Expr *base, StrCat(std::format("({} as {}).offset({})", ToString(base->IgnoreImplicit()), ConvertPtrType(base->IgnoreImplicit()->getType()), - ConvertRValue(idx))); + ConvertSubscriptIndex(idx))); if (is_inner_boxed) { StrCat(GetPointerDerefSuffix(type), ".as_pointer()"); diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index e58853e1..5b969a0d 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -242,6 +242,8 @@ class ConverterRefCount final : public Converter { std::string ConvertPtrType(clang::QualType type); std::string ConvertPointeeType(clang::QualType ptr_type) override; + std::string ConvertSubscriptIndex(clang::Expr *idx); + std::string GetSafeTypeAsString(clang::QualType qual_type) const; /// The kind of conversion that should be performed. diff --git a/tests/unit/enum_int_interop_c.c b/tests/unit/enum_int_interop_c.c index 22218c40..e08da80c 100644 --- a/tests/unit/enum_int_interop_c.c +++ b/tests/unit/enum_int_interop_c.c @@ -140,5 +140,16 @@ int main() { assert(entries[2].color == BLUE); assert(entries[2].opt == OPT_C); + const char *names[] = {"red", "green", "blue"}; + enum Color idx = GREEN; + assert(names[idx][0] == 'g'); + assert(entries[idx].opt == OPT_A); + assert(names[global_tag][0] == 'b'); + + const char **pp = &names[idx]; + assert((*pp)[0] == 'g'); + struct Entry *pe = &entries[idx]; + assert(pe->opt == OPT_A); + return 0; } diff --git a/tests/unit/out/refcount/enum_int_interop_c.rs b/tests/unit/out/refcount/enum_int_interop_c.rs index c6945040..edb5e2f5 100644 --- a/tests/unit/out/refcount/enum_int_interop_c.rs +++ b/tests/unit/out/refcount/enum_int_interop_c.rs @@ -319,5 +319,50 @@ fn main_0() -> i32 { == ((Option::OPT_C as i32) as u32)) as i32) != 0) ); + let names: Value]>> = Rc::new(RefCell::new(Box::new([ + Ptr::from_string_literal(b"red"), + Ptr::from_string_literal(b"green"), + Ptr::from_string_literal(b"blue"), + ]))); + let idx: Value = Rc::new(RefCell::new(Color::GREEN)); + assert!( + ((((((*names.borrow())[(*idx.borrow()) as usize] + .offset((0) as isize) + .read()) as i32) + == ('g' as i32)) as i32) + != 0) + ); + assert!( + (((((*(*entries_3.with(Value::clone).borrow())[(*idx.borrow()) as usize] + .opt + .borrow()) as u32) + == ((Option::OPT_A as i32) as u32)) as i32) + != 0) + ); + assert!( + ((((((*names.borrow())[(*global_tag_2.with(Value::clone).borrow()) as usize] + .offset((0) as isize) + .read()) as i32) + == ('b' as i32)) as i32) + != 0) + ); + let pp: Value>> = Rc::new(RefCell::new( + ((names.as_pointer() as Ptr>).offset((*idx.borrow()) as isize)), + )); + assert!( + (((((((*pp.borrow()).read()).offset((0) as isize).read()) as i32) == ('g' as i32)) as i32) + != 0) + ); + let pe: Value> = Rc::new(RefCell::new( + ((entries_3.with(Value::clone).as_pointer() as Ptr) + .offset((*idx.borrow()) as isize)), + )); + assert!( + ((({ + let _lhs = ((*(*(*pe.borrow()).upgrade().deref()).opt.borrow()) as u32).clone(); + _lhs == ((Option::OPT_A as i32) as u32) + }) as i32) + != 0) + ); return 0; } diff --git a/tests/unit/out/unsafe/enum_int_interop_c.rs b/tests/unit/out/unsafe/enum_int_interop_c.rs index e4fa3dd0..2b4d91bc 100644 --- a/tests/unit/out/unsafe/enum_int_interop_c.rs +++ b/tests/unit/out/unsafe/enum_int_interop_c.rs @@ -220,5 +220,26 @@ unsafe fn main_0() -> i32 { assert!( ((((entries_3[(2) as usize].opt as u32) == ((Option::OPT_C as i32) as u32)) as i32) != 0) ); + let mut names: [*const libc::c_char; 3] = [ + (c"red".as_ptr().cast_mut()).cast_const(), + (c"green".as_ptr().cast_mut()).cast_const(), + (c"blue".as_ptr().cast_mut()).cast_const(), + ]; + let mut idx: Color = Color::GREEN; + assert!( + (((((*names[(idx) as usize].offset((0) as isize)) as i32) == ('g' as i32)) as i32) != 0) + ); + assert!( + ((((entries_3[(idx) as usize].opt as u32) == ((Option::OPT_A as i32) as u32)) as i32) != 0) + ); + assert!( + (((((*names[(global_tag_2) as usize].offset((0) as isize)) as i32) == ('b' as i32)) + as i32) + != 0) + ); + let mut pp: *mut *const libc::c_char = (&mut names[(idx) as usize] as *mut *const libc::c_char); + assert!((((((*(*pp).offset((0) as isize)) as i32) == ('g' as i32)) as i32) != 0)); + let mut pe: *mut Entry = (&mut entries_3[(idx) as usize] as *mut Entry); + assert!((((((*pe).opt as u32) == ((Option::OPT_A as i32) as u32)) as i32) != 0)); return 0; }