@@ -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+
16171648std::optional<Converter::TempMaterializationCtx>
16181649Converter::ConvertCallExpr (clang::CallExpr *expr) {
16191650 auto *callee = expr->getCallee ();
0 commit comments