Mark OOP support code as experimental.

PiperOrigin-RevId: 604278765
Change-Id: I4c8751933091a01778b399fa290a297f8a0db372
diff --git a/rs_bindings_from_cc/src_code_gen.rs b/rs_bindings_from_cc/src_code_gen.rs
index 5492f54..563069e 100644
--- a/rs_bindings_from_cc/src_code_gen.rs
+++ b/rs_bindings_from_cc/src_code_gen.rs
@@ -2374,7 +2374,15 @@
         })
         .collect::<Result<Vec<_>>>()?;
 
-    record_generated_items.push(cc_struct_upcast_impl(record, &ir)?);
+    // Both the template definition and its instantiation should enable experimental
+    // features.
+    let mut crubit_features = ir.target_crubit_features(&record.owning_target);
+    if let Some(defining_target) = &record.defining_target {
+        crubit_features |= ir.target_crubit_features(defining_target);
+    }
+    if crubit_features.contains(ir::CrubitFeature::Experimental) {
+        record_generated_items.push(cc_struct_upcast_impl(record, &ir)?);
+    }
 
     let mut items = vec![];
     let mut thunks_from_record_items = vec![];
diff --git a/rs_bindings_from_cc/test/extern_c/BUILD b/rs_bindings_from_cc/test/extern_c/BUILD
index 82e5b8e..b9414dd 100644
--- a/rs_bindings_from_cc/test/extern_c/BUILD
+++ b/rs_bindings_from_cc/test/extern_c/BUILD
@@ -25,6 +25,10 @@
     proc_macro_deps = [
         "//common:item_exists",
     ],
+    deps = [
+        "//support:oops",
+        "@crate_index//:static_assertions",
+    ],
 )
 
 crubit_rust_test(
diff --git a/rs_bindings_from_cc/test/extern_c/has_bindings.h b/rs_bindings_from_cc/test/extern_c/has_bindings.h
index 55e5418..500bbbf 100644
--- a/rs_bindings_from_cc/test/extern_c/has_bindings.h
+++ b/rs_bindings_from_cc/test/extern_c/has_bindings.h
@@ -9,7 +9,7 @@
 namespace crubit::has_bindings {
 extern "C" {
 
-struct Struct final {
+struct Struct {
   int* x;
   float y;
   Struct* z;
@@ -57,5 +57,9 @@
 typedef void (*NullableCallback)(int* x);
 inline void crubit_invoke_nullable_callback(void (*f)(int* x), int* x) { f(x); }
 }
+
+struct MyDerivedStruct : Struct {
+  int derived_x;
+};
 }  // namespace crubit::has_bindings
 #endif  // THIRD_PARTY_CRUBIT_RS_BINDINGS_FROM_CC_TEST_EXTERN_C_ALLOWED_H_
diff --git a/rs_bindings_from_cc/test/extern_c/has_bindings_test.rs b/rs_bindings_from_cc/test/extern_c/has_bindings_test.rs
index 9865d6a..5b2cc69 100644
--- a/rs_bindings_from_cc/test/extern_c/has_bindings_test.rs
+++ b/rs_bindings_from_cc/test/extern_c/has_bindings_test.rs
@@ -3,6 +3,7 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
 use has_bindings::crubit::has_bindings;
+use static_assertions::assert_not_impl_any;
 
 #[test]
 fn test_void_function() {
@@ -119,3 +120,11 @@
     }
     assert_eq!(state, 42);
 }
+
+/// You can use a class that uses inheritance, but to Rust, it looks like
+/// private inheritance: the struct is only available as an opaque thunk within
+/// the derived class.
+#[test]
+fn test_oop() {
+    assert_not_impl_any!(has_bindings::MyDerivedStruct : oops::Inherits<has_bindings::Struct>);
+}