Support deprecated attribute for type aliases

This CL adds functionality that, given a Rust type alias defined as:

```
#[deprecated = "Use `OtherTypeAlias` instead"]
pub type TypeAlias = i32;
```

...generates the following C++ type alias:

```
using TypeAlias [[deprecated("Use `OtherTypeAlias` instead")]] = std::int32_t;
```

PiperOrigin-RevId: 660553142
Change-Id: I0af595a1bcb1acb06f6314eb6592bd4de3951844
diff --git a/bazel/llvm.bzl b/bazel/llvm.bzl
index 543a5c9..fd4ba9c 100644
--- a/bazel/llvm.bzl
+++ b/bazel/llvm.bzl
@@ -53,7 +53,7 @@
             executable = False,
         )
 
-LLVM_COMMIT_SHA = "2f28378317827afed81db1c2ce33c187ee6582a0"
+LLVM_COMMIT_SHA = "41491c77231e9d389ef18593be1fab4f4e810e88"
 
 def llvm_loader_repository_dependencies():
     # This *declares* the dependency, but it won't actually be *downloaded* unless it's used.
diff --git a/cc_bindings_from_rs/bindings.rs b/cc_bindings_from_rs/bindings.rs
index 658e9d4..3b24687 100644
--- a/cc_bindings_from_rs/bindings.rs
+++ b/cc_bindings_from_rs/bindings.rs
@@ -1219,12 +1219,8 @@
     }
 }
 
-/// Checks if the item associated with the given def_id has a deprecated
-/// attribute. If so, returns the corresponding C++ deprecated tag.
-///
-/// TODO(codyheiner): consider adding a more general version of this function
-/// that builds a Vec<TokenStream> containing all the attributes of a given
-/// item.
+/// Returns the C++ deprecated tag for the item identified by `def_id`, if it is
+/// deprecated. Otherwise, returns None.
 fn format_deprecated_tag(tcx: TyCtxt, def_id: DefId) -> Option<TokenStream> {
     if let Some(deprecated_attr) = tcx.get_attr(def_id, rustc_span::symbol::sym::deprecated) {
         if let Some((deprecation, _span)) =
@@ -1321,7 +1317,7 @@
             // This points directly to a type definition, not an alias or compound data
             // type, so we can drop the hir type.
             let use_type = SugaredTy::new(tcx.type_of(def_id).instantiate_identity(), None);
-            create_type_alias(db, using_name, use_type)
+            create_type_alias(db, def_id, using_name, use_type)
         }
         _ => bail!(
             "Unsupported use statement that refers to this type of the entity: {:#?}",
@@ -1341,11 +1337,12 @@
         panic!("called format_type_alias on a non-type-alias");
     };
     let alias_type = SugaredTy::new(tcx.type_of(def_id).instantiate_identity(), Some(*hir_ty));
-    create_type_alias(db, tcx.item_name(def_id).as_str(), alias_type)
+    create_type_alias(db, def_id, tcx.item_name(def_id).as_str(), alias_type)
 }
 
 fn create_type_alias<'tcx>(
     db: &dyn BindingsGenerator<'tcx>,
+    def_id: DefId,
     alias_name: &str,
     alias_type: SugaredTy<'tcx>,
 ) -> Result<ApiSnippets> {
@@ -1354,7 +1351,13 @@
     let actual_type_name = cc_bindings.into_tokens(&mut main_api_prereqs);
 
     let alias_name = format_cc_ident(alias_name).context("Error formatting type alias name")?;
-    let tokens = quote! {using #alias_name = #actual_type_name;};
+
+    let mut attributes = vec![];
+    if let Some(cc_deprecated_tag) = format_deprecated_tag(db.tcx(), def_id) {
+        attributes.push(cc_deprecated_tag);
+    }
+
+    let tokens = quote! {using #alias_name #(#attributes)* = #actual_type_name;};
 
     Ok(ApiSnippets {
         main_api: CcSnippet { prereqs: main_api_prereqs, tokens },
@@ -7302,6 +7305,25 @@
     }
 
     #[test]
+    fn test_format_item_type_alias_deprecated() {
+        let test_src = r#"
+                #[deprecated = "Use `OtherTypeAlias` instead"]
+                pub type TypeAlias = i32;
+            "#;
+        test_format_item(test_src, "TypeAlias", |result| {
+            let result = result.unwrap().unwrap();
+            let main_api = &result.main_api;
+            assert!(!main_api.prereqs.is_empty());
+            assert_cc_matches!(
+                main_api.tokens,
+                quote! {
+                    using TypeAlias [[deprecated("Use `OtherTypeAlias` instead")]] = std::int32_t;
+                }
+            );
+        });
+    }
+
+    #[test]
     fn test_format_item_unsupported_impl_item_const_value() {
         let test_src = r#"
                 #![allow(dead_code)]
diff --git a/cc_bindings_from_rs/test/type_aliases/type_aliases.rs b/cc_bindings_from_rs/test/type_aliases/type_aliases.rs
index 50db93e..6e27c77 100644
--- a/cc_bindings_from_rs/test/type_aliases/type_aliases.rs
+++ b/cc_bindings_from_rs/test/type_aliases/type_aliases.rs
@@ -10,3 +10,8 @@
         0
     }
 }
+
+pub mod test_deprecated_type_alias {
+    #[deprecated = "Use `OtherTypeAlias` instead"]
+    pub type TypeAlias = i32;
+}
diff --git a/cc_bindings_from_rs/test/type_aliases/type_aliases_test.cc b/cc_bindings_from_rs/test/type_aliases/type_aliases_test.cc
index 9051ce4..24357b4 100644
--- a/cc_bindings_from_rs/test/type_aliases/type_aliases_test.cc
+++ b/cc_bindings_from_rs/test/type_aliases/type_aliases_test.cc
@@ -2,8 +2,8 @@
 // Exceptions. See /LICENSE for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
+#include <cstdint>
 #include <type_traits>
-#include <utility>
 
 #include "gtest/gtest.h"
 #include "cc_bindings_from_rs/test/type_aliases/type_aliases_cc_api.h"
@@ -27,5 +27,13 @@
                decltype(type_aliases::test_type_aliases::func_using_alias())>));
 }
 
+// Note: this test verifies that the generated code compiles and gives the
+// correct type, but doesn't check that the C++ type is actually deprecated.
+TEST(TypeAliasesTest, DeprecatedTypeAlias) {
+  EXPECT_TRUE(
+      (std::is_same_v<std::int32_t,
+                      type_aliases::test_deprecated_type_alias::TypeAlias>));
+}
+
 }  // namespace
-}  // namespace crubit
\ No newline at end of file
+}  // namespace crubit