Allow creation of UniquePtrs to trivial aliased types.

This commit is contained in:
Adrian Taylor 2020-10-12 15:54:54 -07:00
parent e35673d7de
commit d75f7e2911
7 changed files with 52 additions and 7 deletions

View File

@ -1245,7 +1245,12 @@ fn write_unique_ptr_common(out: &mut OutFile, ty: &Type, types: &Types) {
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,
};

View File

@ -814,13 +814,22 @@ fn expand_unique_ptr(
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

View File

@ -165,9 +165,17 @@ pub mod kind {
/// 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 {

View File

@ -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);

View File

@ -14,15 +14,23 @@ mod other {
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 @@ mod other {
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)]

View File

@ -37,6 +37,10 @@ struct E {
std::string e_str;
};
struct F {
uint64_t f;
};
enum COwnedEnum {
CVal1,
CVal2,

View File

@ -199,6 +199,7 @@ fn test_extern_trivial() {
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 @@ fn test_extern_opaque() {
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());
}