diff --git a/common/annotation_reader.cc b/common/annotation_reader.cc index a653e7ae1..f02e9a7e9 100644 --- a/common/annotation_reader.cc +++ b/common/annotation_reader.cc @@ -7,6 +7,7 @@ #include #include #include +#include #include "absl/base/attributes.h" #include "absl/base/nullability.h" @@ -303,6 +304,30 @@ absl::StatusOr> GetAnnotationWithStringArg( return std::string(*arg); } +absl::StatusOr>> +GetAnnotationWithStringArgs(const clang::Decl& decl, + absl::string_view annotation_name) { + CRUBIT_ASSIGN_OR_RETURN(std::optional maybe_args, + GetAnnotateAttrArgs(decl, annotation_name)); + if (!maybe_args.has_value()) { + return std::nullopt; + } + const AnnotateArgs& args = *maybe_args; + std::vector result; + result.reserve(args.size()); + for (const clang::Expr* arg_expr : args) { + absl::StatusOr arg = + GetExprAsStringLiteral(*arg_expr, decl.getASTContext()); + if (!arg.ok()) { + return absl::InvalidArgumentError( + absl::StrCat("Annotation ", annotation_name, + " arguments must be string literals.")); + } + result.push_back(std::string(*arg)); + } + return result; +} + absl::StatusOr GetTypeAnnotationSingleDecl(const clang::Type* absl_nonnull type ABSL_ATTRIBUTE_LIFETIME_BOUND, diff --git a/common/annotation_reader.h b/common/annotation_reader.h index bec5ea159..24672af7f 100644 --- a/common/annotation_reader.h +++ b/common/annotation_reader.h @@ -79,6 +79,16 @@ absl::StatusOr GetExprAsStringLiteral( absl::StatusOr> GetAnnotationWithStringArg( const clang::Decl& decl, absl::string_view annotation_name); +// Returns the string arguments of [[clang::annotate(annotation_name, +// string_arg1, string_arg2, ...)]] annotation on `decl`, or none if the +// annotation does not exist. +// +// Returns an error if there are conflicting annotations or if any argument is +// not a string. +absl::StatusOr>> +GetAnnotationWithStringArgs(const clang::Decl& decl, + absl::string_view annotation_name); + // Returns true if `decl` has an annotation with the given name. // // Returns an error if an annotation with the given name exists, but it has diff --git a/common/annotation_reader_test.cc b/common/annotation_reader_test.cc index 4981cd90f..478f8ae03 100644 --- a/common/annotation_reader_test.cc +++ b/common/annotation_reader_test.cc @@ -15,6 +15,7 @@ namespace crubit { namespace { +using testing::ElementsAre; using testing::Eq; using testing::HasSubstr; using testing::Ne; @@ -151,5 +152,41 @@ TEST(AnnotationReaderTest, ASSERT_THAT(GetAnnotateAttrArgs(var, "foo"), IsOkAndHolds(Ne(std::nullopt))); } +TEST(AnnotationReaderTest, GetAnnotationWithStringArgsSuccess) { + clang::TestAST ast(R"cc( + [[clang::annotate("foo", "arg1", "arg2")]] int i; + )cc"); + + auto& var = LookupDecl(ast.context(), "i"); + + auto result = GetAnnotationWithStringArgs(var, "foo"); + ASSERT_THAT(result, IsOkAndHolds(Ne(std::nullopt))); + EXPECT_THAT(**result, ElementsAre("arg1", "arg2")); +} + +TEST(AnnotationReaderTest, GetAnnotationWithStringArgsNone) { + clang::TestAST ast(R"cc( + int i; + )cc"); + + auto& var = LookupDecl(ast.context(), "i"); + + EXPECT_THAT(GetAnnotationWithStringArgs(var, "foo"), + IsOkAndHolds(Eq(std::nullopt))); +} + +TEST(AnnotationReaderTest, GetAnnotationWithStringArgsFailureNonString) { + clang::TestAST ast(R"cc( + [[clang::annotate("foo", "arg1", 42)]] int i; + )cc"); + + auto& var = LookupDecl(ast.context(), "i"); + + EXPECT_THAT( + GetAnnotationWithStringArgs(var, "foo"), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("Annotation foo arguments must be string literals."))); +} + } // namespace } // namespace crubit diff --git a/rs_bindings_from_cc/generate_bindings/database/code_snippet.rs b/rs_bindings_from_cc/generate_bindings/database/code_snippet.rs index 83dbad235..942de8c13 100644 --- a/rs_bindings_from_cc/generate_bindings/database/code_snippet.rs +++ b/rs_bindings_from_cc/generate_bindings/database/code_snippet.rs @@ -540,7 +540,7 @@ pub fn generated_items_to_tokens<'db>( nested_items, indirect_functions, delete, - owned_type_name, + owned_ptr_config, member_methods, free_functions, lifetime_params, @@ -604,10 +604,12 @@ pub fn generated_items_to_tokens<'db>( None }; - let owned_type_def = owned_type_name.as_ref().map(|owned_type_name| { + let owned_type_def = owned_ptr_config.as_ref().map(|cfg| { + let owned_type_name = &cfg.owned_type_name; + let drop_meth = &cfg.drop_impl; let doc_comment = format!( - "Wrapper for a C++ {} owned by Rust. \n\n Style guide: The C++ type to which this refers should be wrapped in an `Arc` or `Mutex` if it is not already thread-safe. \n\n THIS TYPE REQUIRES A MANUAL DROP IMPLEMENTATION. \n You MUST provide an `impl {} {{ pub fn DropImpl(&mut self) {{ ... }} }}` block in a separate Rust file (e.g., via `additional_rust_srcs`). Failure to do so will result in a compile-time error: `method not found in `{}``.", - ident, owned_type_name, owned_type_name + "Wrapper for a C++ {} owned by Rust. \n\n Style guide: The C++ type to which this refers should be wrapped in an `Arc` or `Mutex` if it is not already thread-safe. \n\n THIS TYPE REQUIRES A MANUAL DROP IMPLEMENTATION. \n You MUST provide an `impl {} {{ pub fn {}(&mut self) {{ ... }} }}` block in a separate Rust file (e.g., via `additional_rust_srcs`). Failure to do so will result in a compile-time error: `method not found in `{}``.", + ident, owned_type_name, drop_meth, owned_type_name ); quote! { __NEWLINE__ __NEWLINE__ @@ -618,10 +620,10 @@ pub fn generated_items_to_tokens<'db>( impl Drop for #owned_type_name { fn drop(&mut self) { - __COMMENT__ "IMPORTANT: The DropImpl method for `{}` MUST be implemented in a user-written .rs file (e.g., using `additional_rust_srcs`)." + __COMMENT__ "IMPORTANT: The drop method MUST be implemented in a user-written .rs file (e.g., using `additional_rust_srcs`)." __COMMENT__ "Crubit cannot automatically generate the destruction logic for this type." __COMMENT__ "See the struct documentation for more details." - self.DropImpl(); + self.#drop_meth(); } } } @@ -977,6 +979,12 @@ impl GeneratedItem { } } +#[derive(Clone, Debug)] +pub struct OwnedPtrConfig { + pub owned_type_name: Ident, + pub drop_impl: Ident, +} + #[derive(Clone, Debug)] pub struct Record { pub doc_comment_attr: Option, @@ -1005,8 +1013,8 @@ pub struct Record { /// Functions that get attached either by a trait or from a base class. pub indirect_functions: Vec, pub delete: Option, - /// The name of the owning wrapper type when the type was annotated with CRUBIT_OWNED_POINTEE. - pub owned_type_name: Option, + /// The owning wrapper type configuration when the type was annotated with CRUBIT_OWNED_POINTEE. + pub owned_ptr_config: Option, pub member_methods: Vec, pub free_functions: Vec, pub lifetime_params: Vec, diff --git a/rs_bindings_from_cc/generate_bindings/database/rs_snippet.rs b/rs_bindings_from_cc/generate_bindings/database/rs_snippet.rs index be4d84ba1..221a56021 100644 --- a/rs_bindings_from_cc/generate_bindings/database/rs_snippet.rs +++ b/rs_bindings_from_cc/generate_bindings/database/rs_snippet.rs @@ -844,7 +844,7 @@ impl RsTypeKind { lifetimes, in_cc_std, )?, - owned_ptr_type: record.owned_ptr_type.clone(), + owned_ptr_type: record.owned_ptr_config.as_ref().map(|cfg| cfg.owned_ptr_type.clone()), record, crate_path, lifetimes: lifetimes.to_vec(), @@ -1448,7 +1448,7 @@ impl RsTypeKind { ) }; - let owned_ptr_type = record.owned_ptr_type.as_ref().expect( + let owned_ptr_type = record.owned_ptr_config.as_ref().map(|cfg| cfg.owned_ptr_type.as_ref()).expect( "CRUBIT_OWNED_POINTER annotated pointers should point to a struct with an associated CRUBIT_OWNED_POINTEE", ); diff --git a/rs_bindings_from_cc/generate_bindings/generate_struct_and_union.rs b/rs_bindings_from_cc/generate_bindings/generate_struct_and_union.rs index 7cabbaa73..ada2db574 100644 --- a/rs_bindings_from_cc/generate_bindings/generate_struct_and_union.rs +++ b/rs_bindings_from_cc/generate_bindings/generate_struct_and_union.rs @@ -704,7 +704,11 @@ pub fn generate_record(db: &BindingsGenerator, record: Rc) -> Result) -> Result CXXRecordDeclImporter::Import( std::optional bridge_type = GetBridgeTypeAnnotation(ictx_, *record_decl); - absl::StatusOr> owned_ptr_type = - GetAnnotationWithStringArg(*record_decl, "crubit_owned_pointee"); - if (!owned_ptr_type.ok()) { + absl::StatusOr>> args = + GetAnnotationWithStringArgs(*record_decl, "crubit_owned_pointee"); + if (!args.ok()) { return ictx_.ImportUnsupportedItem( *record_decl, std::nullopt, - FormattedError::FromStatus(std::move(owned_ptr_type).status())); + FormattedError::FromStatus(std::move(args).status())); + } + + std::optional owned_ptr_config; + + if (args->has_value()) { + const auto& args_vec = **args; + if (args_vec.empty() || args_vec.size() > 2) { + return ictx_.ImportUnsupportedItem( + *record_decl, std::nullopt, + FormattedError::Static( + "crubit_owned_pointee takes 1 or 2 arguments")); + } + + std::string owned_ptr_type = args_vec[0]; + std::string drop_impl = "DropImpl"; + + if (args_vec.size() == 2) { + drop_impl = args_vec[1]; + } + + owned_ptr_config = OwnedPtrConfig{ + .owned_ptr_type = std::move(owned_ptr_type), + .drop_impl = std::move(drop_impl), + }; } BazelLabel owning_target = ictx_.GetOwningTarget(record_decl); @@ -1195,7 +1219,7 @@ std::optional CXXRecordDeclImporter::Import( .unknown_attr = std::move(*unknown_attr), .doc_comment = std::move(doc_comment), .bridge_type = std::move(bridge_type), - .owned_ptr_type = *std::move(owned_ptr_type), + .owned_ptr_config = std::move(owned_ptr_config), .source_loc = ictx_.ConvertSourceLocation(source_loc, nullptr), .unambiguous_public_bases = GetUnambiguousPublicBases(*record_decl), .fields = ImportFields(record_decl), diff --git a/rs_bindings_from_cc/ir.cc b/rs_bindings_from_cc/ir.cc index 607fca1b5..c543c238d 100644 --- a/rs_bindings_from_cc/ir.cc +++ b/rs_bindings_from_cc/ir.cc @@ -668,6 +668,13 @@ llvm::json::Value TraitDerives::ToJson() const { }; } +llvm::json::Value OwnedPtrConfig::ToJson() const { + return llvm::json::Object{ + {"owned_ptr_type", owned_ptr_type}, + {"drop_impl", drop_impl}, + }; +} + llvm::json::Value Record::ToJson() const { std::vector json_item_ids; json_item_ids.reserve(child_item_ids.size()); @@ -686,7 +693,6 @@ llvm::json::Value Record::ToJson() const { {"unknown_attr", unknown_attr}, {"doc_comment", doc_comment}, {"bridge_type", bridge_type}, - {"owned_ptr_type", owned_ptr_type}, {"source_loc", source_loc}, {"unambiguous_public_bases", unambiguous_public_bases}, {"fields", fields}, @@ -713,6 +719,10 @@ llvm::json::Value Record::ToJson() const { {"detected_formatter", detected_formatter}, }; + if (owned_ptr_config.has_value()) { + record.insert({"owned_ptr_config", owned_ptr_config->ToJson()}); + } + if (!lifetime_inputs.empty()) { record.insert({"lifetime_inputs", lifetime_inputs}); } diff --git a/rs_bindings_from_cc/ir.h b/rs_bindings_from_cc/ir.h index 061dbca34..a0580ef9e 100644 --- a/rs_bindings_from_cc/ir.h +++ b/rs_bindings_from_cc/ir.h @@ -706,6 +706,13 @@ struct TraitDerives { std::vector custom; }; +struct OwnedPtrConfig { + llvm::json::Value ToJson() const; + + std::string owned_ptr_type; + std::string drop_impl; +}; + // A record (struct, class, union). struct Record { llvm::json::Value ToJson() const; @@ -730,7 +737,7 @@ struct Record { std::optional unknown_attr; std::optional doc_comment; std::optional bridge_type; - std::optional owned_ptr_type; + std::optional owned_ptr_config; std::string source_loc; std::vector unambiguous_public_bases; std::vector fields; diff --git a/rs_bindings_from_cc/ir.rs b/rs_bindings_from_cc/ir.rs index e081f12d5..8683fa55d 100644 --- a/rs_bindings_from_cc/ir.rs +++ b/rs_bindings_from_cc/ir.rs @@ -11,7 +11,7 @@ use code_gen_utils::make_rs_ident; use crubit_feature::CrubitFeature; use proc_macro2::{Ident, TokenStream}; use quote::{quote, ToTokens}; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use std::cell::OnceCell; use std::cmp::Ordering; use std::collections::hash_map::{Entry, HashMap}; @@ -1148,6 +1148,13 @@ pub struct TraitDerives { pub custom: Vec>, } +#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Hash)] +#[serde(deny_unknown_fields)] +pub struct OwnedPtrConfig { + pub owned_ptr_type: Rc, + pub drop_impl: Rc, +} + #[derive(Debug, PartialEq, Eq, Hash, Clone, Deserialize)] #[serde(deny_unknown_fields)] pub struct Record { @@ -1174,7 +1181,8 @@ pub struct Record { pub unknown_attr: Option>, pub doc_comment: Option>, pub bridge_type: Option, - pub owned_ptr_type: Option>, + #[serde(default)] + pub owned_ptr_config: Option, pub source_loc: Rc, pub unambiguous_public_bases: Vec, pub fields: Vec, diff --git a/rs_bindings_from_cc/ir_from_cc_test.rs b/rs_bindings_from_cc/ir_from_cc_test.rs index aa37ec749..3c86bde45 100644 --- a/rs_bindings_from_cc/ir_from_cc_test.rs +++ b/rs_bindings_from_cc/ir_from_cc_test.rs @@ -668,8 +668,8 @@ fn test_struct_with_owned_ptr_type_annotation() -> googletest::Result<()> { let record = ir.records().find(|record| record.rs_name == "RecordWithOwnedPtrType").or_fail()?; - let owned_ptr_type = &record.owned_ptr_type.clone().or_fail()?; - expect_that!(&**owned_ptr_type, eq("SomeOwnedPtrType")); + let owned_ptr_config = record.owned_ptr_config.as_ref().or_fail()?; + expect_that!(&*owned_ptr_config.owned_ptr_type, eq("SomeOwnedPtrType")); Ok(()) } diff --git a/rs_bindings_from_cc/test/annotations/owned_ptr.h b/rs_bindings_from_cc/test/annotations/owned_ptr.h index d32cf8eee..c33644d5e 100644 --- a/rs_bindings_from_cc/test/annotations/owned_ptr.h +++ b/rs_bindings_from_cc/test/annotations/owned_ptr.h @@ -21,4 +21,13 @@ struct CRUBIT_OWNED_POINTEE("OwnedThing") CRUBIT_RUST_NAME("RawThing") Thing { void Close() { delete this; } }; +// A struct that specifies a custom drop method name. +struct CRUBIT_OWNED_POINTEE("CustomOwnedThing", "CustomDropImpl") + CRUBIT_RUST_NAME("CustomRawThing") CustomThing { + explicit CustomThing(int32_t value) : value(value) {}; + int32_t value; + + void CustomDropImpl() { delete this; } +}; + #endif // THIRD_PARTY_CRUBIT_RS_BINDINGS_FROM_CC_TEST_ANNOTATIONS_OWNED_PTR_H_ diff --git a/rs_bindings_from_cc/test/annotations/owned_ptr_api_impl.cc b/rs_bindings_from_cc/test/annotations/owned_ptr_api_impl.cc index 84f091703..d691664a1 100644 --- a/rs_bindings_from_cc/test/annotations/owned_ptr_api_impl.cc +++ b/rs_bindings_from_cc/test/annotations/owned_ptr_api_impl.cc @@ -34,4 +34,20 @@ extern "C" void __rust_thunk___ZN5Thing5CloseEv(struct Thing* __this) { static_assert((void (::Thing::*)()) & ::Thing::Close); +static_assert(CRUBIT_SIZEOF(struct CustomThing) == 4); +static_assert(alignof(struct CustomThing) == 4); +static_assert(CRUBIT_OFFSET_OF(value, struct CustomThing) == 0); + +extern "C" void __rust_thunk___ZN11CustomThingC1Ei(struct CustomThing* __this, + int32_t value) { + crubit::construct_at(__this, value); +} + +extern "C" void __rust_thunk___ZN11CustomThing14CustomDropImplEv( + struct CustomThing* __this) { + __this->CustomDropImpl(); +} + +static_assert((void (::CustomThing::*)()) & ::CustomThing::CustomDropImpl); + #pragma clang diagnostic pop diff --git a/rs_bindings_from_cc/test/annotations/owned_ptr_rs_api.rs b/rs_bindings_from_cc/test/annotations/owned_ptr_rs_api.rs index 1e19b6109..60729a6d2 100644 --- a/rs_bindings_from_cc/test/annotations/owned_ptr_rs_api.rs +++ b/rs_bindings_from_cc/test/annotations/owned_ptr_rs_api.rs @@ -59,7 +59,7 @@ impl RawThing { pub struct OwnedThing(::core::ptr::NonNull); impl Drop for OwnedThing { fn drop(&mut self) { - // IMPORTANT: The DropImpl method for `{}` MUST be implemented in a user-written .rs file (e.g., using `additional_rust_srcs`). + // IMPORTANT: The drop method MUST be implemented in a user-written .rs file (e.g., using `additional_rust_srcs`). // Crubit cannot automatically generate the destruction logic for this type. // See the struct documentation for more details. self.DropImpl(); @@ -100,6 +100,87 @@ pub mod raw_thing { } } +/// A struct that specifies a custom drop method name. +/// +/// Generated from: rs_bindings_from_cc/test/annotations/owned_ptr.h;l=25 +#[derive(Clone, Copy, ::ctor::MoveAndAssignViaCopy)] +#[repr(C)] +///CRUBIT_ANNOTATE: cpp_type=CustomThing +pub struct CustomRawThing { + __non_field_data: [::core::mem::MaybeUninit; 0], + pub value: i32, +} +impl !Send for CustomRawThing {} +impl !Sync for CustomRawThing {} +unsafe impl ::cxx::ExternType for CustomRawThing { + type Id = ::cxx::type_id!("CustomThing"); + type Kind = ::cxx::kind::Trivial; +} +impl CustomRawThing { + /// # Safety + /// + /// The caller must ensure that the following unsafe arguments are not misused by the function: + /// * `__this`: raw pointer + /// + /// Generated from: rs_bindings_from_cc/test/annotations/owned_ptr.h;l=30 + #[inline(always)] + pub unsafe fn CustomDropImpl(__this: *mut Self) { + unsafe { self::custom_raw_thing::CustomDropImpl(__this) } + } +} + +// Generated due to CRUBIT_OWNED_POINTEE annotation. +///Wrapper for a C++ CustomRawThing owned by Rust. +/// +/// Style guide: The C++ type to which this refers should be wrapped in an `Arc` or `Mutex` if it is not already thread-safe. +/// +/// THIS TYPE REQUIRES A MANUAL DROP IMPLEMENTATION. +/// You MUST provide an `impl CustomOwnedThing { pub fn CustomDropImpl(&mut self) { /*...*/ } }` block in a separate Rust file (e.g., via `additional_rust_srcs`). Failure to do so will result in a compile-time error: `method not found in `CustomOwnedThing``. +#[repr(transparent)] +pub struct CustomOwnedThing(::core::ptr::NonNull); +impl Drop for CustomOwnedThing { + fn drop(&mut self) { + // IMPORTANT: The drop method MUST be implemented in a user-written .rs file (e.g., using `additional_rust_srcs`). + // Crubit cannot automatically generate the destruction logic for this type. + // See the struct documentation for more details. + self.CustomDropImpl(); + } +} + +/// Generated from: rs_bindings_from_cc/test/annotations/owned_ptr.h;l=27 +impl From for CustomRawThing { + #[inline(always)] + fn from(args: i32) -> Self { + let mut value = args; + let mut tmp = ::core::mem::MaybeUninit::::zeroed(); + unsafe { + crate::detail::__rust_thunk___ZN11CustomThingC1Ei(&raw mut tmp as *mut _, value); + tmp.assume_init() + } + } +} +impl ::ctor::CtorNew for CustomRawThing { + type CtorType = Self; + type Error = ::ctor::Infallible; + #[inline(always)] + fn ctor_new(args: i32) -> Self::CtorType { + >::from(args) + } +} + +pub mod custom_raw_thing { + /// # Safety + /// + /// The caller must ensure that the following unsafe arguments are not misused by the function: + /// * `__this`: raw pointer + /// + /// Generated from: rs_bindings_from_cc/test/annotations/owned_ptr.h;l=30 + #[inline(always)] + pub(crate) unsafe fn CustomDropImpl(__this: *mut crate::CustomRawThing) { + unsafe { crate::detail::__rust_thunk___ZN11CustomThing14CustomDropImplEv(__this) } + } +} + // Generated from: nowhere/llvm/src/libcxx/include/__type_traits/integral_constant.h;l=21 // error: struct `std::integral_constant` could not be bound // template instantiation is not yet supported @@ -122,6 +203,13 @@ mod detail { value: i32, ); pub(crate) unsafe fn __rust_thunk___ZN5Thing5CloseEv(__this: *mut crate::RawThing); + pub(crate) unsafe fn __rust_thunk___ZN11CustomThingC1Ei( + __this: *mut ::core::ffi::c_void, + value: i32, + ); + pub(crate) unsafe fn __rust_thunk___ZN11CustomThing14CustomDropImplEv( + __this: *mut crate::CustomRawThing, + ); } } @@ -131,4 +219,9 @@ const _: () = { static_assertions::assert_impl_all!(crate::RawThing: Copy,Clone); static_assertions::assert_not_impl_any!(crate::RawThing: Drop); assert!(::core::mem::offset_of!(crate::RawThing, value) == 0); + assert!(::core::mem::size_of::() == 4); + assert!(::core::mem::align_of::() == 4); + static_assertions::assert_impl_all!(crate::CustomRawThing: Copy,Clone); + static_assertions::assert_not_impl_any!(crate::CustomRawThing: Drop); + assert!(::core::mem::offset_of!(crate::CustomRawThing, value) == 0); }; diff --git a/rs_bindings_from_cc/test/annotations/owned_ptr_rust_thing.rs b/rs_bindings_from_cc/test/annotations/owned_ptr_rust_thing.rs index 6a0f7ff5d..f4895fc24 100644 --- a/rs_bindings_from_cc/test/annotations/owned_ptr_rust_thing.rs +++ b/rs_bindings_from_cc/test/annotations/owned_ptr_rust_thing.rs @@ -9,3 +9,11 @@ impl crate::OwnedThing { } } } + +impl crate::CustomOwnedThing { + pub(crate) fn CustomDropImpl(&mut self) { + unsafe { + crate::CustomRawThing::CustomDropImpl(self.0.as_mut()); + } + } +} diff --git a/rs_bindings_from_cc/test/annotations/owned_ptr_test.rs b/rs_bindings_from_cc/test/annotations/owned_ptr_test.rs index 632a0f4ed..57d7b0e7e 100644 --- a/rs_bindings_from_cc/test/annotations/owned_ptr_test.rs +++ b/rs_bindings_from_cc/test/annotations/owned_ptr_test.rs @@ -29,3 +29,8 @@ fn make_and_use_thing_with_raw_ptr() { owned_ptr::RawThing::Close(thing); } } + +#[gtest] +fn make_and_drop_custom_thing_with_owned_ptr() { + let _thing: owned_ptr::CustomOwnedThing = owned_ptr_user::MakeCustomOwnedThing(42); +} diff --git a/rs_bindings_from_cc/test/annotations/owned_ptr_user.cc b/rs_bindings_from_cc/test/annotations/owned_ptr_user.cc index a100453c2..59c430e82 100644 --- a/rs_bindings_from_cc/test/annotations/owned_ptr_user.cc +++ b/rs_bindings_from_cc/test/annotations/owned_ptr_user.cc @@ -12,6 +12,10 @@ Thing* CRUBIT_OWNED_POINTER MakeOwnedThing(int value) { return MakeThing(value); } +CustomThing* CRUBIT_OWNED_POINTER MakeCustomOwnedThing(int value) { + return new CustomThing(value); +} + int GetThingValue(Thing* thing) { return thing->value; } int ThingToValue(Thing* CRUBIT_OWNED_POINTER thing) { auto result = thing->value; diff --git a/rs_bindings_from_cc/test/annotations/owned_ptr_user.h b/rs_bindings_from_cc/test/annotations/owned_ptr_user.h index e4cab1e7f..2006eff9c 100644 --- a/rs_bindings_from_cc/test/annotations/owned_ptr_user.h +++ b/rs_bindings_from_cc/test/annotations/owned_ptr_user.h @@ -13,6 +13,8 @@ Thing* CRUBIT_OWNED_POINTER MakeOwnedThing(int value); +CustomThing* CRUBIT_OWNED_POINTER MakeCustomOwnedThing(int value); + Thing* MakeThing(int value); int ThingToValue(Thing* CRUBIT_OWNED_POINTER thingptr); diff --git a/rs_bindings_from_cc/test/annotations/owned_ptr_user_api_impl.cc b/rs_bindings_from_cc/test/annotations/owned_ptr_user_api_impl.cc index c0cbf82eb..004942a1e 100644 --- a/rs_bindings_from_cc/test/annotations/owned_ptr_user_api_impl.cc +++ b/rs_bindings_from_cc/test/annotations/owned_ptr_user_api_impl.cc @@ -21,6 +21,8 @@ static_assert((struct Thing * (*)(int)) & ::MakeOwnedThing); +static_assert((struct CustomThing * (*)(int)) & ::MakeCustomOwnedThing); + static_assert((struct Thing * (*)(int)) & ::MakeThing); static_assert((int (*)(struct Thing*)) & ::ThingToValue); diff --git a/rs_bindings_from_cc/test/annotations/owned_ptr_user_rs_api.rs b/rs_bindings_from_cc/test/annotations/owned_ptr_user_rs_api.rs index 9ac83d367..1c4608090 100644 --- a/rs_bindings_from_cc/test/annotations/owned_ptr_user_rs_api.rs +++ b/rs_bindings_from_cc/test/annotations/owned_ptr_user_rs_api.rs @@ -26,6 +26,12 @@ pub fn MakeOwnedThing(value: ::ffi_11::c_int) -> ::owned_ptr::OwnedThing { /// Generated from: rs_bindings_from_cc/test/annotations/owned_ptr_user.h;l=16 #[inline(always)] +pub fn MakeCustomOwnedThing(value: ::ffi_11::c_int) -> ::owned_ptr::CustomOwnedThing { + unsafe { ::core::mem::transmute(crate::detail::__rust_thunk___Z20MakeCustomOwnedThingi(value)) } +} + +/// Generated from: rs_bindings_from_cc/test/annotations/owned_ptr_user.h;l=18 +#[inline(always)] pub fn MakeThing(value: ::ffi_11::c_int) -> *mut ::owned_ptr::RawThing { unsafe { crate::detail::__rust_thunk___Z9MakeThingi(value) } } @@ -35,7 +41,7 @@ pub fn MakeThing(value: ::ffi_11::c_int) -> *mut ::owned_ptr::RawThing { /// The caller must ensure that the following unsafe arguments are not misused by the function: /// * `thingptr`: raw pointer /// -/// Generated from: rs_bindings_from_cc/test/annotations/owned_ptr_user.h;l=18 +/// Generated from: rs_bindings_from_cc/test/annotations/owned_ptr_user.h;l=20 #[inline(always)] pub unsafe fn ThingToValue(thingptr: ::owned_ptr::OwnedThing) -> ::ffi_11::c_int { unsafe { @@ -48,7 +54,7 @@ pub unsafe fn ThingToValue(thingptr: ::owned_ptr::OwnedThing) -> ::ffi_11::c_int /// The caller must ensure that the following unsafe arguments are not misused by the function: /// * `thingptr`: raw pointer /// -/// Generated from: rs_bindings_from_cc/test/annotations/owned_ptr_user.h;l=20 +/// Generated from: rs_bindings_from_cc/test/annotations/owned_ptr_user.h;l=22 #[inline(always)] pub unsafe fn GetThingValue(thingptr: *mut ::owned_ptr::RawThing) -> ::ffi_11::c_int { unsafe { crate::detail::__rust_thunk___Z13GetThingValueP5Thing(thingptr) } @@ -70,6 +76,10 @@ mod detail { pub(crate) unsafe fn __rust_thunk___Z14MakeOwnedThingi( value: ::ffi_11::c_int, ) -> *mut ::owned_ptr::RawThing; + #[link_name = "_Z20MakeCustomOwnedThingi"] + pub(crate) unsafe fn __rust_thunk___Z20MakeCustomOwnedThingi( + value: ::ffi_11::c_int, + ) -> *mut ::owned_ptr::CustomRawThing; #[link_name = "_Z9MakeThingi"] pub(crate) unsafe fn __rust_thunk___Z9MakeThingi( value: ::ffi_11::c_int, diff --git a/rs_bindings_from_cc/test/consume_absl/absl_functional.golden.rs b/rs_bindings_from_cc/test/consume_absl/absl_functional.golden.rs index 9a55ea741..029f4628f 100644 --- a/rs_bindings_from_cc/test/consume_absl/absl_functional.golden.rs +++ b/rs_bindings_from_cc/test/consume_absl/absl_functional.golden.rs @@ -339,27 +339,27 @@ pub fn MyOptionIntMapper() -> ::alloc::boxed::Box< // error: class `std::reverse_iterator` could not be bound // template instantiation is not yet supported -// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=35 +// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=34 // error: class `std::__wrap_iter` could not be bound // template instantiation is not yet supported -// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=35 +// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=34 // error: class `std::__wrap_iter` could not be bound // template instantiation is not yet supported -// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=35 +// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=34 // error: class `std::__wrap_iter` could not be bound // template instantiation is not yet supported -// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=35 +// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=34 // error: class `std::__wrap_iter` could not be bound // template instantiation is not yet supported -// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=35 +// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=34 // error: class `std::__wrap_iter` could not be bound // template instantiation is not yet supported -// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=35 +// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=34 // error: class `std::__wrap_iter` could not be bound // template instantiation is not yet supported diff --git a/rs_bindings_from_cc/test/display/displayables_api.rs b/rs_bindings_from_cc/test/display/displayables_api.rs index 35c50fb6d..e6212b978 100644 --- a/rs_bindings_from_cc/test/display/displayables_api.rs +++ b/rs_bindings_from_cc/test/display/displayables_api.rs @@ -692,27 +692,27 @@ impl Default for DisplayInRust { // error: class `std::reverse_iterator` could not be bound // template instantiation is not yet supported -// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=35 +// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=34 // error: class `std::__wrap_iter` could not be bound // template instantiation is not yet supported -// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=35 +// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=34 // error: class `std::__wrap_iter` could not be bound // template instantiation is not yet supported -// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=35 +// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=34 // error: class `std::__wrap_iter` could not be bound // template instantiation is not yet supported -// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=35 +// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=34 // error: class `std::__wrap_iter` could not be bound // template instantiation is not yet supported -// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=35 +// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=34 // error: class `std::__wrap_iter` could not be bound // template instantiation is not yet supported -// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=35 +// Generated from: nowhere/llvm/src/libcxx/include/__iterator/wrap_iter.h;l=34 // error: class `std::__wrap_iter` could not be bound // template instantiation is not yet supported diff --git a/support/annotations.h b/support/annotations.h index f26b47f5b..086d7c9a9 100644 --- a/support/annotations.h +++ b/support/annotations.h @@ -265,11 +265,16 @@ // This will generate a Rust struct called `WrapperTypeName` that simply // contains a pointer to the underlying object. This type will be used in // positions that are annotated with `CRUBIT_OWNED_POINTER`. +// +// You can optionally specify a custom drop method name as a second argument: +// `CRUBIT_OWNED_POINTEE("WrapperTypeName", "DropMethodName")`. If omitted, it +// defaults to `DropImpl`. #define CRUBIT_OWNED_POINTER \ CRUBIT_INTERNAL_ANNOTATE_TYPE("crubit_owned_pointer") -#define CRUBIT_OWNED_POINTEE(name) \ - CRUBIT_INTERNAL_ANNOTATE("crubit_owned_pointee", name) +#define CRUBIT_OWNED_POINTEE(name, ...) \ + CRUBIT_INTERNAL_ANNOTATE("crubit_owned_pointee", \ + name __VA_OPT__(, ) __VA_ARGS__) // Overrides the `Display` binding detection for a type to true or false. // diff --git a/support/annotations.swig b/support/annotations.swig index 0d2d9111b..6fe703d69 100644 --- a/support/annotations.swig +++ b/support/annotations.swig @@ -20,7 +20,7 @@ %enddef %define CRUBIT_DO_NOT_BIND %enddef -%define CRUBIT_OWNED_POINTEE(name) +%define CRUBIT_OWNED_POINTEE(name, ...) %enddef %define CRUBIT_OWNED_POINTER %enddef