Repository: dtolnay/cxx (language: rust)

Issue:
Pinning and mut
Hi!

I'm trying to refactor my Skia bindings to use cxx.
A `Surface` (`SkSurface`) has an associated `Canvas` (`SkCanvas`) that I'm trying to return.

Here's a sample with some stuff omitted:

```rust
unsafe extern "C++" {
    type Canvas;
    type Surface;

    fn canvas(self: Pin<&mut Surface>) -> Pin<&mut Canvas>;
}
```

When building I get: `&mut return type is not allowed unless there is a &mut argument`

Maybe I'm missing something obvious, but I can't find anything in docs.

Thanks,
Christer


Discussion / hints:
I think adding this:

```rust
if let Some(ref r) = efn.receiver {
    if r.mutable {
        return;
    }
}
```

before https://github.com/dtolnay/cxx/blob/83cbe894dcf6605ab3ad44ca851476b6e3e7dcf1/syntax/check.rs#L467 would work.

Fix patch:
diff --git a/syntax/check.rs b/syntax/check.rs
index 3b7b51365..03b472462 100644
--- a/syntax/check.rs
+++ b/syntax/check.rs
@@ -464,6 +464,12 @@ fn check_mut_return_restriction(cx: &mut Check, efn: &ExternFn) {
         _ => return,
     }
 
+    if let Some(r) = &efn.receiver {
+        if r.mutable {
+            return;
+        }
+    }
+
     for arg in &efn.args {
         if let Type::Ref(ty) = &arg.ty {
             if ty.mutable {


Test patch:
diff --git a/tests/ffi/lib.rs b/tests/ffi/lib.rs
index d6be09796..2c065d927 100644
--- a/tests/ffi/lib.rs
+++ b/tests/ffi/lib.rs
@@ -165,9 +165,13 @@ pub mod ffi {
         fn get(self: &C) -> usize;
         fn set(self: Pin<&mut C>, n: usize) -> usize;
         fn get2(&self) -> usize;
+        fn getRef(self: &C) -> &usize;
+        fn getMut(self: Pin<&mut C>) -> &mut usize;
         fn set_succeed(self: Pin<&mut C>, n: usize) -> Result<usize>;
         fn get_fail(self: Pin<&mut C>) -> Result<usize>;
         fn c_method_on_shared(self: &Shared) -> usize;
+        fn c_method_ref_on_shared(self: &Shared) -> &usize;
+        fn c_method_mut_on_shared(self: &mut Shared) -> &mut usize;
         fn c_set_array(self: &mut Array, value: i32);
 
         #[rust_name = "i32_overloaded_method"]
diff --git a/tests/ffi/tests.cc b/tests/ffi/tests.cc
index 2834801a9..eeca98a5e 100644
--- a/tests/ffi/tests.cc
+++ b/tests/ffi/tests.cc
@@ -22,6 +22,10 @@ size_t C::get() const { return this->n; }
 
 size_t C::get2() const { return this->n; }
 
+const size_t &C::getRef() const { return this->n; }
+
+size_t &C::getMut() { return this->n; }
+
 size_t C::set(size_t n) {
   this->n = n;
   return this->n;
@@ -33,6 +37,12 @@ size_t C::get_fail() { throw std::runtime_error("unimplemented"); }
 
 size_t Shared::c_method_on_shared() const noexcept { return 2021; }
 
+const size_t &Shared::c_method_ref_on_shared() const noexcept {
+  return this->z;
+}
+
+size_t &Shared::c_method_mut_on_shared() noexcept { return this->z; }
+
 void Array::c_set_array(int32_t val) noexcept {
   this->a = {val, val, val, val};
 }
diff --git a/tests/ffi/tests.h b/tests/ffi/tests.h
index 024ecead4..355406da4 100644
--- a/tests/ffi/tests.h
+++ b/tests/ffi/tests.h
@@ -45,6 +45,8 @@ class C {
   size_t get() const;
   size_t set(size_t n);
   size_t get2() const;
+  const size_t &getRef() const;
+  size_t &getMut();
   size_t set_succeed(size_t n);
   size_t get_fail();
   const std::vector<uint8_t> &get_v() const;
diff --git a/tests/test.rs b/tests/test.rs
index 00a7228ba..165ae50b9 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -210,9 +210,13 @@ fn test_c_method_calls() {
     assert_eq!(2021, unique_ptr.pin_mut().set(2021));
     assert_eq!(2021, unique_ptr.get());
     assert_eq!(2021, unique_ptr.get2());
+    assert_eq!(2021, *unique_ptr.getRef());
+    assert_eq!(2021, *unique_ptr.pin_mut().getMut());
     assert_eq!(2022, unique_ptr.pin_mut().set_succeed(2022).unwrap());
     assert!(unique_ptr.pin_mut().get_fail().is_err());
     assert_eq!(2021, ffi::Shared { z: 0 }.c_method_on_shared());
+    assert_eq!(2022, *ffi::Shared { z: 2022 }.c_method_ref_on_shared());
+    assert_eq!(2023, *ffi::Shared { z: 2023 }.c_method_mut_on_shared());
 
     let val = 42;
     let mut array = ffi::Array { a: [0, 0, 0, 0] };