Repository: dtolnay/cxx (language: rust)

Issue:
Allow having instance methods of the same name on different types in FFI
This currently doesn't work and fails with an "error[E0428]: the name \`__by_index\` is defined multiple times" even though both the C++ and method implementation code have non-ambiguous names:

```rust
#[cxx::bridge(namespace = "mcrtlib::ffi")]
mod types {
    pub struct TypeA {
        // (...)
    }

    pub struct TypeB {
        // (...)
    }

    extern "Rust" {
        fn by_index(self: &TypeA);
        fn by_index(self: &TypeB);
    }
}
```


Discussion / hints:
Hello,

I am also having the same problem with cxx v1.0.6 and v0.5.10 - I assume cxx has never supported this before?

To reproduce the issue, I have created an example branch here:
https://github.com/david-cattermole/cxx-demo-example/tree/instance-types-and-methods-with-same-name

I have noticed running `cargo expand` produces identical function names for the methods - the struct names are not included in the function names (see below).

Example output when compiling with `cargo build`:
```
error[E0428]: the name `__get_id` is defined multiple times
 --> src\cxxbridge.rs:1:1
  |
1 | #[cxx::bridge(namespace = mmscenegraph)]
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  | |
  | `__get_id` redefined here
  | previous definition of the value `__get_id` here
  |
  = note: `__get_id` must be defined only once in the value namespace of this block
  = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
```

Example (edited) output from `rustup run nightly cargo expand`:
```rust
#[doc(hidden)]
const _: () = {
    #[doc(hidden)]
    #[export_name = "mmscenegraph$cxxbridge1$ReadOperation$get_id"]
    unsafe extern "C" fn __get_id(__self: &ReadOperation) -> u8 {
        let __fn = "mmscenegraph_rs::cxxbridge::ffi::get_id";
        fn __get_id(__self: &ReadOperation) -> u8 {
            ReadOperation::get_id(__self)
        }
        ::cxx::private::catch_unwind(__fn, move || __get_id(__self))
    }
    #[doc(hidden)]
    #[export_name = "mmscenegraph$cxxbridge1$WriteOperation$get_id"]
    unsafe extern "C" fn __get_id(__self: &WriteOperation) -> u8 {
        let __fn = "mmscenegraph_rs::cxxbridge::ffi::get_id";
        fn __get_id(__self: &WriteOperation) -> u8 {
            WriteOperation::get_id(__self)
        }
        ::cxx::private::catch_unwind(__fn, move || __get_id(__self))
    }
};
```

Thank you,
David
Hi @dtolnay,

I have a fix for this issue with my commit here: https://github.com/dtolnay/cxx/commit/a64bfd92fd7abee9b6c40a10ba5dcd19974761d6

My fix is to prefix the generated Rust function name with the struct name. I end up with the below expanded function names for two structs `ReadOperation` and `WriteOperation` that have the same method name `get_id`.

My test functions in my [example project branch](https://github.com/david-cattermole/cxx-demo-example/tree/instance-types-and-methods-with-same-name) now work using this new commit.

# Before
```rust
#[doc(hidden)]
#[export_name = "mmscenegraph$cxxbridge1$ReadOperation$get_id"]
unsafe extern "C" fn __get_id(__self: &ReadOperation) -> u8 {
    let __fn = "mmscenegraph_rs::cxxbridge::ffi::get_id";
    fn __get_id(__self: &ReadOperation) -> u8 {
        ReadOperation::get_id(__self)
    }
    ::cxx::private::catch_unwind(__fn, move || __get_id(__self))
}
#[doc(hidden)]
#[export_name = "mmscenegraph$cxxbridge1$WriteOperation$get_id"]
unsafe extern "C" fn __get_id(__self: &WriteOperation) -> u8 {
    let __fn = "mmscenegraph_rs::cxxbridge::ffi::get_id";
    fn __get_id(__self: &WriteOperation) -> u8 {
        WriteOperation::get_id(__self)
    }
    ::cxx::private::catch_unwind(__fn, move || __get_id(__self))
}
```

# After
```rust
#[doc(hidden)]
#[export_name = "mmscenegraph$cxxbridge1$ReadOperation$get_id"]
unsafe extern "C" fn __ReadOperation_get_id(__self: &ReadOperation) -> u8 {
    let __fn = "mmscenegraph_rs::cxxbridge::ffi::get_id";
    fn __ReadOperation_get_id(__self: &ReadOperation) -> u8 {
        ReadOperation::get_id(__self)
    }
    ::cxx::private::catch_unwind(__fn, move || __ReadOperation_get_id(__self))
}
#[doc(hidden)]
#[export_name = "mmscenegraph$cxxbridge1$WriteOperation$get_id"]
unsafe extern "C" fn __WriteOperation_get_id(__self: &WriteOperation) -> u8 {
    let __fn = "mmscenegraph_rs::cxxbridge::ffi::get_id";
    fn __WriteOperation_get_id(__self: &WriteOperation) -> u8 {
        WriteOperation::get_id(__self)
    }
    ::cxx::private::catch_unwind(__fn, move || __WriteOperation_get_id(__self))
}
```

Fix patch:
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index ae13beb65..63fe888fe 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -665,8 +665,14 @@ fn expand_rust_type_assert_sized(ety: &ExternType) -> TokenStream {
 
 fn expand_rust_function_shim(efn: &ExternFn, types: &Types) -> TokenStream {
     let link_name = mangle::extern_fn(efn, types);
-    let local_name = format_ident!("__{}", efn.name.rust);
-    let catch_unwind_label = format!("::{}", efn.name.rust);
+    let local_name = match &efn.receiver {
+        None => format_ident!("__{}", efn.name.rust),
+        Some(receiver) => format_ident!("__{}__{}", receiver.ty.rust, efn.name.rust),
+    };
+    let catch_unwind_label = match &efn.receiver {
+        None => format!("::{}", efn.name.rust),
+        Some(receiver) => format!("::{}::{}", receiver.ty.rust, efn.name.rust),
+    };
     let invoke = Some(&efn.name.rust);
     expand_rust_function_shim_impl(
         efn,


Test patch: