Suppress fields that have destructors, instead of using `ManuallyDrop`.
Ideally, we'd like to use a `manually_drop` feature instead, in rust, but I haven't... really had time to push that FR forward / it hasn't been a priority after all. Oops. For now, just hide them.
PiperOrigin-RevId: 602640549
Change-Id: Ifb515b0d90191167f8da7c3a8bf8f1f4befab21e
diff --git a/rs_bindings_from_cc/src_code_gen.rs b/rs_bindings_from_cc/src_code_gen.rs
index f8bd356..f251fcc 100644
--- a/rs_bindings_from_cc/src_code_gen.rs
+++ b/rs_bindings_from_cc/src_code_gen.rs
@@ -2046,10 +2046,25 @@
);
}
}
- match &field.type_ {
- Ok(t) => db.rs_type_kind(t.rs_type.clone()),
- Err(e) => Err(anyhow!("{e}")),
+ let type_kind = match &field.type_ {
+ Ok(t) => db.rs_type_kind(t.rs_type.clone())?,
+ Err(e) => bail!("{e}"),
+ };
+ // In extern_c, we replace nontrivial fields with opaque blobs.
+ // This is because we likely don't want the `ManuallyDrop<T>` solution to be the
+ // one users get.
+ //
+ // Users can still work around this with accessor functions.
+ if should_implement_drop(record) && !record.is_union() && needs_manually_drop(&type_kind) {
+ for target in record.defining_target.iter().chain([&record.owning_target]) {
+ let required_features = db.ir().target_crubit_features(target);
+ ensure!(
+ required_features.contains(ir::CrubitFeature::Experimental),
+ "nontrivial fields would be destroyed in the wrong order"
+ );
+ }
}
+ Ok(type_kind)
}
/// Returns the type of a type-less, unaligned block of memory that can hold a
@@ -8768,29 +8783,30 @@
Ok(())
}
- /// Fields with unknown attributes on supported structs are replaced with
- /// opaque blobs.
- ///
- /// This is hard to test any other way than token comparison!
+ /// Nontrivial fields are replaced with opaque blobs, even if they're
+ /// supported!
#[test]
- fn test_extern_c_unknown_attr_field() -> Result<()> {
+ fn test_extern_c_nontrivial_field() -> Result<()> {
let mut ir = ir_from_cc(
"#
- struct Trivial {
- [[deprecated]] void* hidden_field;
- };
+ struct [[clang::trivial_abi]] Inner {~Inner();};
+ struct [[clang::trivial_abi]] Outer {Inner inner_field;};
#",
)?;
*ir.target_crubit_features_mut(&ir.current_target().clone()) =
ir::CrubitFeature::ExternC.into();
let BindingsTokens { rs_api, .. } = generate_bindings_tokens(ir)?;
+ // Note: inner is a supported type, so it isn't being replaced by a blob because
+ // it's unsupporter or anything.
+ assert_rs_matches!(rs_api, quote! {pub struct Inner});
+ // But it _is_ being replaced by a blob!
assert_rs_matches!(
rs_api,
quote! {
- struct Trivial {
+ pub struct Outer {
...
- pub(crate) hidden_field: [::core::mem::MaybeUninit<u8>; 8],
+ pub(crate) inner_field: [::core::mem::MaybeUninit<u8>; 1],
}}
);
Ok(())