From 5006a6aa340eb49b6101bb1fb37bf9c22d3d3fdc Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Tue, 6 Oct 2026 21:35:07 +0100 Subject: [PATCH 1/6] work --- cpp2rust/converter/converter.cpp | 19 +++++++++++++++++++ cpp2rust/converter/converter.h | 2 ++ tests/unit/macros.cpp | 6 ++++++ 3 files changed, 27 insertions(+) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 9c3fd2a58..36cce4d22 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2377,6 +2377,25 @@ Converter::GetCodeUnitArrayLiteral(const clang::StringLiteral *expr) { return out; } +bool Converter::VisitSourceLocExpr(clang::SourceLocExpr *expr) { + auto value = expr->EvaluateInContext(ctx_, nullptr); + clang::Expr *lowered = nullptr; + if (value.isInt()) { + lowered = clang::IntegerLiteral::Create( + ctx_, value.getInt(), expr->getType(), expr->getBeginLoc()); + } else { + auto *str = clang::dyn_cast_or_null( + value.getLValueBase().dyn_cast()); + assert(str && "unsupported SourceLocExpr"); + lowered = clang::ImplicitCastExpr::Create( + ctx_, expr->getType(), clang::CK_ArrayToPointerDecay, + const_cast(str), nullptr, clang::VK_PRValue, + clang::FPOptionsOverride()); + } + Convert(lowered); + return false; +} + bool Converter::VisitStringLiteral(clang::StringLiteral *expr) { if (IsCodeUnitStringLiteral(expr)) { StrCat(GetCodeUnitArrayLiteral(expr)); diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 7d68a5d70..eed09837d 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -380,6 +380,8 @@ class Converter : public clang::RecursiveASTVisitor { uint64_t pad_nulls = 0) const; virtual bool VisitStringLiteral(clang::StringLiteral *expr); + bool VisitSourceLocExpr(clang::SourceLocExpr *expr); + virtual bool VisitCXXBoolLiteralExpr(clang::CXXBoolLiteralExpr *expr); void ConvertIntegerToEnumeralCast(clang::Expr *to, clang::Expr *from); diff --git a/tests/unit/macros.cpp b/tests/unit/macros.cpp index 2c347d39c..ae84fd0c9 100644 --- a/tests/unit/macros.cpp +++ b/tests/unit/macros.cpp @@ -4,8 +4,14 @@ void log(const char *file, int line, const char *func) { printf("%s %d %s\n", file, line, func); } +int line() { return __builtin_LINE(); } + +const char *function() { return __builtin_FUNCTION(); } + int main() { printf("%s %d %s\n", __FILE__, __LINE__, __FUNCTION__); log(__FILE__, __LINE__, __FUNCTION__); + log(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION()); + printf("%d %s\n", line(), function()); return 0; } From 2afc4264cf7485f056a21abd0b6f8f8b20a6a7ff Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 7 Oct 2026 09:28:17 +0100 Subject: [PATCH 2/6] work --- tests/unit/macros.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/macros.cpp b/tests/unit/macros.cpp index ae84fd0c9..7ca0fc3c6 100644 --- a/tests/unit/macros.cpp +++ b/tests/unit/macros.cpp @@ -11,7 +11,7 @@ const char *function() { return __builtin_FUNCTION(); } int main() { printf("%s %d %s\n", __FILE__, __LINE__, __FUNCTION__); log(__FILE__, __LINE__, __FUNCTION__); - log(__builtin_FILE(), __builtin_LINE(), __builtin_FUNCTION()); + log(__FILE__, __builtin_LINE(), __builtin_FUNCTION()); printf("%d %s\n", line(), function()); return 0; } From b29690e60892e41e2fb789e1138ab0d65c400444 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 7 Oct 2026 09:34:47 +0100 Subject: [PATCH 3/6] work --- tests/unit/macros.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/unit/macros.cpp b/tests/unit/macros.cpp index 7ca0fc3c6..bc632a68f 100644 --- a/tests/unit/macros.cpp +++ b/tests/unit/macros.cpp @@ -1,4 +1,10 @@ #include +#include + +const char *base_name(const char *path) { + const char *slash = strrchr(path, '/'); + return slash ? slash + 1 : path; +} void log(const char *file, int line, const char *func) { printf("%s %d %s\n", file, line, func); @@ -11,7 +17,7 @@ const char *function() { return __builtin_FUNCTION(); } int main() { printf("%s %d %s\n", __FILE__, __LINE__, __FUNCTION__); log(__FILE__, __LINE__, __FUNCTION__); - log(__FILE__, __builtin_LINE(), __builtin_FUNCTION()); + log(base_name(__builtin_FILE()), __builtin_LINE(), __builtin_FUNCTION()); printf("%d %s\n", line(), function()); return 0; } From d58067584069603dbcc282054cd899ee93ada677 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 7 Oct 2026 09:40:12 +0100 Subject: [PATCH 4/6] Update tests --- tests/unit/out/refcount/macros.rs | 48 ++++++++++++++++++++++++++++--- tests/unit/out/unsafe/macros.rs | 33 +++++++++++++++++++-- 2 files changed, 74 insertions(+), 7 deletions(-) diff --git a/tests/unit/out/refcount/macros.rs b/tests/unit/out/refcount/macros.rs index 01976bf8b..822b9d425 100644 --- a/tests/unit/out/refcount/macros.rs +++ b/tests/unit/out/refcount/macros.rs @@ -6,9 +6,41 @@ use std::io::prelude::*; use std::io::{Read, Seek, Write}; use std::os::fd::AsFd; use std::rc::{Rc, Weak}; -pub fn log_0(mut file: Ptr, mut line: i32, mut func: Ptr) { +pub fn base_name_0(mut path: Ptr) -> Ptr { + let mut slash: Ptr = { + let __s = (path).clone(); + let __t = (('/' as i8) as i32) as i8; + match __s + .to_c_string_iterator() + .enumerate() + .filter(|__e| __e.1 == __t) + .last() + { + Some((__i, _)) => __s.offset(__i), + None => { + if __t == 0 { + __s.offset(__s.to_c_string_iterator().count()) + } else { + Ptr::null() + } + } + } + }; + return if !(slash).is_null() { + slash.offset((1) as isize) + } else { + path + }; +} +pub fn log_1(mut file: Ptr, mut line: i32, mut func: Ptr) { println!("{} {} {}", file, line, func); } +pub fn line_2() -> i32 { + return (13_u32 as i32); +} +pub fn function_3() -> Ptr { + return Ptr::::from_string_literal(b"function"); +} pub fn main() { __cpp2rust_init_globals(); std::process::exit(main_0()); @@ -17,16 +49,24 @@ fn main_0() -> i32 { println!( "{} {} {}", Ptr::::from_string_literal(b"macros.cpp"), - 8, + 18, Ptr::::from_string_literal(b"main") ); ({ - log_0( + log_1( Ptr::::from_string_literal(b"macros.cpp"), - 9, + 19, + Ptr::::from_string_literal(b"main"), + ) + }); + ({ + log_1( + ({ base_name_0(Ptr::::from_string_literal(b"macros.cpp")) }), + (20_u32 as i32), Ptr::::from_string_literal(b"main"), ) }); + println!("{} {}", ({ line_2() }), ({ function_3() })); return 0; } pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/macros.rs b/tests/unit/out/unsafe/macros.rs index a849f188f..67ad0d9a1 100644 --- a/tests/unit/out/unsafe/macros.rs +++ b/tests/unit/out/unsafe/macros.rs @@ -6,9 +6,24 @@ use std::collections::BTreeMap; use std::io::{Read, Seek, Write}; use std::os::fd::{AsFd, FromRawFd, IntoRawFd}; use std::rc::Rc; -pub unsafe fn log_0(mut file: *const libc::c_char, mut line: i32, mut func: *const libc::c_char) { +pub unsafe fn base_name_0(mut path: *const libc::c_char) -> *const libc::c_char { + let mut slash: *const libc::c_char = + (libc::strrchr(path, (('/' as libc::c_char) as i32)) as *const libc::c_char); + return if !(slash).is_null() { + slash.offset((1) as isize) + } else { + path + }; +} +pub unsafe fn log_1(mut file: *const libc::c_char, mut line: i32, mut func: *const libc::c_char) { printf(c"%s %d %s\n".as_ptr() as *const i8, file, line, func); } +pub unsafe fn line_2() -> i32 { + return (13_u32 as i32); +} +pub unsafe fn function_3() -> *const libc::c_char { + return c"function".as_ptr(); +} pub fn main() { unsafe { __cpp2rust_init_globals(); @@ -19,10 +34,22 @@ unsafe fn main_0() -> i32 { printf( c"%s %d %s\n".as_ptr() as *const i8, c"macros.cpp".as_ptr(), - 8, + 18, c"main".as_ptr(), ); - (unsafe { log_0(c"macros.cpp".as_ptr(), 9, c"main".as_ptr()) }); + (unsafe { log_1(c"macros.cpp".as_ptr(), 19, c"main".as_ptr()) }); + (unsafe { + log_1( + (unsafe { base_name_0(c"macros.cpp".as_ptr()) }), + (20_u32 as i32), + c"main".as_ptr(), + ) + }); + printf( + c"%d %s\n".as_ptr() as *const i8, + (unsafe { line_2() }), + (unsafe { function_3() }), + ); return 0; } pub unsafe fn __cpp2rust_init_globals() {} From 40880955f1ed2a5b1b28e8004eb56556bc52a3c6 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 7 Oct 2026 11:16:21 +0100 Subject: [PATCH 5/6] Use line and file in rust --- cpp2rust/converter/converter.cpp | 38 ++++++++++++------- cpp2rust/converter/converter.h | 2 + .../converter/models/converter_refcount.cpp | 6 +++ .../converter/models/converter_refcount.h | 2 + tests/unit/macros.cpp | 7 +++- tests/unit/out/refcount/macros.rs | 27 ++++++++----- tests/unit/out/unsafe/macros.rs | 24 +++++------- 7 files changed, 67 insertions(+), 39 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 36cce4d22..36079f97d 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -2377,23 +2377,35 @@ Converter::GetCodeUnitArrayLiteral(const clang::StringLiteral *expr) { return out; } +std::string Converter::GetSourceFileAsString(clang::QualType type) { + return std::format("concat!(file!(), \"\\0\").as_ptr() as {}", + ToString(type)); +} + bool Converter::VisitSourceLocExpr(clang::SourceLocExpr *expr) { - auto value = expr->EvaluateInContext(ctx_, nullptr); - clang::Expr *lowered = nullptr; - if (value.isInt()) { - lowered = clang::IntegerLiteral::Create( - ctx_, value.getInt(), expr->getType(), expr->getBeginLoc()); - } else { - auto *str = clang::dyn_cast_or_null( - value.getLValueBase().dyn_cast()); - assert(str && "unsupported SourceLocExpr"); - lowered = clang::ImplicitCastExpr::Create( + switch (expr->getIdentKind()) { + case clang::SourceLocIdentKind::Line: + StrCat(std::format("line!() as {}", ToString(expr->getType()))); + computed_expr_type_ = ComputedExprType::FreshValue; + return false; + case clang::SourceLocIdentKind::File: + StrCat(GetSourceFileAsString(expr->getType())); + computed_expr_type_ = ComputedExprType::FreshPointer; + return false; + case clang::SourceLocIdentKind::Function: { + auto value = expr->EvaluateInContext(ctx_, nullptr); + auto *str = clang::cast( + value.getLValueBase().get()); + Convert(clang::ImplicitCastExpr::Create( ctx_, expr->getType(), clang::CK_ArrayToPointerDecay, const_cast(str), nullptr, clang::VK_PRValue, - clang::FPOptionsOverride()); + clang::FPOptionsOverride())); + return false; + } + default: + assert(0 && "unsupported SourceLocExpr"); + return false; } - Convert(lowered); - return false; } bool Converter::VisitStringLiteral(clang::StringLiteral *expr) { diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index eed09837d..b96597a00 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -382,6 +382,8 @@ class Converter : public clang::RecursiveASTVisitor { bool VisitSourceLocExpr(clang::SourceLocExpr *expr); + virtual std::string GetSourceFileAsString(clang::QualType type); + virtual bool VisitCXXBoolLiteralExpr(clang::CXXBoolLiteralExpr *expr); void ConvertIntegerToEnumeralCast(clang::Expr *to, clang::Expr *from); diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 81c31c934..0715a19c6 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1328,6 +1328,12 @@ bool ConverterRefCount::VisitCallExpr(clang::CallExpr *expr) { return false; } +std::string ConverterRefCount::GetSourceFileAsString(clang::QualType type) { + return std::format( + "Ptr::<{}>::from_string_literal(concat!(file!(), \"\\0\").as_bytes())", + ToStringBase(type->getPointeeType().getUnqualifiedType())); +} + bool ConverterRefCount::VisitStringLiteral(clang::StringLiteral *expr) { if (IsCodeUnitStringLiteral(expr)) { auto arr = GetCodeUnitArrayLiteral(expr); diff --git a/cpp2rust/converter/models/converter_refcount.h b/cpp2rust/converter/models/converter_refcount.h index 56d002cf2..a181c1eae 100644 --- a/cpp2rust/converter/models/converter_refcount.h +++ b/cpp2rust/converter/models/converter_refcount.h @@ -137,6 +137,8 @@ class ConverterRefCount final : public Converter { bool VisitStringLiteral(clang::StringLiteral *expr) override; + std::string GetSourceFileAsString(clang::QualType type) override; + bool VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) override; bool VisitFunctionPointerCast(clang::ExplicitCastExpr *expr); diff --git a/tests/unit/macros.cpp b/tests/unit/macros.cpp index bc632a68f..2d193f91e 100644 --- a/tests/unit/macros.cpp +++ b/tests/unit/macros.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -17,7 +18,9 @@ const char *function() { return __builtin_FUNCTION(); } int main() { printf("%s %d %s\n", __FILE__, __LINE__, __FUNCTION__); log(__FILE__, __LINE__, __FUNCTION__); - log(base_name(__builtin_FILE()), __builtin_LINE(), __builtin_FUNCTION()); - printf("%d %s\n", line(), function()); + assert(__builtin_LINE() > 0); + assert(base_name(__builtin_FILE())[0] != '\0'); + assert(line() > 0); + printf("%s\n", function()); return 0; } diff --git a/tests/unit/out/refcount/macros.rs b/tests/unit/out/refcount/macros.rs index 822b9d425..ea75de657 100644 --- a/tests/unit/out/refcount/macros.rs +++ b/tests/unit/out/refcount/macros.rs @@ -36,7 +36,7 @@ pub fn log_1(mut file: Ptr, mut line: i32, mut func: Ptr) { println!("{} {} {}", file, line, func); } pub fn line_2() -> i32 { - return (13_u32 as i32); + return (line!() as u32 as i32); } pub fn function_3() -> Ptr { return Ptr::::from_string_literal(b"function"); @@ -49,24 +49,31 @@ fn main_0() -> i32 { println!( "{} {} {}", Ptr::::from_string_literal(b"macros.cpp"), - 18, + 19, Ptr::::from_string_literal(b"main") ); ({ log_1( Ptr::::from_string_literal(b"macros.cpp"), - 19, + 20, Ptr::::from_string_literal(b"main"), ) }); - ({ - log_1( - ({ base_name_0(Ptr::::from_string_literal(b"macros.cpp")) }), - (20_u32 as i32), - Ptr::::from_string_literal(b"main"), + assert!((line!() as u32 > 0_u32)); + assert!( + (((elem!( + ({ + base_name_0(Ptr::::from_string_literal( + concat!(file!(), "\0").as_bytes(), + )) + }), + 0 ) - }); - println!("{} {}", ({ line_2() }), ({ function_3() })); + .read()) as i32) + != (('\0' as i8) as i32)) + ); + assert!((({ line_2() }) > 0)); + println!("{}", ({ function_3() })); return 0; } pub fn __cpp2rust_init_globals() {} diff --git a/tests/unit/out/unsafe/macros.rs b/tests/unit/out/unsafe/macros.rs index 67ad0d9a1..af9a53cfd 100644 --- a/tests/unit/out/unsafe/macros.rs +++ b/tests/unit/out/unsafe/macros.rs @@ -19,7 +19,7 @@ pub unsafe fn log_1(mut file: *const libc::c_char, mut line: i32, mut func: *con printf(c"%s %d %s\n".as_ptr() as *const i8, file, line, func); } pub unsafe fn line_2() -> i32 { - return (13_u32 as i32); + return (line!() as u32 as i32); } pub unsafe fn function_3() -> *const libc::c_char { return c"function".as_ptr(); @@ -34,22 +34,18 @@ unsafe fn main_0() -> i32 { printf( c"%s %d %s\n".as_ptr() as *const i8, c"macros.cpp".as_ptr(), - 18, + 19, c"main".as_ptr(), ); - (unsafe { log_1(c"macros.cpp".as_ptr(), 19, c"main".as_ptr()) }); - (unsafe { - log_1( - (unsafe { base_name_0(c"macros.cpp".as_ptr()) }), - (20_u32 as i32), - c"main".as_ptr(), - ) - }); - printf( - c"%d %s\n".as_ptr() as *const i8, - (unsafe { line_2() }), - (unsafe { function_3() }), + (unsafe { log_1(c"macros.cpp".as_ptr(), 20, c"main".as_ptr()) }); + assert!(((line!() as u32) > (0_u32))); + assert!( + (((*(unsafe { base_name_0(concat!(file!(), "\0").as_ptr() as *const libc::c_char,) }) + .offset((0) as isize)) as i32) + != (('\0' as libc::c_char) as i32)) ); + assert!(((unsafe { line_2() }) > (0))); + printf(c"%s\n".as_ptr() as *const i8, (unsafe { function_3() })); return 0; } pub unsafe fn __cpp2rust_init_globals() {} From aa387ab7a56b90194b23489d7d076df1b1292216 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Wed, 7 Oct 2026 13:25:41 +0100 Subject: [PATCH 6/6] from_string_literal already appends null byte --- cpp2rust/converter/models/converter_refcount.cpp | 5 ++--- tests/unit/out/refcount/macros.rs | 6 +----- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/cpp2rust/converter/models/converter_refcount.cpp b/cpp2rust/converter/models/converter_refcount.cpp index 0715a19c6..708583f1a 100644 --- a/cpp2rust/converter/models/converter_refcount.cpp +++ b/cpp2rust/converter/models/converter_refcount.cpp @@ -1329,9 +1329,8 @@ bool ConverterRefCount::VisitCallExpr(clang::CallExpr *expr) { } std::string ConverterRefCount::GetSourceFileAsString(clang::QualType type) { - return std::format( - "Ptr::<{}>::from_string_literal(concat!(file!(), \"\\0\").as_bytes())", - ToStringBase(type->getPointeeType().getUnqualifiedType())); + return std::format("Ptr::<{}>::from_string_literal(file!().as_bytes())", + ToStringBase(type->getPointeeType().getUnqualifiedType())); } bool ConverterRefCount::VisitStringLiteral(clang::StringLiteral *expr) { diff --git a/tests/unit/out/refcount/macros.rs b/tests/unit/out/refcount/macros.rs index ea75de657..ba0ec28d8 100644 --- a/tests/unit/out/refcount/macros.rs +++ b/tests/unit/out/refcount/macros.rs @@ -62,11 +62,7 @@ fn main_0() -> i32 { assert!((line!() as u32 > 0_u32)); assert!( (((elem!( - ({ - base_name_0(Ptr::::from_string_literal( - concat!(file!(), "\0").as_bytes(), - )) - }), + ({ base_name_0(Ptr::::from_string_literal(file!().as_bytes()),) }), 0 ) .read()) as i32)