From 908070947406dd942ada377278c26715077187e2 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 24 Jun 2026 15:38:31 +0100 Subject: [PATCH] Add ByteRepr for enums --- cpp2rust/converter/converter.cpp | 3 ++ cpp2rust/converter/converter.h | 2 + .../converter/models/converter_refcount.cpp | 17 ++++-- .../converter/models/converter_refcount.h | 2 + .../refcount/cross_tu_anon_enum_collision.rs | 16 ++++++ .../out/refcount/cross_tu_tag_collision.rs | 8 +++ .../ub/out/refcount/enum_out_of_range_cast.rs | 8 +++ .../refcount/enum_out_of_range_increment.rs | 8 +++ tests/unit/out/refcount/anonymous_enum.rs | 53 ++++++++++++++++++- tests/unit/out/refcount/anonymous_enum_c.rs | 53 ++++++++++++++++++- .../unit/out/refcount/bool_condition_enum.rs | 8 +++ .../out/refcount/bool_condition_enum_c.rs | 8 +++ .../out/refcount/bool_condition_logical.rs | 8 +++ .../out/refcount/bool_condition_logical_c.rs | 8 +++ tests/unit/out/refcount/c_struct.rs | 8 +++ .../out/refcount/enum_default_in_static.rs | 21 +++++++- tests/unit/out/refcount/enum_increment.rs | 8 +++ tests/unit/out/refcount/enum_int_interop.rs | 24 +++++++++ tests/unit/out/refcount/enum_int_interop_c.rs | 24 +++++++++ tests/unit/out/refcount/switch_char.rs | 8 +++ tests/unit/out/refcount/switch_enum.rs | 8 +++ .../out/refcount/va_arg_non_primitive_ptrs.rs | 8 +++ 22 files changed, 304 insertions(+), 7 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 131cb7ed..09e9d526 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -3154,6 +3154,7 @@ bool Converter::VisitEnumDecl(clang::EnumDecl *decl) { AddFromImpl(decl); AddIncDecImpls(decl); + AddByteReprTrait(decl); return false; } @@ -3936,6 +3937,8 @@ void Converter::EmitDefaultStructLiteral(const clang::RecordDecl *decl) { void Converter::AddByteReprTrait(const clang::RecordDecl *decl) {} +void Converter::AddByteReprTrait(const clang::EnumDecl *decl) {} + void Converter::ConvertUnsignedArithBinaryOperator(clang::BinaryOperator *op, clang::Expr *expr) { StrCat(token::kDot); diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 63de20e4..735b118e 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -539,6 +539,8 @@ class Converter : public clang::RecursiveASTVisitor { virtual void AddByteReprTrait(const clang::RecordDecl *decl); + virtual void AddByteReprTrait(const clang::EnumDecl *decl); + virtual void ConvertUnsignedArithBinaryOperator(clang::BinaryOperator *binary_operator, clang::Expr *expr); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 6dedd871..17b4f149 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -510,10 +510,8 @@ static bool recordImplementsByteRepr(const clang::RecordDecl *decl) { // fields. for (auto *f : decl->fields()) { auto qt = f->getType(); - if (qt->isEnumeralType()) { - return false; - } - if (!qt->isIntegerType() && !qt->isFloatingType()) { + if (!qt->isIntegerType() && !qt->isFloatingType() && + !qt->isEnumeralType()) { return false; } } @@ -567,6 +565,17 @@ void ConverterRefCount::AddByteReprTrait(const clang::RecordDecl *decl) { } } +void ConverterRefCount::AddByteReprTrait(const clang::EnumDecl *decl) { + auto name = GetRecordName(decl); + StrCat(std::format("impl ByteRepr for {}", name)); + PushBrace impl_brace(*this); + StrCat( + "fn to_bytes(&self, buf: &mut [u8]) { (*self as i32).to_bytes(buf); }"); + StrCat(std::format("fn from_bytes(buf: &[u8]) -> Self {{ " + "<{}>::from(i32::from_bytes(buf)) }}", + name)); +} + std::string ConverterRefCount::GetSelfMaybeWithMut(const clang::CXXMethodDecl *decl) { return "&self"; diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index 491c5222..122a930d 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -39,6 +39,8 @@ class ConverterRefCount final : public Converter { void AddByteReprTrait(const clang::RecordDecl *decl) override; + void AddByteReprTrait(const clang::EnumDecl *decl) override; + void AddDefaultTrait(const clang::RecordDecl *decl) override; void AddDefaultTraitForUnion(const clang::RecordDecl *decl) override; diff --git a/tests/multi-file/cross_tu_anon_enum_collision/out/refcount/cross_tu_anon_enum_collision.rs b/tests/multi-file/cross_tu_anon_enum_collision/out/refcount/cross_tu_anon_enum_collision.rs index c7edae33..0ce84bdb 100644 --- a/tests/multi-file/cross_tu_anon_enum_collision/out/refcount/cross_tu_anon_enum_collision.rs +++ b/tests/multi-file/cross_tu_anon_enum_collision/out/refcount/cross_tu_anon_enum_collision.rs @@ -20,6 +20,14 @@ impl From for anon_0 { } } libcc2rs::impl_enum_inc_dec!(anon_0); +impl ByteRepr for anon_0 { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} pub fn a_value_1() -> i32 { let x: Value = Rc::new(RefCell::new(0)); (*x.borrow_mut()) |= (anon_0::ALPHA as i32); @@ -47,6 +55,14 @@ impl From for anon_3 { } } libcc2rs::impl_enum_inc_dec!(anon_3); +impl ByteRepr for anon_3 { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} pub fn b_value_2() -> i32 { let x: Value = Rc::new(RefCell::new(0)); (*x.borrow_mut()) |= (anon_3::BETA as i32); diff --git a/tests/multi-file/cross_tu_tag_collision/out/refcount/cross_tu_tag_collision.rs b/tests/multi-file/cross_tu_tag_collision/out/refcount/cross_tu_tag_collision.rs index 5fd97a8f..90529368 100644 --- a/tests/multi-file/cross_tu_tag_collision/out/refcount/cross_tu_tag_collision.rs +++ b/tests/multi-file/cross_tu_tag_collision/out/refcount/cross_tu_tag_collision.rs @@ -51,6 +51,14 @@ impl From for widget_enum { } } libcc2rs::impl_enum_inc_dec!(widget_enum); +impl ByteRepr for widget_enum { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} pub fn b_value_1() -> i32 { let w: Value = Rc::new(RefCell::new(widget_enum::WIDGET_C)); return ((*w.borrow()) as i32).clone(); diff --git a/tests/ub/out/refcount/enum_out_of_range_cast.rs b/tests/ub/out/refcount/enum_out_of_range_cast.rs index 60538ac8..cdd50986 100644 --- a/tests/ub/out/refcount/enum_out_of_range_cast.rs +++ b/tests/ub/out/refcount/enum_out_of_range_cast.rs @@ -24,6 +24,14 @@ impl From for Color { } } libcc2rs::impl_enum_inc_dec!(Color); +impl ByteRepr for Color { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/ub/out/refcount/enum_out_of_range_increment.rs b/tests/ub/out/refcount/enum_out_of_range_increment.rs index 4809fa73..1b764f17 100644 --- a/tests/ub/out/refcount/enum_out_of_range_increment.rs +++ b/tests/ub/out/refcount/enum_out_of_range_increment.rs @@ -24,6 +24,14 @@ impl From for color { } } libcc2rs::impl_enum_inc_dec!(color); +impl ByteRepr for color { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/unit/out/refcount/anonymous_enum.rs b/tests/unit/out/refcount/anonymous_enum.rs index 25de7201..9fbf91ed 100644 --- a/tests/unit/out/refcount/anonymous_enum.rs +++ b/tests/unit/out/refcount/anonymous_enum.rs @@ -22,6 +22,14 @@ impl From for anon_0 { } } libcc2rs::impl_enum_inc_dec!(anon_0); +impl ByteRepr for anon_0 { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Clone, Copy, PartialEq, Debug, Default)] enum anon_1 { #[default] @@ -38,6 +46,14 @@ impl From for anon_1 { } } libcc2rs::impl_enum_inc_dec!(anon_1); +impl ByteRepr for anon_1 { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Default)] pub struct S { pub a: Value, @@ -76,6 +92,14 @@ impl From for TdEnum { } } libcc2rs::impl_enum_inc_dec!(TdEnum); +impl ByteRepr for TdEnum { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Clone, Copy, PartialEq, Debug, Default)] enum anon_2 { #[default] @@ -92,6 +116,14 @@ impl From for anon_2 { } } libcc2rs::impl_enum_inc_dec!(anon_2); +impl ByteRepr for anon_2 { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Default)] pub struct WithAnonField { pub a: Value, @@ -106,7 +138,18 @@ impl Clone for WithAnonField { this } } -impl ByteRepr for WithAnonField {} +impl ByteRepr for WithAnonField { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.a.borrow()).to_bytes(&mut buf[0..4]); + (*self.field.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + a: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + field: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} pub fn main() { std::process::exit(main_0()); } @@ -127,6 +170,14 @@ fn main_0() -> i32 { } } libcc2rs::impl_enum_inc_dec!(anon_3); + impl ByteRepr for anon_3 { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } + }; assert!(((anon_0::FIRST_A as i32) != (anon_0::FIRST_B as i32))); assert!(((anon_1::SECOND_A as i32) != (anon_1::SECOND_B as i32))); assert!(((anon_3::THIRD_A as i32) != (anon_3::THIRD_B as i32))); diff --git a/tests/unit/out/refcount/anonymous_enum_c.rs b/tests/unit/out/refcount/anonymous_enum_c.rs index 772ea6e5..199dc233 100644 --- a/tests/unit/out/refcount/anonymous_enum_c.rs +++ b/tests/unit/out/refcount/anonymous_enum_c.rs @@ -22,6 +22,14 @@ impl From for anon_0 { } } libcc2rs::impl_enum_inc_dec!(anon_0); +impl ByteRepr for anon_0 { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Clone, Copy, PartialEq, Debug, Default)] enum anon_1 { #[default] @@ -38,6 +46,14 @@ impl From for anon_1 { } } libcc2rs::impl_enum_inc_dec!(anon_1); +impl ByteRepr for anon_1 { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Default)] pub struct S { pub a: Value, @@ -68,6 +84,14 @@ impl From for TdEnum_enum { } } libcc2rs::impl_enum_inc_dec!(TdEnum_enum); +impl ByteRepr for TdEnum_enum { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Clone, Copy, PartialEq, Debug, Default)] enum anon_2 { #[default] @@ -84,12 +108,31 @@ impl From for anon_2 { } } libcc2rs::impl_enum_inc_dec!(anon_2); +impl ByteRepr for anon_2 { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Default)] pub struct WithAnonField { pub a: Value, pub field: Value, } -impl ByteRepr for WithAnonField {} +impl ByteRepr for WithAnonField { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.a.borrow()).to_bytes(&mut buf[0..4]); + (*self.field.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + a: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + field: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} pub fn main() { std::process::exit(main_0()); } @@ -110,6 +153,14 @@ fn main_0() -> i32 { } } libcc2rs::impl_enum_inc_dec!(anon_3); + impl ByteRepr for anon_3 { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } + }; assert!(((((anon_0::FIRST_A as i32) != (anon_0::FIRST_B as i32)) as i32) != 0)); assert!(((((anon_1::SECOND_A as i32) != (anon_1::SECOND_B as i32)) as i32) != 0)); assert!(((((anon_3::THIRD_A as i32) != (anon_3::THIRD_B as i32)) as i32) != 0)); diff --git a/tests/unit/out/refcount/bool_condition_enum.rs b/tests/unit/out/refcount/bool_condition_enum.rs index 1d7dc853..228c2f70 100644 --- a/tests/unit/out/refcount/bool_condition_enum.rs +++ b/tests/unit/out/refcount/bool_condition_enum.rs @@ -24,6 +24,14 @@ impl From for Code { } } libcc2rs::impl_enum_inc_dec!(Code); +impl ByteRepr for Code { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/unit/out/refcount/bool_condition_enum_c.rs b/tests/unit/out/refcount/bool_condition_enum_c.rs index f84c1a88..c22850e6 100644 --- a/tests/unit/out/refcount/bool_condition_enum_c.rs +++ b/tests/unit/out/refcount/bool_condition_enum_c.rs @@ -24,6 +24,14 @@ impl From for Code { } } libcc2rs::impl_enum_inc_dec!(Code); +impl ByteRepr for Code { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/unit/out/refcount/bool_condition_logical.rs b/tests/unit/out/refcount/bool_condition_logical.rs index 9b340849..815ea3f8 100644 --- a/tests/unit/out/refcount/bool_condition_logical.rs +++ b/tests/unit/out/refcount/bool_condition_logical.rs @@ -24,6 +24,14 @@ impl From for Code { } } libcc2rs::impl_enum_inc_dec!(Code); +impl ByteRepr for Code { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} thread_local!( pub static side_effect_0: Value = Rc::new(RefCell::new(0)); ); diff --git a/tests/unit/out/refcount/bool_condition_logical_c.rs b/tests/unit/out/refcount/bool_condition_logical_c.rs index a878ce93..e0bae274 100644 --- a/tests/unit/out/refcount/bool_condition_logical_c.rs +++ b/tests/unit/out/refcount/bool_condition_logical_c.rs @@ -24,6 +24,14 @@ impl From for Code { } } libcc2rs::impl_enum_inc_dec!(Code); +impl ByteRepr for Code { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} thread_local!( pub static side_effect_0: Value = Rc::new(RefCell::new(0)); ); diff --git a/tests/unit/out/refcount/c_struct.rs b/tests/unit/out/refcount/c_struct.rs index 0549baab..36ebdeb4 100644 --- a/tests/unit/out/refcount/c_struct.rs +++ b/tests/unit/out/refcount/c_struct.rs @@ -53,6 +53,14 @@ impl From for Color { } } libcc2rs::impl_enum_inc_dec!(Color); +impl ByteRepr for Color { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Default)] pub struct Inner { pub a: Value, diff --git a/tests/unit/out/refcount/enum_default_in_static.rs b/tests/unit/out/refcount/enum_default_in_static.rs index 96f3bd8e..0e6f4c29 100644 --- a/tests/unit/out/refcount/enum_default_in_static.rs +++ b/tests/unit/out/refcount/enum_default_in_static.rs @@ -24,12 +24,31 @@ impl From for Mode { } } libcc2rs::impl_enum_inc_dec!(Mode); +impl ByteRepr for Mode { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Default)] pub struct Config { pub count: Value, pub mode: Value, } -impl ByteRepr for Config {} +impl ByteRepr for Config { + fn to_bytes(&self, buf: &mut [u8]) { + (*self.count.borrow()).to_bytes(&mut buf[0..4]); + (*self.mode.borrow()).to_bytes(&mut buf[4..8]); + } + fn from_bytes(buf: &[u8]) -> Self { + Self { + count: Rc::new(RefCell::new(::from_bytes(&buf[0..4]))), + mode: Rc::new(RefCell::new(::from_bytes(&buf[4..8]))), + } + } +} thread_local!( pub static config_0: Value = >::default(); ); diff --git a/tests/unit/out/refcount/enum_increment.rs b/tests/unit/out/refcount/enum_increment.rs index 25a24a2f..387ac2b6 100644 --- a/tests/unit/out/refcount/enum_increment.rs +++ b/tests/unit/out/refcount/enum_increment.rs @@ -26,6 +26,14 @@ impl From for color { } } libcc2rs::impl_enum_inc_dec!(color); +impl ByteRepr for color { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} pub fn main() { std::process::exit(main_0()); } diff --git a/tests/unit/out/refcount/enum_int_interop.rs b/tests/unit/out/refcount/enum_int_interop.rs index 887ea844..fea2807d 100644 --- a/tests/unit/out/refcount/enum_int_interop.rs +++ b/tests/unit/out/refcount/enum_int_interop.rs @@ -24,6 +24,14 @@ impl From for Color { } } libcc2rs::impl_enum_inc_dec!(Color); +impl ByteRepr for Color { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { + ::from(i32::from_bytes(buf)) + } +} #[derive(Clone, Copy, PartialEq, Debug, Default)] enum Option { #[default] @@ -44,6 +52,14 @@ impl From for Option { } } libcc2rs::impl_enum_inc_dec!(Option); +impl ByteRepr for Option { + fn to_bytes(&self, buf: &mut [u8]) { + (*self as i32).to_bytes(buf); + } + fn from_bytes(buf: &[u8]) -> Self { +