Unique names for parameters expanded from a template parameter pack.

Before this CL, all parameters expanded from a template parameter pack
would have the same name in the IR.

PiperOrigin-RevId: 449008529
diff --git a/rs_bindings_from_cc/importer.cc b/rs_bindings_from_cc/importer.cc
index 49c30cb..3c27643 100644
--- a/rs_bindings_from_cc/importer.cc
+++ b/rs_bindings_from_cc/importer.cc
@@ -810,12 +810,20 @@
   switch (named_decl->getDeclName().getNameKind()) {
     case clang::DeclarationName::Identifier: {
       auto name = std::string(named_decl->getName());
-      if (name.empty()) {
-        if (const clang::ParmVarDecl* param_decl =
-                clang::dyn_cast<clang::ParmVarDecl>(named_decl)) {
-          int param_pos = param_decl->getFunctionScopeIndex();
+      if (const clang::ParmVarDecl* param_decl =
+              clang::dyn_cast<clang::ParmVarDecl>(named_decl)) {
+        int param_pos = param_decl->getFunctionScopeIndex();
+        if (name.empty()) {
           return {Identifier(absl::StrCat("__param_", param_pos))};
         }
+        if (auto* sttpt = param_decl->getType()
+                              ->getAs<clang::SubstTemplateTypeParmType>();
+            sttpt && sttpt->getReplacedParameter()->isParameterPack()) {
+          // Avoid giving the same name to all parameters expanded from a pack.
+          return {Identifier(absl::StrCat("__", name, "_", param_pos))};
+        }
+      }
+      if (name.empty()) {
         // TODO(lukasza): Handle anonymous structs (probably this won't be an
         // issue until nested types are handled - b/200067824).
         return std::nullopt;
diff --git a/rs_bindings_from_cc/ir_from_cc_test.rs b/rs_bindings_from_cc/ir_from_cc_test.rs
index d978e75..0898e09 100644
--- a/rs_bindings_from_cc/ir_from_cc_test.rs
+++ b/rs_bindings_from_cc/ir_from_cc_test.rs
@@ -1066,6 +1066,53 @@
 }
 
 #[test]
+fn test_subst_template_type_parm_pack_type() -> Result<()> {
+    let ir = ir_from_cc(
+        r#" #pragma clang lifetime_elision
+            template <typename... TArgs>
+            struct MyStruct {
+                static int GetSum(TArgs... my_args) { return (0 + ... + my_args); }
+            };
+            using MyTypeAlias = MyStruct<int, int>; "#,
+    )?;
+    assert_ir_matches!(
+        ir,
+        quote! {
+          Record(Record {
+            rs_name: "__CcTemplateInst8MyStructIJiiEE", ...
+            cc_name: "MyStruct<int, int>", ...
+          }),
+        }
+    );
+    assert_ir_matches!(
+        ir,
+        quote! {
+            Func {
+                name: "GetSum", ...
+                mangled_name: "_ZN8MyStructIJiiEE6GetSumEii___test_testing_target", ...
+                params: [
+                    FuncParam {
+                        type_: MappedType {
+                            rs_type: RsType { name: Some("i32"), ...  },
+                            cc_type: CcType { name: Some("int"), ...  },
+                        },
+                        identifier: "__my_args_0",
+                    },
+                    FuncParam {
+                        type_: MappedType {
+                            rs_type: RsType { name: Some("i32"), ...  },
+                            cc_type: CcType { name: Some("int"), ...  },
+                        },
+                        identifier: "__my_args_1",
+                    },
+                ], ...
+            }
+        }
+    );
+    Ok(())
+}
+
+#[test]
 fn test_no_instantiation_of_template_only_used_in_private_field() -> Result<()> {
     let ir = ir_from_cc(
         r#" #pragma clang lifetime_elision