mirror of
https://gitee.com/openharmony/third_party_rust_cxx
synced 2024-11-23 07:10:29 +00:00
Support raw pointers in cxx::bridge.
This allows raw pointers to types to be passed into and out of cxx::bridge extern "C++" APIs. As normal with raw pointers in Rust, there are no safety or lifetime guarantees. Passing a raw pointer into such an API requires that the function be marked "unsafe".
This commit is contained in:
parent
2029c873c2
commit
38ae228834
@ -222,7 +222,7 @@ fn pick_includes_and_builtins(out: &mut OutFile, apis: &[Api]) {
|
||||
Type::Fn(_) => out.builtin.rust_fn = true,
|
||||
Type::SliceRef(_) => out.builtin.rust_slice = true,
|
||||
Type::Array(_) => out.include.array = true,
|
||||
Type::Ref(_) | Type::Void(_) => {}
|
||||
Type::Ref(_) | Type::Void(_) | Type::Ptr(_) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1179,6 +1179,13 @@ fn write_type(out: &mut OutFile, ty: &Type) {
|
||||
write_type(out, &r.inner);
|
||||
write!(out, " &");
|
||||
}
|
||||
Type::Ptr(p) => {
|
||||
if !p.mutable {
|
||||
write!(out, "const ");
|
||||
}
|
||||
write_type(out, &p.inner);
|
||||
write!(out, " *");
|
||||
}
|
||||
Type::Str(_) => {
|
||||
write!(out, "::rust::Str");
|
||||
}
|
||||
@ -1253,7 +1260,7 @@ fn write_space_after_type(out: &mut OutFile, ty: &Type) {
|
||||
| Type::SliceRef(_)
|
||||
| Type::Fn(_)
|
||||
| Type::Array(_) => write!(out, " "),
|
||||
Type::Ref(_) => {}
|
||||
Type::Ref(_) | Type::Ptr(_) => {}
|
||||
Type::Void(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,8 @@ use proc_macro2::{Delimiter, Group, Ident, TokenStream};
|
||||
use quote::{quote, ToTokens};
|
||||
use std::fmt::Display;
|
||||
|
||||
use super::Ptr;
|
||||
|
||||
pub(crate) struct Check<'a> {
|
||||
apis: &'a [Api],
|
||||
types: &'a Types<'a>,
|
||||
@ -35,6 +37,7 @@ fn do_typecheck(cx: &mut Check) {
|
||||
Type::WeakPtr(ptr) => check_type_weak_ptr(cx, ptr),
|
||||
Type::CxxVector(ptr) => check_type_cxx_vector(cx, ptr),
|
||||
Type::Ref(ty) => check_type_ref(cx, ty),
|
||||
Type::Ptr(ty) => check_type_ptr(cx, ty),
|
||||
Type::Array(array) => check_type_array(cx, array),
|
||||
Type::Fn(ty) => check_type_fn(cx, ty),
|
||||
Type::SliceRef(ty) => check_type_slice_ref(cx, ty),
|
||||
@ -221,7 +224,7 @@ fn check_type_ref(cx: &mut Check, ty: &Ref) {
|
||||
}
|
||||
|
||||
match ty.inner {
|
||||
Type::Fn(_) | Type::Void(_) => {}
|
||||
Type::Fn(_) | Type::Void(_) | Type::Ptr(_) => {}
|
||||
Type::Ref(_) => {
|
||||
cx.error(ty, "C++ does not allow references to references");
|
||||
return;
|
||||
@ -232,6 +235,12 @@ fn check_type_ref(cx: &mut Check, ty: &Ref) {
|
||||
cx.error(ty, "unsupported reference type");
|
||||
}
|
||||
|
||||
fn check_type_ptr(cx: &mut Check, ty: &Ptr) {
|
||||
if let Type::Ident(_) = ty.inner { return }
|
||||
|
||||
cx.error(ty, "unsupported pointer type");
|
||||
}
|
||||
|
||||
fn check_type_slice_ref(cx: &mut Check, ty: &SliceRef) {
|
||||
let supported = !is_unsized(cx, &ty.inner)
|
||||
|| match &ty.inner {
|
||||
@ -555,6 +564,7 @@ fn is_unsized(cx: &mut Check, ty: &Type) -> bool {
|
||||
| Type::SharedPtr(_)
|
||||
| Type::WeakPtr(_)
|
||||
| Type::Ref(_)
|
||||
| Type::Ptr(_)
|
||||
| Type::Str(_)
|
||||
| Type::SliceRef(_) => false,
|
||||
}
|
||||
@ -628,6 +638,7 @@ fn describe(cx: &mut Check, ty: &Type) -> String {
|
||||
Type::SharedPtr(_) => "shared_ptr".to_owned(),
|
||||
Type::WeakPtr(_) => "weak_ptr".to_owned(),
|
||||
Type::Ref(_) => "reference".to_owned(),
|
||||
Type::Ptr(_) => "raw pointer".to_owned(),
|
||||
Type::Str(_) => "&str".to_owned(),
|
||||
Type::CxxVector(_) => "C++ vector".to_owned(),
|
||||
Type::SliceRef(_) => "slice".to_owned(),
|
||||
|
@ -5,6 +5,8 @@ use std::hash::{Hash, Hasher};
|
||||
use std::mem;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use super::Ptr;
|
||||
|
||||
impl PartialEq for Include {
|
||||
fn eq(&self, other: &Include) -> bool {
|
||||
let Include {
|
||||
@ -47,6 +49,7 @@ impl Hash for Type {
|
||||
Type::SharedPtr(t) => t.hash(state),
|
||||
Type::WeakPtr(t) => t.hash(state),
|
||||
Type::Ref(t) => t.hash(state),
|
||||
Type::Ptr(t) => t.hash(state),
|
||||
Type::Str(t) => t.hash(state),
|
||||
Type::RustVec(t) => t.hash(state),
|
||||
Type::CxxVector(t) => t.hash(state),
|
||||
@ -189,6 +192,42 @@ impl Hash for Ref {
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Ptr {}
|
||||
|
||||
impl PartialEq for Ptr {
|
||||
fn eq(&self, other: &Ptr) -> bool {
|
||||
let Ptr {
|
||||
star: _,
|
||||
mutable,
|
||||
inner,
|
||||
mutability: _,
|
||||
constness: _,
|
||||
} = self;
|
||||
let Ptr {
|
||||
star: _,
|
||||
mutable: mutable2,
|
||||
inner: inner2,
|
||||
mutability: _,
|
||||
constness: _,
|
||||
} = other;
|
||||
mutable == mutable2 && inner == inner2
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Ptr {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
let Ptr {
|
||||
star: _,
|
||||
mutable,
|
||||
inner,
|
||||
mutability: _,
|
||||
constness: _,
|
||||
} = self;
|
||||
mutable.hash(state);
|
||||
inner.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for SliceRef {}
|
||||
|
||||
impl PartialEq for SliceRef {
|
||||
|
@ -32,6 +32,7 @@ impl<'a> Types<'a> {
|
||||
Definite(false)
|
||||
}
|
||||
Type::Ref(ty) => self.determine_improper_ctype(&ty.inner),
|
||||
Type::Ptr(ty) => self.determine_improper_ctype(&ty.inner),
|
||||
Type::Array(ty) => self.determine_improper_ctype(&ty.inner),
|
||||
}
|
||||
}
|
||||
|
@ -204,6 +204,7 @@ pub enum Type {
|
||||
SharedPtr(Box<Ty1>),
|
||||
WeakPtr(Box<Ty1>),
|
||||
Ref(Box<Ref>),
|
||||
Ptr(Box<Ptr>),
|
||||
Str(Box<Ref>),
|
||||
CxxVector(Box<Ty1>),
|
||||
Fn(Box<Signature>),
|
||||
@ -229,6 +230,14 @@ pub struct Ref {
|
||||
pub mutability: Option<Token![mut]>,
|
||||
}
|
||||
|
||||
pub struct Ptr {
|
||||
pub star: Token![*],
|
||||
pub mutable: bool,
|
||||
pub inner: Type,
|
||||
pub mutability: Option<Token![mut]>,
|
||||
pub constness: Option<Token![const]>,
|
||||
}
|
||||
|
||||
pub struct SliceRef {
|
||||
pub ampersand: Token![&],
|
||||
pub lifetime: Option<Lifetime>,
|
||||
|
@ -11,7 +11,7 @@ use crate::syntax::{
|
||||
use proc_macro2::{Delimiter, Group, Span, TokenStream, TokenTree};
|
||||
use quote::{format_ident, quote, quote_spanned};
|
||||
use std::mem;
|
||||
use syn::parse::{ParseStream, Parser};
|
||||
use syn::{TypePtr, parse::{ParseStream, Parser}};
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::{
|
||||
Abi, Attribute, Error, Expr, Fields, FnArg, ForeignItem, ForeignItemFn, ForeignItemType,
|
||||
@ -21,6 +21,8 @@ use syn::{
|
||||
TypeReference, Variant as RustVariant, Visibility,
|
||||
};
|
||||
|
||||
use super::Ptr;
|
||||
|
||||
pub mod kw {
|
||||
syn::custom_keyword!(Pin);
|
||||
syn::custom_keyword!(Result);
|
||||
@ -547,6 +549,7 @@ fn parse_extern_fn(
|
||||
));
|
||||
}
|
||||
|
||||
let unsafety = foreign_fn.sig.unsafety;
|
||||
let mut receiver = None;
|
||||
let mut args = Punctuated::new();
|
||||
for arg in foreign_fn.sig.inputs.pairs() {
|
||||
@ -583,6 +586,11 @@ fn parse_extern_fn(
|
||||
let attrs = OtherAttrs::none();
|
||||
let visibility = Token![pub](ident.span());
|
||||
let name = pair(Namespace::default(), &ident, None, None);
|
||||
if let Type::Ptr(_) = &ty {
|
||||
if unsafety.is_none() {
|
||||
return Err(Error::new_spanned(arg, "pointer argument requires that the function be marked unsafe"));
|
||||
}
|
||||
}
|
||||
args.push_value(Var {
|
||||
doc,
|
||||
attrs,
|
||||
@ -620,7 +628,6 @@ fn parse_extern_fn(
|
||||
let ret = parse_return_type(&foreign_fn.sig.output, &mut throws_tokens)?;
|
||||
let throws = throws_tokens.is_some();
|
||||
let visibility = visibility_pub(&foreign_fn.vis, &foreign_fn.sig.ident);
|
||||
let unsafety = foreign_fn.sig.unsafety;
|
||||
let fn_token = foreign_fn.sig.fn_token;
|
||||
let name = pair(namespace, &foreign_fn.sig.ident, cxx_name, rust_name);
|
||||
let generics = generics.clone();
|
||||
@ -965,6 +972,7 @@ fn parse_impl(imp: ItemImpl) -> Result<Api> {
|
||||
},
|
||||
Type::Ident(_)
|
||||
| Type::Ref(_)
|
||||
| Type::Ptr(_)
|
||||
| Type::Str(_)
|
||||
| Type::Fn(_)
|
||||
| Type::Void(_)
|
||||
@ -1033,6 +1041,7 @@ fn parse_include(input: ParseStream) -> Result<Include> {
|
||||
fn parse_type(ty: &RustType) -> Result<Type> {
|
||||
match ty {
|
||||
RustType::Reference(ty) => parse_type_reference(ty),
|
||||
RustType::Ptr(ty) => parse_type_ptr(ty),
|
||||
RustType::Path(ty) => parse_type_path(ty),
|
||||
RustType::Array(ty) => parse_type_array(ty),
|
||||
RustType::BareFn(ty) => parse_type_fn(ty),
|
||||
@ -1084,6 +1093,26 @@ fn parse_type_reference(ty: &TypeReference) -> Result<Type> {
|
||||
})))
|
||||
}
|
||||
|
||||
fn parse_type_ptr(ty: &TypePtr) -> Result<Type> {
|
||||
let star = ty.star_token;
|
||||
let mutable = ty.mutability.is_some();
|
||||
let constness = ty.const_token;
|
||||
let mutability = ty.mutability;
|
||||
if !constness.is_some() && !mutable {
|
||||
return Err(Error::new_spanned(ty, "pointer is neither const nor mut"));
|
||||
}
|
||||
|
||||
let inner = parse_type(&ty.elem)?;
|
||||
|
||||
Ok(Type::Ptr(Box::new(Ptr {
|
||||
star,
|
||||
mutable,
|
||||
inner,
|
||||
mutability,
|
||||
constness,
|
||||
})))
|
||||
}
|
||||
|
||||
fn parse_type_path(ty: &TypePath) -> Result<Type> {
|
||||
let path = &ty.path;
|
||||
if ty.qself.is_none() && path.leading_colon.is_none() && path.segments.len() == 1 {
|
||||
|
@ -29,7 +29,7 @@ impl<'a> Types<'a> {
|
||||
| Type::WeakPtr(_)
|
||||
| Type::CxxVector(_)
|
||||
| Type::Void(_) => false,
|
||||
Type::Ref(_) | Type::Str(_) | Type::Fn(_) | Type::SliceRef(_) => true,
|
||||
Type::Ref(_) | Type::Str(_) | Type::Fn(_) | Type::SliceRef(_) | Type::Ptr(_) => true,
|
||||
Type::Array(array) => self.is_guaranteed_pod(&array.inner),
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,8 @@ use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{quote_spanned, ToTokens};
|
||||
use syn::{token, Token};
|
||||
|
||||
use super::Ptr;
|
||||
|
||||
impl ToTokens for Type {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
match self {
|
||||
@ -27,6 +29,7 @@ impl ToTokens for Type {
|
||||
| Type::CxxVector(ty)
|
||||
| Type::RustVec(ty) => ty.to_tokens(tokens),
|
||||
Type::Ref(r) | Type::Str(r) => r.to_tokens(tokens),
|
||||
Type::Ptr(p) => p.to_tokens(tokens),
|
||||
Type::Array(a) => a.to_tokens(tokens),
|
||||
Type::Fn(f) => f.to_tokens(tokens),
|
||||
Type::Void(span) => tokens.extend(quote_spanned!(*span=> ())),
|
||||
@ -100,6 +103,22 @@ impl ToTokens for Ref {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for Ptr {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Ptr {
|
||||
star,
|
||||
mutable: _,
|
||||
inner,
|
||||
mutability,
|
||||
constness,
|
||||
} = self;
|
||||
star.to_tokens(tokens);
|
||||
mutability.to_tokens(tokens);
|
||||
constness.to_tokens(tokens);
|
||||
inner.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for SliceRef {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let SliceRef {
|
||||
|
@ -51,6 +51,7 @@ impl<'a> Types<'a> {
|
||||
| Type::CxxVector(ty)
|
||||
| Type::RustVec(ty) => visit(all, &ty.inner),
|
||||
Type::Ref(r) => visit(all, &r.inner),
|
||||
Type::Ptr(p) => visit(all, &p.inner),
|
||||
Type::Array(a) => visit(all, &a.inner),
|
||||
Type::SliceRef(s) => visit(all, &s.inner),
|
||||
Type::Fn(f) => {
|
||||
|
@ -121,6 +121,8 @@ pub mod ffi {
|
||||
fn c_return_nested_ns_ref(shared: &ABShared) -> &usize;
|
||||
fn c_return_ns_enum(n: u16) -> AEnum;
|
||||
fn c_return_nested_ns_enum(n: u16) -> ABEnum;
|
||||
fn c_return_opaque_raw_ptr(n: usize) -> *const C;
|
||||
fn c_return_opaque_mut_raw_ptr(n: usize) -> *mut C;
|
||||
|
||||
fn c_take_primitive(n: usize);
|
||||
fn c_take_shared(shared: Shared);
|
||||
@ -161,6 +163,12 @@ pub mod ffi {
|
||||
fn c_take_nested_ns_shared(shared: ABShared);
|
||||
fn c_take_rust_vec_ns_shared(v: Vec<AShared>);
|
||||
fn c_take_rust_vec_nested_ns_shared(v: Vec<ABShared>);
|
||||
/// # Unsafety
|
||||
/// To keep clippy happy.
|
||||
unsafe fn c_take_opaque_mut_raw_ptr(c: *mut C) -> usize;
|
||||
/// # Unsafety
|
||||
/// To keep clippy happy.
|
||||
unsafe fn c_take_opaque_raw_ptr(c: *const C) -> usize;
|
||||
|
||||
fn c_try_return_void() -> Result<()>;
|
||||
fn c_try_return_primitive() -> Result<usize>;
|
||||
|
@ -207,6 +207,24 @@ Enum c_return_enum(uint16_t n) {
|
||||
}
|
||||
}
|
||||
|
||||
const C* c_return_opaque_raw_ptr(size_t c) {
|
||||
return new C(c);
|
||||
}
|
||||
|
||||
C* c_return_opaque_mut_raw_ptr(size_t c) {
|
||||
return new C(c);
|
||||
}
|
||||
|
||||
size_t c_take_opaque_raw_ptr(const C* c) {
|
||||
return c->get();
|
||||
}
|
||||
|
||||
size_t c_take_opaque_mut_raw_ptr(C* c) {
|
||||
size_t result = c->get();
|
||||
delete c;
|
||||
return result;
|
||||
}
|
||||
|
||||
Borrow::Borrow(const std::string &s) : s(s) {}
|
||||
|
||||
void Borrow::const_member() const {}
|
||||
|
@ -118,6 +118,8 @@ Enum c_return_enum(uint16_t n);
|
||||
::A::AEnum c_return_ns_enum(uint16_t n);
|
||||
::A::B::ABEnum c_return_nested_ns_enum(uint16_t n);
|
||||
std::unique_ptr<Borrow> c_return_borrow(const std::string &s);
|
||||
const C* c_return_opaque_raw_ptr(size_t n);
|
||||
C* c_return_opaque_mut_raw_ptr(size_t n);
|
||||
|
||||
void c_take_primitive(size_t n);
|
||||
void c_take_shared(Shared shared);
|
||||
@ -161,6 +163,8 @@ void c_take_callback(rust::Fn<size_t(rust::String)> callback);
|
||||
void c_take_enum(Enum e);
|
||||
void c_take_ns_enum(::A::AEnum e);
|
||||
void c_take_nested_ns_enum(::A::B::ABEnum e);
|
||||
size_t c_take_opaque_raw_ptr(const C* c);
|
||||
size_t c_take_opaque_mut_raw_ptr(C* c);
|
||||
|
||||
void c_try_return_void();
|
||||
size_t c_try_return_primitive();
|
||||
|
@ -335,3 +335,19 @@ fn test_extern_opaque() {
|
||||
check!(ffi2::c_take_opaque_ns_ref(f.as_ref().unwrap()));
|
||||
check!(ffi2::c_take_opaque_ns_ptr(f));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_raw_ptr() {
|
||||
let c = ffi::c_return_opaque_mut_raw_ptr(2023);
|
||||
let mut c_unique = unsafe { cxx::UniquePtr::from_raw(c) };
|
||||
assert_eq!(2023, c_unique.pin_mut().set_succeed(2023).unwrap());
|
||||
// c will be dropped as it's now in a UniquePtr
|
||||
|
||||
let c2 = ffi::c_return_opaque_mut_raw_ptr(2024);
|
||||
assert_eq!(2024, unsafe { ffi::c_take_opaque_raw_ptr(c2) });
|
||||
assert_eq!(2024, unsafe { ffi::c_take_opaque_mut_raw_ptr(c2) }); // deletes c2
|
||||
|
||||
let c3 = ffi::c_return_opaque_raw_ptr(2025);
|
||||
assert_eq!(2025, unsafe { ffi::c_take_opaque_raw_ptr(c3) });
|
||||
assert_eq!(2025, unsafe { ffi::c_take_opaque_mut_raw_ptr(c3 as *mut ffi::C) }); // deletes c3
|
||||
}
|
30
tests/ui/unsupported_ptr.rs
Normal file
30
tests/ui/unsupported_ptr.rs
Normal file
@ -0,0 +1,30 @@
|
||||
#[cxx::bridge]
|
||||
mod ffi {
|
||||
unsafe extern "C++" {
|
||||
type C;
|
||||
|
||||
fn not_unsafe_ptr(c: *mut C);
|
||||
}
|
||||
}
|
||||
|
||||
#[cxx::bridge]
|
||||
mod ffi2 {
|
||||
unsafe extern "C++" {
|
||||
type C;
|
||||
|
||||
fn get_neither_const_nor_mut() -> *C;
|
||||
}
|
||||
}
|
||||
|
||||
#[cxx::bridge]
|
||||
mod ffi3 {
|
||||
unsafe extern "C++" {
|
||||
type C;
|
||||
|
||||
fn get_ptr_ptr() -> *mut *mut C;
|
||||
fn get_ptr_reference() -> *mut & C;
|
||||
fn get_reference_ptr() -> & *mut C;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
37
tests/ui/unsupported_ptr.stderr
Normal file
37
tests/ui/unsupported_ptr.stderr
Normal file
@ -0,0 +1,37 @@
|
||||
error: expected mut or const in raw pointer type
|
||||
--> $DIR/unsupported_ptr.rs:15:43
|
||||
|
|
||||
15 | fn get_neither_const_nor_mut() -> *C;
|
||||
| ^ expected mut or const in raw pointer type
|
||||
|
|
||||
= help: use `*mut T` or `*const T` as appropriate
|
||||
|
||||
error: pointer argument requires that the function be marked unsafe
|
||||
--> $DIR/unsupported_ptr.rs:6:27
|
||||
|
|
||||
6 | fn not_unsafe_ptr(c: *mut C);
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: expected `const` or `mut`
|
||||
--> $DIR/unsupported_ptr.rs:15:44
|
||||
|
|
||||
15 | fn get_neither_const_nor_mut() -> *C;
|
||||
| ^
|
||||
|
||||
error: unsupported pointer type
|
||||
--> $DIR/unsupported_ptr.rs:24:29
|
||||
|
|
||||
24 | fn get_ptr_ptr() -> *mut *mut C;
|
||||
| ^^^^^^^^^^^
|
||||
|
||||
error: unsupported pointer type
|
||||
--> $DIR/unsupported_ptr.rs:25:35
|
||||
|
|
||||
25 | fn get_ptr_reference() -> *mut & C;
|
||||
| ^^^^^^^^
|
||||
|
||||
error: unsupported reference type
|
||||
--> $DIR/unsupported_ptr.rs:26:35
|
||||
|
|
||||
26 | fn get_reference_ptr() -> & *mut C;
|
||||
| ^^^^^^^^
|
Loading…
Reference in New Issue
Block a user