diff --git a/Cargo.lock b/Cargo.lock index 760e57bd4..9ee725e65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -165,8 +165,6 @@ dependencies = [ [[package]] name = "autocxx-bindgen" version = "0.65.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c9fb7b8dd83a582e12157367773d8d1195f2dea54d4250aaf3426abae3237aa" dependencies = [ "bitflags", "cexpr", diff --git a/Cargo.toml b/Cargo.toml index 0aaa33f1e..3b59a0064 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,9 +34,8 @@ moveit = { version = "0.6", features = [ "cxx" ] } members = ["parser", "engine", "gen/cmd", "gen/build", "macro", "demo", "tools/reduce", "tools/mdbook-preprocessor", "integration-tests"] exclude = ["examples/s2", "examples/steam-mini", "examples/subclass", "examples/chromium-fake-render-frame-host", "examples/pod", "examples/non-trivial-type-on-stack", "examples/llvm", "examples/reference-wrappers", "examples/cpp_calling_rust", "tools/stress-test"] -#[patch.crates-io] +[patch.crates-io] #cxx = { path="../cxx" } #cxx-gen = { path="../cxx/gen/lib" } -#autocxx-bindgen = { path="../bindgen" } +autocxx-bindgen = { path="../bindgen/bindgen" } #moveit = { path="../moveit" } -#moveit = { git = "https://github.com/silvanshade/moveit", branch = "fix-deref-move-soundness-hole" } diff --git a/engine/src/conversion/analysis/tdef.rs b/engine/src/conversion/analysis/tdef.rs index 1c414e8c4..006782d25 100644 --- a/engine/src/conversion/analysis/tdef.rs +++ b/engine/src/conversion/analysis/tdef.rs @@ -24,9 +24,12 @@ use crate::{ types::QualifiedName, }; +use super::{type_converter::TypedefTargetType, PointerTreatment}; + #[derive(std::fmt::Debug)] pub(crate) struct TypedefAnalysis { pub(crate) kind: TypedefKind, + pub(crate) target: TypedefTargetType, pub(crate) deps: HashSet<QualifiedName>, } @@ -64,12 +67,16 @@ pub(crate) fn convert_typedef_targets( &mut type_converter, &mut extra_apis, )?, - TypedefKind::Use { .. } => Api::Typedef { + TypedefKind::Use(ref _itu, ref boxed_type) => Api::Typedef { name, item: item.clone(), old_tyname, analysis: TypedefAnalysis { - kind: item, + kind: item.clone(), + target: TypedefTargetType { + ty: boxed_type.as_ref().clone(), + is_reference: false, + }, deps: HashSet::new(), }, }, @@ -96,10 +103,18 @@ fn get_replacement_typedef( let mut converted_type = ity.clone(); let metadata = BindgenSemanticAttributes::new_retaining_others(&mut converted_type.attrs); metadata.check_for_fatal_attrs(&ity.ident)?; + let is_reference = metadata.has_attr("reference"); + let type_conversion_context = if is_reference { + TypeConversionContext::OuterType { + pointer_treatment: PointerTreatment::Reference, + } + } else { + TypeConversionContext::WithinReference + }; let type_conversion_results = type_converter.convert_type( (*ity.ty).clone(), name.name.get_namespace(), - &TypeConversionContext::WithinReference, + &type_conversion_context, ); match type_conversion_results { Err(err) => Err(ConvertErrorWithContext( @@ -122,6 +137,10 @@ fn get_replacement_typedef( old_tyname, analysis: TypedefAnalysis { kind: TypedefKind::Type(converted_type.into()), + target: TypedefTargetType { + ty: final_type.ty.into(), + is_reference: final_type.kind.is_reference(), + }, deps: final_type.types_encountered, }, }) diff --git a/engine/src/conversion/analysis/type_converter.rs b/engine/src/conversion/analysis/type_converter.rs index 63f7ae99f..41bd087f1 100644 --- a/engine/src/conversion/analysis/type_converter.rs +++ b/engine/src/conversion/analysis/type_converter.rs @@ -8,7 +8,7 @@ use crate::{ conversion::{ - api::{AnalysisPhase, Api, ApiName, NullPhase, TypedefKind, UnanalyzedApi}, + api::{AnalysisPhase, Api, ApiName, NullPhase, UnanalyzedApi}, apivec::ApiVec, codegen_cpp::type_to_cpp::CppNameMap, ConvertErrorFromCpp, @@ -40,6 +40,15 @@ pub(crate) enum TypeKind { MutableReference, } +impl TypeKind { + pub(crate) fn is_reference(&self) -> bool { + matches!( + self, + Self::Reference | Self::RValueReference | Self::MutableReference + ) + } +} + /// Results of some type conversion, annotated with a list of every type encountered, /// and optionally any extra APIs we need in order to use this type. pub(crate) struct Annotated<T> { @@ -125,7 +134,7 @@ impl TypeConversionContext { /// inspecting the pre-existing list of APIs. pub(crate) struct TypeConverter<'a> { types_found: HashSet<QualifiedName>, - typedefs: HashMap<QualifiedName, Type>, + typedefs: HashMap<QualifiedName, TypedefTargetType>, concrete_templates: HashMap<String, QualifiedName>, forward_declarations: HashSet<QualifiedName>, ignored_types: HashSet<QualifiedName>, @@ -271,20 +280,33 @@ impl<'a> TypeConverter<'a> { // First let's see if this is a typedef. let (typ, tn) = match self.resolve_typedef(&original_tn)? { None => (typ, original_tn), - Some(Type::Path(resolved_tp)) => { + Some(TypedefTargetType { + ty: crate::minisyn::Type(Type::Path(resolved_tp)), + .. + }) => { let resolved_tn = QualifiedName::from_type_path(resolved_tp); deps.insert(resolved_tn.clone()); (resolved_tp.clone(), resolved_tn) } - Some(Type::Ptr(resolved_tp)) => { + Some(TypedefTargetType { + ty: crate::minisyn::Type(Type::Ptr(resolved_tp)), + is_reference, + }) => { return Ok(Annotated::new( Type::Ptr(resolved_tp.clone()), deps, ApiVec::new(), - TypeKind::Pointer, + if *is_reference { + TypeKind::Reference + } else { + TypeKind::Pointer + }, )) } - Some(other) => { + Some(TypedefTargetType { + ty: crate::minisyn::Type(other), + .. + }) => { return Ok(Annotated::new( other.clone(), deps, @@ -421,14 +443,17 @@ impl<'a> TypeConverter<'a> { fn resolve_typedef<'b>( &'b self, tn: &QualifiedName, - ) -> Result<Option<&'b Type>, ConvertErrorFromCpp> { + ) -> Result<Option<&'b TypedefTargetType>, ConvertErrorFromCpp> { let mut encountered = HashSet::new(); let mut tn = tn.clone(); let mut previous_typ = None; loop { let r = self.typedefs.get(&tn); match r { - Some(Type::Path(typ)) => { + Some(TypedefTargetType { + ty: crate::minisyn::Type(Type::Path(typ)), + is_reference: false, + }) => { previous_typ = r; let new_tn = QualifiedName::from_type_path(typ); if encountered.contains(&new_tn) { @@ -445,6 +470,10 @@ impl<'a> TypeConverter<'a> { encountered.insert(new_tn.clone()); tn = new_tn; } + Some(TypedefTargetType { + ty: crate::minisyn::Type(Type::Path(_)), + is_reference: true, + }) => panic!("Only Type::Pointer should be a reference"), None => return Ok(previous_typ), _ => return Ok(r), } @@ -632,7 +661,9 @@ impl<'a> TypeConverter<'a> { Ok(TypeKind::Regular) } - fn find_typedefs<A: AnalysisPhase>(apis: &ApiVec<A>) -> HashMap<QualifiedName, Type> + fn find_typedefs<A: AnalysisPhase>( + apis: &ApiVec<A>, + ) -> HashMap<QualifiedName, TypedefTargetType> where A::TypedefAnalysis: TypedefTarget, { @@ -705,22 +736,27 @@ pub(crate) fn add_analysis<A: AnalysisPhase>(api: UnanalyzedApi) -> Api<A> { _ => panic!("Function analysis created an unexpected type of extra API"), } } + +/// Target type of a typedef. +#[derive(Debug, Clone)] +pub(crate) struct TypedefTargetType { + pub(crate) ty: crate::minisyn::Type, + pub(crate) is_reference: bool, +} + pub(crate) trait TypedefTarget { - fn get_target(&self) -> Option<&Type>; + fn get_target(&self) -> Option<&TypedefTargetType>; } impl TypedefTarget for () { - fn get_target(&self) -> Option<&Type> { + fn get_target(&self) -> Option<&TypedefTargetType> { None } } impl TypedefTarget for TypedefAnalysis { - fn get_target(&self) -> Option<&Type> { - Some(match self.kind { - TypedefKind::Type(ref ty) => &ty.ty, - TypedefKind::Use(_, ref ty) => ty, - }) + fn get_target(&self) -> Option<&TypedefTargetType> { + Some(&self.target) } } diff --git a/engine/src/conversion/parse/bindgen_semantic_attributes.rs b/engine/src/conversion/parse/bindgen_semantic_attributes.rs index f2dd7d7d7..442f03d92 100644 --- a/engine/src/conversion/parse/bindgen_semantic_attributes.rs +++ b/engine/src/conversion/parse/bindgen_semantic_attributes.rs @@ -72,7 +72,7 @@ impl BindgenSemanticAttributes { } /// Whether the given attribute is present. - pub(super) fn has_attr(&self, attr_name: &str) -> bool { + pub(crate) fn has_attr(&self, attr_name: &str) -> bool { self.0.iter().any(|a| a.is_ident(attr_name)) } diff --git a/integration-tests/tests/integration_test.rs b/integration-tests/tests/integration_test.rs index ec2b1e7e2..bfb92c2d7 100644 --- a/integration-tests/tests/integration_test.rs +++ b/integration-tests/tests/integration_test.rs @@ -12241,6 +12241,22 @@ fn test_ignore_va_list() { run_test("", hdr, rs, &["A"], &[]); } +#[test] +fn test_reference_const_char_cast() { + let hdr = indoc! {" + class Bytes { + public: + typedef const char& reference; + private: + const char *d_ptr; + public: + reference front() const { return d_ptr[0]; } + }; + "}; + let rs = quote! {}; + run_test("", hdr, rs, &["Bytes"], &[]); +} + // Yet to test: // - Ifdef // - Out param pointers