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: 18 additions & 4 deletions common/code_gen_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -378,12 +378,26 @@ 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::)* })
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)
}

pub fn cc_idents(&self) -> Result<Vec<Ident>> {
self.parts().map(|ns| format_cc_ident(ns)).collect()
/// Returns `foo::bar::baz::` (never reporting errors).
pub fn format_for_cc_debug(&self) -> String {
let mut path = String::new();
for part in self.parts() {
path.push_str(part);
path.push_str("::");
}
path
}
}

Expand Down
23 changes: 2 additions & 21 deletions rs_bindings_from_cc/generate_bindings/cpp_type_name.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,25 +137,6 @@ pub fn format_cpp_type_inner(
/// For example, for `namespace x { struct Y { using X = int; }; }`, the name
/// for `X` is `x::Y::X`.
pub fn tagless_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:?}"),
}
}

match item {
Item::IncompleteRecord(incomplete_record) => {
let ident = expect_format_cc_type_name(incomplete_record.cc_name.identifier.as_ref());
Expand All @@ -165,12 +146,12 @@ pub fn tagless_cpp_type_name_for_item(item: &ir::Item, ir: &IR) -> Result<TokenS
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 namespace_qualifier = cpp_qualified_path_prefix(item, ir)?;
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 namespace_qualifier = cpp_qualified_path_prefix(item, ir)?;
let namespace_qualifier = ir.namespace_qualifier(item).format_for_cc()?;
Ok(quote! { #namespace_qualifier #ident })
}
Item::ExistingRustType(existing_rust_type) => existing_rust_type
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
88 changes: 55 additions & 33 deletions rs_bindings_from_cc/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -870,25 +870,35 @@ impl GenericItem for Func {
Some(self.owning_target.clone())
}
fn debug_name(&self, ir: &IR) -> Rc<str> {
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 mut name = ir.namespace_qualifier(self).format_for_cc_debug();
let record_name = || -> Option<Rc<str>> {
let record = ir.record_for_member_func(self)?;
if let Item::Record(r) = record {
Some(r.cc_name.identifier.clone())
} else {
None
}
};

let func_name = match &self.rs_name {
UnqualifiedIdentifier::Identifier(id) => id.identifier.to_string(),
UnqualifiedIdentifier::Operator(op) => op.cc_name(),
match &self.cc_name {
UnqualifiedIdentifier::Identifier(id) => {
name.push_str(&id.identifier);
}
UnqualifiedIdentifier::Operator(op) => {
name.push_str(&op.cc_name());
}
UnqualifiedIdentifier::Destructor => {
format!("~{}", record.expect("destructor must be associated with a record"))
name.push('~');
name.push_str(&record_name().expect("destructor must be associated with a record"));
}
UnqualifiedIdentifier::Constructor => {
record.expect("constructor must be associated with a record").to_string()
name.push_str(
&record_name().expect("constructor must be associated with a record"),
);
}
};

if let Some(record_name) = record {
format!("{}::{}", record_name, func_name).into()
} else {
func_name.into()
}

name.into()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
if self.cc_name == UnqualifiedIdentifier::Constructor {
Expand All @@ -909,11 +919,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 @@ -987,8 +1002,9 @@ impl GenericItem for IncompleteRecord {
fn owning_target(&self) -> Option<BazelLabel> {
Some(self.owning_target.clone())
}
fn debug_name(&self, _: &IR) -> Rc<str> {
self.cc_name.identifier.clone()
fn debug_name(&self, ir: &IR) -> Rc<str> {
format!("{}{}", ir.namespace_qualifier(self).format_for_cc_debug(), self.cc_name.identifier)
.into()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
self.record_type.unsupported_item_kind()
Expand Down Expand Up @@ -1176,8 +1192,9 @@ impl GenericItem for Record {
fn owning_target(&self) -> Option<BazelLabel> {
Some(self.owning_target.clone())
}
fn debug_name(&self, _: &IR) -> Rc<str> {
self.cc_name.identifier.clone()
fn debug_name(&self, ir: &IR) -> Rc<str> {
format!("{}{}", ir.namespace_qualifier(self).format_for_cc_debug(), self.cc_name.identifier)
.into()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
self.record_type.unsupported_item_kind()
Expand Down Expand Up @@ -1325,8 +1342,9 @@ impl GenericItem for GlobalVar {
fn owning_target(&self) -> Option<BazelLabel> {
Some(self.owning_target.clone())
}
fn debug_name(&self, _: &IR) -> Rc<str> {
self.rs_name.identifier.clone()
fn debug_name(&self, ir: &IR) -> Rc<str> {
format!("{}{}", ir.namespace_qualifier(self).format_for_cc_debug(), self.cc_name.identifier)
.into()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
UnsupportedItemKind::GlobalVar
Expand Down Expand Up @@ -1370,8 +1388,9 @@ impl GenericItem for Enum {
fn owning_target(&self) -> Option<BazelLabel> {
Some(self.owning_target.clone())
}
fn debug_name(&self, _: &IR) -> Rc<str> {
self.rs_name.identifier.clone()
fn debug_name(&self, ir: &IR) -> Rc<str> {
format!("{}{}", ir.namespace_qualifier(self).format_for_cc_debug(), self.cc_name.identifier)
.into()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
UnsupportedItemKind::Enum
Expand Down Expand Up @@ -1419,8 +1438,9 @@ impl GenericItem for TypeAlias {
fn owning_target(&self) -> Option<BazelLabel> {
Some(self.owning_target.clone())
}
fn debug_name(&self, _: &IR) -> Rc<str> {
self.rs_name.identifier.clone()
fn debug_name(&self, ir: &IR) -> Rc<str> {
format!("{}{}", ir.namespace_qualifier(self).format_for_cc_debug(), self.cc_name.identifier)
.into()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
UnsupportedItemKind::TypeAlias
Expand Down Expand Up @@ -1546,6 +1566,7 @@ impl GenericItem for UnsupportedItem {
None
}
fn debug_name(&self, _: &IR) -> Rc<str> {
// Note: name is supposed to be populated with the `debug_name()` of the unsupported item.
self.name.clone()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
Expand Down Expand Up @@ -1640,7 +1661,7 @@ impl GenericItem for Comment {
None
}
fn debug_name(&self, _: &IR) -> Rc<str> {
"comment".into()
"<comment>".into()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
UnsupportedItemKind::Other
Expand Down Expand Up @@ -1680,8 +1701,9 @@ impl GenericItem for Namespace {
fn owning_target(&self) -> Option<BazelLabel> {
Some(self.owning_target.clone())
}
fn debug_name(&self, _: &IR) -> Rc<str> {
self.rs_name.to_string().into()
fn debug_name(&self, ir: &IR) -> Rc<str> {
format!("{}{}", ir.namespace_qualifier(self).format_for_cc_debug(), self.cc_name.identifier)
.into()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
UnsupportedItemKind::Namespace
Expand Down Expand Up @@ -1714,7 +1736,7 @@ impl GenericItem for UseMod {
None
}
fn debug_name(&self, _: &IR) -> Rc<str> {
format!("[internal] use mod {}::* = {}", self.mod_name, self.path).into()
format!("<[internal] use mod {}::* = {}>", self.mod_name, self.path).into()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
UnsupportedItemKind::Other
Expand Down Expand Up @@ -1750,8 +1772,8 @@ impl GenericItem for ExistingRustType {
fn owning_target(&self) -> Option<BazelLabel> {
Some(self.owning_target.clone())
}
fn debug_name(&self, _: &IR) -> Rc<str> {
self.cc_name.clone()
fn debug_name(&self, ir: &IR) -> Rc<str> {
format!("{}{}", ir.namespace_qualifier(self).format_for_cc_debug(), self.cc_name).into()
}
fn unsupported_kind(&self) -> UnsupportedItemKind {
UnsupportedItemKind::Other
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
Loading