From cdcd3ab66cba468007c49a026f27b148760dbab6 Mon Sep 17 00:00:00 2001 From: Nicholas Bishop Date: Mon, 9 Mar 2026 10:49:31 -0400 Subject: [PATCH] Handle pack expansion for dependent non-type template params (#6850) https://github.com/carbon-language/carbon-lang/issues/6717 --- toolchain/check/cpp/call.cpp | 25 +++++++++++++------ .../cpp/template/non_type_param.carbon | 14 +++++++++++ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/toolchain/check/cpp/call.cpp b/toolchain/check/cpp/call.cpp index ed835c2093a5..558583e91129 100644 --- a/toolchain/check/cpp/call.cpp +++ b/toolchain/check/cpp/call.cpp @@ -112,7 +112,8 @@ static auto MakePlaceholderTemplateArg(Context& context, SemIR::InstId arg_id) static auto ConvertArgToTemplateArg( Context& context, clang::TemplateDecl* template_decl, clang::NamedDecl* param_decl, SemIR::InstId arg_id, - clang::SmallVector* template_args, bool diagnose) + clang::SmallVector* template_args, + unsigned argument_pack_index, bool diagnose) -> std::optional { if (isa(param_decl)) { auto type = ExprAsType(context, SemIR::LocId(arg_id), arg_id, diagnose); @@ -153,6 +154,9 @@ static auto ConvertArgToTemplateArg( if (auto* non_type = dyn_cast(param_decl)) { auto param_type = non_type->getType(); + if (non_type->isParameterPack() && non_type->isExpandedParameterPack()) { + param_type = non_type->getExpansionType(argument_pack_index); + } // Handle non-type parameters with a dependent type. For example: // @@ -179,9 +183,13 @@ static auto ConvertArgToTemplateArg( /*Final=*/true); mltal.addOuterRetainedLevels(non_type->getDepth()); - // TODO: handle pack expansion by passing in the pack index from - // `ConvertArgsToTemplateArgs`. - if (!param_type->getAs()) { + if (const auto* pet = param_type->getAs()) { + clang::Sema::ArgPackSubstIndexRAII subst_index(context.clang_sema(), + argument_pack_index); + param_type = context.clang_sema().SubstType(pet->getPattern(), mltal, + non_type->getLocation(), + non_type->getDeclName()); + } else { param_type = context.clang_sema().SubstType(param_type, mltal, non_type->getLocation(), non_type->getDeclName()); @@ -292,12 +300,13 @@ auto ConvertArgsToTemplateArgs(Context& context, llvm::ArrayRef args_for_param = param_decl->isTemplateParameterPack() ? std::exchange(arg_ids, {}) : arg_ids.consume_front(); - for (auto arg_id : args_for_param) { - if (auto arg = - ConvertArgToTemplateArg(context, template_decl, param_decl, - arg_id, &template_args, diagnose)) { + for (auto [argument_pack_index, arg_id] : llvm::enumerate(args_for_param)) { + if (auto arg = ConvertArgToTemplateArg(context, template_decl, param_decl, + arg_id, &template_args, + argument_pack_index, diagnose)) { arg_list.addArgument(*arg); template_args.push_back(arg->getArgument()); + argument_pack_index++; } else { return false; } diff --git a/toolchain/check/testdata/interop/cpp/template/non_type_param.carbon b/toolchain/check/testdata/interop/cpp/template/non_type_param.carbon index 98eb68f31229..dd55afc88103 100644 --- a/toolchain/check/testdata/interop/cpp/template/non_type_param.carbon +++ b/toolchain/check/testdata/interop/cpp/template/non_type_param.carbon @@ -164,6 +164,20 @@ var n: i32; // CHECK:STDERR: var x: Cpp.TwoNonType(1, &n); +// --- dependent_parameter_pack.carbon + +library "[[@TEST_NAME]]"; + +import Cpp inline ''' +template struct X { + template static int n; +}; +'''; + +fn G() -> i32 { + return Cpp.X(i32, i32).n(1, 2); +} + // CHECK:STDOUT: --- valid.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants {