Compute the space occupied by bases, vptr, etc. based on offset of first field.
This amounts to giving up: rather than enumerating each source of data, we just check the offset of the first field (or end of the array). I did it this way because, best as I can tell, ASTRecordLayout does not export information about vtable pointers except whether one exists or not -- so, for example, it doesn't say how many there are. It's simpler and unifying for several cases to simply write down an opaque thunk. This also unifies the logic with the empty struct / sizeof one case, though really that might be a bad thing, as it prevents us from making the field public.
We do still need to e.g. check that any base classes exist at all, in order to decide whether there must be a private field.
PiperOrigin-RevId: 446904649
diff --git a/docs/struct_layout.md b/docs/struct_layout.md
index 457c66c..aecebd8 100644
--- a/docs/struct_layout.md
+++ b/docs/struct_layout.md
@@ -15,11 +15,22 @@
* Public subobjects must have the same offsets in C++ and Rust versions of the
structs.
-## Empty Structs
+## Non-field data
-In C++, an empty struct or class (e.g. `struct Empty{};`) has size `1`, while in
-Rust, it has size `0`. To make the layout match up, bindings for empty structs
-have a private `MaybeUninit<u8>` field.
+Rust bindings introduce a `__non_field_data: [MaybeUninit<u8>; N]` field to
+cover data within the object that is not part of individual fields. This
+includes:
+
+* Base classes.
+* VTable pointers.
+* Empty struct padding.
+
+### Empty Structs
+
+One notable special case of this is the empty struct padding. An empty struct or
+class (e.g. `struct Empty{};`) has size `1`, while in Rust, it has size `0`. To
+make the layout match up, bindings for empty structs will always enforce that
+the struct has size of at least 1, via `__non_field_data`.
(In C++, different array elements are guaranteed to have different addresses,
and also, arrays are guaranteed to be contiguous. Therefore, no object in C++
@@ -90,7 +101,7 @@
// and Rust wouldn't permit `z` to live inside of it.
// Nor do we align the array, for the same reason -- correct alignment must be
// achieved via the repr(align(2)) at the top.
- __base_class_subobjects : [MaybeUninit<u8>; 3];
+ __non_field_data : [MaybeUninit<u8>; 3];
pub z: i8,
}
```
diff --git a/rs_bindings_from_cc/importers/cxx_record.cc b/rs_bindings_from_cc/importers/cxx_record.cc
index 0ae0fde..c4a8774 100644
--- a/rs_bindings_from_cc/importers/cxx_record.cc
+++ b/rs_bindings_from_cc/importers/cxx_record.cc
@@ -59,20 +59,9 @@
const clang::ASTRecordLayout& layout =
ictx_.ctx_.getASTRecordLayout(record_decl);
- llvm::Optional<size_t> base_size;
- bool override_alignment = record_decl->hasAttr<clang::AlignedAttr>();
- if (record_decl->getNumBases() != 0) {
- // The size of the base class subobjects is easy to compute, so long as we
- // know that fields start after the base class subobjects. (This is not
- // guaranteed by the standard, but is true on the ABIs we work with.)
- base_size = layout.getFieldCount() == 0
- ? static_cast<size_t>(layout.getDataSize().getQuantity())
- : layout.getFieldOffset(0) / 8;
- // Ideally, we'd only include an alignment adjustment if one of the base
- // classes is more-aligned than any of the fields, but it is simpler do it
- // whenever there are any base classes at all.
- override_alignment = true;
- }
+ bool is_derived_class = record_decl->getNumBases() != 0;
+ bool override_alignment = record_decl->hasAttr<clang::AlignedAttr>() ||
+ is_derived_class || layout.hasOwnVFPtr();
absl::StatusOr<std::vector<Field>> fields = ImportFields(record_decl);
if (!fields.ok()) {
@@ -99,7 +88,7 @@
.fields = *std::move(fields),
.size = layout.getSize().getQuantity(),
.alignment = layout.getAlignment().getQuantity(),
- .base_size = base_size,
+ .is_derived_class = is_derived_class,
.override_alignment = override_alignment,
.copy_constructor = GetCopyCtorSpecialMemberFunc(*record_decl),
.move_constructor = GetMoveCtorSpecialMemberFunc(*record_decl),
diff --git a/rs_bindings_from_cc/ir.cc b/rs_bindings_from_cc/ir.cc
index c626004..d6eb023 100644
--- a/rs_bindings_from_cc/ir.cc
+++ b/rs_bindings_from_cc/ir.cc
@@ -390,7 +390,7 @@
{"lifetime_params", lifetime_params},
{"size", size},
{"alignment", alignment},
- {"base_size", base_size},
+ {"is_derived_class", is_derived_class},
{"override_alignment", override_alignment},
{"copy_constructor", copy_constructor},
{"move_constructor", move_constructor},
diff --git a/rs_bindings_from_cc/ir.h b/rs_bindings_from_cc/ir.h
index feb8736..dfb30c1 100644
--- a/rs_bindings_from_cc/ir.h
+++ b/rs_bindings_from_cc/ir.h
@@ -553,13 +553,8 @@
int64_t size;
int64_t alignment;
- // The size of the base class subobjects, or null if there are none.
- //
- // More information: docs/struct_layout
- //
- // `llvm::Optional` is used because it integrates better with `llvm::json`
- // library than `std::optional`.
- llvm::Optional<size_t> base_size;
+ // True if any base classes exist.
+ bool is_derived_class;
// True if the alignment may differ from what the fields would imply.
//
diff --git a/rs_bindings_from_cc/ir.rs b/rs_bindings_from_cc/ir.rs
index acccc09..dee5d61 100644
--- a/rs_bindings_from_cc/ir.rs
+++ b/rs_bindings_from_cc/ir.rs
@@ -354,7 +354,7 @@
pub lifetime_params: Vec<LifetimeName>,
pub size: usize,
pub alignment: usize,
- pub base_size: Option<usize>,
+ pub is_derived_class: bool,
pub override_alignment: bool,
pub copy_constructor: SpecialMemberFunc,
pub move_constructor: SpecialMemberFunc,
diff --git a/rs_bindings_from_cc/ir_from_cc_test.rs b/rs_bindings_from_cc/ir_from_cc_test.rs
index 9a6f813..5d6852f 100644
--- a/rs_bindings_from_cc/ir_from_cc_test.rs
+++ b/rs_bindings_from_cc/ir_from_cc_test.rs
@@ -831,10 +831,9 @@
}], ...
size: 8,
alignment: 4,
- base_size: Some(4),
+ is_derived_class: true,
override_alignment: true,
...
- ...
}),
}
);
diff --git a/rs_bindings_from_cc/src_code_gen.rs b/rs_bindings_from_cc/src_code_gen.rs
index 7610ba8..e5f0e81 100644
--- a/rs_bindings_from_cc/src_code_gen.rs
+++ b/rs_bindings_from_cc/src_code_gen.rs
@@ -1014,13 +1014,21 @@
repr_attributes.push(quote! {align(#alignment)});
}
- // Adjust the struct to also include base class subobjects. We use an opaque
- // field because subobjects can live in the alignment of base class
- // subobjects.
- let base_subobjects_field = if let Some(base_size) = record.base_size {
- let n = proc_macro2::Literal::usize_unsuffixed(base_size);
+ // Adjust the struct to also include base class subobjects, vtables, etc.
+ let head_padding = if let Some(first_field) = record.fields.first() {
+ first_field.offset / 8
+ } else {
+ record.size
+ };
+ // TODO(b/231664029): Rework this check.
+ // It is probably fine to be a derived class, if it is trivially-relocatable
+ // (and thus implicit-lifetime), then we can initialize it through copying.
+ // The more important issue is that we should not sidestep user-defined
+ // constructors!
+ let head_padding = if head_padding > 0 || record.is_derived_class {
+ let n = proc_macro2::Literal::usize_unsuffixed(head_padding);
quote! {
- __base_class_subobjects: [rust_std::mem::MaybeUninit<u8>; #n],
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; #n],
}
} else {
quote! {}
@@ -1033,16 +1041,6 @@
forward_declare::unsafe_define!(forward_declare::symbol!(#incomplete_symbol), #ident);
};
- let empty_struct_placeholder_field =
- if record.fields.is_empty() && record.base_size.unwrap_or(0) == 0 {
- quote! {
- /// Prevent empty C++ struct being zero-size in Rust.
- placeholder: rust_std::mem::MaybeUninit<u8>,
- }
- } else {
- quote! {}
- };
-
let no_unique_address_accessors = cc_struct_no_unique_address_impl(record, ir)?;
let mut record_generated_items = record
.child_item_ids
@@ -1079,9 +1077,8 @@
#derives
#[repr(#( #repr_attributes ),*)]
pub #record_kind #ident {
- #base_subobjects_field
+ #head_padding
#( #field_doc_coments #field_accesses #field_idents: #field_types, )*
- #empty_struct_placeholder_field
}
#incomplete_definition
@@ -3094,7 +3091,7 @@
quote! {
#[repr(C, align(8))]
pub struct Derived {
- __base_class_subobjects: [rust_std::mem::MaybeUninit<u8>; 10],
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 10],
pub z: i16,
}
}
@@ -3119,7 +3116,7 @@
quote! {
#[repr(C, align(8))]
pub struct Derived {
- __base_class_subobjects: [rust_std::mem::MaybeUninit<u8>; 10],
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 10],
pub z: i16,
}
}
@@ -3144,7 +3141,7 @@
quote! {
#[repr(C, align(8))]
pub struct Derived {
- __base_class_subobjects: [rust_std::mem::MaybeUninit<u8>; 10],
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 10],
pub z: i16,
}
}
@@ -3168,7 +3165,7 @@
quote! {
#[repr(C, align(8))]
pub struct Derived {
- __base_class_subobjects: [rust_std::mem::MaybeUninit<u8>; 9],
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 16],
}
}
);
@@ -3189,9 +3186,7 @@
quote! {
#[repr(C)]
pub struct Derived {
- __base_class_subobjects: [rust_std::mem::MaybeUninit<u8>; 0],
- /// Prevent empty C++ struct being zero-size in Rust.
- placeholder: rust_std::mem::MaybeUninit<u8>,
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 1],
}
}
);
@@ -3203,18 +3198,19 @@
let ir = ir_from_cc(
r#"
class Base {};
- struct Derived final : Base {};
+ struct Derived final : Base {
+ __INT16_TYPE__ x;
+ };
"#,
)?;
let rs_api = generate_bindings_tokens(&ir)?.rs_api;
assert_rs_matches!(
rs_api,
quote! {
- #[repr(C)]
+ #[repr(C, align(2))]
pub struct Derived {
- __base_class_subobjects: [rust_std::mem::MaybeUninit<u8>; 0],
- /// Prevent empty C++ struct being zero-size in Rust.
- placeholder: rust_std::mem::MaybeUninit<u8>,
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 0],
+ pub x: i16,
}
}
);
@@ -3683,6 +3679,37 @@
}
#[test]
+ fn test_empty_struct() -> Result<()> {
+ let ir = ir_from_cc(
+ r#"
+ struct EmptyStruct final {};
+ "#,
+ )?;
+ let rs_api = generate_bindings_tokens(&ir)?.rs_api;
+
+ assert_rs_matches!(
+ rs_api,
+ quote! {
+ #[derive(Clone, Copy)]
+ #[repr(C)]
+ pub struct EmptyStruct {
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 1],
+ }
+ }
+ );
+
+ assert_rs_matches!(
+ rs_api,
+ quote! {
+ const _: () = assert!(rust_std::mem::size_of::<EmptyStruct>() == 1usize);
+ const _: () = assert!(rust_std::mem::align_of::<EmptyStruct>() == 1usize);
+ }
+ );
+
+ Ok(())
+ }
+
+ #[test]
fn test_empty_union() -> Result<()> {
let ir = ir_from_cc(
r#"
@@ -3697,8 +3724,7 @@
#[derive(Clone, Copy)]
#[repr(C)]
pub union EmptyUnion {
- /// Prevent empty C++ struct being zero-size in Rust.
- placeholder: rust_std::mem::MaybeUninit<u8>,
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 1],
}
}
);
diff --git a/rs_bindings_from_cc/test/golden/BUILD b/rs_bindings_from_cc/test/golden/BUILD
index feebe4a..46d9d52 100644
--- a/rs_bindings_from_cc/test/golden/BUILD
+++ b/rs_bindings_from_cc/test/golden/BUILD
@@ -64,7 +64,6 @@
) for name in TESTS if name not in [
# TODO(hlopko): These tests fail to compile, fix them.
"namespace",
- "polymorphic",
"types",
]]
diff --git a/rs_bindings_from_cc/test/golden/clang_attrs_rs_api.rs b/rs_bindings_from_cc/test/golden/clang_attrs_rs_api.rs
index 12dc6b4..d013603 100644
--- a/rs_bindings_from_cc/test/golden/clang_attrs_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/clang_attrs_rs_api.rs
@@ -18,8 +18,7 @@
#[repr(C, align(64))]
pub struct HasCustomAlignment {
- /// Prevent empty C++ struct being zero-size in Rust.
- placeholder: rust_std::mem::MaybeUninit<u8>,
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 64],
}
forward_declare::unsafe_define!(forward_declare::symbol!("HasCustomAlignment"), HasCustomAlignment);
@@ -78,9 +77,7 @@
#[repr(C, align(64))]
pub struct InheritsFromBaseWithCustomAlignment {
- __base_class_subobjects: [rust_std::mem::MaybeUninit<u8>; 0],
- /// Prevent empty C++ struct being zero-size in Rust.
- placeholder: rust_std::mem::MaybeUninit<u8>,
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 64],
}
forward_declare::unsafe_define!(
forward_declare::symbol!("InheritsFromBaseWithCustomAlignment"),
@@ -117,8 +114,7 @@
#[repr(C, align(64))]
pub struct HasCustomAlignmentWithGnuAttr {
- /// Prevent empty C++ struct being zero-size in Rust.
- placeholder: rust_std::mem::MaybeUninit<u8>,
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 64],
}
forward_declare::unsafe_define!(
forward_declare::symbol!("HasCustomAlignmentWithGnuAttr"),
diff --git a/rs_bindings_from_cc/test/golden/inheritance_rs_api.rs b/rs_bindings_from_cc/test/golden/inheritance_rs_api.rs
index 71ae6b5..1e3ca30 100644
--- a/rs_bindings_from_cc/test/golden/inheritance_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/inheritance_rs_api.rs
@@ -21,8 +21,7 @@
/// objects, even if the POD type is potentially-overlapping.
#[repr(C)]
pub struct Base0 {
- /// Prevent empty C++ struct being zero-size in Rust.
- placeholder: rust_std::mem::MaybeUninit<u8>,
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 1],
}
forward_declare::unsafe_define!(forward_declare::symbol!("Base0"), Base0);
@@ -108,7 +107,7 @@
#[derive(Clone, Copy)]
#[repr(C, align(8))]
pub struct Derived {
- __base_class_subobjects: [rust_std::mem::MaybeUninit<u8>; 12],
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 12],
pub derived_1: u8,
}
forward_declare::unsafe_define!(forward_declare::symbol!("Derived"), Derived);
@@ -151,7 +150,7 @@
#[repr(C, align(8))]
pub struct VirtualBase1 {
- __base_class_subobjects: [rust_std::mem::MaybeUninit<u8>; 17],
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 24],
}
forward_declare::unsafe_define!(forward_declare::symbol!("VirtualBase1"), VirtualBase1);
@@ -185,7 +184,7 @@
#[repr(C, align(8))]
pub struct VirtualBase2 {
- __base_class_subobjects: [rust_std::mem::MaybeUninit<u8>; 17],
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 24],
}
forward_declare::unsafe_define!(forward_declare::symbol!("VirtualBase2"), VirtualBase2);
@@ -219,7 +218,7 @@
#[repr(C, align(8))]
pub struct VirtualDerived {
- __base_class_subobjects: [rust_std::mem::MaybeUninit<u8>; 32],
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 32],
}
forward_declare::unsafe_define!(forward_declare::symbol!("VirtualDerived"), VirtualDerived);
diff --git a/rs_bindings_from_cc/test/golden/no_elided_lifetimes_rs_api.rs b/rs_bindings_from_cc/test/golden/no_elided_lifetimes_rs_api.rs
index 796e093..b8405b1 100644
--- a/rs_bindings_from_cc/test/golden/no_elided_lifetimes_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/no_elided_lifetimes_rs_api.rs
@@ -24,8 +24,7 @@
#[derive(Clone, Copy)]
#[repr(C)]
pub struct S {
- /// Prevent empty C++ struct being zero-size in Rust.
- placeholder: rust_std::mem::MaybeUninit<u8>,
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 1],
}
forward_declare::unsafe_define!(forward_declare::symbol!("S"), S);
diff --git a/rs_bindings_from_cc/test/golden/polymorphic.h b/rs_bindings_from_cc/test/golden/polymorphic.h
index 579c0c1..a457b18 100644
--- a/rs_bindings_from_cc/test/golden/polymorphic.h
+++ b/rs_bindings_from_cc/test/golden/polymorphic.h
@@ -7,9 +7,16 @@
#pragma clang lifetime_elision
-class PolymorphicClass {
+class PolymorphicBase {
public:
- virtual ~PolymorphicClass();
+ virtual ~PolymorphicBase();
};
+class PolymorphicBase2 {
+ public:
+ virtual void Foo();
+ virtual ~PolymorphicBase2();
+};
+
+class PolymorphicDerived : PolymorphicBase, PolymorphicBase2 {};
#endif // CRUBIT_RS_BINDINGS_FROM_CC_TEST_GOLDEN_POLYMORPHIC_H_
diff --git a/rs_bindings_from_cc/test/golden/polymorphic_rs_api.rs b/rs_bindings_from_cc/test/golden/polymorphic_rs_api.rs
index b7879bb..e8be41c 100644
--- a/rs_bindings_from_cc/test/golden/polymorphic_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/polymorphic_rs_api.rs
@@ -16,23 +16,22 @@
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-#[repr(C)]
-pub struct PolymorphicClass {
- /// Prevent empty C++ struct being zero-size in Rust.
- placeholder: rust_std::mem::MaybeUninit<u8>,
+#[repr(C, align(8))]
+pub struct PolymorphicBase {
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 8],
}
-forward_declare::unsafe_define!(forward_declare::symbol!("PolymorphicClass"), PolymorphicClass);
+forward_declare::unsafe_define!(forward_declare::symbol!("PolymorphicBase"), PolymorphicBase);
-impl !Unpin for PolymorphicClass {}
+impl !Unpin for PolymorphicBase {}
-impl ctor::CtorNew<()> for PolymorphicClass {
+impl ctor::CtorNew<()> for PolymorphicBase {
type CtorType = impl ctor::Ctor<Output = Self>;
#[inline(always)]
fn ctor_new(args: ()) -> Self::CtorType {
let () = args;
ctor::FnCtor::new(
move |dest: rust_std::pin::Pin<&mut rust_std::mem::MaybeUninit<Self>>| unsafe {
- detail::__rust_thunk___ZN16PolymorphicClassC1Ev(
+ detail::__rust_thunk___ZN15PolymorphicBaseC1Ev(
rust_std::pin::Pin::into_inner_unchecked(dest),
);
},
@@ -40,14 +39,14 @@
}
}
-impl<'b> ctor::CtorNew<&'b PolymorphicClass> for PolymorphicClass {
+impl<'b> ctor::CtorNew<&'b PolymorphicBase> for PolymorphicBase {
type CtorType = impl ctor::Ctor<Output = Self>;
#[inline(always)]
- fn ctor_new(args: &'b PolymorphicClass) -> Self::CtorType {
+ fn ctor_new(args: &'b PolymorphicBase) -> Self::CtorType {
let __param_0 = args;
ctor::FnCtor::new(
move |dest: rust_std::pin::Pin<&mut rust_std::mem::MaybeUninit<Self>>| unsafe {
- detail::__rust_thunk___ZN16PolymorphicClassC1ERKS_(
+ detail::__rust_thunk___ZN15PolymorphicBaseC1ERKS_(
rust_std::pin::Pin::into_inner_unchecked(dest),
__param_0,
);
@@ -55,50 +54,244 @@
)
}
}
-impl<'b> ctor::CtorNew<(&'b PolymorphicClass,)> for PolymorphicClass {
+impl<'b> ctor::CtorNew<(&'b PolymorphicBase,)> for PolymorphicBase {
type CtorType = impl ctor::Ctor<Output = Self>;
#[inline(always)]
- fn ctor_new(args: (&'b PolymorphicClass,)) -> Self::CtorType {
+ fn ctor_new(args: (&'b PolymorphicBase,)) -> Self::CtorType {
let (arg,) = args;
- <Self as ctor::CtorNew<&'b PolymorphicClass>>::ctor_new(arg)
+ <Self as ctor::CtorNew<&'b PolymorphicBase>>::ctor_new(arg)
}
}
// rs_bindings_from_cc/test/golden/polymorphic.h;l=10
-// Error while generating bindings for item 'PolymorphicClass::operator=':
+// Error while generating bindings for item 'PolymorphicBase::operator=':
// Bindings for this kind of operator are not supported
-impl Drop for PolymorphicClass {
+impl Drop for PolymorphicBase {
#[inline(always)]
fn drop<'a>(&'a mut self) {
- unsafe { detail::__rust_thunk___ZN16PolymorphicClassD1Ev(self) }
+ unsafe { detail::__rust_thunk___ZN15PolymorphicBaseD1Ev(self) }
}
}
+#[repr(C, align(8))]
+pub struct PolymorphicBase2 {
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 8],
+}
+forward_declare::unsafe_define!(forward_declare::symbol!("PolymorphicBase2"), PolymorphicBase2);
+
+impl !Unpin for PolymorphicBase2 {}
+
+impl ctor::CtorNew<()> for PolymorphicBase2 {
+ type CtorType = impl ctor::Ctor<Output = Self>;
+ #[inline(always)]
+ fn ctor_new(args: ()) -> Self::CtorType {
+ let () = args;
+ ctor::FnCtor::new(
+ move |dest: rust_std::pin::Pin<&mut rust_std::mem::MaybeUninit<Self>>| unsafe {
+ detail::__rust_thunk___ZN16PolymorphicBase2C1Ev(
+ rust_std::pin::Pin::into_inner_unchecked(dest),
+ );
+ },
+ )
+ }
+}
+
+impl<'b> ctor::CtorNew<&'b PolymorphicBase2> for PolymorphicBase2 {
+ type CtorType = impl ctor::Ctor<Output = Self>;
+ #[inline(always)]
+ fn ctor_new(args: &'b PolymorphicBase2) -> Self::CtorType {
+ let __param_0 = args;
+ ctor::FnCtor::new(
+ move |dest: rust_std::pin::Pin<&mut rust_std::mem::MaybeUninit<Self>>| unsafe {
+ detail::__rust_thunk___ZN16PolymorphicBase2C1ERKS_(
+ rust_std::pin::Pin::into_inner_unchecked(dest),
+ __param_0,
+ );
+ },
+ )
+ }
+}
+impl<'b> ctor::CtorNew<(&'b PolymorphicBase2,)> for PolymorphicBase2 {
+ type CtorType = impl ctor::Ctor<Output = Self>;
+ #[inline(always)]
+ fn ctor_new(args: (&'b PolymorphicBase2,)) -> Self::CtorType {
+ let (arg,) = args;
+ <Self as ctor::CtorNew<&'b PolymorphicBase2>>::ctor_new(arg)
+ }
+}
+
+// rs_bindings_from_cc/test/golden/polymorphic.h;l=14
+// Error while generating bindings for item 'PolymorphicBase2::operator=':
+// Bindings for this kind of operator are not supported
+
+impl PolymorphicBase2 {
+ #[inline(always)]
+ pub fn Foo<'a>(self: rust_std::pin::Pin<&'a mut Self>) {
+ unsafe { detail::__rust_thunk___ZN16PolymorphicBase23FooEv(self) }
+ }
+}
+
+impl Drop for PolymorphicBase2 {
+ #[inline(always)]
+ fn drop<'a>(&'a mut self) {
+ unsafe { detail::__rust_thunk___ZN16PolymorphicBase2D1Ev(self) }
+ }
+}
+
+#[repr(C, align(8))]
+pub struct PolymorphicDerived {
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 16],
+}
+forward_declare::unsafe_define!(forward_declare::symbol!("PolymorphicDerived"), PolymorphicDerived);
+
+impl !Unpin for PolymorphicDerived {}
+
+impl ctor::CtorNew<()> for PolymorphicDerived {
+ type CtorType = impl ctor::Ctor<Output = Self>;
+ #[inline(always)]
+ fn ctor_new(args: ()) -> Self::CtorType {
+ let () = args;
+ ctor::FnCtor::new(
+ move |dest: rust_std::pin::Pin<&mut rust_std::mem::MaybeUninit<Self>>| unsafe {
+ detail::__rust_thunk___ZN18PolymorphicDerivedC1Ev(
+ rust_std::pin::Pin::into_inner_unchecked(dest),
+ );
+ },
+ )
+ }
+}
+
+impl<'b> ctor::CtorNew<&'b PolymorphicDerived> for PolymorphicDerived {
+ type CtorType = impl ctor::Ctor<Output = Self>;
+ #[inline(always)]
+ fn ctor_new(args: &'b PolymorphicDerived) -> Self::CtorType {
+ let __param_0 = args;
+ ctor::FnCtor::new(
+ move |dest: rust_std::pin::Pin<&mut rust_std::mem::MaybeUninit<Self>>| unsafe {
+ detail::__rust_thunk___ZN18PolymorphicDerivedC1ERKS_(
+ rust_std::pin::Pin::into_inner_unchecked(dest),
+ __param_0,
+ );
+ },
+ )
+ }
+}
+impl<'b> ctor::CtorNew<(&'b PolymorphicDerived,)> for PolymorphicDerived {
+ type CtorType = impl ctor::Ctor<Output = Self>;
+ #[inline(always)]
+ fn ctor_new(args: (&'b PolymorphicDerived,)) -> Self::CtorType {
+ let (arg,) = args;
+ <Self as ctor::CtorNew<&'b PolymorphicDerived>>::ctor_new(arg)
+ }
+}
+
+impl<'b> ctor::CtorNew<ctor::RvalueReference<'b, PolymorphicDerived>> for PolymorphicDerived {
+ type CtorType = impl ctor::Ctor<Output = Self>;
+ #[inline(always)]
+ fn ctor_new(args: ctor::RvalueReference<'b, PolymorphicDerived>) -> Self::CtorType {
+ let __param_0 = args;
+ ctor::FnCtor::new(
+ move |dest: rust_std::pin::Pin<&mut rust_std::mem::MaybeUninit<Self>>| unsafe {
+ detail::__rust_thunk___ZN18PolymorphicDerivedC1EOS_(
+ rust_std::pin::Pin::into_inner_unchecked(dest),
+ __param_0,
+ );
+ },
+ )
+ }
+}
+impl<'b> ctor::CtorNew<(ctor::RvalueReference<'b, PolymorphicDerived>,)> for PolymorphicDerived {
+ type CtorType = impl ctor::Ctor<Output = Self>;
+ #[inline(always)]
+ fn ctor_new(args: (ctor::RvalueReference<'b, PolymorphicDerived>,)) -> Self::CtorType {
+ let (arg,) = args;
+ <Self as ctor::CtorNew<ctor::RvalueReference<'b, PolymorphicDerived>>>::ctor_new(arg)
+ }
+}
+
+impl Drop for PolymorphicDerived {
+ #[inline(always)]
+ fn drop<'a>(&'a mut self) {
+ unsafe { detail::__rust_thunk___ZN18PolymorphicDerivedD1Ev(self) }
+ }
+}
+
+// rs_bindings_from_cc/test/golden/polymorphic.h;l=20
+// Error while generating bindings for item 'PolymorphicDerived::operator=':
+// Bindings for this kind of operator are not supported
+
+// rs_bindings_from_cc/test/golden/polymorphic.h;l=20
+// Error while generating bindings for item 'PolymorphicDerived::operator=':
+// Bindings for this kind of operator are not supported
+
// CRUBIT_RS_BINDINGS_FROM_CC_TEST_GOLDEN_POLYMORPHIC_H_
mod detail {
#[allow(unused_imports)]
use super::*;
extern "C" {
- pub(crate) fn __rust_thunk___ZN16PolymorphicClassC1Ev<'a>(
- __this: &'a mut rust_std::mem::MaybeUninit<PolymorphicClass>,
+ pub(crate) fn __rust_thunk___ZN15PolymorphicBaseC1Ev<'a>(
+ __this: &'a mut rust_std::mem::MaybeUninit<PolymorphicBase>,
);
- pub(crate) fn __rust_thunk___ZN16PolymorphicClassC1ERKS_<'a, 'b>(
- __this: &'a mut rust_std::mem::MaybeUninit<PolymorphicClass>,
- __param_0: &'b PolymorphicClass,
+ pub(crate) fn __rust_thunk___ZN15PolymorphicBaseC1ERKS_<'a, 'b>(
+ __this: &'a mut rust_std::mem::MaybeUninit<PolymorphicBase>,
+ __param_0: &'b PolymorphicBase,
);
- pub(crate) fn __rust_thunk___ZN16PolymorphicClassD1Ev<'a>(__this: *mut PolymorphicClass);
+ pub(crate) fn __rust_thunk___ZN15PolymorphicBaseD1Ev<'a>(__this: *mut PolymorphicBase);
+ pub(crate) fn __rust_thunk___ZN16PolymorphicBase2C1Ev<'a>(
+ __this: &'a mut rust_std::mem::MaybeUninit<PolymorphicBase2>,
+ );
+ pub(crate) fn __rust_thunk___ZN16PolymorphicBase2C1ERKS_<'a, 'b>(
+ __this: &'a mut rust_std::mem::MaybeUninit<PolymorphicBase2>,
+ __param_0: &'b PolymorphicBase2,
+ );
+ pub(crate) fn __rust_thunk___ZN16PolymorphicBase23FooEv<'a>(
+ __this: rust_std::pin::Pin<&'a mut PolymorphicBase2>,
+ );
+ pub(crate) fn __rust_thunk___ZN16PolymorphicBase2D1Ev<'a>(__this: *mut PolymorphicBase2);
+ pub(crate) fn __rust_thunk___ZN18PolymorphicDerivedC1Ev<'a>(
+ __this: &'a mut rust_std::mem::MaybeUninit<PolymorphicDerived>,
+ );
+ pub(crate) fn __rust_thunk___ZN18PolymorphicDerivedC1ERKS_<'a, 'b>(
+ __this: &'a mut rust_std::mem::MaybeUninit<PolymorphicDerived>,
+ __param_0: &'b PolymorphicDerived,
+ );
+ pub(crate) fn __rust_thunk___ZN18PolymorphicDerivedC1EOS_<'a, 'b>(
+ __this: &'a mut rust_std::mem::MaybeUninit<PolymorphicDerived>,
+ __param_0: ctor::RvalueReference<'b, PolymorphicDerived>,
+ );
+ pub(crate) fn __rust_thunk___ZN18PolymorphicDerivedD1Ev<'a>(
+ __this: *mut PolymorphicDerived,
+ );
}
}
const _: () = assert!(rust_std::mem::size_of::<Option<&i32>>() == rust_std::mem::size_of::<&i32>());
-const _: () = assert!(rust_std::mem::size_of::<PolymorphicClass>() == 8usize);
-const _: () = assert!(rust_std::mem::align_of::<PolymorphicClass>() == 8usize);
+const _: () = assert!(rust_std::mem::size_of::<PolymorphicBase>() == 8usize);
+const _: () = assert!(rust_std::mem::align_of::<PolymorphicBase>() == 8usize);
const _: () = {
- static_assertions::assert_not_impl_all!(PolymorphicClass: Copy);
+ static_assertions::assert_not_impl_all!(PolymorphicBase: Copy);
};
const _: () = {
- static_assertions::assert_impl_all!(PolymorphicClass: Drop);
+ static_assertions::assert_impl_all!(PolymorphicBase: Drop);
+};
+
+const _: () = assert!(rust_std::mem::size_of::<PolymorphicBase2>() == 8usize);
+const _: () = assert!(rust_std::mem::align_of::<PolymorphicBase2>() == 8usize);
+const _: () = {
+ static_assertions::assert_not_impl_all!(PolymorphicBase2: Copy);
+};
+const _: () = {
+ static_assertions::assert_impl_all!(PolymorphicBase2: Drop);
+};
+
+const _: () = assert!(rust_std::mem::size_of::<PolymorphicDerived>() == 16usize);
+const _: () = assert!(rust_std::mem::align_of::<PolymorphicDerived>() == 8usize);
+const _: () = {
+ static_assertions::assert_not_impl_all!(PolymorphicDerived: Copy);
+};
+const _: () = {
+ static_assertions::assert_impl_all!(PolymorphicDerived: Drop);
};
diff --git a/rs_bindings_from_cc/test/golden/polymorphic_rs_api_impl.cc b/rs_bindings_from_cc/test/golden/polymorphic_rs_api_impl.cc
index 5e91e5b..3fe51c0 100644
--- a/rs_bindings_from_cc/test/golden/polymorphic_rs_api_impl.cc
+++ b/rs_bindings_from_cc/test/golden/polymorphic_rs_api_impl.cc
@@ -11,25 +11,82 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wthread-safety-analysis"
-extern "C" void __rust_thunk___ZN16PolymorphicClassC1Ev(
- class PolymorphicClass* __this) {
+extern "C" void __rust_thunk___ZN15PolymorphicBaseC1Ev(
+ class PolymorphicBase* __this) {
crubit::construct_at(std::forward<decltype(__this)>(__this));
}
-extern "C" void __rust_thunk___ZN16PolymorphicClassC1ERKS_(
- class PolymorphicClass* __this, const class PolymorphicClass& __param_0) {
+extern "C" void __rust_thunk___ZN15PolymorphicBaseC1ERKS_(
+ class PolymorphicBase* __this, const class PolymorphicBase& __param_0) {
crubit::construct_at(std::forward<decltype(__this)>(__this),
std::forward<decltype(__param_0)>(__param_0));
}
-extern "C" class PolymorphicClass& __rust_thunk___ZN16PolymorphicClassaSERKS_(
- class PolymorphicClass* __this, const class PolymorphicClass& __param_0) {
+extern "C" class PolymorphicBase& __rust_thunk___ZN15PolymorphicBaseaSERKS_(
+ class PolymorphicBase* __this, const class PolymorphicBase& __param_0) {
return __this->operator=(std::forward<decltype(__param_0)>(__param_0));
}
-extern "C" void __rust_thunk___ZN16PolymorphicClassD1Ev(
- class PolymorphicClass* __this) {
+extern "C" void __rust_thunk___ZN15PolymorphicBaseD1Ev(
+ class PolymorphicBase* __this) {
std::destroy_at(std::forward<decltype(__this)>(__this));
}
+extern "C" void __rust_thunk___ZN16PolymorphicBase2C1Ev(
+ class PolymorphicBase2* __this) {
+ crubit::construct_at(std::forward<decltype(__this)>(__this));
+}
+extern "C" void __rust_thunk___ZN16PolymorphicBase2C1ERKS_(
+ class PolymorphicBase2* __this, const class PolymorphicBase2& __param_0) {
+ crubit::construct_at(std::forward<decltype(__this)>(__this),
+ std::forward<decltype(__param_0)>(__param_0));
+}
+extern "C" class PolymorphicBase2& __rust_thunk___ZN16PolymorphicBase2aSERKS_(
+ class PolymorphicBase2* __this, const class PolymorphicBase2& __param_0) {
+ return __this->operator=(std::forward<decltype(__param_0)>(__param_0));
+}
+extern "C" void __rust_thunk___ZN16PolymorphicBase23FooEv(
+ class PolymorphicBase2* __this) {
+ __this->Foo();
+}
+extern "C" void __rust_thunk___ZN16PolymorphicBase2D1Ev(
+ class PolymorphicBase2* __this) {
+ std::destroy_at(std::forward<decltype(__this)>(__this));
+}
+extern "C" void __rust_thunk___ZN18PolymorphicDerivedC1Ev(
+ class PolymorphicDerived* __this) {
+ crubit::construct_at(std::forward<decltype(__this)>(__this));
+}
+extern "C" void __rust_thunk___ZN18PolymorphicDerivedC1ERKS_(
+ class PolymorphicDerived* __this,
+ const class PolymorphicDerived& __param_0) {
+ crubit::construct_at(std::forward<decltype(__this)>(__this),
+ std::forward<decltype(__param_0)>(__param_0));
+}
+extern "C" void __rust_thunk___ZN18PolymorphicDerivedC1EOS_(
+ class PolymorphicDerived* __this, class PolymorphicDerived&& __param_0) {
+ crubit::construct_at(std::forward<decltype(__this)>(__this),
+ std::forward<decltype(__param_0)>(__param_0));
+}
+extern "C" void __rust_thunk___ZN18PolymorphicDerivedD1Ev(
+ class PolymorphicDerived* __this) {
+ std::destroy_at(std::forward<decltype(__this)>(__this));
+}
+extern "C" class PolymorphicDerived&
+__rust_thunk___ZN18PolymorphicDerivedaSERKS_(
+ class PolymorphicDerived* __this,
+ const class PolymorphicDerived& __param_0) {
+ return __this->operator=(std::forward<decltype(__param_0)>(__param_0));
+}
+extern "C" class PolymorphicDerived&
+__rust_thunk___ZN18PolymorphicDerivedaSEOS_(
+ class PolymorphicDerived* __this, class PolymorphicDerived&& __param_0) {
+ return __this->operator=(std::forward<decltype(__param_0)>(__param_0));
+}
-static_assert(sizeof(class PolymorphicClass) == 8);
-static_assert(alignof(class PolymorphicClass) == 8);
+static_assert(sizeof(class PolymorphicBase) == 8);
+static_assert(alignof(class PolymorphicBase) == 8);
+
+static_assert(sizeof(class PolymorphicBase2) == 8);
+static_assert(alignof(class PolymorphicBase2) == 8);
+
+static_assert(sizeof(class PolymorphicDerived) == 16);
+static_assert(alignof(class PolymorphicDerived) == 8);
#pragma clang diagnostic pop
diff --git a/rs_bindings_from_cc/test/golden/types_rs_api.rs b/rs_bindings_from_cc/test/golden/types_rs_api.rs
index 7eb2b1c..8fc3b40 100644
--- a/rs_bindings_from_cc/test/golden/types_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/types_rs_api.rs
@@ -19,8 +19,7 @@
#[derive(Clone, Copy)]
#[repr(C)]
pub struct SomeStruct {
- /// Prevent empty C++ struct being zero-size in Rust.
- placeholder: rust_std::mem::MaybeUninit<u8>,
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 1],
}
forward_declare::unsafe_define!(forward_declare::symbol!("SomeStruct"), SomeStruct);
@@ -59,8 +58,7 @@
#[derive(Clone, Copy)]
#[repr(C)]
pub union EmptyUnion {
- /// Prevent empty C++ struct being zero-size in Rust.
- placeholder: rust_std::mem::MaybeUninit<u8>,
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 1],
}
forward_declare::unsafe_define!(forward_declare::symbol!("EmptyUnion"), EmptyUnion);
diff --git a/rs_bindings_from_cc/test/golden/unsupported_rs_api.rs b/rs_bindings_from_cc/test/golden/unsupported_rs_api.rs
index 4fef7fa..1c75f54 100644
--- a/rs_bindings_from_cc/test/golden/unsupported_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/unsupported_rs_api.rs
@@ -78,8 +78,7 @@
#[derive(Clone, Copy)]
#[repr(C)]
pub struct ContainingStruct {
- /// Prevent empty C++ struct being zero-size in Rust.
- placeholder: rust_std::mem::MaybeUninit<u8>,
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 1],
}
forward_declare::unsafe_define!(forward_declare::symbol!("ContainingStruct"), ContainingStruct);
diff --git a/rs_bindings_from_cc/test/golden/user_of_base_class_rs_api.rs b/rs_bindings_from_cc/test/golden/user_of_base_class_rs_api.rs
index 79f3510..b8dd7e3 100644
--- a/rs_bindings_from_cc/test/golden/user_of_base_class_rs_api.rs
+++ b/rs_bindings_from_cc/test/golden/user_of_base_class_rs_api.rs
@@ -23,7 +23,7 @@
/// TODO(b/216195042): Correctly namespace base classes in generated Rust code.
#[repr(C, align(8))]
pub struct Derived2 {
- __base_class_subobjects: [rust_std::mem::MaybeUninit<u8>; 20],
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 20],
pub derived_1: u8,
}
forward_declare::unsafe_define!(forward_declare::symbol!("Derived2"), Derived2);
@@ -68,7 +68,7 @@
#[repr(C, align(8))]
pub struct VirtualDerived2 {
- __base_class_subobjects: [rust_std::mem::MaybeUninit<u8>; 32],
+ __non_field_data: [rust_std::mem::MaybeUninit<u8>; 32],
}
forward_declare::unsafe_define!(forward_declare::symbol!("VirtualDerived2"), VirtualDerived2);