Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
117afb3
Translate free function ptr as Option<fn>
lucic71 Apr 13, 2026
562978b
Fix null ptr deref
lucic71 Apr 13, 2026
32ae03c
Fix translation of lambdas
lucic71 Apr 13, 2026
c431b29
Translate type of lambda as _ instead of Rc<dyn Fn>
lucic71 Apr 13, 2026
de96315
Translate non-const globals as static mut
lucic71 Apr 13, 2026
212d22b
Use concerete default val for initializing globals
lucic71 Apr 13, 2026
58c39b9
Help the compiler deduce the type of a function
lucic71 Apr 13, 2026
12a4433
Don't add &mut in function ptr conditionals
lucic71 Apr 13, 2026
7ab067d
Add fn_ptr and lambda tests
lucic71 Apr 13, 2026
ddd13a8
clang-format
lucic71 Apr 13, 2026
4d93cd4
Update tests
lucic71 Apr 13, 2026
691a435
clang-format
lucic71 Apr 13, 2026
f026728
Translate fn ptr cast using mem::transmute
lucic71 Apr 13, 2026
e320bdb
Add support for function pointers in PtrKind
lucic71 Apr 14, 2026
a5d65f6
Move PtrKind::Fn into FnPtr
lucic71 Apr 14, 2026
01e9e9f
Fix signature of fread and fwrite
lucic71 Apr 15, 2026
e3a69af
Add name and module in ExprTgt
lucic71 Apr 15, 2026
e30fef0
Use rule function name in AddrOf context
lucic71 Apr 15, 2026
133e94f
Check name and module are never empty
lucic71 Apr 15, 2026
25b203f
Get fully qualified name of translation rule
lucic71 Apr 15, 2026
9cfda12
Update output of fn_ptr_stdlib_compare
lucic71 Apr 15, 2026
06b73fd
Change to deafult with suffix
lucic71 Apr 15, 2026
942bde3
Make rules public
lucic71 Apr 15, 2026
03e7ab7
cargo-fmt
lucic71 Apr 15, 2026
a2e1c1a
Delete unused Cargo.toml
lucic71 Apr 15, 2026
1c1ab7d
Use prebuilt rules and libcc2rs targets
lucic71 Apr 15, 2026
840863d
Implement Deref for FnPtr
lucic71 Apr 15, 2026
3c1b9c7
Update rules IR
lucic71 Apr 15, 2026
e7fa221
Remove unused fn ptr cast and fn_ptr_anon
lucic71 Apr 15, 2026
0c1ebf9
Delete ByteRepr for fn pointers
lucic71 Apr 15, 2026
60fd8c3
Drop Clone trait from ErasedPtr
lucic71 Apr 15, 2026
81581df
Allow casting between nullptr's of different types
lucic71 Apr 15, 2026
82b9ed0
Update output of fn_ptr_stdlib_compare
lucic71 Apr 15, 2026
207106c
Allow char*/void* <-> T* conversions in adapter
lucic71 Apr 15, 2026
c500cff
Omit enumeral types on generating default integers
lucic71 Apr 15, 2026
60209ac
Merge branch 'master' into fn-ptr
lucic71 Apr 20, 2026
f138af5
Rename GetFnRefName to MapFunctionName
lucic71 Apr 20, 2026
a929df9
Add ConvertPointeeType
lucic71 Apr 20, 2026
1e0794a
Add ShouldReplaceWithMappedBody
lucic71 Apr 20, 2026
747195b
Replace single char strings with char literals
lucic71 Apr 20, 2026
1645da1
Short-circuit ConvertPointeeType for integer types
lucic71 Apr 20, 2026
6455886
Merge branch 'master' into fn-ptr
lucic71 Apr 21, 2026
2f7ce1b
Update tests
lucic71 Apr 21, 2026
83e8868
Replace rules::stdio_tgt_unsafe::f5 with rules::fread_unsafe
lucic71 Apr 24, 2026
f1ce30d
Merge branch 'master' into fn-ptr
lucic71 Apr 24, 2026
81a2f40
Revert translation_rule to master
lucic71 Apr 24, 2026
d7709d5
Add fread alias for f5 rule
lucic71 Apr 24, 2026
44a6d61
Add call to fread through function pointer
lucic71 Apr 24, 2026
9b3b165
rustfmt
lucic71 Apr 24, 2026
06d80a3
Move implementation of fread inside libcc2rs
lucic71 Apr 24, 2026
c6ab724
Remove unused import
lucic71 Apr 24, 2026
a689a25
Update the IR
lucic71 Apr 24, 2026
ff7719a
Call fread both through func ptr and direct func call
lucic71 Apr 24, 2026
b993692
Remove unintented generated files
lucic71 Apr 24, 2026
6234360
Revert making rules visible
lucic71 Apr 24, 2026
3890493
Delete unrelated file
lucic71 Apr 24, 2026
49034f3
Use strinv_view in Trim
lucic71 Apr 24, 2026
7aa0fdb
Move overlapping check in assert
lucic71 Apr 24, 2026
c6c7024
Fix clippy errors
lucic71 Apr 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions cpp2rust/converter/converter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1430,7 +1430,7 @@ void Converter::EmitFnPtrCall(clang::Expr *callee) {

void Converter::ConvertFunctionToFunctionPointer(
const clang::FunctionDecl *fn_decl) {
StrCat(std::format("Some({})", GetNamedDeclAsString(fn_decl)));
StrCat(std::format("Some({})", Mapper::MapFunctionName(fn_decl)));
}

void Converter::ConvertGenericCallExpr(clang::CallExpr *expr) {
Expand Down Expand Up @@ -2070,7 +2070,7 @@ std::string Converter::ConvertDeclRefExpr(clang::DeclRefExpr *expr) {
}

auto *decl = expr->getDecl();
if (Mapper::Contains(expr)) {
if (ShouldReplaceWithMappedBody(expr)) {
return GetMappedAsString(expr);
} else if (auto *function = decl->getAsFunction()) {
if (auto method = clang::dyn_cast<clang::CXXMethodDecl>(function)) {
Expand Down Expand Up @@ -3472,6 +3472,13 @@ bool Converter::isCallee() const {
return !curr_expr_kind_.empty() && curr_expr_kind_.back() == ExprKind::Callee;
}

bool Converter::ShouldReplaceWithMappedBody(clang::DeclRefExpr *expr) const {
if (clang::isa<clang::FunctionDecl>(expr->getDecl()) && isAddrOf()) {
return false;
}
return Mapper::Contains(expr);
}

void Converter::SetFresh() {
switch (computed_expr_type_) {
case ComputedExprType::Value:
Expand Down
2 changes: 2 additions & 0 deletions cpp2rust/converter/converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,8 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {

virtual bool RecordDerivesDefault(const clang::RecordDecl *decl);

bool ShouldReplaceWithMappedBody(clang::DeclRefExpr *expr) const;

std::string *rs_code_;
clang::ASTContext &ctx_;
clang::FunctionDecl *curr_function_ = nullptr;
Expand Down
20 changes: 20 additions & 0 deletions cpp2rust/converter/converter_lib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
#include <clang/AST/ParentMapContext.h>
#include <clang/Basic/SourceManager.h>

#include <algorithm>
#include <array>
#include <cctype>
#include <filesystem>
#include <unordered_set>

Expand Down Expand Up @@ -660,4 +662,22 @@ clang::Expr *CreateConversionToBool(clang::Expr *expr, clang::ASTContext &ctx) {
/*BasePath=*/nullptr, clang::VK_PRValue, clang::FPOptionsOverride());
}

static std::string_view Trim(std::string_view s) {
auto is_space = [](unsigned char c) { return std::isspace(c); };
auto b = std::find_if_not(s.begin(), s.end(), is_space);
auto e = std::find_if_not(s.rbegin(), s.rend(), is_space).base();
return {b, e};
}

void Unwrap(std::string &s, std::string_view prefix, std::string_view suffix) {
auto trimmed = Trim(s);
if (trimmed.starts_with(prefix) && trimmed.ends_with(suffix)) {
assert(trimmed.size() >= prefix.size() + suffix.size() &&
"prefix and suffix overlap in s");
trimmed.remove_prefix(prefix.size());
trimmed.remove_suffix(suffix.size());
s = std::string(trimmed);
}
}

} // namespace cpp2rust
3 changes: 3 additions & 0 deletions cpp2rust/converter/converter_lib.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <optional>
#include <regex>
#include <string>
#include <string_view>
#include <vector>

namespace cpp2rust {
Expand Down Expand Up @@ -154,4 +155,6 @@ bool ContainsVAArgExpr(const clang::Stmt *stmt);

clang::Expr *CreateConversionToBool(clang::Expr *expr, clang::ASTContext &ctx);

void Unwrap(std::string &s, std::string_view prefix, std::string_view suffix);

} // namespace cpp2rust
10 changes: 10 additions & 0 deletions cpp2rust/converter/mapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <llvm/Support/ThreadPool.h>

#include <atomic>
#include <format>
#include <mutex>
#include <regex>
#include <utility>
Expand Down Expand Up @@ -581,6 +582,15 @@ const TranslationRule::ExprTgt *GetExprTgt(const clang::Expr *expr) {
return nullptr;
}

std::string MapFunctionName(const clang::FunctionDecl *decl) {
assert(decl);
if (exprs_.contains(ToString(decl))) {
return std::format("libcc2rs::{}_{}", decl->getNameAsString(),
model_ == Model::kRefCount ? "refcount" : "unsafe");
}
return GetNamedDeclAsString(decl->getCanonicalDecl());
}

std::string InstantiateTemplate(const clang::Expr *expr,
const std::string &text) {
auto it = search(expr);
Expand Down
1 change: 1 addition & 0 deletions cpp2rust/converter/mapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ bool Contains(const clang::Expr *expr);

std::string Map(clang::QualType qual_type);
const TranslationRule::ExprTgt *GetExprTgt(const clang::Expr *expr);
std::string MapFunctionName(const clang::FunctionDecl *decl);
std::string InstantiateTemplate(const clang::Expr *expr,
const std::string &text);
bool ReturnsPointer(const clang::Expr *expr);
Expand Down
24 changes: 19 additions & 5 deletions cpp2rust/converter/models/converter_refcount.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ std::string ConverterRefCount::BuildFnAdapter(
closure += "{ ";

// Build adapter body: src_fn(convert(a0), convert(a1), ...)
closure += GetNamedDeclAsString(src_fn) + "(";
closure += Mapper::MapFunctionName(src_fn) + '(';
for (unsigned i = 0; i < src_proto->getNumParams(); ++i) {
auto src_pty = src_proto->getParamType(i);
auto tgt_pty = target_proto->getParamType(i);
Expand All @@ -204,12 +204,12 @@ std::string ConverterRefCount::BuildFnAdapter(
} else if (src_pty->isPointerType() && tgt_pty->isPointerType()) {
if (tgt_pty->isVoidPointerType()) {
closure += std::format("a{}.cast::<{}>().unwrap()", i,
ToString(src_pty->getPointeeType()));
ConvertPointeeType(src_pty));
} else if (src_pty->isVoidPointerType()) {
closure += std::format("a{}.to_any()", i);
} else if (tgt_pty->getPointeeType()->isCharType()) {
closure += std::format("a{}.reinterpret_cast::<{}>()", i,
ToString(src_pty->getPointeeType()));
ConvertPointeeType(src_pty));
} else if (src_pty->getPointeeType()->isCharType()) {
closure += std::format("a{}.reinterpret_cast::<u8>()", i);
}
Expand Down Expand Up @@ -625,7 +625,7 @@ bool ConverterRefCount::VisitDeclRefExpr(clang::DeclRefExpr *expr) {
}
}

if (Mapper::Contains(expr)) {
if (ShouldReplaceWithMappedBody(expr)) {
StrCat(GetMappedAsString(expr));
return false;
}
Expand Down Expand Up @@ -1037,7 +1037,7 @@ void ConverterRefCount::ConvertFunctionToFunctionPointer(
StrCat(std::format("FnPtr::<{}>::new({})",
ConvertFunctionPointerType(
fn_decl->getType()->getAs<clang::FunctionProtoType>()),
GetNamedDeclAsString(fn_decl)));
Mapper::MapFunctionName(fn_decl)));
}

void ConverterRefCount::ConvertEqualsNullPtr(clang::Expr *expr) {
Expand Down Expand Up @@ -2155,4 +2155,18 @@ std::string ConverterRefCount::ConvertMappedMethodCall(
return std::format("{}.with_mut(|__v: {}| __v{})", ptr, param_type, body);
}

std::string ConverterRefCount::ConvertPointeeType(clang::QualType ptr_type) {
if (ptr_type->getPointeeType()->isIntegerType()) {
return ToString(ptr_type->getPointeeType());
}

// Pointee of a pointer to incomplete type is an incomplete type that does
// not have a translation rule. Hence ToString(ptr_type->getPointeeType()) is
// not enough
assert(ptr_type->isPointerType());
auto str = ToString(ptr_type);
Unwrap(str, "Ptr<", ">");
return str;
}

} // namespace cpp2rust
1 change: 1 addition & 0 deletions cpp2rust/converter/models/converter_refcount.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ class ConverterRefCount final : public Converter {
std::string ConvertFreshPointer(clang::Expr *expr) override;

std::string ConvertPtrType(clang::QualType type);
std::string ConvertPointeeType(clang::QualType ptr_type);

/// The kind of conversion that should be performed.
enum class ConversionKind : uint8_t {
Expand Down
82 changes: 81 additions & 1 deletion libcc2rs/src/io.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) 2022-present INESC-ID.
// Distributed under the MIT license that can be found in the LICENSE file.

use crate::{AsPointer, Ptr, Value};
use crate::{AnyPtr, AsPointer, Ptr, Value};
use std::cell::{RefCell, UnsafeCell};
use std::os::fd::{AsFd, FromRawFd, IntoRawFd};
use std::rc::Rc;
Expand Down Expand Up @@ -58,3 +58,83 @@ pub unsafe fn cout_unsafe() -> *mut std::fs::File {
pub unsafe fn cerr_unsafe() -> *mut std::fs::File {
UNSAFE_STDERR.with(UnsafeCell::get)
}

pub fn fread_refcount(a0: AnyPtr, a1: u64, a2: u64, a3: Ptr<::std::fs::File>) -> u64 {
let total = a1.saturating_mul(a2) as usize;
let mut dst = a0
.cast::<u8>()
.expect("fread: only supporting u8 pointers")
.clone();

let f = (*a3.upgrade().deref())
.try_clone()
.expect("try_clone failed");
let mut reader = std::io::BufReader::with_capacity(64 * 1024, f);

let mut read_bytes: usize = 0;
let mut buffer: [u8; 8192] = [0; 8192];

while read_bytes < total {
let remaining = total - read_bytes;
let to_read = std::cmp::min(buffer.len(), remaining);

let n = match std::io::Read::read(&mut reader, &mut buffer[..to_read]) {
Ok(0) => break,
Ok(n) => n,
Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => continue,
Err(e) => panic!("Unhandled error in fread: {e}"),
};

for &byte in &buffer[..n] {
dst.write(byte);
dst = dst.offset(1);
}

read_bytes += n;
}

(read_bytes / a1 as usize) as u64
}

/// # Safety
///
/// `a0` must point to a writable buffer of at least `a1 * a2` bytes, and `a3`
/// must point to a valid, open `std::fs::File`.
pub unsafe fn fread_unsafe(
a0: *mut ::std::ffi::c_void,
a1: u64,
a2: u64,
a3: *mut ::std::fs::File,
) -> u64 {
let total = a1.saturating_mul(a2) as usize;
let mut dst = a0 as *mut u8;

let f = unsafe { (*a3).try_clone().expect("try_clone failed") };
let mut reader = std::io::BufReader::with_capacity(64 * 1024, f);

let mut read_bytes: usize = 0;
let mut buffer: [u8; 8192] = [0; 8192];

while read_bytes < total {
let remaining = total - read_bytes;
let to_read = std::cmp::min(buffer.len(), remaining);

let n = match std::io::Read::read(&mut reader, &mut buffer[..to_read]) {
Ok(0) => break,
Ok(n) => n,
Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => continue,
Err(e) => panic!("Unhandled error in fread: {e}"),
};

for &byte in &buffer[..n] {
unsafe {
*dst = byte;
dst = dst.offset(1);
}
}

read_bytes += n;
}

(read_bytes / a1 as usize) as u64
}
Loading
Loading