Avoid conflicts/duplicates in `CovertToCcIdentifier(const BazelLabel&)`.

PiperOrigin-RevId: 453679924
diff --git a/docs/sitemap.md b/docs/sitemap.md
index 142ef7b..fd21d77 100644
--- a/docs/sitemap.md
+++ b/docs/sitemap.md
@@ -2,4 +2,5 @@
 *   [Lifetime Annotations for C++](lifetime_annotations_cpp.md)
 *   [Static Analysis for C++ Lifetimes](lifetimes_static_analysis.md)
 *   [Struct Layout](struct_layout.md)
+*   [Thunks for class template member functions](thunks_for_class_template_member_functions.md)
 *   [`Unpin` for C++ Types](unpin.md)
diff --git a/docs/thunks_for_class_template_member_functions.md b/docs/thunks_for_class_template_member_functions.md
new file mode 100644
index 0000000..6f91af8
--- /dev/null
+++ b/docs/thunks_for_class_template_member_functions.md
@@ -0,0 +1,172 @@
+# Thunks for class template member functions
+
+## Problem definition
+
+Given the C++ header below...
+
+```cpp
+#pragma clang lifetime_elision
+
+template <typename T>
+class MyTemplate {
+ public:
+  MyTemplate(T value) : value_(value) {}
+  const T& GetValue() const;
+ private:
+  T value_;
+};
+
+using MyIntTemplate = MyTemplate<int>;
+```
+
+... Crubit will generate Rust bindings that can call into the
+`MyTemplate<int>::GetValue()` member function. To support such calls, Crubit has
+to generate a C++ *thunk* (to *instantiate* the class template and to provide a
+symbol for a C-ABI-compatible function that Rust can call into):
+
+```cpp
+extern "C"  // <- C ABI
+int const& __rust_thunk___ZNK10MyTemplateIiE8GetValueEv(
+    const class MyTemplate<int>* __this) {
+  return __this->GetValue();
+}
+```
+
+There are other (non-`template`-related) scenarios that require generating
+thunks (e.g. `inline` functions, or functions that use a custom calling
+convention), but templates bring one extra requirement: a class template can
+be defined in one header (say `my_template.h`) and used in *multiple* other
+headers (e.g. `library_foo/template_user1.h` and
+`library_bar/template_user2.h`). Because of this, the same thunk might need to
+be present in *multiple* generated `..._rs_api_impl.cc` files (e.g. in
+`library_foo_rs_api_impl.cc` and `library_bar_rs_api_impl.cc`). This may lead to
+duplicate symbol errors from the linker:
+
+```stderr
+ld: error: duplicate symbol: __rust_thunk___ZNK10MyTemplateIiE8GetValueEv
+```
+
+## Implemented solution: Encoding target name in the thunk name
+
+One solution is to give each of the generated thunks a unique,
+target/library-specific name, e.g.:
+`__rust_thunk___ZNK10MyTemplateIiE8GetValueEv__library_foo` (note the
+`library_foo` suffix).
+
+Pros:
+
+-   **Minimal extra code complexity** (e.g. no need for templates-specific code
+    in thunk-related code in `src_code_gen.rs`).
+-   **Obviously correct behavior-wise** (e.g. since it is just like other thunks
+    which we assume are implemented correctly).
+
+Cons:
+
+-   **Performance guarantees are unclear**. Binary size depends on link time
+    optimization (LTO) recognizing that all the thunks are identical and
+    deduplicating them.
+
+    -   This seems to work in practice (at least for production binaries).
+    -   Future work: add tests + consider asking LLVM to provide LTO guarantees
+
+-   **Requires escaping Bazel target names** into valid C identifiers. See
+    `ConvertToCcIdentifier(const BazelLabel&)` in `bazel_types.cc`.
+
+## Alternative solutions
+
+### Function template
+
+An alternative solution would be to use a function template that we immediately
+explicitly instantiate. These still generate the code we need, but their
+duplicated symbol definitions (across multiple binding crates) won't cause an
+ODR violation. It is expected that a single function template is instantiated
+multiple times in multiple translation units, therefore the linker silently
+merges these equivalent definitions.
+
+Example:
+
+```cpp
+// Thunk is expressed as a function template:
+template <typename = void>
+__attribute__((__always_inline__)) int const&
+__rust_thunk___ZNK10MyTemplateIiE8GetValueEv(
+    const class MyTemplate<int>* __this) {
+  return __this->GetValue();
+}
+
+// Explicit instantiation of the function template:
+// (to generate a symbol that `..._rs_api.rs` can call into)
+template int const& __rust_thunk___ZNK10MyTemplateIiE8GetValueEv(
+    const class MyTemplate<int>* __this);
+```
+
+Pros:
+
+-   **Naturally deduplicated** (just depending on what C++ already does for
+    function templates).
+
+Cons:
+
+-   **Depends on implementation details of Clang**:
+    -   It is unclear if the function template specialization is guaranteed to
+        use the C calling convention
+    -   Requires calculating the mangled name of the function template
+        specialization.
+        -   Crubit doesn’t have a `clang::FunctionDecl` corresponding to the
+            function-template-based thunk, and therefore Crubit can’t use
+            `clang::MangleContext::mangleName` to calculate the linkable/mangled
+            name of the thunk.
+        -   Reimplementing `clang::MangleContext::mangleName` in Crubit seems
+            fragile. One risk is bugs in Crubit's code that would make it behave
+            differently from Clang (e.g. code review of the initial prototype
+            identified that
+            [mangling compression](https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression)
+            was missing). Another risk is having to implement not just
+            `ItaniumMangleContext`, but also `MicrosoftMangleContext`.
+        -   One idea to avoid reimpliementing mangling is to explicitly specify
+            the name for the function template instantiation using
+            `__asm__("abc")` (sadly this doesn't seem to work - it may be a
+            Clang bug).
+
+An abandoned prototype of this approach can be found in a (Google-internal)
+cl/450495903.
+
+### Explicit `linkonce_odr` attribute
+
+Example:
+
+```cpp
+extern "C"
+int const& __rust_thunk___ZNK10MyTemplateIiE8GetValueEv(
+    const class MyTemplate<int>* __this)
+    __attribute__((linkonce_odr))  // <- THIS IS THE PROPOSAL
+{
+  return __this->GetValue();
+}
+```
+
+Pros:
+
+-   All the "pros" of the "Encoding target name in the thunk name" approach
+    (simplicity + correctness of behavior)
+-   All the "pros" of the "Function template" template approach (deduplication)
+
+Cons:
+
+-   Requires changing Clang to support the new attribute (e.g. requires
+    convincing the Clang community that this is a language extension that is
+    worth supporting).
+    **TODO(b/234889162)**: Send out a short RFC to gauge interest?
+
+## Rejected solutions
+
+-   [`selectany`](https://clang.llvm.org/docs/AttributeReference.html#selectany)
+    doesn't work with functions, only data members. Furthermore, we need
+    something that maps to `linkonce_odr`, and selectany maps only to
+    `linkonce`.
+
+-   `__attribute__((weak))` has the disadvantage that a weak definition can be
+    overridden by a strong one. This rule makes weak definitions non-inlineable
+    except in full-program LTO. C++ function template instead follows the ODR
+    rule that says that all definitions must be equivalent, making them
+    inlineable.
diff --git a/rs_bindings_from_cc/BUILD b/rs_bindings_from_cc/BUILD
index c22994a..ef337d9 100644
--- a/rs_bindings_from_cc/BUILD
+++ b/rs_bindings_from_cc/BUILD
@@ -124,11 +124,21 @@
     srcs = ["bazel_types.cc"],
     hdrs = ["bazel_types.h"],
     deps = [
+        "//common:check",
         "//common:string_type",
         "@absl//absl/strings",
     ],
 )
 
