Update GetTranslatedName and GetTranslatedIdentifier to return both rs_name and cc_name.

Supporting overwriting the rust name of a c++ decl requires keeping track of a cc_name and rs_name to support renaming C++ decls; this CL adds support for using the rs_name to generate the rust bindings.

PiperOrigin-RevId: 733080188
Change-Id: I9887584fe34020fb6c78e1fd264ac3e6fa562969
diff --git a/cargo/rs_bindings_from_cc/importer_sys/Cargo.toml b/cargo/rs_bindings_from_cc/importer_sys/Cargo.toml
index b6c0be0..9f7ec67 100644
--- a/cargo/rs_bindings_from_cc/importer_sys/Cargo.toml
+++ b/cargo/rs_bindings_from_cc/importer_sys/Cargo.toml
@@ -14,11 +14,12 @@
 path = "lib.rs"
 
 [dependencies]
+annotations_consumer_sys = { path = "../../../cargo/rs_bindings_from_cc/annotations_consumer_sys" }
 ast_util_sys = { path = "../../../cargo/rs_bindings_from_cc/ast_util_sys" }
 cc_ir_sys = { path = "../../../cargo/rs_bindings_from_cc/cc_ir_sys" }
+recording_diagnostic_consumer_sys = { path = "../../../cargo/rs_bindings_from_cc/recording_diagnostic_consumer_sys" }
 type_map_sys = { path = "../../../cargo/rs_bindings_from_cc/type_map_sys" }
 type_lifetimes_sys = { path = "../../../cargo/lifetime_annotations/type_lifetimes_sys" }
-recording_diagnostic_consumer_sys = { path = "../../../cargo/rs_bindings_from_cc/recording_diagnostic_consumer_sys" }
 class_template_sys = { path = "../../../cargo/rs_bindings_from_cc/importers/class_template_sys" }
 cxx_record_sys = { path = "../../../cargo/rs_bindings_from_cc/importers/cxx_record_sys" }
 enum_sys = { path = "../../../cargo/rs_bindings_from_cc/importers/enum_sys" }
diff --git a/cargo/rs_bindings_from_cc/importer_sys/lib.rs b/cargo/rs_bindings_from_cc/importer_sys/lib.rs
index d8d16cf..bd32270 100644
--- a/cargo/rs_bindings_from_cc/importer_sys/lib.rs
+++ b/cargo/rs_bindings_from_cc/importer_sys/lib.rs
@@ -4,6 +4,7 @@
 
 // Automatically @generated lib.rs for the cc_library importer.
 
+extern crate annotations_consumer_sys;
 extern crate ast_util_sys;
 extern crate cc_ir_sys;
 extern crate class_template_sys;
