From 9d889380e39af6beca47697f9bbe35c370b7cf2d Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Sat, 18 Apr 2026 21:43:23 +0100 Subject: [PATCH 1/7] Translate C structs --- cpp2rust/converter/converter.cpp | 186 +++++++++++------- cpp2rust/converter/converter.h | 8 +- .../converter/models/converter_refcount.cpp | 7 +- .../converter/models/converter_refcount.h | 5 +- 4 files changed, 125 insertions(+), 81 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index d1e6eb00..a5845592 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -580,6 +580,113 @@ static bool recordDerivesCopy(const clang::CXXRecordDecl *decl) { return true; } +bool Converter::VisitRecordDecl(clang::RecordDecl *decl) { + decl->dumpColor(); + + // VisitCXXRecordDecl already visited the record + if (clang::isa(decl)) { + return true; + } + + if (!decl->isCompleteDefinition()) { + return false; + } + + if (!record_decls_.insert(GetID(decl)).second) { + return false; + } + + Mapper::AddRuleForUserDefinedType(decl); + EmitRustStruct(decl); + + return false; +} + +void Converter::EmitRustStruct(clang::RecordDecl *decl) { + // Enums and static variables. In rust they live outside the record + for (auto *d : decl->decls()) { + if (auto *enum_decl = llvm::dyn_cast(d)) { + VisitEnumDecl(enum_decl); + } + if (auto *var_decl = clang::dyn_cast(d)) { + VisitVarDecl(var_decl); + } + } + + // Inner records. In rust they live outside the record + for (auto *d : decl->decls()) { + if (auto *nested = clang::dyn_cast(d)) { + if (!nested->isImplicit()) { + inner_structs_[GetID(nested)] = GetRecordName(nested); + if (auto *cxx = clang::dyn_cast(nested)) { + VisitCXXRecordDecl(cxx); + } else { + VisitRecordDecl(nested); + } + } + } + } + + // Derived traits + StrCat("#[derive("); + if (auto *cxx = clang::dyn_cast(decl)) { + for (auto *attr : GetStructAttributes(cxx)) { + StrCat(attr, ","); + } + } else { + StrCat("Clone, Default"); + } + StrCat(")]"); + + // Fields + auto access = clang::dyn_cast(decl) + ? AccessSpecifierAsString(decl->getAccess()) + : keyword::kPub; + StrCat(access, keyword::kStruct, GetRecordName(decl), + token::kOpenCurlyBracket); + for (auto *field : decl->fields()) { + VisitFieldDecl(field); + } + StrCat(token::kCloseCurlyBracket); + + // C++ method decls + if (auto *cxx = clang::dyn_cast(decl)) { + auto struct_name = GetRecordName(cxx); + + ConvertCXXMethodDecls( + cxx, std::string(keyword::kImpl) + ' ' + struct_name, + [](const auto *method) { + return !method->isImplicit() && + !(method->getDefinition() && + method->getDefinition()->isDefaulted()) && + (method->isThisDeclarationADefinition() || + clang::isa(method)) && + !method->isVirtual() && + !clang::isa(method); + }); + + if (cxx->bases_begin() != cxx->bases_end()) { + ConvertCXXMethodDecls( + cxx, + std::format("{} impl {} for {}", keyword_unsafe_, + GetUnsafeTypeAsString(cxx->bases_begin()->getType()), + struct_name), + [](const auto *method) { + return !method->isImplicit() && method->isVirtual(); + }); + } + } + + // Traits + if (auto *cxx = clang::dyn_cast(decl)) { + AddOrdTrait(cxx); + AddCloneTrait(cxx); + AddDropTrait(cxx); + AddDefaultTrait(cxx); + } + AddByteReprTrait(decl); +} + bool Converter::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) { if (clang::isa(decl)) { materializeTemplateSpecialization(decl); @@ -623,74 +730,7 @@ bool Converter::VisitCXXRecordDecl(clang::CXXRecordDecl *decl) { } } - auto struct_name = GetRecordName(decl); - - // First visit the nested enums - for (auto d : decl->decls()) { - if (auto enum_decl = llvm::dyn_cast(d)) { - VisitEnumDecl(enum_decl); - } - } - - for (auto *decl : decl->decls()) { - if (auto var_decl = clang::dyn_cast(decl)) { - VisitVarDecl(var_decl); - } - } - - auto nested = GetNestedStructs(decl); - for (auto *record_decl : nested) { - auto ID = GetID(record_decl); - inner_structs_[ID] = GetRecordName(record_decl); - VisitCXXRecordDecl(record_decl); - } - - StrCat(token::kHash, token::kOpenBracket, "derive", token::kOpenParen); - bool derives_default = RecordDerivesDefault(decl); - - for (auto *struct_attr : GetStructAttributes(decl, derives_default)) { - StrCat(struct_attr, token::kComma); - } - StrCat(token::kCloseParen, token::kCloseBracket); - - auto access_specifier = decl->getAccess(); - StrCat(AccessSpecifierAsString(access_specifier), keyword::kStruct, - struct_name, token::kOpenCurlyBracket); - for (auto *field : decl->fields()) { - VisitFieldDecl(field); - } - StrCat(token::kCloseCurlyBracket); - - ConvertCXXMethodDecls( - decl, std::string(keyword::kImpl) + ' ' + struct_name, - [](const auto *method) { - return !method->isImplicit() && - !(method->getDefinition() && - method->getDefinition()->isDefaulted()) && - (method->isThisDeclarationADefinition() || - clang::isa(method)) && - !method->isVirtual() && - !clang::isa(method); - }); - - AddOrdTrait(decl); - AddCloneTrait(decl); - AddDropTrait(decl); - if (!derives_default) { - AddDefaultTrait(decl); - } - AddByteReprTrait(decl); - - if (decl->bases_begin() != decl->bases_end()) { - ConvertCXXMethodDecls( - decl, - std::format("{} impl {} for {}", keyword_unsafe_, - GetUnsafeTypeAsString(decl->bases_begin()->getType()), - struct_name), - [](const auto *method) { - return !method->isImplicit() && method->isVirtual(); - }); - } + EmitRustStruct(decl); } else { // FIXME: improve error handling assert(0 && "unsupported union"); @@ -2797,8 +2837,7 @@ std::string Converter::GetRecordName(const clang::NamedDecl *decl) const { } std::vector -Converter::GetStructAttributes(const clang::CXXRecordDecl *decl, - bool &out_impl_default) { +Converter::GetStructAttributes(const clang::CXXRecordDecl *decl) { std::vector struct_attrs = {}; if (recordDerivesCopy(decl)) { @@ -3106,11 +3145,14 @@ void Converter::AddCloneTrait(const clang::CXXRecordDecl *decl) {} void Converter::AddDropTrait(const clang::CXXRecordDecl *decl) {} void Converter::AddDefaultTrait(const clang::CXXRecordDecl *decl) { + if (RecordDerivesDefault(decl)) { + return; + } auto struct_name = GetRecordName(decl); StrCat(std::format("impl Default for {}", struct_name), token::kOpenCurlyBracket, "fn default() -> Self", token::kOpenCurlyBracket); - if (auto default_ctor = GetUserDefinedDefaultConstructor(decl)) { + if (auto *default_ctor = GetUserDefinedDefaultConstructor(decl)) { StrCat(keyword_unsafe_, token::kOpenCurlyBracket); Convert(clang::CXXConstructExpr::Create( ctx_, ctx_.getCanonicalTagType(decl), clang::SourceLocation(), @@ -3133,7 +3175,7 @@ void Converter::AddDefaultTrait(const clang::CXXRecordDecl *decl) { StrCat(token::kCloseCurlyBracket, token::kCloseCurlyBracket); } -void Converter::AddByteReprTrait(const clang::CXXRecordDecl *decl) {} +void Converter::AddByteReprTrait(const clang::RecordDecl *decl) {} void Converter::ConvertUnsignedArithBinaryOperator(clang::BinaryOperator *op, clang::Expr *expr) { diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 6f2c3719..141769bf 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -95,8 +95,12 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool ConvertLambdaVarDecl(clang::VarDecl *decl); + bool VisitRecordDecl(clang::RecordDecl *decl); + virtual bool VisitCXXRecordDecl(clang::CXXRecordDecl *decl); + void EmitRustStruct(clang::RecordDecl *decl); + virtual bool VisitCXXMethodDecl(clang::CXXMethodDecl *decl); virtual std::string GetSelfMaybeWithMut(const clang::CXXMethodDecl *decl); @@ -355,7 +359,7 @@ class Converter : public clang::RecursiveASTVisitor { virtual std::string GetRecordName(const clang::NamedDecl *decl) const; virtual std::vector - GetStructAttributes(const clang::CXXRecordDecl *decl, bool &out_impl_default); + GetStructAttributes(const clang::CXXRecordDecl *decl); virtual std::string GetUnsafeTypeAsString(clang::QualType qual_type) const; @@ -410,7 +414,7 @@ class Converter : public clang::RecursiveASTVisitor { virtual void AddDefaultTrait(const clang::CXXRecordDecl *decl); - virtual void AddByteReprTrait(const clang::CXXRecordDecl *decl); + virtual void AddByteReprTrait(const clang::RecordDecl *decl); virtual void ConvertUnsignedArithBinaryOperator(clang::BinaryOperator *binary_operator, diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 223bd51a..74f9cbaa 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -494,7 +494,7 @@ void ConverterRefCount::AddDropTrait(const clang::CXXRecordDecl *decl) { StrCat("}"); } -void ConverterRefCount::AddByteReprTrait(const clang::CXXRecordDecl *decl) { +void ConverterRefCount::AddByteReprTrait(const clang::RecordDecl *decl) { auto struct_name = GetRecordName(decl); StrCat(std::format("impl ByteRepr for {}", struct_name), token::kOpenCurlyBracket, token::kCloseCurlyBracket); @@ -1604,11 +1604,10 @@ ConverterRefCount::ConvertVarDefaultInit(clang::QualType qual_type) { } std::vector -ConverterRefCount::GetStructAttributes(const clang::CXXRecordDecl *decl, - bool &out_impl_default) { +ConverterRefCount::GetStructAttributes(const clang::CXXRecordDecl *decl) { std::vector attrs = {}; - if (out_impl_default) { + if (RecordDerivesDefault(decl)) { attrs.emplace_back("Default"); } return attrs; diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index a55aad58..2a39caec 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -35,7 +35,7 @@ class ConverterRefCount final : public Converter { void AddDropTrait(const clang::CXXRecordDecl *decl) override; - void AddByteReprTrait(const clang::CXXRecordDecl *decl) override; + void AddByteReprTrait(const clang::RecordDecl *decl) override; void AddDefaultTrait(const clang::CXXRecordDecl *decl) override; @@ -121,8 +121,7 @@ class ConverterRefCount final : public Converter { std::string ConvertVarDefaultInit(clang::QualType qual_type) override; std::vector - GetStructAttributes(const clang::CXXRecordDecl *decl, - bool &out_impl_default) override; + GetStructAttributes(const clang::CXXRecordDecl *decl) override; bool MayCauseBorrowMutError(const clang::Expr *lhs, const clang::Expr *rhs); From f9cdc9cb1cbcbc5910ecb31106a0b3613102ef6b Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Sat, 18 Apr 2026 21:47:14 +0100 Subject: [PATCH 2/7] Move va_arg files to cpp They don't compile in C for the moment. --- tests/unit/{va_arg_chain.c => va_arg_chain.cpp} | 0 tests/unit/{va_arg_concat.c => va_arg_concat.cpp} | 0 tests/unit/{va_arg_conditional.c => va_arg_conditional.cpp} | 0 tests/unit/{va_arg_copy.c => va_arg_copy.cpp} | 0 tests/unit/{va_arg_forward.c => va_arg_forward.cpp} | 0 tests/unit/{va_arg_mixed_int_ptr.c => va_arg_mixed_int_ptr.cpp} | 0 tests/unit/{va_arg_mixed_types.c => va_arg_mixed_types.cpp} | 0 tests/unit/{va_arg_printf.c => va_arg_printf.cpp} | 0 tests/unit/{va_arg_promotion.c => va_arg_promotion.cpp} | 0 tests/unit/{va_arg_snprintf.c => va_arg_snprintf.cpp} | 0 tests/unit/{va_arg_two_passes.c => va_arg_two_passes.cpp} | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename tests/unit/{va_arg_chain.c => va_arg_chain.cpp} (100%) rename tests/unit/{va_arg_concat.c => va_arg_concat.cpp} (100%) rename tests/unit/{va_arg_conditional.c => va_arg_conditional.cpp} (100%) rename tests/unit/{va_arg_copy.c => va_arg_copy.cpp} (100%) rename tests/unit/{va_arg_forward.c => va_arg_forward.cpp} (100%) rename tests/unit/{va_arg_mixed_int_ptr.c => va_arg_mixed_int_ptr.cpp} (100%) rename tests/unit/{va_arg_mixed_types.c => va_arg_mixed_types.cpp} (100%) rename tests/unit/{va_arg_printf.c => va_arg_printf.cpp} (100%) rename tests/unit/{va_arg_promotion.c => va_arg_promotion.cpp} (100%) rename tests/unit/{va_arg_snprintf.c => va_arg_snprintf.cpp} (100%) rename tests/unit/{va_arg_two_passes.c => va_arg_two_passes.cpp} (100%) diff --git a/tests/unit/va_arg_chain.c b/tests/unit/va_arg_chain.cpp similarity index 100% rename from tests/unit/va_arg_chain.c rename to tests/unit/va_arg_chain.cpp diff --git a/tests/unit/va_arg_concat.c b/tests/unit/va_arg_concat.cpp similarity index 100% rename from tests/unit/va_arg_concat.c rename to tests/unit/va_arg_concat.cpp diff --git a/tests/unit/va_arg_conditional.c b/tests/unit/va_arg_conditional.cpp similarity index 100% rename from tests/unit/va_arg_conditional.c rename to tests/unit/va_arg_conditional.cpp diff --git a/tests/unit/va_arg_copy.c b/tests/unit/va_arg_copy.cpp similarity index 100% rename from tests/unit/va_arg_copy.c rename to tests/unit/va_arg_copy.cpp diff --git a/tests/unit/va_arg_forward.c b/tests/unit/va_arg_forward.cpp similarity index 100% rename from tests/unit/va_arg_forward.c rename to tests/unit/va_arg_forward.cpp diff --git a/tests/unit/va_arg_mixed_int_ptr.c b/tests/unit/va_arg_mixed_int_ptr.cpp similarity index 100% rename from tests/unit/va_arg_mixed_int_ptr.c rename to tests/unit/va_arg_mixed_int_ptr.cpp diff --git a/tests/unit/va_arg_mixed_types.c b/tests/unit/va_arg_mixed_types.cpp similarity index 100% rename from tests/unit/va_arg_mixed_types.c rename to tests/unit/va_arg_mixed_types.cpp diff --git a/tests/unit/va_arg_printf.c b/tests/unit/va_arg_printf.cpp similarity index 100% rename from tests/unit/va_arg_printf.c rename to tests/unit/va_arg_printf.cpp diff --git a/tests/unit/va_arg_promotion.c b/tests/unit/va_arg_promotion.cpp similarity index 100% rename from tests/unit/va_arg_promotion.c rename to tests/unit/va_arg_promotion.cpp diff --git a/tests/unit/va_arg_snprintf.c b/tests/unit/va_arg_snprintf.cpp similarity index 100% rename from tests/unit/va_arg_snprintf.c rename to tests/unit/va_arg_snprintf.cpp diff --git a/tests/unit/va_arg_two_passes.c b/tests/unit/va_arg_two_passes.cpp similarity index 100% rename from tests/unit/va_arg_two_passes.c rename to tests/unit/va_arg_two_passes.cpp From cf39bf2e4929f87e5497232d55f67573ba1c4078 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Sat, 18 Apr 2026 21:49:45 +0100 Subject: [PATCH 3/7] Add C struct test --- tests/unit/c_struct.c | 51 ++++++++++++++ tests/unit/out/refcount/c_struct.rs | 100 ++++++++++++++++++++++++++++ tests/unit/out/unsafe/c_struct.rs | 80 ++++++++++++++++++++++ 3 files changed, 231 insertions(+) create mode 100644 tests/unit/c_struct.c create mode 100644 tests/unit/out/refcount/c_struct.rs create mode 100644 tests/unit/out/unsafe/c_struct.rs diff --git a/tests/unit/c_struct.c b/tests/unit/c_struct.c new file mode 100644 index 00000000..9e79b582 --- /dev/null +++ b/tests/unit/c_struct.c @@ -0,0 +1,51 @@ +#include + +struct Point { + int x; + int y; +}; + +struct Line { + struct Point start; + struct Point end; +}; + +struct Node { + int value; + struct Node *next; +}; + +struct Container { + struct Inner { + int a; + int b; + } inner; + enum Color { RED, GREEN, BLUE } color; + int count; +}; + +int main() { + struct Point p = {10, 20}; + assert(p.x == 10); + assert(p.y == 20); + + struct Line l = {{1, 2}, {3, 4}}; + assert(l.start.x == 1); + assert(l.end.y == 4); + + struct Node a = {1, 0}; + struct Node b = {2, &a}; + assert(b.next->value == 1); + + struct Container c = {{5, 6}, GREEN, 42}; + assert(c.inner.a == 5); + assert(c.inner.b == 6); + assert(c.color == GREEN); + assert(c.count == 42); + + struct Container c2; + c2.color = BLUE; + assert(c2.color == 2); + + return 0; +} diff --git a/tests/unit/out/refcount/c_struct.rs b/tests/unit/out/refcount/c_struct.rs new file mode 100644 index 00000000..1882c0e0 --- /dev/null +++ b/tests/unit/out/refcount/c_struct.rs @@ -0,0 +1,100 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +#[derive(Clone, Default)] +pub struct Point { + pub x: Value, + pub y: Value, +} +impl ByteRepr for Point {} +#[derive(Clone, Default)] +pub struct Line { + pub start: Value, + pub end: Value, +} +impl ByteRepr for Line {} +#[derive(Clone, Default)] +pub struct Node { + pub value: Value, + pub next: Value>, +} +impl ByteRepr for Node {} +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum Color { + #[default] + RED = 0, + GREEN = 1, + BLUE = 2, +} +#[derive(Clone, Default)] +pub struct Inner { + pub a: Value, + pub b: Value, +} +impl ByteRepr for Inner {} +#[derive(Clone, Default)] +pub struct Container { + pub inner: Value, + pub color: Value, + pub count: Value, +} +impl ByteRepr for Container {} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let p: Value = Rc::new(RefCell::new(Point { + x: Rc::new(RefCell::new(10)), + y: Rc::new(RefCell::new(20)), + })); + assert!(((*(*p.borrow()).x.borrow()) == 10)); + assert!(((*(*p.borrow()).y.borrow()) == 20)); + let l: Value = Rc::new(RefCell::new(Line { + start: Rc::new(RefCell::new(Point { + x: Rc::new(RefCell::new(1)), + y: Rc::new(RefCell::new(2)), + })), + end: Rc::new(RefCell::new(Point { + x: Rc::new(RefCell::new(3)), + y: Rc::new(RefCell::new(4)), + })), + })); + assert!(((*(*(*l.borrow()).start.borrow()).x.borrow()) == 1)); + assert!(((*(*(*l.borrow()).end.borrow()).y.borrow()) == 4)); + let a: Value = Rc::new(RefCell::new(Node { + value: Rc::new(RefCell::new(1)), + next: Rc::new(RefCell::new(Default::default())), + })); + let b: Value = Rc::new(RefCell::new(Node { + value: Rc::new(RefCell::new(2)), + next: Rc::new(RefCell::new((a.as_pointer()))), + })); + assert!( + ((*(*(*(*b.borrow()).next.borrow()).upgrade().deref()) + .value + .borrow()) + == 1) + ); + let c: Value = Rc::new(RefCell::new(Container { + inner: Rc::new(RefCell::new(Inner { + a: Rc::new(RefCell::new(5)), + b: Rc::new(RefCell::new(6)), + })), + color: Rc::new(RefCell::new((Color::GREEN as Color))), + count: Rc::new(RefCell::new(42)), + })); + assert!(((*(*(*c.borrow()).inner.borrow()).a.borrow()) == 5)); + assert!(((*(*(*c.borrow()).inner.borrow()).b.borrow()) == 6)); + assert!((((*(*c.borrow()).color.borrow()) as u32) == (Color::GREEN as u32))); + assert!(((*(*c.borrow()).count.borrow()) == 42)); + let c2: Value = >::default(); + (*(*c2.borrow()).color.borrow_mut()) = (Color::BLUE as Color); + assert!((((*(*c2.borrow()).color.borrow()) as u32) == 2_u32)); + return 0; +} diff --git a/tests/unit/out/unsafe/c_struct.rs b/tests/unit/out/unsafe/c_struct.rs new file mode 100644 index 00000000..5a584be5 --- /dev/null +++ b/tests/unit/out/unsafe/c_struct.rs @@ -0,0 +1,80 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::Seek; +use std::io::{Read, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +#[derive(Clone, Default)] +pub struct Point { + pub x: i32, + pub y: i32, +} +#[derive(Clone, Default)] +pub struct Line { + pub start: Point, + pub end: Point, +} +#[derive(Clone, Default)] +pub struct Node { + pub value: i32, + pub next: *mut Node, +} +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum Color { + #[default] + RED = 0, + GREEN = 1, + BLUE = 2, +} +#[derive(Clone, Default)] +pub struct Inner { + pub a: i32, + pub b: i32, +} +#[derive(Clone, Default)] +pub struct Container { + pub inner: Inner, + pub color: Color, + pub count: i32, +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut p: Point = Point { x: 10, y: 20 }; + assert!(((p.x) == (10))); + assert!(((p.y) == (20))); + let mut l: Line = Line { + start: Point { x: 1, y: 2 }, + end: Point { x: 3, y: 4 }, + }; + assert!(((l.start.x) == (1))); + assert!(((l.end.y) == (4))); + let mut a: Node = Node { + value: 1, + next: Default::default(), + }; + let mut b: Node = Node { + value: 2, + next: (&mut a as *mut Node), + }; + assert!((((*b.next).value) == (1))); + let mut c: Container = Container { + inner: Inner { a: 5, b: 6 }, + color: (Color::GREEN as Color), + count: 42, + }; + assert!(((c.inner.a) == (5))); + assert!(((c.inner.b) == (6))); + assert!(((c.color as u32) == (Color::GREEN as u32))); + assert!(((c.count) == (42))); + let mut c2: Container = ::default(); + c2.color = (Color::BLUE as Color); + assert!(((c2.color as u32) == (2_u32))); + return 0; +} From 0656e070237e865f60dccdf4cdc7ac7507a86eb5 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Sat, 18 Apr 2026 21:54:10 +0100 Subject: [PATCH 4/7] Move order of traits and abstract classes --- tests/unit/out/refcount/polymorphism.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/unit/out/refcount/polymorphism.rs b/tests/unit/out/refcount/polymorphism.rs index d86e1977..8add81ba 100644 --- a/tests/unit/out/refcount/polymorphism.rs +++ b/tests/unit/out/refcount/polymorphism.rs @@ -11,6 +11,11 @@ pub trait Animal { } #[derive(Default)] pub struct Dog {} +impl Animal for Dog { + fn bark(&self) -> bool { + return true; + } +} impl Clone for Dog { fn clone(&self) -> Self { let mut this = Self {}; @@ -18,11 +23,6 @@ impl Clone for Dog { } } impl ByteRepr for Dog {} -impl Animal for Dog { - fn bark(&self) -> bool { - return true; - } -} #[derive(Default)] pub struct Cat {} impl Cat { @@ -30,6 +30,11 @@ impl Cat { return true; } } +impl Animal for Cat { + fn bark(&self) -> bool { + return false; + } +} impl Clone for Cat { fn clone(&self) -> Self { let mut this = Self {}; @@ -37,11 +42,6 @@ impl Clone for Cat { } } impl ByteRepr for Cat {} -impl Animal for Cat { - fn bark(&self) -> bool { - return false; - } -} pub fn main() { std::process::exit(main_0()); } From deda3e27234ced3268e0be975f979e332b65c805 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 21 Apr 2026 16:41:45 +0100 Subject: [PATCH 5/7] Revert "Move va_arg files to cpp" This reverts commit e17ef73f4993168071ba59ea4ad0640ed4ce3c69. --- tests/unit/out/unsafe/va_arg_concat.rs | 2 +- tests/unit/out/unsafe/va_arg_snprintf.rs | 2 +- tests/unit/out/unsafe/va_arg_two_passes.rs | 2 +- tests/unit/{va_arg_chain.cpp => va_arg_chain.c} | 4 +++- tests/unit/{va_arg_concat.cpp => va_arg_concat.c} | 0 tests/unit/{va_arg_conditional.cpp => va_arg_conditional.c} | 0 tests/unit/{va_arg_copy.cpp => va_arg_copy.c} | 0 tests/unit/{va_arg_forward.cpp => va_arg_forward.c} | 0 .../{va_arg_mixed_int_ptr.cpp => va_arg_mixed_int_ptr.c} | 0 tests/unit/{va_arg_mixed_types.cpp => va_arg_mixed_types.c} | 0 tests/unit/{va_arg_printf.cpp => va_arg_printf.c} | 0 tests/unit/{va_arg_promotion.cpp => va_arg_promotion.c} | 6 +++--- tests/unit/{va_arg_snprintf.cpp => va_arg_snprintf.c} | 0 tests/unit/{va_arg_struct_ctx.cpp => va_arg_struct_ctx.c} | 0 tests/unit/{va_arg_two_passes.cpp => va_arg_two_passes.c} | 0 15 files changed, 9 insertions(+), 7 deletions(-) rename tests/unit/{va_arg_chain.cpp => va_arg_chain.c} (86%) rename tests/unit/{va_arg_concat.cpp => va_arg_concat.c} (100%) rename tests/unit/{va_arg_conditional.cpp => va_arg_conditional.c} (100%) rename tests/unit/{va_arg_copy.cpp => va_arg_copy.c} (100%) rename tests/unit/{va_arg_forward.cpp => va_arg_forward.c} (100%) rename tests/unit/{va_arg_mixed_int_ptr.cpp => va_arg_mixed_int_ptr.c} (100%) rename tests/unit/{va_arg_mixed_types.cpp => va_arg_mixed_types.c} (100%) rename tests/unit/{va_arg_printf.cpp => va_arg_printf.c} (100%) rename tests/unit/{va_arg_promotion.cpp => va_arg_promotion.c} (72%) rename tests/unit/{va_arg_snprintf.cpp => va_arg_snprintf.c} (100%) rename tests/unit/{va_arg_struct_ctx.cpp => va_arg_struct_ctx.c} (100%) rename tests/unit/{va_arg_two_passes.cpp => va_arg_two_passes.c} (100%) diff --git a/tests/unit/out/unsafe/va_arg_concat.rs b/tests/unit/out/unsafe/va_arg_concat.rs index 571cd946..ef884a39 100644 --- a/tests/unit/out/unsafe/va_arg_concat.rs +++ b/tests/unit/out/unsafe/va_arg_concat.rs @@ -10,7 +10,7 @@ pub unsafe fn sum_ints_0(mut first: i32, args: &[VaArg]) -> i32 { let mut ap: VaList = VaList::default(); let mut total: i32 = first; ap = VaList::new(args); - let mut val: i32 = 0_i32; + let mut val: i32 = ::default(); 'loop_: while ((({ val = ap.arg::(); val diff --git a/tests/unit/out/unsafe/va_arg_snprintf.rs b/tests/unit/out/unsafe/va_arg_snprintf.rs index 889a1659..48aff03c 100644 --- a/tests/unit/out/unsafe/va_arg_snprintf.rs +++ b/tests/unit/out/unsafe/va_arg_snprintf.rs @@ -24,7 +24,7 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut buf: [u8; 64] = [0_u8; 64]; + let mut buf: [u8; 64] = [::default(); 64]; assert!( ((unsafe { let _buf: *mut u8 = buf.as_mut_ptr(); diff --git a/tests/unit/out/unsafe/va_arg_two_passes.rs b/tests/unit/out/unsafe/va_arg_two_passes.rs index 56cdb54c..b974ff2f 100644 --- a/tests/unit/out/unsafe/va_arg_two_passes.rs +++ b/tests/unit/out/unsafe/va_arg_two_passes.rs @@ -11,7 +11,7 @@ pub unsafe fn sum_then_product_0(mut first: i32, args: &[VaArg]) -> i32 { let mut sum: i32 = first; let mut product: i32 = first; ap = VaList::new(args); - let mut val: i32 = 0_i32; + let mut val: i32 = ::default(); 'loop_: while ((({ val = ap.arg::(); val diff --git a/tests/unit/va_arg_chain.cpp b/tests/unit/va_arg_chain.c similarity index 86% rename from tests/unit/va_arg_chain.cpp rename to tests/unit/va_arg_chain.c index c7233384..5b627395 100644 --- a/tests/unit/va_arg_chain.cpp +++ b/tests/unit/va_arg_chain.c @@ -8,7 +8,9 @@ int extract_nth(int n, va_list ap) { return va_arg(ap, int); } -int middle_layer(int n, va_list ap) { return extract_nth(n, ap); } +int middle_layer(int n, va_list ap) { + return extract_nth(n, ap); +} int top_level(int n, ...) { va_list ap; diff --git a/tests/unit/va_arg_concat.cpp b/tests/unit/va_arg_concat.c similarity index 100% rename from tests/unit/va_arg_concat.cpp rename to tests/unit/va_arg_concat.c diff --git a/tests/unit/va_arg_conditional.cpp b/tests/unit/va_arg_conditional.c similarity index 100% rename from tests/unit/va_arg_conditional.cpp rename to tests/unit/va_arg_conditional.c diff --git a/tests/unit/va_arg_copy.cpp b/tests/unit/va_arg_copy.c similarity index 100% rename from tests/unit/va_arg_copy.cpp rename to tests/unit/va_arg_copy.c diff --git a/tests/unit/va_arg_forward.cpp b/tests/unit/va_arg_forward.c similarity index 100% rename from tests/unit/va_arg_forward.cpp rename to tests/unit/va_arg_forward.c diff --git a/tests/unit/va_arg_mixed_int_ptr.cpp b/tests/unit/va_arg_mixed_int_ptr.c similarity index 100% rename from tests/unit/va_arg_mixed_int_ptr.cpp rename to tests/unit/va_arg_mixed_int_ptr.c diff --git a/tests/unit/va_arg_mixed_types.cpp b/tests/unit/va_arg_mixed_types.c similarity index 100% rename from tests/unit/va_arg_mixed_types.cpp rename to tests/unit/va_arg_mixed_types.c diff --git a/tests/unit/va_arg_printf.cpp b/tests/unit/va_arg_printf.c similarity index 100% rename from tests/unit/va_arg_printf.cpp rename to tests/unit/va_arg_printf.c diff --git a/tests/unit/va_arg_promotion.cpp b/tests/unit/va_arg_promotion.c similarity index 72% rename from tests/unit/va_arg_promotion.cpp rename to tests/unit/va_arg_promotion.c index 54b38526..7b74bbef 100644 --- a/tests/unit/va_arg_promotion.cpp +++ b/tests/unit/va_arg_promotion.c @@ -6,11 +6,11 @@ int test_promotions(int count, ...) { va_start(ap, count); // char and short are promoted to int by the caller - int a = va_arg(ap, int); // was passed as char 'A' (65) - int b = va_arg(ap, int); // was passed as short 10 + int a = va_arg(ap, int); // was passed as char 'A' (65) + int b = va_arg(ap, int); // was passed as short 10 // float is promoted to double by the caller - double c = va_arg(ap, double); // was passed as float 3.0 + double c = va_arg(ap, double); // was passed as float 3.0 va_end(ap); diff --git a/tests/unit/va_arg_snprintf.cpp b/tests/unit/va_arg_snprintf.c similarity index 100% rename from tests/unit/va_arg_snprintf.cpp rename to tests/unit/va_arg_snprintf.c diff --git a/tests/unit/va_arg_struct_ctx.cpp b/tests/unit/va_arg_struct_ctx.c similarity index 100% rename from tests/unit/va_arg_struct_ctx.cpp rename to tests/unit/va_arg_struct_ctx.c diff --git a/tests/unit/va_arg_two_passes.cpp b/tests/unit/va_arg_two_passes.c similarity index 100% rename from tests/unit/va_arg_two_passes.cpp rename to tests/unit/va_arg_two_passes.c From e7c656cda2a463aeb60a445e3ca74b7703db72b6 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 21 Apr 2026 17:08:26 +0100 Subject: [PATCH 6/7] Make GetStructAttributes receive a RecordDecl --- cpp2rust/converter/converter.cpp | 30 ++++++++++--------- cpp2rust/converter/converter.h | 4 +-- .../converter/models/converter_refcount.cpp | 2 +- .../converter/models/converter_refcount.h | 2 +- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index a5845592..359210aa 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -519,9 +519,11 @@ bool IsPointerType(clang::QualType qual_type) { ->getCanonicalTypeInternal())); } -bool Converter::RecordDerivesDefault(const clang::CXXRecordDecl *decl) { - if (GetUserDefinedDefaultConstructor(decl)) { - return false; +bool Converter::RecordDerivesDefault(const clang::RecordDecl *decl) { + if (auto cxx_decl = clang::dyn_cast(decl)) { + if (GetUserDefinedDefaultConstructor(cxx_decl)) { + return false; + } } for (auto f : decl->fields()) { @@ -546,7 +548,7 @@ bool Converter::RecordDerivesDefault(const clang::CXXRecordDecl *decl) { return true; } -static bool recordDerivesCopy(const clang::CXXRecordDecl *decl) { +static bool recordDerivesCopy(const clang::RecordDecl *decl) { for (auto f : decl->fields()) { // Records that contain std::vector, std::array, std::string or anything // that is translated to Vec<>, do not derive Copy @@ -569,8 +571,8 @@ static bool recordDerivesCopy(const clang::CXXRecordDecl *decl) { } } - // Look recursively into fields that are CXXRecordDecl - if (auto field_record = f->getType()->getAsCXXRecordDecl()) { + // Look recursively into fields that are RecordDecl + if (auto field_record = f->getType()->getAsRecordDecl()) { if (!recordDerivesCopy(field_record)) { return false; } @@ -629,12 +631,8 @@ void Converter::EmitRustStruct(clang::RecordDecl *decl) { // Derived traits StrCat("#[derive("); - if (auto *cxx = clang::dyn_cast(decl)) { - for (auto *attr : GetStructAttributes(cxx)) { - StrCat(attr, ","); - } - } else { - StrCat("Clone, Default"); + for (auto *attr : GetStructAttributes(decl)) { + StrCat(attr, ","); } StrCat(")]"); @@ -2837,14 +2835,18 @@ std::string Converter::GetRecordName(const clang::NamedDecl *decl) const { } std::vector -Converter::GetStructAttributes(const clang::CXXRecordDecl *decl) { +Converter::GetStructAttributes(const clang::RecordDecl *decl) { std::vector struct_attrs = {}; if (recordDerivesCopy(decl)) { struct_attrs.emplace_back("Copy"); } - if (!decl->defaultedCopyConstructorIsDeleted()) { + if (auto cxx_decl = clang::dyn_cast(decl)) { + if (!cxx_decl->defaultedCopyConstructorIsDeleted()) { + struct_attrs.emplace_back("Clone"); + } + } else /* RecordDecl */ { struct_attrs.emplace_back("Clone"); } diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 141769bf..74e8e750 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -359,7 +359,7 @@ class Converter : public clang::RecursiveASTVisitor { virtual std::string GetRecordName(const clang::NamedDecl *decl) const; virtual std::vector - GetStructAttributes(const clang::CXXRecordDecl *decl); + GetStructAttributes(const clang::RecordDecl *decl); virtual std::string GetUnsafeTypeAsString(clang::QualType qual_type) const; @@ -457,7 +457,7 @@ class Converter : public clang::RecursiveASTVisitor { virtual bool IsReferenceType(const clang::Expr *expr) const; - virtual bool RecordDerivesDefault(const clang::CXXRecordDecl *decl); + virtual bool RecordDerivesDefault(const clang::RecordDecl *decl); std::string *rs_code_; clang::ASTContext &ctx_; diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 74f9cbaa..97c3d84f 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1604,7 +1604,7 @@ ConverterRefCount::ConvertVarDefaultInit(clang::QualType qual_type) { } std::vector -ConverterRefCount::GetStructAttributes(const clang::CXXRecordDecl *decl) { +ConverterRefCount::GetStructAttributes(const clang::RecordDecl *decl) { std::vector attrs = {}; if (RecordDerivesDefault(decl)) { diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index 2a39caec..26ba88a3 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -121,7 +121,7 @@ class ConverterRefCount final : public Converter { std::string ConvertVarDefaultInit(clang::QualType qual_type) override; std::vector - GetStructAttributes(const clang::CXXRecordDecl *decl) override; + GetStructAttributes(const clang::RecordDecl *decl) override; bool MayCauseBorrowMutError(const clang::Expr *lhs, const clang::Expr *rhs); From bb3cc727db762645eeeee2b98792d76c5a7f1e49 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 21 Apr 2026 17:11:09 +0100 Subject: [PATCH 7/7] Update tests --- tests/unit/out/refcount/c_struct.rs | 13 ++++++------- tests/unit/out/refcount/va_arg_struct_ctx.rs | 11 +---------- tests/unit/out/unsafe/c_struct.rs | 13 ++++++------- tests/unit/out/unsafe/va_arg_concat.rs | 2 +- tests/unit/out/unsafe/va_arg_snprintf.rs | 2 +- tests/unit/out/unsafe/va_arg_two_passes.rs | 2 +- tests/unit/va_arg_chain.c | 4 +--- tests/unit/va_arg_promotion.c | 6 +++--- 8 files changed, 20 insertions(+), 33 deletions(-) diff --git a/tests/unit/out/refcount/c_struct.rs b/tests/unit/out/refcount/c_struct.rs index 1882c0e0..2343bb35 100644 --- a/tests/unit/out/refcount/c_struct.rs +++ b/tests/unit/out/refcount/c_struct.rs @@ -3,23 +3,22 @@ use libcc2rs::*; use std::cell::RefCell; use std::collections::BTreeMap; use std::io::prelude::*; -use std::io::Seek; -use std::io::{Read, Write}; +use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -#[derive(Clone, Default)] +#[derive(Default)] pub struct Point { pub x: Value, pub y: Value, } impl ByteRepr for Point {} -#[derive(Clone, Default)] +#[derive(Default)] pub struct Line { pub start: Value, pub end: Value, } impl ByteRepr for Line {} -#[derive(Clone, Default)] +#[derive(Default)] pub struct Node { pub value: Value, pub next: Value>, @@ -32,13 +31,13 @@ enum Color { GREEN = 1, BLUE = 2, } -#[derive(Clone, Default)] +#[derive(Default)] pub struct Inner { pub a: Value, pub b: Value, } impl ByteRepr for Inner {} -#[derive(Clone, Default)] +#[derive(Default)] pub struct Container { pub inner: Value, pub color: Value, diff --git a/tests/unit/out/refcount/va_arg_struct_ctx.rs b/tests/unit/out/refcount/va_arg_struct_ctx.rs index 3d3f74c7..3076b601 100644 --- a/tests/unit/out/refcount/va_arg_struct_ctx.rs +++ b/tests/unit/out/refcount/va_arg_struct_ctx.rs @@ -11,15 +11,6 @@ pub struct context { pub verbose: Value, pub last_error: Value, } -impl Clone for context { - fn clone(&self) -> Self { - let mut this = Self { - verbose: Rc::new(RefCell::new((*self.verbose.borrow()))), - last_error: Rc::new(RefCell::new((*self.last_error.borrow()))), - }; - this - } -} impl ByteRepr for context {} pub fn set_error_0(ctx: Ptr, fmt: Ptr, args: &[VaArg]) { let ctx: Value> = Rc::new(RefCell::new(ctx)); @@ -35,7 +26,7 @@ pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - let ctx: Value = Rc::new(RefCell::new(::default())); + let ctx: Value = >::default(); (*(*ctx.borrow()).verbose.borrow_mut()) = 1; (*(*ctx.borrow()).last_error.borrow_mut()) = 0; ({ diff --git a/tests/unit/out/unsafe/c_struct.rs b/tests/unit/out/unsafe/c_struct.rs index 5a584be5..3d12a8fd 100644 --- a/tests/unit/out/unsafe/c_struct.rs +++ b/tests/unit/out/unsafe/c_struct.rs @@ -3,21 +3,20 @@ use libc::*; extern crate libcc2rs; use libcc2rs::*; use std::collections::BTreeMap; -use std::io::Seek; -use std::io::{Read, Write}; +use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; -#[derive(Clone, Default)] +#[derive(Copy, Clone, Default)] pub struct Point { pub x: i32, pub y: i32, } -#[derive(Clone, Default)] +#[derive(Copy, Clone, Default)] pub struct Line { pub start: Point, pub end: Point, } -#[derive(Clone, Default)] +#[derive(Copy, Clone, Default)] pub struct Node { pub value: i32, pub next: *mut Node, @@ -29,12 +28,12 @@ enum Color { GREEN = 1, BLUE = 2, } -#[derive(Clone, Default)] +#[derive(Copy, Clone, Default)] pub struct Inner { pub a: i32, pub b: i32, } -#[derive(Clone, Default)] +#[derive(Copy, Clone, Default)] pub struct Container { pub inner: Inner, pub color: Color, diff --git a/tests/unit/out/unsafe/va_arg_concat.rs b/tests/unit/out/unsafe/va_arg_concat.rs index ef884a39..571cd946 100644 --- a/tests/unit/out/unsafe/va_arg_concat.rs +++ b/tests/unit/out/unsafe/va_arg_concat.rs @@ -10,7 +10,7 @@ pub unsafe fn sum_ints_0(mut first: i32, args: &[VaArg]) -> i32 { let mut ap: VaList = VaList::default(); let mut total: i32 = first; ap = VaList::new(args); - let mut val: i32 = ::default(); + let mut val: i32 = 0_i32; 'loop_: while ((({ val = ap.arg::(); val diff --git a/tests/unit/out/unsafe/va_arg_snprintf.rs b/tests/unit/out/unsafe/va_arg_snprintf.rs index 48aff03c..889a1659 100644 --- a/tests/unit/out/unsafe/va_arg_snprintf.rs +++ b/tests/unit/out/unsafe/va_arg_snprintf.rs @@ -24,7 +24,7 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut buf: [u8; 64] = [::default(); 64]; + let mut buf: [u8; 64] = [0_u8; 64]; assert!( ((unsafe { let _buf: *mut u8 = buf.as_mut_ptr(); diff --git a/tests/unit/out/unsafe/va_arg_two_passes.rs b/tests/unit/out/unsafe/va_arg_two_passes.rs index b974ff2f..56cdb54c 100644 --- a/tests/unit/out/unsafe/va_arg_two_passes.rs +++ b/tests/unit/out/unsafe/va_arg_two_passes.rs @@ -11,7 +11,7 @@ pub unsafe fn sum_then_product_0(mut first: i32, args: &[VaArg]) -> i32 { let mut sum: i32 = first; let mut product: i32 = first; ap = VaList::new(args); - let mut val: i32 = ::default(); + let mut val: i32 = 0_i32; 'loop_: while ((({ val = ap.arg::(); val diff --git a/tests/unit/va_arg_chain.c b/tests/unit/va_arg_chain.c index 5b627395..c7233384 100644 --- a/tests/unit/va_arg_chain.c +++ b/tests/unit/va_arg_chain.c @@ -8,9 +8,7 @@ int extract_nth(int n, va_list ap) { return va_arg(ap, int); } -int middle_layer(int n, va_list ap) { - return extract_nth(n, ap); -} +int middle_layer(int n, va_list ap) { return extract_nth(n, ap); } int top_level(int n, ...) { va_list ap; diff --git a/tests/unit/va_arg_promotion.c b/tests/unit/va_arg_promotion.c index 7b74bbef..54b38526 100644 --- a/tests/unit/va_arg_promotion.c +++ b/tests/unit/va_arg_promotion.c @@ -6,11 +6,11 @@ int test_promotions(int count, ...) { va_start(ap, count); // char and short are promoted to int by the caller - int a = va_arg(ap, int); // was passed as char 'A' (65) - int b = va_arg(ap, int); // was passed as short 10 + int a = va_arg(ap, int); // was passed as char 'A' (65) + int b = va_arg(ap, int); // was passed as short 10 // float is promoted to double by the caller - double c = va_arg(ap, double); // was passed as float 3.0 + double c = va_arg(ap, double); // was passed as float 3.0 va_end(ap);