@@ -1594,128 +1594,159 @@ void Converter::ConvertFunctionToFunctionPointer(
15941594 StrCat (std::format (" Some({})" , Mapper::MapFunctionName (fn_decl)));
15951595}
15961596
1597- void Converter::ConvertGenericCallExpr (clang::CallExpr *expr) {
1598- clang::Expr *callee = expr->getCallee ();
1599- auto convert_param_ty = [&](clang::QualType param_type, clang::Expr *expr) {
1600- if (param_type->isLValueReferenceType ()) {
1601- PushExprKind push (*this , ExprKind::AddrOf);
1602- ConvertVarInit (param_type, expr);
1603- } else {
1604- ConvertVarInit (param_type, expr);
1605- }
1606- };
1597+ Converter::CallInfo Converter::CollectCallInfo (clang::CallExpr *expr) {
1598+ using Kind = CallArg::Kind;
16071599
1608- unsigned arg_begin = 0 ; // skip count for operator()'s implicit object arg
1600+ CallInfo info;
1601+ info.callee = expr->getCallee ();
1602+ unsigned arg_begin = 0 ;
16091603 if (auto op_call = llvm::dyn_cast<clang::CXXOperatorCallExpr>(expr)) {
16101604 if (op_call->getOperator () == clang::OO_Call) {
1611- callee = op_call->getArg (0 );
1605+ info. callee = op_call->getArg (0 );
16121606 arg_begin = 1 ;
16131607 }
16141608 }
16151609
1616- PushParen outer (*this );
1617- StrCat (keyword_unsafe_);
1618- PushBrace unsafe_brace (*this );
16191610 const auto *function =
16201611 expr->getCalleeDecl () ? expr->getCalleeDecl ()->getAsFunction () : nullptr ;
16211612 const clang::FunctionProtoType *proto = nullptr ;
1622-
16231613 if (!function) {
1624- auto callee_ty = callee->getType ().getDesugaredType (ctx_);
1614+ auto callee_ty = info. callee ->getType ().getDesugaredType (ctx_);
16251615 if (auto ptr_ty = callee_ty->getAs <clang::PointerType>()) {
16261616 proto = ptr_ty->getPointeeType ()->getAs <clang::FunctionProtoType>();
16271617 }
16281618 }
1629-
16301619 assert ((function || proto) &&
16311620 " Either function decl or function prototype should be known" );
16321621
1633- auto num_args = expr->getNumArgs () - arg_begin;
1634- bool is_variadic =
1635- function ? function->isVariadic () : (proto && proto->isVariadic ());
1636- unsigned num_named_params = function
1637- ? function->getNumParams ()
1638- : (proto ? proto->getNumParams () : num_args);
1639-
1640- // Track which args are materialized temps bound to reference params
1641- std::vector<std::string> temp_refs (num_args);
1622+ unsigned num_args = expr->getNumArgs () - arg_begin;
1623+ unsigned num_named_params =
1624+ function ? function->getNumParams () : proto->getNumParams ();
1625+ info.is_variadic = function ? function->isVariadic () : proto->isVariadic ();
1626+ info.is_fn_ptr_call = !function;
16421627
16431628 for (unsigned i = 0 ; i < num_named_params && i < num_args; ++i) {
16441629 auto *arg = expr->getArg (i + arg_begin);
1645- std::string param_name = function
1646- ? function->getParamDecl (i)->getNameAsString ()
1647- : (" arg" + std::to_string (i));
1648- clang::QualType param_type = function ? function->getParamDecl (i)->getType ()
1649- : proto->getParamType (i);
1630+ CallArg ca{
1631+ .param_name = function
1632+ ? (" _" + function->getParamDecl (i)->getNameAsString ())
1633+ : (" _arg" + std::to_string (i)),
1634+ .param_type = function ? function->getParamDecl (i)->getType ()
1635+ : proto->getParamType (i),
1636+ .expr = arg,
1637+ .has_default = function && function->getParamDecl (i)->hasDefaultArg (),
1638+ .kind = Kind::Hoisted,
1639+ };
1640+ bool is_materialize = clang::isa<clang::MaterializeTemporaryExpr>(arg);
1641+ if (is_materialize && ca.param_type ->isLValueReferenceType ()) {
1642+ ca.kind = Kind::Materialized;
1643+ } else if (is_materialize) {
1644+ ca.kind = Kind::Inline;
1645+ }
1646+ info.args .push_back (std::move (ca));
1647+ }
1648+
1649+ if (info.is_variadic ) {
1650+ for (unsigned i = num_named_params; i < num_args; ++i) {
1651+ info.variadic_args .push_back (expr->getArg (i + arg_begin));
1652+ }
1653+ }
16501654
1651- bool is_materialize_to_ref =
1652- clang::isa<clang::MaterializeTemporaryExpr>(arg) &&
1653- param_type->isLValueReferenceType ();
1655+ return info;
1656+ }
16541657
1655- if (is_materialize_to_ref) {
1658+ void Converter::ConvertParamTy (clang::QualType param_type, clang::Expr *expr) {
1659+ if (param_type->isLValueReferenceType ()) {
1660+ PushExprKind push (*this , ExprKind::AddrOf);
1661+ ConvertVarInit (param_type, expr);
1662+ } else {
1663+ ConvertVarInit (param_type, expr);
1664+ }
1665+ }
1666+
1667+ void Converter::EmitHoistedArgs (CallInfo &info) {
1668+ using Kind = CallArg::Kind;
1669+ for (auto &ca : info.args ) {
1670+ switch (ca.kind ) {
1671+ case Kind::Hoisted:
1672+ StrCat (
1673+ std::format (" let {}: {} =" , ca.param_name , ToString (ca.param_type )));
1674+ ConvertParamTy (ca.param_type , ca.expr );
1675+ StrCat (" ;" );
1676+ break ;
1677+ case Kind::Materialized: {
16561678 auto [binding, ref] =
1657- MaterializeTemp (std::format ( " _{} " , param_name), param_type, arg );
1679+ MaterializeTemp (ca. param_name , ca. param_type , ca. expr );
16581680 StrCat (binding);
1659- temp_refs[i] = std::move (ref);
1660- } else if (!clang::isa<clang::MaterializeTemporaryExpr>(arg)) {
1661- StrCat (" let" , std::format (" _{}: {}" , param_name, ToString (param_type)),
1662- ' =' );
1663- convert_param_ty (param_type, arg);
1664- StrCat (' ;' );
1681+ ca.ref_temp_name = std::move (ref);
1682+ break ;
1683+ }
1684+ case Kind::Inline:
1685+ break ;
16651686 }
16661687 }
1688+ }
16671689
1668- if (proto && !function) {
1669- EmitFnPtrCall (callee);
1670- } else {
1671- PushExprKind push (*this , ExprKind::Callee);
1672- Convert (callee);
1673- }
1674- {
1675- PushParen call_args (*this );
1676- for (unsigned i = 0 ; i < num_named_params && i < num_args; ++i) {
1677- auto *arg = expr->getArg (i + arg_begin);
1678- std::string param_name =
1679- function ? function->getParamDecl (i)->getNameAsString ()
1680- : (" arg" + std::to_string (i));
1681- clang::QualType param_type = function
1682- ? function->getParamDecl (i)->getType ()
1683- : proto->getParamType (i);
1684- bool is_parm_with_default_value =
1685- function && function->getParamDecl (i)->hasDefaultArg ();
1686-
1687- if (is_parm_with_default_value) {
1688- StrCat (" Some(" );
1689- }
1690- if (!temp_refs[i].empty ()) {
1691- StrCat (temp_refs[i]);
1692- } else if (clang::isa<clang::MaterializeTemporaryExpr>(arg)) {
1693- convert_param_ty (param_type, arg);
1694- } else {
1695- StrCat (std::format (" _{}" , param_name));
1696- }
1697- if (is_parm_with_default_value) {
1698- StrCat (' )' );
1690+ void Converter::EmitArgList (const CallInfo &info) {
1691+ using Kind = CallArg::Kind;
1692+ PushParen call_args (*this );
1693+
1694+ for (const auto &ca : info.args ) {
1695+ if (ca.has_default ) {
1696+ StrCat (" Some" );
1697+ }
1698+
1699+ {
1700+ PushParen push (*this , ca.has_default );
1701+ switch (ca.kind ) {
1702+ case Kind::Hoisted:
1703+ StrCat (ca.param_name );
1704+ break ;
1705+ case Kind::Materialized:
1706+ StrCat (ca.ref_temp_name );
1707+ break ;
1708+ case Kind::Inline:
1709+ ConvertParamTy (ca.param_type , ca.expr );
1710+ break ;
16991711 }
1700- StrCat (token::kComma );
17011712 }
17021713
1703- // Variadic args: wrap in &[arg.into(), ...]
1704- if (is_variadic) {
1705- StrCat ( " & [ " );
1706- for ( unsigned i = num_named_params; i < num_args; ++i ) {
1707- auto *arg = expr-> getArg (i + arg_begin );
1708- {
1709- PushParen p (* this );
1710- ConvertVariadicArg (arg);
1711- }
1712- StrCat ( " .into() " , token:: kComma );
1714+ StrCat (token:: kComma );
1715+ }
1716+
1717+ if (info. is_variadic ) {
1718+ StrCat (token:: kRef );
1719+ PushBracket push (* this );
1720+ for ( auto *arg : info. variadic_args ) {
1721+ {
1722+ PushParen p (* this );
1723+ ConvertVariadicArg (arg );
17131724 }
1714- StrCat (' ] ' );
1725+ StrCat (" .into() " , token:: kComma );
17151726 }
17161727 }
17171728}
17181729
1730+ void Converter::EmitCall (CallInfo &&info) {
1731+ EmitHoistedArgs (info);
1732+
1733+ if (info.is_fn_ptr_call ) {
1734+ EmitFnPtrCall (info.callee );
1735+ } else {
1736+ PushExprKind push (*this , ExprKind::Callee);
1737+ Convert (info.callee );
1738+ }
1739+
1740+ EmitArgList (info);
1741+ }
1742+
1743+ void Converter::ConvertGenericCallExpr (clang::CallExpr *expr) {
1744+ PushParen outer (*this );
1745+ StrCat (keyword_unsafe_);
1746+ PushBrace unsafe_brace (*this );
1747+ EmitCall (CollectCallInfo (expr));
1748+ }
1749+
17191750std::optional<Converter::TempMaterializationCtx>
17201751Converter::ConvertCallExpr (clang::CallExpr *expr) {
17211752 auto *callee = expr->getCallee ();
0 commit comments