diff -pur spack-src/clang/bindings/python/clang/cindex.py spack-src-new/clang/bindings/python/clang/cindex.py
--- spack-src/clang/bindings/python/clang/cindex.py	2025-02-03 18:51:43.871219854 +0100
+++ spack-src-new/clang/bindings/python/clang/cindex.py	2025-02-03 18:39:41.616213701 +0100
@@ -1426,6 +1426,15 @@ class Cursor(Structure):
     """
     _fields_ = [("_kind_id", c_int), ("xdata", c_int), ("data", c_void_p * 3)]
 
+    # Default behavior.
+    GET_CHILDREN_NONE = 0
+
+    # Used to indicate that implicit cursors should be visited.
+    GET_CHILDREN_WITH_IMPLICIT = 1
+
+    # Used to indicate that template instantiations should be visited.
+    GET_CHILDREN_WITH_TEMPLATE_INSTANTIATIONS = 2
+
     @staticmethod
     def from_location(tu, location):
         # We store a reference to the TU in the instance so the TU won't get
@@ -1515,6 +1524,10 @@ class Cursor(Structure):
         """
         return conf.lib.clang_EnumDecl_isScoped(self)
 
+    def is_implicit(self):
+        """Test whether the cursor refers to an implicit declaration."""
+        return conf.lib.clang_isImplicit(self)
+
     def get_definition(self):
         """
         If the cursor is a reference to a declaration or a declaration of
@@ -1831,8 +1844,12 @@ class Cursor(Structure):
         """Returns the value of the indicated arg as an unsigned 64b integer."""
         return conf.lib.clang_Cursor_getTemplateArgumentUnsignedValue(self, num)
 
-    def get_children(self):
-        """Return an iterator for accessing the children of this cursor."""
+    def get_children(self, with_implicit=False, with_template_instantiations=False):
+        """Return an iterator for accessing the children of this cursor.
+
+        By default, cursors representing implicit declarations or template instantiations
+        will be skipped.
+        """
 
         # FIXME: Expose iteration from CIndex, PR6125.
         def visitor(child, parent, children):
@@ -1845,18 +1862,24 @@ class Cursor(Structure):
             children.append(child)
             return 1 # continue
         children = []
-        conf.lib.clang_visitChildren(self, callbacks['cursor_visit'](visitor),
-            children)
+        dispatch = conf.lib.clang_visitChildren
+        options = Cursor.GET_CHILDREN_NONE
+        if with_implicit:
+            options |= Cursor.GET_CHILDREN_WITH_IMPLICIT
+        if with_template_instantiations:
+            options |= Cursor.GET_CHILDREN_WITH_TEMPLATE_INSTANTIATIONS
+        conf.lib.clang_visitChildrenWithOptions(
+            self, callbacks['cursor_visit'](visitor), children, options)
         return iter(children)
 
-    def walk_preorder(self):
+    def walk_preorder(self, **kwargs):
         """Depth-first preorder walk over the cursor and its descendants.
 
         Yields cursors.
         """
         yield self
-        for child in self.get_children():
-            for descendant in child.walk_preorder():
+        for child in self.get_children(**kwargs):
+            for descendant in child.walk_preorder(**kwargs):
                 yield descendant
 
     def get_tokens(self, options=0):
@@ -3928,6 +3951,10 @@ functionList = [
    [Type],
    bool),
 
+  ("clang_isImplicit",
+   [Cursor],
+   bool),
+
   ("clang_isInvalid",
    [CursorKind],
    bool),
@@ -3991,6 +4018,10 @@ functionList = [
    [Cursor, callbacks['cursor_visit'], py_object],
    c_uint),
 
+  ("clang_visitChildrenWithOptions",
+   [Cursor, callbacks['cursor_visit'], py_object, c_uint],
+   c_uint),
+
   ("clang_Cursor_getNumArguments",
    [Cursor],
    c_int),
diff -pur spack-src/clang/bindings/python/tests/cindex/test_cursor.py spack-src-new/clang/bindings/python/tests/cindex/test_cursor.py
--- spack-src/clang/bindings/python/tests/cindex/test_cursor.py	2025-02-03 18:51:43.871219854 +0100
+++ spack-src-new/clang/bindings/python/tests/cindex/test_cursor.py	2025-02-03 18:39:41.616213701 +0100
@@ -94,6 +94,39 @@ class TestCursor(unittest.TestCase):
         self.assertEqual(tu_nodes[2].displayname, 'f0(int, int)')
         self.assertEqual(tu_nodes[2].is_definition(), True)
 
+    def test_get_children_with_implicit():
+        tu = get_tu('struct X {}; X x;', lang='cpp')
+        cursor = get_cursor(tu, 'X')
+
+        children = list(cursor.get_children())
+        self.assertEqual(len(children), 0, [(c.kind, c.spelling) for c in children])
+
+        children = list(cursor.get_children(with_implicit=True))
+        self.assertNotEqual(len(children), 0)
+        for child in children:
+            self.assertTrue(child.is_implicit())
+            self.assertEqual(child.spelling, "X")
+            self.assertIn(child.kind, [CursorKind.CONSTRUCTOR, CursorKind.STRUCT_DECL])
+
+    def test_get_children_with_template_instantiations():
+        tu = get_tu(
+            'template <typename T> T frobnicate(T val);'
+            'extern template int frobnicate<int>(int);',
+            lang='cpp')
+        cursor = get_cursor(tu, 'frobnicate')
+        self.assertEqual(cursor.kind, CursorKind.FUNCTION_TEMPLATE)
+
+        for child in cursor.get_children():
+            # should not return an instantiation:
+            self.assertNotEqual(child.kind, CursorKind.FUNCTION_DECL)
+
+        for child in cursor.get_children(with_template_instantiations=True):
+            if child.kind == CursorKind.FUNCTION_DECL:
+                self.assertEqual(child.spelling, 'frobnicate')
+                break
+        else:
+            self.fail("Couldn't find template instantiation")
+
     def test_references(self):
         """Ensure that references to TranslationUnit are kept."""
         tu = get_tu('int x;')
diff -pur spack-src/clang/include/clang-c/Index.h spack-src-new/clang/include/clang-c/Index.h
--- spack-src/clang/include/clang-c/Index.h	2025-02-03 18:51:43.871219854 +0100
+++ spack-src-new/clang/include/clang-c/Index.h	2025-02-03 18:40:48.276492163 +0100
@@ -33,7 +33,7 @@
  * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable.
  */
 #define CINDEX_VERSION_MAJOR 0
-#define CINDEX_VERSION_MINOR 65
+#define CINDEX_VERSION_MINOR 66
 
 #define CINDEX_VERSION_ENCODE(major, minor) (((major)*10000) + ((minor)*1))
 
@@ -2817,6 +2817,11 @@ CINDEX_LINKAGE unsigned clang_isPreproce
  */
 CINDEX_LINKAGE unsigned clang_isUnexposed(enum CXCursorKind);
 
+/***
+ * \brief Determine whether the given cursor represents an implicit declaration.
+ */
+CINDEX_LINKAGE unsigned clang_isImplicit(CXCursor);
+
 /**
  * Describe the linkage of the entity referred to by a cursor.
  */
@@ -4274,6 +4279,32 @@ clang_visitChildrenWithBlock(CXCursor pa
 #endif
 #endif
 
+typedef enum {
+  /**
+   * \brief Default behavior.
+   */
+  CXVisitChildren_None = 0x0,
+
+  /**
+   * \brief Used to indicate that implicit cursors should be visited.
+   */
+  CXVisitChildren_WithImplicit = 0x1,
+
+  /**
+   * \brief Used to indicate that template instantiations should be visited.
+   */
+  CXVisitChildren_WithTemplateInstantiations = 0x2
+} CXVisitChildren_Flags;
+
+/**
+ * \brief Visits the children of a cursor, allowing to pass extra options.
+ * Behaves identically to clang_visitChildren() in all other respects.
+ */
+CINDEX_LINKAGE unsigned clang_visitChildrenWithOptions(CXCursor parent,
+                                                       CXCursorVisitor visitor,
+                                                       CXClientData client_data,
+                                                       unsigned options);
+
 /**
  * @}
  */
diff -pur spack-src/clang/tools/libclang/CIndex.cpp spack-src-new/clang/tools/libclang/CIndex.cpp
--- spack-src/clang/tools/libclang/CIndex.cpp	2025-02-03 18:51:43.871219854 +0100
+++ spack-src-new/clang/tools/libclang/CIndex.cpp	2025-02-03 18:39:43.000219486 +0100
@@ -203,9 +203,10 @@ bool CursorVisitor::Visit(CXCursor Curso
       return true; // abort.
     }
 
-    // Ignore implicit declarations, unless it's an objc method because
-    // currently we should report implicit methods for properties when indexing.
-    if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
+    // Unless instructed otherwise we ignore implicit declarations.
+    // ObjC methods are currently visited in any case, because implicit methods
+    // for properties should be reported when indexing.
+    if (!VisitImplicitDeclarations && D->isImplicit() && !isa<ObjCMethodDecl>(D))
       return false;
   }
 
@@ -713,10 +714,13 @@ bool CursorVisitor::VisitTagDecl(TagDecl
 
 bool CursorVisitor::VisitClassTemplateSpecializationDecl(
     ClassTemplateSpecializationDecl *D) {
-  bool ShouldVisitBody = false;
+  bool ShouldVisitBody = VisitTemplateInstantiations;
   switch (D->getSpecializationKind()) {
-  case TSK_Undeclared:
   case TSK_ImplicitInstantiation:
+    if (VisitTemplateInstantiations && VisitImplicitDeclarations) {
+      break;
+    }
+  case TSK_Undeclared:
     // Nothing to visit
     return false;
 
@@ -725,6 +729,7 @@ bool CursorVisitor::VisitClassTemplateSp
     break;
 
   case TSK_ExplicitSpecialization:
+    // Always visit body of explicit specializations
     ShouldVisitBody = true;
     break;
   }
@@ -945,7 +950,31 @@ bool CursorVisitor::VisitFunctionTemplat
     return true;
 
   auto *FD = D->getTemplatedDecl();
-  return VisitAttributes(FD) || VisitFunctionDecl(FD);
+  if (VisitAttributes(FD) || VisitFunctionDecl(FD))
+    return true;
+
+  if (VisitTemplateInstantiations && D == D->getCanonicalDecl()) {
+    for (auto *FD : D->specializations()) {
+      for (auto *RD : FD->redecls()) {
+        switch (RD->getTemplateSpecializationKind()) {
+        case TSK_Undeclared:
+        case TSK_ImplicitInstantiation:
+        case TSK_ExplicitInstantiationDeclaration:
+        case TSK_ExplicitInstantiationDefinition: {
+          const Optional<bool> V = handleDeclForVisitation(RD);
+          if (!V.hasValue())
+            continue;
+          return V.getValue();
+        }
+
+        case TSK_ExplicitSpecialization:
+          break;
+        }
+      }
+    }
+  }
+
+  return false;
 }
 
 bool CursorVisitor::VisitClassTemplateDecl(ClassTemplateDecl *D) {
@@ -956,6 +985,40 @@ bool CursorVisitor::VisitClassTemplateDe
 
   auto *CD = D->getTemplatedDecl();
   return VisitAttributes(CD) || VisitCXXRecordDecl(CD);
+  if (VisitAttributes(CD) || VisitCXXRecordDecl(CD))
+    return true;
+
+  if (VisitTemplateInstantiations && D == D->getCanonicalDecl()) {
+    for (auto *SD : D->specializations()) {
+      for (auto *RD : SD->redecls()) {
+        // We don't want to visit injected-class-names in this traversal.
+        if (cast<CXXRecordDecl>(RD)->isInjectedClassName())
+          continue;
+
+        switch (
+            cast<ClassTemplateSpecializationDecl>(RD)->getSpecializationKind()) {
+          // Visit the implicit instantiations with the requested pattern.
+        case TSK_Undeclared:
+        case TSK_ImplicitInstantiation: {
+          const Optional<bool> V = handleDeclForVisitation(RD);
+          if (!V.hasValue())
+            continue;
+          return V.getValue();
+        }
+
+          // We don't need to do anything on an explicit instantiation
+          // or explicit specialization because there will be an explicit
+          // node for it elsewhere.
+        case TSK_ExplicitInstantiationDeclaration:
+        case TSK_ExplicitInstantiationDefinition:
+        case TSK_ExplicitSpecialization:
+          break;
+        }
+      }
+    }
+  }
+
+  return false;
 }
 
 bool CursorVisitor::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) {
@@ -4596,6 +4659,24 @@ unsigned clang_visitChildrenWithBlock(CX
   return clang_visitChildren(parent, visitWithBlock, block);
 }
 
+unsigned clang_visitChildrenWithOptions(CXCursor parent,
+                                        CXCursorVisitor visitor,
+                                        CXClientData client_data,
+                                        unsigned options) {
+  CursorVisitor CursorVis(
+      getCursorTU(parent), visitor, client_data,
+      /*VisitPreprocessorLast=*/false,
+      /*VisitIncludedPreprocessingEntries=*/false,
+      /*RegionOfInterest=*/SourceRange(),
+      /*VisitDeclsOnly=*/false,
+      /*PostChildrenVisitor=*/nullptr,
+      /*VisitImplicitDeclarations=*/(options & CXVisitChildren_WithImplicit),
+      /*VisitTemplateInstantiations=*/
+      (options & CXVisitChildren_WithTemplateInstantiations));
+
+  return CursorVis.VisitChildren(parent);
+}
+
 static CXString getDeclSpelling(const Decl *D) {
   if (!D)
     return cxstring::createEmpty();
@@ -5983,6 +6064,22 @@ unsigned clang_isUnexposed(enum CXCursor
   }
 }
 
+unsigned clang_isImplicit(CXCursor Cursor) {
+  if (clang_isInvalid(Cursor.kind))
+    return false;
+
+  if (!clang_isDeclaration(Cursor.kind))
+    return false;
+
+  const Decl *D = getCursorDecl(Cursor);
+  if (!D) {
+    assert(0 && "Invalid declaration cursor");
+    return true; // abort.
+  }
+
+  return D->isImplicit();
+}
+
 CXCursorKind clang_getCursorKind(CXCursor C) { return C.kind; }
 
 CXSourceLocation clang_getCursorLocation(CXCursor C) {
diff -pur spack-src/clang/tools/libclang/CursorVisitor.h spack-src-new/clang/tools/libclang/CursorVisitor.h
--- spack-src/clang/tools/libclang/CursorVisitor.h	2022-01-20 22:31:59.000000000 +0100
+++ spack-src-new/clang/tools/libclang/CursorVisitor.h	2025-02-03 18:39:43.000219486 +0100
@@ -104,6 +104,12 @@ private:
   /// record entries.
   bool VisitDeclsOnly;
 
+  /// \brief Whether we should visit implicit declarations.
+  bool VisitImplicitDeclarations;
+
+  /// \brief Whether we should recurse into template instantiations.
+  bool VisitTemplateInstantiations;
+
   // FIXME: Eventually remove.  This part of a hack to support proper
   // iteration over all Decls contained lexically within an ObjC container.
   DeclContext::decl_iterator *DI_current;
@@ -152,12 +158,16 @@ public:
                 bool VisitIncludedPreprocessingEntries = false,
                 SourceRange RegionOfInterest = SourceRange(),
                 bool VisitDeclsOnly = false,
-                PostChildrenVisitorTy PostChildrenVisitor = nullptr)
+                PostChildrenVisitorTy PostChildrenVisitor = nullptr,
+                bool VisitImplicitDeclarations = false,
+                bool VisitTemplateInstantiations = false)
       : TU(TU), AU(cxtu::getASTUnit(TU)), Visitor(Visitor),
         PostChildrenVisitor(PostChildrenVisitor), ClientData(ClientData),
         VisitPreprocessorLast(VisitPreprocessorLast),
         VisitIncludedEntities(VisitIncludedPreprocessingEntries),
         RegionOfInterest(RegionOfInterest), VisitDeclsOnly(VisitDeclsOnly),
+        VisitImplicitDeclarations(VisitImplicitDeclarations),
+        VisitTemplateInstantiations(VisitTemplateInstantiations),
         DI_current(nullptr), FileDI_current(nullptr) {
     Parent.kind = CXCursor_NoDeclFound;
     Parent.data[0] = nullptr;
diff -pur spack-src/clang/tools/libclang/libclang.map spack-src-new/clang/tools/libclang/libclang.map
--- spack-src/clang/tools/libclang/libclang.map	2025-02-03 18:51:43.871219854 +0100
+++ spack-src-new/clang/tools/libclang/libclang.map	2025-02-03 18:40:21.600380765 +0100
@@ -375,6 +375,7 @@ LLVM_13 {
     clang_isExpression;
     clang_isFileMultipleIncludeGuarded;
     clang_isFunctionTypeVariadic;
+    clang_isImplicit;
     clang_isInvalid;
     clang_isInvalidDeclaration;
     clang_isPODType;
@@ -403,6 +404,7 @@ LLVM_13 {
     clang_uninstall_llvm_fatal_error_handler;
     clang_visitChildren;
     clang_visitChildrenWithBlock;
+    clang_visitChildrenWithOptions;
 
   local: *;
 };