Squashed 'third_party/autocxx/' changes from 629e8fa53..c35090b75
c35090b75 Merge pull request #1131 from google/rev-0.22.3
94f20d716 Revise to 0.22.3.
b4776fdd5 Merge pull request #1070 from google/reference-wrapper
25f08f567 Better encapsulate TypeConversionPolicy. No functional changes.
b389afdeb Add reference wrapper safety policy.
cd169853b Merge pull request #1126 from google/issue-1125
92f48fa30 Merge pull request #1123 from google/segfault-detection
ca60bacca Add comment
724a4971d Add test for issue 1125.
d8a9a8ca7 Detect segfaults in reduction
e147efc7c Merge pull request #1122 from google/rev-0.22.2
dfa9b99a4 Revise to 0.22.2.
4cb1da848 Merge pull request #1120 from chbaker0/main
79afb97d9 Replace lingering tempdir usages with tempfile
f945331a3 Merge pull request #1118 from google/fix-test-fixed-num
5a8b28751 Merge pull request #1117 from google/docs-tweaks
b5486faa1 Merge pull request #1109 from bsilver8192/bindgen-skip-rustfmt
f62c17273 Fix faulty test_fixed_num test.
ad954fa72 Minor doc updates.
eaa1f8737 Leave bindgen enabled when logging is
bdff5db56 Merge pull request #1110 from bsilver8192/subclass-std
922f98be4 Merge pull request #1111 from bsilver8192/subclass-unsafe
bfbcc6b94 Merge pull request #1114 from google/rev-0.22.1
4f68a2e59 Merge pull request #1112 from bsilver8192/subclass-upcast-uniqueptr
993c5705b Revise to 0.22.1.
7bf667bbf Add a function to upcast UniquePtr
733d751a2 Fix clippy and docs
8023cee43 Fix and test subclass without `safety!(unsafe)`
4ae4d47e4 Fix and test subclasses with C++ std in scope
c50b1ee7e Tell bindgen to skip rustfmt
f9b24b90e Merge pull request #1107 from google/reject-anon-namespace-typedefs
070c9755d Merge pull request #1093 from google/always-output-rs
8eb71c5e7 Merge pull request #1095 from google/issue-1094
c86f1ce7e Reject forward declared nested types.
c118dba64 Merge branch 'main' into reject-anon-namespace-typedefs
243079997 Merge pull request #1108 from google/reject-type-param-typedefs
f803c3ba5 Reject type params - fixes #1098
f3381ba52 Reject typedefs to anon namespaces.
669d932a7 Merge pull request #1106 from google/lotsa-failing-tests
f0e8487fe Marking tests as ignored.
524c2bbfc Add tests for multiple issues.
67e16ac2a Merge branch 'main' of github.com:google/autocxx into always-output-rs
5f62daf3f Merge pull request #1104 from google/roll-cxx
43ee55ca2 Further upgrade from 1.0.67 to 1.0.68
e29e3c899 Merge pull request #1100 from bsilver8192/extern_cpp_type-namespace
d2c8edef4 Merge pull request #1101 from google/fix-1081
094dbd957 Roll cxx minimal version.
94c39f35b Merge pull request #1102 from google/fix-book-build
8764f1218 Alter mdbook-mermaid installation.
85543656f Test for issue 1081
b170df056 Fix and test extern_cpp_type with type in a C++ namespace
e4b56dd49 Fix gen tests.
5457e615d Fix #1092.
git-subtree-dir: third_party/autocxx
git-subtree-split: c35090b754619531b4eebdf4d8b583db72349943
Signed-off-by: Brian Silverman <bsilver16384@gmail.com>
Change-Id: Ia34285bc1c30f7e3c71fa9e7b677a58902648843
diff --git a/engine/src/conversion/codegen_rs/fun_codegen.rs b/engine/src/conversion/codegen_rs/fun_codegen.rs
index 7c32b1b..db222a6 100644
--- a/engine/src/conversion/codegen_rs/fun_codegen.rs
+++ b/engine/src/conversion/codegen_rs/fun_codegen.rs
@@ -6,6 +6,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use autocxx_parser::IncludeCppConfig;
use indexmap::set::IndexSet as HashSet;
use std::borrow::Cow;
@@ -23,15 +24,15 @@
function_wrapper_rs::RustParamConversion,
maybe_unsafes_to_tokens,
unqualify::{unqualify_params, unqualify_ret_type},
- ImplBlockDetails, MaybeUnsafeStmt, RsCodegenResult, TraitImplBlockDetails, Use,
+ ImplBlockDetails, ImplBlockKey, MaybeUnsafeStmt, RsCodegenResult, TraitImplBlockDetails, Use,
};
use crate::{
conversion::{
analysis::fun::{
- ArgumentAnalysis, FnAnalysis, FnKind, MethodKind, RustRenameStrategy,
- TraitMethodDetails,
+ function_wrapper::TypeConversionPolicy, ArgumentAnalysis, FnAnalysis, FnKind,
+ MethodKind, RustRenameStrategy, TraitMethodDetails,
},
- api::UnsafetyNeeded,
+ api::{Pointerness, UnsafetyNeeded},
},
types::{Namespace, QualifiedName},
};
@@ -89,6 +90,7 @@
analysis: FnAnalysis,
cpp_call_name: String,
non_pod_types: &HashSet<QualifiedName>,
+ config: &IncludeCppConfig,
) -> RsCodegenResult {
if analysis.ignore_reason.is_err() || !analysis.externally_callable {
return RsCodegenResult::default();
@@ -96,6 +98,7 @@
let cxxbridge_name = analysis.cxxbridge_name;
let rust_name = &analysis.rust_name;
let ret_type = analysis.ret_type;
+ let ret_conversion = analysis.ret_conversion;
let param_details = analysis.param_details;
let wrapper_function_needed = analysis.cpp_wrapper.is_some();
let params = analysis.params;
@@ -119,6 +122,9 @@
always_unsafe_due_to_trait_definition,
doc_attrs: &doc_attrs,
non_pod_types,
+ ret_type: &ret_type,
+ ret_conversion: &ret_conversion,
+ reference_wrappers: config.unsafe_policy.requires_cpprefs(),
};
// In rare occasions, we might need to give an explicit lifetime.
let (lifetime_tokens, params, ret_type) = add_explicit_lifetime_if_necessary(
@@ -148,15 +154,14 @@
impl_entry = Some(fn_generator.generate_method_impl(
matches!(method_kind, MethodKind::Constructor { .. }),
impl_for,
- &ret_type,
));
}
FnKind::TraitMethod { ref details, .. } => {
- trait_impl_entry = Some(fn_generator.generate_trait_impl(details, &ret_type));
+ trait_impl_entry = Some(fn_generator.generate_trait_impl(details));
}
_ => {
// Generate plain old function
- bindgen_mod_items.push(fn_generator.generate_function_impl(&ret_type));
+ bindgen_mod_items.push(fn_generator.generate_function_impl());
}
}
}
@@ -225,20 +230,23 @@
#[derive(Clone)]
struct FnGenerator<'a> {
param_details: &'a [ArgumentAnalysis],
+ ret_conversion: &'a Option<TypeConversionPolicy>,
+ ret_type: &'a ReturnType,
cxxbridge_name: &'a Ident,
rust_name: &'a str,
unsafety: &'a UnsafetyNeeded,
always_unsafe_due_to_trait_definition: bool,
doc_attrs: &'a Vec<Attribute>,
non_pod_types: &'a HashSet<QualifiedName>,
+ reference_wrappers: bool,
}
impl<'a> FnGenerator<'a> {
fn common_parts<'b>(
- &self,
+ &'b self,
avoid_self: bool,
parameter_reordering: &Option<Vec<usize>>,
- ret_type: &'b ReturnType,
+ ret_type: Option<ReturnType>,
) -> (
Option<TokenStream>,
Punctuated<FnArg, Comma>,
@@ -249,15 +257,20 @@
let mut local_variables = Vec::new();
let mut arg_list = Vec::new();
let mut ptr_arg_name = None;
- let mut ret_type = Cow::Borrowed(ret_type);
+ let mut ret_type: Cow<'a, _> = ret_type
+ .map(Cow::Owned)
+ .unwrap_or(Cow::Borrowed(self.ret_type));
let mut any_conversion_requires_unsafe = false;
+ let mut variable_counter = 0usize;
for pd in self.param_details {
let wrapper_arg_name = if pd.self_type.is_some() && !avoid_self {
parse_quote!(self)
} else {
pd.name.clone()
};
- let rust_for_param = pd.conversion.rust_conversion(wrapper_arg_name.clone());
+ let rust_for_param = pd
+ .conversion
+ .rust_conversion(parse_quote! { #wrapper_arg_name }, &mut variable_counter);
match rust_for_param {
RustParamConversion::Param {
ty,
@@ -305,6 +318,39 @@
},
any_conversion_requires_unsafe || matches!(self.unsafety, UnsafetyNeeded::JustBridge),
);
+ let context_is_unsafe = matches!(self.unsafety, UnsafetyNeeded::Always)
+ || self.always_unsafe_due_to_trait_definition;
+ let (call_body, ret_type) = match self.ret_conversion {
+ Some(ret_conversion) if ret_conversion.rust_work_needed() => {
+ let expr = maybe_unsafes_to_tokens(vec![call_body], context_is_unsafe);
+ let conv =
+ ret_conversion.rust_conversion(parse_quote! { #expr }, &mut variable_counter);
+ let (conversion, requires_unsafe, ty) = match conv {
+ RustParamConversion::Param {
+ local_variables, ..
+ } if !local_variables.is_empty() => panic!("return type required variables"),
+ RustParamConversion::Param {
+ conversion,
+ conversion_requires_unsafe,
+ ty,
+ ..
+ } => (conversion, conversion_requires_unsafe, ty),
+ _ => panic!(
+ "Unexpected - return type is supposed to be converted to a return type"
+ ),
+ };
+ (
+ if requires_unsafe {
+ MaybeUnsafeStmt::NeedsUnsafe(conversion)
+ } else {
+ MaybeUnsafeStmt::Normal(conversion)
+ },
+ Cow::Owned(parse_quote! { -> #ty }),
+ )
+ }
+ _ => (call_body, ret_type),
+ };
+
let call_stmts = if let Some(ptr_arg_name) = ptr_arg_name {
let mut closure_stmts = local_variables;
closure_stmts.push(MaybeUnsafeStmt::binary(
@@ -323,8 +369,6 @@
call_stmts.push(call_body);
call_stmts
};
- let context_is_unsafe = matches!(self.unsafety, UnsafetyNeeded::Always)
- || self.always_unsafe_due_to_trait_definition;
let call_body = maybe_unsafes_to_tokens(call_stmts, context_is_unsafe);
(lifetime_tokens, wrapper_params, ret_type, call_body)
}
@@ -334,13 +378,44 @@
&self,
avoid_self: bool,
impl_block_type_name: &QualifiedName,
- ret_type: &ReturnType,
) -> Box<ImplBlockDetails> {
let (lifetime_tokens, wrapper_params, ret_type, call_body) =
- self.common_parts(avoid_self, &None, ret_type);
+ self.common_parts(avoid_self, &None, None);
let rust_name = make_ident(self.rust_name);
let unsafety = self.unsafety.wrapper_token();
let doc_attrs = self.doc_attrs;
+ let receiver_pointerness = self
+ .param_details
+ .iter()
+ .next()
+ .map(|pd| pd.conversion.is_a_pointer())
+ .unwrap_or(Pointerness::Not);
+ let ty = impl_block_type_name.get_final_ident();
+ let ty = if self.reference_wrappers {
+ match receiver_pointerness {
+ Pointerness::MutPtr => ImplBlockKey {
+ ty: parse_quote! {
+ CppMutRef< 'a, #ty>
+ },
+ lifetime: Some(parse_quote! { 'a }),
+ },
+ Pointerness::ConstPtr => ImplBlockKey {
+ ty: parse_quote! {
+ CppRef< 'a, #ty>
+ },
+ lifetime: Some(parse_quote! { 'a }),
+ },
+ Pointerness::Not => ImplBlockKey {
+ ty: parse_quote! { # ty },
+ lifetime: None,
+ },
+ }
+ } else {
+ ImplBlockKey {
+ ty: parse_quote! { # ty },
+ lifetime: None,
+ }
+ };
Box::new(ImplBlockDetails {
item: ImplItem::Method(parse_quote! {
#(#doc_attrs)*
@@ -348,18 +423,14 @@
#call_body
}
}),
- ty: impl_block_type_name.get_final_ident(),
+ ty,
})
}
/// Generate an 'impl Trait for Type { methods-go-here }' in its entrety.
- fn generate_trait_impl(
- &self,
- details: &TraitMethodDetails,
- ret_type: &ReturnType,
- ) -> Box<TraitImplBlockDetails> {
+ fn generate_trait_impl(&self, details: &TraitMethodDetails) -> Box<TraitImplBlockDetails> {
let (lifetime_tokens, wrapper_params, ret_type, call_body) =
- self.common_parts(details.avoid_self, &details.parameter_reordering, ret_type);
+ self.common_parts(details.avoid_self, &details.parameter_reordering, None);
let doc_attrs = self.doc_attrs;
let unsafety = self.unsafety.wrapper_token();
let key = details.trt.clone();
@@ -381,25 +452,28 @@
) -> Box<ImplBlockDetails> {
let ret_type: ReturnType = parse_quote! { -> impl autocxx::moveit::new::New<Output=Self> };
let (lifetime_tokens, wrapper_params, ret_type, call_body) =
- self.common_parts(true, &None, &ret_type);
+ self.common_parts(true, &None, Some(ret_type));
let rust_name = make_ident(&self.rust_name);
let doc_attrs = self.doc_attrs;
let unsafety = self.unsafety.wrapper_token();
- Box::new(ImplBlockDetails {
- item: ImplItem::Method(parse_quote! {
+ let ty = impl_block_type_name.get_final_ident();
+ let ty = parse_quote! { #ty };
+ let stuff = quote! {
#(#doc_attrs)*
pub #unsafety fn #rust_name #lifetime_tokens ( #wrapper_params ) #ret_type {
#call_body
}
- }),
- ty: impl_block_type_name.get_final_ident(),
+ };
+ Box::new(ImplBlockDetails {
+ item: ImplItem::Method(parse_quote! { #stuff }),
+ ty: ImplBlockKey { ty, lifetime: None },
})
}
/// Generate a function call wrapper
- fn generate_function_impl(&self, ret_type: &ReturnType) -> Item {
+ fn generate_function_impl(&self) -> Item {
let (lifetime_tokens, wrapper_params, ret_type, call_body) =
- self.common_parts(false, &None, ret_type);
+ self.common_parts(false, &None, None);
let rust_name = make_ident(self.rust_name);
let doc_attrs = self.doc_attrs;
let unsafety = self.unsafety.wrapper_token();
diff --git a/engine/src/conversion/codegen_rs/function_wrapper_rs.rs b/engine/src/conversion/codegen_rs/function_wrapper_rs.rs
index a3fc71f..708d41c 100644
--- a/engine/src/conversion/codegen_rs/function_wrapper_rs.rs
+++ b/engine/src/conversion/codegen_rs/function_wrapper_rs.rs
@@ -7,7 +7,7 @@
// except according to those terms.
use proc_macro2::TokenStream;
-use syn::{Pat, Type, TypePtr};
+use syn::{Expr, Type, TypePtr};
use crate::{
conversion::analysis::fun::function_wrapper::{RustConversionType, TypeConversionPolicy},
@@ -32,8 +32,7 @@
}
impl TypeConversionPolicy {
- /// If returns `None` then this parameter should be omitted entirely.
- pub(super) fn rust_conversion(&self, var: Pat) -> RustParamConversion {
+ pub(super) fn rust_conversion(&self, var: Expr, counter: &mut usize) -> RustParamConversion {
match self.rust_conversion {
RustConversionType::None => RustParamConversion::Param {
ty: self.converted_rust_type(),
@@ -63,7 +62,7 @@
}
}
RustConversionType::FromPinMaybeUninitToPtr => {
- let ty = match &self.unwrapped_type {
+ let ty = match self.cxxbridge_type() {
Type::Ptr(TypePtr { elem, .. }) => &*elem,
_ => panic!("Not a ptr"),
};
@@ -80,7 +79,7 @@
}
}
RustConversionType::FromPinMoveRefToPtr => {
- let ty = match &self.unwrapped_type {
+ let ty = match self.cxxbridge_type() {
Type::Ptr(TypePtr { elem, .. }) => &*elem,
_ => panic!("Not a ptr"),
};
@@ -99,7 +98,7 @@
}
}
RustConversionType::FromTypeToPtr => {
- let ty = match &self.unwrapped_type {
+ let ty = match self.cxxbridge_type() {
Type::Ptr(TypePtr { elem, .. }) => &*elem,
_ => panic!("Not a ptr"),
};
@@ -123,13 +122,11 @@
};
let handler_type = make_ident(handler_type);
let param_trait = make_ident(param_trait);
- let var_name = if let Pat::Ident(pti) = &var {
- &pti.ident
- } else {
- panic!("Unexpected non-ident parameter name");
- };
- let space_var_name = make_ident(format!("{}_space", var_name));
- let ty = &self.unwrapped_type;
+ let var_counter = *counter;
+ *counter += 1;
+ let space_var_name = format!("space{}", var_counter);
+ let space_var_name = make_ident(space_var_name);
+ let ty = self.cxxbridge_type();
let ty = parse_quote! { impl autocxx::#param_trait<#ty> };
// This is the usual trick to put something on the stack, then
// immediately shadow the variable name so it can't be accessed or moved.
@@ -148,7 +145,7 @@
},
),
MaybeUnsafeStmt::needs_unsafe(
- quote! { #space_var_name.as_mut().populate(#var_name); },
+ quote! { #space_var_name.as_mut().populate(#var); },
),
],
conversion: quote! {
@@ -161,12 +158,55 @@
// but not in the arguments for the wrapper function, because instead we return an
// impl New which uses the cxx::bridge function's pointer parameter.
RustConversionType::FromPlacementParamToNewReturn => {
- let ty = match &self.unwrapped_type {
+ let ty = match self.cxxbridge_type() {
Type::Ptr(TypePtr { elem, .. }) => *(*elem).clone(),
_ => panic!("Not a ptr"),
};
RustParamConversion::ReturnValue { ty }
}
+ RustConversionType::FromPointerToReferenceWrapper => {
+ let (is_mut, ty) = match self.cxxbridge_type() {
+ Type::Ptr(TypePtr {
+ mutability, elem, ..
+ }) => (mutability.is_some(), elem.as_ref()),
+ _ => panic!("Not a pointer"),
+ };
+ let (ty, wrapper_name) = if is_mut {
+ (parse_quote! { CppMutRef<'a, #ty> }, "CppMutRef")
+ } else {
+ (parse_quote! { CppRef<'a, #ty> }, "CppRef")
+ };
+ let wrapper_name = make_ident(wrapper_name);
+ RustParamConversion::Param {
+ ty,
+ local_variables: Vec::new(),
+ conversion: quote! {
+ #wrapper_name (#var, std::marker::PhantomData)
+ },
+ conversion_requires_unsafe: false,
+ }
+ }
+ RustConversionType::FromReferenceWrapperToPointer => {
+ let (is_mut, ty) = match self.cxxbridge_type() {
+ Type::Ptr(TypePtr {
+ mutability, elem, ..
+ }) => (mutability.is_some(), elem.as_ref()),
+ _ => panic!("Not a pointer"),
+ };
+ let ty = if is_mut {
+ parse_quote! { &mut CppMutRef<'a, #ty> }
+ } else {
+ parse_quote! { &CppRef<'a, #ty> }
+ };
+ RustParamConversion::Param {
+ ty,
+ local_variables: Vec::new(),
+ conversion: quote! {
+ #var .0
+ },
+ conversion_requires_unsafe: false,
+ }
+ }
}
}
}
diff --git a/engine/src/conversion/codegen_rs/mod.rs b/engine/src/conversion/codegen_rs/mod.rs
index d488d52..5dd4cbb 100644
--- a/engine/src/conversion/codegen_rs/mod.rs
+++ b/engine/src/conversion/codegen_rs/mod.rs
@@ -17,13 +17,14 @@
use indexmap::map::IndexMap as HashMap;
use indexmap::set::IndexSet as HashSet;
-use autocxx_parser::{ExternCppType, IncludeCppConfig, RustFun};
+use autocxx_parser::{ExternCppType, IncludeCppConfig, RustFun, UnsafePolicy};
use itertools::Itertools;
use proc_macro2::{Span, TokenStream};
use syn::{
parse_quote, punctuated::Punctuated, token::Comma, Attribute, Expr, FnArg, ForeignItem,
- ForeignItemFn, Ident, ImplItem, Item, ItemForeignMod, ItemMod, TraitItem, TypePath,
+ ForeignItemFn, Ident, ImplItem, Item, ItemForeignMod, ItemMod, Lifetime, TraitItem, Type,
+ TypePath,
};
use crate::{
@@ -61,10 +62,16 @@
use super::{convert_error::ErrorContext, ConvertError};
use quote::quote;
+#[derive(Clone, Hash, PartialEq, Eq)]
+struct ImplBlockKey {
+ ty: Type,
+ lifetime: Option<Lifetime>,
+}
+
/// An entry which needs to go into an `impl` block for a given type.
struct ImplBlockDetails {
item: ImplItem,
- ty: Ident,
+ ty: ImplBlockKey,
}
struct TraitImplBlockDetails {
@@ -130,10 +137,96 @@
.to_vec()
}
+fn get_cppref_items() -> Vec<Item> {
+ [
+ Item::Struct(parse_quote! {
+ #[repr(transparent)]
+ pub struct CppRef<'a, T>(pub *const T, pub ::std::marker::PhantomData<&'a T>);
+ }),
+ Item::Impl(parse_quote! {
+ impl<'a, T> autocxx::CppRef<'a, T> for CppRef<'a, T> {
+ fn as_ptr(&self) -> *const T {
+ self.0
+ }
+ }
+ }),
+ Item::Struct(parse_quote! {
+ #[repr(transparent)]
+ pub struct CppMutRef<'a, T>(pub *mut T, pub ::std::marker::PhantomData<&'a T>);
+ }),
+ Item::Impl(parse_quote! {
+ impl<'a, T> autocxx::CppRef<'a, T> for CppMutRef<'a, T> {
+ fn as_ptr(&self) -> *const T {
+ self.0
+ }
+ }
+ }),
+ Item::Impl(parse_quote! {
+ impl<'a, T> autocxx::CppMutRef<'a, T> for CppMutRef<'a, T> {
+ fn as_mut_ptr(&self) -> *mut T {
+ self.0
+ }
+ }
+ }),
+ Item::Impl(parse_quote! {
+ impl<'a, T: ::cxx::private::UniquePtrTarget> CppMutRef<'a, T> {
+ /// Create a const C++ reference from this mutable C++ reference.
+ pub fn as_cpp_ref(&self) -> CppRef<'a, T> {
+ use autocxx::CppRef;
+ CppRef(self.as_ptr(), ::std::marker::PhantomData)
+ }
+ }
+ }),
+ Item::Struct(parse_quote! {
+ /// "Pins" a `UniquePtr` to an object, so that C++-compatible references can be created.
+ /// See [`::autocxx::CppPin`]
+ #[repr(transparent)]
+ pub struct CppUniquePtrPin<T: ::cxx::private::UniquePtrTarget>(::cxx::UniquePtr<T>);
+ }),
+ Item::Impl(parse_quote! {
+ impl<'a, T: 'a + ::cxx::private::UniquePtrTarget> autocxx::CppPin<'a, T> for CppUniquePtrPin<T>
+ {
+ type CppRef = CppRef<'a, T>;
+ type CppMutRef = CppMutRef<'a, T>;
+ fn as_ptr(&self) -> *const T {
+ // TODO add as_ptr to cxx to avoid the ephemeral reference
+ self.0.as_ref().unwrap() as *const T
+ }
+ fn as_mut_ptr(&mut self) -> *mut T {
+ unsafe { ::std::pin::Pin::into_inner_unchecked(self.0.as_mut().unwrap()) as *mut T }
+ }
+ fn as_cpp_ref(&self) -> Self::CppRef {
+ CppRef(self.as_ptr(), ::std::marker::PhantomData)
+ }
+ fn as_cpp_mut_ref(&mut self) -> Self::CppMutRef {
+ CppMutRef(self.as_mut_ptr(), ::std::marker::PhantomData)
+ }
+ }
+ }),
+ Item::Impl(parse_quote! {
+ impl<T: ::cxx::private::UniquePtrTarget> CppUniquePtrPin<T> {
+ pub fn new(item: ::cxx::UniquePtr<T>) -> Self {
+ Self(item)
+ }
+ }
+ }),
+ Item::Fn(parse_quote! {
+ /// Pin this item so that we can create C++ references to it.
+ /// This makes it impossible to hold Rust references because Rust
+ /// references are fundamentally incompatible with C++ references.
+ pub fn cpp_pin_uniqueptr<T: ::cxx::private::UniquePtrTarget> (item: ::cxx::UniquePtr<T>) -> CppUniquePtrPin<T> {
+ CppUniquePtrPin::new(item)
+ }
+ })
+ ]
+ .to_vec()
+}
+
/// Type which handles generation of Rust code.
/// In practice, much of the "generation" involves connecting together
/// existing lumps of code within the Api structures.
pub(crate) struct RsCodeGenerator<'a> {
+ unsafe_policy: &'a UnsafePolicy,
include_list: &'a [String],
bindgen_mod: ItemMod,
original_name_map: CppNameMap,
@@ -145,12 +238,14 @@
/// Generate code for a set of APIs that was discovered during parsing.
pub(crate) fn generate_rs_code(
all_apis: ApiVec<FnPhase>,
+ unsafe_policy: &'a UnsafePolicy,
include_list: &'a [String],
bindgen_mod: ItemMod,
config: &'a IncludeCppConfig,
header_name: Option<String>,
) -> Vec<Item> {
let c = Self {
+ unsafe_policy,
include_list,
bindgen_mod,
original_name_map: original_name_map_from_apis(&all_apis),
@@ -219,6 +314,9 @@
let mut extern_rust_mod_items = extern_rust_mod_items.into_iter().flatten().collect();
// And a list of global items to include at the top level.
let mut all_items: Vec<Item> = all_items.into_iter().flatten().collect();
+ if self.config.unsafe_policy.requires_cpprefs() {
+ all_items.append(&mut get_cppref_items())
+ }
// And finally any C++ we need to generate. And by "we" I mean autocxx not cxx.
let has_additional_cpp_needs = additional_cpp_needs.into_iter().any(std::convert::identity);
extern_c_mod_items.extend(self.build_include_foreign_items(has_additional_cpp_needs));
@@ -357,23 +455,24 @@
}
fn append_uses_for_ns(&mut self, items: &mut Vec<Item>, ns: &Namespace) {
+ let mut imports_from_super = vec!["cxxbridge"];
+ if !self.config.exclude_utilities() {
+ imports_from_super.push("ToCppString");
+ }
+ if self.config.unsafe_policy.requires_cpprefs() {
+ imports_from_super.extend(["CppRef", "CppMutRef"]);
+ }
+ let imports_from_super = imports_from_super.into_iter().map(make_ident);
let super_duper = std::iter::repeat(make_ident("super")); // I'll get my coat
let supers = super_duper.clone().take(ns.depth() + 2);
items.push(Item::Use(parse_quote! {
#[allow(unused_imports)]
use self::
#(#supers)::*
- ::cxxbridge;
+ ::{
+ #(#imports_from_super),*
+ };
}));
- if !self.config.exclude_utilities() {
- let supers = super_duper.clone().take(ns.depth() + 2);
- items.push(Item::Use(parse_quote! {
- #[allow(unused_imports)]
- use self::
- #(#supers)::*
- ::ToCppString;
- }));
- }
let supers = super_duper.take(ns.depth() + 1);
items.push(Item::Use(parse_quote! {
#[allow(unused_imports)]
@@ -407,8 +506,10 @@
}
}
for (ty, entries) in impl_entries_by_type.into_iter() {
+ let lt = ty.lifetime.map(|lt| quote! { < #lt > });
+ let ty = ty.ty;
output_items.push(Item::Impl(parse_quote! {
- impl #ty {
+ impl #lt #ty {
#(#entries)*
}
}))
@@ -487,6 +588,7 @@
analysis,
cpp_call_name,
non_pod_types,
+ self.config,
),
Api::Const { const_item, .. } => RsCodegenResult {
bindgen_mod_items: vec![Item::Const(const_item)],
@@ -609,8 +711,11 @@
name, superclass, ..
} => {
let methods = associated_methods.get(&superclass);
- let generate_peer_constructor =
- subclasses_with_a_single_trivial_constructor.contains(&name.0.name);
+ let generate_peer_constructor = subclasses_with_a_single_trivial_constructor.contains(&name.0.name) &&
+ // TODO: Create an UnsafeCppPeerConstructor trait for calling an unsafe
+ // constructor instead? Need to create unsafe versions of everything that uses
+ // it too.
+ matches!(self.unsafe_policy, UnsafePolicy::AllFunctionsSafe);
self.generate_subclass(name, &superclass, methods, generate_peer_constructor)
}
Api::ExternCppType {
@@ -723,6 +828,10 @@
extern_c_mod_items.push(parse_quote! {
fn #as_mut_id(self: Pin<&mut #cpp_id>) -> Pin<&mut #super_cxxxbridge_id>;
});
+ let as_unique_ptr_id = make_ident(format!("{}_As_{}_UniquePtr", cpp_id, super_name));
+ extern_c_mod_items.push(parse_quote! {
+ fn #as_unique_ptr_id(u: UniquePtr<#cpp_id>) -> UniquePtr<#super_cxxxbridge_id>;
+ });
bindgen_mod_items.push(parse_quote! {
impl AsRef<#super_path> for super::super::super::#id {
fn as_ref(&self) -> &cxxbridge::#super_cxxxbridge_id {
@@ -740,6 +849,14 @@
}
}
});
+ let rs_as_unique_ptr_id = make_ident(format!("as_{}_unique_ptr", super_name));
+ bindgen_mod_items.push(parse_quote! {
+ impl super::super::super::#id {
+ pub fn #rs_as_unique_ptr_id(u: cxx::UniquePtr<#cpp_id>) -> cxx::UniquePtr<cxxbridge::#super_cxxxbridge_id> {
+ cxxbridge::#as_unique_ptr_id(u)
+ }
+ }
+ });
let remove_ownership = sub.remove_ownership();
global_items.push(parse_quote! {
#[allow(non_snake_case)]
@@ -813,7 +930,7 @@
.as_ref()
.#borrow()
.expect(#reentrancy_panic_msg);
- let r = std::ops::#deref_ty::#deref_call(& #mut_token b);
+ let r = ::std::ops::#deref_ty::#deref_call(& #mut_token b);
#methods_trait :: #method_name
(r,
#args)
@@ -1012,7 +1129,7 @@
rust_path: TypePath,
ns_depth: usize,
) -> RsCodegenResult {
- let id = name.get_final_ident();
+ let id = name.type_path_from_root();
let super_duper = std::iter::repeat(make_ident("super"));
let supers = super_duper.take(ns_depth + 2);
let use_statement = parse_quote! {
@@ -1057,7 +1174,10 @@
fn #method(_uhoh: autocxx::BindingGenerationFailure) {
}
},
- ty: self_ty,
+ ty: ImplBlockKey {
+ ty: parse_quote! { #self_ty },
+ lifetime: None,
+ },
})),
None,
None,