+cc_test(
+    name = "bazel_types_test",
+    srcs = ["bazel_types_test.cc"],
+    deps = [
+        ":bazel_types",
+        "@com_google_googletest//:gtest_main",
+    ],
+)
+
 cc_library(
     name = "cmdline",
     srcs = ["cmdline.cc"],
diff --git a/rs_bindings_from_cc/bazel_types.cc b/rs_bindings_from_cc/bazel_types.cc
index fa4cde8..dd8f60a 100644
--- a/rs_bindings_from_cc/bazel_types.cc
+++ b/rs_bindings_from_cc/bazel_types.cc
@@ -4,27 +4,36 @@
 
 #include "rs_bindings_from_cc/bazel_types.h"
 
+#include <limits>
+
 #include "absl/strings/ascii.h"
+#include "absl/strings/str_cat.h"
+#include "common/check.h"
 
 namespace crubit {
 
 std::string ConvertToCcIdentifier(const BazelLabel& target) {
-  std::string result = target.value();
+  std::string result;
+  {
+    size_t predicted_length = target.value().size();
+    if (predicted_length < (std::numeric_limits<size_t>::max() / 2))
+      predicted_length *= 2;
+    result.reserve(predicted_length);
+  }
 
-  // TODO(b/222001243): The escaping below can arrive at the same result for 2
-  // distinct targets like //foo/bar:baz and //foo_bar:baz.  In the long-term
-  // this should be fixed, or alternatively ConvertToCcIdentifier should be
-  // removed (the latter is the current plan of record - see also "Handling
-  // thunks" section in <internal link>).
-  for (char& c : result) {
-    if (!absl::ascii_isalnum(c)) {
-      c = '_';
+  // This is yet another escaping scheme... :-/  Compare this with
+  // https://github.com/bazelbuild/rules_rust/blob/1f2e6231de29d8fad8d21486f0d16403632700bf/rust/private/utils.bzl#L459-L586
+  for (char c : target.value()) {
+    if (absl::ascii_isalnum(c)) {
+      result += c;
+    } else {
+      absl::StrAppend(&result, "_", absl::Hex(c, absl::kZeroPad2));
     }
   }
-  if (!result.empty() && !absl::ascii_isalpha(result[0])) {
-    result[0] = '_';
-  }
+  result.shrink_to_fit();
 
+  CRUBIT_CHECK(!result.empty());
+  CRUBIT_CHECK(absl::ascii_isalpha(result[0]) || result[0] == '_');
   return result;
 }
 
diff --git a/rs_bindings_from_cc/bazel_types_test.cc b/rs_bindings_from_cc/bazel_types_test.cc
new file mode 100644
index 0000000..f2e7657
--- /dev/null
+++ b/rs_bindings_from_cc/bazel_types_test.cc
@@ -0,0 +1,35 @@
+// Part of the Crubit project, under the Apache License v2.0 with LLVM
+// Exceptions. See /LICENSE for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+#include "rs_bindings_from_cc/bazel_types.h"
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace crubit {
+
+TEST(BazelTypesTest,
+     ConvertBazelLabelToCcIdentifier_AlphanumericNotTransformed) {
+  constexpr absl::string_view kTestInputs[] = {
+      "abc",
+      "foo123",
+  };
+  for (absl::string_view kTestInput : kTestInputs) {
+    EXPECT_EQ(kTestInput,
+              ConvertToCcIdentifier(BazelLabel(std::string(kTestInput))));
+  }
+}
+
+TEST(BazelTypesTest, ConvertBazelLabelToCcIdentifier_SimpleTargets) {
+  EXPECT_EQ(
+      "_2f_2ffoo_2fbar_3abaz_5fabc",
+      ConvertToCcIdentifier(BazelLabel(std::string("//foo/bar:baz_abc"))));
+}
+
+TEST(BazelTypesTest, ConvertBazelLabelToCcIdentifier_Conflict) {
+  EXPECT_NE(ConvertToCcIdentifier(BazelLabel(std::string("//foo_bar:baz"))),
+            ConvertToCcIdentifier(BazelLabel(std::string("//foo/bar:baz"))));
+}
+
+}  // namespace crubit
diff --git a/rs_bindings_from_cc/importers/function.cc b/rs_bindings_from_cc/importers/function.cc
index 3d8d3ac..2996dd9 100644
--- a/rs_bindings_from_cc/importers/function.cc
+++ b/rs_bindings_from_cc/importers/function.cc
@@ -219,11 +219,9 @@
 
   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>
+    // `thunks_for_class_template_member_functions.md` explains in more detail
+    // why the `mangled_name` has to include the target name when working with
+    // members or descendants of a class template.
     mangled_name += '_';
     mangled_name += ConvertToCcIdentifier(ictx_.GetOwningTarget(function_decl));
   }
diff --git a/rs_bindings_from_cc/ir_from_cc_test.rs b/rs_bindings_from_cc/ir_from_cc_test.rs
index 6e66263..a49f6b1 100644
--- a/rs_bindings_from_cc/ir_from_cc_test.rs
+++ b/rs_bindings_from_cc/ir_from_cc_test.rs
@@ -943,7 +943,7 @@
           Func {
             name: "GetValue",
             owning_target: BazelLabel("//test:testing_target"),
-            mangled_name: "_ZNK8MyStructIiE8GetValueEv___test_testing_target", ...
+            mangled_name: "_ZNK8MyStructIiE8GetValueEv__2f_2ftest_3atesting_5ftarget", ...
             doc_comment: Some("Doc comment of GetValue method."), ...
             is_inline: true, ...
             member_func_metadata: Some(MemberFuncMetadata {
@@ -963,7 +963,7 @@
           Func {
               name: "operator=",
               owning_target: BazelLabel("//test:testing_target"),
-              mangled_name: "_ZN8MyStructIiEaSERKS0____test_testing_target", ...
+              mangled_name: "_ZN8MyStructIiEaSERKS0___2f_2ftest_3atesting_5ftarget", ...
               doc_comment: None, ...
           }
         }
@@ -1025,7 +1025,7 @@
           Func {
             name: "GetValue",
             owning_target: BazelLabel("//test:testing_target"),
-            mangled_name: "_ZNK8MyStructIiE8GetValueEv___test_testing_target", ...
+            mangled_name: "_ZNK8MyStructIiE8GetValueEv__2f_2ftest_3atesting_5ftarget", ...
             doc_comment: Some("Doc comment of the GetValue method specialization for T=int."), ...
             is_inline: true, ...
             member_func_metadata: Some(MemberFuncMetadata {
@@ -1207,7 +1207,7 @@
         quote! {
             Func {
                 name: "GetSum", ...
-                mangled_name: "_ZN8MyStructIJiiEE6GetSumEii___test_testing_target", ...
+                mangled_name: "_ZN8MyStructIJiiEE6GetSumEii__2f_2ftest_3atesting_5ftarget", ...
                 params: [
                     FuncParam {
                         type_: MappedType {
diff --git a/rs_bindings_from_cc/src_code_gen.rs b/rs_bindings_from_cc/src_code_gen.rs
index f182386..a26c241 100644
--- a/rs_bindings_from_cc/src_code_gen.rs
+++ b/rs_bindings_from_cc/src_code_gen.rs
@@ -2823,7 +2823,7 @@
                 impl __CcTemplateInst10MyTemplateIiE {
                     #[inline(always)]
                     pub fn GetValue<'a>(self: ... Pin<&'a mut Self>) -> i32 { unsafe {
-                        crate::detail::__rust_thunk___ZN10MyTemplateIiE8GetValueEv___test_testing_target(
+                        crate::detail::__rust_thunk___ZN10MyTemplateIiE8GetValueEv__2f_2ftest_3atesting_5ftarget(
                             self)
                     }}
                 }
@@ -2838,23 +2838,21 @@
         assert_rs_matches!(
             rs_api,
             quote! {
-                mod detail {
+                mod detail { ...  extern "C" {
                     ...
-                    extern "C" {
-                        ...
-                        pub(crate) fn
-                        __rust_thunk___ZN10MyTemplateIiE8GetValueEv___test_testing_target<'a>(
-                            __this: ... Pin<&'a mut crate::__CcTemplateInst10MyTemplateIiE>
-                        ) -> i32;
-                        ...
-                    }
-                }
+                    pub(crate) fn
+                    __rust_thunk___ZN10MyTemplateIiE8GetValueEv__2f_2ftest_3atesting_5ftarget<'a>(
+                        __this: ... Pin<&'a mut crate::__CcTemplateInst10MyTemplateIiE>
+                    ) -> i32;
+                    ...
+                } }
             }
         );
         assert_cc_matches!(
             rs_api_impl,
             quote! {
-                extern "C" int __rust_thunk___ZN10MyTemplateIiE8GetValueEv___test_testing_target(
+                extern "C"
+                int __rust_thunk___ZN10MyTemplateIiE8GetValueEv__2f_2ftest_3atesting_5ftarget(
                         class MyTemplate<int>* __this) {
                     return __this->GetValue();
                 }
@@ -2901,7 +2899,8 @@
             rs_api_impl,
             quote! {
                 extern "C" class MyTemplate<int>
-                __rust_thunk___ZN10MyTemplateIiE6CreateEi___test_testing_target(int value) {
+                __rust_thunk___ZN10MyTemplateIiE6CreateEi__2f_2ftest_3atesting_5ftarget(
+                        int value) {
                     return MyTemplate<int>::Create(std::forward<decltype(value)>(value));
                 }
             }
@@ -2910,7 +2909,7 @@
             rs_api_impl,
             quote! {
                 extern "C" int const&
-                __rust_thunk___ZNK10MyTemplateIiE5valueEv___test_testing_target(
+                __rust_thunk___ZNK10MyTemplateIiE5valueEv__2f_2ftest_3atesting_5ftarget(
                         const class MyTemplate<int>*__this) {
                     return __this->value();
                 }
diff --git a/rs_bindings_from_cc/test/golden/doc_comment_rs_api.rs b/rs_bindings_from_cc/test/golden/doc_comment_rs_api.rs
index 8d67db3..d21b69b 100644
--- a/rs_bindings_from_cc/test/golden/doc_comment_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/doc_comment_rs_api.rs
@@ -305,7 +305,7 @@
     fn default() -> Self {
         let mut tmp = crate::rust_std::mem::MaybeUninit::<Self>::zeroed();
         unsafe {
-            crate::detail::__rust_thunk___ZN10MyTemplateIfEC1Ev___third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc(&mut tmp);
+            crate::detail::__rust_thunk___ZN10MyTemplateIfEC1Ev__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc(&mut tmp);
             tmp.assume_init()
         }
     }
@@ -318,7 +318,7 @@
     fn from(__param_0: ctor::RvalueReference<'b, crate::__CcTemplateInst10MyTemplateIfE>) -> Self {
         let mut tmp = crate::rust_std::mem::MaybeUninit::<Self>::zeroed();
         unsafe {
-            crate::detail::__rust_thunk___ZN10MyTemplateIfEC1EOS0____third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc(&mut tmp,__param_0);
+            crate::detail::__rust_thunk___ZN10MyTemplateIfEC1EOS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc(&mut tmp,__param_0);
             tmp.assume_init()
         }
     }
@@ -337,7 +337,7 @@
     #[inline(always)]
     pub fn get_field_value<'a>(&'a self) -> &'a f32 {
         unsafe {
-            crate::detail::__rust_thunk___ZNK10MyTemplateIfE15get_field_valueEv___third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc(self)
+            crate::detail::__rust_thunk___ZNK10MyTemplateIfE15get_field_valueEv__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc(self)
         }
     }
 }
@@ -375,7 +375,7 @@
     fn default() -> Self {
         let mut tmp = crate::rust_std::mem::MaybeUninit::<Self>::zeroed();
         unsafe {
-            crate::detail::__rust_thunk___ZN10MyTemplateIiEC1Ev___third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc(&mut tmp);
+            crate::detail::__rust_thunk___ZN10MyTemplateIiEC1Ev__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc(&mut tmp);
             tmp.assume_init()
         }
     }
@@ -388,7 +388,7 @@
     fn from(__param_0: ctor::RvalueReference<'b, crate::__CcTemplateInst10MyTemplateIiE>) -> Self {
         let mut tmp = crate::rust_std::mem::MaybeUninit::<Self>::zeroed();
         unsafe {
-            crate::detail::__rust_thunk___ZN10MyTemplateIiEC1EOS0____third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc(&mut tmp,__param_0);
+            crate::detail::__rust_thunk___ZN10MyTemplateIiEC1EOS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc(&mut tmp,__param_0);
             tmp.assume_init()
         }
     }
@@ -409,7 +409,7 @@
     #[inline(always)]
     pub fn get_field_value<'a>(&'a self) -> &'a i32 {
         unsafe {
-            crate::detail::__rust_thunk___ZNK10MyTemplateIiE15get_field_valueEv___third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc(self)
+            crate::detail::__rust_thunk___ZNK10MyTemplateIiE15get_field_valueEv__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc(self)
         }
     }
 }
@@ -471,14 +471,14 @@
             __param_0: ctor::RvalueReference<'b, crate::MultilineOneStar>,
         );
         pub(crate) fn __rust_thunk___Z3foov() -> i32;
-        pub(crate) fn __rust_thunk___ZN10MyTemplateIfEC1Ev___third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc<
+        pub(crate) fn __rust_thunk___ZN10MyTemplateIfEC1Ev__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc<
             'a,
         >(
             __this: &'a mut crate::rust_std::mem::MaybeUninit<
                 crate::__CcTemplateInst10MyTemplateIfE,
             >,
         );
-        pub(crate) fn __rust_thunk___ZN10MyTemplateIfEC1EOS0____third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc<
+        pub(crate) fn __rust_thunk___ZN10MyTemplateIfEC1EOS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc<
             'a,
             'b,
         >(
@@ -487,19 +487,19 @@
             >,
             __param_0: ctor::RvalueReference<'b, crate::__CcTemplateInst10MyTemplateIfE>,
         );
-        pub(crate) fn __rust_thunk___ZNK10MyTemplateIfE15get_field_valueEv___third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc<
+        pub(crate) fn __rust_thunk___ZNK10MyTemplateIfE15get_field_valueEv__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc<
             'a,
         >(
             __this: &'a crate::__CcTemplateInst10MyTemplateIfE,
         ) -> &'a f32;
-        pub(crate) fn __rust_thunk___ZN10MyTemplateIiEC1Ev___third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc<
+        pub(crate) fn __rust_thunk___ZN10MyTemplateIiEC1Ev__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc<
             'a,
         >(
             __this: &'a mut crate::rust_std::mem::MaybeUninit<
                 crate::__CcTemplateInst10MyTemplateIiE,
             >,
         );
-        pub(crate) fn __rust_thunk___ZN10MyTemplateIiEC1EOS0____third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc<
+        pub(crate) fn __rust_thunk___ZN10MyTemplateIiEC1EOS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc<
             'a,
             'b,
         >(
@@ -508,7 +508,7 @@
             >,
             __param_0: ctor::RvalueReference<'b, crate::__CcTemplateInst10MyTemplateIiE>,
         );
-        pub(crate) fn __rust_thunk___ZNK10MyTemplateIiE15get_field_valueEv___third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc<
+        pub(crate) fn __rust_thunk___ZNK10MyTemplateIiE15get_field_valueEv__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc<
             'a,
         >(
             __this: &'a crate::__CcTemplateInst10MyTemplateIiE,
diff --git a/rs_bindings_from_cc/test/golden/doc_comment_rs_api_impl.cc b/rs_bindings_from_cc/test/golden/doc_comment_rs_api_impl.cc
index ce1e8fe..737378f 100644
--- a/rs_bindings_from_cc/test/golden/doc_comment_rs_api_impl.cc
+++ b/rs_bindings_from_cc/test/golden/doc_comment_rs_api_impl.cc
@@ -143,72 +143,72 @@
 }
 extern "C" int __rust_thunk___Z3foov() { return foo(); }
 extern "C" void
-__rust_thunk___ZN10MyTemplateIiEC1Ev___third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc(
+__rust_thunk___ZN10MyTemplateIiEC1Ev__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc(
     class MyTemplate<int>* __this) {
   crubit::construct_at(std::forward<decltype(__this)>(__this));
 }
 extern "C" void
-__rust_thunk___ZN10MyTemplateIiEC1ERKS0____third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc(
+__rust_thunk___ZN10MyTemplateIiEC1ERKS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc(
     class MyTemplate<int>* __this, const class MyTemplate<int>& __param_0) {
   crubit::construct_at(std::forward<decltype(__this)>(__this),
                        std::forward<decltype(__param_0)>(__param_0));
 }
 extern "C" void
-__rust_thunk___ZN10MyTemplateIiEC1EOS0____third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc(
+__rust_thunk___ZN10MyTemplateIiEC1EOS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc(
     class MyTemplate<int>* __this, class MyTemplate<int>&& __param_0) {
   crubit::construct_at(std::forward<decltype(__this)>(__this),
                        std::forward<decltype(__param_0)>(__param_0));
 }
 extern "C" void
-__rust_thunk___ZN10MyTemplateIiED1Ev___third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc(
+__rust_thunk___ZN10MyTemplateIiED1Ev__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc(
     class MyTemplate<int>* __this) {
   std::destroy_at(std::forward<decltype(__this)>(__this));
 }
 extern "C" class MyTemplate<int>&
-__rust_thunk___ZN10MyTemplateIiEaSERKS0____third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc(
+__rust_thunk___ZN10MyTemplateIiEaSERKS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc(
     class MyTemplate<int>* __this, const class MyTemplate<int>& __param_0) {
   return __this->operator=(std::forward<decltype(__param_0)>(__param_0));
 } extern "C" class MyTemplate<int>&
-__rust_thunk___ZN10MyTemplateIiEaSEOS0____third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc(
+__rust_thunk___ZN10MyTemplateIiEaSEOS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc(
     class MyTemplate<int>* __this, class MyTemplate<int>&& __param_0) {
   return __this->operator=(std::forward<decltype(__param_0)>(__param_0));
 } extern "C" int const&
-__rust_thunk___ZNK10MyTemplateIiE15get_field_valueEv___third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc(
+__rust_thunk___ZNK10MyTemplateIiE15get_field_valueEv__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc(
     const class MyTemplate<int>* __this) {
   return __this->get_field_value();
 }
 extern "C" void
-__rust_thunk___ZN10MyTemplateIfEC1Ev___third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc(
+__rust_thunk___ZN10MyTemplateIfEC1Ev__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc(
     class MyTemplate<float>* __this) {
   crubit::construct_at(std::forward<decltype(__this)>(__this));
 }
 extern "C" void
-__rust_thunk___ZN10MyTemplateIfEC1ERKS0____third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc(
+__rust_thunk___ZN10MyTemplateIfEC1ERKS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc(
     class MyTemplate<float>* __this, const class MyTemplate<float>& __param_0) {
   crubit::construct_at(std::forward<decltype(__this)>(__this),
                        std::forward<decltype(__param_0)>(__param_0));
 }
 extern "C" void
-__rust_thunk___ZN10MyTemplateIfEC1EOS0____third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc(
+__rust_thunk___ZN10MyTemplateIfEC1EOS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc(
     class MyTemplate<float>* __this, class MyTemplate<float>&& __param_0) {
   crubit::construct_at(std::forward<decltype(__this)>(__this),
                        std::forward<decltype(__param_0)>(__param_0));
 }
 extern "C" void
-__rust_thunk___ZN10MyTemplateIfED1Ev___third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc(
+__rust_thunk___ZN10MyTemplateIfED1Ev__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc(
     class MyTemplate<float>* __this) {
   std::destroy_at(std::forward<decltype(__this)>(__this));
 }
 extern "C" class MyTemplate<float>&
-__rust_thunk___ZN10MyTemplateIfEaSERKS0____third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc(
+__rust_thunk___ZN10MyTemplateIfEaSERKS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc(
     class MyTemplate<float>* __this, const class MyTemplate<float>& __param_0) {
   return __this->operator=(std::forward<decltype(__param_0)>(__param_0));
 } extern "C" class MyTemplate<float>&
-__rust_thunk___ZN10MyTemplateIfEaSEOS0____third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc(
+__rust_thunk___ZN10MyTemplateIfEaSEOS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc(
     class MyTemplate<float>* __this, class MyTemplate<float>&& __param_0) {
   return __this->operator=(std::forward<decltype(__param_0)>(__param_0));
 } extern "C" float const&
-__rust_thunk___ZNK10MyTemplateIfE15get_field_valueEv___third_party_crubit_rs_bindings_from_cc_test_golden_doc_comment_cc(
+__rust_thunk___ZNK10MyTemplateIfE15get_field_valueEv__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3adoc_5fcomment_5fcc(
     const class MyTemplate<float>* __this) {
   return __this->get_field_value();
 }
diff --git a/rs_bindings_from_cc/test/golden/templates_rs_api.rs b/rs_bindings_from_cc/test/golden/templates_rs_api.rs
index f6cdbf6..0a7cf64 100644
--- a/rs_bindings_from_cc/test/golden/templates_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/templates_rs_api.rs
@@ -53,7 +53,7 @@
         let () = args;
         ctor::FnCtor::new(
             move |dest: crate::rust_std::pin::Pin<&mut crate::rust_std::mem::MaybeUninit<Self>>| unsafe {
-                crate::detail::__rust_thunk___ZN10MyTemplateIiEC1Ev___third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(crate::rust_std::pin::Pin::into_inner_unchecked(dest));
+                crate::detail::__rust_thunk___ZN10MyTemplateIiEC1Ev__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(crate::rust_std::pin::Pin::into_inner_unchecked(dest));
             },
         )
     }
@@ -68,7 +68,7 @@
         let __param_0 = args;
         ctor::FnCtor::new(
             move |dest: crate::rust_std::pin::Pin<&mut crate::rust_std::mem::MaybeUninit<Self>>| unsafe {
-                crate::detail::__rust_thunk___ZN10MyTemplateIiEC1ERKS0____third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(crate::rust_std::pin::Pin::into_inner_unchecked(dest),__param_0);
+                crate::detail::__rust_thunk___ZN10MyTemplateIiEC1ERKS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(crate::rust_std::pin::Pin::into_inner_unchecked(dest),__param_0);
             },
         )
     }
@@ -95,7 +95,7 @@
         let __param_0 = args;
         ctor::FnCtor::new(
             move |dest: crate::rust_std::pin::Pin<&mut crate::rust_std::mem::MaybeUninit<Self>>| unsafe {
-                crate::detail::__rust_thunk___ZN10MyTemplateIiEC1EOS0____third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(crate::rust_std::pin::Pin::into_inner_unchecked(dest),__param_0);
+                crate::detail::__rust_thunk___ZN10MyTemplateIiEC1EOS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(crate::rust_std::pin::Pin::into_inner_unchecked(dest),__param_0);
             },
         )
     }
@@ -125,7 +125,7 @@
     #[inline(always)]
     pub fn Create(value: i32) -> crate::__CcTemplateInst10MyTemplateIiE {
         unsafe {
-            crate::detail::__rust_thunk___ZN10MyTemplateIiE6CreateEi___third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(value)
+            crate::detail::__rust_thunk___ZN10MyTemplateIiE6CreateEi__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(value)
         }
     }
 }
@@ -134,7 +134,7 @@
     #[inline(always)]
     pub fn value<'a>(&'a self) -> &'a i32 {
         unsafe {
-            crate::detail::__rust_thunk___ZNK10MyTemplateIiE5valueEv___third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(self)
+            crate::detail::__rust_thunk___ZNK10MyTemplateIiE5valueEv__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(self)
         }
     }
 }
@@ -157,7 +157,7 @@
         let () = args;
         ctor::FnCtor::new(
             move |dest: crate::rust_std::pin::Pin<&mut crate::rust_std::mem::MaybeUninit<Self>>| unsafe {
-                crate::detail::__rust_thunk___ZN21TemplateWithTwoParamsIifEC1Ev___third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(crate::rust_std::pin::Pin::into_inner_unchecked(dest));
+                crate::detail::__rust_thunk___ZN21TemplateWithTwoParamsIifEC1Ev__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(crate::rust_std::pin::Pin::into_inner_unchecked(dest));
             },
         )
     }
@@ -172,7 +172,7 @@
         let __param_0 = args;
         ctor::FnCtor::new(
             move |dest: crate::rust_std::pin::Pin<&mut crate::rust_std::mem::MaybeUninit<Self>>| unsafe {
-                crate::detail::__rust_thunk___ZN21TemplateWithTwoParamsIifEC1ERKS0____third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(crate::rust_std::pin::Pin::into_inner_unchecked(dest),__param_0);
+                crate::detail::__rust_thunk___ZN21TemplateWithTwoParamsIifEC1ERKS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(crate::rust_std::pin::Pin::into_inner_unchecked(dest),__param_0);
             },
         )
     }
@@ -202,7 +202,7 @@
         let __param_0 = args;
         ctor::FnCtor::new(
             move |dest: crate::rust_std::pin::Pin<&mut crate::rust_std::mem::MaybeUninit<Self>>| unsafe {
-                crate::detail::__rust_thunk___ZN21TemplateWithTwoParamsIifEC1EOS0____third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(crate::rust_std::pin::Pin::into_inner_unchecked(dest),__param_0);
+                crate::detail::__rust_thunk___ZN21TemplateWithTwoParamsIifEC1EOS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(crate::rust_std::pin::Pin::into_inner_unchecked(dest),__param_0);
             },
         )
     }
@@ -235,14 +235,14 @@
     #[allow(unused_imports)]
     use super::*;
     extern "C" {
-        pub(crate) fn __rust_thunk___ZN10MyTemplateIiEC1Ev___third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc<
+        pub(crate) fn __rust_thunk___ZN10MyTemplateIiEC1Ev__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc<
             'a,
         >(
             __this: &'a mut crate::rust_std::mem::MaybeUninit<
                 crate::__CcTemplateInst10MyTemplateIiE,
             >,
         );
-        pub(crate) fn __rust_thunk___ZN10MyTemplateIiEC1ERKS0____third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc<
+        pub(crate) fn __rust_thunk___ZN10MyTemplateIiEC1ERKS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc<
             'a,
             'b,
         >(
@@ -251,7 +251,7 @@
             >,
             __param_0: &'b crate::__CcTemplateInst10MyTemplateIiE,
         );
-        pub(crate) fn __rust_thunk___ZN10MyTemplateIiEC1EOS0____third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc<
+        pub(crate) fn __rust_thunk___ZN10MyTemplateIiEC1EOS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc<
             'a,
             'b,
         >(
@@ -260,22 +260,22 @@
             >,
             __param_0: ctor::RvalueReference<'b, crate::__CcTemplateInst10MyTemplateIiE>,
         );
-        pub(crate) fn __rust_thunk___ZN10MyTemplateIiE6CreateEi___third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(
+        pub(crate) fn __rust_thunk___ZN10MyTemplateIiE6CreateEi__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(
             value: i32,
         ) -> crate::__CcTemplateInst10MyTemplateIiE;
-        pub(crate) fn __rust_thunk___ZNK10MyTemplateIiE5valueEv___third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc<
+        pub(crate) fn __rust_thunk___ZNK10MyTemplateIiE5valueEv__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc<
             'a,
         >(
             __this: &'a crate::__CcTemplateInst10MyTemplateIiE,
         ) -> &'a i32;
-        pub(crate) fn __rust_thunk___ZN21TemplateWithTwoParamsIifEC1Ev___third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc<
+        pub(crate) fn __rust_thunk___ZN21TemplateWithTwoParamsIifEC1Ev__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc<
             'a,
         >(
             __this: &'a mut crate::rust_std::mem::MaybeUninit<
                 crate::__CcTemplateInst21TemplateWithTwoParamsIifE,
             >,
         );
-        pub(crate) fn __rust_thunk___ZN21TemplateWithTwoParamsIifEC1ERKS0____third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc<
+        pub(crate) fn __rust_thunk___ZN21TemplateWithTwoParamsIifEC1ERKS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc<
             'a,
             'b,
         >(
@@ -284,7 +284,7 @@
             >,
             __param_0: &'b crate::__CcTemplateInst21TemplateWithTwoParamsIifE,
         );
-        pub(crate) fn __rust_thunk___ZN21TemplateWithTwoParamsIifEC1EOS0____third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc<
+        pub(crate) fn __rust_thunk___ZN21TemplateWithTwoParamsIifEC1EOS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc<
             'a,
             'b,
         >(
diff --git a/rs_bindings_from_cc/test/golden/templates_rs_api_impl.cc b/rs_bindings_from_cc/test/golden/templates_rs_api_impl.cc
index cef53db..32f3d5b 100644
--- a/rs_bindings_from_cc/test/golden/templates_rs_api_impl.cc
+++ b/rs_bindings_from_cc/test/golden/templates_rs_api_impl.cc
@@ -12,75 +12,75 @@
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wthread-safety-analysis"
 extern "C" void
-__rust_thunk___ZN10MyTemplateIiEC1Ev___third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(
+__rust_thunk___ZN10MyTemplateIiEC1Ev__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(
     class MyTemplate<int>* __this) {
   crubit::construct_at(std::forward<decltype(__this)>(__this));
 }
 extern "C" void
-__rust_thunk___ZN10MyTemplateIiEC1ERKS0____third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(
+__rust_thunk___ZN10MyTemplateIiEC1ERKS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(
     class MyTemplate<int>* __this, const class MyTemplate<int>& __param_0) {
   crubit::construct_at(std::forward<decltype(__this)>(__this),
                        std::forward<decltype(__param_0)>(__param_0));
 }
 extern "C" void
-__rust_thunk___ZN10MyTemplateIiEC1EOS0____third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(
+__rust_thunk___ZN10MyTemplateIiEC1EOS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(
     class MyTemplate<int>* __this, class MyTemplate<int>&& __param_0) {
   crubit::construct_at(std::forward<decltype(__this)>(__this),
                        std::forward<decltype(__param_0)>(__param_0));
 }
 extern "C" void
-__rust_thunk___ZN10MyTemplateIiED1Ev___third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(
+__rust_thunk___ZN10MyTemplateIiED1Ev__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(
     class MyTemplate<int>* __this) {
   std::destroy_at(std::forward<decltype(__this)>(__this));
 }
 extern "C" class MyTemplate<int>&
-__rust_thunk___ZN10MyTemplateIiEaSERKS0____third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(
+__rust_thunk___ZN10MyTemplateIiEaSERKS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(
     class MyTemplate<int>* __this, const class MyTemplate<int>& __param_0) {
   return __this->operator=(std::forward<decltype(__param_0)>(__param_0));
 } extern "C" class MyTemplate<int>&
-__rust_thunk___ZN10MyTemplateIiEaSEOS0____third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(
+__rust_thunk___ZN10MyTemplateIiEaSEOS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(
     class MyTemplate<int>* __this, class MyTemplate<int>&& __param_0) {
   return __this->operator=(std::forward<decltype(__param_0)>(__param_0));
 } extern "C" class MyTemplate<int>
-__rust_thunk___ZN10MyTemplateIiE6CreateEi___third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(
+__rust_thunk___ZN10MyTemplateIiE6CreateEi__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(
     int value) {
   return MyTemplate<int>::Create(std::forward<decltype(value)>(value));
 } extern "C" int const&
-__rust_thunk___ZNK10MyTemplateIiE5valueEv___third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(
+__rust_thunk___ZNK10MyTemplateIiE5valueEv__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(
     const class MyTemplate<int>* __this) {
   return __this->value();
 }
 extern "C" void
-__rust_thunk___ZN21TemplateWithTwoParamsIifEC1Ev___third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(
+__rust_thunk___ZN21TemplateWithTwoParamsIifEC1Ev__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(
     class TemplateWithTwoParams<int, float>* __this) {
   crubit::construct_at(std::forward<decltype(__this)>(__this));
 }
 extern "C" void
-__rust_thunk___ZN21TemplateWithTwoParamsIifEC1ERKS0____third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(
+__rust_thunk___ZN21TemplateWithTwoParamsIifEC1ERKS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(
     class TemplateWithTwoParams<int, float>* __this,
     const class TemplateWithTwoParams<int, float>& __param_0) {
   crubit::construct_at(std::forward<decltype(__this)>(__this),
                        std::forward<decltype(__param_0)>(__param_0));
 }
 extern "C" void
-__rust_thunk___ZN21TemplateWithTwoParamsIifEC1EOS0____third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(
+__rust_thunk___ZN21TemplateWithTwoParamsIifEC1EOS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(
     class TemplateWithTwoParams<int, float>* __this,
     class TemplateWithTwoParams<int, float>&& __param_0) {
   crubit::construct_at(std::forward<decltype(__this)>(__this),
                        std::forward<decltype(__param_0)>(__param_0));
 }
 extern "C" void
-__rust_thunk___ZN21TemplateWithTwoParamsIifED1Ev___third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(
+__rust_thunk___ZN21TemplateWithTwoParamsIifED1Ev__2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(
     class TemplateWithTwoParams<int, float>* __this) {
   std::destroy_at(std::forward<decltype(__this)>(__this));
 }
 extern "C" class TemplateWithTwoParams<int, float>&
-__rust_thunk___ZN21TemplateWithTwoParamsIifEaSERKS0____third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(
+__rust_thunk___ZN21TemplateWithTwoParamsIifEaSERKS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(
     class TemplateWithTwoParams<int, float>* __this,
     const class TemplateWithTwoParams<int, float>& __param_0) {
   return __this->operator=(std::forward<decltype(__param_0)>(__param_0));
 } extern "C" class TemplateWithTwoParams<int, float>&
-__rust_thunk___ZN21TemplateWithTwoParamsIifEaSEOS0____third_party_crubit_rs_bindings_from_cc_test_golden_templates_cc(
+__rust_thunk___ZN21TemplateWithTwoParamsIifEaSEOS0___2f_2fthird_5fparty_2fcrubit_2frs_5fbindings_5ffrom_5fcc_2ftest_2fgolden_3atemplates_5fcc(
     class TemplateWithTwoParams<int, float>* __this,
     class TemplateWithTwoParams<int, float>&& __param_0) {
   return __this->operator=(std::forward<decltype(__param_0)>(__param_0));