https://github.com/fscheidl updated 
https://github.com/llvm/llvm-project/pull/183504

>From 50546d2c0cd9474cf34da269c0f6ebc8e4de6200 Mon Sep 17 00:00:00 2001
From: Fabian Scheidl <[email protected]>
Date: Sun, 1 Mar 2026 19:01:25 +0100
Subject: [PATCH 1/3] [[libclang] Add functions to query template parameters
 and fix parameter pack handling

---
 clang/bindings/python/clang/cindex.py         |  29 ++++
 .../python/tests/cindex/test_cursor.py        | 121 ++++++++++++++++
 clang/docs/ReleaseNotes.rst                   |   6 +
 clang/include/clang-c/Index.h                 |  58 +++++++-
 clang/test/Index/template-parameters.cpp      |  14 ++
 clang/tools/c-index-test/c-index-test.c       |   9 +-
 clang/tools/libclang/CXCursor.cpp             | 135 ++++++++++++++----
 clang/tools/libclang/libclang.map             |   4 +
 8 files changed, 342 insertions(+), 34 deletions(-)
 create mode 100644 clang/test/Index/template-parameters.cpp

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index b71f9ed2275e0..83daebb1d18ab 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -2277,6 +2277,31 @@ def get_template_argument_unsigned_value(self, num: int) 
-> int:
         """Returns the value of the indicated arg as an unsigned 64b 
integer."""
         return conf.lib.clang_Cursor_getTemplateArgumentUnsignedValue(self, 
num)  # type: ignore [no-any-return]
 
+    @cursor_null_guard
+    def get_template_argument_integral_type(self, num: int) -> Type:
+        """Returns the type of an integral template argument at the given 
index."""
+        return Type.from_result(
+            conf.lib.clang_Cursor_getTemplateArgumentIntegralType(self, num), 
self
+        )
+
+    @cursor_null_guard
+    def get_num_template_parameters(self) -> int:
+        """Returns the number of template parameters, or -1 if not a 
template."""
+        return conf.lib.clang_Cursor_getNumTemplateParameters(self)  # type: 
ignore [no-any-return]
+
+    @cursor_null_guard
+    def get_template_parameter(self, num: int) -> Cursor:
+        """Returns the template parameter at the given index.
+
+        If the index is out of range, a null cursor is returned
+        """
+        return conf.lib.clang_Cursor_getTemplateParameter(self, num)  # type: 
ignore [no-any-return]
+
+    @cursor_null_guard
+    def is_template_parameter_pack(self) -> bool:
+        """Returns True if the cursor is a template parameter pack."""
+        return bool(conf.lib.clang_Cursor_isTemplateParameterPack(self))
+
     @cursor_null_guard
     def get_children(self) -> Iterator[Cursor]:
         """Return an iterator for accessing the children of this cursor."""
@@ -4483,6 +4508,10 @@ def set_property(self, property, value):
     ("clang_Cursor_getTemplateArgumentType", [Cursor, c_uint], Type),
     ("clang_Cursor_getTemplateArgumentValue", [Cursor, c_uint], c_longlong),
     ("clang_Cursor_getTemplateArgumentUnsignedValue", [Cursor, c_uint], 
c_ulonglong),
+    ("clang_Cursor_getTemplateArgumentIntegralType", [Cursor, c_uint], Type),
+    ("clang_Cursor_getNumTemplateParameters", [Cursor], c_int),
+    ("clang_Cursor_getTemplateParameter", [Cursor, c_uint], Cursor),
+    ("clang_Cursor_isTemplateParameterPack", [Cursor], c_uint),
     ("clang_getCursorBinaryOperatorKind", [Cursor], c_int),
     ("clang_Cursor_getBriefCommentText", [Cursor], _CXString),
     ("clang_Cursor_getRawCommentText", [Cursor], _CXString),
diff --git a/clang/bindings/python/tests/cindex/test_cursor.py 
b/clang/bindings/python/tests/cindex/test_cursor.py
index 76680e576b307..7304e2702205e 100644
--- a/clang/bindings/python/tests/cindex/test_cursor.py
+++ b/clang/bindings/python/tests/cindex/test_cursor.py
@@ -916,6 +916,127 @@ def test_get_template_argument_unsigned_value(self):
         self.assertEqual(foos[1].get_template_argument_unsigned_value(0), 
2**32 - 7)
         self.assertEqual(foos[1].get_template_argument_unsigned_value(2), True)
 
+    def test_get_template_argument_integral_type(self):
+        tu = get_tu(TEMPLATE_ARG_TEST, lang="cpp")
+        foos = get_cursors(tu, "foo")
+
+        self.assertEqual(
+            foos[1].get_template_argument_integral_type(0).kind, TypeKind.INT
+        )
+        self.assertEqual(
+            foos[1].get_template_argument_integral_type(1).kind,
+            TypeKind.INVALID,
+        )
+        self.assertEqual(
+            foos[1].get_template_argument_integral_type(2).kind, TypeKind.BOOL
+        )
+
+    def test_get_template_argument_integral_type_pack(self):
+        source = """
+            template<int... Ns> struct Foo {};
+            template class Foo<1, 2, 3>;
+        """
+        tu = get_tu(source, lang="cpp")
+        foos = get_cursors(tu, "Foo")
+        spec = foos[1]
+        self.assertEqual(spec.kind, CursorKind.STRUCT_DECL)
+        self.assertEqual(spec.get_num_template_arguments(), 3)
+        self.assertEqual(spec.get_template_argument_integral_type(0).kind, 
TypeKind.INT)
+        self.assertEqual(spec.get_template_argument_integral_type(1).kind, 
TypeKind.INT)
+        self.assertEqual(spec.get_template_argument_integral_type(2).kind, 
TypeKind.INT)
+
+    def test_get_num_template_parameters(self):
+        source = "template<typename T, int N> void foo(); template<typename... 
Ts> void bar(); void baz();"
+        tu = get_tu(source, lang="cpp")
+        foo = get_cursor(tu, "foo")
+        bar = get_cursor(tu, "bar")
+        baz = get_cursor(tu, "baz")
+        self.assertIsNotNone(foo)
+        self.assertIsNotNone(bar)
+        self.assertIsNotNone(baz)
+
+        self.assertEqual(foo.get_num_template_parameters(), 2)
+        self.assertEqual(bar.get_num_template_parameters(), 1)
+        self.assertEqual(baz.get_num_template_parameters(), -1)
+
+    def test_get_template_parameter(self):
+        source = "template<typename T, int N> void foo();"
+        tu = get_tu(source, lang="cpp")
+        foo = get_cursor(tu, "foo")
+        self.assertIsNotNone(foo)
+
+        t_param = foo.get_template_parameter(0)
+        n_param = foo.get_template_parameter(1)
+        self.assertEqual(t_param.kind, CursorKind.TEMPLATE_TYPE_PARAMETER)
+        self.assertEqual(t_param.spelling, "T")
+        self.assertEqual(n_param.kind, CursorKind.TEMPLATE_NON_TYPE_PARAMETER)
+        self.assertEqual(n_param.spelling, "N")
+        oob = foo.get_template_parameter(2)
+        self.assertTrue(oob.is_null())
+
+    def test_is_template_parameter_pack(self):
+        # Type parameter pack
+        source = "template<typename T, typename... Ts> void foo();"
+        tu = get_tu(source, lang="cpp")
+        foo = get_cursor(tu, "foo")
+        self.assertIsNotNone(foo)
+        
self.assertFalse(foo.get_template_parameter(0).is_template_parameter_pack())
+        
self.assertTrue(foo.get_template_parameter(1).is_template_parameter_pack())
+
+        # Non-type parameter pack
+        source = "template<int... Ns> void bar();"
+        tu = get_tu(source, lang="cpp")
+        bar = get_cursor(tu, "bar")
+        self.assertIsNotNone(bar)
+        
self.assertTrue(bar.get_template_parameter(0).is_template_parameter_pack())
+
+        # Template template parameter pack
+        source = "template<template<typename> class... Ts> void baz();"
+        tu = get_tu(source, lang="cpp")
+        baz = get_cursor(tu, "baz")
+        self.assertIsNotNone(baz)
+        
self.assertTrue(baz.get_template_parameter(0).is_template_parameter_pack())
+
+    def test_get_template_argument_variadic(self):
+        source = """
+            template<typename T, typename... Ts> struct Foo {};
+            Foo<int, float, double> x;
+            Foo<int> y;
+        """
+        tu = get_tu(source, lang="cpp")
+
+        x = get_cursor(tu, "x")
+        self.assertIsNotNone(x)
+        x_type = x.type.get_declaration()
+        self.assertEqual(x_type.get_num_template_arguments(), 3)
+        self.assertEqual(x_type.get_template_argument_type(0).kind, 
TypeKind.INT)
+        self.assertEqual(x_type.get_template_argument_type(1).kind, 
TypeKind.FLOAT)
+        self.assertEqual(x_type.get_template_argument_type(2).kind, 
TypeKind.DOUBLE)
+        self.assertEqual(x_type.get_template_argument_type(3).kind, 
TypeKind.INVALID)
+
+        # Empty pack: only T=int, pack contributes 0.
+        y = get_cursor(tu, "y")
+        self.assertIsNotNone(y)
+        y_type = y.type.get_declaration()
+        self.assertEqual(y_type.get_num_template_arguments(), 1)
+
+    def test_get_num_template_arguments_method(self):
+        source = """
+            struct S {
+                template<typename U> void method(U) {}
+            };
+            void use() { S().method(42); }
+        """
+        tu = get_tu(source, lang="cpp")
+        methods = get_cursors(tu, "method")
+        call_expr = methods[1]
+        self.assertEqual(call_expr.kind, CursorKind.CALL_EXPR)
+        method_spec = call_expr.referenced
+        self.assertIsNotNone(method_spec)
+        self.assertEqual(method_spec.kind, CursorKind.CXX_METHOD)
+        self.assertEqual(method_spec.get_num_template_arguments(), 1)
+        self.assertEqual(method_spec.get_template_argument_type(0).kind, 
TypeKind.INT)
+
     def test_referenced(self):
         tu = get_tu("void foo(); void bar() { foo(); }")
         foo = get_cursor(tu, "foo")
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 2da7175b51ea3..063d648972294 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -583,6 +583,10 @@ libclang
 - Visit switch initializer statements 
(https://bugs.kde.org/show_bug.cgi?id=415537#c2)
 - Fix crash in clang_getBinaryOperatorKindSpelling and 
clang_getUnaryOperatorKindSpelling
 - The clang_Module_getASTFile API is deprecated and now always returns nullptr
+- Added ``clang_Cursor_getNumTemplateParameters``, 
``clang_Cursor_getTemplateParameter``,
+  ``clang_Cursor_isTemplateParameterPack``, and 
``clang_Cursor_getTemplateArgumentIntegralType``.
+- Fixed ``clang_Cursor_getNumTemplateArguments`` and related APIs to work with
+  ``CXCursor_CXXMethod`` cursors and to correctly allow indexing into 
parameter pack arguments.
 
 Code Completion
 ---------------
@@ -623,6 +627,8 @@ Python Binding Changes
   so it can be used the same as ``CodeCompletionResults.results``.
 - Added a new helper method ``get_clang_version`` to the class ``Config`` to
   read the version string of the libclang in use.
+- Added ``Cursor.get_num_template_parameters``, 
``Cursor.get_template_parameter``,
+  ``Cursor.is_template_parameter_pack``, and 
``Cursor.get_template_argument_integral_type``.
 
 OpenMP Support
 --------------
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index dcf1f4f1b4258..d2f4e6e10dacd 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -3267,7 +3267,29 @@ CINDEX_LINKAGE CXType 
clang_Cursor_getTemplateArgumentType(CXCursor C,
                                                            unsigned I);
 
 /**
- * Retrieve the value of an Integral TemplateArgument (of a function
+ * Retrieve the type of an Integral TemplateArgument at a given index.
+ *
+ * For example, for:
+ *   template <typename T, int N>
+ *   void foo() {}
+ *
+ *   template <>
+ *   void foo<float, 42>();
+ *
+ * If called with I = 1, the type "int" will be returned (the type of the
+ * integral argument 42). An invalid type is returned if the argument at
+ * index I is not integral, or if the index is out of range.
+ *
+ * \param C a cursor representing a template specialization.
+ * \param I the zero-based index of the template argument.
+ *
+ * \returns the type of the integral template argument, or an invalid type.
+ */
+CINDEX_LINKAGE CXType clang_Cursor_getTemplateArgumentIntegralType(CXCursor C,
+                                                                   unsigned I);
+
+/**
+ * Retrieve the value of an Integral TemplateArgument (of a function or class
  *  decl representing a template specialization) as a signed long long.
  *
  * It is undefined to call this function on a CXCursor that does not represent 
a
@@ -3288,7 +3310,7 @@ CINDEX_LINKAGE long long 
clang_Cursor_getTemplateArgumentValue(CXCursor C,
                                                                unsigned I);
 
 /**
- * Retrieve the value of an Integral TemplateArgument (of a function
+ * Retrieve the value of an Integral TemplateArgument (of a function or class
  *  decl representing a template specialization) as an unsigned long long.
  *
  * It is undefined to call this function on a CXCursor that does not represent 
a
@@ -3308,6 +3330,38 @@ CINDEX_LINKAGE long long 
clang_Cursor_getTemplateArgumentValue(CXCursor C,
 CINDEX_LINKAGE unsigned long long
 clang_Cursor_getTemplateArgumentUnsignedValue(CXCursor C, unsigned I);
 
+/**
+ * Retrieve the number of template parameters on a template declaration.
+ *
+ * \param C a cursor representing a class template or function template.
+ *
+ * \returns the number of template parameters, or -1 if the cursor does not
+ * represent a template.
+ */
+CINDEX_LINKAGE int clang_Cursor_getNumTemplateParameters(CXCursor C);
+
+/**
+ * Retrieve a template parameter at the given index.
+ *
+ * \param C a cursor representing a class template or function template.
+ * \param I the zero-based index of the template parameter.
+ *
+ * \returns a cursor for the template parameter, or a null cursor if the
+ * index is out of range or the cursor is not a template.
+ */
+CINDEX_LINKAGE CXCursor clang_Cursor_getTemplateParameter(CXCursor C,
+                                                          unsigned I);
+
+/**
+ * Determine whether a template parameter is a parameter pack.
+ *
+ * \param C a cursor representing a template type parameter, non-type
+ * template parameter, or template template parameter.
+ *
+ * \returns non-zero if the template parameter is a parameter pack.
+ */
+CINDEX_LINKAGE unsigned clang_Cursor_isTemplateParameterPack(CXCursor C);
+
 /**
  * Determine whether two CXTypes represent the same type.
  *
diff --git a/clang/test/Index/template-parameters.cpp 
b/clang/test/Index/template-parameters.cpp
new file mode 100644
index 0000000000000..b78e850de59e2
--- /dev/null
+++ b/clang/test/Index/template-parameters.cpp
@@ -0,0 +1,14 @@
+// Test template argument pack expansion.
+// RUN: c-index-test -test-load-source all -fno-delayed-template-parsing %s | 
FileCheck %s
+
+template<typename T, typename... Ts>
+struct Variadic {};
+
+template class Variadic<int, float, double>;
+template class Variadic<int>;
+
+// Pack with 3 args: should report 3 (not 2).
+// CHECK: StructDecl=Variadic:7:16 (Definition) [Specialization of 
Variadic:5:8] [Template arg 0: kind: 1, type: int] [Template arg 1: kind: 1, 
type: float] [Template arg 2: kind: 1, type: double]
+
+// Empty pack: should report 1 (just T, pack contributes 0).
+// CHECK: StructDecl=Variadic:8:16 (Definition) [Specialization of 
Variadic:5:8] [Template arg 0: kind: 1, type: int]
diff --git a/clang/tools/c-index-test/c-index-test.c 
b/clang/tools/c-index-test/c-index-test.c
index 4b3e105aa7aff..6f71c16f58deb 100644
--- a/clang/tools/c-index-test/c-index-test.c
+++ b/clang/tools/c-index-test/c-index-test.c
@@ -1054,10 +1054,11 @@ static void PrintCursor(CXCursor Cursor, const char 
*CommentSchemaFile) {
              clang_getCString(Name), line, column);
       clang_disposeString(Name);
 
-      if (Cursor.kind == CXCursor_FunctionDecl
-          || Cursor.kind == CXCursor_StructDecl
-          || Cursor.kind == CXCursor_ClassDecl
-          || Cursor.kind == CXCursor_ClassTemplatePartialSpecialization) {
+      if (Cursor.kind == CXCursor_FunctionDecl ||
+          Cursor.kind == CXCursor_CXXMethod ||
+          Cursor.kind == CXCursor_StructDecl ||
+          Cursor.kind == CXCursor_ClassDecl ||
+          Cursor.kind == CXCursor_ClassTemplatePartialSpecialization) {
         /* Collect the template parameter kinds from the base template. */
         int NumTemplateArgs = clang_Cursor_getNumTemplateArguments(Cursor);
         int I;
diff --git a/clang/tools/libclang/CXCursor.cpp 
b/clang/tools/libclang/CXCursor.cpp
index d31d2c0c9bb67..a60b26590a724 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -1439,29 +1439,40 @@ CXCursor clang_Cursor_getArgument(CXCursor C, unsigned 
i) {
 
 int clang_Cursor_getNumTemplateArguments(CXCursor C) {
   CXCursorKind kind = clang_getCursorKind(C);
-  if (kind != CXCursor_FunctionDecl && kind != CXCursor_StructDecl &&
-      kind != CXCursor_ClassDecl &&
+  if (kind != CXCursor_FunctionDecl && kind != CXCursor_CXXMethod &&
+      kind != CXCursor_StructDecl && kind != CXCursor_ClassDecl &&
       kind != CXCursor_ClassTemplatePartialSpecialization) {
     return -1;
   }
 
-  if (const auto *FD =
-          llvm::dyn_cast_if_present<clang::FunctionDecl>(getCursorDecl(C))) {
+  const TemplateArgumentList *TAL = nullptr;
+
+  if (const auto *FD = dyn_cast_if_present<FunctionDecl>(getCursorDecl(C))) {
     const FunctionTemplateSpecializationInfo *SpecInfo =
         FD->getTemplateSpecializationInfo();
     if (!SpecInfo) {
       return -1;
     }
-    return SpecInfo->TemplateArguments->size();
+    TAL = SpecInfo->TemplateArguments;
   }
 
-  if (const auto *SD =
-          llvm::dyn_cast_if_present<clang::ClassTemplateSpecializationDecl>(
-              getCursorDecl(C))) {
-    return SD->getTemplateArgs().size();
+  if (!TAL) {
+    if (const auto *SD = dyn_cast_if_present<ClassTemplateSpecializationDecl>(
+            getCursorDecl(C))) {
+      TAL = &SD->getTemplateArgs();
+    }
   }
 
-  return -1;
+  if (!TAL)
+    return -1;
+
+  unsigned ArgCount = TAL->size();
+  for (unsigned i = 0; i < TAL->size(); i++) {
+    const TemplateArgument &Arg = TAL->get(i);
+    if (Arg.getKind() == TemplateArgument::Pack)
+      ArgCount += Arg.pack_size() - 1;
+  }
+  return ArgCount;
 }
 
 enum CXGetTemplateArgumentStatus {
@@ -1486,14 +1497,15 @@ enum CXGetTemplateArgumentStatus {
 static int clang_Cursor_getTemplateArgument(CXCursor C, unsigned I,
                                             TemplateArgument *TA) {
   CXCursorKind kind = clang_getCursorKind(C);
-  if (kind != CXCursor_FunctionDecl && kind != CXCursor_StructDecl &&
-      kind != CXCursor_ClassDecl &&
+  if (kind != CXCursor_FunctionDecl && kind != CXCursor_CXXMethod &&
+      kind != CXCursor_StructDecl && kind != CXCursor_ClassDecl &&
       kind != CXCursor_ClassTemplatePartialSpecialization) {
     return -1;
   }
 
-  if (const auto *FD =
-          llvm::dyn_cast_if_present<clang::FunctionDecl>(getCursorDecl(C))) {
+  const TemplateArgumentList *TAL = nullptr;
+
+  if (const auto *FD = dyn_cast_if_present<FunctionDecl>(getCursorDecl(C))) {
 
     const FunctionTemplateSpecializationInfo *SpecInfo =
         FD->getTemplateSpecializationInfo();
@@ -1501,26 +1513,38 @@ static int clang_Cursor_getTemplateArgument(CXCursor C, 
unsigned I,
       return CXGetTemplateArgumentStatus_NullTemplSpecInfo;
     }
 
-    if (I >= SpecInfo->TemplateArguments->size()) {
-      return CXGetTemplateArgumentStatus_InvalidIndex;
-    }
-
-    *TA = SpecInfo->TemplateArguments->get(I);
-    return 0;
+    TAL = SpecInfo->TemplateArguments;
   }
 
-  if (const auto *SD =
-          llvm::dyn_cast_if_present<clang::ClassTemplateSpecializationDecl>(
-              getCursorDecl(C))) {
-    if (I >= SD->getTemplateArgs().size()) {
-      return CXGetTemplateArgumentStatus_InvalidIndex;
+  if (!TAL) {
+    if (const auto *SD = dyn_cast_if_present<ClassTemplateSpecializationDecl>(
+            getCursorDecl(C))) {
+      TAL = &SD->getTemplateArgs();
     }
+  }
 
-    *TA = SD->getTemplateArgs()[I];
-    return 0;
+  if (!TAL)
+    return CXGetTemplateArgumentStatus_BadDeclCast;
+
+  unsigned current = 0;
+  for (unsigned i = 0; i < TAL->size(); i++) {
+    const auto &TACand = TAL->get(i);
+    if (TACand.getKind() == TemplateArgument::Pack) {
+      if (I < current + TACand.pack_size()) {
+        *TA = TACand.pack_elements()[I - current];
+        return 0;
+      }
+      current += TACand.pack_size();
+      continue;
+    }
+    if (current == I) {
+      *TA = TACand;
+      return 0;
+    }
+    current++;
   }
 
-  return CXGetTemplateArgumentStatus_BadDeclCast;
+  return CXGetTemplateArgumentStatus_InvalidIndex;
 }
 
 enum CXTemplateArgumentKind clang_Cursor_getTemplateArgumentKind(CXCursor C,
@@ -1604,6 +1628,61 @@ unsigned long long 
clang_Cursor_getTemplateArgumentUnsignedValue(CXCursor C,
   return TA.getAsIntegral().getZExtValue();
 }
 
+CXType clang_Cursor_getTemplateArgumentIntegralType(CXCursor C, unsigned I) {
+  TemplateArgument TA;
+  if (clang_Cursor_getTemplateArgument(C, I, &TA))
+    return cxtype::MakeCXType(QualType(), getCursorTU(C));
+
+  if (TA.getKind() != TemplateArgument::Integral)
+    return cxtype::MakeCXType(QualType(), getCursorTU(C));
+
+  return cxtype::MakeCXType(TA.getIntegralType(), getCursorTU(C));
+}
+
+int clang_Cursor_getNumTemplateParameters(CXCursor C) {
+  CXCursorKind kind = clang_getCursorKind(C);
+  if (kind != CXCursor_ClassTemplate && kind != CXCursor_FunctionTemplate)
+    return -1;
+
+  const Decl *D = getCursorDecl(C);
+  if (const auto *CTD = dyn_cast_if_present<ClassTemplateDecl>(D))
+    return CTD->getTemplateParameters()->size();
+  if (const auto *FTD = dyn_cast_if_present<FunctionTemplateDecl>(D))
+    return FTD->getTemplateParameters()->size();
+
+  return -1;
+}
+
+CXCursor clang_Cursor_getTemplateParameter(CXCursor C, unsigned I) {
+  CXCursorKind kind = clang_getCursorKind(C);
+  if (kind != CXCursor_ClassTemplate && kind != CXCursor_FunctionTemplate)
+    return clang_getNullCursor();
+
+  const Decl *D = getCursorDecl(C);
+  const TemplateParameterList *TPL = nullptr;
+  if (const auto *CTD = dyn_cast_if_present<ClassTemplateDecl>(D))
+    TPL = CTD->getTemplateParameters();
+  else if (const auto *FTD = dyn_cast_if_present<FunctionTemplateDecl>(D))
+    TPL = FTD->getTemplateParameters();
+
+  if (!TPL || I >= TPL->size())
+    return clang_getNullCursor();
+
+  const NamedDecl *ND = TPL->getParam(I);
+  return MakeCXCursor(ND, getCursorTU(C));
+}
+
+unsigned clang_Cursor_isTemplateParameterPack(CXCursor C) {
+  const Decl *D = getCursorDecl(C);
+  if (const auto *TTPD = dyn_cast_if_present<TemplateTypeParmDecl>(D))
+    return TTPD->isParameterPack();
+  if (const auto *NTTPD = dyn_cast_if_present<NonTypeTemplateParmDecl>(D))
+    return NTTPD->isParameterPack();
+  if (const auto *TTPD = dyn_cast_if_present<TemplateTemplateParmDecl>(D))
+    return TTPD->isParameterPack();
+  return 0;
+}
+
 
//===----------------------------------------------------------------------===//
 // CXCursorSet.
 
//===----------------------------------------------------------------------===//
diff --git a/clang/tools/libclang/libclang.map 
b/clang/tools/libclang/libclang.map
index 2691602d432f6..e1fe6064dd730 100644
--- a/clang/tools/libclang/libclang.map
+++ b/clang/tools/libclang/libclang.map
@@ -460,6 +460,10 @@ LLVM_21 {
 LLVM_23 {
   global:
     clang_ModuleCache_prune;
+    clang_Cursor_getNumTemplateParameters;
+    clang_Cursor_getTemplateParameter;
+    clang_Cursor_getTemplateArgumentIntegralType;
+    clang_Cursor_isTemplateParameterPack;
 };
 
 # Example of how to add a new symbol version entry.  If you do add a new symbol

>From 48042ba8e3b7e21029ca7516b0566bf3599008ec Mon Sep 17 00:00:00 2001
From: Fabian Scheidl <[email protected]>
Date: Tue, 7 Apr 2026 17:33:29 +0200
Subject: [PATCH 2/3] [libclang] Rename to getConstantTemplateArgumentType, add
 variable template support

- Rename getIntegralType API to getConstantTemplateArgumentType
- Add variable template specialization support
- Fix Python null cursor handling
---
 clang/bindings/python/clang/cindex.py         |  32 ++++--
 .../python/tests/cindex/test_cursor.py        |  96 ++++++++++++++--
 clang/bindings/python/tests/cindex/util.py    |   3 +-
 clang/docs/ReleaseNotes.rst                   |  33 +++++-
 clang/include/clang-c/Index.h                 | 107 +++++++++++++-----
 clang/lib/Sema/SemaCodeComplete.cpp           |   5 +
 clang/test/Index/template-parameters.cpp      |  36 ++++++
 clang/tools/c-index-test/c-index-test.c       |   4 +-
 clang/tools/libclang/CIndex.cpp               |   4 +
 clang/tools/libclang/CIndexCXX.cpp            |  22 +++-
 clang/tools/libclang/CXCursor.cpp             |  86 ++++++++++----
 clang/tools/libclang/libclang.map             |   2 +-
 12 files changed, 344 insertions(+), 86 deletions(-)

diff --git a/clang/bindings/python/clang/cindex.py 
b/clang/bindings/python/clang/cindex.py
index 83daebb1d18ab..39027d3bbc6f6 100644
--- a/clang/bindings/python/clang/cindex.py
+++ b/clang/bindings/python/clang/cindex.py
@@ -1575,6 +1575,10 @@ def is_unexposed(self):
     FRIEND_DECL = 603
     # A concept declaration
     CONCEPT_DECL = 604
+    # A C++ variable template declaration
+    VAR_TEMPLATE = 605
+    # A C++ variable template partial specialization
+    VAR_TEMPLATE_PARTIAL_SPECIALIZATION = 606
 
     # A code completion overload candidate.
     OVERLOAD_CANDIDATE = 700
@@ -2278,24 +2282,32 @@ def get_template_argument_unsigned_value(self, num: 
int) -> int:
         return conf.lib.clang_Cursor_getTemplateArgumentUnsignedValue(self, 
num)  # type: ignore [no-any-return]
 
     @cursor_null_guard
-    def get_template_argument_integral_type(self, num: int) -> Type:
-        """Returns the type of an integral template argument at the given 
index."""
+    def get_constant_template_argument_type(self, num: int) -> Type:
+        """Returns the type of a constant template argument at the given index.
+
+        Returns an invalid Type if the argument is not a constant template
+        argument, the index is out of range, or the cursor is not a template
+        specialization.
+        """
         return Type.from_result(
-            conf.lib.clang_Cursor_getTemplateArgumentIntegralType(self, num), 
self
+            conf.lib.clang_Cursor_getConstantTemplateArgumentType(self, num), 
self
         )
 
     @cursor_null_guard
     def get_num_template_parameters(self) -> int:
-        """Returns the number of template parameters, or -1 if not a 
template."""
+        """Returns the number of template parameters, or -1 if the cursor does
+        not represent a template.
+        """
         return conf.lib.clang_Cursor_getNumTemplateParameters(self)  # type: 
ignore [no-any-return]
 
     @cursor_null_guard
-    def get_template_parameter(self, num: int) -> Cursor:
-        """Returns the template parameter at the given index.
-
-        If the index is out of range, a null cursor is returned
+    def get_template_parameter(self, num: int) -> Cursor | None:
+        """Returns the template parameter at the given index, or None if the
+        index is out of range or the cursor is not a template.
         """
-        return conf.lib.clang_Cursor_getTemplateParameter(self, num)  # type: 
ignore [no-any-return]
+        return Cursor.from_cursor_result(
+            conf.lib.clang_Cursor_getTemplateParameter(self, num), self
+        )
 
     @cursor_null_guard
     def is_template_parameter_pack(self) -> bool:
@@ -4508,7 +4520,7 @@ def set_property(self, property, value):
     ("clang_Cursor_getTemplateArgumentType", [Cursor, c_uint], Type),
     ("clang_Cursor_getTemplateArgumentValue", [Cursor, c_uint], c_longlong),
     ("clang_Cursor_getTemplateArgumentUnsignedValue", [Cursor, c_uint], 
c_ulonglong),
-    ("clang_Cursor_getTemplateArgumentIntegralType", [Cursor, c_uint], Type),
+    ("clang_Cursor_getConstantTemplateArgumentType", [Cursor, c_uint], Type),
     ("clang_Cursor_getNumTemplateParameters", [Cursor], c_int),
     ("clang_Cursor_getTemplateParameter", [Cursor, c_uint], Cursor),
     ("clang_Cursor_isTemplateParameterPack", [Cursor], c_uint),
diff --git a/clang/bindings/python/tests/cindex/test_cursor.py 
b/clang/bindings/python/tests/cindex/test_cursor.py
index 7304e2702205e..8773dacc3389f 100644
--- a/clang/bindings/python/tests/cindex/test_cursor.py
+++ b/clang/bindings/python/tests/cindex/test_cursor.py
@@ -916,22 +916,40 @@ def test_get_template_argument_unsigned_value(self):
         self.assertEqual(foos[1].get_template_argument_unsigned_value(0), 
2**32 - 7)
         self.assertEqual(foos[1].get_template_argument_unsigned_value(2), True)
 
-    def test_get_template_argument_integral_type(self):
-        tu = get_tu(TEMPLATE_ARG_TEST, lang="cpp")
+    def test_get_constant_template_argument_type(self):
+        source = """
+            template<typename T, int N> void foo();
+            template<> void foo<float, -7>();
+            int g;
+            template<int* P> void bar();
+            template<> void bar<&g>();
+            template<int* Q> void baz();
+            template<> void baz<nullptr>();
+            template<float F> void bax();
+            template<> void bax<3.14f>();
+        """
+        tu = get_tu(source, lang="cpp", flags=["-std=c++20"])
         foos = get_cursors(tu, "foo")
-
         self.assertEqual(
-            foos[1].get_template_argument_integral_type(0).kind, TypeKind.INT
+            foos[1].get_constant_template_argument_type(0).kind, TypeKind.INT
+        )
+        self.assertEqual(
+            foos[1].get_constant_template_argument_type(1).kind, 
TypeKind.INVALID
+        )
+        bars = get_cursors(tu, "bar")
+        self.assertEqual(
+            bars[1].get_constant_template_argument_type(0).kind, 
TypeKind.POINTER
         )
+        bazs = get_cursors(tu, "baz")
         self.assertEqual(
-            foos[1].get_template_argument_integral_type(1).kind,
-            TypeKind.INVALID,
+            bazs[1].get_constant_template_argument_type(0).kind, 
TypeKind.POINTER
         )
+        baxs = get_cursors(tu, "bax")
         self.assertEqual(
-            foos[1].get_template_argument_integral_type(2).kind, TypeKind.BOOL
+            baxs[1].get_constant_template_argument_type(0).kind, TypeKind.FLOAT
         )
 
-    def test_get_template_argument_integral_type_pack(self):
+    def test_get_constant_template_argument_type_pack(self):
         source = """
             template<int... Ns> struct Foo {};
             template class Foo<1, 2, 3>;
@@ -941,9 +959,9 @@ def test_get_template_argument_integral_type_pack(self):
         spec = foos[1]
         self.assertEqual(spec.kind, CursorKind.STRUCT_DECL)
         self.assertEqual(spec.get_num_template_arguments(), 3)
-        self.assertEqual(spec.get_template_argument_integral_type(0).kind, 
TypeKind.INT)
-        self.assertEqual(spec.get_template_argument_integral_type(1).kind, 
TypeKind.INT)
-        self.assertEqual(spec.get_template_argument_integral_type(2).kind, 
TypeKind.INT)
+        self.assertEqual(spec.get_constant_template_argument_type(0).kind, 
TypeKind.INT)
+        self.assertEqual(spec.get_constant_template_argument_type(1).kind, 
TypeKind.INT)
+        self.assertEqual(spec.get_constant_template_argument_type(2).kind, 
TypeKind.INT)
 
     def test_get_num_template_parameters(self):
         source = "template<typename T, int N> void foo(); template<typename... 
Ts> void bar(); void baz();"
@@ -972,7 +990,21 @@ def test_get_template_parameter(self):
         self.assertEqual(n_param.kind, CursorKind.TEMPLATE_NON_TYPE_PARAMETER)
         self.assertEqual(n_param.spelling, "N")
         oob = foo.get_template_parameter(2)
-        self.assertTrue(oob.is_null())
+        self.assertIsNone(oob)
+
+    def test_get_template_parameter_variable_template(self):
+        source = "template<typename T, int N> T val = T(N);"
+        tu = get_tu(source, lang="cpp")
+        val = get_cursor(tu, "val")
+        self.assertIsNotNone(val)
+        self.assertEqual(val.kind, CursorKind.VAR_TEMPLATE)
+        self.assertEqual(val.get_num_template_parameters(), 2)
+        t_param = val.get_template_parameter(0)
+        self.assertEqual(t_param.kind, CursorKind.TEMPLATE_TYPE_PARAMETER)
+        self.assertEqual(t_param.spelling, "T")
+        n_param = val.get_template_parameter(1)
+        self.assertEqual(n_param.kind, CursorKind.TEMPLATE_NON_TYPE_PARAMETER)
+        self.assertEqual(n_param.spelling, "N")
 
     def test_is_template_parameter_pack(self):
         # Type parameter pack
@@ -1037,6 +1069,46 @@ def test_get_num_template_arguments_method(self):
         self.assertEqual(method_spec.get_num_template_arguments(), 1)
         self.assertEqual(method_spec.get_template_argument_type(0).kind, 
TypeKind.INT)
 
+    def test_get_num_template_arguments_variable_template(self):
+        source = """
+            template<typename T> T pi = T(3.14);
+            template<> int pi<int> = 3;
+        """
+        tu = get_tu(source, lang="cpp")
+        pis = get_cursors(tu, "pi")
+        spec = pis[1]
+        self.assertEqual(spec.get_num_template_arguments(), 1)
+        self.assertEqual(spec.get_template_argument_type(0).kind, TypeKind.INT)
+
+    def test_get_num_template_arguments_variable_template_partial_spec(self):
+        source = """
+            template<typename T> T val = T(0);
+            template<typename U> U val<U*> = U(1);
+        """
+        tu = get_tu(source, lang="cpp")
+        vals = get_cursors(tu, "val")
+        partial = [
+            c for c in vals if c.kind == 
CursorKind.VAR_TEMPLATE_PARTIAL_SPECIALIZATION
+        ]
+        self.assertEqual(len(partial), 1)
+        self.assertEqual(partial[0].get_num_template_arguments(), 1)
+
+    def test_get_template_argument_kind_variable_template(self):
+        source = """
+            template<typename T, int N> T val = T(N);
+            template<> int val<int, 42> = 42;
+        """
+        tu = get_tu(source, lang="cpp")
+        vals = get_cursors(tu, "val")
+        spec = vals[1]
+        self.assertEqual(spec.get_num_template_arguments(), 2)
+        self.assertEqual(spec.get_template_argument_kind(0), 
TemplateArgumentKind.TYPE)
+        self.assertEqual(
+            spec.get_template_argument_kind(1), TemplateArgumentKind.INTEGRAL
+        )
+        self.assertEqual(spec.get_template_argument_value(1), 42)
+        self.assertEqual(spec.get_template_argument_unsigned_value(1), 42)
+
     def test_referenced(self):
         tu = get_tu("void foo(); void bar() { foo(); }")
         foo = get_cursor(tu, "foo")
diff --git a/clang/bindings/python/tests/cindex/util.py 
b/clang/bindings/python/tests/cindex/util.py
index 5e66a9dc82c44..4f227c058e98e 100644
--- a/clang/bindings/python/tests/cindex/util.py
+++ b/clang/bindings/python/tests/cindex/util.py
@@ -18,7 +18,8 @@ def get_tu(source, lang="c", all_warnings=False, flags=[]):
     name = "t.c"
     if lang == "cpp":
         name = "t.cpp"
-        args.append("-std=c++11")
+        if not any(f.startswith("-std=") for f in args):
+            args.append("-std=c++11")
     elif lang == "objc":
         name = "t.m"
     elif lang != "c":
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 063d648972294..f461ec0920f55 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -78,7 +78,14 @@ Clang Frontend Potentially Breaking Changes
   libraries will need to be recompiled, or used with
   (`--no-offload-new-driver`). This option will be removed in the next release.
 
-
+libclang Potentially Breaking Changes
+-------------------------------------
+- ``clang_Cursor_getNumTemplateArguments`` and related accessor APIs now
+  expand parameter pack arguments into individual arguments, instead of
+  reporting the pack as a single argument.
+- Variable template declarations and partial specializations now produce
+  ``CXCursor_VarTemplate`` and ``CXCursor_VarTemplatePartialSpecialization``
+  cursor kinds, respectively, instead of ``CXCursor_UnexposedDecl``.
 
 Clang Python Bindings Potentially Breaking Changes
 --------------------------------------------------
@@ -115,6 +122,12 @@ Clang Python Bindings Potentially Breaking Changes
   ``UnsavedFile`` is already available to use and existing uses should
   be adapted to refer to it instead. ``_CXUnsavedFile`` will be removed in a 
   future release.
+- ``Cursor.get_num_template_arguments`` and related methods now expand
+  parameter pack arguments into individual arguments, instead of reporting
+  the pack as a single argument.
+- Variable template declarations and partial specializations now produce
+  ``CursorKind.VAR_TEMPLATE`` and 
``CursorKind.VAR_TEMPLATE_PARTIAL_SPECIALIZATION``
+  cursor kinds, respectively, instead of ``CursorKind.UNEXPOSED_DECL``.
 
 What's New in Clang |release|?
 ==============================
@@ -584,9 +597,19 @@ libclang
 - Fix crash in clang_getBinaryOperatorKindSpelling and 
clang_getUnaryOperatorKindSpelling
 - The clang_Module_getASTFile API is deprecated and now always returns nullptr
 - Added ``clang_Cursor_getNumTemplateParameters``, 
``clang_Cursor_getTemplateParameter``,
-  ``clang_Cursor_isTemplateParameterPack``, and 
``clang_Cursor_getTemplateArgumentIntegralType``.
-- Fixed ``clang_Cursor_getNumTemplateArguments`` and related APIs to work with
-  ``CXCursor_CXXMethod`` cursors and to correctly allow indexing into 
parameter pack arguments.
+  ``clang_Cursor_isTemplateParameterPack``, and 
``clang_Cursor_getConstantTemplateArgumentType``.
+- Added ``CXCursor_VarTemplate`` and 
``CXCursor_VarTemplatePartialSpecialization`` cursor kinds
+  for variable template declarations and partial specializations, which were 
previously
+  reported as ``CXCursor_UnexposedDecl``.
+- Extended ``clang_Cursor_getNumTemplateArguments``, 
``clang_Cursor_getTemplateArgumentKind``,
+  ``clang_Cursor_getTemplateArgumentType``, 
``clang_Cursor_getTemplateArgumentValue``, and
+  ``clang_Cursor_getTemplateArgumentUnsignedValue`` to work with variable 
template
+  specializations (``CXCursor_VarDecl``) and partial specializations
+  (``CXCursor_VarTemplatePartialSpecialization``).
+- Extended ``clang_Cursor_getNumTemplateParameters`` and 
``clang_Cursor_getTemplateParameter``
+  to work with variable templates (``CXCursor_VarTemplate``).
+- Fixed ``clang_Cursor_getNumTemplateArguments`` and related APIs to 
transparently expand
+  parameter pack arguments and to work with ``CXCursor_CXXMethod`` cursors.
 
 Code Completion
 ---------------
@@ -628,7 +651,7 @@ Python Binding Changes
 - Added a new helper method ``get_clang_version`` to the class ``Config`` to
   read the version string of the libclang in use.
 - Added ``Cursor.get_num_template_parameters``, 
``Cursor.get_template_parameter``,
-  ``Cursor.is_template_parameter_pack``, and 
``Cursor.get_template_argument_integral_type``.
+  ``Cursor.is_template_parameter_pack``, and 
``Cursor.get_constant_template_argument_type``.
 
 OpenMP Support
 --------------
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index d2f4e6e10dacd..041f2ec4a3b20 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -2310,9 +2310,17 @@ enum CXCursorKind {
    * a concept declaration.
    */
   CXCursor_ConceptDecl = 604,
+  /**
+   * a C++ variable template declaration.
+   */
+  CXCursor_VarTemplate = 605,
+  /**
+   * a C++ variable template partial specialization.
+   */
+  CXCursor_VarTemplatePartialSpecialization = 606,
 
   CXCursor_FirstExtraDecl = CXCursor_ModuleImportDecl,
-  CXCursor_LastExtraDecl = CXCursor_ConceptDecl,
+  CXCursor_LastExtraDecl = CXCursor_VarTemplatePartialSpecialization,
 
   /**
    * A code completion overload candidate.
@@ -3208,11 +3216,11 @@ enum CXTemplateArgumentKind {
 };
 
 /**
- * Returns the number of template args of a function, struct, or class decl
- * representing a template specialization.
+ * Returns the number of template args of a function, struct, class, or
+ * variable decl representing a template specialization.
  *
- * If the argument cursor cannot be converted into a template function
- * declaration, -1 is returned.
+ * If the argument cursor does not represent a template specialization,
+ * -1 is returned.
  *
  * For example, for the following declaration and specialization:
  *   template <typename T, int kInt, bool kBool>
@@ -3222,14 +3230,24 @@ enum CXTemplateArgumentKind {
  *   void foo<float, -7, true>();
  *
  * The value 3 would be returned from this call.
+ *
+ * Parameter pack arguments are expanded. For example:
+ *   template <typename T, typename... Ts>
+ *   struct Bar {};
+ *
+ *   Bar<int, float, double> bar;
+ *
+ * The value 3 would be returned (not 2), and each argument is individually
+ * accessible via \c clang_Cursor_getTemplateArgumentKind and related APIs.
  */
 CINDEX_LINKAGE int clang_Cursor_getNumTemplateArguments(CXCursor C);
 
 /**
  * Retrieve the kind of the I'th template argument of the CXCursor C.
  *
- * If the argument CXCursor does not represent a FunctionDecl, StructDecl, or
- * ClassTemplatePartialSpecialization, an invalid template argument kind is
+ * If the argument CXCursor does not represent a FunctionDecl, CXXMethod,
+ * StructDecl, ClassDecl, ClassTemplatePartialSpecialization, VarDecl, or
+ * VarTemplatePartialSpecialization, an invalid template argument kind is
  * returned.
  *
  * For example, for the following declaration and specialization:
@@ -3247,11 +3265,13 @@ clang_Cursor_getTemplateArgumentKind(CXCursor C, 
unsigned I);
 
 /**
  * Retrieve a CXType representing the type of a TemplateArgument of a
- *  function decl representing a template specialization.
+ *  function, struct, class, or variable decl representing a template
+ *  specialization.
  *
- * If the argument CXCursor does not represent a FunctionDecl, StructDecl,
- * ClassDecl or ClassTemplatePartialSpecialization whose I'th template argument
- * has a kind of CXTemplateArgKind_Integral, an invalid type is returned.
+ * If the argument CXCursor does not represent a FunctionDecl, CXXMethod,
+ * StructDecl, ClassDecl, ClassTemplatePartialSpecialization, VarDecl, or
+ * VarTemplatePartialSpecialization whose I'th template argument has a kind of
+ * CXTemplateArgKind_Type, an invalid type is returned.
  *
  * For example, for the following declaration and specialization:
  *   template <typename T, int kInt, bool kBool>
@@ -3260,16 +3280,20 @@ clang_Cursor_getTemplateArgumentKind(CXCursor C, 
unsigned I);
  *   template <>
  *   void foo<float, -7, true>();
  *
- * If called with I = 0, "float", will be returned.
+ * If called with I = 0, "float" will be returned.
  * Invalid types will be returned for I == 1 or 2.
  */
 CINDEX_LINKAGE CXType clang_Cursor_getTemplateArgumentType(CXCursor C,
                                                            unsigned I);
 
 /**
- * Retrieve the type of an Integral TemplateArgument at a given index.
+ * Retrieve the type of a constant template argument at a given index.
  *
- * For example, for:
+ * If the argument CXCursor does not represent a FunctionDecl, CXXMethod,
+ * StructDecl, ClassDecl, ClassTemplatePartialSpecialization, VarDecl, or
+ * VarTemplatePartialSpecialization, an invalid type is returned.
+ *
+ * For example, for the following declaration and specialization:
  *   template <typename T, int N>
  *   void foo() {}
  *
@@ -3277,24 +3301,38 @@ CINDEX_LINKAGE CXType 
clang_Cursor_getTemplateArgumentType(CXCursor C,
  *   void foo<float, 42>();
  *
  * If called with I = 1, the type "int" will be returned (the type of the
- * integral argument 42). An invalid type is returned if the argument at
- * index I is not integral, or if the index is out of range.
+ * constant template argument 42). An invalid type is returned if the argument
+ * at the given index is not a constant template argument, or if the index is
+ * out of range.
+ *
+ * Note that this returns the type of the argument after conversion to the
+ * parameter type. For example:
+ *   template <short S>
+ *   void bar() {}
+ *
+ *   template <>
+ *   void bar<12>();
+ *
+ * If called with I = 0, "short" will be returned, not "int".
  *
  * \param C a cursor representing a template specialization.
  * \param I the zero-based index of the template argument.
  *
- * \returns the type of the integral template argument, or an invalid type.
+ * \returns the type of the constant template argument, or an invalid type.
  */
-CINDEX_LINKAGE CXType clang_Cursor_getTemplateArgumentIntegralType(CXCursor C,
+CINDEX_LINKAGE CXType clang_Cursor_getConstantTemplateArgumentType(CXCursor C,
                                                                    unsigned I);
 
 /**
- * Retrieve the value of an Integral TemplateArgument (of a function or class
- *  decl representing a template specialization) as a signed long long.
+ * Retrieve the value of an Integral TemplateArgument (of a function, struct,
+ *  class, or variable decl representing a template specialization) as a signed
+ *  long long.
  *
  * It is undefined to call this function on a CXCursor that does not represent 
a
- * FunctionDecl, StructDecl, ClassDecl or ClassTemplatePartialSpecialization
- * whose I'th template argument is not an integral value.
+ * FunctionDecl, CXXMethod, StructDecl, ClassDecl,
+ * ClassTemplatePartialSpecialization, VarDecl, or
+ * VarTemplatePartialSpecialization whose I'th template argument is
+ * not an integral value.
  *
  * For example, for the following declaration and specialization:
  *   template <typename T, int kInt, bool kBool>
@@ -3310,12 +3348,15 @@ CINDEX_LINKAGE long long 
clang_Cursor_getTemplateArgumentValue(CXCursor C,
                                                                unsigned I);
 
 /**
- * Retrieve the value of an Integral TemplateArgument (of a function or class
- *  decl representing a template specialization) as an unsigned long long.
+ * Retrieve the value of an Integral TemplateArgument (of a function, struct,
+ *  class, or variable decl representing a template specialization) as an
+ *  unsigned long long.
  *
  * It is undefined to call this function on a CXCursor that does not represent 
a
- * FunctionDecl, StructDecl, ClassDecl or ClassTemplatePartialSpecialization or
- * whose I'th template argument is not an integral value.
+ * FunctionDecl, CXXMethod, StructDecl, ClassDecl,
+ * ClassTemplatePartialSpecialization, VarDecl, or
+ * VarTemplatePartialSpecialization whose I'th template argument is
+ * not an integral value.
  *
  * For example, for the following declaration and specialization:
  *   template <typename T, int kInt, bool kBool>
@@ -3333,7 +3374,17 @@ clang_Cursor_getTemplateArgumentUnsignedValue(CXCursor 
C, unsigned I);
 /**
  * Retrieve the number of template parameters on a template declaration.
  *
- * \param C a cursor representing a class template or function template.
+ * A parameter pack counts as a single template parameter. Use
+ * \c clang_Cursor_isTemplateParameterPack to check whether a specific
+ * parameter is a pack.
+ *
+ * For example:
+ *   template <typename T, typename... Ts>
+ *   struct Foo {};
+ *
+ * The value 2 would be returned (T and Ts).
+ *
+ * \param C a cursor representing a class, function, or variable template.
  *
  * \returns the number of template parameters, or -1 if the cursor does not
  * represent a template.
@@ -3343,7 +3394,7 @@ CINDEX_LINKAGE int 
clang_Cursor_getNumTemplateParameters(CXCursor C);
 /**
  * Retrieve a template parameter at the given index.
  *
- * \param C a cursor representing a class template or function template.
+ * \param C a cursor representing a class, function, or variable template.
  * \param I the zero-based index of the template parameter.
  *
  * \returns a cursor for the template parameter, or a null cursor if the
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp 
b/clang/lib/Sema/SemaCodeComplete.cpp
index 0cd9819dc2964..1fac84d4d3de6 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -4429,7 +4429,10 @@ CXCursorKind clang::getCursorKindForDecl(const Decl *D) {
   case Decl::TypeAliasTemplate:
     return CXCursor_TypeAliasTemplateDecl;
   case Decl::Var:
+  case Decl::VarTemplateSpecialization:
     return CXCursor_VarDecl;
+  case Decl::VarTemplatePartialSpecialization:
+    return CXCursor_VarTemplatePartialSpecialization;
   case Decl::Namespace:
     return CXCursor_Namespace;
   case Decl::NamespaceAlias:
@@ -4444,6 +4447,8 @@ CXCursorKind clang::getCursorKindForDecl(const Decl *D) {
     return CXCursor_FunctionTemplate;
   case Decl::ClassTemplate:
     return CXCursor_ClassTemplate;
+  case Decl::VarTemplate:
+    return CXCursor_VarTemplate;
   case Decl::AccessSpec:
     return CXCursor_CXXAccessSpecifier;
   case Decl::ClassTemplatePartialSpecialization:
diff --git a/clang/test/Index/template-parameters.cpp 
b/clang/test/Index/template-parameters.cpp
index b78e850de59e2..ac48929612c90 100644
--- a/clang/test/Index/template-parameters.cpp
+++ b/clang/test/Index/template-parameters.cpp
@@ -12,3 +12,39 @@ template class Variadic<int>;
 
 // Empty pack: should report 1 (just T, pack contributes 0).
 // CHECK: StructDecl=Variadic:8:16 (Definition) [Specialization of 
Variadic:5:8] [Template arg 0: kind: 1, type: int]
+
+template<typename T>
+T pi = T(3.14);
+
+template<>
+int pi<int> = 3;
+
+// Variable template declaration: should produce VarTemplate cursor.
+// CHECK: VarTemplate=pi:17:3 (Definition)
+
+// Variable template specialization: should report 1 argument.
+// CHECK: VarDecl=pi:20:5 (Definition) [Specialization of pi:17:3] [Template 
arg 0: kind: 1, type: int]
+
+template<typename T>
+T tau = T(6.28);
+
+template<>
+float tau<float> = 6.28f;
+
+template<typename U>
+U tau<U*> = U(0);
+
+// Variable template explicit specialization.
+// CHECK: VarDecl=tau:32:7 (Definition) [Specialization of tau:29:3] [Template 
arg 0: kind: 1, type: float]
+
+// Variable template partial specialization.
+// CHECK: VarTemplatePartialSpecialization=tau:35:3 (Definition) 
[Specialization of tau:29:3] [Template arg 0: kind: 1, type: type-parameter-0-0 
*]
+
+template<int N>
+int ival = N;
+
+template<>
+int ival<42> = 42;
+
+// Variable template with NTTP: should report integral argument.
+// CHECK: VarDecl=ival:47:5 (Definition) [Specialization of ival:44:5] 
[Template arg 0: kind: 4, intval: 42]
diff --git a/clang/tools/c-index-test/c-index-test.c 
b/clang/tools/c-index-test/c-index-test.c
index 6f71c16f58deb..5b1d9bd645c94 100644
--- a/clang/tools/c-index-test/c-index-test.c
+++ b/clang/tools/c-index-test/c-index-test.c
@@ -1058,7 +1058,9 @@ static void PrintCursor(CXCursor Cursor, const char 
*CommentSchemaFile) {
           Cursor.kind == CXCursor_CXXMethod ||
           Cursor.kind == CXCursor_StructDecl ||
           Cursor.kind == CXCursor_ClassDecl ||
-          Cursor.kind == CXCursor_ClassTemplatePartialSpecialization) {
+          Cursor.kind == CXCursor_ClassTemplatePartialSpecialization ||
+          Cursor.kind == CXCursor_VarDecl ||
+          Cursor.kind == CXCursor_VarTemplatePartialSpecialization) {
         /* Collect the template parameter kinds from the base template. */
         int NumTemplateArgs = clang_Cursor_getNumTemplateArguments(Cursor);
         int I;
diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 3ee37ed2dfc27..4fa9a30b500c6 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -6481,6 +6481,10 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind 
Kind) {
     return cxstring::createRef("attribute(aligned)");
   case CXCursor_ConceptDecl:
     return cxstring::createRef("ConceptDecl");
+  case CXCursor_VarTemplate:
+    return cxstring::createRef("VarTemplate");
+  case CXCursor_VarTemplatePartialSpecialization:
+    return cxstring::createRef("VarTemplatePartialSpecialization");
   case CXCursor_OpenACCComputeConstruct:
     return cxstring::createRef("OpenACCComputeConstruct");
   case CXCursor_OpenACCLoopConstruct:
diff --git a/clang/tools/libclang/CIndexCXX.cpp 
b/clang/tools/libclang/CIndexCXX.cpp
index 605f3ef9a4a62..2ee4189b51109 100644
--- a/clang/tools/libclang/CIndexCXX.cpp
+++ b/clang/tools/libclang/CIndexCXX.cpp
@@ -104,8 +104,9 @@ enum CXCursorKind clang_getTemplateCursorKind(CXCursor C) {
   using namespace clang::cxcursor;
   
   switch (C.kind) {
-  case CXCursor_ClassTemplate: 
+  case CXCursor_ClassTemplate:
   case CXCursor_FunctionTemplate:
+  case CXCursor_VarTemplate:
     if (const TemplateDecl *Template
                            = dyn_cast_or_null<TemplateDecl>(getCursorDecl(C)))
       return MakeCXCursor(Template->getTemplatedDecl(), getCursorTU(C)).kind;
@@ -128,7 +129,10 @@ enum CXCursorKind clang_getTemplateCursorKind(CXCursor C) {
       }
     }
     break;
-      
+
+  case CXCursor_VarTemplatePartialSpecialization:
+    return CXCursor_VarDecl;
+
   default:
     break;
   }
@@ -166,7 +170,19 @@ CXCursor clang_getSpecializedCursorTemplate(CXCursor C) {
     if (!Template)
       Template = Function->getInstantiatedFromMemberFunction();
   } else if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
-    if (Var->isStaticDataMember())
+    if (const VarTemplatePartialSpecializationDecl *PartialSpec
+          = dyn_cast<VarTemplatePartialSpecializationDecl>(Var))
+      Template = PartialSpec->getSpecializedTemplate();
+    else if (const VarTemplateSpecializationDecl *VTSpec
+               = dyn_cast<VarTemplateSpecializationDecl>(Var)) {
+      llvm::PointerUnion<VarTemplateDecl *,
+                         VarTemplatePartialSpecializationDecl *> Result
+        = VTSpec->getSpecializedTemplateOrPartial();
+      if (isa<VarTemplateDecl *>(Result))
+        Template = cast<VarTemplateDecl *>(Result);
+      else
+        Template = cast<VarTemplatePartialSpecializationDecl *>(Result);
+    } else if (Var->isStaticDataMember())
       Template = Var->getInstantiatedFromStaticDataMember();
   } else if (const RedeclarableTemplateDecl *Tmpl
                                         = 
dyn_cast<RedeclarableTemplateDecl>(D))
diff --git a/clang/tools/libclang/CXCursor.cpp 
b/clang/tools/libclang/CXCursor.cpp
index a60b26590a724..58df654472cb2 100644
--- a/clang/tools/libclang/CXCursor.cpp
+++ b/clang/tools/libclang/CXCursor.cpp
@@ -1441,13 +1441,16 @@ int clang_Cursor_getNumTemplateArguments(CXCursor C) {
   CXCursorKind kind = clang_getCursorKind(C);
   if (kind != CXCursor_FunctionDecl && kind != CXCursor_CXXMethod &&
       kind != CXCursor_StructDecl && kind != CXCursor_ClassDecl &&
-      kind != CXCursor_ClassTemplatePartialSpecialization) {
+      kind != CXCursor_ClassTemplatePartialSpecialization &&
+      kind != CXCursor_VarDecl &&
+      kind != CXCursor_VarTemplatePartialSpecialization) {
     return -1;
   }
 
   const TemplateArgumentList *TAL = nullptr;
+  const Decl *D = getCursorDecl(C);
 
-  if (const auto *FD = dyn_cast_if_present<FunctionDecl>(getCursorDecl(C))) {
+  if (const auto *FD = dyn_cast_if_present<FunctionDecl>(D)) {
     const FunctionTemplateSpecializationInfo *SpecInfo =
         FD->getTemplateSpecializationInfo();
     if (!SpecInfo) {
@@ -1457,12 +1460,19 @@ int clang_Cursor_getNumTemplateArguments(CXCursor C) {
   }
 
   if (!TAL) {
-    if (const auto *SD = dyn_cast_if_present<ClassTemplateSpecializationDecl>(
-            getCursorDecl(C))) {
+    if (const auto *SD =
+            dyn_cast_if_present<ClassTemplateSpecializationDecl>(D)) {
       TAL = &SD->getTemplateArgs();
     }
   }
 
+  if (!TAL) {
+    if (const auto *VD =
+            dyn_cast_if_present<VarTemplateSpecializationDecl>(D)) {
+      TAL = &VD->getTemplateArgs();
+    }
+  }
+
   if (!TAL)
     return -1;
 
@@ -1479,12 +1489,12 @@ enum CXGetTemplateArgumentStatus {
   /** The operation completed successfully */
   CXGetTemplateArgumentStatus_Success = 0,
 
-  /** The specified cursor did not represent a FunctionDecl or
-      ClassTemplateSpecializationDecl.                         */
+  /** The specified cursor did not represent a FunctionDecl,
+      ClassTemplateSpecializationDecl, or VarTemplateSpecializationDecl. */
   CXGetTemplateArgumentStatus_CursorNotCompatibleDecl = -1,
 
-  /** The specified cursor was not castable to a FunctionDecl or
-      ClassTemplateSpecializationDecl.                         */
+  /** The specified cursor was not castable to a FunctionDecl,
+      ClassTemplateSpecializationDecl, or VarTemplateSpecializationDecl. */
   CXGetTemplateArgumentStatus_BadDeclCast = -2,
 
   /** A NULL FunctionTemplateSpecializationInfo was retrieved. */
@@ -1499,13 +1509,16 @@ static int clang_Cursor_getTemplateArgument(CXCursor C, 
unsigned I,
   CXCursorKind kind = clang_getCursorKind(C);
   if (kind != CXCursor_FunctionDecl && kind != CXCursor_CXXMethod &&
       kind != CXCursor_StructDecl && kind != CXCursor_ClassDecl &&
-      kind != CXCursor_ClassTemplatePartialSpecialization) {
+      kind != CXCursor_ClassTemplatePartialSpecialization &&
+      kind != CXCursor_VarDecl &&
+      kind != CXCursor_VarTemplatePartialSpecialization) {
     return -1;
   }
 
   const TemplateArgumentList *TAL = nullptr;
+  const Decl *D = getCursorDecl(C);
 
-  if (const auto *FD = dyn_cast_if_present<FunctionDecl>(getCursorDecl(C))) {
+  if (const auto *FD = dyn_cast_if_present<FunctionDecl>(D)) {
 
     const FunctionTemplateSpecializationInfo *SpecInfo =
         FD->getTemplateSpecializationInfo();
@@ -1517,12 +1530,19 @@ static int clang_Cursor_getTemplateArgument(CXCursor C, 
unsigned I,
   }
 
   if (!TAL) {
-    if (const auto *SD = dyn_cast_if_present<ClassTemplateSpecializationDecl>(
-            getCursorDecl(C))) {
+    if (const auto *SD =
+            dyn_cast_if_present<ClassTemplateSpecializationDecl>(D)) {
       TAL = &SD->getTemplateArgs();
     }
   }
 
+  if (!TAL) {
+    if (const auto *VD =
+            dyn_cast_if_present<VarTemplateSpecializationDecl>(D)) {
+      TAL = &VD->getTemplateArgs();
+    }
+  }
+
   if (!TAL)
     return CXGetTemplateArgumentStatus_BadDeclCast;
 
@@ -1595,6 +1615,27 @@ CXType clang_Cursor_getTemplateArgumentType(CXCursor C, 
unsigned I) {
   return cxtype::MakeCXType(TA.getAsType(), getCursorTU(C));
 }
 
+CXType clang_Cursor_getConstantTemplateArgumentType(CXCursor C, unsigned I) {
+  TemplateArgument TA;
+  if (clang_Cursor_getTemplateArgument(C, I, &TA) !=
+      CXGetTemplateArgumentStatus_Success) {
+    return cxtype::MakeCXType(QualType(), getCursorTU(C));
+  }
+
+  switch (TA.getKind()) {
+  case TemplateArgument::Integral:
+    return cxtype::MakeCXType(TA.getIntegralType(), getCursorTU(C));
+  case TemplateArgument::Declaration:
+    return cxtype::MakeCXType(TA.getParamTypeForDecl(), getCursorTU(C));
+  case TemplateArgument::NullPtr:
+    return cxtype::MakeCXType(TA.getNullPtrType(), getCursorTU(C));
+  case TemplateArgument::StructuralValue:
+    return cxtype::MakeCXType(TA.getStructuralValueType(), getCursorTU(C));
+  default:
+    return cxtype::MakeCXType(QualType(), getCursorTU(C));
+  }
+}
+
 long long clang_Cursor_getTemplateArgumentValue(CXCursor C, unsigned I) {
   TemplateArgument TA;
   if (clang_Cursor_getTemplateArgument(C, I, &TA) !=
@@ -1628,20 +1669,10 @@ unsigned long long 
clang_Cursor_getTemplateArgumentUnsignedValue(CXCursor C,
   return TA.getAsIntegral().getZExtValue();
 }
 
-CXType clang_Cursor_getTemplateArgumentIntegralType(CXCursor C, unsigned I) {
-  TemplateArgument TA;
-  if (clang_Cursor_getTemplateArgument(C, I, &TA))
-    return cxtype::MakeCXType(QualType(), getCursorTU(C));
-
-  if (TA.getKind() != TemplateArgument::Integral)
-    return cxtype::MakeCXType(QualType(), getCursorTU(C));
-
-  return cxtype::MakeCXType(TA.getIntegralType(), getCursorTU(C));
-}
-
 int clang_Cursor_getNumTemplateParameters(CXCursor C) {
   CXCursorKind kind = clang_getCursorKind(C);
-  if (kind != CXCursor_ClassTemplate && kind != CXCursor_FunctionTemplate)
+  if (kind != CXCursor_ClassTemplate && kind != CXCursor_FunctionTemplate &&
+      kind != CXCursor_VarTemplate)
     return -1;
 
   const Decl *D = getCursorDecl(C);
@@ -1649,13 +1680,16 @@ int clang_Cursor_getNumTemplateParameters(CXCursor C) {
     return CTD->getTemplateParameters()->size();
   if (const auto *FTD = dyn_cast_if_present<FunctionTemplateDecl>(D))
     return FTD->getTemplateParameters()->size();
+  if (const auto *VTD = dyn_cast_if_present<VarTemplateDecl>(D))
+    return VTD->getTemplateParameters()->size();
 
   return -1;
 }
 
 CXCursor clang_Cursor_getTemplateParameter(CXCursor C, unsigned I) {
   CXCursorKind kind = clang_getCursorKind(C);
-  if (kind != CXCursor_ClassTemplate && kind != CXCursor_FunctionTemplate)
+  if (kind != CXCursor_ClassTemplate && kind != CXCursor_FunctionTemplate &&
+      kind != CXCursor_VarTemplate)
     return clang_getNullCursor();
 
   const Decl *D = getCursorDecl(C);
@@ -1664,6 +1698,8 @@ CXCursor clang_Cursor_getTemplateParameter(CXCursor C, 
unsigned I) {
     TPL = CTD->getTemplateParameters();
   else if (const auto *FTD = dyn_cast_if_present<FunctionTemplateDecl>(D))
     TPL = FTD->getTemplateParameters();
+  else if (const auto *VTD = dyn_cast_if_present<VarTemplateDecl>(D))
+    TPL = VTD->getTemplateParameters();
 
   if (!TPL || I >= TPL->size())
     return clang_getNullCursor();
diff --git a/clang/tools/libclang/libclang.map 
b/clang/tools/libclang/libclang.map
index e1fe6064dd730..7f837fa3051c7 100644
--- a/clang/tools/libclang/libclang.map
+++ b/clang/tools/libclang/libclang.map
@@ -462,7 +462,7 @@ LLVM_23 {
     clang_ModuleCache_prune;
     clang_Cursor_getNumTemplateParameters;
     clang_Cursor_getTemplateParameter;
-    clang_Cursor_getTemplateArgumentIntegralType;
+    clang_Cursor_getConstantTemplateArgumentType;
     clang_Cursor_isTemplateParameterPack;
 };
 

>From ce1697aef2284374ff480b10af40ca3670f88042 Mon Sep 17 00:00:00 2001
From: Fabian Scheidl <[email protected]>
Date: Wed, 8 Apr 2026 10:49:05 +0200
Subject: [PATCH 3/3] [libclang] Improve getConstantTemplateArgumentType docs
 and tests

---
 .../python/tests/cindex/test_cursor.py        | 18 +++++++++++++--
 clang/include/clang-c/Index.h                 | 23 +++++++------------
 clang/tools/libclang/CIndexCXX.cpp            | 12 +++++-----
 3 files changed, 30 insertions(+), 23 deletions(-)

diff --git a/clang/bindings/python/tests/cindex/test_cursor.py 
b/clang/bindings/python/tests/cindex/test_cursor.py
index 8773dacc3389f..8f863f3fdfb7d 100644
--- a/clang/bindings/python/tests/cindex/test_cursor.py
+++ b/clang/bindings/python/tests/cindex/test_cursor.py
@@ -927,14 +927,20 @@ def test_get_constant_template_argument_type(self):
             template<> void baz<nullptr>();
             template<float F> void bax();
             template<> void bax<3.14f>();
+            int v[5];
+            template<int b[5]> void arr();
+            template<> void arr<v>();
+            void handler(int);
+            template<void f(int)> void func();
+            template<> void func<handler>();
         """
         tu = get_tu(source, lang="cpp", flags=["-std=c++20"])
         foos = get_cursors(tu, "foo")
         self.assertEqual(
-            foos[1].get_constant_template_argument_type(0).kind, TypeKind.INT
+            foos[1].get_constant_template_argument_type(0).kind, 
TypeKind.INVALID
         )
         self.assertEqual(
-            foos[1].get_constant_template_argument_type(1).kind, 
TypeKind.INVALID
+            foos[1].get_constant_template_argument_type(1).kind, TypeKind.INT
         )
         bars = get_cursors(tu, "bar")
         self.assertEqual(
@@ -948,6 +954,14 @@ def test_get_constant_template_argument_type(self):
         self.assertEqual(
             baxs[1].get_constant_template_argument_type(0).kind, TypeKind.FLOAT
         )
+        arrs = get_cursors(tu, "arr")
+        self.assertEqual(
+            arrs[1].get_constant_template_argument_type(0).kind, 
TypeKind.POINTER
+        )
+        funcs = get_cursors(tu, "func")
+        self.assertEqual(
+            funcs[1].get_constant_template_argument_type(0).kind, 
TypeKind.POINTER
+        )
 
     def test_get_constant_template_argument_type_pack(self):
         source = """
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h
index 041f2ec4a3b20..f7f0fe6b74e81 100644
--- a/clang/include/clang-c/Index.h
+++ b/clang/include/clang-c/Index.h
@@ -3293,27 +3293,20 @@ CINDEX_LINKAGE CXType 
clang_Cursor_getTemplateArgumentType(CXCursor C,
  * StructDecl, ClassDecl, ClassTemplatePartialSpecialization, VarDecl, or
  * VarTemplatePartialSpecialization, an invalid type is returned.
  *
- * For example, for the following declaration and specialization:
- *   template <typename T, int N>
+ * The returned type reflects conversion to the parameter type. For example:
+ *   template <typename T, short S>
  *   void foo() {}
  *
  *   template <>
  *   void foo<float, 42>();
  *
- * If called with I = 1, the type "int" will be returned (the type of the
- * constant template argument 42). An invalid type is returned if the argument
- * at the given index is not a constant template argument, or if the index is
- * out of range.
- *
- * Note that this returns the type of the argument after conversion to the
- * parameter type. For example:
- *   template <short S>
- *   void bar() {}
- *
- *   template <>
- *   void bar<12>();
+ * If called with I = 0, an invalid type is returned (T is not a constant
+ * template argument). If called with I = 1, "short" is returned, not "int".
+ * Similarly, a parameter declared as \c int[5] will yield a pointer type
+ * after adjustment.
  *
- * If called with I = 0, "short" will be returned, not "int".
+ * For expanded parameter pack arguments, the type of the pack parameter is
+ * returned for each expanded argument.
  *
  * \param C a cursor representing a template specialization.
  * \param I the zero-based index of the template argument.
diff --git a/clang/tools/libclang/CIndexCXX.cpp 
b/clang/tools/libclang/CIndexCXX.cpp
index 2ee4189b51109..b4c03fc9705d6 100644
--- a/clang/tools/libclang/CIndexCXX.cpp
+++ b/clang/tools/libclang/CIndexCXX.cpp
@@ -170,14 +170,14 @@ CXCursor clang_getSpecializedCursorTemplate(CXCursor C) {
     if (!Template)
       Template = Function->getInstantiatedFromMemberFunction();
   } else if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
-    if (const VarTemplatePartialSpecializationDecl *PartialSpec
-          = dyn_cast<VarTemplatePartialSpecializationDecl>(Var))
+    if (const VarTemplatePartialSpecializationDecl *PartialSpec =
+            dyn_cast<VarTemplatePartialSpecializationDecl>(Var))
       Template = PartialSpec->getSpecializedTemplate();
-    else if (const VarTemplateSpecializationDecl *VTSpec
-               = dyn_cast<VarTemplateSpecializationDecl>(Var)) {
+    else if (const VarTemplateSpecializationDecl *VTSpec =
+                 dyn_cast<VarTemplateSpecializationDecl>(Var)) {
       llvm::PointerUnion<VarTemplateDecl *,
-                         VarTemplatePartialSpecializationDecl *> Result
-        = VTSpec->getSpecializedTemplateOrPartial();
+                         VarTemplatePartialSpecializationDecl *>
+          Result = VTSpec->getSpecializedTemplateOrPartial();
       if (isa<VarTemplateDecl *>(Result))
         Template = cast<VarTemplateDecl *>(Result);
       else

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to