Consistently handle explicit and implicit class template specializations.

If a template specialization is used in a type alias (or in a parameter
type, etc.) Crubit's IR includes a corresponding `Record` as a top-level
item.  OTOH, if a template specialization is *not* actually used, then
there is no need to include its `Record`.

Before this CL, the above was haphazardly achieved by checking
`ClassTemplateSpecializationDecl::isExplicitSpecialization` and skipping
explicit specializations, incorrectly assumming that such
specializations are not used in a type alias, etc.

After this CL, the above is achieved by skipping processing of
`ClassTemplateSpecializationDecl` in `GetCanonicalChildren` (and
therefore only processing such decls via
`Importer::ConvertTemplateSpecializationType`).

As a side-effect, this CL also fixes a bug, where we would assume that
all `ClassTemplateSpecializationDecl` have no `enclosing_namespace_id`,
but `GetCanonicalChildren` could still include such decls as children of
a namespace.  The CL adds coverage for this bug under
`test/templates/extern_definition`.

PiperOrigin-RevId: 473297905
diff --git a/rs_bindings_from_cc/importer.cc b/rs_bindings_from_cc/importer.cc
index 4aec2ba..d0874ea 100644
--- a/rs_bindings_from_cc/importer.cc
+++ b/rs_bindings_from_cc/importer.cc
@@ -325,6 +325,14 @@
       continue;
     }
 
+    // `CXXRecordDeclImporter::Import` supports class template specializations
+    // but such import should only be triggered when
+    // `Importer::ConvertTemplateSpecializationType` is called (which means that
+    // the specialization is actually used in an explicit instantiation via
+    // `cc_template!` macro, in a type alias, or as a parameter type of a
+    // function, etc.).
+    if (clang::isa<clang::ClassTemplateSpecializationDecl>(decl)) continue;
+
     // In general we only import (and include as children) canonical decls.
     // Namespaces are exempted to ensure that we process every one of
     // (potential) multiple namespace blocks with the same name.
@@ -640,11 +648,8 @@
   // side-effect and we rely on this here. `decl->getDefinition()` can
   // return nullptr before the call to sema and return its definition
   // afterwards.
-  if (!sema_.isCompleteType(specialization_decl->getLocation(),
-                            ctx_.getRecordType(specialization_decl))) {
-    return absl::InvalidArgumentError(absl::Substitute(
-        "'$0' template specialization is incomplete", type_string));
-  }
+  (void)sema_.isCompleteType(specialization_decl->getLocation(),
+                             ctx_.getRecordType(specialization_decl));
 
   // TODO(lukasza): Limit specialization depth? (e.g. using
   // `isSpecializationDepthGreaterThan` from earlier prototypes).
@@ -657,13 +662,9 @@
         type_string, import_status.message()));
   }
 
-  if (IsFromCurrentTarget(specialization_decl) &&
-      !specialization_decl->isExplicitSpecialization()) {
-    // Store implicit `specialization_decl`s so that they will get included in
-    // IR::top_level_item_ids.
-    class_template_instantiations_for_current_target_.insert(
-        specialization_decl);
-  }
+  // Store `specialization_decl`s so that they will get included in
+  // IR::top_level_item_ids.
+  class_template_instantiations_for_current_target_.insert(specialization_decl);
 
   return ConvertTypeDecl(specialization_decl);
 }