Repository: mozilla/cbindgen (language: rust)

Issue:
Add support for UnsafeCell and SyncUnsafeCell
Support for `RefCell` has been added in #489, but `UnsafeCell` and `SyncUnsafeCell` are not supported.
Both are substantially equal to a `Cell`, so it could be implemented in the same way.


Discussion / hints:

Fix patch:
diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs
index 4a41d4cf3..2d0d692ae 100644
--- a/src/bindgen/ir/ty.rs
+++ b/src/bindgen/ir/ty.rs
@@ -559,7 +559,7 @@ impl Type {
                 is_nullable: false,
                 is_ref: false,
             }),
-            "Cell" => Some(generic.into_owned()),
+            "SyncUnsafeCell" | "UnsafeCell" | "Cell" => Some(generic.into_owned()),
             "ManuallyDrop" | "MaybeUninit" | "Pin" if config.language != Language::Cxx => {
                 Some(generic.into_owned())
             }


Test patch:
diff --git a/tests/expectations/unsafe_cell.c b/tests/expectations/unsafe_cell.c
new file mode 100644
index 000000000..a4d73f695
--- /dev/null
+++ b/tests/expectations/unsafe_cell.c
@@ -0,0 +1,14 @@
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef struct NotReprC_i32 NotReprC_i32;
+
+typedef NotReprC_i32 Foo;
+
+typedef struct {
+  int32_t number;
+} MyStruct;
+
+void root(const Foo *a, const MyStruct *with_cell);
diff --git a/tests/expectations/unsafe_cell.compat.c b/tests/expectations/unsafe_cell.compat.c
new file mode 100644
index 000000000..fc9410d46
--- /dev/null
+++ b/tests/expectations/unsafe_cell.compat.c
@@ -0,0 +1,22 @@
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef struct NotReprC_i32 NotReprC_i32;
+
+typedef NotReprC_i32 Foo;
+
+typedef struct {
+  int32_t number;
+} MyStruct;
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+void root(const Foo *a, const MyStruct *with_cell);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif  // __cplusplus
diff --git a/tests/expectations/unsafe_cell.cpp b/tests/expectations/unsafe_cell.cpp
new file mode 100644
index 000000000..d0ae403cb
--- /dev/null
+++ b/tests/expectations/unsafe_cell.cpp
@@ -0,0 +1,20 @@
+#include <cstdarg>
+#include <cstdint>
+#include <cstdlib>
+#include <ostream>
+#include <new>
+
+template<typename T = void>
+struct NotReprC;
+
+using Foo = NotReprC<int32_t>;
+
+struct MyStruct {
+  int32_t number;
+};
+
+extern "C" {
+
+void root(const Foo *a, const MyStruct *with_cell);
+
+}  // extern "C"
diff --git a/tests/expectations/unsafe_cell.pyx b/tests/expectations/unsafe_cell.pyx
new file mode 100644
index 000000000..afb1109c5
--- /dev/null
+++ b/tests/expectations/unsafe_cell.pyx
@@ -0,0 +1,17 @@
+from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t
+from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t
+cdef extern from *:
+  ctypedef bint bool
+  ctypedef struct va_list
+
+cdef extern from *:
+
+  ctypedef struct NotReprC_i32:
+    pass
+
+  ctypedef NotReprC_i32 Foo;
+
+  ctypedef struct MyStruct:
+    int32_t number;
+
+  void root(const Foo *a, const MyStruct *with_cell);
diff --git a/tests/expectations/unsafe_cell_both.c b/tests/expectations/unsafe_cell_both.c
new file mode 100644
index 000000000..61d7ce8a9
--- /dev/null
+++ b/tests/expectations/unsafe_cell_both.c
@@ -0,0 +1,14 @@
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef struct NotReprC_i32 NotReprC_i32;
+
+typedef struct NotReprC_i32 Foo;
+
+typedef struct MyStruct {
+  int32_t number;
+} MyStruct;
+
+void root(const Foo *a, const struct MyStruct *with_cell);
diff --git a/tests/expectations/unsafe_cell_both.compat.c b/tests/expectations/unsafe_cell_both.compat.c
new file mode 100644
index 000000000..0f9cd51d6
--- /dev/null
+++ b/tests/expectations/unsafe_cell_both.compat.c
@@ -0,0 +1,22 @@
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+typedef struct NotReprC_i32 NotReprC_i32;
+
+typedef struct NotReprC_i32 Foo;
+
+typedef struct MyStruct {
+  int32_t number;
+} MyStruct;
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+void root(const Foo *a, const struct MyStruct *with_cell);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif  // __cplusplus
diff --git a/tests/expectations/unsafe_cell_tag.c b/tests/expectations/unsafe_cell_tag.c
new file mode 100644
index 000000000..61c69e774
--- /dev/null
+++ b/tests/expectations/unsafe_cell_tag.c
@@ -0,0 +1,14 @@
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+struct NotReprC_i32;
+
+typedef struct NotReprC_i32 Foo;
+
+struct MyStruct {
+  int32_t number;
+};
+
+void root(const Foo *a, const struct MyStruct *with_cell);
diff --git a/tests/expectations/unsafe_cell_tag.compat.c b/tests/expectations/unsafe_cell_tag.compat.c
new file mode 100644
index 000000000..e69b5f610
--- /dev/null
+++ b/tests/expectations/unsafe_cell_tag.compat.c
@@ -0,0 +1,22 @@
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+struct NotReprC_i32;
+
+typedef struct NotReprC_i32 Foo;
+
+struct MyStruct {
+  int32_t number;
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif // __cplusplus
+
+void root(const Foo *a, const struct MyStruct *with_cell);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif  // __cplusplus
diff --git a/tests/expectations/unsafe_cell_tag.pyx b/tests/expectations/unsafe_cell_tag.pyx
new file mode 100644
index 000000000..88cd7e926
--- /dev/null
+++ b/tests/expectations/unsafe_cell_tag.pyx
@@ -0,0 +1,17 @@
+from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t
+from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t
+cdef extern from *:
+  ctypedef bint bool
+  ctypedef struct va_list
+
+cdef extern from *:
+
+  cdef struct NotReprC_i32:
+    pass
+
+  ctypedef NotReprC_i32 Foo;
+
+  cdef struct MyStruct:
+    int32_t number;
+
+  void root(const Foo *a, const MyStruct *with_cell);
diff --git a/tests/rust/unsafe_cell.rs b/tests/rust/unsafe_cell.rs
new file mode 100644
index 000000000..880dd8d1a
--- /dev/null
+++ b/tests/rust/unsafe_cell.rs
@@ -0,0 +1,11 @@
+#[repr(C)]
+pub struct MyStruct {
+    number: std::cell::UnsafeCell<i32>,
+}
+
+pub struct NotReprC<T> { inner: T }
+
+pub type Foo = NotReprC<std::cell::SyncUnsafeCell<i32>>;
+
+#[no_mangle]
+pub extern "C" fn root(a: &Foo, with_cell: &MyStruct) {}