Skip to content

Commit fbf685f

Browse files
committed
Refactor ConvertGenericCallExpr
1 parent a41a08e commit fbf685f

2 files changed

Lines changed: 151 additions & 86 deletions

File tree

cpp2rust/converter/converter.cpp

Lines changed: 118 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,125 +1495,157 @@ void Converter::ConvertFunctionToFunctionPointer(
14951495
StrCat(std::format("Some({})", Mapper::MapFunctionName(fn_decl)));
14961496
}
14971497

1498-
void Converter::ConvertGenericCallExpr(clang::CallExpr *expr) {
1499-
clang::Expr *callee = expr->getCallee();
1500-
auto convert_param_ty = [&](clang::QualType param_type, clang::Expr *expr) {
1501-
if (param_type->isLValueReferenceType()) {
1502-
PushExprKind push(*this, ExprKind::AddrOf);
1503-
ConvertVarInit(param_type, expr);
1504-
} else {
1505-
ConvertVarInit(param_type, expr);
1506-
}
1507-
};
1498+
Converter::CallInfo Converter::CollectCallInfo(clang::CallExpr *expr) {
1499+
using Kind = CallArg::Kind;
15081500

1509-
unsigned arg_begin = 0; // skip count for operator()'s implicit object arg
1501+
CallInfo info{};
1502+
info.callee = expr->getCallee();
1503+
unsigned arg_begin = 0;
15101504
if (auto op_call = llvm::dyn_cast<clang::CXXOperatorCallExpr>(expr)) {
15111505
if (op_call->getOperator() == clang::OO_Call) {
1512-
callee = op_call->getArg(0);
1506+
info.callee = op_call->getArg(0);
15131507
arg_begin = 1;
15141508
}
15151509
}
15161510

1517-
PushParen outer(*this);
1518-
StrCat(keyword_unsafe_);
1519-
PushBrace unsafe_brace(*this);
15201511
const auto *function =
15211512
expr->getCalleeDecl() ? expr->getCalleeDecl()->getAsFunction() : nullptr;
15221513
const clang::FunctionProtoType *proto = nullptr;
1523-
15241514
if (!function) {
1525-
auto callee_ty = callee->getType().getDesugaredType(ctx_);
1515+
auto callee_ty = info.callee->getType().getDesugaredType(ctx_);
15261516
if (auto ptr_ty = callee_ty->getAs<clang::PointerType>()) {
15271517
proto = ptr_ty->getPointeeType()->getAs<clang::FunctionProtoType>();
15281518
}
15291519
}
1530-
15311520
assert((function || proto) &&
15321521
"Either function decl or function prototype should be known");
15331522

1534-
auto num_args = expr->getNumArgs() - arg_begin;
1535-
bool is_variadic =
1536-
function ? function->isVariadic() : (proto && proto->isVariadic());
1537-
unsigned num_named_params = function
1538-
? function->getNumParams()
1539-
: (proto ? proto->getNumParams() : num_args);
1540-
1541-
// Track which args are materialized temps bound to reference params
1542-
std::vector<std::string> temp_refs(num_args);
1523+
unsigned num_args = expr->getNumArgs() - arg_begin;
1524+
unsigned num_named_params =
1525+
function ? function->getNumParams() : proto->getNumParams();
1526+
info.is_variadic = function ? function->isVariadic() : proto->isVariadic();
1527+
info.is_fn_ptr_call = !function;
15431528

15441529
for (unsigned i = 0; i < num_named_params && i < num_args; ++i) {
15451530
auto *arg = expr->getArg(i + arg_begin);
1546-
std::string param_name = function
1547-
? function->getParamDecl(i)->getNameAsString()
1548-
: ("arg" + std::to_string(i));
1549-
clang::QualType param_type = function ? function->getParamDecl(i)->getType()
1550-
: proto->getParamType(i);
1551-
1552-
bool is_materialize_to_ref =
1553-
clang::isa<clang::MaterializeTemporaryExpr>(arg) &&
1554-
param_type->isLValueReferenceType();
1555-
1556-
if (is_materialize_to_ref) {
1557-
auto [binding, ref] =
1558-
MaterializeTemp(std::format("_{}", param_name), param_type, arg);
1559-
StrCat(binding);
1560-
temp_refs[i] = std::move(ref);
1561-
} else if (!clang::isa<clang::MaterializeTemporaryExpr>(arg)) {
1562-
StrCat("let", std::format("_{}: {}", param_name, ToString(param_type)),
1563-
"=");
1564-
convert_param_ty(param_type, arg);
1565-
StrCat(";");
1531+
CallArg ca{
1532+
.expr = arg,
1533+
.kind = Kind::Hoisted,
1534+
.param_name = function ? function->getParamDecl(i)->getNameAsString()
1535+
: ("arg" + std::to_string(i)),
1536+
.param_type = function ? function->getParamDecl(i)->getType()
1537+
: proto->getParamType(i),
1538+
.has_default = function && function->getParamDecl(i)->hasDefaultArg(),
1539+
};
1540+
bool is_materialize = clang::isa<clang::MaterializeTemporaryExpr>(arg);
1541+
if (is_materialize && ca.param_type->isLValueReferenceType()) {
1542+
ca.kind = Kind::RefTemp;
1543+
} else if (is_materialize) {
1544+
ca.kind = Kind::InlineTemp;
1545+
}
1546+
info.args.push_back(std::move(ca));
1547+
}
1548+
1549+
if (info.is_variadic) {
1550+
info.variadic_args.reserve(num_args - num_named_params);
1551+
for (unsigned i = num_named_params; i < num_args; ++i) {
1552+
info.variadic_args.push_back(expr->getArg(i + arg_begin));
15661553
}
15671554
}
15681555

1569-
if (proto && !function) {
1570-
EmitFnPtrCall(callee);
1556+
return info;
1557+
}
1558+
1559+
void Converter::ConvertParamTy(clang::QualType param_type, clang::Expr *expr) {
1560+
if (param_type->isLValueReferenceType()) {
1561+
PushExprKind push(*this, ExprKind::AddrOf);
1562+
ConvertVarInit(param_type, expr);
15711563
} else {
1572-
PushExprKind push(*this, ExprKind::Callee);
1573-
Convert(callee);
1564+
ConvertVarInit(param_type, expr);
15741565
}
1575-
{
1576-
PushParen call_args(*this);
1577-
for (unsigned i = 0; i < num_named_params && i < num_args; ++i) {
1578-
auto *arg = expr->getArg(i + arg_begin);
1579-
std::string param_name =
1580-
function ? function->getParamDecl(i)->getNameAsString()
1581-
: ("arg" + std::to_string(i));
1582-
clang::QualType param_type = function
1583-
? function->getParamDecl(i)->getType()
1584-
: proto->getParamType(i);
1585-
bool is_parm_with_default_value =
1586-
function && function->getParamDecl(i)->hasDefaultArg();
1587-
1588-
if (is_parm_with_default_value) {
1589-
StrCat("Some(");
1590-
}
1591-
if (!temp_refs[i].empty()) {
1592-
StrCat(temp_refs[i]);
1593-
} else if (clang::isa<clang::MaterializeTemporaryExpr>(arg)) {
1594-
convert_param_ty(param_type, arg);
1595-
} else {
1596-
StrCat(std::format("_{}", param_name));
1597-
}
1598-
if (is_parm_with_default_value) {
1599-
StrCat(')');
1600-
}
1601-
StrCat(token::kComma);
1566+
}
1567+
1568+
void Converter::EmitArgBindings(CallInfo &info) {
1569+
using Kind = CallArg::Kind;
1570+
for (auto &ca : info.args) {
1571+
switch (ca.kind) {
1572+
case Kind::Hoisted:
1573+
StrCat("let",
1574+
std::format("_{}: {}", ca.param_name, ToString(ca.param_type)),
1575+
"=");
1576+
ConvertParamTy(ca.param_type, ca.expr);
1577+
StrCat(";");
1578+
break;
1579+
case Kind::RefTemp: {
1580+
auto [binding, ref] = MaterializeTemp(std::format("_{}", ca.param_name),
1581+
ca.param_type, ca.expr);
1582+
StrCat(binding);
1583+
ca.ref_temp_name = std::move(ref);
1584+
break;
16021585
}
1586+
case Kind::InlineTemp:
1587+
break;
1588+
}
1589+
}
1590+
}
1591+
1592+
void Converter::EmitArgList(const CallInfo &info) {
1593+
using Kind = CallArg::Kind;
1594+
PushParen call_args(*this);
16031595

1604-
// Variadic args: wrap in &[arg.into(), ...]
1605-
if (is_variadic) {
1606-
StrCat("& [");
1607-
for (unsigned i = num_named_params; i < num_args; ++i) {
1608-
auto *arg = expr->getArg(i + arg_begin);
1609-
ConvertVariadicArg(arg);
1610-
StrCat(".into()", token::kComma);
1596+
for (const auto &ca : info.args) {
1597+
if (ca.has_default) {
1598+
StrCat("Some");
1599+
}
1600+
1601+
{
1602+
PushParen push(*this, ca.has_default);
1603+
switch (ca.kind) {
1604+
case Kind::Hoisted:
1605+
StrCat(std::format("_{}", ca.param_name));
1606+
break;
1607+
case Kind::RefTemp:
1608+
StrCat(ca.ref_temp_name);
1609+
break;
1610+
case Kind::InlineTemp:
1611+
ConvertParamTy(ca.param_type, ca.expr);
1612+
break;
16111613
}
1612-
StrCat(']');
1614+
}
1615+
1616+
StrCat(token::kComma);
1617+
}
1618+
1619+
if (info.is_variadic) {
1620+
StrCat(token::kRef);
1621+
PushBracket push(*this);
1622+
for (auto *arg : info.variadic_args) {
1623+
ConvertVariadicArg(arg);
1624+
StrCat(".into()", token::kComma);
16131625
}
16141626
}
16151627
}
16161628

1629+
void Converter::EmitCall(CallInfo info) {
1630+
EmitArgBindings(info);
1631+
1632+
if (info.is_fn_ptr_call) {
1633+
EmitFnPtrCall(info.callee);
1634+
} else {
1635+
PushExprKind push(*this, ExprKind::Callee);
1636+
Convert(info.callee);
1637+
}
1638+
1639+
EmitArgList(info);
1640+
}
1641+
1642+
void Converter::ConvertGenericCallExpr(clang::CallExpr *expr) {
1643+
PushParen outer(*this);
1644+
StrCat(keyword_unsafe_);
1645+
PushBrace unsafe_brace(*this);
1646+
EmitCall(CollectCallInfo(expr));
1647+
}
1648+
16171649
std::optional<Converter::TempMaterializationCtx>
16181650
Converter::ConvertCallExpr(clang::CallExpr *expr) {
16191651
auto *callee = expr->getCallee();

cpp2rust/converter/converter.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,39 @@ class Converter : public clang::RecursiveASTVisitor<Converter> {
217217

218218
std::optional<TempMaterializationCtx> ConvertCallExpr(clang::CallExpr *expr);
219219

220+
struct CallArg {
221+
enum class Kind {
222+
InlineTemp,
223+
Hoisted,
224+
RefTemp,
225+
};
226+
227+
clang::Expr *expr;
228+
Kind kind;
229+
std::string param_name;
230+
clang::QualType param_type;
231+
bool has_default;
232+
std::string ref_temp_name;
233+
};
234+
235+
struct CallInfo {
236+
clang::Expr *callee;
237+
bool is_variadic;
238+
bool is_fn_ptr_call;
239+
std::vector<CallArg> args;
240+
std::vector<clang::Expr *> variadic_args;
241+
};
242+
243+
CallInfo CollectCallInfo(clang::CallExpr *expr);
244+
245+
void ConvertParamTy(clang::QualType param_type, clang::Expr *expr);
246+
247+
void EmitArgBindings(CallInfo &info);
248+
249+
void EmitArgList(const CallInfo &info);
250+
251+
void EmitCall(CallInfo info);
252+
220253
void ConvertGenericCallExpr(clang::CallExpr *expr);
221254

222255
virtual void EmitFnPtrCall(clang::Expr *callee);

0 commit comments

Comments
 (0)