Implement inline namespaces.

Items in an inline namespace are exported both in the inline namespace's `mod`, and the parent `mod`, via `pub use inline_ns::*;`.

PiperOrigin-RevId: 473316917
diff --git a/rs_bindings_from_cc/importers/namespace.cc b/rs_bindings_from_cc/importers/namespace.cc
index 0fcd9d2..4f934a7 100644
--- a/rs_bindings_from_cc/importers/namespace.cc
+++ b/rs_bindings_from_cc/importers/namespace.cc
@@ -29,7 +29,7 @@
       .owning_target = ictx_.GetOwningTarget(namespace_decl),
       .child_item_ids = std::move(item_ids),
       .enclosing_namespace_id = GetEnclosingNamespaceId(namespace_decl),
-  };
+      .is_inline = namespace_decl->isInline()};
 }
 
 }  // namespace crubit
diff --git a/rs_bindings_from_cc/ir.cc b/rs_bindings_from_cc/ir.cc
index 9e4b77c..7869e42 100644
--- a/rs_bindings_from_cc/ir.cc
+++ b/rs_bindings_from_cc/ir.cc
@@ -512,6 +512,7 @@
       {"owning_target", owning_target},
       {"child_item_ids", std::move(json_item_ids)},
       {"enclosing_namespace_id", enclosing_namespace_id},
+      {"is_inline", is_inline},
   };
 
   return llvm::json::Object{
diff --git a/rs_bindings_from_cc/ir.h b/rs_bindings_from_cc/ir.h
index abdc741..868f6ac 100644
--- a/rs_bindings_from_cc/ir.h
+++ b/rs_bindings_from_cc/ir.h
@@ -751,6 +751,7 @@
   BazelLabel owning_target;
   std::vector<ItemId> child_item_ids;
   llvm::Optional<ItemId> enclosing_namespace_id;
+  bool is_inline = false;
 };
 
 inline std::ostream& operator<<(std::ostream& o, const Namespace& n) {
diff --git a/rs_bindings_from_cc/ir.rs b/rs_bindings_from_cc/ir.rs
index 05123ee..bb10ce6 100644
--- a/rs_bindings_from_cc/ir.rs
+++ b/rs_bindings_from_cc/ir.rs
@@ -520,6 +520,7 @@
     #[serde(default)]
     pub child_item_ids: Vec<ItemId>,
     pub enclosing_namespace_id: Option<ItemId>,
+    pub is_inline: bool,
 }
 
 #[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)]
diff --git a/rs_bindings_from_cc/src_code_gen.rs b/rs_bindings_from_cc/src_code_gen.rs
index a6562fd..267fc51 100644
--- a/rs_bindings_from_cc/src_code_gen.rs
+++ b/rs_bindings_from_cc/src_code_gen.rs
@@ -2150,10 +2150,12 @@
     }
 
     let reopened_namespace_idx = ir.get_reopened_namespace_idx(namespace.id)?;
-    let should_skip_index =
+    // True if this is actually the module with the name `#name`, rather than e.g.
+    // `#name_0`, `#name_1`, etc.
+    let is_canonical_namespace_module =
         ir.is_last_reopened_namespace(namespace.id, namespace.canonical_namespace_id)?;
 
