Switch to build-time squashing of 'new' method.

This commit is contained in:
Adrian Taylor 2020-10-12 17:29:25 -07:00
parent 117d3baac7
commit 9f7ff2e3a6
10 changed files with 44 additions and 46 deletions

View File

@ -1247,9 +1247,9 @@ fn write_unique_ptr_common(out: &mut OutFile, ty: &Type, types: &Types) {
let can_construct_from_value = match ty {
// 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.
// and Rust side bindings for a "new" method anyway. But the Rust
// code can't be called for Opaque types because the 'new'
// method is not implemented.
Type::Ident(ident) => types.structs.contains_key(ident) || types.aliases.contains_key(ident),
_ => false,
};

View File

@ -815,21 +815,12 @@ fn expand_unique_ptr(
let link_drop = format!("{}drop", prefix);
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,17 +165,9 @@ pub mod kind {
/// indirection.
pub enum 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() {}
}
pub trait Kind: private::Sealed {}
impl Kind for Opaque {}
impl Kind for Trivial {}
}
mod private {

View File

@ -1,5 +1,7 @@
use crate::cxx_string::CxxString;
use crate::cxx_vector::{self, CxxVector, VectorElement};
use crate::ExternType;
use crate::kind::Trivial;
use core::ffi::c_void;
use core::fmt::{self, Debug, Display};
use core::marker::PhantomData;
@ -32,7 +34,9 @@ where
}
/// Allocates memory on the heap and makes a UniquePtr pointing to it.
pub fn new(value: T) -> Self {
pub fn new(value: T) -> Self
where
T: ExternType<Kind = Trivial> {
UniquePtr {
repr: T::__new(value),
ty: PhantomData,

View File

@ -12,14 +12,12 @@
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,25 +14,17 @@ mod other {
use cxx::kind::{Opaque, Trivial};
use cxx::{type_id, CxxString, ExternType};
// Trivial.
#[repr(C)]
pub struct D {
pub d: u64,
}
// Opaque, and has realistic complexity.
#[repr(C)]
pub struct E {
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 {
type Id = type_id!("tests::D");
type Kind = Trivial;
@ -42,11 +34,6 @@ 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,10 +37,6 @@ struct E {
std::string e_str;
};
struct F {
uint64_t f;
};
enum COwnedEnum {
CVal1,
CVal2,

View File

@ -207,7 +207,4 @@ 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());
}

View File

@ -0,0 +1,26 @@
mod outside {
#[repr(C)]
pub struct C {
pub a: u8,
}
unsafe impl cxx::ExternType for C {
type Id = cxx::type_id!("C");
type Kind = cxx::kind::Opaque;
}
}
#[cxx::bridge]
mod ffi {
impl UniquePtr<C> {}
extern "C" {
type C = crate::outside::C;
}
impl UniquePtr<C> {}
}
fn main() {
cxx::UniquePtr::new(outside::C { a: 4 } );
}

View File

@ -0,0 +1,7 @@
error[E0271]: type mismatch resolving `<outside::C as ExternType>::Kind == Trivial`
--> $DIR/unique_ptr_to_opaque.rs:25:5
|
25 | cxx::UniquePtr::new(outside::C { a: 4 } );
| ^^^^^^^^^^^^^^^^^^^ expected enum `Trivial`, found enum `cxx::kind::Opaque`
|
= note: required by `UniquePtr::<T>::new`