Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions common/code_gen_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,11 +183,7 @@ fn parse_any(ident: &str) -> syn::Result<Ident> {
/// Formats a C++ (qualified) identifier. Returns an error when `ident` is a C++
/// reserved keyword or is an invalid identifier.
pub fn format_cc_ident(ident: &str) -> Result<Ident> {
ensure!(!ident.is_empty(), "Empty string is not a valid C++ identifier");
ensure!(
!is_cpp_reserved_keyword(ident),
"`{ident}` is a C++ reserved keyword and can't be used as a C++ identifier",
);
check_valid_cc_name(ident)?;
// Explicitly mapping the error via `anyhow!`, because `LexError` is not `Sync`
// (required for `anyhow::Error` to implement `From<LexError>`) and
// therefore we can't just use `?`.
Expand Down Expand Up @@ -378,12 +374,16 @@ impl NamespaceQualifier {

/// Returns `foo::bar::baz::` (reporting errors for C++ keywords).
pub fn format_for_cc(&self) -> Result<TokenStream> {
let namespace_cc_idents = self.cc_idents()?;
Ok(quote! { #(#namespace_cc_idents::)* })
}

pub fn cc_idents(&self) -> Result<Vec<Ident>> {
self.parts().map(|ns| format_cc_ident(ns)).collect()
let mut path = quote! {};
for namespace in &self.namespaces {
let namespace = format_cc_ident(namespace)?;
path.extend(quote! { #namespace :: });
}
for (rs_name, cc_name) in &self.nested_records {
let cc_name = format_cc_type_name(&cc_name)?;
path.extend(quote! { #cc_name ::});
}
Ok(path)
}
}

Expand Down
65 changes: 20 additions & 45 deletions rs_bindings_from_cc/generate_bindings/cpp_type_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,73 +111,48 @@ pub fn format_cpp_type_inner(
> #ptr
})
}
RsTypeKind::IncompleteRecord { incomplete_record, .. } => {
cpp_type_name_for_item(&Item::IncompleteRecord(Rc::clone(incomplete_record)), ir)
}
RsTypeKind::IncompleteRecord { incomplete_record, .. } => tagless_cpp_type_name_for_item(
&Item::IncompleteRecord(Rc::clone(incomplete_record)),
ir,
),
RsTypeKind::Record { record, .. } => cpp_type_name_for_record(record, ir),
RsTypeKind::Enum { enum_, .. } => cpp_type_name_for_item(&Item::Enum(Rc::clone(enum_)), ir),
RsTypeKind::Enum { enum_, .. } => {
tagless_cpp_type_name_for_item(&Item::Enum(Rc::clone(enum_)), ir)
}
RsTypeKind::TypeAlias { type_alias, .. } => {
cpp_type_name_for_item(&Item::TypeAlias(Rc::clone(type_alias)), ir)
tagless_cpp_type_name_for_item(&Item::TypeAlias(Rc::clone(type_alias)), ir)
}
RsTypeKind::Primitive(primitive) => Ok(quote! { #primitive }),
RsTypeKind::BridgeType { original_type, .. } => cpp_type_name_for_record(original_type, ir),
RsTypeKind::ExistingRustType(existing_rust_type) => {
cpp_type_name_for_item(&Item::ExistingRustType(Rc::clone(existing_rust_type)), ir)
}
RsTypeKind::ExistingRustType(existing_rust_type) => tagless_cpp_type_name_for_item(
&Item::ExistingRustType(Rc::clone(existing_rust_type)),
ir,
),
RsTypeKind::C9Co { original_type, .. } => cpp_type_name_for_record(original_type, ir),
}
}

/// Returns the fully-qualified name for an item, not including the type tag.
pub fn tagless_cpp_type_name_for_item(item: &ir::Item, ir: &IR) -> Result<TokenStream> {
if let ir::Item::Record(record) = item {
cpp_tagless_type_name_for_record(record, ir)
} else {
cpp_type_name_for_item(item, ir)
}
}

/// Returns the fully qualified name for an item.
/// Returns the fully qualified name for an item (not including type tags).
///
/// For example, for `namespace x { struct Y { using X = int; }; }`, the name
/// for `X` is `x::Y::X`.
fn cpp_type_name_for_item(item: &ir::Item, ir: &IR) -> Result<TokenStream> {
/// Returns the namespace / class qualifiers necessary to access the item.
///
/// For example, for `namespace x { struct Y { using X = int; }; }`, the prefix
/// for `X` is `x::Y::`.
fn cpp_qualified_path_prefix(item: &ir::Item, ir: &ir::IR) -> Result<TokenStream> {
let Some(parent) = item.enclosing_item_id() else {
return Ok(quote! {});
};
let parent: &ir::Item = ir.find_decl(parent)?;
match parent {
ir::Item::Namespace(_) => Ok(ir.namespace_qualifier(item).format_for_cc()?),
ir::Item::Record(r) => {
let name = cpp_tagless_type_name_for_record(r, ir)?;
Ok(quote! {#name ::})
}
_ => bail!("Unexpected enclosing item: {item:?}"),
}
}

pub fn tagless_cpp_type_name_for_item(item: &ir::Item, ir: &IR) -> Result<TokenStream> {
match item {
Item::IncompleteRecord(incomplete_record) => {
let ident = expect_format_cc_type_name(incomplete_record.cc_name.identifier.as_ref());
let namespace_qualifier = ir.namespace_qualifier(incomplete_record).format_for_cc()?;
let tag_kind = incomplete_record.record_type;
Ok(quote! { #tag_kind #namespace_qualifier #ident })
Ok(quote! { #namespace_qualifier #ident })
}
Item::Record(record) => cpp_type_name_for_record(record, ir),
Item::Record(record) => cpp_tagless_type_name_for_record(record, ir),
Item::Enum(enum_) => {
let ident = expect_format_cc_type_name(&enum_.rs_name.identifier);
let qualifier = cpp_qualified_path_prefix(item, ir)?;
Ok(quote! { #qualifier #ident })
let namespace_qualifier = ir.namespace_qualifier(item).format_for_cc()?;
Ok(quote! { #namespace_qualifier #ident })
}
Item::TypeAlias(type_alias) => {
let ident = expect_format_cc_type_name(&type_alias.cc_name.identifier);
let qualifier = cpp_qualified_path_prefix(item, ir)?;
Ok(quote! { #qualifier #ident })
let namespace_qualifier = ir.namespace_qualifier(item).format_for_cc()?;
Ok(quote! { #namespace_qualifier #ident })
}
Item::ExistingRustType(existing_rust_type) => existing_rust_type
.cc_name
Expand Down
73 changes: 25 additions & 48 deletions rs_bindings_from_cc/generate_bindings/generate_function_thunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,44 +260,32 @@ fn generate_function_assertation_for_identifier(
let ir = db.ir();

let fn_ident = expect_format_cc_ident(&id.identifier);
let path_to_func = ir.namespace_qualifier(func).format_for_cc()?;
let implementation_function = quote! { :: #path_to_func #fn_ident };
let method_qualification;
let implementation_function;
let member_function_prefix;
let func_params;
if let Some(meta) = func.member_func_metadata.as_ref() {
let record: &Rc<Record> = ir.find_decl(meta.record_id)?;
let record_ident = expect_format_cc_type_name(record.cc_name.identifier.as_ref());
let namespace_qualifier = ir.namespace_qualifier(record).format_for_cc()?;
if let Some(instance_method_metadata) = meta.instance_method_metadata.as_ref() {
let const_qualifier = if instance_method_metadata.is_const {
quote! {const}
} else {
quote! {}
};

method_qualification = match instance_method_metadata.reference {
ir::ReferenceQualification::Unqualified => const_qualifier,
ir::ReferenceQualification::LValue => {
quote! { #const_qualifier & }
}
ir::ReferenceQualification::RValue => {
quote! { #const_qualifier && }
}
};
implementation_function = quote! { #namespace_qualifier #record_ident :: #fn_ident };
member_function_prefix = quote! { :: #namespace_qualifier #record_ident :: };
// The first parameter of instance methods is `this`.
func_params = &func.params[1..];
if let Some(instance_method_metadata) = func.instance_method_metadata() {
let const_qualifier = if instance_method_metadata.is_const {
quote! {const}
} else {
method_qualification = quote! {};
implementation_function = quote! { #namespace_qualifier #record_ident :: #fn_ident };
member_function_prefix = quote! {};
func_params = &func.params[..];
}
quote! {}
};

method_qualification = match instance_method_metadata.reference {
ir::ReferenceQualification::Unqualified => const_qualifier,
ir::ReferenceQualification::LValue => {
quote! { #const_qualifier & }
}
ir::ReferenceQualification::RValue => {
quote! { #const_qualifier && }
}
};
member_function_prefix = path_to_func;
// The first parameter of instance methods is `this`.
func_params = &func.params[1..];
} else {
let namespace_qualifier = ir.namespace_qualifier(func).format_for_cc()?;
method_qualification = quote! {};
implementation_function = quote! { #namespace_qualifier #fn_ident };
member_function_prefix = quote! {};
func_params = &func.params[..];
}
Expand Down Expand Up @@ -394,22 +382,11 @@ pub fn generate_function_thunk_impl(
}
UnqualifiedIdentifier::Identifier(id) => {
let fn_ident = expect_format_cc_ident(&id.identifier);
match func.member_func_metadata.as_ref() {
Some(meta) => {
if meta.instance_method_metadata.is_some() {
quote! { #fn_ident }
} else {
let record: &Rc<Record> = ir.find_decl(meta.record_id)?;
let record_name =
expect_format_cc_type_name(record.cc_name.identifier.as_ref());
let namespace_qualifier = ir.namespace_qualifier(record).format_for_cc()?;
quote! { #namespace_qualifier #record_name :: #fn_ident }
}
}
None => {
let namespace_qualifier = ir.namespace_qualifier(func).format_for_cc()?;
quote! { #namespace_qualifier #fn_ident }
}
let namespace_qualifier = ir.namespace_qualifier(func).format_for_cc()?;
if func.instance_method_metadata().is_some() {
quote! {#fn_ident}
} else {
quote! { #namespace_qualifier #fn_ident }
}
}
// Use `destroy_at` to avoid needing to spell out the class name. Destructor identiifers
Expand Down
23 changes: 14 additions & 9 deletions rs_bindings_from_cc/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -873,7 +873,7 @@ impl GenericItem for Func {
let record: Option<Rc<str>> = ir.record_for_member_func(self).map(|r| r.debug_name(ir));
let record: Option<&str> = record.as_deref();

let func_name = match &self.rs_name {
let func_name = match &self.cc_name {
UnqualifiedIdentifier::Identifier(id) => id.identifier.to_string(),
UnqualifiedIdentifier::Operator(op) => op.cc_name(),
UnqualifiedIdentifier::Destructor => {
Expand Down Expand Up @@ -909,11 +909,16 @@ impl GenericItem for Func {
}

impl Func {
pub fn instance_method_metadata(&self) -> Option<&InstanceMethodMetadata> {
if let Some(meta) = &self.member_func_metadata {
if let Some(instance_method_metadata) = &meta.instance_method_metadata {
return Some(instance_method_metadata);
}
}
None
}
pub fn is_instance_method(&self) -> bool {
self.member_func_metadata
.as_ref()
.filter(|meta| meta.instance_method_metadata.is_some())
.is_some()
self.instance_method_metadata().is_some()
}
}

Expand Down Expand Up @@ -1326,7 +1331,7 @@ impl GenericItem for GlobalVar {
Some(self.owning_target.clone())
}
fn debug_name(&self, _: &IR) -> Rc<str> {
self.rs_name.identifier.clone()
self.cc_name.identifier.clone()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
UnsupportedItemKind::GlobalVar
Expand Down Expand Up @@ -1371,7 +1376,7 @@ impl GenericItem for Enum {
Some(self.owning_target.clone())
}
fn debug_name(&self, _: &IR) -> Rc<str> {
self.rs_name.identifier.clone()
self.cc_name.identifier.clone()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
UnsupportedItemKind::Enum
Expand Down Expand Up @@ -1420,7 +1425,7 @@ impl GenericItem for TypeAlias {
Some(self.owning_target.clone())
}
fn debug_name(&self, _: &IR) -> Rc<str> {
self.rs_name.identifier.clone()
self.cc_name.identifier.clone()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
UnsupportedItemKind::TypeAlias
Expand Down Expand Up @@ -1681,7 +1686,7 @@ impl GenericItem for Namespace {
Some(self.owning_target.clone())
}
fn debug_name(&self, _: &IR) -> Rc<str> {
self.rs_name.to_string().into()
self.cc_name.to_string().into()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
UnsupportedItemKind::Namespace
Expand Down
10 changes: 5 additions & 5 deletions rs_bindings_from_cc/test/annotations/do_not_bind_api_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ __rust_thunk___ZN6crubit4test11DoNotBindFnENS0_23ArgumentToBoundOverloadE(
crubit::test::DoNotBindFn(std::move(*__param_0));
}

static_assert((void (*)(
struct crubit::test::ArgumentToBoundOverload))&crubit::test::DoNotBindFn);
static_assert((void (*)(struct crubit::test::ArgumentToBoundOverload)) &
::crubit::test::DoNotBindFn);

static_assert(sizeof(struct crubit::test::StructWithDoNotBindConstructor) == 1);
static_assert(alignof(struct crubit::test::StructWithDoNotBindConstructor) ==
Expand Down Expand Up @@ -70,8 +70,8 @@ __rust_thunk___ZN6crubit4test25StructWithDoNotBindMethod15DoNotBindMethodENS0_23
__this->DoNotBindMethod(std::move(*__param_0));
}

static_assert((void (::crubit::test::StructWithDoNotBindMethod::*)(
struct crubit::test::ArgumentToBoundOverload))&crubit::test::
StructWithDoNotBindMethod::DoNotBindMethod);
static_assert((void (crubit::test::StructWithDoNotBindMethod::*)(
struct crubit::test::ArgumentToBoundOverload)) &
::crubit::test::StructWithDoNotBindMethod::DoNotBindMethod);

#pragma clang diagnostic pop
2 changes: 1 addition & 1 deletion rs_bindings_from_cc/test/annotations/owned_ptr_api_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ extern "C" void __rust_thunk___ZN5Thing5CloseEv(struct Thing* __this) {
__this->Close();
}

static_assert((void (::Thing::*)())&Thing::Close);
static_assert((void (Thing::*)()) & ::Thing::Close);

#pragma clang diagnostic pop
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wthread-safety-analysis"

static_assert((struct Thing * (*)(int)) & MakeOwnedThing);
static_assert((struct Thing * (*)(int)) & ::MakeOwnedThing);

static_assert((struct Thing * (*)(int)) & MakeThing);
static_assert((struct Thing * (*)(int)) & ::MakeThing);

static_assert((int (*)(struct Thing*))&ThingToValue);
static_assert((int (*)(struct Thing*)) & ::ThingToValue);

static_assert((int (*)(struct Thing*))&GetThingValue);
static_assert((int (*)(struct Thing*)) & ::GetThingValue);

#pragma clang diagnostic pop
6 changes: 3 additions & 3 deletions rs_bindings_from_cc/test/annotations/rust_name_api_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ extern "C" void __rust_thunk___ZN6crubit4test13FreeFnOldNameEv() {
crubit::test::FreeFnOldName();
}

static_assert((void (*)())&crubit::test::FreeFnOldName);
static_assert((void (*)()) & ::crubit::test::FreeFnOldName);

static_assert(sizeof(struct crubit::test::StructOldName) == 1);
static_assert(alignof(struct crubit::test::StructOldName) == 1);
Expand Down Expand Up @@ -53,7 +53,7 @@ extern "C" void __rust_thunk___ZNK6crubit4test10SomeStruct13MethodOldNameEv(
__this->MethodOldName();
}

static_assert((void (::crubit::test::SomeStruct::*)() const) &
crubit::test::SomeStruct::MethodOldName);
static_assert((void (crubit::test::SomeStruct::*)() const) &
::crubit::test::SomeStruct::MethodOldName);

#pragma clang diagnostic pop
8 changes: 4 additions & 4 deletions rs_bindings_from_cc/test/function/inline/inline_api_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ extern "C" int __rust_thunk___Z18hello_world_inlinev() {
return hello_world_inline();
}

static_assert((int (*)())&hello_world_inline);
static_assert((int (*)()) & ::hello_world_inline);

static_assert(CRUBIT_SIZEOF(struct SomeStruct) == 4);
static_assert(alignof(struct SomeStruct) == 4);
Expand All @@ -38,19 +38,19 @@ extern "C" int __rust_thunk___Z24take_struct_by_const_ptrPK10SomeStruct(
return take_struct_by_const_ptr(s);
}

static_assert((int (*)(struct SomeStruct const*))&take_struct_by_const_ptr);
static_assert((int (*)(struct SomeStruct const*)) & ::take_struct_by_const_ptr);

extern "C" unsigned int __rust_thunk___Z19double_unsigned_intj(unsigned int i) {
return double_unsigned_int(i);
}

static_assert((unsigned int (*)(unsigned int))&double_unsigned_int);
static_assert((unsigned int (*)(unsigned int)) & ::double_unsigned_int);

extern "C" int __rust_thunk___ZN10namespaced24forward_declared_doublerEi(
int x) {
return namespaced::forward_declared_doubler(x);
}

static_assert((int (*)(int))&namespaced::forward_declared_doubler);
static_assert((int (*)(int)) & ::namespaced::forward_declared_doubler);

#pragma clang diagnostic pop
Loading
Loading