-    let name = if should_skip_index {
+    let name = if is_canonical_namespace_module {
         make_rs_ident(&namespace.name.identifier)
     } else {
         make_rs_ident(&format!("{}_{}", &namespace.name.identifier, reopened_namespace_idx))
@@ -2170,12 +2172,20 @@
         quote! { pub use super::#previous_namespace_ident::*; __NEWLINE__ __NEWLINE__ }
     };
 
+    let use_stmt_for_inline_namespace = if namespace.is_inline && is_canonical_namespace_module {
+        quote! {pub use #name::*; __NEWLINE__}
+    } else {
+        quote! {}
+    };
+
     let namespace_tokens = quote! {
         pub mod #name {
             #use_stmt_for_previous_namespace
 
             #( #items __NEWLINE__ __NEWLINE__ )*
         }
+        __NEWLINE__
+        #use_stmt_for_inline_namespace
     };
 
     Ok(GeneratedItem {
@@ -7286,6 +7296,7 @@
                         ...
                         pub struct MyStruct {...} ...
                     }
+                    pub use inner::*;
                     ...
                     pub fn processMyStruct(s: crate::test_namespace_bindings::inner::MyStruct)
                     ...
@@ -7301,6 +7312,38 @@
     }
 
     #[test]
+    fn test_inline_namespace_not_marked_inline() -> Result<()> {
+        let rs_api = generate_bindings_tokens(ir_from_cc(
+            r#"
+            inline namespace my_inline {}
+            namespace foo {}
+            namespace my_inline {  // still an inline namespace!
+                struct MyStruct final {};
+            }
+            "#,
+        )?)?
+        .rs_api;
+
+        assert_rs_matches!(
+            rs_api,
+            quote! {
+               ...
+               pub mod my_inline_0 {}
+               pub mod foo {}
+               pub mod my_inline {
+                   pub use super::my_inline_0::*;
+                   ...
+                   pub struct MyStruct {...}
+                   ...
+               }
+               pub use my_inline::*;
+               ...
+            }
+        );
+        Ok(())
+    }
+
+    #[test]
     fn test_implicit_template_specializations_are_sorted_by_mangled_name() -> Result<()> {
         let bindings = generate_bindings_tokens(ir_from_cc(
             r#"
diff --git a/rs_bindings_from_cc/test/cc_std/test.rs b/rs_bindings_from_cc/test/cc_std/test.rs
index 578c639..eed19d2 100644
--- a/rs_bindings_from_cc/test/cc_std/test.rs
+++ b/rs_bindings_from_cc/test/cc_std/test.rs
@@ -29,15 +29,13 @@
     }
 
     #[test]
-    fn test_limits() {
+    fn test_limits_inline() {
         // Tests of items from the `<limits>` header.
         // https://en.cppreference.com/w/cpp/types/numeric_limits/float_round_style:
-        //
-        // TODO(b/244601795): Stop mentioning the `inline` `__u` namespace below
-        assert_eq!(0, std::__u::float_round_style::round_toward_zero.into());
-        assert_eq!(1, std::__u::float_round_style::round_to_nearest.into());
-        assert_eq!(2, std::__u::float_round_style::round_toward_infinity.into());
-        assert_eq!(3, std::__u::float_round_style::round_toward_neg_infinity.into());
-        assert_eq!(-1, std::__u::float_round_style::round_indeterminate.into());
+        assert_eq!(0, std::float_round_style::round_toward_zero.into());
+        assert_eq!(1, std::float_round_style::round_to_nearest.into());
+        assert_eq!(2, std::float_round_style::round_toward_infinity.into());
+        assert_eq!(3, std::float_round_style::round_toward_neg_infinity.into());
+        assert_eq!(-1, std::float_round_style::round_indeterminate.into());
     }
 }
diff --git a/rs_bindings_from_cc/test/golden/namespace_rs_api.rs b/rs_bindings_from_cc/test/golden/namespace_rs_api.rs
index 120ac0b..cc60f89 100644
--- a/rs_bindings_from_cc/test/golden/namespace_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/namespace_rs_api.rs
@@ -229,6 +229,7 @@
         // Error while generating bindings for item 'StructInInlineNamespace::operator=':
         // operator= for Unpin types is not yet supported.
     }
+    pub use inner::*;
 
     // namespace inner
 }
diff --git a/rs_bindings_from_cc/test/namespace/inline/test.rs b/rs_bindings_from_cc/test/namespace/inline/test.rs
index 505ca0a..5e3711d 100644
--- a/rs_bindings_from_cc/test/namespace/inline/test.rs
+++ b/rs_bindings_from_cc/test/namespace/inline/test.rs
@@ -19,15 +19,16 @@
         // `std::__u::string`. Therefore the test verifies that the
         // inner types and functions are also available in the parent
         // namespace.
-        //
-        // TODO(b/244601795): Add test coverage below.
-        // > // `foo::MyStruct` should be a type alias for
-        // > // `foo::inline1::MyStruct`.
-        // > let mut s2 = foo::MyStruct { value: 456 };
-        // > s2 = s;
-        // > // The functions should be available as `foo::GetStructValue...`
-        // > // as well.
-        // > assert_eq!(123, foo::GetStructValue1(&s));
-        // > assert_eq!(123, foo::GetStructValue2(&s));
+        // `foo::MyStruct` should be a type alias for
+        // `foo::inline1::MyStruct`.
+        #[allow(unused_assignments)]
+        let mut s2 = foo::MyStruct { value: 456 };
+        s2 = s; // these are literally the same type.
+        // The functions should be available as `foo::GetStructValue...`
+        // as well.
+        assert_eq!(123, foo::GetStructValue1(&s2));
+        assert_eq!(123, foo::GetStructValue2(&s2));
+        assert_eq!(123, foo::GetStructValue3(&s2));
+        assert_eq!(123, foo::GetStructValue4(&s2));
     }
 }