@@ -243,11 +243,16 @@ bool Converter::VisitPointerType(clang::PointerType *type) {
243243 return false ;
244244 }
245245
246+ if (IsVaListType (ctx_, clang::QualType (type, 0 ))) {
247+ StrCat (" VaList" );
248+ return false ;
249+ }
250+
246251 StrCat (token::kStar );
247252 auto pointee_type = type->getPointeeType ();
248253 StrCat (pointee_type.isConstQualified () ? keyword::kConst : keyword_mut_);
249254 if (pointee_type->isRecordType () &&
250- abstract_structs_.contains (GetID (pointee_type->getAsCXXRecordDecl ()))) {
255+ abstract_structs_.contains (GetID (pointee_type->getAsRecordDecl ()))) {
251256 StrCat (keyword::kDyn );
252257 }
253258 return Convert (pointee_type);
@@ -352,9 +357,25 @@ bool Converter::VisitFunctionTemplateDecl(clang::FunctionTemplateDecl *decl) {
352357 return false ;
353358}
354359
360+ void Converter::ConvertVaListVarDecl (clang::VarDecl *decl) {
361+ if (clang::isa<clang::ParmVarDecl>(decl)) {
362+ // va_list parameter (decayed to __va_list_tag *)
363+ } else {
364+ // va_list local variable
365+ StrCat (keyword::kLet );
366+ }
367+ StrCat (keyword_mut_, GetNamedDeclAsString (decl), token::kColon , " VaList" );
368+ }
369+
355370bool Converter::ConvertVarDeclSkipInit (clang::VarDecl *decl) {
356371 auto qual_type = decl->getType ();
357372 auto name = GetNamedDeclAsString (decl);
373+
374+ if (IsVaListType (ctx_, qual_type) && decl->isLocalVarDecl ()) {
375+ ConvertVaListVarDecl (decl);
376+ return true ;
377+ }
378+
358379 if (decl->isFileVarDecl ()) {
359380 name = std::regex_replace (Mapper::ToString (decl), std::regex (" ::" ), " _" );
360381 if ((decl->isExternallyDeclarable () && !decl->hasInit ()) ||
@@ -1259,7 +1280,28 @@ std::optional<std::string> Converter::TryPluginConvert(clang::CallExpr *call) {
12591280 return std::nullopt ;
12601281}
12611282
1283+ void Converter::ConvertVAArgCall (clang::CallExpr *expr) {
1284+ if (IsBuiltinVaStart (expr)) {
1285+ StrCat (ToString (expr->getArg (0 )->IgnoreImpCasts ()), " = VaList::new(args)" );
1286+ return ;
1287+ }
1288+ if (IsBuiltinVaEnd (expr)) {
1289+ // va_end is a no-op
1290+ return ;
1291+ }
1292+ if (IsBuiltinVaCopy (expr)) {
1293+ StrCat (ToString (expr->getArg (0 )->IgnoreImpCasts ()), " =" ,
1294+ ToString (expr->getArg (1 )->IgnoreImpCasts ()), " .clone()" );
1295+ return ;
1296+ }
1297+ }
1298+
12621299bool Converter::VisitCallExpr (clang::CallExpr *expr) {
1300+ if (IsBuiltinVaStart (expr) || IsBuiltinVaEnd (expr) || IsBuiltinVaCopy (expr)) {
1301+ ConvertVAArgCall (expr);
1302+ return false ;
1303+ }
1304+
12631305 if (auto plugin_str = TryPluginConvert (expr)) {
12641306 StrCat (*plugin_str);
12651307 return false ;
@@ -1356,11 +1398,16 @@ void Converter::ConvertGenericCallExpr(clang::CallExpr *expr) {
13561398 " Either function decl or function prototype should be known" );
13571399
13581400 auto num_args = expr->getNumArgs () - arg_begin;
1401+ bool is_variadic =
1402+ function ? function->isVariadic () : (proto && proto->isVariadic ());
1403+ unsigned num_named_params = function
1404+ ? function->getNumParams ()
1405+ : (proto ? proto->getNumParams () : num_args);
13591406
13601407 // Track which args are materialized temps bound to reference params
13611408 std::vector<std::string> temp_refs (num_args);
13621409
1363- for (unsigned i = 0 ; i < num_args; ++i) {
1410+ for (unsigned i = 0 ; i < num_named_params && i < num_args; ++i) {
13641411 auto *arg = expr->getArg (i + arg_begin);
13651412 std::string param_name = function
13661413 ? function->getParamDecl (i)->getNameAsString ()
@@ -1387,7 +1434,7 @@ void Converter::ConvertGenericCallExpr(clang::CallExpr *expr) {
13871434
13881435 Convert (callee);
13891436 StrCat (token::kOpenParen );
1390- for (unsigned i = 0 ; i < num_args; ++i) {
1437+ for (unsigned i = 0 ; i < num_named_params && i < num_args; ++i) {
13911438 auto *arg = expr->getArg (i + arg_begin);
13921439 std::string param_name = function
13931440 ? function->getParamDecl (i)->getNameAsString ()
@@ -1412,6 +1459,18 @@ void Converter::ConvertGenericCallExpr(clang::CallExpr *expr) {
14121459 }
14131460 StrCat (token::kComma );
14141461 }
1462+
1463+ // Variadic args: wrap in &[arg.into(), ...]
1464+ if (is_variadic) {
1465+ StrCat (" & [" );
1466+ for (unsigned i = num_named_params; i < num_args; ++i) {
1467+ auto *arg = expr->getArg (i + arg_begin);
1468+ Convert (arg);
1469+ StrCat (" .into()" , token::kComma );
1470+ }
1471+ StrCat (" ]" );
1472+ }
1473+
14151474 StrCat (token::kCloseParen );
14161475 StrCat (token::kCloseCurlyBracket );
14171476 StrCat (token::kCloseParen );
@@ -1561,6 +1620,11 @@ bool Converter::VisitImplicitCastExpr(clang::ImplicitCastExpr *expr) {
15611620 clang::isa<clang::PredefinedExpr>(sub_expr)) {
15621621 return Convert (sub_expr);
15631622 }
1623+ // __va_list_tag [1] decays to __va_list_tag *. Just pass through by value
1624+ if (IsVaListType (ctx_, sub_expr->getType ())) {
1625+ Convert (sub_expr);
1626+ break ;
1627+ }
15641628 Convert (sub_expr);
15651629 if (sub_expr->getType ().isConstQualified ()) {
15661630 StrCat (keyword_ptr_decay_const_);
@@ -2209,6 +2273,18 @@ bool Converter::VisitCXXNullPtrLiteralExpr(clang::CXXNullPtrLiteralExpr *expr) {
22092273 return false ;
22102274}
22112275
2276+ bool Converter::VisitVAArgExpr (clang::VAArgExpr *expr) {
2277+ auto va_list_expr = expr->getSubExpr ();
2278+ if (auto *cast = clang::dyn_cast<clang::ImplicitCastExpr>(va_list_expr)) {
2279+ va_list_expr = cast->getSubExpr ();
2280+ }
2281+ Convert (va_list_expr);
2282+ StrCat (" .arg::<" );
2283+ Convert (expr->getType ());
2284+ StrCat (" >()" );
2285+ return false ;
2286+ }
2287+
22122288bool Converter::VisitGNUNullExpr (clang::GNUNullExpr *expr) {
22132289 StrCat (keyword_default_);
22142290 computed_expr_type_ = ComputedExprType::FreshPointer;
@@ -2807,6 +2883,9 @@ void Converter::ConvertFunctionParameters(clang::FunctionDecl *decl) {
28072883 ConvertVarDeclSkipInit (parameter);
28082884 StrCat (token::kComma );
28092885 }
2886+ if (decl->isVariadic ()) {
2887+ StrCat (" args: &[VaArg]" , token::kComma );
2888+ }
28102889 in_function_formals_ = false ;
28112890}
28122891
0 commit comments