Assert that `format_cc_ident` doesn't return reserved C++ keywords.

PiperOrigin-RevId: 479324790
diff --git a/common/BUILD b/common/BUILD
index 7da3f34..667cb93 100644
--- a/common/BUILD
+++ b/common/BUILD
@@ -27,6 +27,7 @@
     name = "code_gen_utils",
     srcs = ["code_gen_utils.rs"],
     deps = [
+        "@crate_index//:once_cell",
         "@crate_index//:proc-macro2",
     ],
 )
diff --git a/common/code_gen_utils.rs b/common/code_gen_utils.rs
index c1161bf..8f05d74 100644
--- a/common/code_gen_utils.rs
+++ b/common/code_gen_utils.rs
@@ -2,7 +2,9 @@
 // Exceptions. See /LICENSE for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
+use once_cell::sync::Lazy;
 use proc_macro2::TokenStream;
+use std::collections::HashSet;
 
 // TODO(lukasza): Consider adding more items into `code_gen_utils` (this crate).
 // For example, the following items from `src_code_gen.rs` will be most likely
@@ -10,11 +12,125 @@
 // - `make_rs_ident`
 // - `NamespaceQualifier`
 
-/// Formats a C++ identifier. Does not escape C++ keywords.
+/// Formats a C++ identifier. Panics when `ident` is a C++ reserved keyword.
 pub fn format_cc_ident(ident: &str) -> TokenStream {
+    // C++ doesn't have an equivalent of
+    // https://doc.rust-lang.org/rust-by-example/compatibility/raw_identifiers.html and therefore
+    // we panic when `ident` is a C++ reserved keyword.
+    assert!(
+        !RESERVED_CC_KEYWORDS.contains(ident),
+        "The following reserved keyword can't be used as a C++ identifier: {}",
+        ident
+    );
+
     ident.parse().unwrap()
 }
 
+static RESERVED_CC_KEYWORDS: Lazy<HashSet<&'static str>> = Lazy::new(|| {
+    // `RESERVED_CC_KEYWORDS` are based on https://en.cppreference.com/w/cpp/keyword
+    [
+        "alignas",
+        "alignof",
+        "and",
+        "and_eq",
+        "asm",
+        "atomic_cancel",
+        "atomic_commit",
+        "atomic_noexcept",
+        "auto",
+        "bitand",
+        "bitor",
+        "bool",
+        "break",
+        "case",
+        "catch",
+        "char",
+        "char8_t",
+        "char16_t",
+        "char32_t",
+        "class",
+        "compl",
+        "concept",
+        "const",
+        "consteval",
+        "constexpr",
+        "constinit",
+        "const_cast",
+        "continue",
+        "co_await",
+        "co_return",
+        "co_yield",
+        "decltype",
+        "default",
+        "delete",
+        "do",
+        "double",
+        "dynamic_cast",
+        "else",
+        "enum",
+        "explicit",
+        "export",
+        "extern",
+        "false",
+        "float",
+        "for",
+        "friend",
+        "goto",
+        "if",
+        "inline",
+        "int",
+        "long",
+        "mutable",
+        "namespace",
+        "new",
+        "noexcept",
+        "not",
+        "not_eq",
+        "nullptr",
+        "operator",
+        "or",
+        "or_eq",
+        "private",
+        "protected",
+        "public",
+        "reflexpr",
+        "register",
+        "reinterpret_cast",
+        "requires",
+        "return",
+        "short",
+        "signed",
+        "sizeof",
+        "static",
+        "static_assert",
+        "static_cast",
+        "struct",
+        "switch",
+        "synchronized",
+        "template",
+        "this",
+        "thread_local",
+        "throw",
+        "true",
+        "try",
+        "typedef",
+        "typeid",
+        "typename",
+        "union",
+        "unsigned",
+        "using",
+        "virtual",
+        "void",
+        "volatile",
+        "wchar_t",
+        "while",
+        "xor",
+        "xor_eq",
+    ]
+    .into_iter()
+    .collect()
+});
+
 #[cfg(test)]
 pub mod tests {
     use super::*;
@@ -32,7 +148,8 @@
     }
 
     #[test]
+    #[should_panic(expected = "can't be used as a C++ identifier: reinterpret_cast")]
     fn test_format_cc_ident_reserved_cc_keyword() {
-        assert_cc_matches!(format_cc_ident("int"), quote! { int });
+        format_cc_ident("reinterpret_cast");
     }
 }
diff --git a/rs_bindings_from_cc/src_code_gen.rs b/rs_bindings_from_cc/src_code_gen.rs
index fb47acd..faea7e1 100644
--- a/rs_bindings_from_cc/src_code_gen.rs
+++ b/rs_bindings_from_cc/src_code_gen.rs
@@ -3136,8 +3136,11 @@
                     if !ty.type_args.is_empty() {
                         bail!("Type not yet supported: {:?}", ty);
                     }
-                    let idents = cc_type_name.split_whitespace().map(format_cc_ident);
-                    Ok(quote! {#( #idents )* #const_fragment})
+                    // Not using `code_gen_utils::format_cc_ident`, because
+                    // `cc_type_name` may be a C++ reserved keyword (e.g.
+                    // `int`).
+                    let cc_ident: TokenStream = cc_type_name.parse().unwrap();
+                    Ok(quote!{ #cc_ident #const_fragment })
                 }
                 Some(abi) => match ty.type_args.split_last() {
                     None => bail!("funcValue type without a return type: {:?}", ty),