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/analysis/fun/function_wrapper.rs b/engine/src/conversion/analysis/fun/function_wrapper.rs
index f2f6aaa..ab3b7d9 100644
--- a/engine/src/conversion/analysis/fun/function_wrapper.rs
+++ b/engine/src/conversion/analysis/fun/function_wrapper.rs
@@ -10,7 +10,8 @@
conversion::api::SubclassName,
types::{Namespace, QualifiedName},
};
-use syn::{parse_quote, Ident, Type};
+use quote::ToTokens;
+use syn::{parse_quote, Ident, Type, TypeReference};
#[derive(Clone, Debug)]
pub(crate) enum CppConversionType {
@@ -23,6 +24,8 @@
/// Ignored in the sense that it isn't passed into the C++ function.
IgnoredPlacementPtrParameter,
FromReturnValueToPlacementPtr,
+ FromPointerToReference, // unwrapped_type is always Type::Ptr
+ FromReferenceToPointer, // unwrapped_type is always Type::Ptr
}
impl CppConversionType {
@@ -36,6 +39,8 @@
CppConversionType::FromValueToUniquePtr
}
CppConversionType::FromValueToUniquePtr => CppConversionType::FromUniquePtrToValue,
+ CppConversionType::FromPointerToReference => CppConversionType::FromReferenceToPointer,
+ CppConversionType::FromReferenceToPointer => CppConversionType::FromPointerToReference,
_ => panic!("Did not expect to have to invert this conversion"),
}
}
@@ -52,6 +57,8 @@
FromValueParamToPtr,
FromPlacementParamToNewReturn,
FromRValueParamToPtr,
+ FromReferenceWrapperToPointer, // unwrapped_type is always Type::Ptr
+ FromPointerToReferenceWrapper, // unwrapped_type is always Type::Ptr
}
impl RustConversionType {
@@ -74,19 +81,53 @@
/// * Finally, the actual C++ API receives a `std::string` by value.
/// The implementation here is distributed across this file, and
/// `function_wrapper_rs` and `function_wrapper_cpp`.
+/// TODO: we should make this into a single enum, with the Type as enum
+/// variant params. That would remove the possibility of various runtime
+/// panics by enforcing (for example) that conversion from a pointer always
+/// has a Type::Ptr.
#[derive(Clone)]
pub(crate) struct TypeConversionPolicy {
- pub(crate) unwrapped_type: Type,
+ unwrapped_type: Type,
pub(crate) cpp_conversion: CppConversionType,
pub(crate) rust_conversion: RustConversionType,
}
impl TypeConversionPolicy {
pub(crate) fn new_unconverted(ty: Type) -> Self {
- TypeConversionPolicy {
+ Self::new(ty, CppConversionType::None, RustConversionType::None)
+ }
+
+ pub(crate) fn new(
+ ty: Type,
+ cpp_conversion: CppConversionType,
+ rust_conversion: RustConversionType,
+ ) -> Self {
+ Self {
unwrapped_type: ty,
- cpp_conversion: CppConversionType::None,
- rust_conversion: RustConversionType::None,
+ cpp_conversion,
+ rust_conversion,
+ }
+ }
+
+ pub(crate) fn cxxbridge_type(&self) -> &Type {
+ &self.unwrapped_type
+ }
+
+ pub(crate) fn return_reference_into_wrapper(ty: Type) -> Self {
+ let (unwrapped_type, is_mut) = match ty {
+ Type::Reference(TypeReference {
+ elem, mutability, ..
+ }) => (*elem, mutability.is_some()),
+ _ => panic!("Not a ptr: {}", ty.to_token_stream()),
+ };
+ TypeConversionPolicy {
+ unwrapped_type: if is_mut {
+ parse_quote! { *mut #unwrapped_type }
+ } else {
+ parse_quote! { *const #unwrapped_type }
+ },
+ cpp_conversion: CppConversionType::FromReferenceToPointer,
+ rust_conversion: RustConversionType::FromPointerToReferenceWrapper,
}
}
@@ -161,6 +202,8 @@
RustConversionType::FromValueParamToPtr
| RustConversionType::FromRValueParamToPtr
| RustConversionType::FromPlacementParamToNewReturn
+ | RustConversionType::FromPointerToReferenceWrapper { .. }
+ | RustConversionType::FromReferenceWrapperToPointer { .. }
)
}
diff --git a/engine/src/conversion/analysis/fun/mod.rs b/engine/src/conversion/analysis/fun/mod.rs
index 19340f9..7194746 100644
--- a/engine/src/conversion/analysis/fun/mod.rs
+++ b/engine/src/conversion/analysis/fun/mod.rs
@@ -41,7 +41,7 @@
use quote::quote;
use syn::{
parse_quote, punctuated::Punctuated, token::Comma, FnArg, Ident, Pat, ReturnType, Type,
- TypePtr, Visibility,
+ TypePath, TypePtr, TypeReference, Visibility,
};
use crate::{
@@ -183,7 +183,7 @@
pub(crate) is_placement_return_destination: bool,
}
-struct ReturnTypeAnalysis {
+pub(crate) struct ReturnTypeAnalysis {
rt: ReturnType,
conversion: Option<TypeConversionPolicy>,
was_reference: bool,
@@ -270,7 +270,7 @@
}
pub(crate) struct FnAnalyzer<'a> {
- unsafe_policy: UnsafePolicy,
+ unsafe_policy: &'a UnsafePolicy,
extra_apis: ApiVec<NullPhase>,
type_converter: TypeConverter<'a>,
bridge_name_tracker: BridgeNameTracker,
@@ -288,7 +288,7 @@
impl<'a> FnAnalyzer<'a> {
pub(crate) fn analyze_functions(
apis: ApiVec<PodPhase>,
- unsafe_policy: UnsafePolicy,
+ unsafe_policy: &'a UnsafePolicy,
config: &'a IncludeCppConfig,
) -> ApiVec<FnPrePhase2> {
let mut me = Self {
@@ -476,7 +476,9 @@
UnsafetyNeeded::Always => UnsafetyNeeded::JustBridge,
_ => unsafest_param,
},
- _ if self.unsafe_policy == UnsafePolicy::AllFunctionsUnsafe => UnsafetyNeeded::Always,
+ _ if matches!(self.unsafe_policy, UnsafePolicy::AllFunctionsUnsafe) => {
+ UnsafetyNeeded::Always
+ }
_ => match unsafest_non_placement_param {
UnsafetyNeeded::Always => UnsafetyNeeded::Always,
UnsafetyNeeded::JustBridge => match unsafest_param {
@@ -638,6 +640,7 @@
receiver_mutability,
sup,
subclass_fn_deps,
+ self.unsafe_policy,
));
// Create the trait item for the <superclass>_methods and <superclass>_supers
@@ -655,6 +658,7 @@
receiver_mutability,
sup.clone(),
is_pure_virtual,
+ self.unsafe_policy,
));
}
}
@@ -836,7 +840,7 @@
let arg_is_reference = matches!(
param_details
.get(1)
- .map(|param| ¶m.conversion.unwrapped_type),
+ .map(|param| param.conversion.cxxbridge_type()),
Some(Type::Reference(_))
);
// Some exotic forms of copy constructor have const and/or volatile qualifiers.
@@ -1209,6 +1213,11 @@
let ret_type_conversion_needed = ret_type_conversion
.as_ref()
.map_or(false, |x| x.cpp_work_needed());
+ let return_needs_rust_conversion = ret_type_conversion
+ .as_ref()
+ .map(|ra| ra.rust_work_needed())
+ .unwrap_or_default();
+
// See https://github.com/dtolnay/cxx/issues/878 for the reason for this next line.
let effective_cpp_name = cpp_name.as_ref().unwrap_or(&rust_name);
let cpp_name_incompatible_with_cxx =
@@ -1346,9 +1355,10 @@
.any(|pd| pd.conversion.rust_work_needed());
let rust_wrapper_needed = match kind {
+ _ if any_param_needs_rust_conversion || return_needs_rust_conversion => true,
FnKind::TraitMethod { .. } => true,
- FnKind::Method { .. } => any_param_needs_rust_conversion || cxxbridge_name != rust_name,
- _ => any_param_needs_rust_conversion,
+ FnKind::Method { .. } => cxxbridge_name != rust_name,
+ _ => false,
};
// Naming, part two.
@@ -1642,6 +1652,7 @@
}
_ => old_pat,
};
+
let is_placement_return_destination = is_placement_return_destination
|| matches!(
force_rust_conversion,
@@ -1653,6 +1664,8 @@
is_move_constructor,
force_rust_conversion,
sophistication,
+ self_type.is_some(),
+ is_placement_return_destination,
);
let new_ty = annotated_type.ty;
pt.pat = Box::new(new_pat.clone());
@@ -1694,6 +1707,8 @@
is_move_constructor: bool,
force_rust_conversion: Option<RustConversionType>,
sophistication: TypeConversionSophistication,
+ is_self: bool,
+ is_placement_return_destination: bool,
) -> TypeConversionPolicy {
let is_subclass_holder = match &annotated_type.kind {
type_converter::TypeKind::SubclassHolder(holder) => Some(holder),
@@ -1703,6 +1718,9 @@
annotated_type.kind,
type_converter::TypeKind::RValueReference
);
+ let is_reference =
+ matches!(annotated_type.kind, type_converter::TypeKind::Reference) || is_self;
+ let rust_conversion_forced = force_rust_conversion.is_some();
let ty = &*annotated_type.ty;
if let Some(holder_id) = is_subclass_holder {
let subclass = SubclassName::from_holder_name(holder_id);
@@ -1710,91 +1728,127 @@
let ty = parse_quote! {
rust::Box<#holder_id>
};
- TypeConversionPolicy {
- unwrapped_type: ty,
- cpp_conversion: CppConversionType::Move,
- rust_conversion: RustConversionType::ToBoxedUpHolder(subclass),
- }
+ TypeConversionPolicy::new(
+ ty,
+ CppConversionType::Move,
+ RustConversionType::ToBoxedUpHolder(subclass),
+ )
};
} else if matches!(
force_rust_conversion,
Some(RustConversionType::FromPlacementParamToNewReturn)
) && matches!(sophistication, TypeConversionSophistication::Regular)
{
- return TypeConversionPolicy {
- unwrapped_type: ty.clone(),
- cpp_conversion: CppConversionType::IgnoredPlacementPtrParameter,
- rust_conversion: RustConversionType::FromPlacementParamToNewReturn,
- };
+ return TypeConversionPolicy::new(
+ ty.clone(),
+ CppConversionType::IgnoredPlacementPtrParameter,
+ RustConversionType::FromPlacementParamToNewReturn,
+ );
}
match ty {
Type::Path(p) => {
let ty = ty.clone();
let tn = QualifiedName::from_type_path(p);
- if self.pod_safe_types.contains(&tn) {
+ if matches!(
+ self.config.unsafe_policy,
+ UnsafePolicy::ReferencesWrappedAllFunctionsSafe
+ ) && is_reference
+ && !rust_conversion_forced
+ // must be std::pin::Pin<&mut T>
+ {
+ let unwrapped_type = extract_type_from_pinned_mut_ref(p);
+ TypeConversionPolicy::new(
+ parse_quote! { *mut #unwrapped_type },
+ CppConversionType::FromPointerToReference,
+ RustConversionType::FromReferenceWrapperToPointer,
+ )
+ } else if self.pod_safe_types.contains(&tn) {
if known_types().lacks_copy_constructor(&tn) {
- TypeConversionPolicy {
- unwrapped_type: ty,
- cpp_conversion: CppConversionType::Move,
- rust_conversion: RustConversionType::None,
- }
+ TypeConversionPolicy::new(
+ ty,
+ CppConversionType::Move,
+ RustConversionType::None,
+ )
} else {
TypeConversionPolicy::new_unconverted(ty)
}
} else if known_types().convertible_from_strs(&tn)
&& !self.config.exclude_utilities()
{
- TypeConversionPolicy {
- unwrapped_type: ty,
- cpp_conversion: CppConversionType::FromUniquePtrToValue,
- rust_conversion: RustConversionType::FromStr,
- }
+ TypeConversionPolicy::new(
+ ty,
+ CppConversionType::FromUniquePtrToValue,
+ RustConversionType::FromStr,
+ )
} else if matches!(
sophistication,
TypeConversionSophistication::SimpleForSubclasses
) {
- TypeConversionPolicy {
- unwrapped_type: ty,
- cpp_conversion: CppConversionType::FromUniquePtrToValue,
- rust_conversion: RustConversionType::None,
- }
+ TypeConversionPolicy::new(
+ ty,
+ CppConversionType::FromUniquePtrToValue,
+ RustConversionType::None,
+ )
} else {
- TypeConversionPolicy {
- unwrapped_type: ty,
- cpp_conversion: CppConversionType::FromPtrToValue,
- rust_conversion: RustConversionType::FromValueParamToPtr,
- }
+ TypeConversionPolicy::new(
+ ty,
+ CppConversionType::FromPtrToValue,
+ RustConversionType::FromValueParamToPtr,
+ )
}
}
Type::Ptr(tp) => {
let rust_conversion = force_rust_conversion.unwrap_or(RustConversionType::None);
if is_move_constructor {
- TypeConversionPolicy {
- unwrapped_type: ty.clone(),
- cpp_conversion: CppConversionType::FromPtrToMove,
+ TypeConversionPolicy::new(
+ ty.clone(),
+ CppConversionType::FromPtrToMove,
rust_conversion,
- }
+ )
} else if is_rvalue_ref {
- TypeConversionPolicy {
- unwrapped_type: *tp.elem.clone(),
- cpp_conversion: CppConversionType::FromPtrToValue,
- rust_conversion: RustConversionType::FromRValueParamToPtr,
- }
+ TypeConversionPolicy::new(
+ *tp.elem.clone(),
+ CppConversionType::FromPtrToValue,
+ RustConversionType::FromRValueParamToPtr,
+ )
+ } else if matches!(
+ self.config.unsafe_policy,
+ UnsafePolicy::ReferencesWrappedAllFunctionsSafe
+ ) && is_reference
+ && !rust_conversion_forced
+ && !is_placement_return_destination
+ {
+ TypeConversionPolicy::new(
+ ty.clone(),
+ CppConversionType::FromPointerToReference,
+ RustConversionType::FromReferenceWrapperToPointer,
+ )
} else {
- TypeConversionPolicy {
- unwrapped_type: ty.clone(),
- cpp_conversion: CppConversionType::None,
- rust_conversion,
- }
+ TypeConversionPolicy::new(ty.clone(), CppConversionType::None, rust_conversion)
}
}
+ Type::Reference(TypeReference {
+ elem, mutability, ..
+ }) if matches!(
+ self.config.unsafe_policy,
+ UnsafePolicy::ReferencesWrappedAllFunctionsSafe
+ ) && !rust_conversion_forced
+ && !is_placement_return_destination =>
+ {
+ let is_mut = mutability.is_some();
+ TypeConversionPolicy::new(
+ if is_mut {
+ panic!("Never expected to find &mut T at this point, we should be Pin<&mut T> by now")
+ } else {
+ parse_quote! { *const #elem }
+ },
+ CppConversionType::FromPointerToReference,
+ RustConversionType::FromReferenceWrapperToPointer,
+ )
+ }
_ => {
let rust_conversion = force_rust_conversion.unwrap_or(RustConversionType::None);
- TypeConversionPolicy {
- unwrapped_type: ty.clone(),
- cpp_conversion: CppConversionType::None,
- rust_conversion,
- }
+ TypeConversionPolicy::new(ty.clone(), CppConversionType::None, rust_conversion)
}
}
}
@@ -1870,8 +1924,19 @@
}
}
_ => {
- let was_reference = matches!(boxed_type.as_ref(), Type::Reference(_));
- let conversion = Some(TypeConversionPolicy::new_unconverted(ty.clone()));
+ let was_reference = references.ref_return;
+ let conversion = Some(
+ if was_reference
+ && matches!(
+ self.config.unsafe_policy,
+ UnsafePolicy::ReferencesWrappedAllFunctionsSafe
+ )
+ {
+ TypeConversionPolicy::return_reference_into_wrapper(ty.clone())
+ } else {
+ TypeConversionPolicy::new_unconverted(ty.clone())
+ },
+ );
ReturnTypeAnalysis {
rt: ReturnType::Type(*rarrow, boxed_type),
conversion,
@@ -2138,3 +2203,24 @@
}
}
}
+
+fn extract_type_from_pinned_mut_ref(ty: &TypePath) -> Type {
+ match ty
+ .path
+ .segments
+ .last()
+ .expect("was not std::pin::Pin")
+ .arguments
+ {
+ syn::PathArguments::AngleBracketed(ref ab) => {
+ match ab.args.first().expect("did not have angle bracketed args") {
+ syn::GenericArgument::Type(ref ty) => match ty {
+ Type::Reference(ref tyr) => tyr.elem.as_ref().clone(),
+ _ => panic!("pin did not contain a reference"),
+ },
+ _ => panic!("argument was not a type"),
+ }
+ }
+ _ => panic!("did not find angle bracketed args"),
+ }
+}
diff --git a/engine/src/conversion/analysis/fun/subclass.rs b/engine/src/conversion/analysis/fun/subclass.rs
index c017249..6383d2c 100644
--- a/engine/src/conversion/analysis/fun/subclass.rs
+++ b/engine/src/conversion/analysis/fun/subclass.rs
@@ -10,7 +10,7 @@
use syn::{parse_quote, FnArg, PatType, Type, TypePtr};
-use crate::conversion::analysis::fun::{FnKind, MethodKind, ReceiverMutability};
+use crate::conversion::analysis::fun::{FnKind, MethodKind, ReceiverMutability, UnsafePolicy};
use crate::conversion::analysis::pod::PodPhase;
use crate::conversion::api::{
CppVisibility, FuncToConvert, Provenance, RustSubclassFnDetails, SubclassConstructorDetails,
@@ -79,12 +79,18 @@
receiver_mutability: &ReceiverMutability,
receiver: QualifiedName,
is_pure_virtual: bool,
+ unsafe_policy: &UnsafePolicy,
) -> Api<FnPrePhase1> {
let param_names = analysis
.param_details
.iter()
.map(|pd| pd.name.clone())
.collect();
+ let requires_unsafe = if matches!(unsafe_policy, UnsafePolicy::AllFunctionsUnsafe) {
+ UnsafetyNeeded::Always
+ } else {
+ UnsafetyNeeded::from_param_details(&analysis.param_details, false)
+ };
Api::SubclassTraitItem {
name,
details: SuperclassMethod {
@@ -93,7 +99,7 @@
ret_type: analysis.ret_type.clone(),
param_names,
receiver_mutability: receiver_mutability.clone(),
- requires_unsafe: UnsafetyNeeded::from_param_details(&analysis.param_details, false),
+ requires_unsafe,
is_pure_virtual,
receiver,
},
@@ -107,6 +113,7 @@
receiver_mutability: &ReceiverMutability,
superclass: &QualifiedName,
dependencies: Vec<QualifiedName>,
+ unsafe_policy: &UnsafePolicy,
) -> Api<FnPrePhase1> {
let cpp = sub.cpp();
let holder_name = sub.holder();
@@ -131,6 +138,11 @@
.skip(1)
.map(|p| p.conversion.clone())
.collect();
+ let requires_unsafe = if matches!(unsafe_policy, UnsafePolicy::AllFunctionsUnsafe) {
+ UnsafetyNeeded::Always
+ } else {
+ UnsafetyNeeded::from_param_details(&analysis.param_details, false)
+ };
Api::RustSubclassFn {
name: ApiName::new_in_root_namespace(rust_call_name.clone()),
subclass: sub.clone(),
@@ -151,7 +163,7 @@
superclass: superclass.clone(),
receiver_mutability: receiver_mutability.clone(),
dependencies,
- requires_unsafe: UnsafetyNeeded::from_param_details(&analysis.param_details, false),
+ requires_unsafe,
is_pure_virtual: matches!(
analysis.kind,
FnKind::Method {
diff --git a/engine/src/conversion/analysis/pod/mod.rs b/engine/src/conversion/analysis/pod/mod.rs
index 6722c23..eeb5051 100644
--- a/engine/src/conversion/analysis/pod/mod.rs
+++ b/engine/src/conversion/analysis/pod/mod.rs
@@ -18,7 +18,7 @@
use crate::{
conversion::{
analysis::type_converter::{self, add_analysis, TypeConversionContext, TypeConverter},
- api::{AnalysisPhase, Api, ApiName, CppVisibility, NullPhase, StructDetails, TypeKind},
+ api::{AnalysisPhase, Api, ApiName, NullPhase, StructDetails, TypeKind},
apivec::ApiVec,
convert_error::{ConvertErrorWithContext, ErrorContext},
error_reporter::convert_apis,
@@ -134,12 +134,6 @@
config: &IncludeCppConfig,
) -> Result<Box<dyn Iterator<Item = Api<PodPhase>>>, ConvertErrorWithContext> {
let id = name.name.get_final_ident();
- if details.vis != CppVisibility::Public {
- return Err(ConvertErrorWithContext(
- ConvertError::NonPublicNestedType,
- Some(ErrorContext::new_for_item(id)),
- ));
- }
let metadata = BindgenSemanticAttributes::new_retaining_others(&mut details.item.attrs);
metadata.check_for_fatal_attrs(&id)?;
let bases = get_bases(&details.item);
@@ -208,9 +202,14 @@
extra_apis: &mut ApiVec<NullPhase>,
) -> Vec<ConvertError> {
let mut convert_errors = Vec::new();
+ let struct_type_params = s
+ .generics
+ .type_params()
+ .map(|tp| tp.ident.clone())
+ .collect();
+ let type_conversion_context = TypeConversionContext::WithinStructField { struct_type_params };
for f in &s.fields {
- let annotated =
- type_converter.convert_type(f.ty.clone(), ns, &TypeConversionContext::WithinReference);
+ let annotated = type_converter.convert_type(f.ty.clone(), ns, &type_conversion_context);
match annotated {
Ok(mut r) => {
extra_apis.append(&mut r.extra_apis);
diff --git a/engine/src/conversion/analysis/type_converter.rs b/engine/src/conversion/analysis/type_converter.rs
index afdda8a..7e2d2bd 100644
--- a/engine/src/conversion/analysis/type_converter.rs
+++ b/engine/src/conversion/analysis/type_converter.rs
@@ -91,6 +91,7 @@
/// from [TypeConverter] _might_ be used in the [cxx::bridge].
pub(crate) enum TypeConversionContext {
WithinReference,
+ WithinStructField { struct_type_params: HashSet<Ident> },
WithinContainer,
OuterType { pointer_treatment: PointerTreatment },
}
@@ -98,13 +99,25 @@
impl TypeConversionContext {
fn pointer_treatment(&self) -> PointerTreatment {
match self {
- Self::WithinReference | Self::WithinContainer => PointerTreatment::Pointer,
+ Self::WithinReference | Self::WithinContainer | Self::WithinStructField { .. } => {
+ PointerTreatment::Pointer
+ }
Self::OuterType { pointer_treatment } => *pointer_treatment,
}
}
fn allow_instantiation_of_forward_declaration(&self) -> bool {
matches!(self, Self::WithinReference)
}
+ fn allowed_generic_type(&self, ident: &Ident) -> bool {
+ match self {
+ Self::WithinStructField { struct_type_params }
+ if struct_type_params.contains(ident) =>
+ {
+ false
+ }
+ _ => true,
+ }
+ }
}
/// A type which can convert from a type encountered in `bindgen`
@@ -156,7 +169,7 @@
) -> Result<Annotated<Type>, ConvertError> {
let result = match ty {
Type::Path(p) => {
- let newp = self.convert_type_path(p, ns)?;
+ let newp = self.convert_type_path(p, ns, ctx)?;
if let Type::Path(newpp) = &newp.ty {
let qn = QualifiedName::from_type_path(newpp);
if !ctx.allow_instantiation_of_forward_declaration()
@@ -216,6 +229,7 @@
&mut self,
mut typ: TypePath,
ns: &Namespace,
+ ctx: &TypeConversionContext,
) -> Result<Annotated<Type>, ConvertError> {
// First, qualify any unqualified paths.
if typ.path.segments.iter().next().unwrap().ident != "root" {
@@ -323,7 +337,24 @@
// Oh poop. It's a generic type which cxx won't be able to handle.
// We'll have to come up with a concrete type in both the cxx::bridge (in Rust)
// and a corresponding typedef in C++.
- // Let's first see if this is a concrete version of a templated type
+ // First let's see if this actually depends on a generic type
+ // param of the surrounding struct.
+ for seg in &typ.path.segments {
+ if let PathArguments::AngleBracketed(args) = &seg.arguments {
+ for arg in args.args.iter() {
+ if let GenericArgument::Type(Type::Path(typ)) = arg {
+ if let Some(seg) = typ.path.segments.last() {
+ if typ.path.segments.len() == 1
+ && !ctx.allowed_generic_type(&seg.ident)
+ {
+ return Err(ConvertError::ReferringToGenericTypeParam);
+ }
+ }
+ }
+ }
+ }
+ }
+ // Let's second see if this is a concrete version of a templated type
// which we already rejected. Some, but possibly not all, of the reasons
// for its rejection would also apply to any concrete types we
// make. Err on the side of caution. In future we may be able to relax
@@ -393,6 +424,14 @@
if encountered.contains(&new_tn) {
return Err(ConvertError::InfinitelyRecursiveTypedef(tn.clone()));
}
+ if typ
+ .path
+ .segments
+ .iter()
+ .any(|seg| seg.ident.to_string().starts_with("_bindgen_mod"))
+ {
+ return Err(ConvertError::TypedefToTypeInAnonymousNamespace);
+ }
encountered.insert(new_tn.clone());
tn = new_tn;
}