Type aliases bound to fully-instantiated template

PiperOrigin-RevId: 449002160
diff --git a/rs_bindings_from_cc/importers/function.cc b/rs_bindings_from_cc/importers/function.cc
index e09245b..1f1e363 100644
--- a/rs_bindings_from_cc/importers/function.cc
+++ b/rs_bindings_from_cc/importers/function.cc
@@ -5,6 +5,7 @@
 #include "rs_bindings_from_cc/importers/function.h"
 
 #include "absl/strings/substitute.h"
+#include "rs_bindings_from_cc/ast_util.h"
 
 namespace crubit {
 
@@ -187,9 +188,34 @@
   bool has_c_calling_convention =
       function_decl->getType()->getAs<clang::FunctionType>()->getCallConv() ==
       clang::CC_C;
+  bool is_member_or_descendant_of_class_template =
+      IsFullClassTemplateSpecializationOrChild(function_decl);
   std::optional<UnqualifiedIdentifier> translated_name =
       ictx_.GetTranslatedName(function_decl);
 
+  llvm::Optional<std::string> doc_comment = ictx_.GetComment(function_decl);
+  if (!doc_comment.hasValue() && is_member_or_descendant_of_class_template) {
+    // Despite `is_member_or_descendant_of_class_template` check above, we are
+    // not guaranteed that a `func_pattern` exists below.  For example, it may
+    // be missing when `function_decl` is an implicitly defined constructor of a
+    // class template -- such decls are generated, not instantiated.
+    if (clang::FunctionDecl* func_pattern =
+            function_decl->getTemplateInstantiationPattern()) {
+      doc_comment = ictx_.GetComment(func_pattern);
+    }
+  }
+
+  std::string mangled_name = ictx_.GetMangledName(function_decl);
+  if (is_member_or_descendant_of_class_template) {
+    // TODO(b/222001243): Avoid calling `ConvertToCcIdentifier(target)` to
+    // distinguish multiple definitions of a template instantiation.  Instead
+    // help the linker merge all the definitions into one, by defining the
+    // thunk via a function template - see "Handling thunks" section in
+    // <internal link>
+    mangled_name += '_';
+    mangled_name += ConvertToCcIdentifier(ictx_.GetOwningTarget(function_decl));
+  }
+
   // Silence ClangTidy, checked above: calling `add_error` if
   // `!return_type.ok()` and returning early if `!errors.empty()`.
   CRUBIT_CHECK(return_type.ok());
@@ -198,14 +224,16 @@
     return Func{
         .name = *translated_name,
         .owning_target = ictx_.GetOwningTarget(function_decl),
-        .doc_comment = ictx_.GetComment(function_decl),
-        .mangled_name = ictx_.GetMangledName(function_decl),
+        .doc_comment = std::move(doc_comment),
+        .mangled_name = std::move(mangled_name),
         .return_type = *return_type,
         .params = std::move(params),
         .lifetime_params = std::move(lifetime_params),
         .is_inline = function_decl->isInlined(),
         .member_func_metadata = std::move(member_func_metadata),
         .has_c_calling_convention = has_c_calling_convention,
+        .is_member_or_descendant_of_class_template =
+            is_member_or_descendant_of_class_template,
         .source_loc = ictx_.ConvertSourceLocation(function_decl->getBeginLoc()),
         .id = GenerateItemId(function_decl),
         .enclosing_namespace_id = GetEnclosingNamespaceId(function_decl),