Skip to content

Commit bd0e046

Browse files
committed
Refactor ConvertGenericCallExpr
1 parent a41a08e commit bd0e046

2 files changed

Lines changed: 150 additions & 86 deletions

File tree

cpp2rust/converter/converter.cpp

Lines changed: 117 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1495,125 +1495,156 @@ 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::Materialized;
1543+
} else if (is_materialize) {
1544+
ca.kind = Kind::Inline;
1545+
}
1546+
info.args.push_back(std::move(ca));
1547+
}
1548+
1549+
if (info.is_variadic) {
1550+
for (unsigned i = num_named_params; i < num_args; ++i) {
1551+
info.variadic_args.push_back(expr->getArg(i + arg_begin));
15661552
}
15671553
}
15681554

1569-
if (proto && !function) {
1570-
EmitFnPtrCall(callee);
1555+
return info;
1556+
}
1557+
1558+
void Converter::ConvertParamTy(clang::QualType param_type, clang::Expr *expr) {
1559+
if (param_type->isLValueReferenceType()) {
1560+
PushExprKind push(*this, ExprKind::AddrOf);
1561+
ConvertVarInit(param_type, expr);
15711562
} else {
1572-
PushExprKind push(*this, ExprKind::Callee);
1573-
Convert(callee);
1563+
ConvertVarInit(param_type, expr);
15741564
}
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);
1565+
}
1566+
1567+
void Converter::EmitArgBindings(CallInfo &info) {
1568+
using Kind = CallArg::Kind;
1569+
for (auto &ca : info.args) {
1570+
switch (ca.kind) {
1571+
case Kind::Hoisted:
1572+
StrCat("let",
1573+
std::format("_{}: {}", ca.param_name, ToString(ca.param_type)),
1574+
"=");
1575+
ConvertParamTy(ca.param_type, ca.expr);
1576+
StrCat(";");
1577+
break;
1578+
case Kind::Materialized: {
1579+
auto [binding, ref] = MaterializeTemp(std::format("_{}", ca.param_name),
1580+
ca.param_type, ca.expr);
1581+
StrCat(binding);
1582+
ca.ref_temp_name = std::move(ref);
1583+
break;
16021584
}
1585+
case Kind::Inline:
1586+
break;
1587+
}
1588+
}
1589+
}
1590+
1591+
void Converter::EmitArgList(const CallInfo &info) {
1592+
using Kind = CallArg::Kind;
1593+
PushParen call_args(*this);
16031594

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);
1595+
for (const auto &ca : info.args) {
1596+
if (ca.has_default) {
1597+
StrCat("Some");
1598+
}
1599+
1600+
{
1601+
PushParen push(*this, ca.has_default);
1602+
switch (ca.kind) {
1603+
case Kind::Hoisted:
1604+
StrCat(std::format("_{}", ca.param_name));
1605+
break;
1606+
case Kind::Materialized:
1607+
StrCat(ca.ref_temp_name);
1608+
break;
1609+
case Kind::Inline:
1610+
ConvertParamTy(ca.param_type, ca.expr);
1611+
break;
16111612
}
1612-
StrCat(']');
1613+
}
1614+
1615+
StrCat(token::kComma);
1616+
}
1617+
1618+
if (info.is_variadic) {
1619+
StrCat(token::kRef);
1620+
PushBracket push(*this);
1621+
for (auto *arg : info.variadic_args) {
1622+
ConvertVariadicArg(arg);
1623+
StrCat(".into()", token::kComma);
16131624
}
16141625
}
16151626
}
16161627

1628+
void Converter::EmitCall(CallInfo info) {
1629+
EmitArgBindings(info);
1630+
1631+
if (info.is_fn_ptr_call) {
1632+
EmitFnPtrCall(info.callee);
1633+
} else {
1634+
PushExprKind push(*this, ExprKind::Callee);
1635+
Convert(info.callee);
1636+
}
1637+
1638+
EmitArgList(info);
1639+
}
1640+
1641+
void Converter::ConvertGenericCallExpr(clang::CallExpr *expr) {
1642+
PushParen outer(*this);
1643+
StrCat(keyword_unsafe_);
1644+
PushBrace unsafe_brace(*this);
1645+
EmitCall(CollectCallInfo(expr));
1646+
}
1647+
16171648
std::optional<Converter::TempMaterializationCtx>
16181649
Converter::ConvertCallExpr(clang::CallExpr *expr) {
16191650
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+
Hoisted,
223+
Inline,
224+
Materialized,
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)