Allow creation of UniquePtrs to trivial aliased types.
diff --git a/gen/src/write.rs b/gen/src/write.rs
index 5d47c63..3cd94d1 100644
--- a/gen/src/write.rs
+++ b/gen/src/write.rs
@@ -1245,7 +1245,12 @@
let instance = to_mangled(&out.namespace, ty);
let can_construct_from_value = match ty {
- Type::Ident(ident) => types.structs.contains_key(ident),
+ // Some aliases are to opaque types; some are to trivial types.
+ // We can't know at code generation time, so we generate both C++
+ // and Rust side bindings for a "new" method anyway. But that
+ // Rust code will explode at runtime if anyone tries to call it on
+ // an opaque type.
+ Type::Ident(ident) => types.structs.contains_key(ident) || types.aliases.contains_key(ident),
_ => false,
};
diff --git a/macro/src/expand.rs b/macro/src/expand.rs
index 6fa7ea7..4213b4d 100644
--- a/macro/src/expand.rs
+++ b/macro/src/expand.rs
@@ -814,13 +814,22 @@
let link_release = format!("{}release", prefix);
let link_drop = format!("{}drop", prefix);
- let new_method = if types.structs.contains_key(ident) {
+ let new_method = if types.structs.contains_key(ident) || types.aliases.contains_key(ident) {
+ let trivial_assertion: Option<syn::Stmt> = if types.aliases.contains_key(ident) {
+ Some(parse_quote! {
+ < < #ident as :: cxx :: ExternType > :: Kind as :: cxx :: kind :: Kind > :: assert_trivial();
+ })
+ } else {
+ None
+ };
+
Some(quote! {
fn __new(mut value: Self) -> *mut ::std::ffi::c_void {
extern "C" {
#[link_name = #link_new]
fn __new(this: *mut *mut ::std::ffi::c_void, value: *mut #ident);
}
+ #trivial_assertion
let mut repr = ::std::ptr::null_mut::<::std::ffi::c_void>();
unsafe { __new(&mut repr, &mut value) }
repr
diff --git a/src/extern_type.rs b/src/extern_type.rs
index b9c5386..45414c8 100644
--- a/src/extern_type.rs
+++ b/src/extern_type.rs
@@ -165,9 +165,17 @@
/// indirection.
pub enum Trivial {}
- pub trait Kind: private::Sealed {}
- impl Kind for Opaque {}
- impl Kind for Trivial {}
+ pub trait Kind: private::Sealed {
+ fn assert_trivial();
+ }
+ impl Kind for Opaque {
+ fn assert_trivial() {
+ panic!("Type not trivial");
+ }
+ }
+ impl Kind for Trivial {
+ fn assert_trivial() {}
+ }
}
mod private {
diff --git a/tests/ffi/extra.rs b/tests/ffi/extra.rs
index a809ea4..6209702 100644
--- a/tests/ffi/extra.rs
+++ b/tests/ffi/extra.rs
@@ -12,12 +12,14 @@
pub mod ffi2 {
impl UniquePtr<D> {}
impl UniquePtr<E> {}
+ impl UniquePtr<F> {}
extern "C" {
include!("tests/ffi/tests.h");
type D = crate::other::D;
type E = crate::other::E;
+ type F = crate::other::F;
fn c_take_trivial_ptr(d: UniquePtr<D>);
fn c_take_trivial_ref(d: &D);
diff --git a/tests/ffi/lib.rs b/tests/ffi/lib.rs
index 7cffded..f80cda7 100644
--- a/tests/ffi/lib.rs
+++ b/tests/ffi/lib.rs
@@ -14,15 +14,23 @@
use cxx::kind::{Opaque, Trivial};
use cxx::{type_id, CxxString, ExternType};
+ // Trivial.
#[repr(C)]
pub struct D {
- d: u64,
+ pub d: u64,
}
+ // Opaque, and has realistic complexity.
#[repr(C)]
pub struct E {
- e: u64,
e_str: CxxString,
+ e: u64,
+ }
+
+ // Opaque, but simple enough that bad code can try to create it.
+ #[repr(C)]
+ pub struct F {
+ pub f: u64,
}
unsafe impl ExternType for D {
@@ -34,6 +42,11 @@
type Id = type_id!("tests::E");
type Kind = Opaque;
}
+
+ unsafe impl ExternType for F {
+ type Id = type_id!("tests::F");
+ type Kind = Opaque;
+ }
}
#[cxx::bridge(namespace = tests)]
diff --git a/tests/ffi/tests.h b/tests/ffi/tests.h
index b3f547e..ff1fbd3 100644
--- a/tests/ffi/tests.h
+++ b/tests/ffi/tests.h
@@ -37,6 +37,10 @@
std::string e_str;
};
+struct F {
+ uint64_t f;
+};
+
enum COwnedEnum {
CVal1,
CVal2,
diff --git a/tests/test.rs b/tests/test.rs
index a9cd8e1..3ea02fa 100644
--- a/tests/test.rs
+++ b/tests/test.rs
@@ -199,6 +199,7 @@
check!(ffi2::c_take_trivial(d));
let d = ffi2::c_return_trivial_ptr();
check!(ffi2::c_take_trivial_ptr(d));
+ cxx::UniquePtr::new(ffi2::D { d: 42 });
}
#[test]
@@ -206,4 +207,7 @@
let e = ffi2::c_return_opaque_ptr();
check!(ffi2::c_take_opaque_ref(e.as_ref().unwrap()));
check!(ffi2::c_take_opaque_ptr(e));
+ assert!(std::panic::catch_unwind(|| {
+ cxx::UniquePtr::new(ffi2::F { f: 42 })
+ }).is_err());
}