diff --git a/rs_bindings_from_cc/BUILD b/rs_bindings_from_cc/BUILD
index 4dddf63..45cbbe5 100644
--- a/rs_bindings_from_cc/BUILD
+++ b/rs_bindings_from_cc/BUILD
@@ -278,14 +278,15 @@
     srcs = ["importer.cc"],
     hdrs = ["importer.h"],
     deps = [
+        ":annotations_consumer",
         ":ast_util",
         ":bazel_types",
         ":cc_ir",
         ":decl_importer",
+        ":recording_diagnostic_consumer",
         ":type_map",
         "//common:status_macros",
         "//lifetime_annotations:type_lifetimes",
-        "//rs_bindings_from_cc:recording_diagnostic_consumer",
         "//rs_bindings_from_cc/importers:class_template",
         "//rs_bindings_from_cc/importers:cxx_record",
         "//rs_bindings_from_cc/importers:enum",
diff --git a/rs_bindings_from_cc/collect_namespaces.cc b/rs_bindings_from_cc/collect_namespaces.cc
index e3b9c43..cfaae63 100644
--- a/rs_bindings_from_cc/collect_namespaces.cc
+++ b/rs_bindings_from_cc/collect_namespaces.cc
@@ -62,7 +62,7 @@
 
   // Creates a node from a Namespace and inserts it into the trie.
   void InsertNode(int parent_idx, const Namespace* ns) {
-    auto name = ns->cc_name.Ident();
+    auto name = ns->rs_name.Ident();
     auto parent = &trie_nodes_[parent_idx];
     int child_idx;
     if (parent->child_name_to_idx.find(name) ==
diff --git a/rs_bindings_from_cc/decl_importer.h b/rs_bindings_from_cc/decl_importer.h
index 91c586a..ee9f00c 100644
--- a/rs_bindings_from_cc/decl_importer.h
+++ b/rs_bindings_from_cc/decl_importer.h
@@ -153,12 +153,12 @@
   // a SpecialName.
   //
   // If the name can't be translated (or is empty), this returns an error.
-  virtual absl::StatusOr<UnqualifiedIdentifier> GetTranslatedName(
+  virtual absl::StatusOr<TranslatedUnqualifiedIdentifier> GetTranslatedName(
       const clang::NamedDecl* named_decl) const = 0;
 
   // GetTranslatedName, but only for identifier names. This is the common case.
   // If the name can't be translated (or is empty), this returns an error.
-  virtual absl::StatusOr<Identifier> GetTranslatedIdentifier(
+  virtual absl::StatusOr<TranslatedIdentifier> GetTranslatedIdentifier(
       const clang::NamedDecl* named_decl) const = 0;
 
   // Gets the doc comment of the declaration.
diff --git a/rs_bindings_from_cc/generate_bindings/generate_enum.rs b/rs_bindings_from_cc/generate_bindings/generate_enum.rs
index 7cf4db0..354e8ef 100644
--- a/rs_bindings_from_cc/generate_bindings/generate_enum.rs
+++ b/rs_bindings_from_cc/generate_bindings/generate_enum.rs
@@ -16,7 +16,7 @@
 use std::rc::Rc;
 
 pub fn generate_enum(db: &dyn BindingsGenerator, enum_: Rc<Enum>) -> Result<ApiSnippets> {
-    let ident = expect_format_cc_ident(&enum_.rs_name.identifier);
+    let ident = expect_format_cc_ident(&enum_.cc_name.identifier);
     let namespace_qualifier = db.ir().namespace_qualifier(&enum_).format_for_cc()?;
     let fully_qualified_cc_name = quote! { #namespace_qualifier #ident }.to_string();
     let name = make_rs_ident(&enum_.rs_name.identifier);
diff --git a/rs_bindings_from_cc/importer.cc b/rs_bindings_from_cc/importer.cc
index a999720..22fe3e3 100644
--- a/rs_bindings_from_cc/importer.cc
+++ b/rs_bindings_from_cc/importer.cc
@@ -32,6 +32,7 @@
 #include "absl/strings/substitute.h"
 #include "common/status_macros.h"
 #include "lifetime_annotations/type_lifetimes.h"
+#include "rs_bindings_from_cc/annotations_consumer.h"
 #include "rs_bindings_from_cc/ast_util.h"
 #include "rs_bindings_from_cc/bazel_types.h"
 #include "rs_bindings_from_cc/ir.h"
@@ -1265,13 +1266,12 @@
   // segfaults inside ItaniumMangleContextImpl::mangleCXXName. We're not working
   // with a fully-instantiated template declaration, so there is no mangled
   // name to refer to.
-  auto rs_name = GetTranslatedName(template_decl);
-  if (!rs_name.ok()) {
+  auto names = GetTranslatedName(template_decl);
+  if (!names.ok()) {
     return std::nullopt;
   }
-
   return UnsupportedItem::Path{
-      .ident = std::move(*rs_name),
+      .ident = names->cc_identifier,
       .enclosing_item_id = *enclosing_item_id,
   };
 }
@@ -1305,7 +1305,7 @@
   }
 }
 
-absl::StatusOr<UnqualifiedIdentifier> Importer::GetTranslatedName(
+absl::StatusOr<TranslatedUnqualifiedIdentifier> Importer::GetTranslatedName(
     const clang::NamedDecl* named_decl) const {
   switch (named_decl->getDeclName().getNameKind()) {
     case clang::DeclarationName::Identifier: {
@@ -1314,21 +1314,30 @@
         return absl::InvalidArgumentError("Missing identifier");
       }
 
+      std::optional<Identifier> crubit_rust_name = CrubitRustName(named_decl);
+
       // `r#foo` syntax in Rust can't be used to escape `crate`, `self`,
       // `super`, not `Self` identifiers - see
       // https://doc.rust-lang.org/reference/identifiers.html#identifiers
-      if (name == "crate" || name == "self" || name == "super" ||
-          name == "Self") {
+      if ((name == "crate" || name == "self" || name == "super" ||
+           name == "Self") &&
+          !crubit_rust_name.has_value()) {
         return absl::InvalidArgumentError(
             absl::StrCat("Unescapable identifier: ", name));
       }
 
-      return {Identifier(std::move(name))};
+      TranslatedUnqualifiedIdentifier identifier = {
+          .cc_identifier = Identifier(name),
+          .crubit_rust_name = crubit_rust_name,
+      };
+      return identifier;
     }
     case clang::DeclarationName::CXXConstructorName:
-      return {SpecialName::kConstructor};
+      return TranslatedUnqualifiedIdentifier{.cc_identifier =
+                                                 SpecialName::kConstructor};
     case clang::DeclarationName::CXXDestructorName:
-      return {SpecialName::kDestructor};
+      return TranslatedUnqualifiedIdentifier{.cc_identifier =
+                                                 SpecialName::kDestructor};
     case clang::DeclarationName::CXXOperatorName:
       switch (named_decl->getDeclName().getCXXOverloadedOperator()) {
         case clang::OO_None:
@@ -1338,7 +1347,9 @@
           // clang-format off
         #define OVERLOADED_OPERATOR(name, spelling, ...)  \
         case clang::OO_##name: {                          \
-          return {Operator(spelling)};                    \
+          return TranslatedUnqualifiedIdentifier{ \
+            .cc_identifier = Operator(spelling) \
+          }; \
         }
         #include "clang/Basic/OperatorKinds.def"
         #undef OVERLOADED_OPERATOR
@@ -1355,6 +1366,35 @@
   }
 }
 
+absl::StatusOr<TranslatedIdentifier> Importer::GetTranslatedIdentifier(
+    const clang::NamedDecl* named_decl) const {
+  CRUBIT_ASSIGN_OR_RETURN(TranslatedUnqualifiedIdentifier unqualified,
+                          GetTranslatedName(named_decl));
+  Identifier* cc_identifier =
+      std::get_if<Identifier>(&unqualified.cc_identifier);
+  CHECK(cc_identifier) << "Incorrectly called with a special name";
+
+  TranslatedIdentifier translated_identifiers = {
+      .cc_identifier = *cc_identifier,
+  };
+
+  if (!unqualified.crubit_rust_name.has_value()) {
+    translated_identifiers.crubit_rust_name = *cc_identifier;
+    return translated_identifiers;
+  }
+
+  if (!std::holds_alternative<Identifier>(*unqualified.crubit_rust_name)) {
+    CHECK(unqualified.crubit_rust_name)
+        << "Crubit rust name cannot be a special name";
+  }
+
+  // TODO(yulanlin): potentially buggy
+  translated_identifiers.crubit_rust_name =
+      std::move(std::get<Identifier>(*unqualified.crubit_rust_name));
+
+  return translated_identifiers;
+}
+
 void Importer::MarkAsSuccessfullyImported(const clang::NamedDecl* decl) {
   known_type_decls_.insert(
       clang::cast<clang::NamedDecl>(CanonicalizeDecl(decl)));
diff --git a/rs_bindings_from_cc/importer.h b/rs_bindings_from_cc/importer.h
index 84f9f93..a644ce8 100644
--- a/rs_bindings_from_cc/importer.h
+++ b/rs_bindings_from_cc/importer.h
@@ -94,16 +94,10 @@
       clang::RedeclarableTemplateDecl* template_decl) override;
   BazelLabel GetOwningTarget(const clang::Decl* decl) const override;
   bool IsFromCurrentTarget(const clang::Decl* decl) const override;
-  absl::StatusOr<UnqualifiedIdentifier> GetTranslatedName(
+  absl::StatusOr<TranslatedUnqualifiedIdentifier> GetTranslatedName(
       const clang::NamedDecl* named_decl) const override;
-  absl::StatusOr<Identifier> GetTranslatedIdentifier(
-      const clang::NamedDecl* named_decl) const override {
-    CRUBIT_ASSIGN_OR_RETURN(UnqualifiedIdentifier unqualified,
-                            GetTranslatedName(named_decl));
-    Identifier* identifier = std::get_if<Identifier>(&unqualified);
-    CHECK(identifier) << "Incorrectly called with a special name";
-    return *identifier;
-  }
+  absl::StatusOr<TranslatedIdentifier> GetTranslatedIdentifier(
+      const clang::NamedDecl* named_decl) const override;
   std::optional<std::string> GetComment(const clang::Decl* decl) const override;
   std::string ConvertSourceLocation(clang::SourceLocation loc) const override;
   absl::StatusOr<MappedType> ConvertQualType(
diff --git a/rs_bindings_from_cc/importers/cxx_record.cc b/rs_bindings_from_cc/importers/cxx_record.cc
index c112395..864de0f 100644
--- a/rs_bindings_from_cc/importers/cxx_record.cc
+++ b/rs_bindings_from_cc/importers/cxx_record.cc
@@ -298,12 +298,13 @@
     return std::nullopt;
   }
 
-  absl::StatusOr<Identifier> name = ictx_.GetTranslatedIdentifier(field_decl);
+  absl::StatusOr<TranslatedIdentifier> name =
+      ictx_.GetTranslatedIdentifier(field_decl);
   if (!name.ok()) {
     unsigned field_pos = field_decl->getFieldIndex();
     return {Identifier(absl::StrCat("__field_", field_pos))};
   }
-  return *name;
+  return (*name).rs_identifier();
 }
 
 bool IsKnownAttr(const clang::Attr& attr) {
@@ -433,10 +434,11 @@
     }
     CHECK(!named_decl->getName().empty());
 
-    absl::StatusOr<Identifier> record_name =
+    absl::StatusOr<TranslatedIdentifier> record_name =
         ictx_.GetTranslatedIdentifier(named_decl);
     if (record_name.ok()) {
-      rs_name = cc_name = record_name->Ident();
+      rs_name = (*record_name).rs_identifier().Ident();
+      cc_name = (*record_name).cc_identifier.Ident();
       doc_comment = ictx_.GetComment(record_decl);
       source_loc = record_decl->getBeginLoc();
     } else {
diff --git a/rs_bindings_from_cc/importers/enum.cc b/rs_bindings_from_cc/importers/enum.cc
index 214192d..e08f16f 100644
--- a/rs_bindings_from_cc/importers/enum.cc
+++ b/rs_bindings_from_cc/importers/enum.cc
@@ -29,7 +29,7 @@
         enum_decl, UnsupportedItem::Kind::kUnnameable, std::nullopt,
         FormattedError::Static("Unnamed enums are not supported yet"));
   }
-  absl::StatusOr<Identifier> enum_name =
+  absl::StatusOr<TranslatedIdentifier> enum_name =
       ictx_.GetTranslatedIdentifier(enum_decl);
   if (!enum_name.ok()) {
     return ictx_.ImportUnsupportedItem(
@@ -54,7 +54,7 @@
                       enum_decl](FormattedError error) {
     return ictx_.ImportUnsupportedItem(
         enum_decl, UnsupportedItem::Kind::kType,
-        UnsupportedItem::Path{.ident = *enum_name,
+        UnsupportedItem::Path{.ident = (*enum_name).rs_identifier(),
                               .enclosing_item_id = *enclosing_item_id},
         error);
   };
@@ -80,7 +80,7 @@
   std::vector<Enumerator> enumerators;
   enumerators.reserve(absl::c_distance(enum_decl->enumerators()));
   for (clang::EnumConstantDecl* enumerator : enum_decl->enumerators()) {
-    absl::StatusOr<Identifier> enumerator_name =
+    absl::StatusOr<TranslatedIdentifier> enumerator_name =
         ictx_.GetTranslatedIdentifier(enumerator);
     if (!enumerator_name.ok()) {
       // It's not clear that this case is possible
@@ -90,7 +90,7 @@
     }
 
     enumerators.push_back(Enumerator{
-        .identifier = *enumerator_name,
+        .identifier = (*enumerator_name).rs_identifier(),
         .value = IntegerConstant(enumerator->getInitVal()),
         .unknown_attr = CollectUnknownAttrs(*enumerator),
     });
@@ -98,8 +98,8 @@
 
   ictx_.MarkAsSuccessfullyImported(enum_decl);
   return Enum{
-      .cc_name = *enum_name,
-      .rs_name = *enum_name,
+      .cc_name = (*enum_name).cc_identifier,
+      .rs_name = (*enum_name).rs_identifier(),
       .id = ictx_.GenerateItemId(enum_decl),
       .owning_target = ictx_.GetOwningTarget(enum_decl),
       .source_loc = ictx_.ConvertSourceLocation(enum_decl->getBeginLoc()),
diff --git a/rs_bindings_from_cc/importers/function.cc b/rs_bindings_from_cc/importers/function.cc
index 63db8e1..15c8ee0 100644
--- a/rs_bindings_from_cc/importers/function.cc
+++ b/rs_bindings_from_cc/importers/function.cc
@@ -114,7 +114,8 @@
 Identifier FunctionDeclImporter::GetTranslatedParamName(
     const clang::ParmVarDecl* param_decl) {
   int param_pos = param_decl->getFunctionScopeIndex();
-  absl::StatusOr<Identifier> name = ictx_.GetTranslatedIdentifier(param_decl);
+  absl::StatusOr<TranslatedIdentifier> name =
+      ictx_.GetTranslatedIdentifier(param_decl);
   if (!name.ok()) {
     return {Identifier(absl::StrCat("__param_", param_pos))};
   }
@@ -122,9 +123,10 @@
           param_decl->getType()->getAs<clang::SubstTemplateTypeParmType>();
       sttpt && sttpt->getReplacedParameter()->isParameterPack()) {
     // Avoid giving the same name to all parameters expanded from a pack.
-    return {Identifier(absl::StrCat("__", name->Ident(), "_", param_pos))};
+    return {Identifier(
+        absl::StrCat("__", name->rs_identifier().Ident(), "_", param_pos))};
   }
-  return *name;
+  return Identifier(std::string((*name).rs_identifier().Ident()));
 }
 
 std::optional<IR::Item> FunctionDeclImporter::Import(
@@ -155,7 +157,7 @@
     }
   }
 
-  absl::StatusOr<UnqualifiedIdentifier> translated_name =
+  absl::StatusOr<TranslatedUnqualifiedIdentifier> translated_name =
       ictx_.GetTranslatedName(function_decl);
   if (!translated_name.ok()) {
     return ictx_.ImportUnsupportedItem(
@@ -180,7 +182,7 @@
                       function_decl](FormattedError error) {
     return ictx_.ImportUnsupportedItem(
         function_decl, UnsupportedItem::Kind::kValue,
-        UnsupportedItem::Path{.ident = *translated_name,
+        UnsupportedItem::Path{.ident = (*translated_name).cc_identifier,
                               .enclosing_item_id = *enclosing_item_id},
         error);
   };
@@ -433,7 +435,7 @@
   if (!errors.error_set.empty()) {
     return ictx_.ImportUnsupportedItem(
         function_decl, UnsupportedItem::Kind::kValue,
-        UnsupportedItem::Path{.ident = *translated_name,
+        UnsupportedItem::Path{.ident = (*translated_name).cc_identifier,
                               .enclosing_item_id = *enclosing_item_id},
         std::vector(errors.error_set.begin(), errors.error_set.end()));
   }
@@ -485,8 +487,8 @@
   CHECK_OK(return_type);
 
   return Func{
-      .cc_name = *translated_name,
-      .rs_name = *translated_name,
+      .cc_name = (*translated_name).cc_identifier,
+      .rs_name = (*translated_name).rs_identifier(),
       .owning_target = ictx_.GetOwningTarget(function_decl),
       .doc_comment = std::move(doc_comment),
       .mangled_name = ictx_.GetMangledName(function_decl),
diff --git a/rs_bindings_from_cc/importers/namespace.cc b/rs_bindings_from_cc/importers/namespace.cc
index 1707833..2d411db 100644
--- a/rs_bindings_from_cc/importers/namespace.cc
+++ b/rs_bindings_from_cc/importers/namespace.cc
@@ -23,7 +23,7 @@
         FormattedError::Static("Anonymous namespaces are not supported yet"));
   }
 
-  absl::StatusOr<Identifier> identifier =
+  absl::StatusOr<TranslatedIdentifier> identifier =
       ictx_.GetTranslatedIdentifier(namespace_decl);
   if (!identifier.ok()) {
     return ictx_.ImportUnsupportedItem(
@@ -46,8 +46,16 @@
         namespace_decl, UnsupportedItem::Kind::kType, std::nullopt,
         FormattedError::FromStatus(std::move(enclosing_item_id.status())));
   }
-  return Namespace{.cc_name = *identifier,
-                   .rs_name = *identifier,
+  // Renames are not currently supported for namespaces.
+  // TODO - b/399487279: Support namespace renames using CRUBIT_RUST_NAME.
+  // if (identifier->crubit_rust_name.has_value()) {
+  //   return ictx_.ImportUnsupportedItem(
+  //       namespace_decl, UnsupportedItem::Kind::kType, std::nullopt,
+  //       FormattedError::Static("Namespace renames are not supported yet"));
+  // }
+
+  return Namespace{.cc_name = identifier->cc_identifier,
+                   .rs_name = identifier->cc_identifier,
                    .id = ictx_.GenerateItemId(namespace_decl),
                    .canonical_namespace_id =
                        ictx_.GenerateItemId(namespace_decl->getCanonicalDecl()),
diff --git a/rs_bindings_from_cc/importers/type_alias.cc b/rs_bindings_from_cc/importers/type_alias.cc
index 1d3a061..b590c5f 100644
--- a/rs_bindings_from_cc/importers/type_alias.cc
+++ b/rs_bindings_from_cc/importers/type_alias.cc
@@ -56,7 +56,8 @@
     return std::nullopt;
   }
 
-  absl::StatusOr<Identifier> identifier = ictx_.GetTranslatedIdentifier(decl);
+  absl::StatusOr<TranslatedIdentifier> identifier =
+      ictx_.GetTranslatedIdentifier(decl);
   if (!identifier.ok()) {
     return ictx_.ImportUnsupportedItem(
         decl, UnsupportedItem::Kind::kType, std::nullopt,
@@ -80,7 +81,7 @@
   if (!underlying_type.ok()) {
     return ictx_.ImportUnsupportedItem(
         decl, UnsupportedItem::Kind::kType,
-        UnsupportedItem::Path{.ident = *identifier,
+        UnsupportedItem::Path{.ident = (*identifier).cc_identifier,
                               .enclosing_item_id = *enclosing_item_id},
         FormattedError::FromStatus(std::move(underlying_type.status())));
   }
@@ -91,10 +92,10 @@
   // string_view with a lifetime.
   const bool is_string_view =
       decl->getQualifiedNameAsString() == "std::string_view";
-  Identifier rs_name =
-      is_string_view ? Identifier("raw_string_view") : *identifier;
+  Identifier rs_name = is_string_view ? Identifier("raw_string_view")
+                                      : (*identifier).rs_identifier();
   return TypeAlias{
-      .cc_name = *std::move(identifier),
+      .cc_name = (*identifier).cc_identifier,
       .rs_name = rs_name,
       .id = ictx_.GenerateItemId(decl),
       .owning_target = ictx_.GetOwningTarget(decl),
diff --git a/rs_bindings_from_cc/ir.cc b/rs_bindings_from_cc/ir.cc
index 069c094..74a3c5e 100644
--- a/rs_bindings_from_cc/ir.cc
+++ b/rs_bindings_from_cc/ir.cc
@@ -291,6 +291,20 @@
   return o << SpecialNameToString(special_name);
 }
 
+UnqualifiedIdentifier& TranslatedUnqualifiedIdentifier::rs_identifier() {
+  if (crubit_rust_name.has_value()) {
+    return *crubit_rust_name;
+  }
+  return cc_identifier;
+}
+
+Identifier& TranslatedIdentifier::rs_identifier() {
+  if (crubit_rust_name.has_value()) {
+    return *crubit_rust_name;
+  }
+  return cc_identifier;
+}
+
 llvm::json::Value MemberFuncMetadata::InstanceMethodMetadata::ToJson() const {
   const char* reference_str = nullptr;
   switch (reference) {
diff --git a/rs_bindings_from_cc/ir.h b/rs_bindings_from_cc/ir.h
index 8f5d030..742a89a 100644
--- a/rs_bindings_from_cc/ir.h
+++ b/rs_bindings_from_cc/ir.h
@@ -408,6 +408,19 @@
 using UnqualifiedIdentifier = std::variant<Identifier, Operator, SpecialName>;
 llvm::json::Value toJSON(const UnqualifiedIdentifier& unqualified_identifier);
 
+struct TranslatedUnqualifiedIdentifier {
+  UnqualifiedIdentifier cc_identifier;
+  std::optional<UnqualifiedIdentifier> crubit_rust_name;
+
+  UnqualifiedIdentifier& rs_identifier();
+};
+
+struct TranslatedIdentifier {
+  Identifier cc_identifier;
+  std::optional<Identifier> crubit_rust_name;
+  Identifier& rs_identifier();
+};
+
 struct MemberFuncMetadata {
   enum ReferenceQualification : char {
     kLValue,       // void Foo() &;
diff --git a/rs_bindings_from_cc/test/golden/enums.h b/rs_bindings_from_cc/test/golden/enums.h
index c7383a2..9d68fcc 100644
--- a/rs_bindings_from_cc/test/golden/enums.h
+++ b/rs_bindings_from_cc/test/golden/enums.h
@@ -11,6 +11,8 @@
   kGreen,
 };
 
+enum [[clang::annotate("crubit_rust_name", "RenamedEnum")]] EnumToRename {};
+
 enum Empty {};
 enum EmptyBool : bool {};
 enum EmptyInt : unsigned int {};
diff --git a/rs_bindings_from_cc/test/golden/enums_rs_api.rs b/rs_bindings_from_cc/test/golden/enums_rs_api.rs
index 05293d7..a86bcbb 100644
--- a/rs_bindings_from_cc/test/golden/enums_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/enums_rs_api.rs
@@ -37,6 +37,22 @@
 
 #[repr(transparent)]
 #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, PartialOrd, Ord)]
+#[__crubit::annotate(cpp_type = "EnumToRename")]
+pub struct RenamedEnum(::core::ffi::c_uint);
+impl RenamedEnum {}
+impl From<::core::ffi::c_uint> for RenamedEnum {
+    fn from(value: ::core::ffi::c_uint) -> RenamedEnum {
+        RenamedEnum(value)
+    }
+}
+impl From<RenamedEnum> for ::core::ffi::c_uint {
+    fn from(value: RenamedEnum) -> ::core::ffi::c_uint {
+        value.0
+    }
+}
+
+#[repr(transparent)]
+#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, PartialOrd, Ord)]
 #[__crubit::annotate(cpp_type = "Empty")]
 pub struct Empty(::core::ffi::c_uint);
 impl Empty {}
diff --git a/rs_bindings_from_cc/test/golden/overloads.h b/rs_bindings_from_cc/test/golden/overloads.h
index 9d97f69..a1cd977 100644
--- a/rs_bindings_from_cc/test/golden/overloads.h
+++ b/rs_bindings_from_cc/test/golden/overloads.h
@@ -8,6 +8,12 @@
 void Overload();
 void Overload(int);
 
+// Both Overload2() overloads should be generated, because one should be
+// renamed.
+void Overload2();
+[[clang::annotate("crubit_rust_name", "RenamedOverload2")]]
+void Overlaod2(int);
+
 // An overload where at least one of the functions is uncallable.
 // This can happen in real code, one example is the `void*` overload of
 // absl::flags_internal::FlagImpl::Read().
diff --git a/rs_bindings_from_cc/test/golden/overloads_rs_api.rs b/rs_bindings_from_cc/test/golden/overloads_rs_api.rs
index 5bb1674..ba98393 100644
--- a/rs_bindings_from_cc/test/golden/overloads_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/overloads_rs_api.rs
@@ -20,6 +20,18 @@
 // Error while generating bindings for item 'Overload':
 // Cannot generate bindings for overloaded function
 
+/// Both Overload2() overloads should be generated, because one should be
+/// renamed.
+#[inline(always)]
+pub fn Overload2() {
+    unsafe { crate::detail::__rust_thunk___Z9Overload2v() }
+}
+
+#[inline(always)]
+pub fn RenamedOverload2(__param_0: ::core::ffi::c_int) {
+    unsafe { crate::detail::__rust_thunk___Z9Overlaod2i(__param_0) }
+}
+
 // Error while generating bindings for item 'UncallableOverload':
 // Cannot generate bindings for overloaded function
 
@@ -44,6 +56,10 @@
     #[allow(unused_imports)]
     use super::*;
     unsafe extern "C" {
+        #[link_name = "_Z9Overload2v"]
+        pub(crate) unsafe fn __rust_thunk___Z9Overload2v();
+        #[link_name = "_Z9Overlaod2i"]
+        pub(crate) unsafe fn __rust_thunk___Z9Overlaod2i(__param_0: ::core::ffi::c_int);
         pub(crate) unsafe fn __rust_thunk___Z20AlsoTemplateOverloadv();
     }
 }
diff --git a/rs_bindings_from_cc/test/golden/unions.h b/rs_bindings_from_cc/test/golden/unions.h
index 2c2f81b..37ac3be 100644
--- a/rs_bindings_from_cc/test/golden/unions.h
+++ b/rs_bindings_from_cc/test/golden/unions.h
@@ -16,6 +16,8 @@
   int field;
 };
 
+union [[clang::annotate("crubit_rust_name", "RenamedUnion")]] UnionToRename {};
+
 struct TriviallyCopyableButNontriviallyDestructible {
   TriviallyCopyableButNontriviallyDestructible(
       const TriviallyCopyableButNontriviallyDestructible&) = default;
diff --git a/rs_bindings_from_cc/test/golden/unions_rs_api.rs b/rs_bindings_from_cc/test/golden/unions_rs_api.rs
index a215f7a..474f7e1 100644
--- a/rs_bindings_from_cc/test/golden/unions_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/unions_rs_api.rs
@@ -133,6 +133,61 @@
     }
 }
 
+#[derive(Clone, Copy)]
+#[repr(C)]
+#[__crubit::annotate(cpp_type = "UnionToRename")]
+pub union RenamedUnion {
+    __non_field_data: [::core::mem::MaybeUninit<u8>; 1],
+}
+impl !Send for RenamedUnion {}
+impl !Sync for RenamedUnion {}
+forward_declare::unsafe_define!(forward_declare::symbol!("UnionToRename"), crate::RenamedUnion);
+
+impl Default for RenamedUnion {
+    #[inline(always)]
+    fn default() -> Self {
+        let mut tmp = ::core::mem::MaybeUninit::<Self>::zeroed();
+        unsafe {
+            crate::detail::__rust_thunk___ZN13UnionToRenameC1Ev(
+                &raw mut tmp as *mut ::core::ffi::c_void,
+            );
+            tmp.assume_init()
+        }
+    }
+}
+
+impl<'b> From<::ctor::RvalueReference<'b, Self>> for RenamedUnion {
+    #[inline(always)]
+    fn from(__param_0: ::ctor::RvalueReference<'b, Self>) -> Self {
+        let mut tmp = ::core::mem::MaybeUninit::<Self>::zeroed();
+        unsafe {
+            crate::detail::__rust_thunk___ZN13UnionToRenameC1EOS_(
+                &raw mut tmp as *mut ::core::ffi::c_void,
+                __param_0,
+            );
+            tmp.assume_init()
+        }
+    }
+}
+
+impl<'b> ::ctor::UnpinAssign<&'b Self> for RenamedUnion {
+    #[inline(always)]
+    fn unpin_assign<'a>(&'a mut self, __param_0: &'b Self) {
+        unsafe {
+            crate::detail::__rust_thunk___ZN13UnionToRenameaSERKS_(self, __param_0);
+        }
+    }
+}
+
+impl<'b> ::ctor::UnpinAssign<::ctor::RvalueReference<'b, Self>> for RenamedUnion {
+    #[inline(always)]
+    fn unpin_assign<'a>(&'a mut self, __param_0: ::ctor::RvalueReference<'b, Self>) {
+        unsafe {
+            crate::detail::__rust_thunk___ZN13UnionToRenameaSEOS_(self, __param_0);
+        }
+    }
+}
+
 #[::ctor::recursively_pinned(PinnedDrop)]
 #[repr(C)]
 #[__crubit::annotate(cpp_type = "TriviallyCopyableButNontriviallyDestructible")]
@@ -634,6 +689,19 @@
             __this: *mut ::core::ffi::c_void,
             __param_0: ::ctor::RvalueReference<'b, crate::Nontrivial>,
         );
+        pub(crate) unsafe fn __rust_thunk___ZN13UnionToRenameC1Ev(__this: *mut ::core::ffi::c_void);
+        pub(crate) unsafe fn __rust_thunk___ZN13UnionToRenameC1EOS_<'b>(
+            __this: *mut ::core::ffi::c_void,
+            __param_0: ::ctor::RvalueReference<'b, crate::RenamedUnion>,
+        );
+        pub(crate) unsafe fn __rust_thunk___ZN13UnionToRenameaSERKS_<'a, 'b>(
+            __this: &'a mut crate::RenamedUnion,
+            __param_0: &'b crate::RenamedUnion,
+        ) -> &'a mut crate::RenamedUnion;
+        pub(crate) unsafe fn __rust_thunk___ZN13UnionToRenameaSEOS_<'a, 'b>(
+            __this: &'a mut crate::RenamedUnion,
+            __param_0: ::ctor::RvalueReference<'b, crate::RenamedUnion>,
+        ) -> &'a mut crate::RenamedUnion;
         pub(crate) unsafe fn __rust_thunk___ZN44TriviallyCopyableButNontriviallyDestructibleaSERKS_<
             'a,
             'b,
@@ -762,6 +830,12 @@
     static_assertions::assert_not_impl_any!(crate::Nontrivial: Drop);
     assert!(::core::mem::offset_of!(crate::Nontrivial, field) == 0);
 
+    assert!(::core::mem::size_of::<crate::RenamedUnion>() == 1);
+    assert!(::core::mem::align_of::<crate::RenamedUnion>() == 1);
+    static_assertions::assert_impl_all!(crate::RenamedUnion: Clone);
+    static_assertions::assert_impl_all!(crate::RenamedUnion: Copy);
+    static_assertions::assert_not_impl_any!(crate::RenamedUnion: Drop);
+
     assert!(::core::mem::size_of::<crate::TriviallyCopyableButNontriviallyDestructible>() == 1);
     assert!(::core::mem::align_of::<crate::TriviallyCopyableButNontriviallyDestructible>() == 1);
     static_assertions::assert_not_impl_any!(crate::TriviallyCopyableButNontriviallyDestructible: Copy);
diff --git a/rs_bindings_from_cc/test/golden/unions_rs_api_impl.cc b/rs_bindings_from_cc/test/golden/unions_rs_api_impl.cc
index 2fa7d80..f8da619 100644
--- a/rs_bindings_from_cc/test/golden/unions_rs_api_impl.cc
+++ b/rs_bindings_from_cc/test/golden/unions_rs_api_impl.cc
@@ -44,6 +44,29 @@
 static_assert(alignof(struct Nontrivial) == 4);
 static_assert(CRUBIT_OFFSET_OF(field, struct Nontrivial) == 0);
 
+static_assert(sizeof(union UnionToRename) == 1);
+static_assert(alignof(union UnionToRename) == 1);
+
+extern "C" void __rust_thunk___ZN13UnionToRenameC1Ev(
+    union UnionToRename* __this) {
+  crubit::construct_at(__this);
+}
+
+extern "C" void __rust_thunk___ZN13UnionToRenameC1EOS_(
+    union UnionToRename* __this, union UnionToRename* __param_0) {
+  crubit::construct_at(__this, std::move(*__param_0));
+}
+
+extern "C" union UnionToRename* __rust_thunk___ZN13UnionToRenameaSERKS_(
+    union UnionToRename* __this, const union UnionToRename* __param_0) {
+  return &__this->operator=(*__param_0);
+}
+
+extern "C" union UnionToRename* __rust_thunk___ZN13UnionToRenameaSEOS_(
+    union UnionToRename* __this, union UnionToRename* __param_0) {
+  return &__this->operator=(std::move(*__param_0));
+}
+
 static_assert(sizeof(struct TriviallyCopyableButNontriviallyDestructible) == 1);
 static_assert(alignof(struct TriviallyCopyableButNontriviallyDestructible) ==
               1);