From a15127f83bd844cbe63210cd2361d6dad4e714fb Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 28 Apr 2026 19:20:42 +0100 Subject: [PATCH 01/23] Handle string literalt to char* conversion --- cpp2rust/converter/converter.cpp | 3 +++ cpp2rust/converter/converter_lib.h | 1 - cpp2rust/converter/models/converter_refcount.cpp | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 59943ad2..2c79f86b 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1756,6 +1756,9 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { } case clang::CastKind::CK_NoOp: { Convert(sub_expr); + if (IsConversionFromStringLiteralToCharPtr(expr)) { + StrCat(".cast_mut()"); + } break; } case clang::CastKind::CK_FunctionToPointerDecay: diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index cef84d1a..37007864 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -170,5 +170,4 @@ void Unwrap(std::string &s, std::string_view prefix, std::string_view suffix); std::string ReplaceAll(std::string str, std::string_view from, std::string_view to); - } // namespace cpp2rust diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index eedb1606..94b4545e 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1035,6 +1035,11 @@ bool ConverterRefCount::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { return false; } + if (expr->getCastKind() == clang::CastKind::CK_NoOp) { + Convert(sub_expr); + return false; + } + return Converter::VisitImplicitCastExpr(expr); } From e3c9a83db0b50b0700a3229fd661fe03837f3dc2 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 28 Apr 2026 19:21:08 +0100 Subject: [PATCH 02/23] Add string_literals test --- tests/unit/out/refcount/string_literals.rs | 26 ++++++++++++++++++++++ tests/unit/out/unsafe/string_literals.rs | 24 ++++++++++++++++++++ tests/unit/string_literals.cpp | 8 +++++++ 3 files changed, 58 insertions(+) create mode 100644 tests/unit/out/refcount/string_literals.rs create mode 100644 tests/unit/out/unsafe/string_literals.rs create mode 100644 tests/unit/string_literals.cpp diff --git a/tests/unit/out/refcount/string_literals.rs b/tests/unit/out/refcount/string_literals.rs new file mode 100644 index 00000000..fcf4fc8f --- /dev/null +++ b/tests/unit/out/refcount/string_literals.rs @@ -0,0 +1,26 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let mutable_strings: Value]>> = Rc::new(RefCell::new(Box::new([ + Ptr::from_string_literal("a"), + Ptr::from_string_literal("b"), + Ptr::from_string_literal("c"), + ]))); + let immutable_strings: Value]>> = Rc::new(RefCell::new(Box::new([ + Ptr::from_string_literal("a"), + Ptr::from_string_literal("b"), + Ptr::from_string_literal("c"), + ]))); + let mutable_string: Value> = Rc::new(RefCell::new(Ptr::from_string_literal("hello"))); + let immutable_string: Value> = Rc::new(RefCell::new(Ptr::from_string_literal("hello"))); + return 0; +} diff --git a/tests/unit/out/unsafe/string_literals.rs b/tests/unit/out/unsafe/string_literals.rs new file mode 100644 index 00000000..8981aede --- /dev/null +++ b/tests/unit/out/unsafe/string_literals.rs @@ -0,0 +1,24 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut mutable_strings: [*mut u8; 3] = [ + b"a\0".as_ptr().cast_mut(), + b"b\0".as_ptr().cast_mut(), + b"c\0".as_ptr().cast_mut(), + ]; + let mut immutable_strings: [*const u8; 3] = [b"a\0".as_ptr(), b"b\0".as_ptr(), b"c\0".as_ptr()]; + let mut mutable_string: *mut u8 = b"hello\0".as_ptr().cast_mut(); + let mut immutable_string: *const u8 = b"hello\0".as_ptr(); + return 0; +} diff --git a/tests/unit/string_literals.cpp b/tests/unit/string_literals.cpp new file mode 100644 index 00000000..f828df5e --- /dev/null +++ b/tests/unit/string_literals.cpp @@ -0,0 +1,8 @@ +int main() { + char *mutable_strings[] = {"a", "b", "c"}; + const char *immutable_strings[] = {"a", "b", "c"}; + + char *mutable_string = "hello"; + const char *immutable_string = "hello"; + return 0; +} From fb4e183b85716c45569001ce5f709e4e26ac641a Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 28 Apr 2026 19:59:12 +0100 Subject: [PATCH 03/23] Handle array to pointer decay for C literals In C, as opposed to C++, string literals are char [] instead of const char [] so cast_mut should be added on ArrayToPointerDecay from char [] to char * instead of NoOp const char * to char *. --- cpp2rust/converter/converter.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 2c79f86b..092b5209 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1729,7 +1729,11 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { case clang::CastKind::CK_ArrayToPointerDecay: if (clang::isa(sub_expr) || clang::isa(sub_expr)) { - return Convert(sub_expr); + Convert(sub_expr); + if (IsConversionFromStringLiteralToCharPtr(expr)) { + StrCat(".cast_mut()"); + } + return false; } // __va_list_tag [1] decays to __va_list_tag *. Just pass through by value if (IsVaListType(sub_expr->getType())) { From 72d005f42336cfbed38ae4ee5308d2b5c4b51166 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 28 Apr 2026 20:01:09 +0100 Subject: [PATCH 04/23] Update tests --- tests/unit/out/refcount/string_literals.rs | 11 ++++++ tests/unit/out/refcount/string_literals_c.rs | 37 ++++++++++++++++++++ tests/unit/out/unsafe/string_literals.rs | 9 +++++ tests/unit/out/unsafe/string_literals_c.rs | 37 ++++++++++++++++++++ tests/unit/string_literals.cpp | 7 ++++ tests/unit/string_literals_c.c | 15 ++++++++ 6 files changed, 116 insertions(+) create mode 100644 tests/unit/out/refcount/string_literals_c.rs create mode 100644 tests/unit/out/unsafe/string_literals_c.rs create mode 100644 tests/unit/string_literals_c.c diff --git a/tests/unit/out/refcount/string_literals.rs b/tests/unit/out/refcount/string_literals.rs index fcf4fc8f..a6e63f1b 100644 --- a/tests/unit/out/refcount/string_literals.rs +++ b/tests/unit/out/refcount/string_literals.rs @@ -6,6 +6,9 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; +pub fn foo_0(str: Ptr) { + let str: Value> = Rc::new(RefCell::new(str)); +} pub fn main() { std::process::exit(main_0()); } @@ -22,5 +25,13 @@ fn main_0() -> i32 { ]))); let mutable_string: Value> = Rc::new(RefCell::new(Ptr::from_string_literal("hello"))); let immutable_string: Value> = Rc::new(RefCell::new(Ptr::from_string_literal("hello"))); + ({ + let _str: Ptr = Ptr::from_string_literal("world"); + foo_0(_str) + }); + ({ + let _str: Ptr = (*mutable_string.borrow()).clone(); + foo_0(_str) + }); return 0; } diff --git a/tests/unit/out/refcount/string_literals_c.rs b/tests/unit/out/refcount/string_literals_c.rs new file mode 100644 index 00000000..a6e63f1b --- /dev/null +++ b/tests/unit/out/refcount/string_literals_c.rs @@ -0,0 +1,37 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn foo_0(str: Ptr) { + let str: Value> = Rc::new(RefCell::new(str)); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let mutable_strings: Value]>> = Rc::new(RefCell::new(Box::new([ + Ptr::from_string_literal("a"), + Ptr::from_string_literal("b"), + Ptr::from_string_literal("c"), + ]))); + let immutable_strings: Value]>> = Rc::new(RefCell::new(Box::new([ + Ptr::from_string_literal("a"), + Ptr::from_string_literal("b"), + Ptr::from_string_literal("c"), + ]))); + let mutable_string: Value> = Rc::new(RefCell::new(Ptr::from_string_literal("hello"))); + let immutable_string: Value> = Rc::new(RefCell::new(Ptr::from_string_literal("hello"))); + ({ + let _str: Ptr = Ptr::from_string_literal("world"); + foo_0(_str) + }); + ({ + let _str: Ptr = (*mutable_string.borrow()).clone(); + foo_0(_str) + }); + return 0; +} diff --git a/tests/unit/out/unsafe/string_literals.rs b/tests/unit/out/unsafe/string_literals.rs index 8981aede..36d45ff5 100644 --- a/tests/unit/out/unsafe/string_literals.rs +++ b/tests/unit/out/unsafe/string_literals.rs @@ -6,6 +6,7 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; +pub unsafe fn foo_0(mut str: *mut u8) {} pub fn main() { unsafe { std::process::exit(main_0() as i32); @@ -20,5 +21,13 @@ unsafe fn main_0() -> i32 { let mut immutable_strings: [*const u8; 3] = [b"a\0".as_ptr(), b"b\0".as_ptr(), b"c\0".as_ptr()]; let mut mutable_string: *mut u8 = b"hello\0".as_ptr().cast_mut(); let mut immutable_string: *const u8 = b"hello\0".as_ptr(); + (unsafe { + let _str: *mut u8 = b"world\0".as_ptr().cast_mut(); + foo_0(_str) + }); + (unsafe { + let _str: *mut u8 = mutable_string; + foo_0(_str) + }); return 0; } diff --git a/tests/unit/out/unsafe/string_literals_c.rs b/tests/unit/out/unsafe/string_literals_c.rs new file mode 100644 index 00000000..96a42d56 --- /dev/null +++ b/tests/unit/out/unsafe/string_literals_c.rs @@ -0,0 +1,37 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn foo_0(mut str: *mut u8) {} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut mutable_strings: [*mut u8; 3] = [ + b"a\0".as_ptr().cast_mut(), + b"b\0".as_ptr().cast_mut(), + b"c\0".as_ptr().cast_mut(), + ]; + let mut immutable_strings: [*const u8; 3] = [ + b"a\0".as_ptr().cast_mut(), + b"b\0".as_ptr().cast_mut(), + b"c\0".as_ptr().cast_mut(), + ]; + let mut mutable_string: *mut u8 = b"hello\0".as_ptr().cast_mut(); + let mut immutable_string: *const u8 = b"hello\0".as_ptr().cast_mut(); + (unsafe { + let _str: *mut u8 = b"world\0".as_ptr().cast_mut(); + foo_0(_str) + }); + (unsafe { + let _str: *mut u8 = mutable_string; + foo_0(_str) + }); + return 0; +} diff --git a/tests/unit/string_literals.cpp b/tests/unit/string_literals.cpp index f828df5e..3ad7f257 100644 --- a/tests/unit/string_literals.cpp +++ b/tests/unit/string_literals.cpp @@ -1,8 +1,15 @@ +void foo(char *str) {} + int main() { + // warning: ISO C++11 does not allow conversion from string literal to 'char *' [-Wwritable-strings] char *mutable_strings[] = {"a", "b", "c"}; const char *immutable_strings[] = {"a", "b", "c"}; char *mutable_string = "hello"; const char *immutable_string = "hello"; + + foo("world"); + foo(mutable_string); + // This is not allowed, only string literals to char* are allowed: foo(immutable_string); return 0; } diff --git a/tests/unit/string_literals_c.c b/tests/unit/string_literals_c.c new file mode 100644 index 00000000..3ad7f257 --- /dev/null +++ b/tests/unit/string_literals_c.c @@ -0,0 +1,15 @@ +void foo(char *str) {} + +int main() { + // warning: ISO C++11 does not allow conversion from string literal to 'char *' [-Wwritable-strings] + char *mutable_strings[] = {"a", "b", "c"}; + const char *immutable_strings[] = {"a", "b", "c"}; + + char *mutable_string = "hello"; + const char *immutable_string = "hello"; + + foo("world"); + foo(mutable_string); + // This is not allowed, only string literals to char* are allowed: foo(immutable_string); + return 0; +} From 4899cd9d88bfc663f24080bba6674ff51542b2f1 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 28 Apr 2026 21:04:20 +0100 Subject: [PATCH 05/23] String literals are mutable in C --- cpp2rust/converter/converter.cpp | 45 ++++++++++++++++++---------- cpp2rust/converter/converter_lib.cpp | 12 ++++++++ cpp2rust/converter/converter_lib.h | 10 +++++++ 3 files changed, 52 insertions(+), 15 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 092b5209..e0d4a6fd 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1707,6 +1707,10 @@ std::string Converter::GetEscapedStringLiteral(clang::Expr *expr, bool Converter::VisitStringLiteral(clang::StringLiteral *expr) { StrCat(std::format("b{}.as_ptr()", GetEscapedStringLiteral(expr, true))); + // In C, string literals are char[], in C++ they are const char[] + if (!expr->getType().isConstQualified()) { + StrCat(".cast_mut()"); + } return false; } @@ -1726,27 +1730,27 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { SetValueFreshness(type); break; } - case clang::CastKind::CK_ArrayToPointerDecay: - if (clang::isa(sub_expr) || - clang::isa(sub_expr)) { - Convert(sub_expr); - if (IsConversionFromStringLiteralToCharPtr(expr)) { - StrCat(".cast_mut()"); - } - return false; - } + case clang::CastKind::CK_ArrayToPointerDecay: { // __va_list_tag [1] decays to __va_list_tag *. Just pass through by value if (IsVaListType(sub_expr->getType())) { Convert(sub_expr); break; } Convert(sub_expr); - if (sub_expr->getType().isConstQualified()) { - StrCat(keyword_ptr_decay_const_); - } else { - StrCat(keyword_ptr_decay_); + switch (GetConstCastType( + expr->getType()->getPointeeType(), + sub_expr->getType()->getAsArrayTypeUnsafe()->getElementType())) { + case ConstCastType::MutableToConst: + StrCat(".cast_const()"); + break; + case ConstCastType::ConstToMutable: + StrCat(".cast_mut()"); + break; + default: + break; } break; + } case clang::CastKind::CK_BitCast: { PushParen paren(*this); Convert(sub_expr); @@ -1760,8 +1764,19 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { } case clang::CastKind::CK_NoOp: { Convert(sub_expr); - if (IsConversionFromStringLiteralToCharPtr(expr)) { - StrCat(".cast_mut()"); + if (expr->getType()->isPointerType() && + sub_expr->getType()->isPointerType()) { + switch (GetConstCastType(expr->getType()->getPointeeType(), + sub_expr->getType()->getPointeeType())) { + case ConstCastType::MutableToConst: + StrCat(".cast_const()"); + break; + case ConstCastType::ConstToMutable: + StrCat(".cast_mut()"); + break; + default: + break; + } } break; } diff --git a/cpp2rust/converter/converter_lib.cpp b/cpp2rust/converter/converter_lib.cpp index 40816ddf..6f6a537b 100644 --- a/cpp2rust/converter/converter_lib.cpp +++ b/cpp2rust/converter/converter_lib.cpp @@ -802,4 +802,16 @@ std::string ReplaceAll(std::string str, std::string_view from, return str; } +ConstCastType GetConstCastType(clang::QualType to, clang::QualType from) { + if (to.isConstQualified() && from.isConstQualified()) { + return ConstCastType::ConstToConst; + } else if (!to.isConstQualified() && from.isConstQualified()) { + return ConstCastType::ConstToMutable; + } else if (to.isConstQualified() && !from.isConstQualified()) { + return ConstCastType::MutableToConst; + } else { + return ConstCastType::MutableToMutable; + } +} + } // namespace cpp2rust diff --git a/cpp2rust/converter/converter_lib.h b/cpp2rust/converter/converter_lib.h index 37007864..2522980d 100644 --- a/cpp2rust/converter/converter_lib.h +++ b/cpp2rust/converter/converter_lib.h @@ -170,4 +170,14 @@ void Unwrap(std::string &s, std::string_view prefix, std::string_view suffix); std::string ReplaceAll(std::string str, std::string_view from, std::string_view to); + +enum class ConstCastType { + ConstToConst, + ConstToMutable, + MutableToConst, + MutableToMutable, +}; + +ConstCastType GetConstCastType(clang::QualType to, clang::QualType from); + } // namespace cpp2rust From 2382fcaec5f6c5b44392b8b551cfcd261553b955 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 28 Apr 2026 21:04:46 +0100 Subject: [PATCH 06/23] Update tests --- tests/unit/out/unsafe/string_literals_c.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/unit/out/unsafe/string_literals_c.rs b/tests/unit/out/unsafe/string_literals_c.rs index 96a42d56..c1e7b18b 100644 --- a/tests/unit/out/unsafe/string_literals_c.rs +++ b/tests/unit/out/unsafe/string_literals_c.rs @@ -19,12 +19,12 @@ unsafe fn main_0() -> i32 { b"c\0".as_ptr().cast_mut(), ]; let mut immutable_strings: [*const u8; 3] = [ - b"a\0".as_ptr().cast_mut(), - b"b\0".as_ptr().cast_mut(), - b"c\0".as_ptr().cast_mut(), + b"a\0".as_ptr().cast_mut().cast_const(), + b"b\0".as_ptr().cast_mut().cast_const(), + b"c\0".as_ptr().cast_mut().cast_const(), ]; let mut mutable_string: *mut u8 = b"hello\0".as_ptr().cast_mut(); - let mut immutable_string: *const u8 = b"hello\0".as_ptr().cast_mut(); + let mut immutable_string: *const u8 = b"hello\0".as_ptr().cast_mut().cast_const(); (unsafe { let _str: *mut u8 = b"world\0".as_ptr().cast_mut(); foo_0(_str) From 1c052afc30aff830b0d53ce448540ea55fa0cd2f Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 28 Apr 2026 21:12:03 +0100 Subject: [PATCH 07/23] Stop clang-format formatting comments --- tests/unit/string_literals.cpp | 4 ++-- tests/unit/string_literals_c.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/unit/string_literals.cpp b/tests/unit/string_literals.cpp index 3ad7f257..880f37b9 100644 --- a/tests/unit/string_literals.cpp +++ b/tests/unit/string_literals.cpp @@ -1,7 +1,7 @@ void foo(char *str) {} int main() { - // warning: ISO C++11 does not allow conversion from string literal to 'char *' [-Wwritable-strings] + // -Wwritable-strings warning triggered char *mutable_strings[] = {"a", "b", "c"}; const char *immutable_strings[] = {"a", "b", "c"}; @@ -10,6 +10,6 @@ int main() { foo("world"); foo(mutable_string); - // This is not allowed, only string literals to char* are allowed: foo(immutable_string); + // Calling foo with immutable_string is an error, not an warning return 0; } diff --git a/tests/unit/string_literals_c.c b/tests/unit/string_literals_c.c index 3ad7f257..7ca57daa 100644 --- a/tests/unit/string_literals_c.c +++ b/tests/unit/string_literals_c.c @@ -1,7 +1,6 @@ void foo(char *str) {} int main() { - // warning: ISO C++11 does not allow conversion from string literal to 'char *' [-Wwritable-strings] char *mutable_strings[] = {"a", "b", "c"}; const char *immutable_strings[] = {"a", "b", "c"}; @@ -10,6 +9,6 @@ int main() { foo("world"); foo(mutable_string); - // This is not allowed, only string literals to char* are allowed: foo(immutable_string); + // Calling foo with immutable_string is an error return 0; } From dc53477577a593785f4bf61b592f83e912ff7089 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 29 Apr 2026 13:04:50 +0100 Subject: [PATCH 08/23] Change translation of string literal In unsafe, they are translated as [u8; N] and in refcount they are translated as Box<[u8]>. --- cpp2rust/converter/converter.cpp | 10 ++++++---- cpp2rust/converter/models/converter_refcount.cpp | 7 +++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index e0d4a6fd..6091ed19 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1706,11 +1706,13 @@ std::string Converter::GetEscapedStringLiteral(clang::Expr *expr, } bool Converter::VisitStringLiteral(clang::StringLiteral *expr) { - StrCat(std::format("b{}.as_ptr()", GetEscapedStringLiteral(expr, true))); - // In C, string literals are char[], in C++ they are const char[] - if (!expr->getType().isConstQualified()) { - StrCat(".cast_mut()"); + if (!curr_init_type_.empty() && curr_init_type_.top()->isArrayType()) { + // b"" has type &static [u8; N]. For translating char str[] = + // "string_literal"; we need an initializer of type [u8; N]. Dereferencing + // the &static [u8; N] achieves this. + StrCat(token::kStar); } + StrCat(std::format("b{}", GetEscapedStringLiteral(expr, true))); return false; } diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 94b4545e..b8cc9307 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -946,6 +946,13 @@ bool ConverterRefCount::VisitCallExpr(clang::CallExpr *expr) { } bool ConverterRefCount::VisitStringLiteral(clang::StringLiteral *expr) { + if (!curr_init_type_.empty() && curr_init_type_.top()->isArrayType()) { + // b"" has type &static [u8; N]. For translating char str[] = + // "string_literal"; we need an initializer of type Box<[u8]> + StrCat(std::format("Box::<[u8]>::from(b{}.as_slice())", + GetEscapedStringLiteral(expr, true))); + return false; + } StrCat(GetEscapedStringLiteral(expr)); return false; } From 9db550ffd97aa49cbe7b8d3d92d7f606bb597684 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 29 Apr 2026 13:05:42 +0100 Subject: [PATCH 09/23] Add RAII semantics for curr_init_type_ --- cpp2rust/converter/converter.cpp | 20 +++++++++---------- cpp2rust/converter/converter.h | 13 ++++++++++++ .../converter/models/converter_refcount.cpp | 1 + 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 6091ed19..dabee4dc 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2973,9 +2973,8 @@ void Converter::ConvertVarInit(clang::QualType qual_type, clang::Expr *expr) { if (auto *lambda = clang::dyn_cast( expr->IgnoreUnlessSpelledInSource())) { PushExprKind push(*this, ExprKind::AddrOf); - curr_init_type_.push(qual_type); + PushInitType init_type(*this, qual_type); VisitLambdaExpr(lambda); - curr_init_type_.pop(); return; } } @@ -2992,21 +2991,18 @@ void Converter::ConvertVarInit(clang::QualType qual_type, clang::Expr *expr) { { PushParen paren(*this); StrCat(token::kStar); - curr_init_type_.push(qual_type); + PushInitType init_type(*this, qual_type); Convert(expr); - curr_init_type_.pop(); } StrCat(".clone()"); } else if (IsReferenceType(expr) || qual_type->isFunctionPointerType()) { PushExprKind push(*this, ExprKind::AddrOf); - curr_init_type_.push(qual_type); + PushInitType init_type(*this, qual_type); Convert(expr); - curr_init_type_.pop(); } else { PushExprKind push(*this, ExprKind::RValue); - curr_init_type_.push(qual_type); + PushInitType init_type(*this, qual_type); Convert(expr); - curr_init_type_.pop(); } if (qual_type->isReferenceType() && !IsReferenceType(expr)) { StrCat(keyword::kAs); @@ -3080,9 +3076,11 @@ void Converter::ConvertArraySubscript(clang::Expr *base, clang::Expr *idx, void Converter::ConvertAssignment(clang::Expr *lhs, clang::Expr *rhs, std::string_view assign_operator) { - curr_init_type_.push(lhs->getType()); - auto lhs_as_string = ConvertLValue(lhs); - curr_init_type_.pop(); + std::string lhs_as_string; + { + PushInitType init_type(*this, lhs->getType()); + lhs_as_string = ConvertLValue(lhs); + } auto rhs_as_string = ConvertFreshRValue(rhs); PushBrace brace(*this, !isVoid()); diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 8e2fda4c..273b6dd3 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -522,6 +522,19 @@ class Converter : public clang::RecursiveASTVisitor { std::stack &stack_; }; + class PushInitType { + public: + PushInitType(Converter &c, clang::QualType type) : c_(c) { + c_.curr_init_type_.push(type); + } + ~PushInitType() { c_.curr_init_type_.pop(); } + PushInitType(const PushInitType &) = delete; + PushInitType &operator=(const PushInitType &) = delete; + + private: + Converter &c_; + }; + std::unordered_set map_iter_decls_; struct ScopedMapIterDecl { diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index b8cc9307..cadad266 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1668,6 +1668,7 @@ void ConverterRefCount::ConvertVarInit(clang::QualType qual_type, bool is_ref = qual_type->isReferenceType(); in_function_formals_ = true; PushConversionKind push(*this, ConversionKind::Unboxed, is_ref); + PushInitType init_type(*this, qual_type); StrCat(BoxValue((is_ref || qual_type->isFunctionPointerType()) ? ConvertFreshPointer(expr) : ConvertFreshRValue(expr))); From b38c414d7a7973b7bdca423b35f40aaf3c6994dd Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 29 Apr 2026 13:05:57 +0100 Subject: [PATCH 10/23] Ignore const casts on this pointer --- cpp2rust/converter/converter.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index dabee4dc..6fa31c41 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1767,7 +1767,8 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { case clang::CastKind::CK_NoOp: { Convert(sub_expr); if (expr->getType()->isPointerType() && - sub_expr->getType()->isPointerType()) { + sub_expr->getType()->isPointerType() && + !clang::isa(expr->IgnoreImplicit())) { switch (GetConstCastType(expr->getType()->getPointeeType(), sub_expr->getType()->getPointeeType())) { case ConstCastType::MutableToConst: From a5e2759e63e67d005a032f3264f529ab5b45cf00 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 29 Apr 2026 13:07:29 +0100 Subject: [PATCH 11/23] Handle string literals in ArrayToPointerDecay --- cpp2rust/converter/converter.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 6fa31c41..de4b8e98 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1739,17 +1739,16 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) { break; } Convert(sub_expr); - switch (GetConstCastType( - expr->getType()->getPointeeType(), - sub_expr->getType()->getAsArrayTypeUnsafe()->getElementType())) { - case ConstCastType::MutableToConst: - StrCat(".cast_const()"); - break; - case ConstCastType::ConstToMutable: - StrCat(".cast_mut()"); - break; - default: - break; + bool dest_pointee_const = + expr->getType()->getPointeeType().isConstQualified(); + if (clang::isa(sub_expr) || + clang::isa(sub_expr)) { + StrCat(".as_ptr()"); + if (!dest_pointee_const) { + StrCat(".cast_mut()"); + } + } else { + StrCat(dest_pointee_const ? ".as_ptr()" : ".as_mut_ptr()"); } break; } From 1a7e2094e7fa517b99352e171bd759900ce5c010 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 29 Apr 2026 13:07:53 +0100 Subject: [PATCH 12/23] Update tests --- tests/unit/out/refcount/string_literals.rs | 37 +++++++++++++++++-- tests/unit/out/refcount/string_literals_c.rs | 37 +++++++++++++++++-- tests/unit/out/unsafe/borrow_mut_opt.rs | 2 +- tests/unit/out/unsafe/huffman.rs | 4 +- tests/unit/out/unsafe/main.rs | 2 +- tests/unit/out/unsafe/pointer_diff.rs | 4 +- tests/unit/out/unsafe/pointer_eq.rs | 6 +-- tests/unit/out/unsafe/pointer_neq.rs | 4 +- tests/unit/out/unsafe/pointer_offset.rs | 4 +- tests/unit/out/unsafe/polymorphism.rs | 6 +-- tests/unit/out/unsafe/printfs.rs | 2 +- tests/unit/out/unsafe/refs_as_args.rs | 2 +- tests/unit/out/unsafe/string.rs | 23 ++++++------ tests/unit/out/unsafe/string_literals.rs | 33 +++++++++++++++-- tests/unit/out/unsafe/string_literals_c.rs | 33 +++++++++++++++-- .../unit/out/unsafe/union_tagged_many_arms.rs | 13 ++----- .../unit/out/unsafe/unique_ptr_const_deref.rs | 5 +-- tests/unit/out/unsafe/va_arg_conditional.rs | 4 +- tests/unit/out/unsafe/va_arg_printf.rs | 4 +- tests/unit/out/unsafe/va_arg_snprintf.rs | 4 +- tests/unit/out/unsafe/va_arg_struct_ctx.rs | 5 +-- tests/unit/out/unsafe/vector.rs | 2 +- tests/unit/string_literals.cpp | 19 +++++++--- tests/unit/string_literals_c.c | 18 +++++++-- tests/unit/union_tagged_struct_arms.c | 1 - 25 files changed, 198 insertions(+), 76 deletions(-) diff --git a/tests/unit/out/refcount/string_literals.rs b/tests/unit/out/refcount/string_literals.rs index a6e63f1b..7d93a21a 100644 --- a/tests/unit/out/refcount/string_literals.rs +++ b/tests/unit/out/refcount/string_literals.rs @@ -6,7 +6,10 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -pub fn foo_0(str: Ptr) { +pub fn foo_mut_0(str: Ptr) { + let str: Value> = Rc::new(RefCell::new(str)); +} +pub fn foo_const_1(str: Ptr) { let str: Value> = Rc::new(RefCell::new(str)); } pub fn main() { @@ -25,13 +28,41 @@ fn main_0() -> i32 { ]))); let mutable_string: Value> = Rc::new(RefCell::new(Ptr::from_string_literal("hello"))); let immutable_string: Value> = Rc::new(RefCell::new(Ptr::from_string_literal("hello"))); + let mutable_string_arr: Value> = + Rc::new(RefCell::new(Box::<[u8]>::from(b"papanasi\0".as_slice()))); + let immutable_string_arr: Value> = + Rc::new(RefCell::new(Box::<[u8]>::from(b"papanasi\0".as_slice()))); + ({ + let _str: Ptr = Ptr::from_string_literal("world"); + foo_mut_0(_str) + }); + ({ + let _str: Ptr = (*mutable_string.borrow()).clone(); + foo_mut_0(_str) + }); + ({ + let _str: Ptr = (mutable_string_arr.as_pointer() as Ptr); + foo_mut_0(_str) + }); ({ let _str: Ptr = Ptr::from_string_literal("world"); - foo_0(_str) + foo_const_1(_str) }); ({ let _str: Ptr = (*mutable_string.borrow()).clone(); - foo_0(_str) + foo_const_1(_str) + }); + ({ + let _str: Ptr = (*immutable_string.borrow()).clone(); + foo_const_1(_str) + }); + ({ + let _str: Ptr = (mutable_string_arr.as_pointer() as Ptr); + foo_const_1(_str) + }); + ({ + let _str: Ptr = (immutable_string_arr.as_pointer() as Ptr); + foo_const_1(_str) }); return 0; } diff --git a/tests/unit/out/refcount/string_literals_c.rs b/tests/unit/out/refcount/string_literals_c.rs index a6e63f1b..7d93a21a 100644 --- a/tests/unit/out/refcount/string_literals_c.rs +++ b/tests/unit/out/refcount/string_literals_c.rs @@ -6,7 +6,10 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -pub fn foo_0(str: Ptr) { +pub fn foo_mut_0(str: Ptr) { + let str: Value> = Rc::new(RefCell::new(str)); +} +pub fn foo_const_1(str: Ptr) { let str: Value> = Rc::new(RefCell::new(str)); } pub fn main() { @@ -25,13 +28,41 @@ fn main_0() -> i32 { ]))); let mutable_string: Value> = Rc::new(RefCell::new(Ptr::from_string_literal("hello"))); let immutable_string: Value> = Rc::new(RefCell::new(Ptr::from_string_literal("hello"))); + let mutable_string_arr: Value> = + Rc::new(RefCell::new(Box::<[u8]>::from(b"papanasi\0".as_slice()))); + let immutable_string_arr: Value> = + Rc::new(RefCell::new(Box::<[u8]>::from(b"papanasi\0".as_slice()))); + ({ + let _str: Ptr = Ptr::from_string_literal("world"); + foo_mut_0(_str) + }); + ({ + let _str: Ptr = (*mutable_string.borrow()).clone(); + foo_mut_0(_str) + }); + ({ + let _str: Ptr = (mutable_string_arr.as_pointer() as Ptr); + foo_mut_0(_str) + }); ({ let _str: Ptr = Ptr::from_string_literal("world"); - foo_0(_str) + foo_const_1(_str) }); ({ let _str: Ptr = (*mutable_string.borrow()).clone(); - foo_0(_str) + foo_const_1(_str) + }); + ({ + let _str: Ptr = (*immutable_string.borrow()).clone(); + foo_const_1(_str) + }); + ({ + let _str: Ptr = (mutable_string_arr.as_pointer() as Ptr); + foo_const_1(_str) + }); + ({ + let _str: Ptr = (immutable_string_arr.as_pointer() as Ptr); + foo_const_1(_str) }); return 0; } diff --git a/tests/unit/out/unsafe/borrow_mut_opt.rs b/tests/unit/out/unsafe/borrow_mut_opt.rs index 14ee319e..9f53ea00 100644 --- a/tests/unit/out/unsafe/borrow_mut_opt.rs +++ b/tests/unit/out/unsafe/borrow_mut_opt.rs @@ -23,7 +23,7 @@ pub unsafe fn convert_without_rhs_0() { let mut w: i32 = ((arr[(y) as usize]) + (arr[(x) as usize])); w += (((z) + (y)) + (x)); let mut arr2: [u8; 3] = [('a' as u8), ('b' as u8), ('c' as u8)]; - let mut p1: *const i32 = (&mut x as *mut i32); + let mut p1: *const i32 = (&mut x as *mut i32).cast_const(); let mut c: u8 = arr2[(*p1) as usize]; c = arr2[(*p1) as usize]; let mut p2: *mut i32 = (&mut x as *mut i32); diff --git a/tests/unit/out/unsafe/huffman.rs b/tests/unit/out/unsafe/huffman.rs index d9da3862..ef9ab27d 100644 --- a/tests/unit/out/unsafe/huffman.rs +++ b/tests/unit/out/unsafe/huffman.rs @@ -6,7 +6,6 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; -#[repr(C)] #[derive(Copy, Clone, Default)] pub struct MinHeapNode { pub data: u8, @@ -41,7 +40,6 @@ pub unsafe fn Swap_0(a: *mut MinHeapNode, b: *mut MinHeapNode) { }) .clone(); } -#[repr(C)] #[derive(Default)] pub struct MinHeap { pub size: i32, @@ -241,7 +239,7 @@ pub unsafe fn CollectCodes_4( CollectCodes_4(_root, _arr, _top, _out, _next) }); } - if (unsafe { (*root).IsLeaf() }) { + if (unsafe { (*root.cast_const()).IsLeaf() }) { (unsafe { let _arr: *mut Option> = arr; let _top: i32 = top; diff --git a/tests/unit/out/unsafe/main.rs b/tests/unit/out/unsafe/main.rs index d59202ca..3114a94a 100644 --- a/tests/unit/out/unsafe/main.rs +++ b/tests/unit/out/unsafe/main.rs @@ -18,7 +18,7 @@ pub fn main() { } unsafe fn main_0(mut argc: i32, mut argv: *mut *mut u8) -> i32 { let mut s: Vec = { - let s = (*argv.offset((0) as isize)); + let s = (*argv.offset((0) as isize)).cast_const(); std::slice::from_raw_parts(s, (0..).take_while(|&i| *s.add(i) != 0).count() + 1).to_vec() }; assert!(((argc) == (1))); diff --git a/tests/unit/out/unsafe/pointer_diff.rs b/tests/unit/out/unsafe/pointer_diff.rs index 45b0bd2a..794fdc58 100644 --- a/tests/unit/out/unsafe/pointer_diff.rs +++ b/tests/unit/out/unsafe/pointer_diff.rs @@ -13,7 +13,7 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut a: [i32; 5] = [1, 2, 3, 4, 5]; - let mut p0: *const i32 = (&mut a[(0) as usize] as *mut i32); - let mut p1: *const i32 = (&mut a[(4) as usize] as *mut i32); + let mut p0: *const i32 = (&mut a[(0) as usize] as *mut i32).cast_const(); + let mut p1: *const i32 = (&mut a[(4) as usize] as *mut i32).cast_const(); return ((((p1 as usize - p0 as usize) / ::std::mem::size_of::()) as u64) as i32); } diff --git a/tests/unit/out/unsafe/pointer_eq.rs b/tests/unit/out/unsafe/pointer_eq.rs index e2ce1241..94d7ce53 100644 --- a/tests/unit/out/unsafe/pointer_eq.rs +++ b/tests/unit/out/unsafe/pointer_eq.rs @@ -13,11 +13,11 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut x: i32 = 5; - let mut p1: *const i32 = (&mut x as *mut i32); - let mut p2: *const i32 = (&mut x as *mut i32); + let mut p1: *const i32 = (&mut x as *mut i32).cast_const(); + let mut p2: *const i32 = (&mut x as *mut i32).cast_const(); assert!(((p1) == (p2))); let mut y: i32 = 5; - let mut p3: *const i32 = (&mut y as *mut i32); + let mut p3: *const i32 = (&mut y as *mut i32).cast_const(); assert!(((p1) != (p3))); let mut arr: [i32; 3] = [1, 2, 3]; let mut p: *mut i32 = arr.as_mut_ptr(); diff --git a/tests/unit/out/unsafe/pointer_neq.rs b/tests/unit/out/unsafe/pointer_neq.rs index 7937b5c8..a3c972ce 100644 --- a/tests/unit/out/unsafe/pointer_neq.rs +++ b/tests/unit/out/unsafe/pointer_neq.rs @@ -13,8 +13,8 @@ pub fn main() { } unsafe fn main_0() -> i32 { let mut x: i32 = 5; - let mut p1: *const i32 = (&mut x as *mut i32); - let mut p2: *const i32 = (&mut x as *mut i32); + let mut p1: *const i32 = (&mut x as *mut i32).cast_const(); + let mut p2: *const i32 = (&mut x as *mut i32).cast_const(); if ((p1) != (p2)) { return 1; } else { diff --git a/tests/unit/out/unsafe/pointer_offset.rs b/tests/unit/out/unsafe/pointer_offset.rs index 34bf0329..e2c76091 100644 --- a/tests/unit/out/unsafe/pointer_offset.rs +++ b/tests/unit/out/unsafe/pointer_offset.rs @@ -14,7 +14,7 @@ pub fn main() { unsafe fn main_0() -> i32 { let mut out: i32 = 0; let mut arr: [i32; 5] = [1, 2, 3, 4, 0]; - let mut ptr: *const i32 = (&mut arr[(0) as usize] as *mut i32); + let mut ptr: *const i32 = (&mut arr[(0) as usize] as *mut i32).cast_const(); 'loop_: while ((*ptr) != (0)) { out += (*ptr); ptr.prefix_inc(); @@ -29,7 +29,7 @@ unsafe fn main_0() -> i32 { out += (*ptr); ptr.postfix_dec(); } - let mut ptr: *const i32 = (&mut arr[(3) as usize] as *mut i32); + let mut ptr: *const i32 = (&mut arr[(3) as usize] as *mut i32).cast_const(); 'loop_: while ((*ptr) != (2)) { out += (*ptr); ptr.prefix_dec(); diff --git a/tests/unit/out/unsafe/polymorphism.rs b/tests/unit/out/unsafe/polymorphism.rs index 3152dceb..295958ac 100644 --- a/tests/unit/out/unsafe/polymorphism.rs +++ b/tests/unit/out/unsafe/polymorphism.rs @@ -9,7 +9,6 @@ use std::rc::Rc; pub unsafe trait Animal { unsafe fn bark(&self) -> bool; } -#[repr(C)] #[derive(Copy, Clone, Default)] pub struct Dog {} unsafe impl Animal for Dog { @@ -17,7 +16,6 @@ unsafe impl Animal for Dog { return true; } } -#[repr(C)] #[derive(Copy, Clone, Default)] pub struct Cat {} impl Cat { @@ -38,9 +36,9 @@ pub fn main() { unsafe fn main_0() -> i32 { let mut dog: Dog = ::default(); let mut animal: *mut dyn Animal = (&mut dog as *mut Dog); - let mut eat1: bool = (unsafe { (*animal).bark() }); + let mut eat1: bool = (unsafe { (*animal.cast_const()).bark() }); let mut cat: Cat = ::default(); animal = (&mut cat as *mut Cat); - let mut eat2: bool = (unsafe { (*animal).bark() }); + let mut eat2: bool = (unsafe { (*animal.cast_const()).bark() }); return (((eat1) && (!eat2)) as i32); } diff --git a/tests/unit/out/unsafe/printfs.rs b/tests/unit/out/unsafe/printfs.rs index 5933ebb7..9e3e799f 100644 --- a/tests/unit/out/unsafe/printfs.rs +++ b/tests/unit/out/unsafe/printfs.rs @@ -40,7 +40,7 @@ unsafe fn main_0() -> i32 { let s = b"a string\0".as_ptr(); std::slice::from_raw_parts(s, (0..).take_while(|&i| *s.add(i) != 0).count() + 1).to_vec() }; - printf(b"%s\n\0".as_ptr() as *const i8, s.as_ptr()); + printf(b"%s\n\0".as_ptr() as *const i8, s.as_mut_ptr()); printf( b"%s\n\0".as_ptr() as *const i8, (unsafe { diff --git a/tests/unit/out/unsafe/refs_as_args.rs b/tests/unit/out/unsafe/refs_as_args.rs index cbb7a05b..656b163a 100644 --- a/tests/unit/out/unsafe/refs_as_args.rs +++ b/tests/unit/out/unsafe/refs_as_args.rs @@ -9,7 +9,7 @@ use std::rc::Rc; pub unsafe fn more_refs_0(mut x1: i32, mut x2: i32, r1: *mut i32, r2: *const i32) { let rx1: *const i32 = &x1 as *const i32; let rx2: *mut i32 = &mut x2 as *mut i32; - let mut pr1: *const i32 = (r1); + let mut pr1: *const i32 = (r1).cast_const(); let mut pr2: *const i32 = (r2); let rpr1: *const i32 = &(*pr1) as *const i32; let rpr2: *const i32 = &(*pr2) as *const i32; diff --git a/tests/unit/out/unsafe/string.rs b/tests/unit/out/unsafe/string.rs index 79044a77..6162f3dc 100644 --- a/tests/unit/out/unsafe/string.rs +++ b/tests/unit/out/unsafe/string.rs @@ -30,7 +30,7 @@ unsafe fn main_0() -> i32 { .to_vec() } ); - let mut p1: *const u8 = s1.as_ptr(); + let mut p1: *const u8 = s1.as_mut_ptr().cast_const(); assert!((((*p1.offset((0) as isize)) as i32) == (('h' as u8) as i32))); assert!((((*p1.offset((1) as isize)) as i32) == (('e' as u8) as i32))); assert!((((*p1.offset((2) as isize)) as i32) == (('l' as u8) as i32))); @@ -41,7 +41,7 @@ unsafe fn main_0() -> i32 { .cloned() .chain(std::iter::once(0)) .collect(); - let mut p2: *const u8 = s2.as_ptr(); + let mut p2: *const u8 = s2.as_mut_ptr().cast_const(); let mut i: u32 = 0_u32; 'loop_: while ((i as u64) < ((s2.len() - 1) as u64)) { assert!( @@ -72,7 +72,7 @@ unsafe fn main_0() -> i32 { }; assert!((((s3.len() - 1) as u64) == (5_u64))); assert!((((s3.len() - 1) as u64) == ((s3.len() - 1) as u64))); - let mut p3: *const u8 = s3.as_ptr(); + let mut p3: *const u8 = s3.as_mut_ptr().cast_const(); let mut i: u32 = 0_u32; 'loop_: while ((i as u64) < ((s3.len() - 1) as u64)) { assert!((((*p3.offset((i) as isize)) as i32) == (s3[(i as u64) as usize] as i32))); @@ -99,7 +99,7 @@ unsafe fn main_0() -> i32 { }; assert!((((s4.len() - 1) as u64) == (3_u64))); assert!((((s4.len() - 1) as u64) == ((s4.len() - 1) as u64))); - let mut p4: *const u8 = s4.as_ptr(); + let mut p4: *const u8 = s4.as_mut_ptr().cast_const(); let mut i: u32 = 0_u32; 'loop_: while ((i as u64) < ((s4.len() - 1) as u64)) { assert!((((*p4.offset((i) as isize)) as i32) == (s4[(i as u64) as usize] as i32))); @@ -118,7 +118,7 @@ unsafe fn main_0() -> i32 { }; assert!((((s5.len() - 1) as u64) == (12_u64))); assert!((((s5.len() - 1) as u64) == ((s5.len() - 1) as u64))); - let mut p5: *const u8 = s5.as_ptr(); + let mut p5: *const u8 = s5.as_mut_ptr().cast_const(); let mut i: u32 = 0_u32; 'loop_: while ((i as u64) < ((s5.len() - 1) as u64)) { assert!((((*p5.offset((i) as isize)) as i32) == (s5[(i as u64) as usize] as i32))); @@ -133,12 +133,13 @@ unsafe fn main_0() -> i32 { ('o' as u8), ('o' as u8), ]; - let mut string: Vec = std::slice::from_raw_parts(arr.as_mut_ptr(), 3_u64 as usize) - .to_vec() - .iter() - .copied() - .chain(std::iter::once(0)) - .collect(); + let mut string: Vec = + std::slice::from_raw_parts(arr.as_mut_ptr().cast_const(), 3_u64 as usize) + .to_vec() + .iter() + .copied() + .chain(std::iter::once(0)) + .collect(); assert!((((string.len() - 1) as u64) == (3_u64))); assert!(((string[(0_u64) as usize] as i32) == (('b' as u8) as i32))); assert!(((string[(1_u64) as usize] as i32) == (('a' as u8) as i32))); diff --git a/tests/unit/out/unsafe/string_literals.rs b/tests/unit/out/unsafe/string_literals.rs index 36d45ff5..7a349ef3 100644 --- a/tests/unit/out/unsafe/string_literals.rs +++ b/tests/unit/out/unsafe/string_literals.rs @@ -6,7 +6,8 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; -pub unsafe fn foo_0(mut str: *mut u8) {} +pub unsafe fn foo_mut_0(mut str: *mut u8) {} +pub unsafe fn foo_const_1(mut str: *const u8) {} pub fn main() { unsafe { std::process::exit(main_0() as i32); @@ -21,13 +22,39 @@ unsafe fn main_0() -> i32 { let mut immutable_strings: [*const u8; 3] = [b"a\0".as_ptr(), b"b\0".as_ptr(), b"c\0".as_ptr()]; let mut mutable_string: *mut u8 = b"hello\0".as_ptr().cast_mut(); let mut immutable_string: *const u8 = b"hello\0".as_ptr(); + let mut mutable_string_arr: [u8; 9] = *b"papanasi\0"; + let immutable_string_arr: [u8; 9] = *b"papanasi\0"; (unsafe { let _str: *mut u8 = b"world\0".as_ptr().cast_mut(); - foo_0(_str) + foo_mut_0(_str) }); (unsafe { let _str: *mut u8 = mutable_string; - foo_0(_str) + foo_mut_0(_str) + }); + (unsafe { + let _str: *mut u8 = mutable_string_arr.as_mut_ptr(); + foo_mut_0(_str) + }); + (unsafe { + let _str: *const u8 = b"world\0".as_ptr(); + foo_const_1(_str) + }); + (unsafe { + let _str: *const u8 = mutable_string.cast_const(); + foo_const_1(_str) + }); + (unsafe { + let _str: *const u8 = immutable_string; + foo_const_1(_str) + }); + (unsafe { + let _str: *const u8 = mutable_string_arr.as_mut_ptr().cast_const(); + foo_const_1(_str) + }); + (unsafe { + let _str: *const u8 = immutable_string_arr.as_ptr(); + foo_const_1(_str) }); return 0; } diff --git a/tests/unit/out/unsafe/string_literals_c.rs b/tests/unit/out/unsafe/string_literals_c.rs index c1e7b18b..75c5cfb7 100644 --- a/tests/unit/out/unsafe/string_literals_c.rs +++ b/tests/unit/out/unsafe/string_literals_c.rs @@ -6,7 +6,8 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; -pub unsafe fn foo_0(mut str: *mut u8) {} +pub unsafe fn foo_mut_0(mut str: *mut u8) {} +pub unsafe fn foo_const_1(mut str: *const u8) {} pub fn main() { unsafe { std::process::exit(main_0() as i32); @@ -25,13 +26,39 @@ unsafe fn main_0() -> i32 { ]; let mut mutable_string: *mut u8 = b"hello\0".as_ptr().cast_mut(); let mut immutable_string: *const u8 = b"hello\0".as_ptr().cast_mut().cast_const(); + let mut mutable_string_arr: [u8; 9] = *b"papanasi\0"; + let immutable_string_arr: [u8; 9] = *b"papanasi\0"; (unsafe { let _str: *mut u8 = b"world\0".as_ptr().cast_mut(); - foo_0(_str) + foo_mut_0(_str) }); (unsafe { let _str: *mut u8 = mutable_string; - foo_0(_str) + foo_mut_0(_str) + }); + (unsafe { + let _str: *mut u8 = mutable_string_arr.as_mut_ptr(); + foo_mut_0(_str) + }); + (unsafe { + let _str: *const u8 = b"world\0".as_ptr().cast_mut().cast_const(); + foo_const_1(_str) + }); + (unsafe { + let _str: *const u8 = mutable_string.cast_const(); + foo_const_1(_str) + }); + (unsafe { + let _str: *const u8 = immutable_string; + foo_const_1(_str) + }); + (unsafe { + let _str: *const u8 = mutable_string_arr.as_mut_ptr().cast_const(); + foo_const_1(_str) + }); + (unsafe { + let _str: *const u8 = immutable_string_arr.as_ptr(); + foo_const_1(_str) }); return 0; } diff --git a/tests/unit/out/unsafe/union_tagged_many_arms.rs b/tests/unit/out/unsafe/union_tagged_many_arms.rs index 1f9f7972..f3f54dde 100644 --- a/tests/unit/out/unsafe/union_tagged_many_arms.rs +++ b/tests/unit/out/unsafe/union_tagged_many_arms.rs @@ -15,21 +15,14 @@ enum Tag { T_FLOAT = 3, T_REF = 4, } -#[repr(C)] -#[derive(Copy, Clone)] -pub union Slot_anon_0 { +#[derive(Copy, Clone, Default)] +pub struct Slot_anon_0 { pub text: *const u8, pub handle: *mut ::libc::c_void, pub signed_n: i64, pub unsigned_n: u64, pub f: f64, } -impl Default for Slot_anon_0 { - fn default() -> Self { - unsafe { std::mem::zeroed() } - } -} -#[repr(C)] #[derive(Copy, Clone, Default)] pub struct Slot { pub tag: Tag, @@ -51,7 +44,7 @@ unsafe fn main_0() -> i32 { assert!(((b.payload.unsigned_n) == (3735928559_u64))); let mut c: Slot = ::default(); c.tag = (Tag::T_TEXT as Tag); - c.payload.text = b"hello\0".as_ptr(); + c.payload.text = b"hello\0".as_ptr().cast_mut().cast_const(); assert!((((*c.payload.text.offset((0) as isize)) as i32) == ('h' as i32))); let mut d: Slot = ::default(); d.tag = (Tag::T_FLOAT as Tag); diff --git a/tests/unit/out/unsafe/unique_ptr_const_deref.rs b/tests/unit/out/unsafe/unique_ptr_const_deref.rs index b7a96774..cfe33ce0 100644 --- a/tests/unit/out/unsafe/unique_ptr_const_deref.rs +++ b/tests/unit/out/unsafe/unique_ptr_const_deref.rs @@ -6,7 +6,6 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; -#[repr(C)] #[derive(Default)] pub struct Holder { pub val: Option>, @@ -30,12 +29,12 @@ unsafe fn main_0() -> i32 { let mut h: Holder = ::default(); h.val = Some(Box::new(10)); (unsafe { - let _h: *const Holder = (&mut h as *mut Holder); + let _h: *const Holder = (&mut h as *mut Holder).cast_const(); let _v: i32 = 42; write_val_1(_h, _v) }); return (unsafe { - let _h: *const Holder = (&mut h as *mut Holder); + let _h: *const Holder = (&mut h as *mut Holder).cast_const(); read_val_0(_h) }); } diff --git a/tests/unit/out/unsafe/va_arg_conditional.rs b/tests/unit/out/unsafe/va_arg_conditional.rs index 1bd74b04..ec9e9e47 100644 --- a/tests/unit/out/unsafe/va_arg_conditional.rs +++ b/tests/unit/out/unsafe/va_arg_conditional.rs @@ -24,14 +24,14 @@ unsafe fn main_0() -> i32 { assert!( ((unsafe { let _verbose: i32 = 1; - let _fmt: *const u8 = b"%d\0".as_ptr(); + let _fmt: *const u8 = b"%d\0".as_ptr().cast_mut().cast_const(); conditional_log_0(_verbose, _fmt, &[42.into()]) }) == (42)) ); assert!( ((unsafe { let _verbose: i32 = 0; - let _fmt: *const u8 = b"%d\0".as_ptr(); + let _fmt: *const u8 = b"%d\0".as_ptr().cast_mut().cast_const(); conditional_log_0(_verbose, _fmt, &[99.into()]) }) == (-1_i32)) ); diff --git a/tests/unit/out/unsafe/va_arg_printf.rs b/tests/unit/out/unsafe/va_arg_printf.rs index 960704cb..364d44de 100644 --- a/tests/unit/out/unsafe/va_arg_printf.rs +++ b/tests/unit/out/unsafe/va_arg_printf.rs @@ -27,13 +27,13 @@ pub fn main() { unsafe fn main_0() -> i32 { assert!( ((unsafe { - let _fmt: *const u8 = b"hello %d %d\0".as_ptr(); + let _fmt: *const u8 = b"hello %d %d\0".as_ptr().cast_mut().cast_const(); logf_1(_fmt, &[10.into(), 32.into()]) }) == (42)) ); assert!( ((unsafe { - let _fmt: *const u8 = b"x %d %d\0".as_ptr(); + let _fmt: *const u8 = b"x %d %d\0".as_ptr().cast_mut().cast_const(); logf_1(_fmt, &[1.into(), 2.into()]) }) == (3)) ); diff --git a/tests/unit/out/unsafe/va_arg_snprintf.rs b/tests/unit/out/unsafe/va_arg_snprintf.rs index 889a1659..841d65b7 100644 --- a/tests/unit/out/unsafe/va_arg_snprintf.rs +++ b/tests/unit/out/unsafe/va_arg_snprintf.rs @@ -29,7 +29,7 @@ unsafe fn main_0() -> i32 { ((unsafe { let _buf: *mut u8 = buf.as_mut_ptr(); let _size: i32 = 1; - let _fmt: *const u8 = b"%d\0".as_ptr(); + let _fmt: *const u8 = b"%d\0".as_ptr().cast_mut().cast_const(); extract_first_0(_buf, _size, _fmt, &[42.into()]) }) == (42)) ); @@ -38,7 +38,7 @@ unsafe fn main_0() -> i32 { ((unsafe { let _buf: *mut u8 = buf.as_mut_ptr(); let _size: i32 = 1; - let _fmt: *const u8 = b"%d\0".as_ptr(); + let _fmt: *const u8 = b"%d\0".as_ptr().cast_mut().cast_const(); extract_first_0(_buf, _size, _fmt, &[65.into()]) }) == (65)) ); diff --git a/tests/unit/out/unsafe/va_arg_struct_ctx.rs b/tests/unit/out/unsafe/va_arg_struct_ctx.rs index 1b7030b1..bff8f3db 100644 --- a/tests/unit/out/unsafe/va_arg_struct_ctx.rs +++ b/tests/unit/out/unsafe/va_arg_struct_ctx.rs @@ -6,7 +6,6 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; -#[repr(C)] #[derive(Copy, Clone, Default)] pub struct context { pub verbose: i32, @@ -30,14 +29,14 @@ unsafe fn main_0() -> i32 { ctx.last_error = 0; (unsafe { let _ctx: *mut context = (&mut ctx as *mut context); - let _fmt: *const u8 = b"error %d\0".as_ptr(); + let _fmt: *const u8 = b"error %d\0".as_ptr().cast_mut().cast_const(); set_error_0(_ctx, _fmt, &[42.into()]) }); assert!(((ctx.last_error) == (42))); ctx.verbose = 0; (unsafe { let _ctx: *mut context = (&mut ctx as *mut context); - let _fmt: *const u8 = b"error %d\0".as_ptr(); + let _fmt: *const u8 = b"error %d\0".as_ptr().cast_mut().cast_const(); set_error_0(_ctx, _fmt, &[99.into()]) }); assert!(((ctx.last_error) == (42))); diff --git a/tests/unit/out/unsafe/vector.rs b/tests/unit/out/unsafe/vector.rs index 11ff23c0..fb44d821 100644 --- a/tests/unit/out/unsafe/vector.rs +++ b/tests/unit/out/unsafe/vector.rs @@ -99,7 +99,7 @@ unsafe fn main_0() -> i32 { assert!((((v7[(i as u64) as usize].0).is_null()) && ((v7[(i as u64) as usize].1) == (0)))); i.prefix_inc(); } - let mut p1: *const f64 = v6.as_mut_ptr(); + let mut p1: *const f64 = v6.as_mut_ptr().cast_const(); assert!(((*p1) == (2.0E+0))); let mut p2: *mut i32 = v3.as_mut_ptr(); assert!(((*p2) == (1))); diff --git a/tests/unit/string_literals.cpp b/tests/unit/string_literals.cpp index 880f37b9..80396e19 100644 --- a/tests/unit/string_literals.cpp +++ b/tests/unit/string_literals.cpp @@ -1,15 +1,24 @@ -void foo(char *str) {} +void foo_mut(char *str) {} +void foo_const(const char *str) {} int main() { - // -Wwritable-strings warning triggered char *mutable_strings[] = {"a", "b", "c"}; const char *immutable_strings[] = {"a", "b", "c"}; char *mutable_string = "hello"; const char *immutable_string = "hello"; - foo("world"); - foo(mutable_string); - // Calling foo with immutable_string is an error, not an warning + char mutable_string_arr[] = "papanasi"; + const char immutable_string_arr[] = "papanasi"; + + foo_mut("world"); + foo_mut(mutable_string); + foo_mut(mutable_string_arr); + + foo_const("world"); + foo_const(mutable_string); + foo_const(immutable_string); + foo_const(mutable_string_arr); + foo_const(immutable_string_arr); return 0; } diff --git a/tests/unit/string_literals_c.c b/tests/unit/string_literals_c.c index 7ca57daa..80396e19 100644 --- a/tests/unit/string_literals_c.c +++ b/tests/unit/string_literals_c.c @@ -1,4 +1,5 @@ -void foo(char *str) {} +void foo_mut(char *str) {} +void foo_const(const char *str) {} int main() { char *mutable_strings[] = {"a", "b", "c"}; @@ -7,8 +8,17 @@ int main() { char *mutable_string = "hello"; const char *immutable_string = "hello"; - foo("world"); - foo(mutable_string); - // Calling foo with immutable_string is an error + char mutable_string_arr[] = "papanasi"; + const char immutable_string_arr[] = "papanasi"; + + foo_mut("world"); + foo_mut(mutable_string); + foo_mut(mutable_string_arr); + + foo_const("world"); + foo_const(mutable_string); + foo_const(immutable_string); + foo_const(mutable_string_arr); + foo_const(immutable_string_arr); return 0; } diff --git a/tests/unit/union_tagged_struct_arms.c b/tests/unit/union_tagged_struct_arms.c index 3cd71f8a..de0c887f 100644 --- a/tests/unit/union_tagged_struct_arms.c +++ b/tests/unit/union_tagged_struct_arms.c @@ -1,4 +1,3 @@ -// no-compile #include #include From 24bd56ba911267fa22851ec1ab8747dcdcaed123 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 29 Apr 2026 13:08:17 +0100 Subject: [PATCH 13/23] Return mutable string from non-const std::string::data() --- rules/string/ir_unsafe.json | 6 +++--- rules/string/tgt_unsafe.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rules/string/ir_unsafe.json b/rules/string/ir_unsafe.json index 2a903675..e863d85f 100644 --- a/rules/string/ir_unsafe.json +++ b/rules/string/ir_unsafe.json @@ -1548,13 +1548,13 @@ { "placeholder": { "arg": "a0", - "access": "read" + "access": "write" } } ], "body": [ { - "text": ".as_ptr()" + "text": ".as_mut_ptr()" } ] } @@ -1562,7 +1562,7 @@ ], "params": { "a0": { - "type": "Vec" + "type": "&mut Vec" } }, "return_type": { diff --git a/rules/string/tgt_unsafe.rs b/rules/string/tgt_unsafe.rs index a16cb743..4498dc9a 100644 --- a/rules/string/tgt_unsafe.rs +++ b/rules/string/tgt_unsafe.rs @@ -35,8 +35,8 @@ unsafe fn f4(a0: &mut Vec, a1: *mut u8, a2: usize) { unsafe fn f5(a0: Vec) -> *const u8 { a0.as_ptr() } -unsafe fn f6(a0: Vec) -> *const u8 { - a0.as_ptr() +unsafe fn f6(a0: &mut Vec) -> *const u8 { + a0.as_mut_ptr() } unsafe fn f7(a0: *const u8, a1: usize) -> Vec { std::slice::from_raw_parts(a0, a1 as usize) From ce234955002958323321995014c730e4c1aa01de Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 29 Apr 2026 13:42:44 +0100 Subject: [PATCH 14/23] Add more string literal tests --- tests/unit/string_literals.cpp | 11 +++++++++ tests/unit/string_literals_c.c | 11 +++++++++ tests/unit/string_literals_concat.cpp | 24 ++++++++++++++++++++ tests/unit/string_literals_concat_c.c | 17 ++++++++++++++ tests/unit/string_literals_return.cpp | 32 +++++++++++++++++++++++++++ tests/unit/string_literals_return_c.c | 32 +++++++++++++++++++++++++++ tests/unit/string_literals_sized.cpp | 29 ++++++++++++++++++++++++ tests/unit/string_literals_sized_c.c | 29 ++++++++++++++++++++++++ 8 files changed, 185 insertions(+) create mode 100644 tests/unit/string_literals_concat.cpp create mode 100644 tests/unit/string_literals_concat_c.c create mode 100644 tests/unit/string_literals_return.cpp create mode 100644 tests/unit/string_literals_return_c.c create mode 100644 tests/unit/string_literals_sized.cpp create mode 100644 tests/unit/string_literals_sized_c.c diff --git a/tests/unit/string_literals.cpp b/tests/unit/string_literals.cpp index 80396e19..d72fcbbf 100644 --- a/tests/unit/string_literals.cpp +++ b/tests/unit/string_literals.cpp @@ -11,6 +11,11 @@ int main() { char mutable_string_arr[] = "papanasi"; const char immutable_string_arr[] = "papanasi"; + char *mutable_empty = ""; + const char *immutable_empty = ""; + char mutable_empty_arr[] = ""; + const char immutable_empty_arr[] = ""; + foo_mut("world"); foo_mut(mutable_string); foo_mut(mutable_string_arr); @@ -20,5 +25,11 @@ int main() { foo_const(immutable_string); foo_const(mutable_string_arr); foo_const(immutable_string_arr); + + foo_const(""); + foo_const(mutable_empty); + foo_const(immutable_empty); + foo_const(mutable_empty_arr); + foo_const(immutable_empty_arr); return 0; } diff --git a/tests/unit/string_literals_c.c b/tests/unit/string_literals_c.c index 80396e19..d72fcbbf 100644 --- a/tests/unit/string_literals_c.c +++ b/tests/unit/string_literals_c.c @@ -11,6 +11,11 @@ int main() { char mutable_string_arr[] = "papanasi"; const char immutable_string_arr[] = "papanasi"; + char *mutable_empty = ""; + const char *immutable_empty = ""; + char mutable_empty_arr[] = ""; + const char immutable_empty_arr[] = ""; + foo_mut("world"); foo_mut(mutable_string); foo_mut(mutable_string_arr); @@ -20,5 +25,11 @@ int main() { foo_const(immutable_string); foo_const(mutable_string_arr); foo_const(immutable_string_arr); + + foo_const(""); + foo_const(mutable_empty); + foo_const(immutable_empty); + foo_const(mutable_empty_arr); + foo_const(immutable_empty_arr); return 0; } diff --git a/tests/unit/string_literals_concat.cpp b/tests/unit/string_literals_concat.cpp new file mode 100644 index 00000000..d717359c --- /dev/null +++ b/tests/unit/string_literals_concat.cpp @@ -0,0 +1,24 @@ +#include + +int main() { + const char *joined = "alpha\n" + "beta\n" + "gamma\n"; + assert(joined[0] == 'a'); + assert(joined[5] == '\n'); + assert(joined[6] == 'b'); + + char arr[] = "foo" "bar"; + assert(arr[0] == 'f'); + assert(arr[3] == 'b'); + assert(arr[5] == 'r'); + assert(arr[6] == '\0'); + + const char *split_pieces = "abc" "def" "ghi"; + assert(split_pieces[0] == 'a'); + assert(split_pieces[3] == 'd'); + assert(split_pieces[6] == 'g'); + assert(split_pieces[8] == 'i'); + assert(split_pieces[9] == '\0'); + return 0; +} diff --git a/tests/unit/string_literals_concat_c.c b/tests/unit/string_literals_concat_c.c new file mode 100644 index 00000000..1382482b --- /dev/null +++ b/tests/unit/string_literals_concat_c.c @@ -0,0 +1,17 @@ +#include + +int main(void) { + char arr[] = "foo" "bar"; + assert(arr[0] == 'f'); + assert(arr[3] == 'b'); + assert(arr[5] == 'r'); + assert(arr[6] == '\0'); + + const char *split_pieces = "abc" "def" "ghi"; + assert(split_pieces[0] == 'a'); + assert(split_pieces[3] == 'd'); + assert(split_pieces[6] == 'g'); + assert(split_pieces[8] == 'i'); + assert(split_pieces[9] == '\0'); + return 0; +} diff --git a/tests/unit/string_literals_return.cpp b/tests/unit/string_literals_return.cpp new file mode 100644 index 00000000..0b828317 --- /dev/null +++ b/tests/unit/string_literals_return.cpp @@ -0,0 +1,32 @@ +#include + +const char *get_greeting() { return "hello"; } +const char *get_empty() { return ""; } + +const char *get_branch(int x) { + if (x > 0) { + return "positive"; + } + return "non-positive"; +} + +int main() { + const char *a = get_greeting(); + assert(a[0] == 'h'); + assert(a[4] == 'o'); + assert(a[5] == '\0'); + + const char *b = get_empty(); + assert(b[0] == '\0'); + + const char *c = get_branch(1); + assert(c[0] == 'p'); + assert(c[7] == 'e'); + assert(c[8] == '\0'); + + const char *d = get_branch(-1); + assert(d[0] == 'n'); + assert(d[11] == 'e'); + assert(d[12] == '\0'); + return 0; +} diff --git a/tests/unit/string_literals_return_c.c b/tests/unit/string_literals_return_c.c new file mode 100644 index 00000000..42db7ba5 --- /dev/null +++ b/tests/unit/string_literals_return_c.c @@ -0,0 +1,32 @@ +#include + +const char *get_greeting(void) { return "hello"; } +const char *get_empty(void) { return ""; } + +const char *get_branch(int x) { + if (x > 0) { + return "positive"; + } + return "non-positive"; +} + +int main(void) { + const char *a = get_greeting(); + assert(a[0] == 'h'); + assert(a[4] == 'o'); + assert(a[5] == '\0'); + + const char *b = get_empty(); + assert(b[0] == '\0'); + + const char *c = get_branch(1); + assert(c[0] == 'p'); + assert(c[7] == 'e'); + assert(c[8] == '\0'); + + const char *d = get_branch(-1); + assert(d[0] == 'n'); + assert(d[11] == 'e'); + assert(d[12] == '\0'); + return 0; +} diff --git a/tests/unit/string_literals_sized.cpp b/tests/unit/string_literals_sized.cpp new file mode 100644 index 00000000..254b1661 --- /dev/null +++ b/tests/unit/string_literals_sized.cpp @@ -0,0 +1,29 @@ +#include + +int main() { + char empty_buf[256] = ""; + assert(empty_buf[0] == '\0'); + assert(empty_buf[255] == '\0'); + + char prefix_buf[32] = "%"; + assert(prefix_buf[0] == '%'); + assert(prefix_buf[1] == '\0'); + assert(prefix_buf[31] == '\0'); + + char short_buf[16] = "hi"; + assert(short_buf[0] == 'h'); + assert(short_buf[1] == 'i'); + assert(short_buf[2] == '\0'); + assert(short_buf[15] == '\0'); + + char exact_buf[6] = "hello"; + assert(exact_buf[0] == 'h'); + assert(exact_buf[4] == 'o'); + assert(exact_buf[5] == '\0'); + + assert(sizeof("hello") == 6); + assert(sizeof("hello") - 1 == 5); + assert(sizeof("") == 1); + assert(sizeof("fifteen-bytes!!") - 1 == 15); + return 0; +} diff --git a/tests/unit/string_literals_sized_c.c b/tests/unit/string_literals_sized_c.c new file mode 100644 index 00000000..e8fdaef0 --- /dev/null +++ b/tests/unit/string_literals_sized_c.c @@ -0,0 +1,29 @@ +#include + +int main() { + char empty_buf[256] = ""; + assert(empty_buf[0] == '\0'); + assert(empty_buf[255] == '\0'); + + char prefix_buf[32] = "%"; + assert(prefix_buf[0] == '%'); + assert(prefix_buf[1] == '\0'); + assert(prefix_buf[31] == '\0'); + + char short_buf[16] = "hi"; + assert(short_buf[0] == 'h'); + assert(short_buf[1] == 'i'); + assert(short_buf[2] == '\0'); + assert(short_buf[15] == '\0'); + + char exact_buf[6] = "hello"; + assert(exact_buf[0] == 'h'); + assert(exact_buf[4] == 'o'); + assert(exact_buf[5] == '\0'); + + assert(sizeof("hello") == 6); + assert(sizeof("hello") - 1 == 5); + assert(sizeof("") == 1); + assert(sizeof("fifteen-bytes!!") - 1 == 15); + return 0; +} From e7d120f7117fb905c28f52767b23bbc1e9dff364 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 29 Apr 2026 13:43:23 +0100 Subject: [PATCH 15/23] Pad with null bytes in GetEscapedStringLiteral --- cpp2rust/converter/converter.cpp | 17 +++++++++++------ cpp2rust/converter/converter.h | 2 +- .../converter/models/converter_refcount.cpp | 11 ++++++++--- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index de4b8e98..986a40dd 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1689,7 +1689,7 @@ std::string Converter::GetEscapedUTF8CharLiteral(clang::Expr *expr) const { } std::string Converter::GetEscapedStringLiteral(clang::Expr *expr, - bool add_null_char) const { + uint64_t pad_nulls) const { auto str_expr = clang::dyn_cast(expr->IgnoreCasts()); assert(str_expr); auto raw = str_expr->getString(); @@ -1698,7 +1698,7 @@ std::string Converter::GetEscapedStringLiteral(clang::Expr *expr, for (unsigned char c : raw) { out += GetEscapedCharLiteral(static_cast(c)); } - if (add_null_char) { + for (uint64_t i = 0; i < pad_nulls; ++i) { out += "\\0"; } out.push_back('"'); @@ -1707,12 +1707,17 @@ std::string Converter::GetEscapedStringLiteral(clang::Expr *expr, bool Converter::VisitStringLiteral(clang::StringLiteral *expr) { if (!curr_init_type_.empty() && curr_init_type_.top()->isArrayType()) { - // b"" has type &static [u8; N]. For translating char str[] = - // "string_literal"; we need an initializer of type [u8; N]. Dereferencing - // the &static [u8; N] achieves this. StrCat(token::kStar); + if (auto *arr_ty = ctx_.getAsConstantArrayType(curr_init_type_.top())) { + uint64_t target = arr_ty->getSize().getZExtValue(); + uint64_t pad = target > expr->getString().size() + ? target - expr->getString().size() + : 0; + StrCat(std::format("b{}", GetEscapedStringLiteral(expr, pad))); + return false; + } } - StrCat(std::format("b{}", GetEscapedStringLiteral(expr, true))); + StrCat(std::format("b{}", GetEscapedStringLiteral(expr, 1))); return false; } diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 273b6dd3..d98e2ad5 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -233,7 +233,7 @@ class Converter : public clang::RecursiveASTVisitor { std::string GetEscapedUTF8CharLiteral(clang::Expr *expr) const; std::string GetEscapedStringLiteral(clang::Expr *expr, - bool add_null_char = false) const; + uint64_t pad_nulls = 0) const; virtual bool VisitStringLiteral(clang::StringLiteral *expr); virtual bool VisitCXXBoolLiteralExpr(clang::CXXBoolLiteralExpr *expr); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index cadad266..a1fd93a8 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -947,10 +947,15 @@ bool ConverterRefCount::VisitCallExpr(clang::CallExpr *expr) { bool ConverterRefCount::VisitStringLiteral(clang::StringLiteral *expr) { if (!curr_init_type_.empty() && curr_init_type_.top()->isArrayType()) { - // b"" has type &static [u8; N]. For translating char str[] = - // "string_literal"; we need an initializer of type Box<[u8]> + uint64_t pad = 1; + if (auto *arr_ty = ctx_.getAsConstantArrayType(curr_init_type_.top())) { + uint64_t target = arr_ty->getSize().getZExtValue(); + pad = target > expr->getString().size() + ? target - expr->getString().size() + : 0; + } StrCat(std::format("Box::<[u8]>::from(b{}.as_slice())", - GetEscapedStringLiteral(expr, true))); + GetEscapedStringLiteral(expr, pad))); return false; } StrCat(GetEscapedStringLiteral(expr)); From dfa8671eb4cf788847e69d88d574c79325c87a1a Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 29 Apr 2026 13:45:47 +0100 Subject: [PATCH 16/23] Update tests --- tests/unit/out/refcount/string_literals.rs | 26 ++++++++++ tests/unit/out/refcount/string_literals_c.rs | 26 ++++++++++ .../out/refcount/string_literals_concat.rs | 41 +++++++++++++++ .../out/refcount/string_literals_concat_c.rs | 25 +++++++++ .../out/refcount/string_literals_return.rs | 51 +++++++++++++++++++ .../out/refcount/string_literals_return_c.rs | 51 +++++++++++++++++++ .../out/refcount/string_literals_sized.rs | 39 ++++++++++++++ .../out/refcount/string_literals_sized_c.rs | 39 ++++++++++++++ tests/unit/out/unsafe/string_literals.rs | 24 +++++++++ tests/unit/out/unsafe/string_literals_c.rs | 24 +++++++++ .../unit/out/unsafe/string_literals_concat.rs | 31 +++++++++++ .../out/unsafe/string_literals_concat_c.rs | 27 ++++++++++ .../unit/out/unsafe/string_literals_return.rs | 48 +++++++++++++++++ .../out/unsafe/string_literals_return_c.rs | 48 +++++++++++++++++ .../unit/out/unsafe/string_literals_sized.rs | 37 ++++++++++++++ .../out/unsafe/string_literals_sized_c.rs | 37 ++++++++++++++ 16 files changed, 574 insertions(+) create mode 100644 tests/unit/out/refcount/string_literals_concat.rs create mode 100644 tests/unit/out/refcount/string_literals_concat_c.rs create mode 100644 tests/unit/out/refcount/string_literals_return.rs create mode 100644 tests/unit/out/refcount/string_literals_return_c.rs create mode 100644 tests/unit/out/refcount/string_literals_sized.rs create mode 100644 tests/unit/out/refcount/string_literals_sized_c.rs create mode 100644 tests/unit/out/unsafe/string_literals_concat.rs create mode 100644 tests/unit/out/unsafe/string_literals_concat_c.rs create mode 100644 tests/unit/out/unsafe/string_literals_return.rs create mode 100644 tests/unit/out/unsafe/string_literals_return_c.rs create mode 100644 tests/unit/out/unsafe/string_literals_sized.rs create mode 100644 tests/unit/out/unsafe/string_literals_sized_c.rs diff --git a/tests/unit/out/refcount/string_literals.rs b/tests/unit/out/refcount/string_literals.rs index 7d93a21a..ba34a5e4 100644 --- a/tests/unit/out/refcount/string_literals.rs +++ b/tests/unit/out/refcount/string_literals.rs @@ -32,6 +32,12 @@ fn main_0() -> i32 { Rc::new(RefCell::new(Box::<[u8]>::from(b"papanasi\0".as_slice()))); let immutable_string_arr: Value> = Rc::new(RefCell::new(Box::<[u8]>::from(b"papanasi\0".as_slice()))); + let mutable_empty: Value> = Rc::new(RefCell::new(Ptr::from_string_literal(""))); + let immutable_empty: Value> = Rc::new(RefCell::new(Ptr::from_string_literal(""))); + let mutable_empty_arr: Value> = + Rc::new(RefCell::new(Box::<[u8]>::from(b"\0".as_slice()))); + let immutable_empty_arr: Value> = + Rc::new(RefCell::new(Box::<[u8]>::from(b"\0".as_slice()))); ({ let _str: Ptr = Ptr::from_string_literal("world"); foo_mut_0(_str) @@ -64,5 +70,25 @@ fn main_0() -> i32 { let _str: Ptr = (immutable_string_arr.as_pointer() as Ptr); foo_const_1(_str) }); + ({ + let _str: Ptr = Ptr::from_string_literal(""); + foo_const_1(_str) + }); + ({ + let _str: Ptr = (*mutable_empty.borrow()).clone(); + foo_const_1(_str) + }); + ({ + let _str: Ptr = (*immutable_empty.borrow()).clone(); + foo_const_1(_str) + }); + ({ + let _str: Ptr = (mutable_empty_arr.as_pointer() as Ptr); + foo_const_1(_str) + }); + ({ + let _str: Ptr = (immutable_empty_arr.as_pointer() as Ptr); + foo_const_1(_str) + }); return 0; } diff --git a/tests/unit/out/refcount/string_literals_c.rs b/tests/unit/out/refcount/string_literals_c.rs index 7d93a21a..ba34a5e4 100644 --- a/tests/unit/out/refcount/string_literals_c.rs +++ b/tests/unit/out/refcount/string_literals_c.rs @@ -32,6 +32,12 @@ fn main_0() -> i32 { Rc::new(RefCell::new(Box::<[u8]>::from(b"papanasi\0".as_slice()))); let immutable_string_arr: Value> = Rc::new(RefCell::new(Box::<[u8]>::from(b"papanasi\0".as_slice()))); + let mutable_empty: Value> = Rc::new(RefCell::new(Ptr::from_string_literal(""))); + let immutable_empty: Value> = Rc::new(RefCell::new(Ptr::from_string_literal(""))); + let mutable_empty_arr: Value> = + Rc::new(RefCell::new(Box::<[u8]>::from(b"\0".as_slice()))); + let immutable_empty_arr: Value> = + Rc::new(RefCell::new(Box::<[u8]>::from(b"\0".as_slice()))); ({ let _str: Ptr = Ptr::from_string_literal("world"); foo_mut_0(_str) @@ -64,5 +70,25 @@ fn main_0() -> i32 { let _str: Ptr = (immutable_string_arr.as_pointer() as Ptr); foo_const_1(_str) }); + ({ + let _str: Ptr = Ptr::from_string_literal(""); + foo_const_1(_str) + }); + ({ + let _str: Ptr = (*mutable_empty.borrow()).clone(); + foo_const_1(_str) + }); + ({ + let _str: Ptr = (*immutable_empty.borrow()).clone(); + foo_const_1(_str) + }); + ({ + let _str: Ptr = (mutable_empty_arr.as_pointer() as Ptr); + foo_const_1(_str) + }); + ({ + let _str: Ptr = (immutable_empty_arr.as_pointer() as Ptr); + foo_const_1(_str) + }); return 0; } diff --git a/tests/unit/out/refcount/string_literals_concat.rs b/tests/unit/out/refcount/string_literals_concat.rs new file mode 100644 index 00000000..3bfeb994 --- /dev/null +++ b/tests/unit/out/refcount/string_literals_concat.rs @@ -0,0 +1,41 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let joined: Value> = Rc::new(RefCell::new(Ptr::from_string_literal( + "alpha\nbeta\ngamma\n", + ))); + assert!(((((*joined.borrow()).offset((0) as isize).read()) as i32) == (('a' as u8) as i32))); + assert!(((((*joined.borrow()).offset((5) as isize).read()) as i32) == (('\n' as u8) as i32))); + assert!(((((*joined.borrow()).offset((6) as isize).read()) as i32) == (('b' as u8) as i32))); + let arr: Value> = Rc::new(RefCell::new(Box::<[u8]>::from(b"foobar\0".as_slice()))); + assert!((((*arr.borrow())[(0) as usize] as i32) == (('f' as u8) as i32))); + assert!((((*arr.borrow())[(3) as usize] as i32) == (('b' as u8) as i32))); + assert!((((*arr.borrow())[(5) as usize] as i32) == (('r' as u8) as i32))); + assert!((((*arr.borrow())[(6) as usize] as i32) == (('\0' as u8) as i32))); + let split_pieces: Value> = Rc::new(RefCell::new(Ptr::from_string_literal("abcdefghi"))); + assert!( + ((((*split_pieces.borrow()).offset((0) as isize).read()) as i32) == (('a' as u8) as i32)) + ); + assert!( + ((((*split_pieces.borrow()).offset((3) as isize).read()) as i32) == (('d' as u8) as i32)) + ); + assert!( + ((((*split_pieces.borrow()).offset((6) as isize).read()) as i32) == (('g' as u8) as i32)) + ); + assert!( + ((((*split_pieces.borrow()).offset((8) as isize).read()) as i32) == (('i' as u8) as i32)) + ); + assert!( + ((((*split_pieces.borrow()).offset((9) as isize).read()) as i32) == (('\0' as u8) as i32)) + ); + return 0; +} diff --git a/tests/unit/out/refcount/string_literals_concat_c.rs b/tests/unit/out/refcount/string_literals_concat_c.rs new file mode 100644 index 00000000..1e59083a --- /dev/null +++ b/tests/unit/out/refcount/string_literals_concat_c.rs @@ -0,0 +1,25 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let arr: Value> = Rc::new(RefCell::new(Box::<[u8]>::from(b"foobar\0".as_slice()))); + assert!((((*arr.borrow())[(0) as usize] as i32) == ('f' as i32))); + assert!((((*arr.borrow())[(3) as usize] as i32) == ('b' as i32))); + assert!((((*arr.borrow())[(5) as usize] as i32) == ('r' as i32))); + assert!((((*arr.borrow())[(6) as usize] as i32) == ('\0' as i32))); + let split_pieces: Value> = Rc::new(RefCell::new(Ptr::from_string_literal("abcdefghi"))); + assert!(((((*split_pieces.borrow()).offset((0) as isize).read()) as i32) == ('a' as i32))); + assert!(((((*split_pieces.borrow()).offset((3) as isize).read()) as i32) == ('d' as i32))); + assert!(((((*split_pieces.borrow()).offset((6) as isize).read()) as i32) == ('g' as i32))); + assert!(((((*split_pieces.borrow()).offset((8) as isize).read()) as i32) == ('i' as i32))); + assert!(((((*split_pieces.borrow()).offset((9) as isize).read()) as i32) == ('\0' as i32))); + return 0; +} diff --git a/tests/unit/out/refcount/string_literals_return.rs b/tests/unit/out/refcount/string_literals_return.rs new file mode 100644 index 00000000..506ba96c --- /dev/null +++ b/tests/unit/out/refcount/string_literals_return.rs @@ -0,0 +1,51 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn get_greeting_0() -> Ptr { + return Ptr::from_string_literal("hello"); +} +pub fn get_empty_1() -> Ptr { + return Ptr::from_string_literal(""); +} +pub fn get_branch_2(x: i32) -> Ptr { + let x: Value = Rc::new(RefCell::new(x)); + if ((*x.borrow()) > 0) { + return Ptr::from_string_literal("positive"); + } + return Ptr::from_string_literal("non-positive"); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let a: Value> = Rc::new(RefCell::new(({ get_greeting_0() }))); + assert!(((((*a.borrow()).offset((0) as isize).read()) as i32) == (('h' as u8) as i32))); + assert!(((((*a.borrow()).offset((4) as isize).read()) as i32) == (('o' as u8) as i32))); + assert!(((((*a.borrow()).offset((5) as isize).read()) as i32) == (('\0' as u8) as i32))); + let b: Value> = Rc::new(RefCell::new(({ get_empty_1() }))); + assert!(((((*b.borrow()).offset((0) as isize).read()) as i32) == (('\0' as u8) as i32))); + let c: Value> = Rc::new(RefCell::new( + ({ + let _x: i32 = 1; + get_branch_2(_x) + }), + )); + assert!(((((*c.borrow()).offset((0) as isize).read()) as i32) == (('p' as u8) as i32))); + assert!(((((*c.borrow()).offset((7) as isize).read()) as i32) == (('e' as u8) as i32))); + assert!(((((*c.borrow()).offset((8) as isize).read()) as i32) == (('\0' as u8) as i32))); + let d: Value> = Rc::new(RefCell::new( + ({ + let _x: i32 = -1_i32; + get_branch_2(_x) + }), + )); + assert!(((((*d.borrow()).offset((0) as isize).read()) as i32) == (('n' as u8) as i32))); + assert!(((((*d.borrow()).offset((11) as isize).read()) as i32) == (('e' as u8) as i32))); + assert!(((((*d.borrow()).offset((12) as isize).read()) as i32) == (('\0' as u8) as i32))); + return 0; +} diff --git a/tests/unit/out/refcount/string_literals_return_c.rs b/tests/unit/out/refcount/string_literals_return_c.rs new file mode 100644 index 00000000..809b731b --- /dev/null +++ b/tests/unit/out/refcount/string_literals_return_c.rs @@ -0,0 +1,51 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn get_greeting_0() -> Ptr { + return Ptr::from_string_literal("hello"); +} +pub fn get_empty_1() -> Ptr { + return Ptr::from_string_literal(""); +} +pub fn get_branch_2(x: i32) -> Ptr { + let x: Value = Rc::new(RefCell::new(x)); + if ((*x.borrow()) > 0) { + return Ptr::from_string_literal("positive"); + } + return Ptr::from_string_literal("non-positive"); +} +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let a: Value> = Rc::new(RefCell::new(({ get_greeting_0() }))); + assert!(((((*a.borrow()).offset((0) as isize).read()) as i32) == ('h' as i32))); + assert!(((((*a.borrow()).offset((4) as isize).read()) as i32) == ('o' as i32))); + assert!(((((*a.borrow()).offset((5) as isize).read()) as i32) == ('\0' as i32))); + let b: Value> = Rc::new(RefCell::new(({ get_empty_1() }))); + assert!(((((*b.borrow()).offset((0) as isize).read()) as i32) == ('\0' as i32))); + let c: Value> = Rc::new(RefCell::new( + ({ + let _x: i32 = 1; + get_branch_2(_x) + }), + )); + assert!(((((*c.borrow()).offset((0) as isize).read()) as i32) == ('p' as i32))); + assert!(((((*c.borrow()).offset((7) as isize).read()) as i32) == ('e' as i32))); + assert!(((((*c.borrow()).offset((8) as isize).read()) as i32) == ('\0' as i32))); + let d: Value> = Rc::new(RefCell::new( + ({ + let _x: i32 = -1_i32; + get_branch_2(_x) + }), + )); + assert!(((((*d.borrow()).offset((0) as isize).read()) as i32) == ('n' as i32))); + assert!(((((*d.borrow()).offset((11) as isize).read()) as i32) == ('e' as i32))); + assert!(((((*d.borrow()).offset((12) as isize).read()) as i32) == ('\0' as i32))); + return 0; +} diff --git a/tests/unit/out/refcount/string_literals_sized.rs b/tests/unit/out/refcount/string_literals_sized.rs new file mode 100644 index 00000000..95eba2bf --- /dev/null +++ b/tests/unit/out/refcount/string_literals_sized.rs @@ -0,0 +1,39 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let empty_buf : Value > = Rc::new(RefCell::new(Box::<[u8]>::from(b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0".as_slice()) )) ; + assert!((((*empty_buf.borrow())[(0) as usize] as i32) == (('\0' as u8) as i32))); + assert!((((*empty_buf.borrow())[(255) as usize] as i32) == (('\0' as u8) as i32))); + let prefix_buf: Value> = Rc::new(RefCell::new(Box::<[u8]>::from( + b"%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0".as_slice(), + ))); + assert!((((*prefix_buf.borrow())[(0) as usize] as i32) == (('%' as u8) as i32))); + assert!((((*prefix_buf.borrow())[(1) as usize] as i32) == (('\0' as u8) as i32))); + assert!((((*prefix_buf.borrow())[(31) as usize] as i32) == (('\0' as u8) as i32))); + let short_buf: Value> = Rc::new(RefCell::new(Box::<[u8]>::from( + b"hi\0\0\0\0\0\0\0\0\0\0\0\0\0\0".as_slice(), + ))); + assert!((((*short_buf.borrow())[(0) as usize] as i32) == (('h' as u8) as i32))); + assert!((((*short_buf.borrow())[(1) as usize] as i32) == (('i' as u8) as i32))); + assert!((((*short_buf.borrow())[(2) as usize] as i32) == (('\0' as u8) as i32))); + assert!((((*short_buf.borrow())[(15) as usize] as i32) == (('\0' as u8) as i32))); + let exact_buf: Value> = + Rc::new(RefCell::new(Box::<[u8]>::from(b"hello\0".as_slice()))); + assert!((((*exact_buf.borrow())[(0) as usize] as i32) == (('h' as u8) as i32))); + assert!((((*exact_buf.borrow())[(4) as usize] as i32) == (('o' as u8) as i32))); + assert!((((*exact_buf.borrow())[(5) as usize] as i32) == (('\0' as u8) as i32))); + assert!((::std::mem::size_of::<[u8; 6]>() as u64 == 6_u64)); + assert!(((::std::mem::size_of::<[u8; 6]>() as u64 as u64).wrapping_sub(1_u64) == 5_u64)); + assert!((::std::mem::size_of::<[u8; 1]>() as u64 == 1_u64)); + assert!(((::std::mem::size_of::<[u8; 16]>() as u64 as u64).wrapping_sub(1_u64) == 15_u64)); + return 0; +} diff --git a/tests/unit/out/refcount/string_literals_sized_c.rs b/tests/unit/out/refcount/string_literals_sized_c.rs new file mode 100644 index 00000000..2225d188 --- /dev/null +++ b/tests/unit/out/refcount/string_literals_sized_c.rs @@ -0,0 +1,39 @@ +extern crate libcc2rs; +use libcc2rs::*; +use std::cell::RefCell; +use std::collections::BTreeMap; +use std::io::prelude::*; +use std::io::{Read, Seek, Write}; +use std::os::fd::AsFd; +use std::rc::{Rc, Weak}; +pub fn main() { + std::process::exit(main_0()); +} +fn main_0() -> i32 { + let empty_buf : Value > = Rc::new(RefCell::new(Box::<[u8]>::from(b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0".as_slice()) )) ; + assert!((((*empty_buf.borrow())[(0) as usize] as i32) == ('\0' as i32))); + assert!((((*empty_buf.borrow())[(255) as usize] as i32) == ('\0' as i32))); + let prefix_buf: Value> = Rc::new(RefCell::new(Box::<[u8]>::from( + b"%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0".as_slice(), + ))); + assert!((((*prefix_buf.borrow())[(0) as usize] as i32) == ('%' as i32))); + assert!((((*prefix_buf.borrow())[(1) as usize] as i32) == ('\0' as i32))); + assert!((((*prefix_buf.borrow())[(31) as usize] as i32) == ('\0' as i32))); + let short_buf: Value> = Rc::new(RefCell::new(Box::<[u8]>::from( + b"hi\0\0\0\0\0\0\0\0\0\0\0\0\0\0".as_slice(), + ))); + assert!((((*short_buf.borrow())[(0) as usize] as i32) == ('h' as i32))); + assert!((((*short_buf.borrow())[(1) as usize] as i32) == ('i' as i32))); + assert!((((*short_buf.borrow())[(2) as usize] as i32) == ('\0' as i32))); + assert!((((*short_buf.borrow())[(15) as usize] as i32) == ('\0' as i32))); + let exact_buf: Value> = + Rc::new(RefCell::new(Box::<[u8]>::from(b"hello\0".as_slice()))); + assert!((((*exact_buf.borrow())[(0) as usize] as i32) == ('h' as i32))); + assert!((((*exact_buf.borrow())[(4) as usize] as i32) == ('o' as i32))); + assert!((((*exact_buf.borrow())[(5) as usize] as i32) == ('\0' as i32))); + assert!((::std::mem::size_of::<[u8; 6]>() as u64 == 6_u64)); + assert!(((::std::mem::size_of::<[u8; 6]>() as u64 as u64).wrapping_sub(1_u64) == 5_u64)); + assert!((::std::mem::size_of::<[u8; 1]>() as u64 == 1_u64)); + assert!(((::std::mem::size_of::<[u8; 16]>() as u64 as u64).wrapping_sub(1_u64) == 15_u64)); + return 0; +} diff --git a/tests/unit/out/unsafe/string_literals.rs b/tests/unit/out/unsafe/string_literals.rs index 7a349ef3..13e47da2 100644 --- a/tests/unit/out/unsafe/string_literals.rs +++ b/tests/unit/out/unsafe/string_literals.rs @@ -24,6 +24,10 @@ unsafe fn main_0() -> i32 { let mut immutable_string: *const u8 = b"hello\0".as_ptr(); let mut mutable_string_arr: [u8; 9] = *b"papanasi\0"; let immutable_string_arr: [u8; 9] = *b"papanasi\0"; + let mut mutable_empty: *mut u8 = b"\0".as_ptr().cast_mut(); + let mut immutable_empty: *const u8 = b"\0".as_ptr(); + let mut mutable_empty_arr: [u8; 1] = *b"\0"; + let immutable_empty_arr: [u8; 1] = *b"\0"; (unsafe { let _str: *mut u8 = b"world\0".as_ptr().cast_mut(); foo_mut_0(_str) @@ -56,5 +60,25 @@ unsafe fn main_0() -> i32 { let _str: *const u8 = immutable_string_arr.as_ptr(); foo_const_1(_str) }); + (unsafe { + let _str: *const u8 = b"\0".as_ptr(); + foo_const_1(_str) + }); + (unsafe { + let _str: *const u8 = mutable_empty.cast_const(); + foo_const_1(_str) + }); + (unsafe { + let _str: *const u8 = immutable_empty; + foo_const_1(_str) + }); + (unsafe { + let _str: *const u8 = mutable_empty_arr.as_mut_ptr().cast_const(); + foo_const_1(_str) + }); + (unsafe { + let _str: *const u8 = immutable_empty_arr.as_ptr(); + foo_const_1(_str) + }); return 0; } diff --git a/tests/unit/out/unsafe/string_literals_c.rs b/tests/unit/out/unsafe/string_literals_c.rs index 75c5cfb7..84ba6537 100644 --- a/tests/unit/out/unsafe/string_literals_c.rs +++ b/tests/unit/out/unsafe/string_literals_c.rs @@ -28,6 +28,10 @@ unsafe fn main_0() -> i32 { let mut immutable_string: *const u8 = b"hello\0".as_ptr().cast_mut().cast_const(); let mut mutable_string_arr: [u8; 9] = *b"papanasi\0"; let immutable_string_arr: [u8; 9] = *b"papanasi\0"; + let mut mutable_empty: *mut u8 = b"\0".as_ptr().cast_mut(); + let mut immutable_empty: *const u8 = b"\0".as_ptr().cast_mut().cast_const(); + let mut mutable_empty_arr: [u8; 1] = *b"\0"; + let immutable_empty_arr: [u8; 1] = *b"\0"; (unsafe { let _str: *mut u8 = b"world\0".as_ptr().cast_mut(); foo_mut_0(_str) @@ -60,5 +64,25 @@ unsafe fn main_0() -> i32 { let _str: *const u8 = immutable_string_arr.as_ptr(); foo_const_1(_str) }); + (unsafe { + let _str: *const u8 = b"\0".as_ptr().cast_mut().cast_const(); + foo_const_1(_str) + }); + (unsafe { + let _str: *const u8 = mutable_empty.cast_const(); + foo_const_1(_str) + }); + (unsafe { + let _str: *const u8 = immutable_empty; + foo_const_1(_str) + }); + (unsafe { + let _str: *const u8 = mutable_empty_arr.as_mut_ptr().cast_const(); + foo_const_1(_str) + }); + (unsafe { + let _str: *const u8 = immutable_empty_arr.as_ptr(); + foo_const_1(_str) + }); return 0; } diff --git a/tests/unit/out/unsafe/string_literals_concat.rs b/tests/unit/out/unsafe/string_literals_concat.rs new file mode 100644 index 00000000..ce35fafb --- /dev/null +++ b/tests/unit/out/unsafe/string_literals_concat.rs @@ -0,0 +1,31 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut joined: *const u8 = b"alpha\nbeta\ngamma\n\0".as_ptr(); + assert!((((*joined.offset((0) as isize)) as i32) == (('a' as u8) as i32))); + assert!((((*joined.offset((5) as isize)) as i32) == (('\n' as u8) as i32))); + assert!((((*joined.offset((6) as isize)) as i32) == (('b' as u8) as i32))); + let mut arr: [u8; 7] = *b"foobar\0"; + assert!(((arr[(0) as usize] as i32) == (('f' as u8) as i32))); + assert!(((arr[(3) as usize] as i32) == (('b' as u8) as i32))); + assert!(((arr[(5) as usize] as i32) == (('r' as u8) as i32))); + assert!(((arr[(6) as usize] as i32) == (('\0' as u8) as i32))); + let mut split_pieces: *const u8 = b"abcdefghi\0".as_ptr(); + assert!((((*split_pieces.offset((0) as isize)) as i32) == (('a' as u8) as i32))); + assert!((((*split_pieces.offset((3) as isize)) as i32) == (('d' as u8) as i32))); + assert!((((*split_pieces.offset((6) as isize)) as i32) == (('g' as u8) as i32))); + assert!((((*split_pieces.offset((8) as isize)) as i32) == (('i' as u8) as i32))); + assert!((((*split_pieces.offset((9) as isize)) as i32) == (('\0' as u8) as i32))); + return 0; +} diff --git a/tests/unit/out/unsafe/string_literals_concat_c.rs b/tests/unit/out/unsafe/string_literals_concat_c.rs new file mode 100644 index 00000000..e12cb8c1 --- /dev/null +++ b/tests/unit/out/unsafe/string_literals_concat_c.rs @@ -0,0 +1,27 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut arr: [u8; 7] = *b"foobar\0"; + assert!(((arr[(0) as usize] as i32) == ('f' as i32))); + assert!(((arr[(3) as usize] as i32) == ('b' as i32))); + assert!(((arr[(5) as usize] as i32) == ('r' as i32))); + assert!(((arr[(6) as usize] as i32) == ('\0' as i32))); + let mut split_pieces: *const u8 = b"abcdefghi\0".as_ptr().cast_mut().cast_const(); + assert!((((*split_pieces.offset((0) as isize)) as i32) == ('a' as i32))); + assert!((((*split_pieces.offset((3) as isize)) as i32) == ('d' as i32))); + assert!((((*split_pieces.offset((6) as isize)) as i32) == ('g' as i32))); + assert!((((*split_pieces.offset((8) as isize)) as i32) == ('i' as i32))); + assert!((((*split_pieces.offset((9) as isize)) as i32) == ('\0' as i32))); + return 0; +} diff --git a/tests/unit/out/unsafe/string_literals_return.rs b/tests/unit/out/unsafe/string_literals_return.rs new file mode 100644 index 00000000..06d1d65e --- /dev/null +++ b/tests/unit/out/unsafe/string_literals_return.rs @@ -0,0 +1,48 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn get_greeting_0() -> *const u8 { + return b"hello\0".as_ptr(); +} +pub unsafe fn get_empty_1() -> *const u8 { + return b"\0".as_ptr(); +} +pub unsafe fn get_branch_2(mut x: i32) -> *const u8 { + if ((x) > (0)) { + return b"positive\0".as_ptr(); + } + return b"non-positive\0".as_ptr(); +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut a: *const u8 = (unsafe { get_greeting_0() }); + assert!((((*a.offset((0) as isize)) as i32) == (('h' as u8) as i32))); + assert!((((*a.offset((4) as isize)) as i32) == (('o' as u8) as i32))); + assert!((((*a.offset((5) as isize)) as i32) == (('\0' as u8) as i32))); + let mut b: *const u8 = (unsafe { get_empty_1() }); + assert!((((*b.offset((0) as isize)) as i32) == (('\0' as u8) as i32))); + let mut c: *const u8 = (unsafe { + let _x: i32 = 1; + get_branch_2(_x) + }); + assert!((((*c.offset((0) as isize)) as i32) == (('p' as u8) as i32))); + assert!((((*c.offset((7) as isize)) as i32) == (('e' as u8) as i32))); + assert!((((*c.offset((8) as isize)) as i32) == (('\0' as u8) as i32))); + let mut d: *const u8 = (unsafe { + let _x: i32 = -1_i32; + get_branch_2(_x) + }); + assert!((((*d.offset((0) as isize)) as i32) == (('n' as u8) as i32))); + assert!((((*d.offset((11) as isize)) as i32) == (('e' as u8) as i32))); + assert!((((*d.offset((12) as isize)) as i32) == (('\0' as u8) as i32))); + return 0; +} diff --git a/tests/unit/out/unsafe/string_literals_return_c.rs b/tests/unit/out/unsafe/string_literals_return_c.rs new file mode 100644 index 00000000..82cded37 --- /dev/null +++ b/tests/unit/out/unsafe/string_literals_return_c.rs @@ -0,0 +1,48 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub unsafe fn get_greeting_0() -> *const u8 { + return b"hello\0".as_ptr().cast_mut().cast_const(); +} +pub unsafe fn get_empty_1() -> *const u8 { + return b"\0".as_ptr().cast_mut().cast_const(); +} +pub unsafe fn get_branch_2(mut x: i32) -> *const u8 { + if ((x) > (0)) { + return b"positive\0".as_ptr().cast_mut().cast_const(); + } + return b"non-positive\0".as_ptr().cast_mut().cast_const(); +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut a: *const u8 = (unsafe { get_greeting_0() }); + assert!((((*a.offset((0) as isize)) as i32) == ('h' as i32))); + assert!((((*a.offset((4) as isize)) as i32) == ('o' as i32))); + assert!((((*a.offset((5) as isize)) as i32) == ('\0' as i32))); + let mut b: *const u8 = (unsafe { get_empty_1() }); + assert!((((*b.offset((0) as isize)) as i32) == ('\0' as i32))); + let mut c: *const u8 = (unsafe { + let _x: i32 = 1; + get_branch_2(_x) + }); + assert!((((*c.offset((0) as isize)) as i32) == ('p' as i32))); + assert!((((*c.offset((7) as isize)) as i32) == ('e' as i32))); + assert!((((*c.offset((8) as isize)) as i32) == ('\0' as i32))); + let mut d: *const u8 = (unsafe { + let _x: i32 = -1_i32; + get_branch_2(_x) + }); + assert!((((*d.offset((0) as isize)) as i32) == ('n' as i32))); + assert!((((*d.offset((11) as isize)) as i32) == ('e' as i32))); + assert!((((*d.offset((12) as isize)) as i32) == ('\0' as i32))); + return 0; +} diff --git a/tests/unit/out/unsafe/string_literals_sized.rs b/tests/unit/out/unsafe/string_literals_sized.rs new file mode 100644 index 00000000..0107e29b --- /dev/null +++ b/tests/unit/out/unsafe/string_literals_sized.rs @@ -0,0 +1,37 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut empty_buf : [ u8 ; 256] = * b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ; + assert!(((empty_buf[(0) as usize] as i32) == (('\0' as u8) as i32))); + assert!(((empty_buf[(255) as usize] as i32) == (('\0' as u8) as i32))); + let mut prefix_buf: [u8; 32] = + *b"%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + assert!(((prefix_buf[(0) as usize] as i32) == (('%' as u8) as i32))); + assert!(((prefix_buf[(1) as usize] as i32) == (('\0' as u8) as i32))); + assert!(((prefix_buf[(31) as usize] as i32) == (('\0' as u8) as i32))); + let mut short_buf: [u8; 16] = *b"hi\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + assert!(((short_buf[(0) as usize] as i32) == (('h' as u8) as i32))); + assert!(((short_buf[(1) as usize] as i32) == (('i' as u8) as i32))); + assert!(((short_buf[(2) as usize] as i32) == (('\0' as u8) as i32))); + assert!(((short_buf[(15) as usize] as i32) == (('\0' as u8) as i32))); + let mut exact_buf: [u8; 6] = *b"hello\0"; + assert!(((exact_buf[(0) as usize] as i32) == (('h' as u8) as i32))); + assert!(((exact_buf[(4) as usize] as i32) == (('o' as u8) as i32))); + assert!(((exact_buf[(5) as usize] as i32) == (('\0' as u8) as i32))); + assert!(((::std::mem::size_of::<[u8; 6]>() as u64) == (6_u64))); + assert!((((::std::mem::size_of::<[u8; 6]>() as u64 as u64).wrapping_sub(1_u64)) == (5_u64))); + assert!(((::std::mem::size_of::<[u8; 1]>() as u64) == (1_u64))); + assert!((((::std::mem::size_of::<[u8; 16]>() as u64 as u64).wrapping_sub(1_u64)) == (15_u64))); + return 0; +} diff --git a/tests/unit/out/unsafe/string_literals_sized_c.rs b/tests/unit/out/unsafe/string_literals_sized_c.rs new file mode 100644 index 00000000..32ee56c8 --- /dev/null +++ b/tests/unit/out/unsafe/string_literals_sized_c.rs @@ -0,0 +1,37 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + let mut empty_buf : [ u8 ; 256] = * b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ; + assert!(((empty_buf[(0) as usize] as i32) == ('\0' as i32))); + assert!(((empty_buf[(255) as usize] as i32) == ('\0' as i32))); + let mut prefix_buf: [u8; 32] = + *b"%\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + assert!(((prefix_buf[(0) as usize] as i32) == ('%' as i32))); + assert!(((prefix_buf[(1) as usize] as i32) == ('\0' as i32))); + assert!(((prefix_buf[(31) as usize] as i32) == ('\0' as i32))); + let mut short_buf: [u8; 16] = *b"hi\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; + assert!(((short_buf[(0) as usize] as i32) == ('h' as i32))); + assert!(((short_buf[(1) as usize] as i32) == ('i' as i32))); + assert!(((short_buf[(2) as usize] as i32) == ('\0' as i32))); + assert!(((short_buf[(15) as usize] as i32) == ('\0' as i32))); + let mut exact_buf: [u8; 6] = *b"hello\0"; + assert!(((exact_buf[(0) as usize] as i32) == ('h' as i32))); + assert!(((exact_buf[(4) as usize] as i32) == ('o' as i32))); + assert!(((exact_buf[(5) as usize] as i32) == ('\0' as i32))); + assert!(((::std::mem::size_of::<[u8; 6]>() as u64) == (6_u64))); + assert!((((::std::mem::size_of::<[u8; 6]>() as u64 as u64).wrapping_sub(1_u64)) == (5_u64))); + assert!(((::std::mem::size_of::<[u8; 1]>() as u64) == (1_u64))); + assert!((((::std::mem::size_of::<[u8; 16]>() as u64 as u64).wrapping_sub(1_u64)) == (15_u64))); + return 0; +} From e64540df564b126098fcdc661d23591ab4dc15b6 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 29 Apr 2026 13:46:09 +0100 Subject: [PATCH 17/23] Add successful union test --- .../out/unsafe/union_tagged_struct_arms.rs | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 tests/unit/out/unsafe/union_tagged_struct_arms.rs diff --git a/tests/unit/out/unsafe/union_tagged_struct_arms.rs b/tests/unit/out/unsafe/union_tagged_struct_arms.rs new file mode 100644 index 00000000..f19dbaf1 --- /dev/null +++ b/tests/unit/out/unsafe/union_tagged_struct_arms.rs @@ -0,0 +1,90 @@ +extern crate libc; +use libc::*; +extern crate libcc2rs; +use libcc2rs::*; +use std::collections::BTreeMap; +use std::io::{Read, Seek, Write}; +use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; +use std::rc::Rc; +#[derive(Clone, Copy, PartialEq, Debug, Default)] +enum Choice { + #[default] + C_LIST = 1, + C_LETTERS = 2, + C_INTEGERS = 3, +} +#[derive(Copy, Clone, Default)] +pub struct Branch_anon_0_anon_0 { + pub items: *mut *mut u8, + pub count: i64, + pub cursor: i64, +} +#[derive(Copy, Clone, Default)] +pub struct Branch_anon_0_anon_1 { + pub lo: i32, + pub hi: i32, + pub curr: i32, + pub step: u8, +} +#[derive(Copy, Clone, Default)] +pub struct Branch_anon_0_anon_2 { + pub lo: i64, + pub hi: i64, + pub curr: i64, + pub step: i64, + pub width: i32, +} +#[derive(Copy, Clone, Default)] +pub struct Branch_anon_0 { + pub list: Branch_anon_0_anon_0, + pub letters: Branch_anon_0_anon_1, + pub integers: Branch_anon_0_anon_2, +} +#[derive(Copy, Clone, Default)] +pub struct Branch { + pub choice: Choice, + pub index: i32, + pub v: Branch_anon_0, +} +pub fn main() { + unsafe { + std::process::exit(main_0() as i32); + } +} +unsafe fn main_0() -> i32 { + static mut items: [*mut u8; 3] = [ + b"a\0".as_ptr().cast_mut(), + b"b\0".as_ptr().cast_mut(), + b"c\0".as_ptr().cast_mut(), + ];; + let mut p_list: Branch = ::default(); + p_list.choice = (Choice::C_LIST as Choice); + p_list.index = 0; + p_list.v.list.items = items.as_mut_ptr(); + p_list.v.list.count = 3_i64; + p_list.v.list.cursor = 1_i64; + assert!(((p_list.v.list.count) == (3_i64))); + assert!( + (((*(*p_list.v.list.items.offset((1) as isize)).offset((0) as isize)) as i32) + == ('b' as i32)) + ); + let mut p_letters: Branch = ::default(); + p_letters.choice = (Choice::C_LETTERS as Choice); + p_letters.index = 1; + p_letters.v.letters.lo = ('a' as i32); + p_letters.v.letters.hi = ('z' as i32); + p_letters.v.letters.curr = ('m' as i32); + p_letters.v.letters.step = 1_u8; + assert!((((p_letters.v.letters.hi) - (p_letters.v.letters.lo)) == (25))); + let mut p_integers: Branch = ::default(); + p_integers.choice = (Choice::C_INTEGERS as Choice); + p_integers.index = 2; + p_integers.v.integers.lo = 1_i64; + p_integers.v.integers.hi = 100_i64; + p_integers.v.integers.curr = 1_i64; + p_integers.v.integers.step = 1_i64; + p_integers.v.integers.width = 3; + assert!(((p_integers.v.integers.hi) == (100_i64))); + assert!(((p_integers.v.integers.width) == (3))); + return 0; +} From fab49f09adb99243b73a452719a6f1b439a12f71 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 29 Apr 2026 13:56:07 +0100 Subject: [PATCH 18/23] Unions don't compile in refcount --- tests/unit/union_tagged_struct_arms.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/union_tagged_struct_arms.c b/tests/unit/union_tagged_struct_arms.c index de0c887f..f5b90e18 100644 --- a/tests/unit/union_tagged_struct_arms.c +++ b/tests/unit/union_tagged_struct_arms.c @@ -1,3 +1,4 @@ +// no-compile: refcount #include #include From b4a84cb4a930a9ed02bc428257a3b60bbf19753e Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 29 Apr 2026 13:56:40 +0100 Subject: [PATCH 19/23] Post-rebase test updates --- tests/unit/out/unsafe/huffman.rs | 2 ++ tests/unit/out/unsafe/polymorphism.rs | 2 ++ tests/unit/out/unsafe/union_tagged_many_arms.rs | 11 +++++++++-- tests/unit/out/unsafe/union_tagged_struct_arms.rs | 14 ++++++++++++-- tests/unit/out/unsafe/unique_ptr_const_deref.rs | 1 + tests/unit/out/unsafe/va_arg_struct_ctx.rs | 1 + 6 files changed, 27 insertions(+), 4 deletions(-) diff --git a/tests/unit/out/unsafe/huffman.rs b/tests/unit/out/unsafe/huffman.rs index ef9ab27d..868c697e 100644 --- a/tests/unit/out/unsafe/huffman.rs +++ b/tests/unit/out/unsafe/huffman.rs @@ -6,6 +6,7 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; +#[repr(C)] #[derive(Copy, Clone, Default)] pub struct MinHeapNode { pub data: u8, @@ -40,6 +41,7 @@ pub unsafe fn Swap_0(a: *mut MinHeapNode, b: *mut MinHeapNode) { }) .clone(); } +#[repr(C)] #[derive(Default)] pub struct MinHeap { pub size: i32, diff --git a/tests/unit/out/unsafe/polymorphism.rs b/tests/unit/out/unsafe/polymorphism.rs index 295958ac..2f98f685 100644 --- a/tests/unit/out/unsafe/polymorphism.rs +++ b/tests/unit/out/unsafe/polymorphism.rs @@ -9,6 +9,7 @@ use std::rc::Rc; pub unsafe trait Animal { unsafe fn bark(&self) -> bool; } +#[repr(C)] #[derive(Copy, Clone, Default)] pub struct Dog {} unsafe impl Animal for Dog { @@ -16,6 +17,7 @@ unsafe impl Animal for Dog { return true; } } +#[repr(C)] #[derive(Copy, Clone, Default)] pub struct Cat {} impl Cat { diff --git a/tests/unit/out/unsafe/union_tagged_many_arms.rs b/tests/unit/out/unsafe/union_tagged_many_arms.rs index f3f54dde..8429c230 100644 --- a/tests/unit/out/unsafe/union_tagged_many_arms.rs +++ b/tests/unit/out/unsafe/union_tagged_many_arms.rs @@ -15,14 +15,21 @@ enum Tag { T_FLOAT = 3, T_REF = 4, } -#[derive(Copy, Clone, Default)] -pub struct Slot_anon_0 { +#[repr(C)] +#[derive(Copy, Clone)] +pub union Slot_anon_0 { pub text: *const u8, pub handle: *mut ::libc::c_void, pub signed_n: i64, pub unsigned_n: u64, pub f: f64, } +impl Default for Slot_anon_0 { + fn default() -> Self { + unsafe { std::mem::zeroed() } + } +} +#[repr(C)] #[derive(Copy, Clone, Default)] pub struct Slot { pub tag: Tag, diff --git a/tests/unit/out/unsafe/union_tagged_struct_arms.rs b/tests/unit/out/unsafe/union_tagged_struct_arms.rs index f19dbaf1..32c74dd6 100644 --- a/tests/unit/out/unsafe/union_tagged_struct_arms.rs +++ b/tests/unit/out/unsafe/union_tagged_struct_arms.rs @@ -13,12 +13,14 @@ enum Choice { C_LETTERS = 2, C_INTEGERS = 3, } +#[repr(C)] #[derive(Copy, Clone, Default)] pub struct Branch_anon_0_anon_0 { pub items: *mut *mut u8, pub count: i64, pub cursor: i64, } +#[repr(C)] #[derive(Copy, Clone, Default)] pub struct Branch_anon_0_anon_1 { pub lo: i32, @@ -26,6 +28,7 @@ pub struct Branch_anon_0_anon_1 { pub curr: i32, pub step: u8, } +#[repr(C)] #[derive(Copy, Clone, Default)] pub struct Branch_anon_0_anon_2 { pub lo: i64, @@ -34,12 +37,19 @@ pub struct Branch_anon_0_anon_2 { pub step: i64, pub width: i32, } -#[derive(Copy, Clone, Default)] -pub struct Branch_anon_0 { +#[repr(C)] +#[derive(Copy, Clone)] +pub union Branch_anon_0 { pub list: Branch_anon_0_anon_0, pub letters: Branch_anon_0_anon_1, pub integers: Branch_anon_0_anon_2, } +impl Default for Branch_anon_0 { + fn default() -> Self { + unsafe { std::mem::zeroed() } + } +} +#[repr(C)] #[derive(Copy, Clone, Default)] pub struct Branch { pub choice: Choice, diff --git a/tests/unit/out/unsafe/unique_ptr_const_deref.rs b/tests/unit/out/unsafe/unique_ptr_const_deref.rs index cfe33ce0..edf42cc6 100644 --- a/tests/unit/out/unsafe/unique_ptr_const_deref.rs +++ b/tests/unit/out/unsafe/unique_ptr_const_deref.rs @@ -6,6 +6,7 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; +#[repr(C)] #[derive(Default)] pub struct Holder { pub val: Option>, diff --git a/tests/unit/out/unsafe/va_arg_struct_ctx.rs b/tests/unit/out/unsafe/va_arg_struct_ctx.rs index bff8f3db..c99b3943 100644 --- a/tests/unit/out/unsafe/va_arg_struct_ctx.rs +++ b/tests/unit/out/unsafe/va_arg_struct_ctx.rs @@ -6,6 +6,7 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; +#[repr(C)] #[derive(Copy, Clone, Default)] pub struct context { pub verbose: i32, From ad7e8eae818d958a513ea4ea70689bbcd7b0366a Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 29 Apr 2026 13:57:00 +0100 Subject: [PATCH 20/23] clang-format --- tests/unit/string_literals_concat.cpp | 7 +++++-- tests/unit/string_literals_concat_c.c | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/unit/string_literals_concat.cpp b/tests/unit/string_literals_concat.cpp index d717359c..3556c3c2 100644 --- a/tests/unit/string_literals_concat.cpp +++ b/tests/unit/string_literals_concat.cpp @@ -8,13 +8,16 @@ int main() { assert(joined[5] == '\n'); assert(joined[6] == 'b'); - char arr[] = "foo" "bar"; + char arr[] = "foo" + "bar"; assert(arr[0] == 'f'); assert(arr[3] == 'b'); assert(arr[5] == 'r'); assert(arr[6] == '\0'); - const char *split_pieces = "abc" "def" "ghi"; + const char *split_pieces = "abc" + "def" + "ghi"; assert(split_pieces[0] == 'a'); assert(split_pieces[3] == 'd'); assert(split_pieces[6] == 'g'); diff --git a/tests/unit/string_literals_concat_c.c b/tests/unit/string_literals_concat_c.c index 1382482b..37159db3 100644 --- a/tests/unit/string_literals_concat_c.c +++ b/tests/unit/string_literals_concat_c.c @@ -1,13 +1,16 @@ #include int main(void) { - char arr[] = "foo" "bar"; + char arr[] = "foo" + "bar"; assert(arr[0] == 'f'); assert(arr[3] == 'b'); assert(arr[5] == 'r'); assert(arr[6] == '\0'); - const char *split_pieces = "abc" "def" "ghi"; + const char *split_pieces = "abc" + "def" + "ghi"; assert(split_pieces[0] == 'a'); assert(split_pieces[3] == 'd'); assert(split_pieces[6] == 'g'); From 28fa3ecdf4b20b61749a89e2ae1047acd3ee9aee Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 29 Apr 2026 19:28:58 +0100 Subject: [PATCH 21/23] Delete tests parts containing mutable char ptr into string literals --- tests/unit/out/refcount/string_literals.rs | 31 ---------------------- tests/unit/out/unsafe/string_literals.rs | 31 ---------------------- tests/unit/string_literals.cpp | 9 ------- 3 files changed, 71 deletions(-) diff --git a/tests/unit/out/refcount/string_literals.rs b/tests/unit/out/refcount/string_literals.rs index ba34a5e4..fd3a5b0a 100644 --- a/tests/unit/out/refcount/string_literals.rs +++ b/tests/unit/out/refcount/string_literals.rs @@ -16,36 +16,21 @@ pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - let mutable_strings: Value]>> = Rc::new(RefCell::new(Box::new([ - Ptr::from_string_literal("a"), - Ptr::from_string_literal("b"), - Ptr::from_string_literal("c"), - ]))); let immutable_strings: Value]>> = Rc::new(RefCell::new(Box::new([ Ptr::from_string_literal("a"), Ptr::from_string_literal("b"), Ptr::from_string_literal("c"), ]))); - let mutable_string: Value> = Rc::new(RefCell::new(Ptr::from_string_literal("hello"))); let immutable_string: Value> = Rc::new(RefCell::new(Ptr::from_string_literal("hello"))); let mutable_string_arr: Value> = Rc::new(RefCell::new(Box::<[u8]>::from(b"papanasi\0".as_slice()))); let immutable_string_arr: Value> = Rc::new(RefCell::new(Box::<[u8]>::from(b"papanasi\0".as_slice()))); - let mutable_empty: Value> = Rc::new(RefCell::new(Ptr::from_string_literal(""))); let immutable_empty: Value> = Rc::new(RefCell::new(Ptr::from_string_literal(""))); let mutable_empty_arr: Value> = Rc::new(RefCell::new(Box::<[u8]>::from(b"\0".as_slice()))); let immutable_empty_arr: Value> = Rc::new(RefCell::new(Box::<[u8]>::from(b"\0".as_slice()))); - ({ - let _str: Ptr = Ptr::from_string_literal("world"); - foo_mut_0(_str) - }); - ({ - let _str: Ptr = (*mutable_string.borrow()).clone(); - foo_mut_0(_str) - }); ({ let _str: Ptr = (mutable_string_arr.as_pointer() as Ptr); foo_mut_0(_str) @@ -54,18 +39,10 @@ fn main_0() -> i32 { let _str: Ptr = Ptr::from_string_literal("world"); foo_const_1(_str) }); - ({ - let _str: Ptr = (*mutable_string.borrow()).clone(); - foo_const_1(_str) - }); ({ let _str: Ptr = (*immutable_string.borrow()).clone(); foo_const_1(_str) }); - ({ - let _str: Ptr = (mutable_string_arr.as_pointer() as Ptr); - foo_const_1(_str) - }); ({ let _str: Ptr = (immutable_string_arr.as_pointer() as Ptr); foo_const_1(_str) @@ -74,18 +51,10 @@ fn main_0() -> i32 { let _str: Ptr = Ptr::from_string_literal(""); foo_const_1(_str) }); - ({ - let _str: Ptr = (*mutable_empty.borrow()).clone(); - foo_const_1(_str) - }); ({ let _str: Ptr = (*immutable_empty.borrow()).clone(); foo_const_1(_str) }); - ({ - let _str: Ptr = (mutable_empty_arr.as_pointer() as Ptr); - foo_const_1(_str) - }); ({ let _str: Ptr = (immutable_empty_arr.as_pointer() as Ptr); foo_const_1(_str) diff --git a/tests/unit/out/unsafe/string_literals.rs b/tests/unit/out/unsafe/string_literals.rs index 13e47da2..b7f66d7c 100644 --- a/tests/unit/out/unsafe/string_literals.rs +++ b/tests/unit/out/unsafe/string_literals.rs @@ -14,28 +14,13 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut mutable_strings: [*mut u8; 3] = [ - b"a\0".as_ptr().cast_mut(), - b"b\0".as_ptr().cast_mut(), - b"c\0".as_ptr().cast_mut(), - ]; let mut immutable_strings: [*const u8; 3] = [b"a\0".as_ptr(), b"b\0".as_ptr(), b"c\0".as_ptr()]; - let mut mutable_string: *mut u8 = b"hello\0".as_ptr().cast_mut(); let mut immutable_string: *const u8 = b"hello\0".as_ptr(); let mut mutable_string_arr: [u8; 9] = *b"papanasi\0"; let immutable_string_arr: [u8; 9] = *b"papanasi\0"; - let mut mutable_empty: *mut u8 = b"\0".as_ptr().cast_mut(); let mut immutable_empty: *const u8 = b"\0".as_ptr(); let mut mutable_empty_arr: [u8; 1] = *b"\0"; let immutable_empty_arr: [u8; 1] = *b"\0"; - (unsafe { - let _str: *mut u8 = b"world\0".as_ptr().cast_mut(); - foo_mut_0(_str) - }); - (unsafe { - let _str: *mut u8 = mutable_string; - foo_mut_0(_str) - }); (unsafe { let _str: *mut u8 = mutable_string_arr.as_mut_ptr(); foo_mut_0(_str) @@ -44,18 +29,10 @@ unsafe fn main_0() -> i32 { let _str: *const u8 = b"world\0".as_ptr(); foo_const_1(_str) }); - (unsafe { - let _str: *const u8 = mutable_string.cast_const(); - foo_const_1(_str) - }); (unsafe { let _str: *const u8 = immutable_string; foo_const_1(_str) }); - (unsafe { - let _str: *const u8 = mutable_string_arr.as_mut_ptr().cast_const(); - foo_const_1(_str) - }); (unsafe { let _str: *const u8 = immutable_string_arr.as_ptr(); foo_const_1(_str) @@ -64,18 +41,10 @@ unsafe fn main_0() -> i32 { let _str: *const u8 = b"\0".as_ptr(); foo_const_1(_str) }); - (unsafe { - let _str: *const u8 = mutable_empty.cast_const(); - foo_const_1(_str) - }); (unsafe { let _str: *const u8 = immutable_empty; foo_const_1(_str) }); - (unsafe { - let _str: *const u8 = mutable_empty_arr.as_mut_ptr().cast_const(); - foo_const_1(_str) - }); (unsafe { let _str: *const u8 = immutable_empty_arr.as_ptr(); foo_const_1(_str) diff --git a/tests/unit/string_literals.cpp b/tests/unit/string_literals.cpp index d72fcbbf..33baffeb 100644 --- a/tests/unit/string_literals.cpp +++ b/tests/unit/string_literals.cpp @@ -2,34 +2,25 @@ void foo_mut(char *str) {} void foo_const(const char *str) {} int main() { - char *mutable_strings[] = {"a", "b", "c"}; const char *immutable_strings[] = {"a", "b", "c"}; - char *mutable_string = "hello"; const char *immutable_string = "hello"; char mutable_string_arr[] = "papanasi"; const char immutable_string_arr[] = "papanasi"; - char *mutable_empty = ""; const char *immutable_empty = ""; char mutable_empty_arr[] = ""; const char immutable_empty_arr[] = ""; - foo_mut("world"); - foo_mut(mutable_string); foo_mut(mutable_string_arr); foo_const("world"); - foo_const(mutable_string); foo_const(immutable_string); - foo_const(mutable_string_arr); foo_const(immutable_string_arr); foo_const(""); - foo_const(mutable_empty); foo_const(immutable_empty); - foo_const(mutable_empty_arr); foo_const(immutable_empty_arr); return 0; } From cf75ab6df4dfe136a13a61b1ed359536cebbf7e4 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 29 Apr 2026 19:34:28 +0100 Subject: [PATCH 22/23] Emit array full of 0 on empty string --- cpp2rust/converter/converter.cpp | 15 ++++++++++----- cpp2rust/converter/models/converter_refcount.cpp | 10 +++++++--- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 986a40dd..219e041a 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1707,15 +1707,20 @@ std::string Converter::GetEscapedStringLiteral(clang::Expr *expr, bool Converter::VisitStringLiteral(clang::StringLiteral *expr) { if (!curr_init_type_.empty() && curr_init_type_.top()->isArrayType()) { - StrCat(token::kStar); if (auto *arr_ty = ctx_.getAsConstantArrayType(curr_init_type_.top())) { - uint64_t target = arr_ty->getSize().getZExtValue(); - uint64_t pad = target > expr->getString().size() - ? target - expr->getString().size() + uint64_t arr_size = arr_ty->getSize().getZExtValue(); + if (expr->getString().empty()) { + StrCat(std::format("[0u8; {}]", arr_size)); + return false; + } + uint64_t pad = arr_size > expr->getString().size() + ? arr_size - expr->getString().size() : 0; - StrCat(std::format("b{}", GetEscapedStringLiteral(expr, pad))); + StrCat(token::kStar, + std::format("b{}", GetEscapedStringLiteral(expr, pad))); return false; } + StrCat(token::kStar); } StrCat(std::format("b{}", GetEscapedStringLiteral(expr, 1))); return false; diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index a1fd93a8..6f66b7fd 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -949,9 +949,13 @@ bool ConverterRefCount::VisitStringLiteral(clang::StringLiteral *expr) { if (!curr_init_type_.empty() && curr_init_type_.top()->isArrayType()) { uint64_t pad = 1; if (auto *arr_ty = ctx_.getAsConstantArrayType(curr_init_type_.top())) { - uint64_t target = arr_ty->getSize().getZExtValue(); - pad = target > expr->getString().size() - ? target - expr->getString().size() + uint64_t arr_size = arr_ty->getSize().getZExtValue(); + if (expr->getString().empty()) { + StrCat(std::format("vec![0u8; {}].into_boxed_slice()", arr_size)); + return false; + } + pad = arr_size > expr->getString().size() + ? arr_size - expr->getString().size() : 0; } StrCat(std::format("Box::<[u8]>::from(b{}.as_slice())", From 0fb3006af9f4ee184029a6dbea30fe78582faa26 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 29 Apr 2026 19:34:58 +0100 Subject: [PATCH 23/23] Update tests --- tests/unit/out/refcount/string_literals.rs | 4 ++-- tests/unit/out/refcount/string_literals_c.rs | 4 ++-- tests/unit/out/refcount/string_literals_sized.rs | 2 +- tests/unit/out/refcount/string_literals_sized_c.rs | 2 +- tests/unit/out/unsafe/string_literals.rs | 4 ++-- tests/unit/out/unsafe/string_literals_c.rs | 4 ++-- tests/unit/out/unsafe/string_literals_sized.rs | 2 +- tests/unit/out/unsafe/string_literals_sized_c.rs | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/unit/out/refcount/string_literals.rs b/tests/unit/out/refcount/string_literals.rs index fd3a5b0a..1cf23e03 100644 --- a/tests/unit/out/refcount/string_literals.rs +++ b/tests/unit/out/refcount/string_literals.rs @@ -28,9 +28,9 @@ fn main_0() -> i32 { Rc::new(RefCell::new(Box::<[u8]>::from(b"papanasi\0".as_slice()))); let immutable_empty: Value> = Rc::new(RefCell::new(Ptr::from_string_literal(""))); let mutable_empty_arr: Value> = - Rc::new(RefCell::new(Box::<[u8]>::from(b"\0".as_slice()))); + Rc::new(RefCell::new(vec![0u8; 1].into_boxed_slice())); let immutable_empty_arr: Value> = - Rc::new(RefCell::new(Box::<[u8]>::from(b"\0".as_slice()))); + Rc::new(RefCell::new(vec![0u8; 1].into_boxed_slice())); ({ let _str: Ptr = (mutable_string_arr.as_pointer() as Ptr); foo_mut_0(_str) diff --git a/tests/unit/out/refcount/string_literals_c.rs b/tests/unit/out/refcount/string_literals_c.rs index ba34a5e4..011caf2a 100644 --- a/tests/unit/out/refcount/string_literals_c.rs +++ b/tests/unit/out/refcount/string_literals_c.rs @@ -35,9 +35,9 @@ fn main_0() -> i32 { let mutable_empty: Value> = Rc::new(RefCell::new(Ptr::from_string_literal(""))); let immutable_empty: Value> = Rc::new(RefCell::new(Ptr::from_string_literal(""))); let mutable_empty_arr: Value> = - Rc::new(RefCell::new(Box::<[u8]>::from(b"\0".as_slice()))); + Rc::new(RefCell::new(vec![0u8; 1].into_boxed_slice())); let immutable_empty_arr: Value> = - Rc::new(RefCell::new(Box::<[u8]>::from(b"\0".as_slice()))); + Rc::new(RefCell::new(vec![0u8; 1].into_boxed_slice())); ({ let _str: Ptr = Ptr::from_string_literal("world"); foo_mut_0(_str) diff --git a/tests/unit/out/refcount/string_literals_sized.rs b/tests/unit/out/refcount/string_literals_sized.rs index 95eba2bf..9cb9f05c 100644 --- a/tests/unit/out/refcount/string_literals_sized.rs +++ b/tests/unit/out/refcount/string_literals_sized.rs @@ -10,7 +10,7 @@ pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - let empty_buf : Value > = Rc::new(RefCell::new(Box::<[u8]>::from(b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0".as_slice()) )) ; + let empty_buf: Value> = Rc::new(RefCell::new(vec![0u8; 256].into_boxed_slice())); assert!((((*empty_buf.borrow())[(0) as usize] as i32) == (('\0' as u8) as i32))); assert!((((*empty_buf.borrow())[(255) as usize] as i32) == (('\0' as u8) as i32))); let prefix_buf: Value> = Rc::new(RefCell::new(Box::<[u8]>::from( diff --git a/tests/unit/out/refcount/string_literals_sized_c.rs b/tests/unit/out/refcount/string_literals_sized_c.rs index 2225d188..fd1ce120 100644 --- a/tests/unit/out/refcount/string_literals_sized_c.rs +++ b/tests/unit/out/refcount/string_literals_sized_c.rs @@ -10,7 +10,7 @@ pub fn main() { std::process::exit(main_0()); } fn main_0() -> i32 { - let empty_buf : Value > = Rc::new(RefCell::new(Box::<[u8]>::from(b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0".as_slice()) )) ; + let empty_buf: Value> = Rc::new(RefCell::new(vec![0u8; 256].into_boxed_slice())); assert!((((*empty_buf.borrow())[(0) as usize] as i32) == ('\0' as i32))); assert!((((*empty_buf.borrow())[(255) as usize] as i32) == ('\0' as i32))); let prefix_buf: Value> = Rc::new(RefCell::new(Box::<[u8]>::from( diff --git a/tests/unit/out/unsafe/string_literals.rs b/tests/unit/out/unsafe/string_literals.rs index b7f66d7c..4ee5d517 100644 --- a/tests/unit/out/unsafe/string_literals.rs +++ b/tests/unit/out/unsafe/string_literals.rs @@ -19,8 +19,8 @@ unsafe fn main_0() -> i32 { let mut mutable_string_arr: [u8; 9] = *b"papanasi\0"; let immutable_string_arr: [u8; 9] = *b"papanasi\0"; let mut immutable_empty: *const u8 = b"\0".as_ptr(); - let mut mutable_empty_arr: [u8; 1] = *b"\0"; - let immutable_empty_arr: [u8; 1] = *b"\0"; + let mut mutable_empty_arr: [u8; 1] = [0u8; 1]; + let immutable_empty_arr: [u8; 1] = [0u8; 1]; (unsafe { let _str: *mut u8 = mutable_string_arr.as_mut_ptr(); foo_mut_0(_str) diff --git a/tests/unit/out/unsafe/string_literals_c.rs b/tests/unit/out/unsafe/string_literals_c.rs index 84ba6537..2f0d7ea7 100644 --- a/tests/unit/out/unsafe/string_literals_c.rs +++ b/tests/unit/out/unsafe/string_literals_c.rs @@ -30,8 +30,8 @@ unsafe fn main_0() -> i32 { let immutable_string_arr: [u8; 9] = *b"papanasi\0"; let mut mutable_empty: *mut u8 = b"\0".as_ptr().cast_mut(); let mut immutable_empty: *const u8 = b"\0".as_ptr().cast_mut().cast_const(); - let mut mutable_empty_arr: [u8; 1] = *b"\0"; - let immutable_empty_arr: [u8; 1] = *b"\0"; + let mut mutable_empty_arr: [u8; 1] = [0u8; 1]; + let immutable_empty_arr: [u8; 1] = [0u8; 1]; (unsafe { let _str: *mut u8 = b"world\0".as_ptr().cast_mut(); foo_mut_0(_str) diff --git a/tests/unit/out/unsafe/string_literals_sized.rs b/tests/unit/out/unsafe/string_literals_sized.rs index 0107e29b..4326ba49 100644 --- a/tests/unit/out/unsafe/string_literals_sized.rs +++ b/tests/unit/out/unsafe/string_literals_sized.rs @@ -12,7 +12,7 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut empty_buf : [ u8 ; 256] = * b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ; + let mut empty_buf: [u8; 256] = [0u8; 256]; assert!(((empty_buf[(0) as usize] as i32) == (('\0' as u8) as i32))); assert!(((empty_buf[(255) as usize] as i32) == (('\0' as u8) as i32))); let mut prefix_buf: [u8; 32] = diff --git a/tests/unit/out/unsafe/string_literals_sized_c.rs b/tests/unit/out/unsafe/string_literals_sized_c.rs index 32ee56c8..d02baca0 100644 --- a/tests/unit/out/unsafe/string_literals_sized_c.rs +++ b/tests/unit/out/unsafe/string_literals_sized_c.rs @@ -12,7 +12,7 @@ pub fn main() { } } unsafe fn main_0() -> i32 { - let mut empty_buf : [ u8 ; 256] = * b"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" ; + let mut empty_buf: [u8; 256] = [0u8; 256]; assert!(((empty_buf[(0) as usize] as i32) == ('\0' as i32))); assert!(((empty_buf[(255) as usize] as i32) == ('\0' as i32))); let mut prefix_buf: [u8; 32] =