From bd0e046dcd9f1588571ad02cad0275368b83975d Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Sat, 23 May 2026 17:13:52 +0100 Subject: [PATCH 1/2] Refactor ConvertGenericCallExpr --- cpp2rust/converter/converter.cpp | 203 ++++++++++++++++++------------- cpp2rust/converter/converter.h | 33 +++++ 2 files changed, 150 insertions(+), 86 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 258d0a2..3c76563 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1495,125 +1495,156 @@ void Converter::ConvertFunctionToFunctionPointer( StrCat(std::format("Some({})", Mapper::MapFunctionName(fn_decl))); } -void Converter::ConvertGenericCallExpr(clang::CallExpr *expr) { - clang::Expr *callee = expr->getCallee(); - auto convert_param_ty = [&](clang::QualType param_type, clang::Expr *expr) { - if (param_type->isLValueReferenceType()) { - PushExprKind push(*this, ExprKind::AddrOf); - ConvertVarInit(param_type, expr); - } else { - ConvertVarInit(param_type, expr); - } - }; +Converter::CallInfo Converter::CollectCallInfo(clang::CallExpr *expr) { + using Kind = CallArg::Kind; - unsigned arg_begin = 0; // skip count for operator()'s implicit object arg + CallInfo info{}; + info.callee = expr->getCallee(); + unsigned arg_begin = 0; if (auto op_call = llvm::dyn_cast(expr)) { if (op_call->getOperator() == clang::OO_Call) { - callee = op_call->getArg(0); + info.callee = op_call->getArg(0); arg_begin = 1; } } - PushParen outer(*this); - StrCat(keyword_unsafe_); - PushBrace unsafe_brace(*this); const auto *function = expr->getCalleeDecl() ? expr->getCalleeDecl()->getAsFunction() : nullptr; const clang::FunctionProtoType *proto = nullptr; - if (!function) { - auto callee_ty = callee->getType().getDesugaredType(ctx_); + auto callee_ty = info.callee->getType().getDesugaredType(ctx_); if (auto ptr_ty = callee_ty->getAs()) { proto = ptr_ty->getPointeeType()->getAs(); } } - assert((function || proto) && "Either function decl or function prototype should be known"); - auto num_args = expr->getNumArgs() - arg_begin; - bool is_variadic = - function ? function->isVariadic() : (proto && proto->isVariadic()); - unsigned num_named_params = function - ? function->getNumParams() - : (proto ? proto->getNumParams() : num_args); - - // Track which args are materialized temps bound to reference params - std::vector temp_refs(num_args); + unsigned num_args = expr->getNumArgs() - arg_begin; + unsigned num_named_params = + function ? function->getNumParams() : proto->getNumParams(); + info.is_variadic = function ? function->isVariadic() : proto->isVariadic(); + info.is_fn_ptr_call = !function; for (unsigned i = 0; i < num_named_params && i < num_args; ++i) { auto *arg = expr->getArg(i + arg_begin); - std::string param_name = function - ? function->getParamDecl(i)->getNameAsString() - : ("arg" + std::to_string(i)); - clang::QualType param_type = function ? function->getParamDecl(i)->getType() - : proto->getParamType(i); - - bool is_materialize_to_ref = - clang::isa(arg) && - param_type->isLValueReferenceType(); - - if (is_materialize_to_ref) { - auto [binding, ref] = - MaterializeTemp(std::format("_{}", param_name), param_type, arg); - StrCat(binding); - temp_refs[i] = std::move(ref); - } else if (!clang::isa(arg)) { - StrCat("let", std::format("_{}: {}", param_name, ToString(param_type)), - "="); - convert_param_ty(param_type, arg); - StrCat(";"); + CallArg ca{ + .expr = arg, + .kind = Kind::Hoisted, + .param_name = function ? function->getParamDecl(i)->getNameAsString() + : ("arg" + std::to_string(i)), + .param_type = function ? function->getParamDecl(i)->getType() + : proto->getParamType(i), + .has_default = function && function->getParamDecl(i)->hasDefaultArg(), + }; + bool is_materialize = clang::isa(arg); + if (is_materialize && ca.param_type->isLValueReferenceType()) { + ca.kind = Kind::Materialized; + } else if (is_materialize) { + ca.kind = Kind::Inline; + } + info.args.push_back(std::move(ca)); + } + + if (info.is_variadic) { + for (unsigned i = num_named_params; i < num_args; ++i) { + info.variadic_args.push_back(expr->getArg(i + arg_begin)); } } - if (proto && !function) { - EmitFnPtrCall(callee); + return info; +} + +void Converter::ConvertParamTy(clang::QualType param_type, clang::Expr *expr) { + if (param_type->isLValueReferenceType()) { + PushExprKind push(*this, ExprKind::AddrOf); + ConvertVarInit(param_type, expr); } else { - PushExprKind push(*this, ExprKind::Callee); - Convert(callee); + ConvertVarInit(param_type, expr); } - { - PushParen call_args(*this); - for (unsigned i = 0; i < num_named_params && i < num_args; ++i) { - auto *arg = expr->getArg(i + arg_begin); - std::string param_name = - function ? function->getParamDecl(i)->getNameAsString() - : ("arg" + std::to_string(i)); - clang::QualType param_type = function - ? function->getParamDecl(i)->getType() - : proto->getParamType(i); - bool is_parm_with_default_value = - function && function->getParamDecl(i)->hasDefaultArg(); - - if (is_parm_with_default_value) { - StrCat("Some("); - } - if (!temp_refs[i].empty()) { - StrCat(temp_refs[i]); - } else if (clang::isa(arg)) { - convert_param_ty(param_type, arg); - } else { - StrCat(std::format("_{}", param_name)); - } - if (is_parm_with_default_value) { - StrCat(')'); - } - StrCat(token::kComma); +} + +void Converter::EmitArgBindings(CallInfo &info) { + using Kind = CallArg::Kind; + for (auto &ca : info.args) { + switch (ca.kind) { + case Kind::Hoisted: + StrCat("let", + std::format("_{}: {}", ca.param_name, ToString(ca.param_type)), + "="); + ConvertParamTy(ca.param_type, ca.expr); + StrCat(";"); + break; + case Kind::Materialized: { + auto [binding, ref] = MaterializeTemp(std::format("_{}", ca.param_name), + ca.param_type, ca.expr); + StrCat(binding); + ca.ref_temp_name = std::move(ref); + break; } + case Kind::Inline: + break; + } + } +} + +void Converter::EmitArgList(const CallInfo &info) { + using Kind = CallArg::Kind; + PushParen call_args(*this); - // Variadic args: wrap in &[arg.into(), ...] - if (is_variadic) { - StrCat("& ["); - for (unsigned i = num_named_params; i < num_args; ++i) { - auto *arg = expr->getArg(i + arg_begin); - ConvertVariadicArg(arg); - StrCat(".into()", token::kComma); + for (const auto &ca : info.args) { + if (ca.has_default) { + StrCat("Some"); + } + + { + PushParen push(*this, ca.has_default); + switch (ca.kind) { + case Kind::Hoisted: + StrCat(std::format("_{}", ca.param_name)); + break; + case Kind::Materialized: + StrCat(ca.ref_temp_name); + break; + case Kind::Inline: + ConvertParamTy(ca.param_type, ca.expr); + break; } - StrCat(']'); + } + + StrCat(token::kComma); + } + + if (info.is_variadic) { + StrCat(token::kRef); + PushBracket push(*this); + for (auto *arg : info.variadic_args) { + ConvertVariadicArg(arg); + StrCat(".into()", token::kComma); } } } +void Converter::EmitCall(CallInfo info) { + EmitArgBindings(info); + + if (info.is_fn_ptr_call) { + EmitFnPtrCall(info.callee); + } else { + PushExprKind push(*this, ExprKind::Callee); + Convert(info.callee); + } + + EmitArgList(info); +} + +void Converter::ConvertGenericCallExpr(clang::CallExpr *expr) { + PushParen outer(*this); + StrCat(keyword_unsafe_); + PushBrace unsafe_brace(*this); + EmitCall(CollectCallInfo(expr)); +} + std::optional Converter::ConvertCallExpr(clang::CallExpr *expr) { auto *callee = expr->getCallee(); diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 9baa504..101a90f 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -217,6 +217,39 @@ class Converter : public clang::RecursiveASTVisitor { std::optional ConvertCallExpr(clang::CallExpr *expr); + struct CallArg { + enum class Kind { + Hoisted, + Inline, + Materialized, + }; + + clang::Expr *expr; + Kind kind; + std::string param_name; + clang::QualType param_type; + bool has_default; + std::string ref_temp_name; + }; + + struct CallInfo { + clang::Expr *callee; + bool is_variadic; + bool is_fn_ptr_call; + std::vector args; + std::vector variadic_args; + }; + + CallInfo CollectCallInfo(clang::CallExpr *expr); + + void ConvertParamTy(clang::QualType param_type, clang::Expr *expr); + + void EmitArgBindings(CallInfo &info); + + void EmitArgList(const CallInfo &info); + + void EmitCall(CallInfo info); + void ConvertGenericCallExpr(clang::CallExpr *expr); virtual void EmitFnPtrCall(clang::Expr *callee); From 2cae1e9a97bb8d4d2b7403bd30e0074c93237c37 Mon Sep 17 00:00:00 2001 From: Lucian Popescu Date: Sat, 23 May 2026 18:44:57 +0100 Subject: [PATCH 2/2] EmitArgBindings -> EmitHoistedArgs --- cpp2rust/converter/converter.cpp | 4 ++-- cpp2rust/converter/converter.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp2rust/converter/converter.cpp b/cpp2rust/converter/converter.cpp index 3c76563..a1c3218 100644 --- a/cpp2rust/converter/converter.cpp +++ b/cpp2rust/converter/converter.cpp @@ -1564,7 +1564,7 @@ void Converter::ConvertParamTy(clang::QualType param_type, clang::Expr *expr) { } } -void Converter::EmitArgBindings(CallInfo &info) { +void Converter::EmitHoistedArgs(CallInfo &info) { using Kind = CallArg::Kind; for (auto &ca : info.args) { switch (ca.kind) { @@ -1626,7 +1626,7 @@ void Converter::EmitArgList(const CallInfo &info) { } void Converter::EmitCall(CallInfo info) { - EmitArgBindings(info); + EmitHoistedArgs(info); if (info.is_fn_ptr_call) { EmitFnPtrCall(info.callee); diff --git a/cpp2rust/converter/converter.h b/cpp2rust/converter/converter.h index 101a90f..d9b6cb5 100644 --- a/cpp2rust/converter/converter.h +++ b/cpp2rust/converter/converter.h @@ -244,7 +244,7 @@ class Converter : public clang::RecursiveASTVisitor { void ConvertParamTy(clang::QualType param_type, clang::Expr *expr); - void EmitArgBindings(CallInfo &info); + void EmitHoistedArgs(CallInfo &info); void EmitArgList(const CallInfo &info);