Use mangled type names in `cc_struct_upcast_impl`'s `cast_fn_name`.

PiperOrigin-RevId: 471545380
diff --git a/rs_bindings_from_cc/importer.cc b/rs_bindings_from_cc/importer.cc
index 7bda89f..2db25fa 100644
--- a/rs_bindings_from_cc/importer.cc
+++ b/rs_bindings_from_cc/importer.cc
@@ -854,24 +854,30 @@
 }
 
 std::string Importer::GetMangledName(const clang::NamedDecl* named_decl) const {
-  if (auto specialization_decl =
-          clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(named_decl)) {
-    // Itanium mangler produces valid Rust identifiers, use it to generate a
-    // name for this instantiation.
+  if (auto record_decl = clang::dyn_cast<clang::RecordDecl>(named_decl)) {
+    // Mangled record names are used to 1) provide valid Rust identifiers for
+    // C++ template specializations, and 2) help build unique names for virtual
+    // upcast thunks.
     llvm::SmallString<128> storage;
     llvm::raw_svector_ostream buffer(storage);
-    mangler_->mangleTypeName(ctx_.getRecordType(specialization_decl), buffer);
+    mangler_->mangleTypeName(ctx_.getRecordType(record_decl), buffer);
 
     // The Itanium mangler does not provide a way to get the mangled
     // representation of a type. Instead, we call mangleTypeName() that
     // returns the name of the RTTI typeinfo symbol, and remove the _ZTS
-    // prefix. Then we prepend __CcTemplateInst to reduce chances of conflict
-    // with regular C and C++ structs.
+    // prefix.
     constexpr llvm::StringRef kZtsPrefix = "_ZTS";
-    constexpr llvm::StringRef kCcTemplatePrefix = "__CcTemplateInst";
     CHECK(buffer.str().take_front(4) == kZtsPrefix);
-    return llvm::formatv("{0}{1}", kCcTemplatePrefix,
-                         buffer.str().drop_front(kZtsPrefix.size()));
+    llvm::StringRef mangled_record_name =
+        buffer.str().drop_front(kZtsPrefix.size());
+
+    if (clang::isa<clang::ClassTemplateSpecializationDecl>(named_decl)) {
+      // We prepend __CcTemplateInst to reduce chances of conflict
+      // with regular C and C++ structs.
+      constexpr llvm::StringRef kCcTemplatePrefix = "__CcTemplateInst";
+      return llvm::formatv("{0}{1}", kCcTemplatePrefix, mangled_record_name);
+    }
+    return std::string(mangled_record_name);
   }
 
   clang::GlobalDecl decl;
diff --git a/rs_bindings_from_cc/importers/cxx_record.cc b/rs_bindings_from_cc/importers/cxx_record.cc
index 30aee17..f9c1ea7 100644
--- a/rs_bindings_from_cc/importers/cxx_record.cc
+++ b/rs_bindings_from_cc/importers/cxx_record.cc
@@ -203,6 +203,7 @@
   return Record{
       .rs_name = std::move(rs_name),
       .cc_name = std::move(cc_name),
+      .mangled_cc_name = ictx_.GetMangledName(record_decl),
       .id = GenerateItemId(record_decl),
       .owning_target = ictx_.GetOwningTarget(record_decl),
       .doc_comment = std::move(doc_comment),
diff --git a/rs_bindings_from_cc/ir.cc b/rs_bindings_from_cc/ir.cc
index e883223..9e4b77c 100644
--- a/rs_bindings_from_cc/ir.cc
+++ b/rs_bindings_from_cc/ir.cc
@@ -399,6 +399,7 @@
   llvm::json::Object record{
       {"rs_name", rs_name},
       {"cc_name", cc_name},
+      {"mangled_cc_name", mangled_cc_name},
       {"id", id},
       {"owning_target", owning_target},
       {"doc_comment", doc_comment},
diff --git a/rs_bindings_from_cc/ir.h b/rs_bindings_from_cc/ir.h
index b3eab93..5573849 100644
--- a/rs_bindings_from_cc/ir.h
+++ b/rs_bindings_from_cc/ir.h
@@ -576,6 +576,7 @@
   // `rs_name` is similar to "__CcTemplateInst8MyStructIiE").
   std::string rs_name;
   std::string cc_name;
+  std::string mangled_cc_name;
 
   ItemId id;
   BazelLabel owning_target;
diff --git a/rs_bindings_from_cc/ir.rs b/rs_bindings_from_cc/ir.rs
index 4e3e404..05123ee 100644
--- a/rs_bindings_from_cc/ir.rs
+++ b/rs_bindings_from_cc/ir.rs
@@ -400,6 +400,7 @@
 pub struct Record {
     pub rs_name: String,
     pub cc_name: String,
+    pub mangled_cc_name: String,
     pub id: ItemId,
     pub owning_target: BazelLabel,
     pub doc_comment: Option<String>,
diff --git a/rs_bindings_from_cc/ir_from_cc_test.rs b/rs_bindings_from_cc/ir_from_cc_test.rs
index e1d3777..bad43c1 100644
--- a/rs_bindings_from_cc/ir_from_cc_test.rs
+++ b/rs_bindings_from_cc/ir_from_cc_test.rs
@@ -2170,6 +2170,7 @@
            Record {
                rs_name: "DerivedClass",
                cc_name: "DerivedClass",
+               mangled_cc_name: "12DerivedClass",
                id: ItemId(...),
                owning_target: BazelLabel("//test:testing_target"),
                doc_comment: Some(...),
@@ -2308,6 +2309,7 @@
             Record {
                 rs_name: "SomeStruct" ...
                 cc_name: "SomeStruct" ...
+                mangled_cc_name: "10SomeStruct" ...
                 fields: [
                     Field {
                         identifier: Some("first_field"), ...
diff --git a/rs_bindings_from_cc/src_code_gen.rs b/rs_bindings_from_cc/src_code_gen.rs
index bd8bc85..f96b863 100644
--- a/rs_bindings_from_cc/src_code_gen.rs
+++ b/rs_bindings_from_cc/src_code_gen.rs
@@ -3165,11 +3165,9 @@
             let offset = Literal::i64_unsuffixed(offset);
             body = quote! {(derived as *const _ as *const u8).offset(#offset) as *const #base_name};
         } else {
-            // TODO(b/216195042): use mangled names here, or otherwise guarantee
-            // non-collision.
             let cast_fn_name = make_rs_ident(&format!(
                 "__crubit_dynamic_upcast__{}__to__{}",
-                record.rs_name, base_record.rs_name
+                record.mangled_cc_name, base_record.mangled_cc_name
             ));
             let base_cc_name = cc_type_name_for_record(base_record.as_ref(), ir)?;
             let derived_cc_name = cc_type_name_for_record(record.as_ref(), ir)?;
@@ -5526,7 +5524,7 @@
             quote! {
                 unsafe impl oops::Inherits<crate::VirtualBase> for crate::Derived {
                     unsafe fn upcast_ptr(derived: *const Self) -> *const crate::VirtualBase {
-                        crate::detail::__crubit_dynamic_upcast__Derived__to__VirtualBase(derived)
+                        crate::detail::__crubit_dynamic_upcast__7Derived__to__11VirtualBase(derived)
                     }
                 }
             }
diff --git a/rs_bindings_from_cc/test/golden/inheritance_rs_api.rs b/rs_bindings_from_cc/test/golden/inheritance_rs_api.rs
index 3fe1815..8930056 100644
--- a/rs_bindings_from_cc/test/golden/inheritance_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/inheritance_rs_api.rs
@@ -471,7 +471,7 @@
 
 unsafe impl oops::Inherits<crate::Base1> for crate::VirtualBase1 {
     unsafe fn upcast_ptr(derived: *const Self) -> *const crate::Base1 {
-        crate::detail::__crubit_dynamic_upcast__VirtualBase1__to__Base1(derived)
+        crate::detail::__crubit_dynamic_upcast__12VirtualBase1__to__5Base1(derived)
     }
 }
 
@@ -574,7 +574,7 @@
 
 unsafe impl oops::Inherits<crate::Base1> for crate::VirtualBase2 {
     unsafe fn upcast_ptr(derived: *const Self) -> *const crate::Base1 {
-        crate::detail::__crubit_dynamic_upcast__VirtualBase2__to__Base1(derived)
+        crate::detail::__crubit_dynamic_upcast__12VirtualBase2__to__5Base1(derived)
     }
 }
 
@@ -683,17 +683,17 @@
 
 unsafe impl oops::Inherits<crate::VirtualBase1> for crate::VirtualDerived {
     unsafe fn upcast_ptr(derived: *const Self) -> *const crate::VirtualBase1 {
-        crate::detail::__crubit_dynamic_upcast__VirtualDerived__to__VirtualBase1(derived)
+        crate::detail::__crubit_dynamic_upcast__14VirtualDerived__to__12VirtualBase1(derived)
     }
 }
 unsafe impl oops::Inherits<crate::Base1> for crate::VirtualDerived {
     unsafe fn upcast_ptr(derived: *const Self) -> *const crate::Base1 {
-        crate::detail::__crubit_dynamic_upcast__VirtualDerived__to__Base1(derived)
+        crate::detail::__crubit_dynamic_upcast__14VirtualDerived__to__5Base1(derived)
     }
 }
 unsafe impl oops::Inherits<crate::VirtualBase2> for crate::VirtualDerived {
     unsafe fn upcast_ptr(derived: *const Self) -> *const crate::VirtualBase2 {
-        crate::detail::__crubit_dynamic_upcast__VirtualDerived__to__VirtualBase2(derived)
+        crate::detail::__crubit_dynamic_upcast__14VirtualDerived__to__12VirtualBase2(derived)
     }
 }
 
@@ -1091,7 +1091,7 @@
             __this: ::std::pin::Pin<&'a mut crate::VirtualBase1>,
             __param_0: ::ctor::RvalueReference<'b, crate::VirtualBase1>,
         ) -> ::std::pin::Pin<&'a mut crate::VirtualBase1>;
-        pub fn __crubit_dynamic_upcast__VirtualBase1__to__Base1(
+        pub fn __crubit_dynamic_upcast__12VirtualBase1__to__5Base1(
             from: *const crate::VirtualBase1,
         ) -> *const crate::Base1;
         pub(crate) fn __rust_thunk___ZN12VirtualBase2C1Ev<'a>(
@@ -1113,7 +1113,7 @@
             __this: ::std::pin::Pin<&'a mut crate::VirtualBase2>,
             __param_0: ::ctor::RvalueReference<'b, crate::VirtualBase2>,
         ) -> ::std::pin::Pin<&'a mut crate::VirtualBase2>;
-        pub fn __crubit_dynamic_upcast__VirtualBase2__to__Base1(
+        pub fn __crubit_dynamic_upcast__12VirtualBase2__to__5Base1(
             from: *const crate::VirtualBase2,
         ) -> *const crate::Base1;
         pub(crate) fn __rust_thunk___ZN14VirtualDerivedC1Ev<'a>(
@@ -1135,13 +1135,13 @@
             __this: ::std::pin::Pin<&'a mut crate::VirtualDerived>,
             __param_0: ::ctor::RvalueReference<'b, crate::VirtualDerived>,
         ) -> ::std::pin::Pin<&'a mut crate::VirtualDerived>;
-        pub fn __crubit_dynamic_upcast__VirtualDerived__to__VirtualBase1(
+        pub fn __crubit_dynamic_upcast__14VirtualDerived__to__12VirtualBase1(
             from: *const crate::VirtualDerived,
         ) -> *const crate::VirtualBase1;
-        pub fn __crubit_dynamic_upcast__VirtualDerived__to__Base1(
+        pub fn __crubit_dynamic_upcast__14VirtualDerived__to__5Base1(
             from: *const crate::VirtualDerived,
         ) -> *const crate::Base1;
-        pub fn __crubit_dynamic_upcast__VirtualDerived__to__VirtualBase2(
+        pub fn __crubit_dynamic_upcast__14VirtualDerived__to__12VirtualBase2(
             from: *const crate::VirtualDerived,
         ) -> *const crate::VirtualBase2;
         pub(crate) fn __rust_thunk___ZN15MyAbstractClassaSERKS_<'a, 'b>(
diff --git a/rs_bindings_from_cc/test/golden/inheritance_rs_api_impl.cc b/rs_bindings_from_cc/test/golden/inheritance_rs_api_impl.cc
index 099a94c..ddf5f6d 100644
--- a/rs_bindings_from_cc/test/golden/inheritance_rs_api_impl.cc
+++ b/rs_bindings_from_cc/test/golden/inheritance_rs_api_impl.cc
@@ -222,28 +222,30 @@
 
 #pragma clang diagnostic pop
 
-extern "C" const class Base1& __crubit_dynamic_upcast__VirtualBase1__to__Base1(
+extern "C" const class Base1&
+__crubit_dynamic_upcast__12VirtualBase1__to__5Base1(
     const class VirtualBase1& from) {
   return from;
 }
 
-extern "C" const class Base1& __crubit_dynamic_upcast__VirtualBase2__to__Base1(
+extern "C" const class Base1&
+__crubit_dynamic_upcast__12VirtualBase2__to__5Base1(
     const class VirtualBase2& from) {
   return from;
 }
 
 extern "C" const class VirtualBase1&
-__crubit_dynamic_upcast__VirtualDerived__to__VirtualBase1(
+__crubit_dynamic_upcast__14VirtualDerived__to__12VirtualBase1(
     const class VirtualDerived& from) {
   return from;
 }
 extern "C" const class Base1&
-__crubit_dynamic_upcast__VirtualDerived__to__Base1(
+__crubit_dynamic_upcast__14VirtualDerived__to__5Base1(
     const class VirtualDerived& from) {
   return from;
 }
 extern "C" const class VirtualBase2&
-__crubit_dynamic_upcast__VirtualDerived__to__VirtualBase2(
+__crubit_dynamic_upcast__14VirtualDerived__to__12VirtualBase2(
     const class VirtualDerived& from) {
   return from;
 }
diff --git a/rs_bindings_from_cc/test/golden/user_of_base_class_rs_api.rs b/rs_bindings_from_cc/test/golden/user_of_base_class_rs_api.rs
index 11382e8..5b5082d 100644
--- a/rs_bindings_from_cc/test/golden/user_of_base_class_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/user_of_base_class_rs_api.rs
@@ -120,7 +120,7 @@
 
 unsafe impl oops::Inherits<inheritance_cc::Base0> for crate::Derived2 {
     unsafe fn upcast_ptr(derived: *const Self) -> *const inheritance_cc::Base0 {
-        crate::detail::__crubit_dynamic_upcast__Derived2__to__Base0(derived)
+        crate::detail::__crubit_dynamic_upcast__8Derived2__to__5Base0(derived)
     }
 }
 unsafe impl oops::Inherits<inheritance_cc::Base1> for crate::Derived2 {
@@ -246,17 +246,17 @@
 
 unsafe impl oops::Inherits<inheritance_cc::VirtualBase1> for crate::VirtualDerived2 {
     unsafe fn upcast_ptr(derived: *const Self) -> *const inheritance_cc::VirtualBase1 {
-        crate::detail::__crubit_dynamic_upcast__VirtualDerived2__to__VirtualBase1(derived)
+        crate::detail::__crubit_dynamic_upcast__15VirtualDerived2__to__12VirtualBase1(derived)
     }
 }
 unsafe impl oops::Inherits<inheritance_cc::Base1> for crate::VirtualDerived2 {
     unsafe fn upcast_ptr(derived: *const Self) -> *const inheritance_cc::Base1 {
-        crate::detail::__crubit_dynamic_upcast__VirtualDerived2__to__Base1(derived)
+        crate::detail::__crubit_dynamic_upcast__15VirtualDerived2__to__5Base1(derived)
     }
 }
 unsafe impl oops::Inherits<inheritance_cc::VirtualBase2> for crate::VirtualDerived2 {
     unsafe fn upcast_ptr(derived: *const Self) -> *const inheritance_cc::VirtualBase2 {
-        crate::detail::__crubit_dynamic_upcast__VirtualDerived2__to__VirtualBase2(derived)
+        crate::detail::__crubit_dynamic_upcast__15VirtualDerived2__to__12VirtualBase2(derived)
     }
 }
 
@@ -285,7 +285,7 @@
             __this: ::std::pin::Pin<&'a mut crate::Derived2>,
             __param_0: ::ctor::RvalueReference<'b, crate::Derived2>,
         ) -> ::std::pin::Pin<&'a mut crate::Derived2>;
-        pub fn __crubit_dynamic_upcast__Derived2__to__Base0(
+        pub fn __crubit_dynamic_upcast__8Derived2__to__5Base0(
             from: *const crate::Derived2,
         ) -> *const inheritance_cc::Base0;
         pub(crate) fn __rust_thunk___ZN15VirtualDerived2C1Ev<'a>(
@@ -307,13 +307,13 @@
             __this: ::std::pin::Pin<&'a mut crate::VirtualDerived2>,
             __param_0: ::ctor::RvalueReference<'b, crate::VirtualDerived2>,
         ) -> ::std::pin::Pin<&'a mut crate::VirtualDerived2>;
-        pub fn __crubit_dynamic_upcast__VirtualDerived2__to__VirtualBase1(
+        pub fn __crubit_dynamic_upcast__15VirtualDerived2__to__12VirtualBase1(
             from: *const crate::VirtualDerived2,
         ) -> *const inheritance_cc::VirtualBase1;
-        pub fn __crubit_dynamic_upcast__VirtualDerived2__to__Base1(
+        pub fn __crubit_dynamic_upcast__15VirtualDerived2__to__5Base1(
             from: *const crate::VirtualDerived2,
         ) -> *const inheritance_cc::Base1;
-        pub fn __crubit_dynamic_upcast__VirtualDerived2__to__VirtualBase2(
+        pub fn __crubit_dynamic_upcast__15VirtualDerived2__to__12VirtualBase2(
             from: *const crate::VirtualDerived2,
         ) -> *const inheritance_cc::VirtualBase2;
     }
diff --git a/rs_bindings_from_cc/test/golden/user_of_base_class_rs_api_impl.cc b/rs_bindings_from_cc/test/golden/user_of_base_class_rs_api_impl.cc
index 30e9905..95975fc 100644
--- a/rs_bindings_from_cc/test/golden/user_of_base_class_rs_api_impl.cc
+++ b/rs_bindings_from_cc/test/golden/user_of_base_class_rs_api_impl.cc
@@ -60,23 +60,23 @@
 
 #pragma clang diagnostic pop
 
-extern "C" const class Base0& __crubit_dynamic_upcast__Derived2__to__Base0(
+extern "C" const class Base0& __crubit_dynamic_upcast__8Derived2__to__5Base0(
     const struct Derived2& from) {
   return from;
 }
 
 extern "C" const class VirtualBase1&
-__crubit_dynamic_upcast__VirtualDerived2__to__VirtualBase1(
+__crubit_dynamic_upcast__15VirtualDerived2__to__12VirtualBase1(
     const class VirtualDerived2& from) {
   return from;
 }
 extern "C" const class Base1&
-__crubit_dynamic_upcast__VirtualDerived2__to__Base1(
+__crubit_dynamic_upcast__15VirtualDerived2__to__5Base1(
     const class VirtualDerived2& from) {
   return from;
 }
 extern "C" const class VirtualBase2&
-__crubit_dynamic_upcast__VirtualDerived2__to__VirtualBase2(
+__crubit_dynamic_upcast__15VirtualDerived2__to__12VirtualBase2(
     const class VirtualDerived2& from) {
   return from;
 }
diff --git a/rs_bindings_from_cc/test/struct/inheritance/upcast.h b/rs_bindings_from_cc/test/struct/inheritance/upcast.h
index a72e3fa..0174b77 100644
--- a/rs_bindings_from_cc/test/struct/inheritance/upcast.h
+++ b/rs_bindings_from_cc/test/struct/inheritance/upcast.h
@@ -82,4 +82,21 @@
 
 }  // namespace virtual_inheritance
 
+namespace another_namespace {
+
+// This class has the same name as another `VirtualBase2` above (in another
+// namespace) to check that upcast thunks have unique names that take the
+// namespace into account.
+class VirtualBase2 : public virtual Base1 {
+ public:
+  VirtualBase2() = default;
+
+  size_t base1_address() const {
+    const Base1* base = this;
+    return reinterpret_cast<size_t>(base);
+  }
+};
+
+}  // namespace another_namespace
+
 #endif  // CRUBIT_RS_BINDINGS_FROM_CC_TEST_STRUCT_INHERITANCE_UPCAST_H_
diff --git a/rs_bindings_from_cc/test/struct/inheritance/upcast_test.rs b/rs_bindings_from_cc/test/struct/inheritance/upcast_test.rs
index be479b3..c3f9eae 100644
--- a/rs_bindings_from_cc/test/struct/inheritance/upcast_test.rs
+++ b/rs_bindings_from_cc/test/struct/inheritance/upcast_test.rs
@@ -5,7 +5,6 @@
 mod tests {
     use ctor::CtorNew as _;
     use oops::Upcast as _;
-    use upcast::virtual_inheritance::*;
     use upcast::*;
 
     #[test]
@@ -27,6 +26,7 @@
 
     #[test]
     fn test_virtual_upcast() {
+        use upcast::virtual_inheritance::*;
         ctor::emplace! {
             let derived = VirtualDerived::ctor_new(());
         }
@@ -45,4 +45,16 @@
         let base1: &Base1 = base3.upcast();
         assert_eq!(base1 as *const _ as usize, base1_address);
     }
+
+    #[test]
+    fn test_upcast_thunk_name_uniqueness() {
+        ctor::emplace! {
+            let derived = another_namespace::VirtualBase2::ctor_new(());
+        }
+        let derived = &*derived;
+
+        let base1: &Base1 = derived.upcast();
+        let base1_address = base1 as *const _ as usize;
+        assert_eq!(base1_address, derived.base1_address());
+    }
 }